ODROID-C4: wireless: esp8089: Support esp8089 driver.

- The esp8089 driver supports many esp's wifi modules. So it is imported.

Change-Id: If039882e183e454baff2c222bf7a1282b6705459
This commit is contained in:
Luke go
2020-09-18 16:19:52 +09:00
committed by Chris
parent 2ed3759b3b
commit 9974e1f2d7
50 changed files with 27198 additions and 3 deletions

View File

@@ -20,7 +20,8 @@ dtbo-$(CONFIG_ARCH_MESON64_ODROIDC4) += spi0.dtbo \
pwm_b-backlight.dtbo \
wifi_bt_combo.dtbo \
sdio.dtbo \
gpio_shortcut.dtbo
gpio_shortcut.dtbo \
esp8089.dtbo
targets += $(dtbo-y)
always := $(dtbo-y)

View File

@@ -0,0 +1,24 @@
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&sd_emmc_a>;
__overlay__ {
status = "okay";
sdio {
caps = "MMC_CAP_4_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED",
"MMC_CAP_NONREMOVABLE",
"MMC_CAP_UHS_SDR12",
"MMC_CAP_UHS_SDR25",
"MMC_CAP_UHS_SDR50",
"MMC_CAP_UHS_SDR104",
"MMC_PM_KEEP_POWER";
};
};
};
};

View File

@@ -2278,7 +2278,9 @@ CONFIG_WLAN_VENDOR_ZYDAS=y
# CONFIG_USB_ZD1201 is not set
# CONFIG_ZD1211RW is not set
# CONFIG_MAC80211_HWSIM is not set
# CONFIG_USB_NET_RNDIS_WLAN is not set
CONFIG_USB_NET_RNDIS_WLAN=m
CONFIG_ESP8089=m
CONFIG_ESP8089_DEBUG_FS=y
#
# Enable WiMAX (Networking options) to see the WiMAX drivers

View File

@@ -2157,7 +2157,9 @@ CONFIG_WLAN_VENDOR_ZYDAS=y
# CONFIG_USB_ZD1201 is not set
# CONFIG_ZD1211RW is not set
# CONFIG_MAC80211_HWSIM is not set
# CONFIG_USB_NET_RNDIS_WLAN is not set
CONFIG_USB_NET_RNDIS_WLAN=m
CONFIG_ESP8089=m
CONFIG_ESP8089_DEBUG_fs=y
#
# Enable WiMAX (Networking options) to see the WiMAX drivers

View File

@@ -32,6 +32,7 @@ source "drivers/net/wireless/rsi/Kconfig"
source "drivers/net/wireless/st/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
source "drivers/net/wireless/esp8089/Kconfig"
config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"

View File

@@ -25,3 +25,5 @@ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_ESP8089) += esp8089/

View File

@@ -0,0 +1,13 @@
config ESP8089
tristate "Espressif ESP8089 SDIO WiFi"
depends on MAC80211
---help---
ESP8089 is a low-budget 2.4GHz WiFi chip by Espressif, used in many
cheap tablets with Allwinner or Rockchip SoC
config ESP8089_DEBUG_FS
bool "Enable DebugFS support for ESP8089"
depends on ESP8089
default y
---help---
DebugFS support for ESP8089

View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,148 @@
MODNAME = esp8089
# By default, we try to compile the modules for the currently running
# kernel. But it's the first approximation, as we will re-read the
# version from the kernel sources.
KVERS_UNAME ?= $(shell uname -r)
KVERS_ARCH ?= $(shell arch)
# KBUILD is the path to the Linux kernel build tree. It is usually the
# same as the kernel source tree, except when the kernel was compiled in
# a separate directory.
KBUILD ?= $(PWD)/out/target/product/$(TARGET_PRODUCT)/obj/KERNEL_OBJ
ifeq (,$(KBUILD))
$(error Kernel build tree not found - please set KBUILD to configured kernel)
endif
KCONFIG := $(KBUILD)/.config
ifeq (,$(wildcard $(KCONFIG)))
$(error No .config found in $(KBUILD), please set KBUILD to configured kernel)
endif
ifneq (,$(wildcard $(KBUILD)/include/linux/version.h))
ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h))
$(error Multiple copies of version.h found, please clean your build tree)
endif
endif
# Kernel Makefile doesn't always know the exact kernel version, so we
# get it from the kernel headers instead and pass it to make.
VERSION_H := $(KBUILD)/include/generated/utsrelease.h
ifeq (,$(wildcard $(VERSION_H)))
VERSION_H := $(KBUILD)/include/linux/utsrelease.h
endif
ifeq (,$(wildcard $(VERSION_H)))
VERSION_H := $(KBUILD)/include/linux/version.h
endif
ifeq (,$(wildcard $(VERSION_H)))
$(error Please run 'make modules_prepare' in $(KBUILD))
endif
KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H))
ifeq (,$(KVERS))
$(error Cannot find UTS_RELEASE in $(VERSION_H), please report)
endif
INST_DIR = /lib/modules/$(KVERS)/misc
SRC_DIR=$(shell pwd)
include $(KCONFIG)
#Shouldn't fail when not having dkms.conf in directory
#(usually when installing a built package on other system)
-include dkms.conf
PACKAGE_NAME := $(patsubst "%",%,$(PACKAGE_NAME))
PACKAGE_VERSION := $(patsubst "%",%,$(PACKAGE_VERSION))
DKMS_PATH := /usr/src/$(PACKAGE_NAME)-$(PACKAGE_VERSION)/
EXTRA_CFLAGS += -DDEBUG -DSIP_DEBUG -DFAST_TX_STATUS \
-DKERNEL_IV_WAR -DRX_SENDUP_SYNC -DDEBUG_FS \
-DSIF_DSR_WAR -DHAS_INIT_DATA -DHAS_FW
EXTRA_CFLAGS += -DESP_USE_SDIO
ifdef ANDROID
EXTRA_CFLAGS += -DANDROID
endif
ifdef P2P_CONCURRENT
EXTRA_CFLAGS += -DP2P_CONCURRENT
endif
ifdef TEST_MODE
EXTRA_CFLAGS += -DTEST_MODE
endif
OBJS = esp_debug.o sdio_sif_esp.o spi_sif_esp.o esp_io.o \
esp_file.o esp_main.o esp_sip.o esp_ext.o esp_ctrl.o \
esp_mac80211.o esp_debug.o esp_utils.o esp_pm.o testmode.o
all: config_check modules
MODULE := $(MODNAME).ko
obj-m := $(MODNAME).o
$(MODNAME)-objs := $(OBJS)
config_check:
@if [ -z "$(CONFIG_WIRELESS_EXT)$(CONFIG_NET_RADIO)" ]; then \
echo; echo; \
echo "*** WARNING: This kernel lacks wireless extensions."; \
echo "Wireless drivers will not work properly."; \
echo; echo; \
fi
# Taken from here:
# http://www.xkyle.com/building-linux-packages-for-kernel-drivers/
dkms:
$(MAKE) config_check
echo $(DKMS_PATH)
echo "$(KVERS_UNAME)"
mkdir -p $(DKMS_PATH)
cp -r . $(DKMS_PATH)
-rm -rf $(DKMS_PATH)/.git
-rm $(DKMS_PATH)/.gitignore
-rm $(DKMS_PATH)/*deb
dkms add -m $(PACKAGE_NAME) -v $(PACKAGE_VERSION)
dkms build -m $(PACKAGE_NAME) -v $(PACKAGE_VERSION)
dkmsdeb: dkms
dkms mkdsc -m $(PACKAGE_NAME) -v $(PACKAGE_VERSION) --source-only
dkms mkdeb -m $(PACKAGE_NAME) -v $(PACKAGE_VERSION) --source-only
cp /var/lib/dkms/$(PACKAGE_NAME)/$(PACKAGE_VERSION)/deb/*.deb .
cleandkms:
-dkms uninstall $(PACKAGE_NAME)/$(PACKAGE_VERSION)
-dkms remove $(PACKAGE_NAME)/$(PACKAGE_VERSION) --all
-rm -rf /var/lib/dkms/$(PACKAGE_NAME)/$(PACKAGE_VERSION) $(DKMS_PATH)
modules:
$(MAKE) -C $(KBUILD) M=$(SRC_DIR)
$(MODULE):
$(MAKE) modules
clean:
rm -f *.o *.ko .*.cmd *.mod.c *.symvers modules.order
rm -rf .tmp_versions
install: config_check $(MODULE)
@/sbin/modinfo $(MODULE) | grep -q "^vermagic: *$(KVERS) " || \
{ echo "$(MODULE)" is not for Linux $(KVERS); exit 1; }
mkdir -p -m 755 $(DESTDIR)$(INST_DIR)
install -m 0644 $(MODULE) $(DESTDIR)$(INST_DIR)
ifndef DESTDIR
-/sbin/depmod -a $(KVERS)
endif
uninstall:
rm -f $(DESTDIR)$(INST_DIR)/$(MODULE)
ifndef DESTDIR
-/sbin/depmod -a $(KVERS)
endif
.PHONY: all modules clean install config_check

View File

@@ -0,0 +1,60 @@
esp8089
======
ESP8089 Linux driver
v1.9 imported from the Rockchip Linux kernel github repo
Modified to build as a standalone module for SDIO devices.
Building:
make
sudo make install
Using:
modprobe should autoload the module as the ESP8089 should be detected by
the SDIO driver and loaded as a dependency.
The ESP8089 requires that the CH_PD signal be reset before the driver
can load properly, so a GPIO is used by the driver to assert this signal
for 200ms. The GPIO defaults to 0 (ID_SD on the Raspberry Pi) but this
can be changed to any GPIO mapped by the kernel GPIO driver through the
esp_reset_gpio module parameter. This can be accomplished by creating a
new modprobe.d config file. For example, to use GPIO 5 instead, create
as root /etc/modprobe.d/esp.conf and add the line:
options esp8089 esp_reset_gpio=5
which changes the GPIO from 0 to 5.
Building a Debian source package:
To build a source package for release, first install the following:
apt-get install debhelper dkms raspberrypi-kernel-headers
Then build the package:
sudo make dkmsdeb
The module will be named esp8089-dkms_*.deb. Don't forget to update the version
in dkms.conf and committing before making a release!
If the build fails to create a source package, try installing dkms from github:
sudo apt-get remove dkms
sudo apt-get install devscripts quilt
git clone https://github.com/dell/dkms.git
cd dkms
sed -ie "s/module-init-tools/kmod/g" debian/control
make debs
and install the resulting package in dist/

View File

@@ -0,0 +1,7 @@
PACKAGE_NAME="esp8089"
PACKAGE_VERSION="1.9.20190603"
CLEAN="make clean"
MAKE[0]="make KVERS_UNAME=$kernelver"
BUILT_MODULE_NAME[0]="esp8089"
DEST_MODULE_LOCATION="/updates"
AUTOINSTALL="yes"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
#ifndef _ESP_CONF_H_
#define _ESP_CONF_H_
#define INIT_DATA_CONF_BUF "crystal_26M_en=1;test_xtal=0;sdio_configure=2;bt_configure=0;bt_protocol=0;dual_ant_configure=0;test_uart_configure=0;share_xtal=0;gpio_wake=0;no_auto_sleep=1;ext_rst=0;wakeup_gpio=12;ate_test=0;speed_suspend=0;$"
#endif /*_ESP_CONF_H_ */

View File

@@ -0,0 +1 @@
EXTRA_CFLAGS += -DP2P_CONCURRENT -DESP_ACK_INTERRUPT -DESP_USE_SDIO

View File

@@ -0,0 +1,807 @@
/*
* Copyright (c) 2009 - 2014 Espressif System.
*
* SIP ctrl packet parse and pack
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <net/mac80211.h>
#include <net/cfg80211.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/firmware.h>
#include "esp_pub.h"
#include "esp_sip.h"
#include "esp_ctrl.h"
#include "esp_sif.h"
#include "esp_debug.h"
#include "esp_wmac.h"
#include "esp_utils.h"
#include "esp_wl.h"
#include "esp_file.h"
#include "esp_path.h"
#ifdef TEST_MODE
#include "testmode.h"
#endif /* TEST_MODE */
#include "esp_version.h"
extern struct completion *gl_bootup_cplx;
static void esp_tx_ba_session_op(struct esp_sip *sip, struct esp_node *node, trc_ampdu_state_t state, u8 tid )
{
struct esp_tx_tid *txtid;
txtid = &node->tid[tid];
if (state == TRC_TX_AMPDU_STOPPED) {
if (txtid->state == ESP_TID_STATE_OPERATIONAL) {
esp_dbg(ESP_DBG_TXAMPDU, "%s tid %d TXAMPDU GOT STOP EVT\n", __func__, tid);
spin_lock_bh(&sip->epub->tx_ampdu_lock);
txtid->state = ESP_TID_STATE_WAIT_STOP;
spin_unlock_bh(&sip->epub->tx_ampdu_lock);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
ieee80211_stop_tx_ba_session(sip->epub->hw, node->addr, (u16)tid, WLAN_BACK_INITIATOR);
#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32))
ieee80211_stop_tx_ba_session(sip->epub->hw, node->sta->addr, (u16)tid, WLAN_BACK_INITIATOR);
#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
ieee80211_stop_tx_ba_session(node->sta, (u16)tid, WLAN_BACK_INITIATOR);
#else
ieee80211_stop_tx_ba_session(node->sta, (u16)tid);
#endif /* KERNEL_VERSION 2.6.39 */
} else {
esp_dbg(ESP_DBG_TXAMPDU, "%s tid %d TXAMPDU GOT STOP EVT IN WRONG STATE %d\n", __func__, tid, txtid->state);
}
} else if (state == TRC_TX_AMPDU_OPERATIONAL) {
if (txtid->state == ESP_TID_STATE_STOP) {
esp_dbg(ESP_DBG_TXAMPDU, "%s tid %d TXAMPDU GOT OPERATIONAL\n", __func__, tid);
spin_lock_bh(&sip->epub->tx_ampdu_lock);
txtid->state = ESP_TID_STATE_TRIGGER;
spin_unlock_bh(&sip->epub->tx_ampdu_lock);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
ieee80211_start_tx_ba_session(sip->epub->hw, node->addr, tid);
#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32))
ieee80211_start_tx_ba_session(sip->epub->hw, node->sta->addr, tid);
#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 37))
ieee80211_start_tx_ba_session(node->sta, (u16)tid);
#else
ieee80211_start_tx_ba_session(node->sta, (u16)tid, 0);
#endif /* KERNEL_VERSION 2.6.39 */
} else if(txtid->state == ESP_TID_STATE_OPERATIONAL) {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
sip_send_ampdu_action(sip->epub, SIP_AMPDU_TX_OPERATIONAL, node->addr, tid, node->ifidx, 0);
#else
sip_send_ampdu_action(sip->epub, SIP_AMPDU_TX_OPERATIONAL, node->sta->addr, tid, node->ifidx, 0);
#endif
} else {
esp_dbg(ESP_DBG_TXAMPDU, "%s tid %d TXAMPDU GOT OPERATIONAL EVT IN WRONG STATE %d\n", __func__, tid, txtid->state);
}
}
}
#ifdef TEST_MODE
int sip_parse_event_debug(struct esp_pub *epub, const u8 *src, u8 *dst)
{
struct sip_evt_debug* debug_evt = (struct sip_evt_debug *)(src + SIP_CTRL_HDR_LEN);
switch (debug_evt->results[0]) {
case RDRSSI: {
u32 mask = debug_evt->results[1];
u8 *p = (u8 *)&debug_evt->results[2];
u8 index;
struct esp_node *enode;
while (mask != 0) {
index = ffs(mask) - 1;
if (index >= ESP_PUB_MAX_STA)
break;
enode = esp_get_node_by_index(epub, index);
if (enode == NULL) {
esp_dbg(ESP_DBG_ERROR, "trc mask dismatch");
} else {
dst += sprintf(dst, "%02x:%02x:%02x:%02x:%02x:%02x 0x%x 0x%x\n",
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
enode->sta->addr[0], enode->sta->addr[1], enode->sta->addr[2],
enode->sta->addr[3], enode->sta->addr[4], enode->sta->addr[5],
#else
enode->addr[0], enode->addr[1], enode->addr[2],
enode->addr[3], enode->addr[4], enode->addr[5],
#endif
*p, *(p+1));
p += 2;
}
mask &= ~(1<<index);
};
dst += sprintf(dst, "%c", '\0');
break;
}
default: {
int i;
for(i = 1; i < debug_evt->len; i++)
dst += sprintf(dst, "0x%x%s", debug_evt->results[i], i == debug_evt->len -1 ? "":" " );
break;
}
}
return 0;
}
#endif /*TEST_MODE*/
int sip_parse_events(struct esp_sip *sip, u8 *buf)
{
struct sip_hdr *hdr = (struct sip_hdr *)buf;
switch (hdr->c_evtid) {
case SIP_EVT_TARGET_ON: {
/* use rx work queue to send... */
if (atomic_read(&sip->state) == SIP_PREPARE_BOOT || atomic_read(&sip->state) == SIP_BOOT) {
atomic_set(&sip->state, SIP_SEND_INIT);
queue_work(sip->epub->esp_wkq, &sip->rx_process_work);
} else {
esp_dbg(ESP_DBG_ERROR, "%s boot during wrong state %d\n", __func__, atomic_read(&sip->state));
}
break;
}
case SIP_EVT_BOOTUP: {
struct sip_evt_bootup2 *bootup_evt = (struct sip_evt_bootup2 *)(buf + SIP_CTRL_HDR_LEN);
if (sip->rawbuf)
kfree(sip->rawbuf);
sip_post_init(sip, bootup_evt);
if (gl_bootup_cplx)
complete(gl_bootup_cplx);
break;
}
case SIP_EVT_RESETTING:{
sip->epub->wait_reset = 1;
if (gl_bootup_cplx)
complete(gl_bootup_cplx);
break;
}
case SIP_EVT_SLEEP:{
//atomic_set(&sip->epub->ps.state, ESP_PM_ON);
break;
}
case SIP_EVT_TXIDLE:{
//struct sip_evt_txidle *txidle = (struct sip_evt_txidle *)(buf + SIP_CTRL_HDR_LEN);
//sip_txdone_clear(sip, txidle->last_seq);
break;
}
#ifndef FAST_TX_STATUS
case SIP_EVT_TX_STATUS: {
struct sip_evt_tx_report *report = (struct sip_evt_tx_report *)(buf + SIP_CTRL_HDR_LEN);
sip_txdoneq_process(sip, report);
break;
}
#endif /* FAST_TX_STATUS */
case SIP_EVT_SCAN_RESULT: {
struct sip_evt_scan_report *report = (struct sip_evt_scan_report *)(buf + SIP_CTRL_HDR_LEN);
if (atomic_read(&sip->epub->wl.off)) {
esp_dbg(ESP_DBG_ERROR, "%s scan result while wlan off\n", __func__);
return 0;
}
sip_scandone_process(sip, report);
break;
}
case SIP_EVT_ROC: {
struct sip_evt_roc* report = (struct sip_evt_roc *)(buf + SIP_CTRL_HDR_LEN);
esp_rocdone_process(sip->epub->hw, report);
break;
}
#ifdef ESP_RX_COPYBACK_TEST
case SIP_EVT_COPYBACK: {
u32 len = hdr->len - SIP_CTRL_HDR_LEN;
esp_dbg(ESP_DBG_TRACE, "%s copyback len %d seq %u\n", __func__, len, hdr->seq);
memcpy(copyback_buf + copyback_offset, pkt->buf + SIP_CTRL_HDR_LEN, len);
copyback_offset += len;
//show_buf(pkt->buf, 256);
//how about totlen % 256 == 0??
if (hdr->hdr.len < 256) {
kfree(copyback_buf);
}
}
break;
#endif /* ESP_RX_COPYBACK_TEST */
case SIP_EVT_CREDIT_RPT:
break;
#ifdef TEST_MODE
case SIP_EVT_WAKEUP: {
u8 check_str[12];
struct sip_evt_wakeup* wakeup_evt= (struct sip_evt_wakeup *)(buf + SIP_CTRL_HDR_LEN);
sprintf((char *)&check_str, "%d", wakeup_evt->check_data);
esp_test_cmd_event(TEST_CMD_WAKEUP, (char *)&check_str);
break;
}
case SIP_EVT_DEBUG: {
u8 check_str[640];
sip_parse_event_debug(sip->epub, buf, check_str);
esp_dbg(ESP_DBG_TRACE, "%s", check_str);
esp_test_cmd_event(TEST_CMD_DEBUG, (char *)&check_str);
break;
}
case SIP_EVT_LOOPBACK: {
u8 check_str[12];
struct sip_evt_loopback *loopback_evt = (struct sip_evt_loopback *)(buf + SIP_CTRL_HDR_LEN);
esp_dbg(ESP_DBG_LOG, "%s loopback len %d seq %u\n", __func__,hdr->len, hdr->seq);
if(loopback_evt->pack_id!=get_loopback_id()) {
sprintf((char *)&check_str, "seq id error %d, expect %d", loopback_evt->pack_id, get_loopback_id());
esp_test_cmd_event(TEST_CMD_LOOPBACK, (char *)&check_str);
}
if((loopback_evt->pack_id+1) <get_loopback_num()) {
inc_loopback_id();
sip_send_loopback_mblk(sip, loopback_evt->txlen, loopback_evt->rxlen, get_loopback_id());
} else {
sprintf((char *)&check_str, "test over!");
sp_test_cmd_event(TEST_CMD_LOOPBACK, (char *)&check_str);
}
break;
}
#endif /*TEST_MODE*/
case SIP_EVT_SNPRINTF_TO_HOST: {
u8 *p = (buf + sizeof(struct sip_hdr) + sizeof(u16));
u16 *len = (u16 *)(buf + sizeof(struct sip_hdr));
char test_res_str[560];
sprintf(test_res_str, "esp_host:%llx\nesp_target: %.*s", DRIVER_VER, *len, p);
esp_dbg(ESP_SHOW, "%s\n", test_res_str);
if(*len && sip->epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT){
char filename[256];
if (mod_eagle_path_get() == NULL)
sprintf(filename, "%s/%s", FWPATH, "test_results");
else
sprintf(filename, "%s/%s", mod_eagle_path_get(), "test_results");
esp_readwrite_file(filename, NULL, test_res_str, strlen(test_res_str));
}
break;
}
case SIP_EVT_TRC_AMPDU: {
struct sip_evt_trc_ampdu *ep = (struct sip_evt_trc_ampdu*)(buf + SIP_CTRL_HDR_LEN);
struct esp_node *node = NULL;
int i = 0;
if (atomic_read(&sip->epub->wl.off)) {
esp_dbg(ESP_DBG_ERROR, "%s scan result while wlan off\n", __func__);
return 0;
}
node = esp_get_node_by_addr(sip->epub, ep->addr);
if(node == NULL)
break;
for (i = 0; i < 8; i++) {
if (ep->tid & (1<<i)) {
esp_tx_ba_session_op(sip, node, ep->state, i);
}
}
break;
}
#ifdef TEST_MODE
case SIP_EVT_EP: {
char *ep = (char *)(buf + SIP_CTRL_HDR_LEN);
static int counter = 0;
esp_dbg(ESP_ATE, "%s EVT_EP \n\n", __func__);
if (counter++ < 2) {
esp_dbg(ESP_ATE, "ATE: %s \n", ep);
}
esp_test_ate_done_cb(ep);
break;
}
#endif /*TEST_MODE*/
case SIP_EVT_INIT_EP: {
char *ep = (char *)(buf + SIP_CTRL_HDR_LEN);
esp_dbg(ESP_ATE, "Phy Init: %s \n", ep);
break;
}
case SIP_EVT_NOISEFLOOR:{
struct sip_evt_noisefloor *ep = (struct sip_evt_noisefloor *)(buf + SIP_CTRL_HDR_LEN);
atomic_set(&sip->noise_floor, ep->noise_floor);
break;
}
default:
break;
}
return 0;
}
#ifdef HAS_INIT_DATA
#include "esp_init_data.h"
#else
#define ESP_INIT_NAME "esp_init_data.bin"
#endif /* HAS_INIT_DATA */
void sip_send_chip_init(struct esp_sip *sip)
{
size_t size = 0;
#ifndef HAS_INIT_DATA
const struct firmware *fw_entry;
u8 * esp_init_data = NULL;
int ret = 0;
ret = esp_request_firmware(&fw_entry, ESP_INIT_NAME, sip->epub->dev);
if (ret) {
esp_dbg(ESP_DBG_ERROR, "%s =============ERROR! NO INIT DATA!!=================\n", __func__);
return;
}
esp_init_data = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
size = fw_entry->size;
esp_release_firmware(fw_entry);
if (esp_init_data == NULL) {
esp_dbg(ESP_DBG_ERROR, "%s =============ERROR! NO MEMORY!!=================\n", __func__);
return;
}
#else
size = sizeof(esp_init_data);
#endif /* !HAS_INIT_DATA */
fix_init_data(esp_init_data, size);
atomic_sub(1, &sip->tx_credits);
sip_send_cmd(sip, SIP_CMD_INIT, size, (void *)esp_init_data);
#ifndef HAS_INIT_DATA
kfree(esp_init_data);
#endif /* !HAS_INIT_DATA */
}
int sip_send_config(struct esp_pub *epub, struct ieee80211_conf * conf)
{
struct sk_buff *skb = NULL;
struct sip_cmd_config *configcmd;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_config) + sizeof(struct sip_hdr), SIP_CMD_CONFIG);
if (!skb)
return -EINVAL;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
esp_dbg(ESP_DBG_TRACE, "%s config center freq %d\n", __func__, conf->chandef.chan->center_freq);
#else
esp_dbg(ESP_DBG_TRACE, "%s config center freq %d\n", __func__, conf->channel->center_freq);
#endif
configcmd = (struct sip_cmd_config *)(skb->data + sizeof(struct sip_hdr));
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
configcmd->center_freq= conf->chandef.chan->center_freq;
#else
configcmd->center_freq= conf->channel->center_freq;
#endif
configcmd->duration= 0;
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
int sip_send_bss_info_update(struct esp_pub *epub, struct esp_vif *evif, u8 *bssid, int assoc)
{
struct sk_buff *skb = NULL;
struct sip_cmd_bss_info_update*bsscmd;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_bss_info_update) + sizeof(struct sip_hdr), SIP_CMD_BSS_INFO_UPDATE);
if (!skb)
return -EINVAL;
bsscmd = (struct sip_cmd_bss_info_update *)(skb->data + sizeof(struct sip_hdr));
if (assoc == 2) { //hack for softAP mode
bsscmd->beacon_int = evif->beacon_interval;
} else if (assoc == 1) {
set_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags);
} else {
clear_bit(ESP_WL_FLAG_CONNECT, &epub->wl.flags);
}
bsscmd->bssid_no = evif->index;
bsscmd->isassoc= assoc;
bsscmd->beacon_int = evif->beacon_interval;
memcpy(bsscmd->bssid, bssid, ETH_ALEN);
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
int sip_send_wmm_params(struct esp_pub *epub, u8 aci, const struct ieee80211_tx_queue_params *params)
{
struct sk_buff *skb = NULL;
struct sip_cmd_set_wmm_params* bsscmd;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_set_wmm_params) + sizeof(struct sip_hdr), SIP_CMD_SET_WMM_PARAM);
if (!skb)
return -EINVAL;
bsscmd = (struct sip_cmd_set_wmm_params *)(skb->data + sizeof(struct sip_hdr));
bsscmd->aci= aci;
bsscmd->aifs=params->aifs;
bsscmd->txop_us=params->txop*32;
bsscmd->ecw_min = 32 - __builtin_clz(params->cw_min);
bsscmd->ecw_max= 32 -__builtin_clz(params->cw_max);
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
int sip_send_ampdu_action(struct esp_pub *epub, u8 action_num, const u8 * addr, u16 tid, u16 ssn, u8 buf_size)
{
int index = 0;
struct sk_buff *skb = NULL;
struct sip_cmd_ampdu_action * action;
if(action_num == SIP_AMPDU_RX_START){
index = esp_get_empty_rxampdu(epub, addr, tid);
} else if(action_num == SIP_AMPDU_RX_STOP){
index = esp_get_exist_rxampdu(epub, addr, tid);
}
if(index < 0)
return -EACCES;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_ampdu_action) + sizeof(struct sip_hdr), SIP_CMD_AMPDU_ACTION);
if(!skb)
return -EINVAL;
action = (struct sip_cmd_ampdu_action *)(skb->data + sizeof(struct sip_hdr));
action->action = action_num;
//for TX, it means interface index
action->index = ssn;
switch(action_num) {
case SIP_AMPDU_RX_START:
action->ssn = ssn;
case SIP_AMPDU_RX_STOP:
action->index = index;
case SIP_AMPDU_TX_OPERATIONAL:
case SIP_AMPDU_TX_STOP:
action->win_size = buf_size;
action->tid = tid;
memcpy(action->addr, addr, ETH_ALEN);
break;
}
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
#ifdef HW_SCAN
/*send cmd to target, if aborted is true, inform target stop scan, report scan complete imediately
return 1: complete over, 0: success, still have next scan, -1: hardware failure
*/
int sip_send_scan(struct esp_pub *epub)
{
struct cfg80211_scan_request *scan_req = epub->wl.scan_req;
struct sk_buff *skb = NULL;
struct sip_cmd_scan *scancmd;
u8 *ptr = NULL;
int i;
u8 append_len, ssid_len;
ESSERT(scan_req != NULL);
ssid_len = scan_req->n_ssids == 0 ? 0:
(scan_req->n_ssids == 1 ? scan_req->ssids->ssid_len: scan_req->ssids->ssid_len + (scan_req->ssids + 1)->ssid_len);
append_len = ssid_len + scan_req->n_channels + scan_req->ie_len;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_scan) + sizeof(struct sip_hdr) + append_len, SIP_CMD_SCAN);
if (!skb)
return -EINVAL;
ptr = skb->data;
scancmd = (struct sip_cmd_scan *)(ptr + sizeof(struct sip_hdr));
ptr += sizeof(struct sip_hdr);
scancmd->aborted= false;
if (scancmd->aborted==false) {
ptr += sizeof(struct sip_cmd_scan);
if (scan_req->n_ssids <=0 || (scan_req->n_ssids == 1&& ssid_len == 0)) {
scancmd->ssid_len = 0;
} else {
scancmd->ssid_len = ssid_len;
if(scan_req->ssids->ssid_len == ssid_len)
memcpy(ptr, scan_req->ssids->ssid, scancmd->ssid_len);
else
memcpy(ptr, (scan_req->ssids + 1)->ssid, scancmd->ssid_len);
}
ptr += scancmd->ssid_len;
scancmd->n_channels=scan_req->n_channels;
for (i=0; i<scan_req->n_channels; i++)
ptr[i] = scan_req->channels[i]->hw_value;
ptr += scancmd->n_channels;
if (scan_req->ie_len && scan_req->ie != NULL) {
scancmd->ie_len=scan_req->ie_len;
memcpy(ptr, scan_req->ie, scan_req->ie_len);
} else {
scancmd->ie_len = 0;
}
//add a flag that support two ssids,
if(scan_req->n_ssids > 1)
scancmd->ssid_len |= 0x80;
}
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
#endif
int sip_send_suspend_config(struct esp_pub *epub, u8 suspend)
{
struct sip_cmd_suspend *cmd = NULL;
struct sk_buff *skb = NULL;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_suspend) + sizeof(struct sip_hdr), SIP_CMD_SUSPEND);
if (!skb)
return -EINVAL;
cmd = (struct sip_cmd_suspend *)(skb->data + sizeof(struct sip_hdr));
cmd->suspend = suspend;
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
int sip_send_ps_config(struct esp_pub *epub, struct esp_ps *ps)
{
struct sip_cmd_ps *pscmd = NULL;
struct sk_buff *skb = NULL;
struct sip_hdr *shdr = NULL;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_ps) + sizeof(struct sip_hdr), SIP_CMD_PS);
if (!skb)
return -EINVAL;
shdr = (struct sip_hdr *)skb->data;
pscmd = (struct sip_cmd_ps *)(skb->data + sizeof(struct sip_hdr));
pscmd->dtim_period = ps->dtim_period;
pscmd->max_sleep_period = ps->max_sleep_period;
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
void sip_scandone_process(struct esp_sip *sip, struct sip_evt_scan_report *scan_report)
{
struct esp_pub *epub = sip->epub;
esp_dbg(ESP_DBG_TRACE, "eagle hw scan report\n");
if (epub->wl.scan_req) {
hw_scan_done(epub, scan_report->aborted);
epub->wl.scan_req = NULL;
}
}
int sip_send_setkey(struct esp_pub *epub, u8 bssid_no, u8 *peer_addr, struct ieee80211_key_conf *key, u8 isvalid)
{
struct sip_cmd_setkey *setkeycmd;
struct sk_buff *skb = NULL;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_setkey) + sizeof(struct sip_hdr), SIP_CMD_SETKEY);
if (!skb)
return -EINVAL;
setkeycmd = (struct sip_cmd_setkey *)(skb->data + sizeof(struct sip_hdr));
if (peer_addr) {
memcpy(setkeycmd->addr, peer_addr, ETH_ALEN);
} else {
memset(setkeycmd->addr, 0, ETH_ALEN);
}
setkeycmd->bssid_no = bssid_no;
setkeycmd->hw_key_idx= key->hw_key_idx;
if (isvalid) {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
setkeycmd->alg= key->alg;
#else
setkeycmd->alg= esp_cipher2alg(key->cipher);
#endif /* NEW_KERNEL */
setkeycmd->keyidx = key->keyidx;
setkeycmd->keylen = key->keylen;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
if (key->alg == ALG_TKIP) {
#else
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
#endif /* NEW_KERNEL */
memcpy(setkeycmd->key, key->key, 16);
memcpy(setkeycmd->key+16,key->key+24,8);
memcpy(setkeycmd->key+24,key->key+16,8);
} else {
memcpy(setkeycmd->key, key->key, key->keylen);
}
setkeycmd->flags=1;
} else {
setkeycmd->flags=0;
}
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
#ifdef FPGA_LOOPBACK
#define LOOPBACK_PKT_LEN 200
int sip_send_loopback_cmd_mblk(struct esp_sip *sip)
{
int cnt, ret;
for (cnt = 0; cnt < 4; cnt++) {
if (0!=(ret=sip_send_loopback_mblk(sip, LOOPBACK_PKT_LEN, LOOPBACK_PKT_LEN, 0)))
return ret;
}
return 0;
}
#endif /* FPGA_LOOPBACK */
int sip_send_loopback_mblk(struct esp_sip *sip, int txpacket_len, int rxpacket_len, int packet_id)
{
struct sk_buff *skb = NULL;
struct sip_cmd_loopback *cmd;
u8 *ptr = NULL;
int i, ret;
//send 100 loopback pkt
if(txpacket_len)
skb = sip_alloc_ctrl_skbuf(sip, sizeof(struct sip_cmd_loopback) + sizeof(struct sip_hdr) + txpacket_len, SIP_CMD_LOOPBACK);
else
skb = sip_alloc_ctrl_skbuf(sip, sizeof(struct sip_cmd_loopback) + sizeof(struct sip_hdr), SIP_CMD_LOOPBACK);
if (!skb)
return -ENOMEM;
ptr = skb->data;
cmd = (struct sip_cmd_loopback *)(ptr + sizeof(struct sip_hdr));
ptr += sizeof(struct sip_hdr);
cmd->txlen = txpacket_len;
cmd->rxlen = rxpacket_len;
cmd->pack_id = packet_id;
if (txpacket_len) {
ptr += sizeof(struct sip_cmd_loopback);
/* fill up pkt payload */
for (i = 0; i < txpacket_len; i++) {
ptr[i] = i;
}
}
ret = sip_cmd_enqueue(sip, skb, ENQUEUE_PRIOR_TAIL);
if (ret <0)
return ret;
return 0;
}
//remain_on_channel
int sip_send_roc(struct esp_pub *epub, u16 center_freq, u16 duration)
{
struct sk_buff *skb = NULL;
struct sip_cmd_config *configcmd;
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_config) + sizeof(struct sip_hdr), SIP_CMD_CONFIG);
if (!skb)
return -EINVAL;
configcmd = (struct sip_cmd_config *)(skb->data + sizeof(struct sip_hdr));
configcmd->center_freq= center_freq;
configcmd->duration= duration;
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set, struct ieee80211_sta *sta, struct ieee80211_vif *vif, u8 index)
#else
int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set, struct esp_node *node, struct ieee80211_vif *vif, u8 index)
#endif
{
struct sk_buff *skb = NULL;
struct sip_cmd_setsta *setstacmd;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
struct ieee80211_ht_info ht_info = node->ht_info;
#endif
skb = sip_alloc_ctrl_skbuf(epub->sip, sizeof(struct sip_cmd_setsta) + sizeof(struct sip_hdr), SIP_CMD_SETSTA);
if (!skb)
return -EINVAL;
setstacmd = (struct sip_cmd_setsta *)(skb->data + sizeof(struct sip_hdr));
setstacmd->ifidx = ifidx;
setstacmd->index = index;
setstacmd->set = set;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
if(sta->aid == 0)
setstacmd->aid = vif->bss_conf.aid;
else
setstacmd->aid = sta->aid;
memcpy(setstacmd->mac, sta->addr, ETH_ALEN);
if(set){
if(sta->ht_cap.ht_supported){
if(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
setstacmd->phymode = ESP_IEEE80211_T_HT20_S;
else
setstacmd->phymode = ESP_IEEE80211_T_HT20_L;
setstacmd->ampdu_factor = sta->ht_cap.ampdu_factor;
setstacmd->ampdu_density = sta->ht_cap.ampdu_density;
} else {
if(sta->supp_rates[IEEE80211_BAND_2GHZ] & (~(u32)CONF_HW_BIT_RATE_11B_MASK)){
setstacmd->phymode = ESP_IEEE80211_T_OFDM;
} else {
setstacmd->phymode = ESP_IEEE80211_T_CCK;
}
}
}
#else
setstacmd->aid = node->aid;
memcpy(setstacmd->mac, node->addr, ETH_ALEN);
if(set){
if(ht_info.ht_supported){
if(ht_info.cap & IEEE80211_HT_CAP_SGI_20)
setstacmd->phymode = ESP_IEEE80211_T_HT20_S;
else
setstacmd->phymode = ESP_IEEE80211_T_HT20_L;
setstacmd->ampdu_factor = ht_info.ampdu_factor;
setstacmd->ampdu_density = ht_info.ampdu_density;
} else {
//note supp_rates is u64[] in 2.6.27
if(node->supp_rates[IEEE80211_BAND_2GHZ] & (~(u64)CONF_HW_BIT_RATE_11B_MASK)){
setstacmd->phymode = ESP_IEEE80211_T_OFDM;
} else {
setstacmd->phymode = ESP_IEEE80211_T_CCK;
}
}
}
#endif
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}
int sip_send_recalc_credit(struct esp_pub *epub)
{
struct sk_buff *skb = NULL;
skb = sip_alloc_ctrl_skbuf(epub->sip, 0 + sizeof(struct sip_hdr), SIP_CMD_RECALC_CREDIT);
if (!skb)
return -ENOMEM;
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_HEAD);
}
int sip_cmd(struct esp_pub *epub, enum sip_cmd_id cmd_id, u8 *cmd_buf, u8 cmd_len)
{
struct sk_buff *skb = NULL;
skb = sip_alloc_ctrl_skbuf(epub->sip, cmd_len + sizeof(struct sip_hdr), cmd_id);
if (!skb)
return -ENOMEM;
memcpy(skb->data + sizeof(struct sip_hdr), cmd_buf, cmd_len);
return sip_cmd_enqueue(epub->sip, skb, ENQUEUE_PRIOR_TAIL);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2009- 2014 Espressif System.
*
* SIP ctrl packet parse and pack
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_CTRL_H_
#define _ESP_CTRL_H_
int sip_send_loopback_mblk(struct esp_sip *sip, int txpacket_len, int rxpacket_len, int packet_id);
int sip_send_config(struct esp_pub *epub, struct ieee80211_conf * conf);
int sip_send_setkey(struct esp_pub *epub, u8 bssid_no, u8 *peer_addr, struct ieee80211_key_conf *key, u8 isvalid);
int sip_send_scan(struct esp_pub *epub);
void sip_scandone_process(struct esp_sip *sip, struct sip_evt_scan_report *scan_report);
int sip_send_bss_info_update(struct esp_pub *epub, struct esp_vif *evif, u8 *bssid, int assoc);
int sip_send_wmm_params(struct esp_pub *epub, u8 aci, const struct ieee80211_tx_queue_params *params);
int sip_send_ampdu_action(struct esp_pub *epub, u8 action_num, const u8 * addr, u16 tid, u16 ssn, u8 buf_size);
int sip_send_roc(struct esp_pub *epub, u16 center_freq, u16 duration);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set, struct ieee80211_sta *sta, struct ieee80211_vif *vif, u8 index);
#else
int sip_send_set_sta(struct esp_pub *epub, u8 ifidx, u8 set, struct esp_node *node, struct ieee80211_vif *vif, u8 index);
#endif
int sip_send_suspend_config(struct esp_pub *epub, u8 suspend);
int sip_send_ps_config(struct esp_pub *epub, struct esp_ps *ps);
int sip_parse_events(struct esp_sip *sip, u8 *buf);
int sip_send_recalc_credit(struct esp_pub *epub);
int sip_cmd(struct esp_pub *epub, enum sip_cmd_id cmd_id, u8 *cmd_buf, u8 cmd_len);
#endif /* _ESP_CTRL_H_ */

View File

@@ -0,0 +1,304 @@
/*
* Copyright (c) 2011-2014 Espressif System.
*
* esp debug interface
* - debugfs
* - debug level control
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <net/mac80211.h>
#include "sip2_common.h"
#include "esp_debug.h"
#if defined(CONFIG_DEBUG_FS) && defined(DEBUG_FS)
static struct dentry *esp_debugfs_root = NULL;
static int esp_debugfs_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
}
static ssize_t esp_debugfs_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
if (*ppos >= 32)
return 0;
if (*ppos + count > 32)
count = 32 - *ppos;
if (copy_to_user(buffer, filp->private_data + *ppos, count))
return -EFAULT;
*ppos += count;
return count;
}
static ssize_t esp_debugfs_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
if (*ppos >= 32)
return 0;
if (*ppos + count > 32)
count = 32 - *ppos;
if (copy_from_user(filp->private_data + *ppos, buffer, count))
return -EFAULT;
*ppos += count;
return count;
}
struct file_operations esp_debugfs_fops = {
.owner = THIS_MODULE,
.open = esp_debugfs_open,
.read = esp_debugfs_read,
.write = esp_debugfs_write,
};
struct dentry *esp_dump_var(const char *name, struct dentry *parent, void *value, esp_type type) {
struct dentry *rc = NULL;
umode_t mode = 0644;
if(!esp_debugfs_root)
return NULL;
if(!parent)
parent = esp_debugfs_root;
switch(type) {
case ESP_U8:
rc = debugfs_create_u8(name, mode, parent, (u8*)value);
break;
case ESP_U16:
rc = debugfs_create_u16(name, mode, parent, (u16*)value);
break;
case ESP_U32:
rc = debugfs_create_u32(name, mode, parent, (u32*)value);
break;
case ESP_U64:
rc = debugfs_create_u64(name, mode, parent, (u64*)value);
break;
case ESP_BOOL:
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
rc = debugfs_create_bool(name, mode, parent, (u32*)value);
#else
rc = debugfs_create_bool(name, mode, parent, (bool*)value);
#endif
break;
default: //32
rc = debugfs_create_u32(name, mode, parent, (u32*)value);
}
if (!rc)
goto Fail;
else
return rc;
Fail:
debugfs_remove_recursive(esp_debugfs_root);
esp_debugfs_root = NULL;
esp_dbg(ESP_DBG_ERROR, "%s failed, debugfs root removed; var name: %s\n", __FUNCTION__, name);
return NULL;
}
struct dentry *esp_dump_array(const char *name, struct dentry *parent, struct debugfs_blob_wrapper *blob) {
struct dentry * rc = NULL;
umode_t mode = 0644;
if(!esp_debugfs_root)
return NULL;
if(!parent)
parent = esp_debugfs_root;
rc = debugfs_create_blob(name, mode, parent, blob);
if (!rc)
goto Fail;
else
return rc;
Fail:
debugfs_remove_recursive(esp_debugfs_root);
esp_debugfs_root = NULL;
esp_dbg(ESP_DBG_ERROR, "%s failed, debugfs root removed; var name: %s\n", __FUNCTION__, name);
return NULL;
}
struct dentry *esp_dump(const char *name, struct dentry *parent, void *data, int size) {
struct dentry *rc;
umode_t mode = 0644;
if(!esp_debugfs_root)
return NULL;
if(!parent)
parent = esp_debugfs_root;
rc = debugfs_create_file(name, mode, parent, data, &esp_debugfs_fops);
if (!rc)
goto Fail;
else
return rc;
Fail:
debugfs_remove_recursive(esp_debugfs_root);
esp_debugfs_root = NULL;
esp_dbg(ESP_DBG_ERROR, "%s failed, debugfs root removed; var name: %s\n", __FUNCTION__, name);
return NULL;
}
struct dentry *esp_debugfs_add_sub_dir(const char *name) {
struct dentry *sub_dir = NULL;
sub_dir = debugfs_create_dir(name, esp_debugfs_root);
if (!sub_dir)
goto Fail;
return sub_dir;
Fail:
debugfs_remove_recursive(esp_debugfs_root);
esp_debugfs_root = NULL;
esp_dbg(ESP_DBG_ERROR, "%s failed, debugfs root removed; dir name: %s\n", __FUNCTION__, name);
return NULL;
}
int esp_debugfs_init(void)
{
esp_dbg(ESP_DBG, "esp debugfs init\n");
esp_debugfs_root = debugfs_create_dir("esp_debug", NULL);
if (!esp_debugfs_root || IS_ERR_OR_NULL(esp_debugfs_root)) {
return -ENOENT;
}
return 0;
}
void esp_debugfs_exit(void)
{
esp_dbg(ESP_DBG, "esp debugfs exit");
debugfs_remove_recursive(esp_debugfs_root);
return;
}
#else
inline struct dentry *esp_dump_var(const char *name, struct dentry *parent, void *value, esp_type type) {
return NULL;
}
inline struct dentry *esp_dump_array(const char *name, struct dentry *parent, struct debugfs_blob_wrapper *blob) {
return NULL;
}
inline struct dentry *esp_dump(const char *name, struct dentry *parent, void *data, int size) {
return NULL;
}
struct dentry *esp_debugfs_add_sub_dir(const char *name) {
return NULL;
}
inline int esp_debugfs_init(void)
{
return -EPERM;
}
inline void esp_debugfs_exit(void)
{
}
#endif
void show_buf(u8 *buf, u32 len)
{
// print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
#if 1
int i = 0, j;
printk(KERN_INFO "\n++++++++++++++++show rbuf+++++++++++++++\n");
for (i = 0; i < (len / 16); i++) {
j = i * 16;
printk(KERN_INFO "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x \n", buf[j], buf[j+1],buf[j+2],buf[j+3],buf[j+4],buf[j+5],buf[j+6],buf[j+7],buf[j+8],buf[j+9],buf[j+10],buf[j+11],buf[j+12],buf[j+13],buf[j+14],buf[j+15]);
}
printk(KERN_INFO "\n++++++++++++++++++++++++++++++++++++++++\n");
#endif//0000
}
#ifdef HOST_RC
static u8 get_cnt(u32 cnt_store, int idx)
{
int shift = idx << 2;
return (u8)((cnt_store>>shift) & 0xf);
}
void esp_show_rcstatus(struct sip_rc_status *rcstatus)
{
int i;
char msg[82];
char rcstr[16];
u32 cnt_store = rcstatus->rc_cnt_store;
memset(msg, 0 ,sizeof(msg));
memset(rcstr, 0 ,sizeof(rcstr));
printk(KERN_INFO "rcstatus map 0x%08x cntStore 0x%08x\n", rcstatus->rc_map, rcstatus->rc_cnt_store);
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
if (rcstatus->rc_map & BIT(i)) {
sprintf(rcstr, "rcIdx %d, cnt %d ", i, get_cnt(cnt_store, i));
strcat(msg, rcstr);
}
}
printk(KERN_INFO "%s \n", msg);
}
void esp_show_tx_rates(struct ieee80211_tx_rate* rates)
{
int i;
char msg[128];
char rcstr[32];
memset(msg, 0 ,sizeof(msg));
memset(rcstr, 0 ,sizeof(rcstr));
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
if (rates->idx != -1 ) {
sprintf(rcstr, "Idx %d, cnt %d, flag %02x ", rates->idx, rates->count, rates->flags);
strcat(msg, rcstr);
}
rates++;
}
strcat(msg, "\n");
printk(KERN_INFO "%s \n", msg);
}
#endif /* HOST_RC */

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2011-2014 Espressif System.
*
* esp debug
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _DEBUG_H_
#ifdef ASSERT_PANIC
#define ESSERT(v) BUG_ON(!(v))
#else
#define ESSERT(v) if(!(v)) printk("ESSERT:%s %d\n", __FILE__, __LINE__)
#endif
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <asm/uaccess.h>
typedef enum esp_type {
ESP_BOOL,
ESP_U8,
ESP_U16,
ESP_U32,
ESP_U64
} esp_type;
struct dentry *esp_dump_var(const char *name, struct dentry *parent, void *value, esp_type type);
struct dentry *esp_dump_array(const char *name, struct dentry *parent, struct debugfs_blob_wrapper *blob);
struct dentry *esp_dump(const char *name, struct dentry *parent, void *data, int size);
struct dentry *esp_debugfs_add_sub_dir(const char *name);
int esp_debugfs_init(void);
void esp_debugfs_exit(void);
enum {
ESP_DBG_ERROR = BIT(0),
ESP_DBG_TRACE = BIT(1),
ESP_DBG_LOG = BIT(2),
ESP_DBG = BIT(3),
ESP_SHOW = BIT(4),
ESP_DBG_TXAMPDU = BIT(5),
ESP_DBG_OP = BIT(6),
ESP_DBG_PS = BIT(7),
ESP_ATE = BIT(8),
ESP_DBG_ALL = 0xffffffff
};
extern unsigned int esp_msg_level;
#ifdef ESP_ANDROID_LOGGER
extern bool log_off;
#endif /* ESP_ANDROID_LOGGER */
#ifdef ESP_ANDROID_LOGGER
#include "esp_file.h"
#define esp_dbg(mask, fmt, args...) do {\
if (esp_msg_level & mask) \
{ \
if (log_off) \
printk(fmt, ##args); \
else \
logger_write(4, "esp_wifi", fmt, ##args);\
} \
} while (0)
#else
#define esp_dbg(mask, fmt, args...) do {\
if (esp_msg_level & mask) \
printk(fmt, ##args); \
} while (0)
#endif /* ESP_ANDROID_LOGGER */
void show_buf(u8 *buf, u32 len);
#ifdef HOST_RC
struct sip_rc_status;
struct ieee80211_tx_rate;
void esp_show_rcstatus(struct sip_rc_status *rcstatus);
void esp_show_tx_rates(struct ieee80211_tx_rate *rates);
#endif /* HOST_RC */
#endif /* _DEBUG_H_ */

View File

@@ -0,0 +1,495 @@
/*
* Copyright (c) 2010 -2013 Espressif System.
*
* extended gpio
* - interface for other driver or kernel
* - gpio control
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef USE_EXT_GPIO
#include <net/cfg80211.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/version.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
#include <linux/completion.h>
#include "esp_ext.h"
#include "esp_debug.h"
#include "esp_sip.h"
#include "esp_sif.h"
#ifdef EXT_GPIO_OPS
extern void register_ext_gpio_ops(struct esp_ext_gpio_ops *ops);
extern void unregister_ext_gpio_ops(void);
static struct esp_ext_gpio_ops ext_gpio_ops = {
.gpio_request = ext_gpio_request, /* gpio_request gpio_no from 0x0 to 0xf*/
.gpio_release = ext_gpio_release, /* gpio_release */
.gpio_set_mode = ext_gpio_set_mode, /* gpio_set_mode, data is irq_func of irq_mode , default level of output_mode */
.gpio_get_mode = ext_gpio_get_mode, /* gpio_get_mode, current mode */
.gpio_set_state = ext_gpio_set_output_state, /* only output state, high level or low level */
.gpio_get_state = ext_gpio_get_state, /* current state */
.irq_ack = ext_irq_ack, /* ack interrupt */
};
#endif
static struct esp_pub *ext_epub = NULL;
static u16 intr_mask_reg = 0x0000;
struct workqueue_struct *ext_irq_wkq = NULL;
struct work_struct ext_irq_work;
static struct mutex ext_mutex_lock;
static struct ext_gpio_info gpio_list[EXT_GPIO_MAX_NUM] = {
{ 0, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 1, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 2, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 3, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 4, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 5, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 6, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 7, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 8, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{ 9, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{10, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{11, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{12, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{13, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{14, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
{15, EXT_GPIO_MODE_DISABLE, EXT_GPIO_STATE_IDLE, NULL},
};
static struct pending_intr_list_info esp_pending_intr_list = {
.start_pos = 0,
.end_pos = 0,
.curr_num = 0,
};
u16 ext_gpio_get_int_mask_reg(void)
{
return intr_mask_reg;
}
int ext_gpio_request(int gpio_no)
{
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_ERROR, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
return -ERANGE;
}
if (gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_DISABLE) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s gpio is already in used by other\n", __func__);
return -EPERM;
} else {
gpio_list[gpio_no].gpio_mode = EXT_GPIO_MODE_MAX;
mutex_unlock(&ext_mutex_lock);
return 0;
}
}
EXPORT_SYMBOL(ext_gpio_request);
int ext_gpio_release(int gpio_no)
{
int ret;
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_ERROR, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
return -ERANGE;
}
sif_lock_bus(ext_epub);
ret = sif_config_gpio_mode(ext_epub, (u8)gpio_no, EXT_GPIO_MODE_DISABLE);
sif_unlock_bus(ext_epub);
if (ret) {
esp_dbg(ESP_DBG_ERROR, "%s gpio release error\n", __func__);
mutex_unlock(&ext_mutex_lock);
return ret;
}
gpio_list[gpio_no].gpio_mode = EXT_GPIO_MODE_DISABLE;
gpio_list[gpio_no].gpio_state = EXT_GPIO_STATE_IDLE;
gpio_list[gpio_no].irq_handler = NULL;
intr_mask_reg &= ~(1<<gpio_no);
mutex_unlock(&ext_mutex_lock);
return 0;
}
EXPORT_SYMBOL(ext_gpio_release);
int ext_gpio_set_mode(int gpio_no, int mode, void *data)
{
u8 gpio_mode;
int ret;
struct ext_gpio_info backup_info;
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
return -ERANGE;
}
if (gpio_list[gpio_no].gpio_mode == EXT_GPIO_MODE_DISABLE) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s gpio is not in occupy, please request gpio\n", __func__);
return -ENOTRECOVERABLE;
}
if (mode <= EXT_GPIO_MODE_OOB || mode >= EXT_GPIO_MODE_MAX) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s gpio mode unknown\n", __func__);
return -EOPNOTSUPP;
}
memcpy(&backup_info, &gpio_list[gpio_no], sizeof(struct ext_gpio_info));
gpio_list[gpio_no].gpio_mode = mode;
gpio_mode = (u8)mode;
switch (mode) {
case EXT_GPIO_MODE_INTR_POSEDGE:
case EXT_GPIO_MODE_INTR_NEGEDGE:
case EXT_GPIO_MODE_INTR_LOLEVEL:
case EXT_GPIO_MODE_INTR_HILEVEL:
if (!data) {
memcpy(&gpio_list[gpio_no], &backup_info, sizeof(struct ext_gpio_info));
esp_dbg(ESP_DBG_ERROR, "%s irq_handler is NULL\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -EINVAL;
}
gpio_list[gpio_no].irq_handler = (ext_irq_handler_t)data;
intr_mask_reg |= (1<<gpio_no);
break;
case EXT_GPIO_MODE_OUTPUT:
if (!data) {
memcpy(&gpio_list[gpio_no], &backup_info, sizeof(struct ext_gpio_info));
esp_dbg(ESP_DBG_ERROR, "%s output default value is NULL\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -EINVAL;
}
*(int *)data = (*(int *)data == 0 ? 0 : 1);
gpio_mode = (u8)(((*(int *)data)<<4) | gpio_mode);
default:
gpio_list[gpio_no].irq_handler = NULL;
intr_mask_reg &= ~(1<<gpio_no);
break;
}
sif_lock_bus(ext_epub);
ret = sif_config_gpio_mode(ext_epub, (u8)gpio_no, gpio_mode);
sif_unlock_bus(ext_epub);
if (ret) {
memcpy(&gpio_list[gpio_no], &backup_info, sizeof(struct ext_gpio_info));
esp_dbg(ESP_DBG_ERROR, "%s gpio set error\n", __func__);
mutex_unlock(&ext_mutex_lock);
return ret;
}
mutex_unlock(&ext_mutex_lock);
return 0;
}
EXPORT_SYMBOL(ext_gpio_set_mode);
int ext_gpio_get_mode(int gpio_no)
{
int gpio_mode;
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -ERANGE;
}
gpio_mode = gpio_list[gpio_no].gpio_mode;
mutex_unlock(&ext_mutex_lock);
return gpio_mode;
}
EXPORT_SYMBOL(ext_gpio_get_mode);
int ext_gpio_set_output_state(int gpio_no, int state)
{
int ret;
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
return -ERANGE;
}
if (gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_OUTPUT) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s gpio is not in output state, please request gpio or set output state\n", __func__);
return -EOPNOTSUPP;
}
if (state != EXT_GPIO_STATE_LOW && state != EXT_GPIO_STATE_HIGH) {
mutex_unlock(&ext_mutex_lock);
esp_dbg(ESP_DBG_ERROR, "%s gpio state unknown\n", __func__);
return -ENOTRECOVERABLE;
}
sif_lock_bus(ext_epub);
ret = sif_set_gpio_output(ext_epub, 1<<gpio_no, state<<gpio_no);
sif_unlock_bus(ext_epub);
if (ret) {
esp_dbg(ESP_DBG_ERROR, "%s gpio state set error\n", __func__);
mutex_unlock(&ext_mutex_lock);
return ret;
}
gpio_list[gpio_no].gpio_state = state;
mutex_unlock(&ext_mutex_lock);
return 0;
}
EXPORT_SYMBOL(ext_gpio_set_output_state);
int ext_gpio_get_state(int gpio_no)
{
int ret;
u16 state;
u16 mask;
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -ERANGE;
}
if (gpio_list[gpio_no].gpio_mode == EXT_GPIO_MODE_OUTPUT) {
state = gpio_list[gpio_no].gpio_state;
} else if (gpio_list[gpio_no].gpio_mode == EXT_GPIO_MODE_INPUT) {
sif_lock_bus(ext_epub);
ret = sif_get_gpio_input(ext_epub, &mask, &state);
sif_unlock_bus(ext_epub);
if (ret) {
esp_dbg(ESP_DBG_ERROR, "%s get gpio_input state error\n", __func__);
mutex_unlock(&ext_mutex_lock);
return ret;
}
} else {
esp_dbg(ESP_DBG_ERROR, "%s gpio_state is not input or output\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -EOPNOTSUPP;
}
mutex_unlock(&ext_mutex_lock);
return (state & (1<<gpio_no)) ? 1 : 0;
}
EXPORT_SYMBOL(ext_gpio_get_state);
int ext_irq_ack(int gpio_no)
{
int ret;
if (ext_epub == NULL || ext_epub->sip == NULL ||
atomic_read(&ext_epub->sip->state) != SIP_RUN) {
esp_dbg(ESP_DBG_LOG, "%s esp state is not ok\n", __func__);
return -ENOTRECOVERABLE;
}
mutex_lock(&ext_mutex_lock);
if (gpio_no >= EXT_GPIO_MAX_NUM || gpio_no < 0) {
esp_dbg(ESP_DBG_ERROR, "%s unkown gpio num\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -ERANGE;
}
if (gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_POSEDGE
&& gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_NEGEDGE
&& gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_LOLEVEL
&& gpio_list[gpio_no].gpio_mode != EXT_GPIO_MODE_INTR_HILEVEL) {
esp_dbg(ESP_DBG_ERROR, "%s gpio mode is not intr mode\n", __func__);
mutex_unlock(&ext_mutex_lock);
return -ENOTRECOVERABLE;
}
sif_lock_bus(ext_epub);
ret = sif_set_gpio_output(ext_epub, 0x00, 1<<gpio_no);
sif_unlock_bus(ext_epub);
if (ret) {
esp_dbg(ESP_DBG_ERROR, "%s gpio intr ack error\n", __func__);
mutex_unlock(&ext_mutex_lock);
return ret;
}
mutex_unlock(&ext_mutex_lock);
return 0;
}
EXPORT_SYMBOL(ext_irq_ack);
void show_status(void)
{
int i=0;
for (i = 0; i < MAX_PENDING_INTR_LIST;i++)
esp_dbg(ESP_DBG_ERROR, "status[%d] = [0x%04x]\n", i, esp_pending_intr_list.pending_intr_list[i]);
esp_dbg(ESP_DBG_ERROR, "start_pos[%d]\n",esp_pending_intr_list.start_pos);
esp_dbg(ESP_DBG_ERROR, "end_pos[%d]\n",esp_pending_intr_list.end_pos);
esp_dbg(ESP_DBG_ERROR, "curr_num[%d]\n",esp_pending_intr_list.curr_num);
}
void esp_tx_work(struct work_struct *work)
{
int i;
u16 tmp_intr_status_reg;
esp_dbg(ESP_DBG_TRACE, "%s enter\n", __func__);
spin_lock(&esp_pending_intr_list.spin_lock);
tmp_intr_status_reg = esp_pending_intr_list.pending_intr_list[esp_pending_intr_list.start_pos];
esp_pending_intr_list.pending_intr_list[esp_pending_intr_list.start_pos] = 0x0000;
esp_pending_intr_list.start_pos = (esp_pending_intr_list.start_pos + 1) % MAX_PENDING_INTR_LIST;
esp_pending_intr_list.curr_num--;
spin_unlock(&esp_pending_intr_list.spin_lock);
for (i = 0; i < EXT_GPIO_MAX_NUM; i++) {
if (tmp_intr_status_reg & (1<<i) && (gpio_list[i].irq_handler))
gpio_list[i].irq_handler();
}
spin_lock(&esp_pending_intr_list.spin_lock);
if (esp_pending_intr_list.curr_num > 0)
queue_work(ext_irq_wkq, &ext_irq_work);
spin_unlock(&esp_pending_intr_list.spin_lock);
}
void ext_gpio_int_process(u16 value) {
if (value == 0x00)
return;
esp_dbg(ESP_DBG_TRACE, "%s enter\n", __func__);
/* intr cycle queue is full, wait */
while (esp_pending_intr_list.curr_num >= MAX_PENDING_INTR_LIST)
{
udelay(1);
}
spin_lock(&esp_pending_intr_list.spin_lock);
esp_pending_intr_list.pending_intr_list[esp_pending_intr_list.end_pos] = value;
esp_pending_intr_list.end_pos = (esp_pending_intr_list.end_pos + 1) % MAX_PENDING_INTR_LIST;
esp_pending_intr_list.curr_num++;
queue_work(ext_irq_wkq, &ext_irq_work);
spin_unlock(&esp_pending_intr_list.spin_lock);
}
int ext_gpio_init(struct esp_pub *epub)
{
esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);
ext_irq_wkq = create_singlethread_workqueue("esp_ext_irq_wkq");
if (ext_irq_wkq == NULL) {
esp_dbg(ESP_DBG_ERROR, "%s create workqueue error\n", __func__);
return -EACCES;
}
INIT_WORK(&ext_irq_work, esp_tx_work);
mutex_init(&ext_mutex_lock);
ext_epub = epub;
if (ext_epub == NULL)
return -EINVAL;
#ifdef EXT_GPIO_OPS
register_ext_gpio_ops(&ext_gpio_ops);
#endif
return 0;
}
void ext_gpio_deinit(void)
{
esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);
#ifdef EXT_GPIO_OPS
unregister_ext_gpio_ops();
#endif
ext_epub = NULL;
cancel_work_sync(&ext_irq_work);
if (ext_irq_wkq)
destroy_workqueue(ext_irq_wkq);
}
#endif /* USE_EXT_GPIO */

View File

@@ -0,0 +1,100 @@
#ifdef USE_EXT_GPIO
#ifndef _ESP_EXT_H_
#define _ESP_EXT_H_
#include <linux/interrupt.h>
#include <linux/module.h>
#include "esp_sip.h"
#define MAX_PENDING_INTR_LIST 16
#ifdef EXT_GPIO_OPS
typedef struct esp_ext_gpio_ops {
int (*gpio_request)(int gpio_no); /* gpio_request gpio_no from 0x0 to 0xf*/
int (*gpio_release)(int gpio_no); /* gpio_release */
int (*gpio_set_mode)(int gpio_no, int mode , void *data); /* gpio_set_mode, data is irq_func of irq_mode , default level of output_mode */
int (*gpio_get_mode)(int gpio_no); /* gpio_get_mode, current mode */
int (*gpio_set_state)(int gpio_no, int state); /* only output state, high level or low level */
int (*gpio_get_state)(int gpio_no); /* current state */
int (*irq_ack)(int gpio_no); /* ack interrupt */
} esp_ext_gpio_ops_t;
#endif
typedef enum EXT_GPIO_NO {
EXT_GPIO_GPIO0 = 0,
EXT_GPIO_U0TXD,
EXT_GPIO_GPIO2,
EXT_GPIO_U0RXD,
EXT_GPIO_GPIO4,
EXT_GPIO_GPIO5,
EXT_GPIO_SD_CLK,
EXT_GPIO_SD_DATA0,
EXT_GPIO_SD_DATA1,
EXT_GPIO_SD_DATA2,
EXT_GPIO_SD_DATA3,
EXT_GPIO_SD_CMD,
EXT_GPIO_MTDI,
EXT_GPIO_MTCK,
EXT_GPIO_MTMS,
EXT_GPIO_MTDO,
EXT_GPIO_MAX_NUM
} EXT_GPIO_NO_T;
typedef enum EXT_GPIO_MODE { //dir def pullup mode wake
EXT_GPIO_MODE_OOB = 0, //output 1 0 n/a n/a
EXT_GPIO_MODE_OUTPUT, //output / 0 n/a n/a
EXT_GPIO_MODE_DISABLE, //input n/a 0 DIS n/a
EXT_GPIO_MODE_INTR_POSEDGE, //input n/a 0 POS 1
EXT_GPIO_MODE_INTR_NEGEDGE, //input n/a 1 NEG 1
EXT_GPIO_MODE_INPUT, //input n/a 0 ANY 1
EXT_GPIO_MODE_INTR_LOLEVEL, //input n/a 1 LOW 1
EXT_GPIO_MODE_INTR_HILEVEL, //input n/a 0 HIGH 1
EXT_GPIO_MODE_MAX,
} EXT_GPIO_MODE_T;
typedef enum EXT_GPIO_STATE {
EXT_GPIO_STATE_LOW,
EXT_GPIO_STATE_HIGH,
EXT_GPIO_STATE_IDLE
} EXT_GPIO_STATE_T;
typedef irqreturn_t (*ext_irq_handler_t)(void);
struct ext_gpio_info {
int gpio_no;
int gpio_mode;
int gpio_state;
ext_irq_handler_t irq_handler;
};
struct pending_intr_list_info {
u16 pending_intr_list[MAX_PENDING_INTR_LIST];
int start_pos;
int end_pos;
int curr_num;
spinlock_t spin_lock;
};
u16 ext_gpio_get_int_mask_reg(void);
/* for extern user start */
int ext_gpio_request(int gpio_no);
int ext_gpio_release(int gpio_no);
int ext_gpio_set_mode(int gpio_no, int mode, void *data);
int ext_gpio_get_mode(int gpio_no);
int ext_gpio_set_output_state(int gpio_no, int state);
int ext_gpio_get_state(int gpio_no);
int ext_irq_ack(int gpio_no);
/* for extern user end */
void ext_gpio_int_process(u16 value);
int ext_gpio_init(struct esp_pub *epub);
void ext_gpio_deinit(void);
#endif /* _ESP_EXT_H_ */
#endif /* USE_EXT_GPIO */

View File

@@ -0,0 +1,419 @@
/*
* Copyright (c) 2010 -2014 Espressif System.
*
* file operation in kernel space
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
#include <linux/aio.h>
#include "esp_file.h"
#include "esp_debug.h"
#include "esp_sif.h"
#include "esp_path.h"
#include "esp_conf.h"
int esp_readwrite_file(const char *filename, char *rbuf, const char *wbuf, size_t length)
{
int ret = 0;
struct file *filp = (struct file *)-ENOENT;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(KERNEL_DS);
do {
int mode = (wbuf) ? O_RDWR | O_CREAT : O_RDONLY;
filp = filp_open(filename, mode, (S_IRUSR | S_IWUSR));
if (IS_ERR(filp) || !filp->f_op) {
esp_dbg(ESP_DBG_ERROR, "%s: file %s filp_open error\n", __FUNCTION__, filename);
ret = -ENOENT;
break;
}
if (length==0) {
/* Read the length of the file only */
struct inode *inode;
inode = GET_INODE_FROM_FILEP(filp);
if (!inode) {
esp_dbg(ESP_DBG_ERROR, "%s: Get inode from %s failed\n", __FUNCTION__, filename);
ret = -ENOENT;
break;
}
ret = i_size_read(inode->i_mapping->host);
break;
}
if (wbuf) {
if ( (ret=vfs_write(filp, wbuf, length, &filp->f_pos)) < 0) {
esp_dbg(ESP_DBG_ERROR, "%s: Write %u bytes to file %s error %d\n", __FUNCTION__,
(unsigned int)length, filename, ret);
break;
}
} else {
if ( (ret=filp->f_op->read(filp, rbuf, length, &filp->f_pos)) < 0) {
esp_dbg(ESP_DBG_ERROR, "%s: Read %u bytes from file %s error %d\n", __FUNCTION__,
(unsigned int)length, filename, ret);
break;
}
}
} while (0);
if (!IS_ERR(filp)) {
filp_close(filp, NULL);
}
set_fs(oldfs);
return ret;
}
int esp_request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device)
{
int ret = 0;
struct firmware *firmware;
char filename[256];
const char *raw_filename = name;
*firmware_p = firmware = kmalloc((sizeof(*firmware)), GFP_KERNEL);
if (!firmware)
return -ENOMEM;
memset(firmware, 0, sizeof(*firmware));
if (mod_eagle_path_get() == NULL)
sprintf(filename, "%s/%s", FWPATH, raw_filename);
else
sprintf(filename, "%s/%s", mod_eagle_path_get(), raw_filename);
do {
size_t length, bufsize, bmisize;
if ( (ret=esp_readwrite_file(filename, NULL, NULL, 0)) < 0) {
break;
} else {
length = ret;
}
bufsize = ALIGN(length, PAGE_SIZE);
bmisize = E_ROUND_UP(length, 4);
bufsize = max(bmisize, bufsize);
firmware->data = vmalloc(bufsize);
firmware->size = length;
if (!firmware->data) {
esp_dbg(ESP_DBG_ERROR, "%s: Cannot allocate buffer for firmware\n", __FUNCTION__);
ret = -ENOMEM;
break;
}
if ( (ret=esp_readwrite_file(filename, (char*)firmware->data, NULL, length)) != length) {
esp_dbg(ESP_DBG_ERROR, "%s: file read error, ret %d request %d\n", __FUNCTION__, ret, (unsigned int)length);
ret = -1;
break;
}
} while (0);
if (ret<0) {
if (firmware) {
if (firmware->data)
vfree(firmware->data);
kfree(firmware);
}
*firmware_p = NULL;
} else {
ret = 0;
}
return ret;
}
void esp_release_firmware(const struct firmware *firmware)
{
if (firmware) {
if (firmware->data)
vfree(firmware->data);
kfree((struct firmware *)firmware);
}
}
#ifdef ESP_ANDROID_LOGGER
int logger_write( const unsigned char prio,
const char __kernel * const tag,
const char __kernel * const fmt,
...)
{
int ret = 0;
va_list vargs;
struct file *filp = (struct file *)-ENOENT;
mm_segment_t oldfs;
struct iovec vec[3];
int tag_bytes = strlen(tag) + 1, msg_bytes;
char *msg;
va_start(vargs, fmt);
msg = kvasprintf(GFP_ATOMIC, fmt, vargs);
va_end(vargs);
if (!msg)
return -ENOMEM;
if (in_interrupt()) {
/* we have no choice since aio_write may be blocked */
printk(KERN_ALERT "%s", msg);
goto out_free_message;
}
msg_bytes = strlen(msg) + 1;
if (msg_bytes <= 1) /* empty message? */
goto out_free_message; /* don't bother, then */
if ((msg_bytes + tag_bytes + 1) > 2048) {
ret = -E2BIG;
goto out_free_message;
}
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
vec[1].iov_len = strlen(tag) + 1;
vec[2].iov_base = (void *) msg;
vec[2].iov_len = strlen(msg) + 1;
oldfs = get_fs();
set_fs(KERNEL_DS);
do {
filp = filp_open("/dev/log/main", O_WRONLY, S_IRUSR);
if (IS_ERR(filp) || !filp->f_op) {
esp_dbg(ESP_DBG_ERROR, "%s: filp open /dev/log/main error\n", __FUNCTION__);
ret = -ENOENT;
break;
}
if (filp->f_op->aio_write) {
int nr_segs = sizeof(vec) / sizeof(vec[0]);
int len = vec[0].iov_len + vec[1].iov_len + vec[2].iov_len;
struct kiocb kiocb;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = 0;
kiocb.ki_left = len;
kiocb.ki_nbytes = len;
ret = filp->f_op->aio_write(&kiocb, vec, nr_segs, kiocb.ki_pos);
}
} while (0);
if (!IS_ERR(filp)) {
filp_close(filp, NULL);
}
set_fs(oldfs);
out_free_message:
if (msg) {
kfree(msg);
}
return ret;
}
#endif
struct esp_init_table_elem esp_init_table[MAX_ATTR_NUM] = {
{"crystal_26M_en", 48, -1},
{"test_xtal", 49, -1},
{"sdio_configure", 50, -1},
{"bt_configure", 51, -1},
{"bt_protocol", 52, -1},
{"dual_ant_configure", 53, -1},
{"test_uart_configure", 54, -1},
{"share_xtal", 55, -1},
{"gpio_wake", 56, -1},
{"no_auto_sleep", 57, -1},
{"speed_suspend", 58, -1},
{"attr11", -1, -1},
{"attr12", -1, -1},
{"attr13", -1, -1},
{"attr14", -1, -1},
{"attr15", -1, -1},
//attr that is not send to target
{"ext_rst", -1, -1},
{"wakeup_gpio", -1, -1},
{"ate_test", -1, -1},
{"attr19", -1, -1},
{"attr20", -1, -1},
{"attr21", -1, -1},
{"attr22", -1, -1},
{"attr23", -1, -1},
};
int esp_atoi(char *str)
{
int num = 0;
int ng_flag = 0;
if (*str == '-') {
str++;
ng_flag = 1;
}
while(*str != '\0') {
num = num * 10 + *str++ - '0';
}
return ng_flag ? 0-num : num;
}
void show_esp_init_table(struct esp_init_table_elem *econf)
{
int i;
for (i = 0; i < MAX_ATTR_NUM; i++)
if (esp_init_table[i].offset > -1)
esp_dbg(ESP_DBG_ERROR, "%s: esp_init_table[%d] attr[%s] offset[%d] value[%d]\n",
__FUNCTION__, i,
esp_init_table[i].attr,
esp_init_table[i].offset,
esp_init_table[i].value);
}
int request_init_conf(void)
{
u8 *conf_buf;
u8 *pbuf;
int flag;
int str_len;
int length;
int ret;
int i;
char attr_name[CONF_ATTR_LEN];
char num_buf[CONF_VAL_LEN];
#ifdef INIT_DATA_CONF
char filename[256];
if (mod_eagle_path_get() == NULL)
sprintf(filename, "%s/%s", FWPATH, INIT_CONF_FILE);
else
sprintf(filename, "%s/%s", mod_eagle_path_get(), INIT_CONF_FILE);
if ((ret=esp_readwrite_file(filename, NULL, NULL, 0)) < 0 || ret > MAX_BUF_LEN) {
esp_dbg(ESP_DBG_ERROR, "%s: file read length error, ret %d\n", __FUNCTION__, ret);
return ret;
} else {
length = ret;
}
#endif /* INIT_DATA_CONF */
conf_buf = (u8 *)kmalloc(MAX_BUF_LEN, GFP_KERNEL);
if (conf_buf == NULL) {
esp_dbg(ESP_DBG_ERROR, "%s: failed kmalloc memory for read init_data_conf", __func__);
return -ENOMEM;
}
#ifdef INIT_DATA_CONF
if ((ret=esp_readwrite_file(filename, conf_buf, NULL, length)) != length) {
esp_dbg(ESP_DBG_ERROR, "%s: file read error, ret %d request %d\n", __FUNCTION__, ret, length);
goto failed;
}
#else
length = strlen(INIT_DATA_CONF_BUF);
strncpy(conf_buf, INIT_DATA_CONF_BUF, length);
#endif
conf_buf[length] = '\0';
flag = 0;
str_len = 0;
for (pbuf = conf_buf; *pbuf != '$' && *pbuf != '\n'; pbuf++) {
if (*pbuf == '=') {
flag = 1;
*(attr_name+str_len) = '\0';
str_len = 0;
continue;
}
if (*pbuf == ';') {
int value;
flag = 0;
*(num_buf+str_len) = '\0';
if((value = esp_atoi(num_buf)) > 255 || value < 0){
esp_dbg(ESP_DBG_ERROR, "%s: value is too big", __FUNCTION__);
goto failed;
}
for (i = 0; i < MAX_ATTR_NUM; i++) {
if (strcmp(esp_init_table[i].attr, attr_name) == 0) {
esp_dbg(ESP_DBG_TRACE, "%s: attr_name[%s]", __FUNCTION__, attr_name); /* add by th */
esp_init_table[i].value = value;
}
if (esp_init_table[i].value < 0)
continue;
if(strcmp(esp_init_table[i].attr, "share_xtal") == 0){
sif_record_bt_config(esp_init_table[i].value);
}
if(strcmp(esp_init_table[i].attr, "ext_rst") == 0){
sif_record_rst_config(esp_init_table[i].value);
}
if(strcmp(esp_init_table[i].attr, "wakeup_gpio") == 0){
sif_record_wakeup_gpio_config(esp_init_table[i].value);
}
if(strcmp(esp_init_table[i].attr, "ate_test") == 0){
sif_record_ate_config(esp_init_table[i].value);
}
}
str_len = 0;
continue;
}
if (flag == 0) {
*(attr_name+str_len) = *pbuf;
if (++str_len > CONF_ATTR_LEN) {
esp_dbg(ESP_DBG_ERROR, "%s: attr len is too long", __FUNCTION__);
goto failed;
}
} else {
*(num_buf+str_len) = *pbuf;
if (++str_len > CONF_VAL_LEN) {
esp_dbg(ESP_DBG_ERROR, "%s: value len is too long", __FUNCTION__);
goto failed;
}
}
}
//show_esp_init_table(esp_init_table);
ret = 0;
failed:
if (conf_buf)
kfree(conf_buf);
return ret;
}
void fix_init_data(u8 *init_data_buf, int buf_size)
{
int i;
for (i = 0; i < MAX_FIX_ATTR_NUM; i++) {
if (esp_init_table[i].offset > -1 && esp_init_table[i].offset < buf_size && esp_init_table[i].value > -1) {
*(u8 *)(init_data_buf + esp_init_table[i].offset) = esp_init_table[i].value;
} else if (esp_init_table[i].offset > buf_size) {
esp_dbg(ESP_DBG_ERROR, "%s: offset[%d] longer than init_data_buf len[%d] Ignore\n", __FUNCTION__, esp_init_table[i].offset, buf_size);
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2010 -2014 Espressif System.
*
* file operation in kernel space
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_FILE_H_
#define _ESP_FILE_H_
#include <linux/version.h>
#include <linux/firmware.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
#define GET_INODE_FROM_FILEP(filp) \
(filp)->f_path.dentry->d_inode
#else
#define GET_INODE_FROM_FILEP(filp) \
(filp)->f_dentry->d_inode
#endif
#define E_ROUND_UP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
int esp_readwrite_file(const char *filename, char *rbuf, const char *wbuf, size_t length);
int esp_request_firmware(const struct firmware **firmware_p, const char *name, struct device *device);
void esp_release_firmware(const struct firmware *firmware);
#ifdef INIT_DATA_CONF
#define INIT_CONF_FILE "init_data.conf"
#endif /* def INIT_DATA_CONF */
#define CONF_ATTR_LEN 24
#define CONF_VAL_LEN 3
#define MAX_ATTR_NUM 24
#define MAX_FIX_ATTR_NUM 16
#define MAX_BUF_LEN ((CONF_ATTR_LEN + CONF_VAL_LEN + 2) * MAX_ATTR_NUM + 2)
struct esp_init_table_elem {
char attr[CONF_ATTR_LEN];
int offset;
short value;
};
int request_init_conf(void);
void fix_init_data(u8 *init_data_buf, int buf_size);
#ifdef ESP_ANDROID_LOGGER
extern int logger_write( const unsigned char prio,
const char __kernel * const tag,
const char __kernel * const fmt,
...);
#endif
#endif /* _ESP_FILE_H_ */

View File

@@ -0,0 +1 @@
static char esp_init_data[] = {0x5,0x0,4,2,5,5,5,2,5,0,4,5,5,4,5,5,4,-2,-3,-1,-16,-16,-16,-32,-32,-32,204,1,0xff,0xff,0,0,0,0,82,78,74,68,64,56,0,0,1,1,2,3,4,5,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,240,10,0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

View File

@@ -0,0 +1,649 @@
/*
* Copyright (c) 2009 - 2014 Espressif System.
* IO interface
* - sdio/spi common i/f driver
* - target sdio hal
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mmc/sdio_func.h>
#include "esp_sif.h"
#include "slc_host_register.h"
#include "esp_debug.h"
#ifdef SIF_DEBUG_DSR_DUMP_REG
static void dump_slc_regs(struct slc_host_regs *regs);
#endif /* SIF_DEBUG_DSR_DUMP_REG */
int esp_common_read(struct esp_pub *epub, u8 *buf, u32 len, int sync, bool noround)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_lldesc_read_sync(epub, buf, len);
#endif
#ifdef ESP_USE_SPI
return sif_spi_read_sync(epub, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_lldesc_read_raw(epub, buf, len, noround);
#endif
#ifdef ESP_USE_SPI
return sif_spi_read_nosync(epub, buf, len, NOT_DUMMYMODE, noround);
#endif
}
}
int esp_common_write(struct esp_pub *epub, u8 *buf, u32 len, int sync)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_lldesc_write_sync(epub, buf, len);
#endif
#ifdef ESP_USE_SPI
return sif_spi_write_sync(epub, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_lldesc_write_raw(epub, buf, len);
#endif
#ifdef ESP_USE_SPI
return sif_spi_write_nosync(epub, buf, len, NOT_DUMMYMODE);
#endif
}
}
int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, int sync)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_io_sync(epub, addr, buf, len, SIF_FROM_DEVICE | SIF_SYNC | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_sync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_io_raw(epub, addr, buf, len, SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_nosync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
}
}
int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, int sync)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_io_sync(epub, addr, buf, len, SIF_TO_DEVICE | SIF_SYNC | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_sync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_io_raw(epub, addr, buf, len, SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_nosync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
}
}
int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, int sync)
{
if(sync){
#ifdef ESP_USE_SDIO
int res;
sif_lock_bus(epub);
*buf = sdio_io_readb(epub, addr, &res);
sif_unlock_bus(epub);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_sync(epub, addr, buf, 1, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
int res;
*buf = sdio_io_readb(epub, addr, &res);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_nosync(epub, addr, buf, 1, NOT_DUMMYMODE);
#endif
}
}
int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf, int sync)
{
if(sync){
#ifdef ESP_USE_SDIO
int res;
sif_lock_bus(epub);
sdio_io_writeb(epub, buf, addr, &res);
sif_unlock_bus(epub);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_sync(epub, addr, &buf, 1, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
int res;
sdio_io_writeb(epub, buf, addr, &res);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_nosync(epub, addr, &buf, 1, NOT_DUMMYMODE);
#endif
}
}
int sif_read_reg_window(struct esp_pub *epub, unsigned int reg_addr, u8 *value)
{
u8 *p_tbuf = NULL;
int ret = 0;
int retry = 20;
reg_addr >>= 2;
if(reg_addr > 0x1f)
return -1;
p_tbuf = kzalloc(4, GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
p_tbuf[0] = 0x80 | (reg_addr & 0x1f);
ret = esp_common_write_with_addr(epub, SLC_HOST_WIN_CMD, p_tbuf, 1, ESP_SIF_NOSYNC);
if(ret == 0)
{
do{
if(retry < 20)
mdelay(10);
retry --;
ret = esp_common_read_with_addr(epub, SLC_HOST_STATE_W0, p_tbuf, 4, ESP_SIF_NOSYNC);
}while(retry >0 && ret != 0);
}
if(ret ==0)
memcpy(value,p_tbuf,4);
kfree(p_tbuf);
return ret;
}
int sif_write_reg_window(struct esp_pub *epub, unsigned int reg_addr,u8 *value)
{
u8 *p_tbuf = NULL;
int ret = 0;
reg_addr >>= 2;
if(reg_addr > 0x1f)
return -1;
p_tbuf = kzalloc(8, GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
memcpy(p_tbuf,value,4);
p_tbuf[4] = 0xc0 |(reg_addr & 0x1f);
ret = esp_common_write_with_addr(epub, SLC_HOST_CONF_W5, p_tbuf, 5, ESP_SIF_NOSYNC);
kfree(p_tbuf);
return ret;
}
int sif_ack_target_read_err(struct esp_pub *epub)
{
u32 value[1];
int ret;
ret = sif_read_reg_window(epub, SLC_RX_LINK, (u8 *)value);
if(ret)
return ret;
value[0] |= SLC_RXLINK_START;
ret = sif_write_reg_window(epub, SLC_RX_LINK, (u8 *)value);
return ret;
}
int sif_had_io_enable(struct esp_pub *epub)
{
u32 *p_tbuf = NULL;
int ret;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = SLC_TXEOF_ENA | (0x4 << SLC_FIFO_MAP_ENA_S) | SLC_TX_DUMMY_MODE | SLC_HDA_MAP_128K | (0xFE << SLC_TX_PUSH_IDLE_NUM_S);
ret = sif_write_reg_window(epub, SLC_BRIDGE_CONF, (u8 *)p_tbuf);
if(ret)
goto _err;
*p_tbuf = 0x30;
ret = esp_common_write_with_addr((epub), SLC_HOST_CONF_W4 + 1, (u8 *)p_tbuf, 1, ESP_SIF_NOSYNC);
if(ret)
goto _err;
//set w3 0
*p_tbuf = 0x1;
ret = esp_common_write_with_addr((epub), SLC_HOST_CONF_W3, (u8 *)p_tbuf, 1, ESP_SIF_NOSYNC);
_err:
kfree(p_tbuf);
return ret;
}
typedef enum _SDIO_INTR_MODE {
SDIO_INTR_IB = 0,
SDIO_INTR_OOB_TOGGLE,
SDIO_INTR_OOB_HIGH_LEVEL,
SDIO_INTR_OOB_LOW_LEVEL,
} SDIO_INTR_MODE;
#define GEN_GPIO_SEL(_gpio_num, _sel_func, _intr_mode, _offset) (((_offset)<< 9 ) |((_intr_mode) << 7)|((_sel_func) << 4)|(_gpio_num))
//bit[3:0] = gpio num, 2
//bit[6:4] = gpio sel func, 0
//bit[8:7] = gpio intr mode, SDIO_INTR_OOB_TOGGLE
//bit[15:9] = register offset, 0x38
u16 gpio_sel_sets[17] = {
GEN_GPIO_SEL(0, 0, SDIO_INTR_OOB_TOGGLE, 0x34),//GPIO0
GEN_GPIO_SEL(1, 3, SDIO_INTR_OOB_TOGGLE, 0x18),//U0TXD
GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38),//GPIO2
GEN_GPIO_SEL(3, 3, SDIO_INTR_OOB_TOGGLE, 0x14),//U0RXD
GEN_GPIO_SEL(4, 0, SDIO_INTR_OOB_TOGGLE, 0x3C),//GPIO4
GEN_GPIO_SEL(5, 0, SDIO_INTR_OOB_TOGGLE, 0x40),//GPIO5
GEN_GPIO_SEL(6, 3, SDIO_INTR_OOB_TOGGLE, 0x1C),//SD_CLK
GEN_GPIO_SEL(7, 3, SDIO_INTR_OOB_TOGGLE, 0x20),//SD_DATA0
GEN_GPIO_SEL(8, 3, SDIO_INTR_OOB_TOGGLE, 0x24),//SD_DATA1
GEN_GPIO_SEL(9, 3, SDIO_INTR_OOB_TOGGLE, 0x28),//SD_DATA2
GEN_GPIO_SEL(10, 3, SDIO_INTR_OOB_TOGGLE, 0x2C),//SD_DATA3
GEN_GPIO_SEL(11, 3, SDIO_INTR_OOB_TOGGLE, 0x30),//SD_CMD
GEN_GPIO_SEL(12, 3, SDIO_INTR_OOB_TOGGLE, 0x04),//MTDI
GEN_GPIO_SEL(13, 3, SDIO_INTR_OOB_TOGGLE, 0x08),//MTCK
GEN_GPIO_SEL(14, 3, SDIO_INTR_OOB_TOGGLE, 0x0C),//MTMS
GEN_GPIO_SEL(15, 3, SDIO_INTR_OOB_TOGGLE, 0x10),//MTDO
//pls do not change sel before, if you want to change intr mode,change the one blow
//GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38)
GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_LOW_LEVEL, 0x38)
};
#if defined(USE_EXT_GPIO)
u16 gpio_forbidden = 0;
#endif
int sif_interrupt_target(struct esp_pub *epub, u8 index)
{
u8 low_byte = BIT(index);
return esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W4 + 2, low_byte, ESP_SIF_NOSYNC);
}
#ifdef USE_EXT_GPIO
int sif_config_gpio_mode(struct esp_pub *epub, u8 gpio_num, u8 gpio_mode)
{
u32 *p_tbuf = NULL;
int err;
if((BIT(gpio_num) & gpio_forbidden) || gpio_num > 15)
return -EINVAL;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = (gpio_mode << 16) | gpio_sel_sets[gpio_num];
err = esp_common_write_with_addr(epub, SLC_HOST_CONF_W1, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
kfree(p_tbuf);
if (err)
return err;
return sif_interrupt_target(epub, 4);
}
int sif_set_gpio_output(struct esp_pub *epub, u16 mask, u16 value)
{
u32 *p_tbuf = NULL;
int err;
mask &= ~gpio_forbidden;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = (mask << 16) | value;
err = esp_common_write_with_addr(epub, SLC_HOST_CONF_W2, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
kfree(p_tbuf);
if (err)
return err;
return sif_interrupt_target(epub, 5);
}
int sif_get_gpio_intr(struct esp_pub *epub, u16 intr_mask, u16 *value)
{
u32 *p_tbuf = NULL;
int err;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = 0;
err = esp_common_read_with_addr(epub, SLC_HOST_CONF_W3, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
if (err){
kfree(p_tbuf);
return err;
}
*value = *p_tbuf & intr_mask;
kfree(p_tbuf);
if(*value == 0)
return 0;
return sif_interrupt_target(epub, 6);
}
int sif_get_gpio_input(struct esp_pub *epub, u16 *mask, u16 *value)
{
u32 *p_tbuf = NULL;
int err;
err = sif_interrupt_target(epub, 3);
if (err)
return err;
udelay(20);
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = 0;
err = esp_common_read_with_addr(epub, SLC_HOST_CONF_W3, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
if (err){
kfree(p_tbuf);
return err;
}
*mask = *p_tbuf >> 16;
*value = *p_tbuf & *mask;
kfree(p_tbuf);
return 0;
}
#endif
void check_target_id(struct esp_pub *epub)
{
u32 date;
int err = 0;
int i;
EPUB_CTRL_CHECK(epub, _err);
sif_lock_bus(epub);
for(i = 0; i < 4; i++) {
err = esp_common_readbyte_with_addr(epub, SLC_HOST_DATE + i, (u8 *)&date + i, ESP_SIF_NOSYNC);
err = esp_common_readbyte_with_addr(epub, SLC_HOST_ID + i, (u8 *)&EPUB_TO_CTRL(epub)->target_id + i, ESP_SIF_NOSYNC);
}
sif_unlock_bus(epub);
esp_dbg(ESP_DBG_LOG, "\n\n \t\t SLC data 0x%08x, ID 0x%08x\n\n", date, EPUB_TO_CTRL(epub)->target_id);
switch(EPUB_TO_CTRL(epub)->target_id) {
case 0x100:
EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000;
break;
case 0x600:
EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000 - 0x800;
do{
u16 gpio_sel;
u8 low_byte = 0;
u8 high_byte = 0;
u8 byte2 = 0;
u8 byte3 = 0;
#ifdef USE_OOB_INTR
gpio_sel = gpio_sel_sets[16];
low_byte = gpio_sel;
high_byte = gpio_sel >> 8;
#ifdef USE_EXT_GPIO
gpio_forbidden |= BIT(gpio_sel & 0xf);
#endif /* USE_EXT_GPIO */
#endif /* USE_OOB_INTR */
if(sif_get_bt_config() == 1 && sif_get_rst_config() != 1){
u8 gpio_num = sif_get_wakeup_gpio_config();
gpio_sel = gpio_sel_sets[gpio_num];
byte2 = gpio_sel;
byte3 = gpio_sel >> 8;
#ifdef USE_EXT_GPIO
gpio_forbidden |= BIT(gpio_num);
#endif
}
sif_lock_bus(epub);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1, low_byte, ESP_SIF_NOSYNC);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 1, high_byte, ESP_SIF_NOSYNC);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 2, byte2, ESP_SIF_NOSYNC);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 3, byte3, ESP_SIF_NOSYNC);
sif_unlock_bus(epub);
}while(0);
break;
default:
EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000;
break;
}
_err:
return;
}
u32 sif_get_blksz(struct esp_pub *epub)
{
EPUB_CTRL_CHECK(epub, _err);
return EPUB_TO_CTRL(epub)->slc_blk_sz;
_err:
return 512;
}
u32 sif_get_target_id(struct esp_pub *epub)
{
EPUB_CTRL_CHECK(epub, _err);
return EPUB_TO_CTRL(epub)->target_id;
_err:
return 0x600;
}
#ifdef ESP_USE_SDIO
void sif_dsr(struct sdio_func *func)
{
struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
#else
void sif_dsr(struct spi_device *spi)
{
struct esp_spi_ctrl *sctrl = spi_get_drvdata(spi);
u32 buf[1];
#endif
static int dsr_cnt = 0, real_intr_cnt = 0, bogus_intr_cnt = 0;
struct slc_host_regs *regs = &(sctrl->slc_regs);
esp_dbg(ESP_DBG_TRACE, " %s enter %d \n", __func__, dsr_cnt++);
#ifdef ESP_USE_SPI
if(sctrl->epub->wait_reset == 1)
{
mdelay(50);
return;
}
if(sctrl->epub->enable_int == 1)
{
sif_read_reg_window(sctrl->epub, SLC_INT_ENA, (u8 *)buf);
buf[0] &= ~(SLC_RX_EOF_INT_ENA);
buf[0] |= SLC_FRHOST_BIT2_INT_ENA;
sif_write_reg_window(sctrl->epub, SLC_INT_ENA, (u8 *)buf);
sctrl->epub->enable_int = 0;
}
#endif
atomic_set(&sctrl->irq_handling, 1);
#ifdef ESP_USE_SDIO
sdio_release_host(sctrl->func);
#endif
sif_lock_bus(sctrl->epub);
do {
int ret =0;
memset(regs, 0x0, sizeof(struct slc_host_regs));
ret = esp_common_read_with_addr(sctrl->epub, REG_SLC_HOST_BASE + 8, (u8 *)regs, sizeof(struct slc_host_regs), ESP_SIF_NOSYNC);
if ( (regs->intr_raw & SLC_HOST_RX_ST) && (ret == 0) ) {
esp_dbg(ESP_DBG_TRACE, "%s eal intr cnt: %d", __func__, ++real_intr_cnt);
esp_dsr(sctrl->epub);
} else {
#ifdef ESP_ACK_INTERRUPT
sif_platform_ack_interrupt(sctrl->epub);
#endif //ESP_ACK_INTERRUPT
sif_unlock_bus(sctrl->epub);
esp_dbg(ESP_DBG_TRACE, "%s bogus_intr_cnt %d\n", __func__, ++bogus_intr_cnt);
}
#ifdef SIF_DEBUG_DSR_DUMP_REG
dump_slc_regs(regs);
#endif /* SIF_DEBUG_DUMP_DSR */
} while (0);
#ifdef ESP_USE_SDIO
sdio_claim_host(func);
#endif
atomic_set(&sctrl->irq_handling, 0);
}
struct slc_host_regs * sif_get_regs(struct esp_pub *epub)
{
EPUB_CTRL_CHECK(epub, _err);
return &EPUB_TO_CTRL(epub)->slc_regs;
_err:
return NULL;
}
void sif_disable_target_interrupt(struct esp_pub *epub)
{
EPUB_FUNC_CHECK(epub, _exit);
sif_lock_bus(epub);
#ifdef HOST_RESET_BUG
mdelay(10);
#endif
memset(EPUB_TO_CTRL(epub)->dma_buffer, 0x00, sizeof(u32));
esp_common_write_with_addr(epub, SLC_HOST_INT_ENA, EPUB_TO_CTRL(epub)->dma_buffer, sizeof(u32), ESP_SIF_NOSYNC);
#ifdef HOST_RESET_BUG
mdelay(10);
#endif
sif_unlock_bus(epub);
mdelay(1);
sif_lock_bus(epub);
sif_interrupt_target(epub, 7);
sif_unlock_bus(epub);
_exit:
return;
}
#ifdef SIF_DEBUG_DSR_DUMP_REG
static void dump_slc_regs(struct slc_host_regs *regs)
{
esp_dbg(ESP_DBG_TRACE, "\n\n ------- %s --------------\n", __func__);
esp_dbg(ESP_DBG_TRACE, " \
intr_raw 0x%08X \t \n \
state_w0 0x%08X \t state_w1 0x%08X \n \
config_w0 0x%08X \t config_w1 0x%08X \n \
intr_status 0x%08X \t config_w2 0x%08X \n \
config_w3 0x%08X \t config_w4 0x%08X \n \
token_wdata 0x%08X \t intr_clear 0x%08X \n \
intr_enable 0x%08X \n\n", regs->intr_raw, \
regs->state_w0, regs->state_w1, regs->config_w0, regs->config_w1, \
regs->intr_status, \
regs->config_w2, regs->config_w3, regs->config_w4, regs->token_wdata, \
regs->intr_clear, regs->intr_enable);
}
#endif /* SIF_DEBUG_DSR_DUMP_REG */
static int bt_config = 0;
void sif_record_bt_config(int value)
{
bt_config = value;
}
int sif_get_bt_config(void)
{
return bt_config;
}
static int rst_config = 0;
void sif_record_rst_config(int value)
{
rst_config = value;
}
int sif_get_rst_config(void)
{
return rst_config;
}
static int ate_test = 0;
void sif_record_ate_config(int value)
{
ate_test =value;
}
int sif_get_ate_config(void)
{
return ate_test;
}
static int retry_reset = 0;
void sif_record_retry_config(void)
{
retry_reset = 1;
}
int sif_get_retry_config(void)
{
return retry_reset;
}
static int wakeup_gpio = 12;
void sif_record_wakeup_gpio_config(int value)
{
wakeup_gpio = value;
}
int sif_get_wakeup_gpio_config(void)
{
return wakeup_gpio;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2011-2014 Espressif System.
*
* MAC80211 support module
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_MAC80211_H_
#define _ESP_MAC80211_H_
struct esp_80211_wmm_ac_param {
u8 aci_aifsn; /* AIFSN, ACM, ACI */
u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
u16 txop_limit;
};
struct esp_80211_wmm_param_element {
/* Element ID 221 (0xdd); length: 24 */
/* required fields for WMM version 1 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 1 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specif QoS info */
u8 reserved; /* 0 */
struct esp_80211_wmm_ac_param ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
};
#endif /* _ESP_MAC80211_H_ */

View File

@@ -0,0 +1,269 @@
/*
* Copyright (c) 2010 - 2014 Espressif System.
*
* main routine
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/firmware.h>
#include <linux/sched.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <linux/time.h>
#include <linux/moduleparam.h>
#include "esp_pub.h"
#include "esp_sip.h"
#include "esp_sif.h"
#include "esp_debug.h"
#include "esp_file.h"
#include "esp_wl.h"
struct completion *gl_bootup_cplx = NULL;
#ifndef FPGA_DEBUG
static int esp_download_fw(struct esp_pub * epub);
#endif /* !FGPA_DEBUG */
static int modparam_no_txampdu = 0;
static int modparam_no_rxampdu = 0;
module_param_named(no_txampdu, modparam_no_txampdu, int, 0444);
MODULE_PARM_DESC(no_txampdu, "Disable tx ampdu.");
module_param_named(no_rxampdu, modparam_no_rxampdu, int, 0444);
MODULE_PARM_DESC(no_rxampdu, "Disable rx ampdu.");
static char *modparam_eagle_path = "";
module_param_named(eagle_path, modparam_eagle_path, charp, 0444);
MODULE_PARM_DESC(eagle_path, "eagle path");
bool mod_support_no_txampdu()
{
return modparam_no_txampdu;
}
bool mod_support_no_rxampdu()
{
return modparam_no_rxampdu;
}
void mod_support_no_txampdu_set(bool value)
{
modparam_no_txampdu = value;
}
char *mod_eagle_path_get(void)
{
if (modparam_eagle_path[0] == '\0')
return NULL;
return modparam_eagle_path;
}
int esp_pub_init_all(struct esp_pub *epub)
{
int ret = 0;
/* completion for bootup event poll*/
DECLARE_COMPLETION_ONSTACK(complete);
atomic_set(&epub->ps.state, ESP_PM_OFF);
if(epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT){
epub->sip = sip_attach(epub);
if (epub->sip == NULL) {
printk(KERN_ERR "%s sip alloc failed\n", __func__);
return -ENOMEM;
}
esp_dump_var("esp_msg_level", NULL, &esp_msg_level, ESP_U32);
#ifdef ESP_ANDROID_LOGGER
esp_dump_var("log_off", NULL, &log_off, ESP_U32);
#endif /* ESP_ANDROID_LOGGER */
} else {
atomic_set(&epub->sip->state, SIP_PREPARE_BOOT);
atomic_set(&epub->sip->tx_credits, 0);
}
epub->sip->to_host_seq = 0;
#ifdef TEST_MODE
if(sif_get_ate_config() != 0 && sif_get_ate_config() != 1 && sif_get_ate_config() !=6 )
{
esp_test_init(epub);
return -1;
}
#endif
#ifndef FPGA_DEBUG
ret = esp_download_fw(epub);
#ifdef ESP_USE_SPI
if(sif_get_ate_config() != 1)
epub->enable_int = 1;
#endif
#ifdef TEST_MODE
if(sif_get_ate_config() == 6)
{
sif_enable_irq(epub);
mdelay(500);
sif_disable_irq(epub);
mdelay(1000);
esp_test_init(epub);
return -1;
}
#endif
if (ret) {
esp_dbg(ESP_DBG_ERROR, "download firmware failed\n");
return ret;
}
esp_dbg(ESP_DBG_TRACE, "download firmware OK \n");
#else
sip_send_bootup(epub->sip);
#endif /* FPGA_DEBUG */
gl_bootup_cplx = &complete;
epub->wait_reset = 0;
sif_enable_irq(epub);
if(epub->sdio_state == ESP_SDIO_STATE_SECOND_INIT || sif_get_ate_config() == 1){
ret = sip_poll_bootup_event(epub->sip);
} else {
ret = sip_poll_resetting_event(epub->sip);
if (ret == 0) {
sif_lock_bus(epub);
sif_interrupt_target(epub, 7);
sif_unlock_bus(epub);
}
}
gl_bootup_cplx = NULL;
if (sif_get_ate_config() == 1)
ret = -EOPNOTSUPP;
return ret;
}
void
esp_dsr(struct esp_pub *epub)
{
sip_rx(epub);
}
struct esp_fw_hdr {
u8 magic;
u8 blocks;
u8 pad[2];
u32 entry_addr;
} __packed;
struct esp_fw_blk_hdr {
u32 load_addr;
u32 data_len;
} __packed;
#define ESP_FW_NAME1 "eagle_fw1.bin"
#define ESP_FW_NAME2 "eagle_fw2.bin"
#define ESP_FW_NAME3 "eagle_fw3.bin"
#ifndef FPGA_DEBUG
static int esp_download_fw(struct esp_pub * epub)
{
#ifndef HAS_FW
const struct firmware *fw_entry;
#endif /* !HAS_FW */
u8 * fw_buf = NULL;
u32 offset = 0;
int ret = 0;
u8 blocks;
struct esp_fw_hdr *fhdr;
struct esp_fw_blk_hdr *bhdr=NULL;
struct sip_cmd_bootup bootcmd;
#ifndef HAS_FW
if(sif_get_ate_config() == 1) {
char * esp_fw_name = ESP_FW_NAME3;
} else {
char * esp_fw_name = epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT ? ESP_FW_NAME1 : ESP_FW_NAME2;
}
ret = esp_request_firmware(&fw_entry, esp_fw_name, epub->dev);
if (ret)
return ret;
fw_buf = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
esp_release_firmware(fw_entry);
if (fw_buf == NULL) {
return -ENOMEM;
}
#else
#include "eagle_fw1.h"
#include "eagle_fw2.h"
#include "eagle_fw3.h"
if(sif_get_ate_config() == 1){
fw_buf = &eagle_fw3[0];
} else {
fw_buf = epub->sdio_state == ESP_SDIO_STATE_FIRST_INIT ? &eagle_fw1[0] : &eagle_fw2[0];
}
#endif /* HAS_FW */
fhdr = (struct esp_fw_hdr *)fw_buf;
if (fhdr->magic != 0xE9) {
esp_dbg(ESP_DBG_ERROR, "%s wrong magic! \n", __func__);
goto _err;
}
blocks = fhdr->blocks;
offset += sizeof(struct esp_fw_hdr);
while (blocks) {
bhdr = (struct esp_fw_blk_hdr *)(&fw_buf[offset]);
offset += sizeof(struct esp_fw_blk_hdr);
ret = sip_write_memory(epub->sip, bhdr->load_addr, &fw_buf[offset], bhdr->data_len);
if (ret) {
esp_dbg(ESP_DBG_ERROR, "%s Failed to write fw, err: %d\n", __func__, ret);
goto _err;
}
blocks--;
offset += bhdr->data_len;
}
/* TODO: last byte should be the checksum and skip checksum for now */
bootcmd.boot_addr = fhdr->entry_addr;
ret = sip_send_cmd(epub->sip, SIP_CMD_BOOTUP, sizeof(struct sip_cmd_bootup), &bootcmd);
if (ret) {
goto _err;
}
_err:
#ifndef HAS_FW
kfree(fw_buf);
#endif /* !HAS_FW */
return ret;
}
#endif /* !FPGA_DEBUG */

View File

@@ -0,0 +1,6 @@
#ifndef _ESP_PATH_H_
#define _ESP_PATH_H_
#define FWPATH "/system/lib/modules"
//module_param_string(fwpath, fwpath, sizeof(fwpath), 0644);
#endif /* _ESP_PATH_H_ */

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2010 -2014 Espressif System.
*
* power save control of system
*/
#ifdef CONFIG_HAS_WAKELOCK
#include <linux/wakelock.h>
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include "esp_pub.h"
#ifdef CONFIG_HAS_EARLYSUSPEND
static void esp_early_suspend(struct early_suspend *h)
{
printk("%s\n", __func__);
}
static void esp_late_resume(struct early_suspend*h)
{
printk("%s\n", __func__);
}
static struct early_suspend esp_early_suspend_ctrl = {
.suspend = esp_early_suspend,
.resume = esp_late_resume,
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20,
};
#endif /* EARLYSUSPEND */
void esp_register_early_suspend(void)
{
#ifdef CONFIG_HAS_EARLYSUSPEND
register_early_suspend(&esp_early_suspend_ctrl);
#endif
}
void esp_unregister_early_suspend(void)
{
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&esp_early_suspend_ctrl);
#endif
}
#ifdef CONFIG_HAS_WAKELOCK
static struct wake_lock esp_wake_lock_;
#endif /* WAKELOCK */
void esp_wakelock_init(void)
{
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_init(&esp_wake_lock_, WAKE_LOCK_SUSPEND, "eagle");
#endif
}
void esp_wakelock_destroy(void)
{
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_destroy(&esp_wake_lock_);
#endif
}
void esp_wake_lock(void)
{
#ifdef CONFIG_HAS_WAKELOCK
wake_lock(&esp_wake_lock_);
#endif
}
void esp_wake_unlock(void)
{
#ifdef CONFIG_HAS_WAKELOCK
wake_unlock(&esp_wake_lock_);
#endif
}

View File

@@ -0,0 +1,254 @@
/*
* Copyright (c) 2011-2014 Espressif System.
*
* wlan device header file
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_PUB_H_
#define _ESP_PUB_H_
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/firmware.h>
#include <linux/sched.h>
#include <net/mac80211.h>
#include <net/cfg80211.h>
#include <linux/nl80211.h>
#include <linux/version.h>
#include "sip2_common.h"
// to support kernel < 2.6.28 there's no ieee80211_sta
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
#include <net/wireless.h>
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
enum ieee80211_band {
IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ,
IEEE80211_BAND_60GHZ = NL80211_BAND_60GHZ,
/* keep last */
IEEE80211_NUM_BANDS
};
#endif
enum esp_sdio_state{
ESP_SDIO_STATE_FIRST_INIT,
ESP_SDIO_STATE_FIRST_NORMAL_EXIT,
ESP_SDIO_STATE_FIRST_ERROR_EXIT,
ESP_SDIO_STATE_SECOND_INIT,
ESP_SDIO_STATE_SECOND_ERROR_EXIT,
};
enum esp_tid_state {
ESP_TID_STATE_INIT,
ESP_TID_STATE_TRIGGER,
ESP_TID_STATE_PROGRESS,
ESP_TID_STATE_OPERATIONAL,
ESP_TID_STATE_WAIT_STOP,
ESP_TID_STATE_STOP,
};
struct esp_tx_tid {
u8 state;
u8 cnt;
u16 ssn;
};
#define WME_NUM_TID 16
struct esp_node {
struct esp_tx_tid tid[WME_NUM_TID];
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
struct ieee80211_sta *sta;
#else
u8 addr[ETH_ALEN];
u16 aid;
u64 supp_rates[IEEE80211_NUM_BANDS];
struct ieee80211_ht_info ht_info;
#endif
u8 ifidx;
u8 index;
};
#define WME_AC_BE 2
#define WME_AC_BK 3
#define WME_AC_VI 1
#define WME_AC_VO 0
struct llc_snap_hdr {
u8 dsap;
u8 ssap;
u8 cntl;
u8 org_code[3];
__be16 eth_type;
} __packed;
struct esp_vif {
struct esp_pub *epub;
u8 index;
u32 beacon_interval;
bool ap_up;
struct timer_list beacon_timer;
};
/* WLAN related, mostly... */
/*struct hw_scan_timeout {
struct delayed_work w;
struct ieee80211_hw *hw;
};*/
typedef struct esp_wl {
u8 bssid[ETH_ALEN];
u8 req_bssid[ETH_ALEN];
//struct hw_scan_timeout *hsd;
struct cfg80211_scan_request *scan_req;
atomic_t ptk_cnt;
atomic_t gtk_cnt;
atomic_t tkip_key_set;
/* so far only 2G band */
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
unsigned long flags;
atomic_t off;
} esp_wl_t;
typedef struct esp_hw_idx_map {
u8 mac[ETH_ALEN];
u8 flag;
} esp_hw_idx_map_t;
#define ESP_WL_FLAG_RFKILL BIT(0)
#define ESP_WL_FLAG_HW_REGISTERED BIT(1)
#define ESP_WL_FLAG_CONNECT BIT(2)
#define ESP_WL_FLAG_STOP_TXQ BIT(3)
#define ESP_PUB_MAX_VIF 2
#define ESP_PUB_MAX_STA 4 //for one interface
#define ESP_PUB_MAX_RXAMPDU 8 //for all interfaces
enum {
ESP_PM_OFF = 0,
ESP_PM_TURNING_ON,
ESP_PM_ON,
ESP_PM_TURNING_OFF, /* Do NOT change the order */
};
struct esp_ps {
u32 dtim_period;
u32 max_sleep_period;
unsigned long last_config_time;
atomic_t state;
bool nulldata_pm_on;
};
struct esp_mac_prefix {
u8 mac_index;
u8 mac_addr_prefix[3];
};
struct esp_pub {
struct device *dev;
#ifdef ESP_NO_MAC80211
struct net_device *net_dev;
struct wireless_dev *wdev;
struct net_device_stats *net_stats;
#else
struct ieee80211_hw *hw;
struct ieee80211_vif *vif;
u8 vif_slot;
#endif /* ESP_MAC80211 */
void *sif; /* serial interface control block, e.g. sdio */
enum esp_sdio_state sdio_state;
struct esp_sip *sip;
struct esp_wl wl;
struct esp_hw_idx_map hi_map[19];
struct esp_hw_idx_map low_map[ESP_PUB_MAX_VIF][2];
//u32 flags; //flags to represent rfkill switch,start
u8 roc_flags; //0: not in remain on channel state, 1: in roc state
struct work_struct tx_work; /* attach to ieee80211 workqueue */
/* latest mac80211 has multiple tx queue, but we stick with single queue now */
spinlock_t rx_lock;
spinlock_t tx_ampdu_lock;
spinlock_t rx_ampdu_lock;
spinlock_t tx_lock;
struct mutex tx_mtx;
struct sk_buff_head txq;
atomic_t txq_stopped;
struct work_struct sendup_work; /* attach to ieee80211 workqueue */
struct sk_buff_head txdoneq;
struct sk_buff_head rxq;
struct workqueue_struct *esp_wkq;
//u8 bssid[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
u32 rx_filter;
unsigned long scan_permit;
bool scan_permit_valid;
struct delayed_work scan_timeout_work;
u32 enodes_map;
u8 rxampdu_map;
u32 enodes_maps[ESP_PUB_MAX_VIF];
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
struct esp_node nodes[ESP_PUB_MAX_STA + 1];
#endif
struct esp_node * enodes[ESP_PUB_MAX_STA + 1];
struct esp_node * rxampdu_node[ESP_PUB_MAX_RXAMPDU];
u8 rxampdu_tid[ESP_PUB_MAX_RXAMPDU];
struct esp_ps ps;
int enable_int;
int wait_reset;
};
typedef struct esp_pub esp_pub_t;
struct esp_pub *esp_pub_alloc_mac80211(struct device *dev);
int esp_pub_dealloc_mac80211(struct esp_pub *epub);
int esp_register_mac80211(struct esp_pub *epub);
int esp_pub_init_all(struct esp_pub *epub);
char *mod_eagle_path_get(void);
void esp_dsr(struct esp_pub *epub);
void hw_scan_done(struct esp_pub *epub, bool aborted);
void esp_rocdone_process(struct ieee80211_hw *hw, struct sip_evt_roc *report);
void esp_ps_config(struct esp_pub *epub, struct esp_ps *ps, bool on);
void esp_register_early_suspend(void);
void esp_unregister_early_suspend(void);
void esp_wakelock_init(void);
void esp_wakelock_destroy(void);
void esp_wake_lock(void);
void esp_wake_unlock(void);
struct esp_node * esp_get_node_by_addr(struct esp_pub * epub, const u8 *addr);
struct esp_node * esp_get_node_by_index(struct esp_pub * epub, u8 index);
int esp_get_empty_rxampdu(struct esp_pub * epub, const u8 *addr, u8 tid);
int esp_get_exist_rxampdu(struct esp_pub * epub, const u8 *addr, u8 tid);
#ifdef TEST_MODE
int test_init_netlink(struct esp_sip *sip);
void test_exit_netlink(void);
void esp_test_cmd_event(u32 cmd_type, char *reply_info);
void esp_test_init(struct esp_pub *epub);
#endif
#endif /* _ESP_PUB_H_ */

View File

@@ -0,0 +1,301 @@
/*
* Copyright (c) 2011 - 2014 Espressif System.
*
* Serial I/F wrapper layer for eagle WLAN device,
* abstraction of buses like SDIO/SIP, and provides
* flow control for tx/rx layer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_SIF_H_
#define _ESP_SIF_H_
#include "esp_pub.h"
#include <linux/mmc/host.h>
#include <linux/spi/spi.h>
/*
* H/W SLC module definitions
*/
#define SIF_SLC_BLOCK_SIZE 512
/* S/W struct mapping to slc registers */
typedef struct slc_host_regs {
/* do NOT read token_rdata
*
u32 pf_data;
u32 token_rdata;
*/
u32 intr_raw;
u32 state_w0;
u32 state_w1;
u32 config_w0;
u32 config_w1;
u32 intr_status;
u32 config_w2;
u32 config_w3;
u32 config_w4;
u32 token_wdata;
u32 intr_clear;
u32 intr_enable;
} sif_slc_reg_t;
enum io_sync_type {
ESP_SIF_NOSYNC = 0,
ESP_SIF_SYNC,
};
#ifdef ESP_USE_SDIO
typedef struct esp_sdio_ctrl {
struct sdio_func *func;
#else
typedef struct esp_spi_ctrl {
struct spi_device *spi;
#endif
struct esp_pub *epub;
struct list_head free_req;
u8 *dma_buffer;
spinlock_t scat_lock;
struct list_head scat_req;
bool off;
atomic_t irq_handling;
#ifdef ESP_USE_SDIO
const struct sdio_device_id *id;
#else
const struct spi_device_id *id;
#endif
u32 slc_blk_sz;
u32 target_id;
u32 slc_window_end_addr;
struct slc_host_regs slc_regs;
atomic_t irq_installed;
#ifdef ESP_USE_SDIO
} esp_sdio_ctrl_t;
#else
} esp_spi_ctrl_t;
#endif
#ifdef ESP_USE_SPI
struct esp_spi_resp {
u32 max_dataW_resp_size;
u32 max_dataR_resp_size;
u32 max_block_dataW_resp_size;
u32 max_block_dataR_resp_size;
u32 max_cmd_resp_size;
u32 data_resp_size_w;
u32 data_resp_size_r;
u32 block_w_data_resp_size_final;
u32 block_r_data_resp_size_final;
};
#endif
#define SIF_TO_DEVICE 0x1
#define SIF_FROM_DEVICE 0x2
#define SIF_SYNC 0x00000010
#define SIF_ASYNC 0x00000020
#define SIF_BYTE_BASIS 0x00000040
#define SIF_BLOCK_BASIS 0x00000080
#define SIF_FIXED_ADDR 0x00000100
#define SIF_INC_ADDR 0x00000200
#ifdef ESP_USE_SDIO
#define EPUB_CTRL_CHECK(_epub, _go_err) do{\
if (_epub == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
if ((_epub)->sif == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
}while(0)
#define EPUB_FUNC_CHECK(_epub, _go_err) do{\
if (_epub == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
if ((_epub)->sif == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
if (((struct esp_sdio_ctrl *)(_epub)->sif)->func == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
}while(0)
#define EPUB_TO_CTRL(_epub) (((struct esp_sdio_ctrl *)(_epub)->sif))
#define EPUB_TO_FUNC(_epub) (((struct esp_sdio_ctrl *)(_epub)->sif)->func)
#endif
#ifdef ESP_USE_SPI
#define EPUB_CTRL_CHECK(_epub, _go_err) do{\
if (_epub == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
if ((_epub)->sif == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
}while(0)
#define EPUB_FUNC_CHECK(_epub, _go_err) do{\
if (_epub == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
if ((_epub)->sif == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
if (((struct esp_spi_ctrl *)(_epub)->sif)->spi == NULL) {\
ESSERT(0);\
goto _go_err;\
}\
}while(0)
#define EPUB_TO_CTRL(_epub) (((struct esp_spi_ctrl *)(_epub)->sif))
#define EPUB_TO_FUNC(_epub) (((struct esp_spi_ctrl *)(_epub)->sif)->spi)
#endif
void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res);
u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res);
void sif_enable_irq(struct esp_pub *epub);
void sif_disable_irq(struct esp_pub *epub);
void sif_disable_target_interrupt(struct esp_pub *epub);
u32 sif_get_blksz(struct esp_pub *epub);
u32 sif_get_target_id(struct esp_pub *epub);
#ifdef ESP_USE_SDIO
void sif_dsr(struct sdio_func *func);
int sif_io_raw(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag);
int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag);
int sif_io_async(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag, void * context);
int sif_lldesc_read_sync(struct esp_pub *epub, u8 *buf, u32 len);
int sif_lldesc_write_sync(struct esp_pub *epub, u8 *buf, u32 len);
int sif_lldesc_read_raw(struct esp_pub *epub, u8 *buf, u32 len, bool noround);
int sif_lldesc_write_raw(struct esp_pub *epub, u8 *buf, u32 len);
void sif_platform_check_r1_ready(struct esp_pub *epub);
#endif
#ifdef ESP_USE_SPI
enum if_dummymode {
NOT_DUMMYMODE = 0,
DUMMYMODE,
};
#ifdef REGISTER_SPI_BOARD_INFO
void sif_platform_register_board_info(void);
#endif
void sif_dsr(struct spi_device *spi);
int sif_spi_read_mix_nosync(struct spi_device *spi, unsigned int addr, unsigned char *buf, int len, int dummymode);
int sif_spi_epub_read_mix_sync(struct esp_pub *epub, unsigned int addr,unsigned char *buf, int len, int dummymode);
int sif_spi_epub_read_mix_nosync(struct esp_pub *epub, unsigned int addr,unsigned char *buf, int len, int dummymode);
int sif_spi_read_sync(struct esp_pub *epub, unsigned char *buf, int len, int dummymode);
int sif_spi_read_nosync(struct esp_pub *epub, unsigned char *buf, int len, int dummymode, bool noround);
int sif_spi_write_mix_nosync(struct spi_device *spi, unsigned int addr, unsigned char *buf, int len, int dummymode);
int sif_spi_epub_write_mix_sync(struct esp_pub *epub, unsigned int addr,unsigned char *buf, int len, int dummymode);
int sif_spi_epub_write_mix_nosync(struct esp_pub *epub, unsigned int addr,unsigned char *buf, int len, int dummymode);
int sif_spi_write_sync(struct esp_pub *epub, unsigned char *buf, int len, int dummymode);
int sif_spi_write_nosync(struct esp_pub *epub, unsigned char *buf, int len, int dummymode);
int sif_platform_get_irq_no(void);
int sif_platform_is_irq_occur(void);
void sif_platform_irq_clear(void);
void sif_platform_irq_mask(int enable_mask);
int sif_platform_irq_init(void);
void sif_platform_irq_deinit(void);
int sif_spi_write_bytes(struct spi_device *spi, unsigned int addr,unsigned char *dst, int count, int check_idle);
int sif_spi_read_bytes(struct spi_device *spi, unsigned int addr,unsigned char *dst, int count, int check_idle);
struct esp_spi_resp *sif_get_spi_resp(void);
#endif
int esp_common_read(struct esp_pub *epub, u8 *buf, u32 len, int sync, bool noround);
int esp_common_write(struct esp_pub *epub, u8 *buf, u32 len, int sync);
int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, int sync);
int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, int sync);
int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, int sync);
int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf, int sync);
int sif_read_reg_window(struct esp_pub *epub, unsigned int reg_addr, unsigned char *value);
int sif_write_reg_window(struct esp_pub *epub, unsigned int reg_addr, unsigned char *value);
int sif_ack_target_read_err(struct esp_pub *epub);
int sif_had_io_enable(struct esp_pub *epub);
struct slc_host_regs * sif_get_regs(struct esp_pub *epub);
void sif_lock_bus(struct esp_pub *epub);
void sif_unlock_bus(struct esp_pub *epub);
void sif_platform_target_poweroff(void);
void sif_platform_target_poweron(void);
void sif_platform_target_speed(int high_speed);
void sif_platform_reset_target(void);
void sif_platform_rescan_card(unsigned insert);
int sif_interrupt_target(struct esp_pub *epub, u8 index);
#ifdef USE_EXT_GPIO
int sif_config_gpio_mode(struct esp_pub *epub, u8 gpio_num, u8 gpio_mode);
int sif_set_gpio_output(struct esp_pub *epub, u16 mask, u16 value);
int sif_get_gpio_intr(struct esp_pub *epub, u16 intr_mask, u16 *value);
int sif_get_gpio_input(struct esp_pub *epub, u16 *mask, u16 *value);
#endif
void check_target_id(struct esp_pub *epub);
void sif_record_bt_config(int value);
int sif_get_bt_config(void);
void sif_record_rst_config(int value);
int sif_get_rst_config(void);
void sif_record_ate_config(int value);
int sif_get_ate_config(void);
void sif_record_retry_config(void);
int sif_get_retry_config(void);
void sif_record_wakeup_gpio_config(int value);
int sif_get_wakeup_gpio_config(void);
#ifdef ESP_ACK_INTERRUPT
//extern void sif_platform_ack_interrupt(struct mmc_host *mmc);
extern void sif_platform_ack_interrupt(struct esp_pub *epub);
#endif //ESP_ACK_INTERRUPT
#define sif_reg_read_sync(epub, addr, buf, len) sif_io_sync((epub), (addr), (buf), (len), SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR)
#define sif_reg_write_sync(epub, addr, buf, len) sif_io_sync((epub), (addr), (buf), (len), SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR)
#endif /* _ESP_SIF_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
/*
* Copyright (c) 2009- 2014 Espressif System.
*
* Serial Interconnctor Protocol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_SIP_H
#define _ESP_SIP_H
#include "sip2_common.h"
#define SIP_CTRL_CREDIT_RESERVE 2
#define SIP_PKT_MAX_LEN (1024*16)
/* 16KB on normal X86 system, should check before porting to orhters */
#define SIP_TX_AGGR_BUF_SIZE (4 * PAGE_SIZE)
#define SIP_RX_AGGR_BUF_SIZE (4 * PAGE_SIZE)
struct sk_buff;
struct sip_pkt {
struct list_head list;
u8 * buf_begin;
u32 buf_len;
u8 * buf;
};
typedef enum RECALC_CREDIT_STATE {
RECALC_CREDIT_DISABLE = 0,
RECALC_CREDIT_ENABLE = 1,
} RECALC_CREDIT_STATE;
typedef enum ENQUEUE_PRIOR {
ENQUEUE_PRIOR_TAIL = 0,
ENQUEUE_PRIOR_HEAD,
} ENQUEUE_PRIOR;
typedef enum SIP_STATE {
SIP_INIT = 0,
SIP_PREPARE_BOOT,
SIP_BOOT,
SIP_SEND_INIT,
SIP_WAIT_BOOTUP,
SIP_RUN,
SIP_SUSPEND,
SIP_STOP
} SIP_STATE;
enum sip_notifier {
SIP_TX_DONE = 1,
SIP_RX_DONE = 2,
};
#define SIP_CREDITS_LOW_THRESHOLD 64 //i.e. 4k
struct esp_sip {
struct list_head free_ctrl_txbuf;
struct list_head free_ctrl_rxbuf;
u32 rxseq; /* sip pkt seq, should match target side */
u32 txseq;
u32 txdataseq;
u8 to_host_seq;
atomic_t state;
spinlock_t lock;
atomic_t tx_credits;
atomic_t tx_ask_credit_update;
u8 * rawbuf; /* used in boot stage, free once chip is fully up */
u8 * tx_aggr_buf;
u8 * tx_aggr_write_ptr; /* update after insertion of each pkt */
u8 * tx_aggr_lastpkt_ptr;
struct mutex rx_mtx;
struct sk_buff_head rxq;
struct work_struct rx_process_work;
u16 tx_blksz;
u16 rx_blksz;
bool dump_rpbm_err;
bool sendup_rpbm_pkt;
bool rxabort_fixed;
bool support_bgscan;
u8 credit_to_reserve;
atomic_t credit_status;
struct timer_list credit_timer;
atomic_t noise_floor;
u32 tx_tot_len; /* total len for one transaction */
u32 rx_tot_len;
atomic_t rx_handling;
atomic_t tx_data_pkt_queued;
#ifndef FAST_TX_STATUS
atomic_t pending_tx_status;
#endif /* !FAST_TX_STATUS */
atomic_t data_tx_stopped;
atomic_t tx_stopped;
struct esp_pub *epub;
};
int sip_rx(struct esp_pub * epub);
//int sip_download_fw(struct esp_sip *sip, u32 load_addr, u32 boot_addr);
int sip_write_memory(struct esp_sip *, u32 addr, u8* buf, u16 len);
void sip_credit_process(struct esp_pub *, u8 credits);
int sip_send_cmd(struct esp_sip *sip, int cid, u32 cmdlen, void * cmd);
struct esp_sip * sip_attach(struct esp_pub *);
int sip_post_init(struct esp_sip *sip, struct sip_evt_bootup2 *bevt);
void sip_detach(struct esp_sip *sip);
void sip_txq_process(struct esp_pub *epub);
struct sk_buff * sip_alloc_ctrl_skbuf(struct esp_sip *sip, u16 len, u32 cid);
void sip_free_ctrl_skbuff(struct esp_sip *sip, struct sk_buff* skb);
bool sip_queue_need_stop(struct esp_sip *sip);
bool sip_queue_may_resume(struct esp_sip *sip);
bool sip_tx_data_need_stop(struct esp_sip *sip);
bool sip_tx_data_may_resume(struct esp_sip *sip);
void sip_tx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb);
void sip_rx_data_pkt_enqueue(struct esp_pub *epub, struct sk_buff *skb);
int sip_cmd_enqueue(struct esp_sip *sip, struct sk_buff *skb, int prior);
int sip_poll_bootup_event(struct esp_sip *sip);
int sip_poll_resetting_event(struct esp_sip *sip);
void sip_trigger_txq_process(struct esp_sip *sip);
void sip_send_chip_init(struct esp_sip *sip);
bool mod_support_no_txampdu(void);
bool mod_support_no_rxampdu(void);
void mod_support_no_txampdu_set(bool value);
#ifdef FPGA_DEBUG
int sip_send_bootup(struct esp_sip *sip);
#endif /* FPGA_DEBUG */
void sip_debug_show(struct esp_sip *sip);
#endif

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2009 - 2014 Espressif System.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "linux/types.h"
#include "linux/kernel.h"
#include <linux/ieee80211.h>
#include <net/mac80211.h>
#include <linux/skbuff.h>
#include <net/tcp.h>
#include <linux/ip.h>
#include <asm/checksum.h>
#include "esp_pub.h"
#include "esp_utils.h"
#include "esp_wmac.h"
#include "esp_debug.h"
/*
* Convert IEEE channel number to MHz frequency.
*/
u32 esp_ieee2mhz(u8 chan)
{
if (chan == 14)
return 2484;
if (chan < 14)
return 2407 + chan*5;
else
return 2512 + ((chan-15)*20);
//TODO, add 5GHz
}
enum {
ESP_RATE_1_LONG = 0x0,
ESP_RATE_2_LONG = 0x1,
ESP_RATE_2_SHORT = 0x5,
ESP_RATE_5_SHORT = 0x6,
ESP_RATE_5_LONG = 0x2,
ESP_RATE_11_SHORT = 0x7,
ESP_RATE_11_LONG = 0x3,
ESP_RATE_6 = 0xb,
ESP_RATE_9 = 0xf,
ESP_RATE_12 = 0xa,
ESP_RATE_18 = 0xe,
ESP_RATE_24 = 0x9,
ESP_RATE_36 = 0xd,
ESP_RATE_48 = 0x8,
ESP_RATE_54 = 0xc,
/* ESP_RATE_MCS0 =0x10,
ESP_RATE_MCS1 =0x11,
ESP_RATE_MCS2 =0x12,
ESP_RATE_MCS3 =0x13,
ESP_RATE_MCS4 =0x14,
ESP_RATE_MCS5 =0x15,
ESP_RATE_MCS6 =0x16,
ESP_RATE_MCS7 =0x17,
*/
};
static u8 esp_rate_table[20] = {
ESP_RATE_1_LONG,
ESP_RATE_2_SHORT,
ESP_RATE_5_SHORT,
ESP_RATE_11_SHORT,
ESP_RATE_6,
ESP_RATE_9,
ESP_RATE_12,
ESP_RATE_18,
ESP_RATE_24,
ESP_RATE_36,
ESP_RATE_48,
ESP_RATE_54,
/* ESP_RATE_MCS0,
ESP_RATE_MCS1,
ESP_RATE_MCS2,
ESP_RATE_MCS3,
ESP_RATE_MCS4,
ESP_RATE_MCS5,
ESP_RATE_MCS6,
ESP_RATE_MCS7,
*/
};
s8 esp_wmac_rate2idx(u8 rate)
{
int i;
if (rate == ESP_RATE_2_LONG)
return 1;
if (rate == ESP_RATE_5_LONG)
return 2;
if (rate == ESP_RATE_11_LONG)
return 3;
for (i = 0; i < 20; i++) {
if (rate == esp_rate_table[i])
return i;
}
esp_dbg(ESP_DBG_ERROR,"%s unknown rate 0x%02x \n", __func__, rate);
return 0;
}
bool esp_wmac_rxsec_error(u8 error)
{
return (error >= RX_SECOV_ERR && error <= RX_SECFIFO_TIMEOUT) || (error >= RX_WEPICV_ERR && error <= RX_WAPIMIC_ERR);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
int esp_cipher2alg(int cipher)
{
if (cipher == WLAN_CIPHER_SUITE_TKIP)
return ALG_TKIP;
if (cipher == WLAN_CIPHER_SUITE_CCMP)
return ALG_CCMP;
if (cipher == WLAN_CIPHER_SUITE_WEP40 || cipher == WLAN_CIPHER_SUITE_WEP104)
return ALG_WEP;
if (cipher == WLAN_CIPHER_SUITE_AES_CMAC)
return ALG_AES_CMAC;
//printk("%s wrong cipher 0x%x!\n",__func__,cipher);
return -1;
}
#endif /* NEW_KERNEL */
#ifdef RX_CHECKSUM_TEST
atomic_t g_iv_len;
void esp_rx_checksum_test(struct sk_buff *skb)
{
static u32 ip_err = 0;
static u32 tcp_err = 0;
struct ieee80211_hdr *pwh = (struct ieee80211_hdr *)skb->data;
int hdrlen = ieee80211_hdrlen(pwh->frame_control);
if(ieee80211_has_protected(pwh->frame_control))
hdrlen += atomic_read(&g_iv_len);
if (ieee80211_is_data(pwh->frame_control)) {
struct llc_snap_hdr * llc = (struct llc_snap_hdr *)(skb->data + hdrlen);
if (ntohs(llc->eth_type) == ETH_P_IP) {
int llclen = sizeof(struct llc_snap_hdr);
struct iphdr *iph = (struct iphdr *)(skb->data + hdrlen + llclen);
__sum16 csum_bak = iph->check;
iph->check = 0;
iph->check = ip_fast_csum(iph, iph->ihl);
if (iph->check != csum_bak) {
esp_dbg(ESP_DBG_ERROR, "total ip checksum error %d\n", ++ip_err);
}
iph->check = csum_bak;
if (iph->protocol == 0x06) {
struct tcphdr *tcph = (struct tcphdr *)(skb->data + hdrlen + llclen + iph->ihl * 4);
int datalen = skb->len - (hdrlen + llclen + iph->ihl * 4);
csum_bak = tcph->check;
tcph->check = 0;
tcph->check = tcp_v4_check(datalen, iph->saddr, iph->daddr, csum_partial((char *)tcph, datalen, 0));
if (tcph->check != csum_bak)
{
esp_dbg(ESP_DBG_ERROR, "total tcp checksum error %d\n", ++tcp_err);
}
tcph->check = csum_bak;
}
}
}
}
#endif
#ifdef GEN_ERR_CHECKSUM
void esp_gen_err_checksum(struct sk_buff *skb)
{
static u32 tx_seq = 0;
if ((tx_seq++ % 16) == 0)
{
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
if(ieee80211_has_protected(pwh->frame_control))
hdrlen += IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
struct llc_snap_hdr * llc = (struct llc_snap_hdr *)(skb->data + hdrlen);
if (ntohs(llc->eth_type) == ETH_P_IP) {
int llclen = sizeof(struct llc_snap_hdr);
struct iphdr *iph = (struct iphdr *)(skb->data + hdrlen + llclen);
iph->check = ~iph->check;
if (iph->protocol == 0x06) {
struct tcphdr *tcph = (struct tcphdr *)(skb->data + hdrlen + llclen + iph->ihl * 4);
tcph->check = ~tcph->check;
}
}
}
}
#endif
bool esp_is_ip_pkt(struct sk_buff *skb)
{
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
int hdrlen;
struct llc_snap_hdr * llc;
if (!ieee80211_is_data(hdr->frame_control))
return false;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if(ieee80211_has_protected(hdr->frame_control))
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
hdrlen += IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
#else
hdrlen += IEEE80211_SKB_CB(skb)->control.iv_len;
#endif
#ifdef RX_CHECKSUM_TEST
atomic_set(&g_iv_len, IEEE80211_SKB_CB(skb)->control.hw_key->iv_len);
#endif
if(skb->len < hdrlen + sizeof(struct llc_snap_hdr))
return false;
llc = (struct llc_snap_hdr *)(skb->data + hdrlen);
if (ntohs(llc->eth_type) != ETH_P_IP)
return false;
else
return true;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2011-2012 Espressif System.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_UTILS_H_
#define _ESP_UTILS_H_
#include "linux/types.h"
#include <linux/version.h>
#ifndef BIT
#define BIT(x) (0x1 << (x))
#endif
u32 esp_ieee2mhz(u8 chan);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
enum ieee80211_key_alg {
ALG_WEP,
ALG_TKIP,
ALG_CCMP,
ALG_AES_CMAC
};
int esp_cipher2alg(int cipher);
void esp_rx_checksum_test(struct sk_buff *skb);
void esp_gen_err_checksum(struct sk_buff *skb);
#endif /* NEW_KERNEL */
bool esp_is_ip_pkt(struct sk_buff *skb);
#endif

View File

@@ -0,0 +1 @@
#define DRIVER_VER 0xbdf5087c3debll

View File

@@ -0,0 +1,61 @@
#ifndef _ESP_WL_H_
#define _ESP_WL_H_
//#define MAX_PROBED_SSID_INDEX 9
enum {
CONF_HW_BIT_RATE_1MBPS = BIT(0),
CONF_HW_BIT_RATE_2MBPS = BIT(1),
CONF_HW_BIT_RATE_5_5MBPS = BIT(2),
CONF_HW_BIT_RATE_11MBPS = BIT(3),
CONF_HW_BIT_RATE_6MBPS = BIT(4),
CONF_HW_BIT_RATE_9MBPS = BIT(5),
CONF_HW_BIT_RATE_12MBPS = BIT(6),
CONF_HW_BIT_RATE_18MBPS = BIT(7),
CONF_HW_BIT_RATE_22MBPS = BIT(8),
CONF_HW_BIT_RATE_24MBPS = BIT(9),
CONF_HW_BIT_RATE_36MBPS = BIT(10),
CONF_HW_BIT_RATE_48MBPS = BIT(11),
CONF_HW_BIT_RATE_54MBPS = BIT(12),
CONF_HW_BIT_RATE_11B_MASK = (CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | CONF_HW_BIT_RATE_11MBPS),
};
#if 0
enum {
CONF_HW_RATE_INDEX_1MBPS = 0,
CONF_HW_RATE_INDEX_2MBPS = 1,
CONF_HW_RATE_INDEX_5_5MBPS = 2,
CONF_HW_RATE_INDEX_6MBPS = 3,
CONF_HW_RATE_INDEX_9MBPS = 4,
CONF_HW_RATE_INDEX_11MBPS = 5,
CONF_HW_RATE_INDEX_12MBPS = 6,
CONF_HW_RATE_INDEX_18MBPS = 7,
CONF_HW_RATE_INDEX_22MBPS = 8,
CONF_HW_RATE_INDEX_24MBPS = 9,
CONF_HW_RATE_INDEX_36MBPS = 10,
CONF_HW_RATE_INDEX_48MBPS = 11,
CONF_HW_RATE_INDEX_54MBPS = 12,
CONF_HW_RATE_INDEX_MAX,
};
enum {
CONF_HW_RXTX_RATE_54 = 0,
CONF_HW_RXTX_RATE_48,
CONF_HW_RXTX_RATE_36,
CONF_HW_RXTX_RATE_24,
CONF_HW_RXTX_RATE_22,
CONF_HW_RXTX_RATE_18,
CONF_HW_RXTX_RATE_12,
CONF_HW_RXTX_RATE_11,
CONF_HW_RXTX_RATE_9,
CONF_HW_RXTX_RATE_6,
CONF_HW_RXTX_RATE_5_5,
CONF_HW_RXTX_RATE_2,
CONF_HW_RXTX_RATE_1,
CONF_HW_RXTX_RATE_MAX,
CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
};
#endif
#endif /* _ESP_WL_H_ */

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2011-2012 Espressif System.
*
* MAC header
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ESP_WMAC_H_
#define _ESP_WMAC_H_
struct esp_mac_rx_ctrl {
signed rssi:8;
unsigned rate:4;
unsigned is_group:1;
unsigned:1;
unsigned sig_mode:2;
unsigned legacy_length:12;
unsigned damatch0:1;
unsigned damatch1:1;
unsigned bssidmatch0:1;
unsigned bssidmatch1:1;
unsigned MCS:7;
unsigned CWB:1;
unsigned HT_length:16;
unsigned Smoothing:1;
unsigned Not_Sounding:1;
unsigned:1;
unsigned Aggregation:1;
unsigned STBC:2;
unsigned FEC_CODING:1;
unsigned SGI:1;
unsigned rxend_state:8;
unsigned ampdu_cnt:8;
unsigned channel:4;
unsigned:4;
signed noise_floor:8;
};
struct esp_rx_ampdu_len {
unsigned substate:8;
unsigned sublen:12;
unsigned :12;
};
struct esp_tx_ampdu_entry {
u32 sub_len:12,
dili_num:7,
:1,
null_byte:2,
data:1,
enc:1,
seq:8;
};
//rxend_state flags
#define RX_PYH_ERR_MIN 0x42
#define RX_AGC_ERR_MIN 0x42
#define RX_AGC_ERR_MAX 0x47
#define RX_OFDM_ERR_MIN 0x50
#define RX_OFDM_ERR_MAX 0x58
#define RX_CCK_ERR_MIN 0x59
#define RX_CCK_ERR_MAX 0x5F
#define RX_ABORT 0x80
#define RX_SF_ERR 0x40
#define RX_FCS_ERR 0x41
#define RX_AHBOV_ERR 0xC0
#define RX_BUFOV_ERR 0xC1
#define RX_BUFINV_ERR 0xC2
#define RX_AMPDUSF_ERR 0xC3
#define RX_AMPDUBUFOV_ERR 0xC4
#define RX_MACBBFIFOOV_ERR 0xC5
#define RX_RPBM_ERR 0xC6
#define RX_BTFORCE_ERR 0xC7
#define RX_SECOV_ERR 0xE1
#define RX_SECPROT_ERR0 0xE2
#define RX_SECPROT_ERR1 0xE3
#define RX_SECKEY_ERR 0xE4
#define RX_SECCRLEN_ERR 0xE5
#define RX_SECFIFO_TIMEOUT 0xE6
#define RX_WEPICV_ERR 0xF0
#define RX_TKIPICV_ERR 0xF4
#define RX_TKIPMIC_ERR 0xF5
#define RX_CCMPMIC_ERR 0xF8
#define RX_WAPIMIC_ERR 0xFC
s8 esp_wmac_rate2idx(u8 rate);
bool esp_wmac_rxsec_error(u8 error);
#endif /* _ESP_WMAC_H_ */

View File

@@ -0,0 +1,203 @@
The esp8089 firmware files are licensed under the Apache License, Version 2.0:
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1 @@
crystal_26M_en=1;test_xtal=0;sdio_configure=2;bt_configure=0;bt_protocol=0;dual_ant_configure=0;test_uart_configure=2;share_xtal=0;gpio_wake=0;no_auto_sleep=0;ext_rst=0;wakeup_gpio=12;ate_test=0;speed_suspend=0;$

View File

@@ -0,0 +1,939 @@
/*
* Copyright (c) 2010 -2013 Espressif System.
*
* sdio serial i/f driver
* - sdio device control routines
* - sync/async DMA/PIO read/write
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef ESP_USE_SDIO
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
#include <linux/module.h>
#include <net/mac80211.h>
#include <linux/time.h>
#include <linux/pm.h>
#include "esp_pub.h"
#include "esp_sif.h"
#include "esp_sip.h"
#include "esp_debug.h"
#include "slc_host_register.h"
#include "esp_version.h"
#include "esp_ctrl.h"
#include "esp_file.h"
#ifdef USE_EXT_GPIO
#include "esp_ext.h"
#endif /* USE_EXT_GPIO */
static int /*__init*/ esp_sdio_init(void);
static void /*__exit*/ esp_sdio_exit(void);
#define ESP_DMA_IBUFSZ 2048
//unsigned int esp_msg_level = 0;
unsigned int esp_msg_level = ESP_DBG_ERROR | ESP_SHOW;
/* HdG: Note:
* 1) MMC_HAS_FORCE_DETECT_CHANGE is a hack which is set by my sunxi-wip
* tree. FIXME replace with a version check once mmc_force_detect_change()
* is added to the mainline kernel.
* 2) This version does NOT implement keep_power, the dts must mark the
* regulators as regulator-always-on and not use mmc-pwrseq for this stub
* to work.
*/
#ifndef MMC_HAS_FORCE_DETECT_CHANGE
void mmc_force_detect_change(struct mmc_host *host, unsigned long delay,
bool keep_power)
{
host->caps &= ~MMC_CAP_NONREMOVABLE;
host->caps |= MMC_CAP_NEEDS_POLL;
mmc_detect_change(host, delay);
}
#endif
static struct semaphore esp_powerup_sem;
static enum esp_sdio_state sif_sdio_state;
struct esp_sdio_ctrl *sif_sctrl = NULL;
#ifdef ESP_ANDROID_LOGGER
bool log_off = false;
#endif /* ESP_ANDROID_LOGGER */
static int esdio_power_off(struct esp_sdio_ctrl *sctrl);
static int esdio_power_on(struct esp_sdio_ctrl *sctrl);
void sif_set_clock(struct sdio_func *func, int clk);
#include "sdio_stub.c"
void sif_lock_bus(struct esp_pub *epub)
{
EPUB_FUNC_CHECK(epub, _exit);
sdio_claim_host(EPUB_TO_FUNC(epub));
_exit:
return;
}
void sif_unlock_bus(struct esp_pub *epub)
{
EPUB_FUNC_CHECK(epub, _exit);
sdio_release_host(EPUB_TO_FUNC(epub));
_exit:
return;
}
static inline bool bad_buf(u8 * buf)
{
return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
}
u8 sdio_io_readb(struct esp_pub *epub, int addr, int *res)
{
struct esp_sdio_ctrl *sctrl = NULL;
struct sdio_func *func = NULL;
sctrl = (struct esp_sdio_ctrl *)epub->sif;
func = sctrl->func;
if(func->num == 0)
return sdio_f0_readb(func, addr, res);
else
return sdio_readb(func, addr, res);
}
void sdio_io_writeb(struct esp_pub *epub, u8 value, int addr, int *res)
{
struct esp_sdio_ctrl *sctrl = NULL;
struct sdio_func *func = NULL;
sctrl = (struct esp_sdio_ctrl *)epub->sif;
func = sctrl->func;
if(func->num == 0)
sdio_f0_writeb(func, value, addr, res);
else
sdio_writeb(func, value, addr, res);
sif_platform_check_r1_ready(epub);
}
int sif_io_raw(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
{
int err = 0;
u8 *ibuf = NULL;
bool need_ibuf = false;
struct esp_sdio_ctrl *sctrl = NULL;
struct sdio_func *func = NULL;
if (epub == NULL || buf == NULL) {
ESSERT(0);
err = -EINVAL;
goto _exit;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
func = sctrl->func;
if (func == NULL) {
ESSERT(0);
err = -EINVAL;
goto _exit;
}
if (bad_buf(buf)) {
esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n", __func__, addr, len);
need_ibuf = true;
ibuf = sctrl->dma_buffer;
} else {
ibuf = buf;
}
if (flag & SIF_BLOCK_BASIS) {
/* round up for block data transcation */
}
if (flag & SIF_TO_DEVICE) {
if (need_ibuf)
memcpy(ibuf, buf, len);
if (flag & SIF_FIXED_ADDR)
err = sdio_writesb(func, addr, ibuf, len);
else if (flag & SIF_INC_ADDR) {
err = sdio_memcpy_toio(func, addr, ibuf, len);
}
sif_platform_check_r1_ready(epub);
} else if (flag & SIF_FROM_DEVICE) {
if (flag & SIF_FIXED_ADDR)
err = sdio_readsb(func, ibuf, addr, len);
else if (flag & SIF_INC_ADDR) {
err = sdio_memcpy_fromio(func, ibuf, addr, len);
}
if (!err && need_ibuf)
memcpy(buf, ibuf, len);
}
_exit:
return err;
}
int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
{
int err = 0;
u8 * ibuf = NULL;
bool need_ibuf = false;
struct esp_sdio_ctrl *sctrl = NULL;
struct sdio_func *func = NULL;
if (epub == NULL || buf == NULL) {
ESSERT(0);
err = -EINVAL;
goto _exit;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
func = sctrl->func;
if (func == NULL) {
ESSERT(0);
err = -EINVAL;
goto _exit;
}
if (bad_buf(buf)) {
esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n", __func__, addr, len);
need_ibuf = true;
ibuf = sctrl->dma_buffer;
} else {
ibuf = buf;
}
if (flag & SIF_BLOCK_BASIS) {
/* round up for block data transcation */
}
if (flag & SIF_TO_DEVICE) {
esp_dbg(ESP_DBG_TRACE, "%s to addr 0x%08x, len %d \n", __func__, addr, len);
if (need_ibuf)
memcpy(ibuf, buf, len);
sdio_claim_host(func);
if (flag & SIF_FIXED_ADDR)
err = sdio_writesb(func, addr, ibuf, len);
else if (flag & SIF_INC_ADDR) {
err = sdio_memcpy_toio(func, addr, ibuf, len);
}
sif_platform_check_r1_ready(epub);
sdio_release_host(func);
} else if (flag & SIF_FROM_DEVICE) {
esp_dbg(ESP_DBG_TRACE, "%s from addr 0x%08x, len %d \n", __func__, addr, len);
sdio_claim_host(func);
if (flag & SIF_FIXED_ADDR)
err = sdio_readsb(func, ibuf, addr, len);
else if (flag & SIF_INC_ADDR) {
err = sdio_memcpy_fromio(func, ibuf, addr, len);
}
sdio_release_host(func);
if (!err && need_ibuf)
memcpy(buf, ibuf, len);
}
_exit:
return err;
}
int sif_lldesc_read_sync(struct esp_pub *epub, u8 *buf, u32 len)
{
struct esp_sdio_ctrl *sctrl = NULL;
u32 read_len;
if (epub == NULL || buf == NULL) {
ESSERT(0);
return -EINVAL;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
switch(sctrl->target_id) {
case 0x100:
read_len = len;
break;
case 0x600:
read_len = roundup(len, sctrl->slc_blk_sz);
break;
default:
read_len = len;
break;
}
return sif_io_sync((epub), (sctrl->slc_window_end_addr - 2 - (len)), (buf), (read_len), SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}
int sif_lldesc_write_sync(struct esp_pub *epub, u8 *buf, u32 len)
{
struct esp_sdio_ctrl *sctrl = NULL;
u32 write_len;
if (epub == NULL || buf == NULL) {
ESSERT(0);
return -EINVAL;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
switch(sctrl->target_id) {
case 0x100:
write_len = len;
break;
case 0x600:
write_len = roundup(len, sctrl->slc_blk_sz);
break;
default:
write_len = len;
break;
}
return sif_io_sync((epub), (sctrl->slc_window_end_addr - (len)), (buf), (write_len), SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}
int sif_lldesc_read_raw(struct esp_pub *epub, u8 *buf, u32 len, bool noround)
{
struct esp_sdio_ctrl *sctrl = NULL;
u32 read_len;
if (epub == NULL || buf == NULL) {
ESSERT(0);
return -EINVAL;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
switch(sctrl->target_id) {
case 0x100:
read_len = len;
break;
case 0x600:
if(!noround)
read_len = roundup(len, sctrl->slc_blk_sz);
else
read_len = len;
break;
default:
read_len = len;
break;
}
return sif_io_raw((epub), (sctrl->slc_window_end_addr - 2 - (len)), (buf), (read_len), SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}
int sif_lldesc_write_raw(struct esp_pub *epub, u8 *buf, u32 len)
{
struct esp_sdio_ctrl *sctrl = NULL;
u32 write_len;
if (epub == NULL || buf == NULL) {
ESSERT(0);
return -EINVAL;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
switch(sctrl->target_id) {
case 0x100:
write_len = len;
break;
case 0x600:
write_len = roundup(len, sctrl->slc_blk_sz);
break;
default:
write_len = len;
break;
}
return sif_io_raw((epub), (sctrl->slc_window_end_addr - (len)), (buf), (write_len), SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
}
#define MANUFACTURER_ID_EAGLE_BASE 0x1110
#define MANUFACTURER_ID_EAGLE_BASE_MASK 0xFF00
#define MANUFACTURER_CODE 0x6666
static const struct sdio_device_id esp_sdio_devices[] = {
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_EAGLE_BASE | 0x1))},
{},
};
static int esdio_power_on(struct esp_sdio_ctrl *sctrl)
{
int err = 0;
if (sctrl->off == false)
return err;
sdio_claim_host(sctrl->func);
err = sdio_enable_func(sctrl->func);
if (err) {
esp_dbg(ESP_DBG_ERROR, "Unable to enable sdio func: %d\n", err);
sdio_release_host(sctrl->func);
return err;
}
sdio_release_host(sctrl->func);
/* ensure device is up */
msleep(5);
sctrl->off = false;
return err;
}
static int esdio_power_off(struct esp_sdio_ctrl *sctrl)
{
int err;
if (sctrl->off)
return 0;
sdio_claim_host(sctrl->func);
err = sdio_disable_func(sctrl->func);
sdio_release_host(sctrl->func);
if (err)
return err;
sctrl->off = true;
return err;
}
void sif_enable_irq(struct esp_pub *epub)
{
int err;
struct esp_sdio_ctrl *sctrl = NULL;
sctrl = (struct esp_sdio_ctrl *)epub->sif;
sdio_claim_host(sctrl->func);
err = sdio_claim_irq(sctrl->func, sif_dsr);
if (err)
esp_dbg(ESP_DBG_ERROR, "sif %s failed\n", __func__);
atomic_set(&epub->sip->state, SIP_BOOT);
atomic_set(&sctrl->irq_installed, 1);
sdio_release_host(sctrl->func);
}
void sif_disable_irq(struct esp_pub *epub)
{
int err;
struct esp_sdio_ctrl *sctrl = (struct esp_sdio_ctrl *)epub->sif;
int i = 0;
if (atomic_read(&sctrl->irq_installed) == 0)
return;
sdio_claim_host(sctrl->func);
while (atomic_read(&sctrl->irq_handling)) {
sdio_release_host(sctrl->func);
schedule_timeout(HZ / 100);
sdio_claim_host(sctrl->func);
if (i++ >= 400) {
esp_dbg(ESP_DBG_ERROR, "%s force to stop irq\n", __func__);
break;
}
}
err = sdio_release_irq(sctrl->func);
if (err) {
esp_dbg(ESP_DBG_ERROR, "%s release irq failed\n", __func__);
}
atomic_set(&sctrl->irq_installed, 0);
sdio_release_host(sctrl->func);
}
void sif_set_clock(struct sdio_func *func, int clk)
{
struct mmc_host *host = NULL;
struct mmc_card *card = NULL;
card = func->card;
host = card->host;
sdio_claim_host(func);
//currently only set clock
host->ios.clock = clk * 1000000;
esp_dbg(ESP_SHOW, "%s clock is %u\n", __func__, host->ios.clock);
if (host->ios.clock > host->f_max) {
host->ios.clock = host->f_max;
}
host->ops->set_ios(host, &host->ios);
mdelay(2);
sdio_release_host(func);
}
static int esp_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
static void esp_sdio_remove(struct sdio_func *func);
static int esp_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
int err = 0;
struct esp_pub *epub;
struct esp_sdio_ctrl *sctrl;
struct mmc_host *host = func->card->host;
esp_dbg(ESP_DBG_TRACE,
"sdio_func_num: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
func->num, func->vendor, func->device, func->max_blksize,
func->cur_blksize);
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){
sctrl = kzalloc(sizeof(struct esp_sdio_ctrl), GFP_KERNEL);
if (sctrl == NULL) {
return -ENOMEM;
}
/* temp buffer reserved for un-dma-able request */
sctrl->dma_buffer = kzalloc(ESP_DMA_IBUFSZ, GFP_KERNEL);
if (sctrl->dma_buffer == NULL) {
err = -ENOMEM;
goto _err_last;
}
sif_sctrl = sctrl;
sctrl->slc_blk_sz = SIF_SLC_BLOCK_SIZE;
epub = esp_pub_alloc_mac80211(&func->dev);
if (epub == NULL) {
esp_dbg(ESP_DBG_ERROR, "no mem for epub \n");
err = -ENOMEM;
goto _err_dma;
}
epub->sif = (void *)sctrl;
sctrl->epub = epub;
#ifdef USE_EXT_GPIO
if (sif_get_ate_config() == 0) {
err = ext_gpio_init(epub);
if (err) {
esp_dbg(ESP_DBG_ERROR, "ext_irq_work_init failed %d\n", err);
goto _err_epub;
}
}
#endif
} else {
sctrl = sif_sctrl;
sif_sctrl = NULL;
epub = sctrl->epub;
SET_IEEE80211_DEV(epub->hw, &func->dev);
epub->dev = &func->dev;
}
epub->sdio_state = sif_sdio_state;
sctrl->func = func;
sdio_set_drvdata(func, sctrl);
sctrl->id = id;
sctrl->off = true;
/* give us some time to enable, in ms */
func->enable_timeout = 100;
err = esdio_power_on(sctrl);
esp_dbg(ESP_DBG_TRACE, " %s >> power_on err %d \n", __func__, err);
if (err){
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT)
goto _err_ext_gpio;
else
goto _err_second_init;
}
check_target_id(epub);
sdio_claim_host(func);
err = sdio_set_block_size(func, sctrl->slc_blk_sz);
if (err) {
esp_dbg(ESP_DBG_ERROR, "Set sdio block size %d failed: %d)\n",
sctrl->slc_blk_sz, err);
sdio_release_host(func);
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT)
goto _err_off;
else
goto _err_second_init;
}
sdio_release_host(func);
#ifdef LOWER_CLK
/* fix clock for dongle */
sif_set_clock(func, 23);
#endif //LOWER_CLK
err = esp_pub_init_all(epub);
if (err) {
esp_dbg(ESP_DBG_ERROR, "esp_init_all failed: %d\n", err);
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){
err = 0;
goto _err_first_init;
}
if(sif_sdio_state == ESP_SDIO_STATE_SECOND_INIT)
goto _err_second_init;
}
esp_dbg(ESP_DBG_TRACE, " %s return %d\n", __func__, err);
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){
esp_dbg(ESP_DBG_ERROR, "first normal exit\n");
sif_sdio_state = ESP_SDIO_STATE_FIRST_NORMAL_EXIT;
/* Rescan the esp8089 after loading the initial firmware */
mmc_force_detect_change(host, msecs_to_jiffies(100), true);
up(&esp_powerup_sem);
}
return err;
_err_off:
esdio_power_off(sctrl);
_err_ext_gpio:
#ifdef USE_EXT_GPIO
if (sif_get_ate_config() == 0)
ext_gpio_deinit();
_err_epub:
#endif
esp_pub_dealloc_mac80211(epub);
_err_dma:
kfree(sctrl->dma_buffer);
_err_last:
kfree(sctrl);
_err_first_init:
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_INIT){
esp_dbg(ESP_DBG_ERROR, "first error exit\n");
sif_sdio_state = ESP_SDIO_STATE_FIRST_ERROR_EXIT;
up(&esp_powerup_sem);
}
return err;
_err_second_init:
sif_sdio_state = ESP_SDIO_STATE_SECOND_ERROR_EXIT;
esp_sdio_remove(func);
return err;
}
static void esp_sdio_remove(struct sdio_func *func)
{
struct esp_sdio_ctrl *sctrl = NULL;
esp_dbg(ESP_SHOW, "%s enter\n", __func__);
sctrl = sdio_get_drvdata(func);
if (sctrl == NULL) {
esp_dbg(ESP_DBG_ERROR, "%s no sctrl\n", __func__);
return;
}
do {
if (sctrl->epub == NULL) {
esp_dbg(ESP_DBG_ERROR, "%s epub null\n", __func__);
break;
}
sctrl->epub->sdio_state = sif_sdio_state;
if(sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT){
if (sctrl->epub->sip) {
sip_detach(sctrl->epub->sip);
sctrl->epub->sip = NULL;
esp_dbg(ESP_DBG_TRACE, "%s sip detached \n", __func__);
}
#ifdef USE_EXT_GPIO
if (sif_get_ate_config() == 0)
ext_gpio_deinit();
#endif
} else {
//sif_disable_target_interrupt(sctrl->epub);
atomic_set(&sctrl->epub->sip->state, SIP_STOP);
sif_disable_irq(sctrl->epub);
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0))
esdio_power_off(sctrl);
esp_dbg(ESP_DBG_TRACE, "%s power off \n", __func__);
#endif /* kernel < 3.3.0 */
#ifdef TEST_MODE
test_exit_netlink();
#endif /* TEST_MODE */
if(sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT){
esp_pub_dealloc_mac80211(sctrl->epub);
esp_dbg(ESP_DBG_TRACE, "%s dealloc mac80211 \n", __func__);
if (sctrl->dma_buffer) {
kfree(sctrl->dma_buffer);
sctrl->dma_buffer = NULL;
esp_dbg(ESP_DBG_TRACE, "%s free dma_buffer \n", __func__);
}
kfree(sctrl);
}
} while (0);
sdio_set_drvdata(func,NULL);
esp_dbg(ESP_DBG_TRACE, "eagle sdio remove complete\n");
}
MODULE_DEVICE_TABLE(sdio, esp_sdio_devices);
static int esp_sdio_suspend(struct device *dev)
{
//#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
struct sdio_func *func = dev_to_sdio_func(dev);
#else
struct sdio_func *func = container_of(dev, struct sdio_func, dev);
#endif
struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
struct esp_pub *epub = sctrl->epub;
printk("%s", __func__);
#if 0
sip_send_suspend_config(epub, 1);
#endif
atomic_set(&epub->ps.state, ESP_PM_ON);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34))
do{
u32 sdio_flags = 0;
int ret = 0;
sdio_flags = sdio_get_host_pm_caps(func);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
printk("%s can't keep power while host is suspended\n", __func__);
}
/* keep power while host suspended */
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret) {
printk("%s error while trying to keep power\n", __func__);
}
}while(0);
#endif
return 0;
}
static int esp_sdio_resume(struct device *dev)
{
esp_dbg(ESP_DBG_ERROR, "%s", __func__);
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
static const struct dev_pm_ops esp_sdio_pm_ops = {
.suspend= esp_sdio_suspend,
.resume= esp_sdio_resume,
};
#else
static struct pm_ops esp_sdio_pm_ops = {
.suspend= esp_sdio_suspend,
.resume= esp_sdio_resume,
};
#endif
static struct sdio_driver esp_sdio_driver = {
.name = "eagle_sdio",
.id_table = esp_sdio_devices,
.probe = esp_sdio_probe,
.remove = esp_sdio_remove,
.drv = { .pm = &esp_sdio_pm_ops, },
};
static int esp_sdio_dummy_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
esp_dbg(ESP_DBG_ERROR, "%s enter\n", __func__);
up(&esp_powerup_sem);
return 0;
}
static void esp_sdio_dummy_remove(struct sdio_func *func)
{
return;
}
static struct sdio_driver esp_sdio_dummy_driver = {
.name = "eagle_sdio_dummy",
.id_table = esp_sdio_devices,
.probe = esp_sdio_dummy_probe,
.remove = esp_sdio_dummy_remove,
};
static int /*__init*/ esp_sdio_init(void)
{
#define ESP_WAIT_UP_TIME_MS 11000
int err;
u64 ver;
int retry = 3;
bool powerup = false;
int edf_ret = 0;
esp_dbg(ESP_DBG_TRACE, "%s \n", __func__);
#ifdef DRIVER_VER
ver = DRIVER_VER;
esp_dbg(ESP_SHOW, "\n***** EAGLE DRIVER VER:%llx*****\n\n", ver);
#endif
edf_ret = esp_debugfs_init();
request_init_conf();
esp_wakelock_init();
esp_wake_lock();
do {
sema_init(&esp_powerup_sem, 0);
sif_platform_target_poweron();
sif_platform_rescan_card(1);
err = sdio_register_driver(&esp_sdio_dummy_driver);
if (err) {
esp_dbg(ESP_DBG_ERROR, "eagle sdio driver registration failed, error code: %d\n", err);
goto _fail;
}
if (down_timeout(&esp_powerup_sem,
msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) == 0)
{
powerup = true;
msleep(200);
break;
}
esp_dbg(ESP_SHOW, "%s ------ RETRY ------ \n", __func__);
sif_record_retry_config();
sdio_unregister_driver(&esp_sdio_dummy_driver);
sif_platform_rescan_card(0);
sif_platform_target_poweroff();
} while (retry--);
if (!powerup) {
esp_dbg(ESP_DBG_ERROR, "eagle sdio can not power up!\n");
err = -ENODEV;
goto _fail;
}
esp_dbg(ESP_SHOW, "%s power up OK\n", __func__);
sdio_unregister_driver(&esp_sdio_dummy_driver);
sif_sdio_state = ESP_SDIO_STATE_FIRST_INIT;
sema_init(&esp_powerup_sem, 0);
sdio_register_driver(&esp_sdio_driver);
if ((down_timeout(&esp_powerup_sem,
msecs_to_jiffies(ESP_WAIT_UP_TIME_MS)) == 0 ) && sif_get_ate_config() == 0) {
if(sif_sdio_state == ESP_SDIO_STATE_FIRST_NORMAL_EXIT){
sdio_unregister_driver(&esp_sdio_driver);
sif_platform_rescan_card(0);
msleep(100);
sif_platform_rescan_card(1);
sif_sdio_state = ESP_SDIO_STATE_SECOND_INIT;
sdio_register_driver(&esp_sdio_driver);
}
}
esp_register_early_suspend();
esp_wake_unlock();
return err;
_fail:
esp_wake_unlock();
esp_wakelock_destroy();
return err;
}
static void /*__exit*/ esp_sdio_exit(void)
{
esp_dbg(ESP_SHOW, "%s \n", __func__);
esp_debugfs_exit();
esp_unregister_early_suspend();
sdio_unregister_driver(&esp_sdio_driver);
sif_platform_rescan_card(0);
#ifndef FPGA_DEBUG
sif_platform_target_poweroff();
#endif /* !FPGA_DEBUG */
esp_wakelock_destroy();
}
MODULE_AUTHOR("Espressif System");
MODULE_DESCRIPTION("Driver for SDIO interconnected eagle low-power WLAN devices");
MODULE_LICENSE("GPL");
#endif /* ESP_USE_SDIO */

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2013 Espressif System.
*
* sdio stub code for RK
*/
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
//#include <mach/iomux.h>
#include <linux/amlogic/wifi_dt.h>
/* reset GPIO parameter defaults to GPIO 0 (ID_SD) on the Raspberry Pi */
/* default reset port of OGA hw rev 1.1 : GPIO3_B1 (105) */
/* default reset port of ODROID-C4 : GPIOX_18(494) */
static int esp_reset_gpio = 494;
module_param(esp_reset_gpio, int, 0);
MODULE_PARM_DESC(esp_reset_gpio, "ESP8089 CH_PD reset GPIO number");
#define ESP8089_DRV_VERSION "1.9"
extern int rk29sdk_wifi_power(int on);
extern int rk29sdk_wifi_set_carddetect(int val);
int rockchip_wifi_init_module(void)
{
return esp_sdio_init();
}
void rockchip_wifi_exit_module(void)
{
esp_sdio_exit();
}
void sif_platform_rescan_card(unsigned insert)
{
}
/* default enable port of ODROID-C4 : GPIOX_17(493) */
static int esp_enable_gpio = 493;
module_param(esp_enable_gpio, int, 0);
MODULE_PARM_DESC(esp_enable_gpio, "ESP8089 CH_EN enable GPIO number");
void sif_platform_reset_target(void)
{
/* set output high by default */
printk("ESP8089 reset via GPIO %d\n", esp_reset_gpio);
gpio_request(esp_reset_gpio,"esp_reset");
gpio_direction_output(esp_reset_gpio, 0);
msleep(200);
gpio_direction_output(esp_reset_gpio, 1);
gpio_free(esp_reset_gpio);
}
void sif_platform_target_poweroff(void)
{
/* reset ESP before unload so that the esp can be probed on
* warm reboot */
sif_platform_reset_target();
gpio_request(esp_enable_gpio,"esp_enable");
gpio_direction_output(esp_enable_gpio, 0);
gpio_free(esp_enable_gpio);
sdio_notify(0);
}
void sif_platform_target_poweron(void)
{
gpio_request(esp_enable_gpio,"esp_enable");
gpio_direction_output(esp_enable_gpio, 0);
sif_platform_reset_target();
msleep(100);
gpio_direction_output(esp_enable_gpio, 1);
gpio_free(esp_enable_gpio);
sdio_notify(1);
sdio_reinit();
}
void sif_platform_target_speed(int high_speed)
{
}
void sif_platform_check_r1_ready(struct esp_pub *epub)
{
}
#ifdef ESP_ACK_INTERRUPT
extern void sdmmc_ack_interrupt(struct mmc_host *mmc);
void sif_platform_ack_interrupt(struct esp_pub *epub)
{
struct esp_sdio_ctrl *sctrl = NULL;
struct sdio_func *func = NULL;
if (epub == NULL) {
ESSERT(epub != NULL);
return;
}
sctrl = (struct esp_sdio_ctrl *)epub->sif;
func = sctrl->func;
if (func == NULL) {
ESSERT(func != NULL);
return;
}
sdmmc_ack_interrupt(func->card->host);
}
#endif //ESP_ACK_INTERRUPT
EXPORT_SYMBOL(rockchip_wifi_init_module);
EXPORT_SYMBOL(rockchip_wifi_exit_module);
late_initcall(esp_sdio_init);
module_exit(esp_sdio_exit);

View File

@@ -0,0 +1,477 @@
/*
* Copyright (c) 2010 - 2014 Espressif System.
*
* Common definitions of Serial Interconnctor Protocol
*
* little endian
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SIP2_COMMON_H
#define _SIP2_COMMON_H
#ifdef __ets__
#include "utils.h"
#endif /*__ets__*/
/* max 16 types */
typedef enum {
SIP_CTRL = 0,
SIP_DATA,
SIP_DATA_AMPDU
} SIP_TYPE;
typedef enum {
SIP_TX_CTRL_BUF = 0, /* from host */
SIP_RX_CTRL_BUF, /* to host */
SIP_TX_DATA_BUF, /* from host */
SIP_RX_DATA_BUF /* to host */
} SIP_BUF_TYPE;
enum sip_cmd_id {
SIP_CMD_GET_VER = 0,
SIP_CMD_WRITE_MEMORY,//1 ROM code
SIP_CMD_READ_MEMORY,//2
SIP_CMD_WRITE_REG,//3 ROM code
SIP_CMD_READ_REG, //4
SIP_CMD_BOOTUP,//5 ROM code
SIP_CMD_COPYBACK,//6
SIP_CMD_INIT, //7
SIP_CMD_SCAN,//8
SIP_CMD_SETKEY,//9
SIP_CMD_CONFIG,//10
SIP_CMD_BSS_INFO_UPDATE,//11
SIP_CMD_LOOPBACK,//12 ROM code
//do not add cmd before this line
SIP_CMD_SET_WMM_PARAM,
SIP_CMD_AMPDU_ACTION,
SIP_CMD_HB_REQ, //15
SIP_CMD_RESET_MAC, //16
SIP_CMD_PRE_DOWN, //17
SIP_CMD_SLEEP, /* for sleep testing */
SIP_CMD_WAKEUP, /* for sleep testing */
SIP_CMD_DEBUG, /* for general testing */
SIP_CMD_GET_FW_VER, /* get fw rev. */
SIP_CMD_SETVIF,
SIP_CMD_SETSTA,
SIP_CMD_PS,
SIP_CMD_ATE,
SIP_CMD_SUSPEND,
SIP_CMD_RECALC_CREDIT,
SIP_CMD_MAX,
};
enum {
SIP_EVT_TARGET_ON = 0, //
SIP_EVT_BOOTUP,//1 in ROM code
SIP_EVT_COPYBACK,//2
SIP_EVT_SCAN_RESULT, //3
SIP_EVT_TX_STATUS,//4
SIP_EVT_CREDIT_RPT, //5, in ROM code
SIP_EVT_ERROR,//6
SIP_EVT_LOOPBACK,//7, in ROM code
SIP_EVT_SNPRINTF_TO_HOST, //8 in ROM code
//do not add evt before this line
SIP_EVT_HB_ACK, //9
SIP_EVT_RESET_MAC_ACK, //10
SIP_EVT_WAKEUP,//11 /* for sleep testing */
SIP_EVT_DEBUG,//12 /* for general testing */
SIP_EVT_PRINT_TO_HOST, //13
SIP_EVT_TRC_AMPDU, //14
SIP_EVT_ROC, //15
SIP_EVT_RESETTING,
SIP_EVT_ATE,
SIP_EVT_EP,
SIP_EVT_INIT_EP,
SIP_EVT_SLEEP,
SIP_EVT_TXIDLE,
SIP_EVT_NOISEFLOOR,
SIP_EVT_MAX
};
#define SIP_IFIDX_MASK 0xf0
#define SIP_IFIDX_S 4
#define SIP_TYPE_MASK 0x0f
#define SIP_TYPE_S 0
#define SIP_HDR_GET_IFIDX(fc0) (((fc0) & SIP_IFIDX_MASK) >> SIP_IFIDX_S)
#define SIP_HDR_SET_IFIDX(fc0, ifidx) ( (fc0) = ((fc0) & ~SIP_IFIDX_MASK) | ((ifidx) << SIP_IFIDX_S & SIP_IFIDX_MASK) )
#define SIP_HDR_GET_TYPE(fc0) ((fc0) & SIP_TYPE_MASK )
/* assume type field is cleared */
#define SIP_HDR_SET_TYPE(fc0, type) ((fc0) = ((fc0) & ~ SIP_TYPE_MASK) | ((type) & SIP_TYPE_MASK))
/* sip 2.0, not hybrid header so far */
#define SIP_HDR_IS_CTRL(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_CTRL)
#define SIP_HDR_IS_DATA(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_DATA)
#define SIP_HDR_IS_AMPDU(hdr) (SIP_HDR_GET_TYPE((hdr)->fc[0]) == SIP_DATA_AMPDU)
/* fc[1] flags, only for data pkt. Ctrl pkts use fc[1] as eventID */
#define SIP_HDR_SET_FLAGS(hdr, flags) ((hdr)->fc[1] |= (flags))
#define SIP_HDR_F_MORE_PKT 0x1
#define SIP_HDR_F_NEED_CRDT_RPT 0x2
#define SIP_HDR_F_SYNC 0x4
#define SIP_HDR_F_SYNC_RESET 0x8
#define SIP_HDR_F_PM_TURNING_ON 0x10
#define SIP_HDR_F_PM_TURNING_OFF 0x20
#define SIP_HDR_NEED_CREDIT_UPDATE(hdr) ((hdr)->fc[1] & SIP_HDR_F_NEED_CRDT_RPT)
#define SIP_HDR_IS_MORE_PKT(hdr) ((hdr)->fc[1] & SIP_HDR_F_MORE_PKT)
#define SIP_HDR_IS_CRDT_RPT(hdr) ((hdr)->fc[1] & SIP_HDR_F_CRDT_RPT)
#define SIP_HDR_IS_SYNC(hdr) ((hdr)->fc[1] & SIP_HDR_F_SYNC)
#define SIP_HDR_IS_SYNC_RESET(hdr) ((hdr)->fc[1] & SIP_HDR_F_SYNC_RESET)
#define SIP_HDR_IS_SYNC_PKT(hdr) (SIP_HDR_IS_SYNC(hdr) | SIP_HDR_IS_SYNC_RESET(hdr))
#define SIP_HDR_SET_SYNC(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_SYNC)
#define SIP_HDR_SET_SYNC_RESET(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_SYNC_RESET)
#define SIP_HDR_SET_MORE_PKT(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_MORE_PKT)
#define SIP_HDR_SET_PM_TURNING_ON(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_PM_TURNING_ON)
#define SIP_HDR_IS_PM_TURNING_ON(hdr) ((hdr)->fc[1] & SIP_HDR_F_PM_TURNING_ON)
#define SIP_HDR_SET_PM_TURNING_OFF(hdr) SIP_HDR_SET_FLAGS((hdr), SIP_HDR_F_PM_TURNING_OFF)
#define SIP_HDR_IS_PM_TURNING_OFF(hdr) ((hdr)->fc[1] & SIP_HDR_F_PM_TURNING_OFF)
/*
* fc[0]: first 4bit: ifidx; last 4bit: type
* fc[1]: flags
*
* Don't touch the header definitons
*/
struct sip_hdr_min {
u8 fc[2];
__le16 len;
} __packed;
/* not more than 4byte long */
struct sip_tx_data_info {
u8 tid;
u8 ac;
u8 p2p:1,
enc_flag:7;
u8 hw_kid;
} __packed;
/* NB: this structure should be not more than 4byte !! */
struct sip_tx_info {
union {
u32 cmdid;
struct sip_tx_data_info dinfo;
} u;
} __packed;
struct sip_hdr {
u8 fc[2]; //fc[0]: type and ifidx ; fc[1] is eventID if the first ctrl pkt in the chain. data pkt still can use fc[1] to set flag
__le16 len;
union {
volatile u32 recycled_credits; /* last 12bits is credits, first 20 bits is actual length of the first pkt in the chain */
struct sip_tx_info tx_info;
} u;
u32 seq;
} __packed;
#define h_credits u.recycled_credits
#define c_evtid fc[1]
#define c_cmdid u.tx_info.u.cmdid
#define d_ac u.tx_info.u.dinfo.ac
#define d_tid u.tx_info.u.dinfo.tid
#define d_p2p u.tx_info.u.dinfo.p2p
#define d_enc_flag u.tx_info.u.dinfo.enc_flag
#define d_hw_kid u.tx_info.u.dinfo.hw_kid
#define SIP_CREDITS_MASK 0xfff /* last 12 bits */
#ifdef HOST_RC
#define RC_CNT_MASK 0xf
struct sip_rc_status {
u32 rc_map;
union {
u32 rc_cnt1:4,
rc_cnt2:4,
rc_cnt3:4,
rc_cnt4:4,
rc_cnt5:4;
u32 rc_cnt_store;
};
};
/* copy from mac80211.h */
struct sip_tx_rc {
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
s8 rts_cts_rate_idx;
};
#endif /* HOST_RC */
#define SIP_HDR_MIN_LEN 4
#define SIP_HDR_LEN sizeof(struct sip_hdr)
#define SIP_CTRL_HDR_LEN SIP_HDR_LEN /* same as sip_hdr in sip2 design */
#define SIP_BOOT_BUF_SIZE 256
#define SIP_CTRL_BUF_SZ 256 /* too much?? */
#define SIP_CTRL_BUF_N 6
#define SIP_CTRL_TXBUF_N 2
#define SIP_CTRL_RXBUF_N 4
/* WAR for mblk */
#define SIP_RX_ADDR_PREFIX_MASK 0xfc000000
#define SIP_RX_ADDR_SHIFT 6 /* [31:5], shift 6 bits*/
struct sip_cmd_write_memory {
u32 addr;
u32 len;
} __packed;
struct sip_cmd_read_memory {
u32 addr;
u32 len;
} __packed;
struct sip_cmd_write_reg {
u32 addr;
u32 val;
} __packed;
struct sip_cmd_bootup {
u32 boot_addr;
} __packed;
struct sip_cmd_loopback {
u32 txlen; //host to target packet len, 0 means no txpacket
u32 rxlen; //target to host packet len, 0 means no rxpacket
u32 pack_id; //sequence of packet
} __packed;
struct sip_evt_loopback {
u32 txlen; //host to target packet len, 0 means no txpacket
u32 rxlen; //target to host packet len, 0 means no rxpacket
u32 pack_id; //sequence of packet
} __packed;
struct sip_cmd_copyback {
u32 addr;
u32 len;
} __packed;
struct sip_cmd_scan {
// u8 ssid[32];
u8 ssid_len;
// u8 hw_channel[14];
u8 n_channels;
u8 ie_len;
u8 aborted;
} __packed; // ie[] append at the end
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif /* ETH_ALEN */
struct sip_cmd_setkey {
u8 bssid_no;
u8 addr[ETH_ALEN];
u8 alg;
u8 keyidx;
u8 hw_key_idx;
u8 flags;
u8 keylen;
u8 key[32];
} __packed;
struct sip_cmd_config {
u16 center_freq;
u16 duration;
} __packed;
struct sip_cmd_bss_info_update {
u8 bssid[ETH_ALEN];
u16 isassoc;
u32 beacon_int;
u8 bssid_no;
} __packed;
struct sip_evt_bootup {
u16 tx_blksz;
u8 mac_addr[ETH_ALEN];
/* anything else ? */
} __packed;
struct sip_cmd_setvif {
u8 index;
u8 mac[ETH_ALEN];
u8 set;
u8 op_mode;
u8 is_p2p;
} __packed;
enum esp_ieee80211_phytype{
ESP_IEEE80211_T_CCK = 0,
ESP_IEEE80211_T_OFDM = 1,
ESP_IEEE80211_T_HT20_L = 2,
ESP_IEEE80211_T_HT20_S = 3,
};
struct sip_cmd_setsta {
u8 ifidx;
u8 index;
u8 set;
u8 phymode;
u8 mac[ETH_ALEN];
u16 aid;
u8 ampdu_factor;
u8 ampdu_density;
u16 resv;
} __packed;
struct sip_cmd_ps {
u8 dtim_period;
u8 max_sleep_period;
u8 on;
u8 resv;
} __packed;
struct sip_cmd_suspend {
u8 suspend;
u8 resv[3];
} __packed;
#define SIP_DUMP_RPBM_ERR BIT(0)
#define SIP_RXABORT_FIXED BIT(1)
#define SIP_SUPPORT_BGSCAN BIT(2)
struct sip_evt_bootup2 {
u16 tx_blksz;
u8 mac_addr[ETH_ALEN];
u16 rx_blksz;
u8 credit_to_reserve;
u8 options;
s16 noise_floor;
u8 resv[2];
/* anything else ? */
} __packed;
typedef enum {
TRC_TX_AMPDU_STOPPED = 1,
TRC_TX_AMPDU_OPERATIONAL,
TRC_TX_AMPDU_WAIT_STOP,
TRC_TX_AMPDU_WAIT_OPERATIONAL,
TRC_TX_AMPDU_START,
} trc_ampdu_state_t;
struct sip_evt_trc_ampdu {
u8 state;
u8 tid;
u8 addr[ETH_ALEN];
} __packed;
struct sip_cmd_set_wmm_params {
u8 aci;
u8 aifs;
u8 ecw_min;
u8 ecw_max;
u16 txop_us;
} __packed;
#define SIP_AMPDU_RX_START 0
#define SIP_AMPDU_RX_STOP 1
#define SIP_AMPDU_TX_OPERATIONAL 2
#define SIP_AMPDU_TX_STOP 3
struct sip_cmd_ampdu_action {
u8 action;
u8 index;
u8 tid;
u8 win_size;
u16 ssn;
u8 addr[ETH_ALEN];
} __packed;
#define SIP_TX_ST_OK 0
#define SIP_TX_ST_NOEB 1
#define SIP_TX_ST_ACKTO 2
#define SIP_TX_ST_ENCERR 3
//NB: sip_tx_status must be 4 bytes aligned
struct sip_tx_status {
u32 sip_seq;
#ifdef HOST_RC
struct sip_rc_status rcstatus;
#endif /* HOST_RC */
u8 errno; /* success or failure code */
u8 rate_index;
char ack_signal;
u8 pad;
} __packed;
struct sip_evt_tx_report {
u32 pkts;
struct sip_tx_status status[0];
} __packed;
struct sip_evt_tx_mblk {
u32 mblk_map;
} __packed;
struct sip_evt_scan_report {
u16 scan_id;
u16 aborted;
} __packed;
struct sip_evt_roc {
u16 state; //start:1, end :0
u16 is_ok;
} __packed;
struct sip_evt_txidle {
u32 last_seq;
} __packed;
struct sip_evt_noisefloor {
s16 noise_floor;
u16 pad;
} __packed;
/*
* for mblk direct memory access, no need for sip_hdr. tx: first 2k for contrl msg,
* rest of 14k for data. rx, same.
*/
#ifdef TEST_MODE
struct sip_cmd_sleep {
u32 sleep_mode;
u32 sleep_tm_ms;
u32 wakeup_tm_ms; //zero: after receive bcn, then sleep, nozero: delay nozero ms to sleep
u32 sleep_times; //zero: always sleep, nozero: after nozero number sleep/wakeup, then end up sleep
} __packed;
struct sip_cmd_wakeup {
u32 check_data; //0:copy to event
} __packed;
struct sip_evt_wakeup {
u32 check_data;
} __packed;
//general debug command
struct sip_cmd_debug {
u32 cmd_type;
u32 para_num;
u32 para[10];
} __packed;
struct sip_evt_debug {
u16 len;
u32 results[12];
u16 pad;
} __packed;
struct sip_cmd_ate {
//u8 len;
u8 cmdstr[0];
} __packed;
#endif //ifdef TEST_MODE
#endif /* _SIP_COMMON_H_ */

View File

@@ -0,0 +1,271 @@
//Generated at 2012-10-23 20:11:08
/*
* Copyright (c) 2011 Espressif System
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SLC_HOST_REGISTER_H_INCLUDED
#define SLC_HOST_REGISTER_H_INCLUDED
/* #define REG_SLC_HOST_BASE 0x00000000 */
/* skip the token1, since reading it will clean the credit */
#define REG_SLC_HOST_BASE 0x00000000
#define REG_SLC_BASE 0x00000000
#define SLC_HOST_PF (REG_SLC_HOST_BASE + 0x0)
#define SLC_HOST_TOKEN_RDATA (REG_SLC_HOST_BASE + 0x4)
#define SLC_HOST_RX_PF_EOF 0x0000000F
#define SLC_HOST_RX_PF_EOF_S 28
#define SLC_HOST_TOKEN1 0x00000FFF
#define SLC_HOST_TOKEN1_S 16
#define SLC_HOST_RX_PF_VALID (BIT(15))
#define SLC_HOST_TOKEN0 0x00000FFF
#define SLC_HOST_TOKEN0_S 0
#define SLC_HOST_TOKEN0_MASK SLC_HOST_TOKEN0
#define SLC_HOST_INT_RAW (REG_SLC_HOST_BASE + 0x8)
#define SLC_HOST_EXT_BIT3_INT_RAW (BIT(22))
#define SLC_HOST_EXT_BIT2_INT_RAW (BIT(21))
#define SLC_HOST_EXT_BIT1_INT_RAW (BIT(20))
#define SLC_HOST_RXFIFO_NOT_EMPTY_INT_RAW (BIT(19))
#define SLC_HOST_RX_PF_VALID_INT_RAW (BIT(18))
#define SLC_HOST_TX_OVF_INT_RAW (BIT(17))
#define SLC_HOST_RX_UDF_INT_RAW (BIT(16))
#define SLC_HOST_TX_START_INT_RAW (BIT(15))
#define SLC_HOST_RX_START_INT_RAW (BIT(14))
#define SLC_HOST_RX_EOF_INT_RAW (BIT(13))
#define SLC_HOST_RX_SOF_INT_RAW (BIT(12))
#define SLC_HOST_TOKEN1_0TO1_INT_RAW (BIT(11))
#define SLC_HOST_TOKEN0_0TO1_INT_RAW (BIT(10))
#define SLC_HOST_TOKEN1_1TO0_INT_RAW (BIT(9))
#define SLC_HOST_TOKEN0_1TO0_INT_RAW (BIT(8))
#define SLC_HOST_TOHOST_BIT7_INT_RAW (BIT(7))
#define SLC_HOST_TOHOST_BIT6_INT_RAW (BIT(6))
#define SLC_HOST_TOHOST_BIT5_INT_RAW (BIT(5))
#define SLC_HOST_TOHOST_BIT4_INT_RAW (BIT(4))
#define SLC_HOST_TOHOST_BIT3_INT_RAW (BIT(3))
#define SLC_HOST_TOHOST_BIT2_INT_RAW (BIT(2))
#define SLC_HOST_TOHOST_BIT1_INT_RAW (BIT(1))
#define SLC_HOST_TOHOST_BIT0_INT_RAW (BIT(0))
#define SLC_HOST_STATE_W0 (REG_SLC_HOST_BASE + 0xC)
#define SLC_HOST_STATE3 0x000000FF
#define SLC_HOST_STATE3_S 24
#define SLC_HOST_STATE2 0x000000FF
#define SLC_HOST_STATE2_S 16
#define SLC_HOST_STATE1 0x000000FF
#define SLC_HOST_STATE1_S 8
#define SLC_HOST_STATE0 0x000000FF
#define SLC_HOST_STATE0_S 0
#define SLC_HOST_STATE_W1 (REG_SLC_HOST_BASE + 0x10)
#define SLC_HOST_STATE7 0x000000FF
#define SLC_HOST_STATE7_S 24
#define SLC_HOST_STATE6 0x000000FF
#define SLC_HOST_STATE6_S 16
#define SLC_HOST_STATE5 0x000000FF
#define SLC_HOST_STATE5_S 8
#define SLC_HOST_STATE4 0x000000FF
#define SLC_HOST_STATE4_S 0
#define SLC_HOST_CONF_W0 (REG_SLC_HOST_BASE + 0x14)
#define SLC_HOST_CONF3 0x000000FF
#define SLC_HOST_CONF3_S 24
#define SLC_HOST_CONF2 0x000000FF
#define SLC_HOST_CONF2_S 16
#define SLC_HOST_CONF1 0x000000FF
#define SLC_HOST_CONF1_S 8
#define SLC_HOST_CONF0 0x000000FF
#define SLC_HOST_CONF0_S 0
#define SLC_HOST_CONF_W1 (REG_SLC_HOST_BASE + 0x18)
#define SLC_HOST_CONF7 0x000000FF
#define SLC_HOST_CONF7_S 24
#define SLC_HOST_CONF6 0x000000FF
#define SLC_HOST_CONF6_S 16
#define SLC_HOST_CONF5 0x000000FF
#define SLC_HOST_CONF5_S 8
#define SLC_HOST_CONF4 0x000000FF
#define SLC_HOST_CONF4_S 0
#define SLC_HOST_INT_ST (REG_SLC_HOST_BASE + 0x1C)
#define SLC_HOST_RX_ST (BIT(23))
#define SLC_HOST_EXT_BIT3_INT_ST (BIT(22))
#define SLC_HOST_EXT_BIT2_INT_ST (BIT(21))
#define SLC_HOST_EXT_BIT1_INT_ST (BIT(20))
#define SLC_HOST_RXFIFO_NOT_EMPTY_INT_ST (BIT(19))
#define SLC_HOST_RX_PF_VALID_INT_ST (BIT(18))
#define SLC_HOST_TX_OVF_INT_ST (BIT(17))
#define SLC_HOST_RX_UDF_INT_ST (BIT(16))
#define SLC_HOST_TX_START_INT_ST (BIT(15))
#define SLC_HOST_RX_START_INT_ST (BIT(14))
#define SLC_HOST_RX_EOF_INT_ST (BIT(13))
#define SLC_HOST_RX_SOF_INT_ST (BIT(12))
#define SLC_HOST_TOKEN1_0TO1_INT_ST (BIT(11))
#define SLC_HOST_TOKEN0_0TO1_INT_ST (BIT(10))
#define SLC_HOST_TOKEN1_1TO0_INT_ST (BIT(9))
#define SLC_HOST_TOKEN0_1TO0_INT_ST (BIT(8))
#define SLC_HOST_TOHOST_BIT7_INT_ST (BIT(7))
#define SLC_HOST_TOHOST_BIT6_INT_ST (BIT(6))
#define SLC_HOST_TOHOST_BIT5_INT_ST (BIT(5))
#define SLC_HOST_TOHOST_BIT4_INT_ST (BIT(4))
#define SLC_HOST_TOHOST_BIT3_INT_ST (BIT(3))
#define SLC_HOST_TOHOST_BIT2_INT_ST (BIT(2))
#define SLC_HOST_TOHOST_BIT1_INT_ST (BIT(1))
#define SLC_HOST_TOHOST_BIT0_INT_ST (BIT(0))
#define SLC_HOST_CONF_W2 (REG_SLC_HOST_BASE + 0x20)
#define SLC_HOST_CONF11 0x000000FF
#define SLC_HOST_CONF11_S 24
#define SLC_HOST_CONF10 0x000000FF
#define SLC_HOST_CONF10_S 16
#define SLC_HOST_CONF9 0x000000FF
#define SLC_HOST_CONF9_S 8
#define SLC_HOST_CONF8 0x000000FF
#define SLC_HOST_CONF8_S 0
#define SLC_HOST_CONF_W3 (REG_SLC_HOST_BASE + 0x24)
#define SLC_HOST_CONF15 0x000000FF
#define SLC_HOST_CONF15_S 24
#define SLC_HOST_CONF14 0x000000FF
#define SLC_HOST_CONF14_S 16
#define SLC_HOST_CONF13 0x000000FF
#define SLC_HOST_CONF13_S 8
#define SLC_HOST_CONF12 0x000000FF
#define SLC_HOST_CONF12_S 0
#define SLC_HOST_GEN_TXDONE_INT BIT(16)
#define SLC_HOST_GEN_RXDONE_INT BIT(17)
#define SLC_HOST_CONF_W4 (REG_SLC_HOST_BASE + 0x28)
#define SLC_HOST_CONF19 0x000000FF
#define SLC_HOST_CONF19_S 24
#define SLC_HOST_CONF18 0x000000FF
#define SLC_HOST_CONF18_S 16
#define SLC_HOST_CONF17 0x000000FF
#define SLC_HOST_CONF17_S 8
#define SLC_HOST_CONF16 0x000000FF
#define SLC_HOST_CONF16_S 0
#define SLC_HOST_TOKEN_WDATA (REG_SLC_HOST_BASE + 0x2C)
#define SLC_HOST_TOKEN1_WD 0x00000FFF
#define SLC_HOST_TOKEN1_WD_S 16
#define SLC_HOST_TOKEN0_WD 0x00000FFF
#define SLC_HOST_TOKEN0_WD_S 0
#define SLC_HOST_INT_CLR (REG_SLC_HOST_BASE + 0x30)
#define SLC_HOST_TOKEN1_WR (BIT(31))
#define SLC_HOST_TOKEN0_WR (BIT(30))
#define SLC_HOST_TOKEN1_DEC (BIT(29))
#define SLC_HOST_TOKEN0_DEC (BIT(28))
#define SLC_HOST_EXT_BIT3_INT_CLR (BIT(22))
#define SLC_HOST_EXT_BIT2_INT_CLR (BIT(21))
#define SLC_HOST_EXT_BIT1_INT_CLR (BIT(20))
#define SLC_HOST_EXT_BIT0_INT_CLR (BIT(19))
#define SLC_HOST_RX_PF_VALID_INT_CLR (BIT(18))
#define SLC_HOST_TX_OVF_INT_CLR (BIT(17))
#define SLC_HOST_RX_UDF_INT_CLR (BIT(16))
#define SLC_HOST_TX_START_INT_CLR (BIT(15))
#define SLC_HOST_RX_START_INT_CLR (BIT(14))
#define SLC_HOST_RX_EOF_INT_CLR (BIT(13))
#define SLC_HOST_RX_SOF_INT_CLR (BIT(12))
#define SLC_HOST_TOKEN1_0TO1_INT_CLR (BIT(11))
#define SLC_HOST_TOKEN0_0TO1_INT_CLR (BIT(10))
#define SLC_HOST_TOKEN1_1TO0_INT_CLR (BIT(9))
#define SLC_HOST_TOKEN0_1TO0_INT_CLR (BIT(8))
#define SLC_HOST_TOHOST_BIT7_INT_CLR (BIT(7))
#define SLC_HOST_TOHOST_BIT6_INT_CLR (BIT(6))
#define SLC_HOST_TOHOST_BIT5_INT_CLR (BIT(5))
#define SLC_HOST_TOHOST_BIT4_INT_CLR (BIT(4))
#define SLC_HOST_TOHOST_BIT3_INT_CLR (BIT(3))
#define SLC_HOST_TOHOST_BIT2_INT_CLR (BIT(2))
#define SLC_HOST_TOHOST_BIT1_INT_CLR (BIT(1))
#define SLC_HOST_TOHOST_BIT0_INT_CLR (BIT(0))
#define SLC_HOST_INT_ENA (REG_SLC_HOST_BASE + 0x34)
#define SLC_HOST_EXT_BIT3_INT_ENA (BIT(22))
#define SLC_HOST_EXT_BIT2_INT_ENA (BIT(21))
#define SLC_HOST_EXT_BIT1_INT_ENA (BIT(20))
#define SLC_HOST_EXT_BIT0_INT_ENA (BIT(19))
#define SLC_HOST_RX_PF_VALID_INT_ENA (BIT(18))
#define SLC_HOST_TX_OVF_INT_ENA (BIT(17))
#define SLC_HOST_RX_UDF_INT_ENA (BIT(16))
#define SLC_HOST_TX_START_INT_ENA (BIT(15))
#define SLC_HOST_RX_START_INT_ENA (BIT(14))
#define SLC_HOST_RX_EOF_INT_ENA (BIT(13))
#define SLC_HOST_RX_SOF_INT_ENA (BIT(12))
#define SLC_HOST_TOKEN1_0TO1_INT_ENA (BIT(11))
#define SLC_HOST_TOKEN0_0TO1_INT_ENA (BIT(10))
#define SLC_HOST_TOKEN1_1TO0_INT_ENA (BIT(9))
#define SLC_HOST_TOKEN0_1TO0_INT_ENA (BIT(8))
#define SLC_HOST_TOHOST_BIT7_INT_ENA (BIT(7))
#define SLC_HOST_TOHOST_BIT6_INT_ENA (BIT(6))
#define SLC_HOST_TOHOST_BIT5_INT_ENA (BIT(5))
#define SLC_HOST_TOHOST_BIT4_INT_ENA (BIT(4))
#define SLC_HOST_TOHOST_BIT3_INT_ENA (BIT(3))
#define SLC_HOST_TOHOST_BIT2_INT_ENA (BIT(2))
#define SLC_HOST_TOHOST_BIT1_INT_ENA (BIT(1))
#define SLC_HOST_TOHOST_BIT0_INT_ENA (BIT(0))
#define SLC_HOST_CONF_W5 (REG_SLC_HOST_BASE + 0x3C)
#define SLC_HOST_CONF23 0x000000FF
#define SLC_HOST_CONF23_S 24
#define SLC_HOST_CONF22 0x000000FF
#define SLC_HOST_CONF22_S 16
#define SLC_HOST_CONF21 0x000000FF
#define SLC_HOST_CONF21_S 8
#define SLC_HOST_CONF20 0x000000FF
#define SLC_HOST_CONF20_S 0
#define SLC_HOST_WIN_CMD (REG_SLC_HOST_BASE + 0x40)
#define SLC_HOST_DATE (REG_SLC_HOST_BASE + 0x78)
#define SLC_HOST_ID (REG_SLC_HOST_BASE + 0x7C)
#define SLC_ADDR_WINDOW_CLEAR_MASK (~(0xf<<12))
#define SLC_FROM_HOST_ADDR_WINDOW (0x1<<12)
#define SLC_TO_HOST_ADDR_WINDOW (0x3<<12)
#define SLC_SET_FROM_HOST_ADDR_WINDOW(v) do { \
(v) &= 0xffff; \
(v) &= SLC_ADDR_WINDOW_CLEAR_MASK; \
(v) |= SLC_FROM_HOST_ADDR_WINDOW; \
} while (0);
#define SLC_SET_TO_HOST_ADDR_WINDOW(v) do { \
(v) &= 0xffff; \
(v) &= SLC_ADDR_WINDOW_CLEAR_MASK; \
(v) |= SLC_TO_HOST_ADDR_WINDOW; \
} while (0);
#define SLC_INT_ENA (REG_SLC_BASE + 0xC)
#define SLC_RX_EOF_INT_ENA BIT(17)
#define SLC_FRHOST_BIT2_INT_ENA BIT(2)
#define SLC_RX_LINK (REG_SLC_BASE + 0x24)
#define SLC_RXLINK_START BIT(29)
#define SLC_BRIDGE_CONF (REG_SLC_BASE + 0x44)
#define SLC_TX_PUSH_IDLE_NUM 0xFFFF
#define SLC_TX_PUSH_IDLE_NUM_S 16
#define SLC_HDA_MAP_128K BIT(13)
#define SLC_TX_DUMMY_MODE BIT(12)
#define SLC_FIFO_MAP_ENA 0x0000000F
#define SLC_FIFO_MAP_ENA_S 8
#define SLC_TXEOF_ENA 0x0000003F
#define SLC_TXEOF_ENA_S
#endif // SLC_HOST_REGISTER_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
/*
* Copyright (c) 2013 Espressif System.
*
* sdio stub code for allwinner
*/
#include <asm/io.h>
#include <mach/irqs.h>
#include <mach/io.h>
#include <mach/iomux.h>
#include <mach/pmu.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include <asm/mach/irq.h>
#include "../drivers/spi/rk29_spim.h"
#include "esp_sif.h"
//#define SPI_FREQ (20000000) // 1. 22.5Mhz 2. 45Mhz
#define SPI_FREQ (30000000) // 1. 22.5Mhz 2. 45Mhz
//Below are for spi HZ 22.5M
#if (SPI_FREQ == 30000000)
#define CMD_RESP_SIZE (10) //(50) //Common respon wait time
#define DATA_RESP_SIZE_W (142+45) // (1024*13)// (1024*16) //(398+400) // (1024*10) //Only for Write bytes function, data write response. max:(361+109)
#define DATA_RESP_SIZE_R (231+75) // (340+102) //(231+75)//(340+102) //Only for Read bytes function, data write response max:(340+102)
#define BLOCK_W_DATA_RESP_SIZE_EACH (10) //For each data write resp size, in block write
#define BLOCK_W_DATA_RESP_SIZE_FINAL (152) // (142+52) //For final data write resp size, in block write ,max: 119
#define BLOCK_R_DATA_RESP_SIZE_1ST (265) // (231+75) //For each data read resp size, in block read ,max: 134
#define BLOCK_R_DATA_RESP_SIZE_EACH (10) // (20) //For each data read resp size, in block read
#elif(SPI_FREQ == 20000000)
#define CMD_RESP_SIZE (10) //Common respon wait time
#define DATA_RESP_SIZE_W (103+40) //Only for Write bytes function, data write response. max: 103
#define DATA_RESP_SIZE_R (118+40) //Only for Read bytes function, data write response max: 118
//w: oxFF : 218 clock. oxFE : 214 clock.
#define BLOCK_W_DATA_RESP_SIZE_EACH (20) //For each data write resp size, in block write
#define BLOCK_W_DATA_RESP_SIZE_FINAL (112+40) //For final data write resp size, in block write ,max :112
#define BLOCK_R_DATA_RESP_SIZE_1ST (123+40) //For each data read resp size, in block read ,max: 123
#define BLOCK_R_DATA_RESP_SIZE_EACH (20) //For each data read resp size, in block read
#endif
//0xE5 ~0xFF 30us totoal
//
struct spi_device_id esp_spi_id[] = {
{"esp_spi_0", 0},
{"esp_spi_1", 1},
{},
};
#ifdef REGISTER_SPI_BOARD_INFO
static struct rk29xx_spi_chip spi_test_chip[] = {
{
//.poll_mode = 1,
.enable_dma = 1,
},
{
//.poll_mode = 1,
.enable_dma = 1,
},
};
static struct spi_board_info esp_board_spi_devices[] = {
{
.modalias = "esp_spi_0",
.bus_num = 0, //0 or 1
.max_speed_hz = 18*1000*1000,
.chip_select = 0,
.mode = SPI_MODE_3,
.controller_data = &spi_test_chip[0],
},
};
void sif_platform_register_board_info(void) {
spi_register_board_info(esp_board_spi_devices, ARRAY_SIZE(esp_board_spi_devices));
}
#endif /*REGISTER_SPI_BOARD_INFO*/
#define RK30_GPIO0_BASE RK2928_GPIO0_BASE
#define GPIO_NO RK30_PIN0_PA0
#define GPIO_BASE_ADDR ((unsigned char __iomem *) RK30_GPIO0_BASE)
#define GPIO_INT_MASK_OFFSET GPIO_INTEN
#define GPIO_INT_STAT_OFFSET GPIO_PORTS_EOI
int sif_platform_get_irq_no(void)
{
return gpio_to_irq(GPIO_NO);
}
int sif_platform_is_irq_occur(void)
{
return 1;
}
void sif_platform_irq_clear(void)
{
}
void sif_platform_irq_mask(int mask)
{
if (mask)
disable_irq_nosync(sif_platform_get_irq_no());
else
enable_irq(sif_platform_get_irq_no());
}
int sif_platform_irq_init(void)
{
int ret;
printk(KERN_ERR "%s enter\n", __func__);
if ( (ret = gpio_request(GPIO_NO, "esp_spi_int")) != 0) {
printk(KERN_ERR "request gpio error\n");
return ret;
}
gpio_direction_input(GPIO_NO);
sif_platform_irq_clear();
sif_platform_irq_mask(1);
udelay(1);
return 0;
}
void sif_platform_irq_deinit(void)
{
gpio_free(GPIO_NO);
}
void sif_platform_reset_target(void)
{
gpio_direction_output(RK30_PIN1_PB3, GPIO_LOW);
mdelay(200);
gpio_direction_output(RK30_PIN1_PB3, GPIO_HIGH);
mdelay(200);
}
void sif_platform_target_poweroff(void)
{
gpio_direction_output(RK30_PIN1_PB3, GPIO_LOW);
}
void sif_platform_target_poweron(void)
{
mdelay(200);
gpio_direction_output(RK30_PIN1_PB3, GPIO_LOW);
mdelay(200);
gpio_direction_output(RK30_PIN1_PB3, GPIO_HIGH);
mdelay(200);
}
void sif_platform_target_speed(int high_speed)
{
}
#ifdef ESP_ACK_INTERRUPT
void sif_platform_ack_interrupt(struct esp_pub *epub)
{
sif_platform_irq_clear();
}
#endif //ESP_ACK_INTERRUPT
module_init(esp_spi_init);
module_exit(esp_spi_exit);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
#ifndef __TEST_MODE
#define __TEST_MODE
enum {
TEST_CMD_UNSPEC,
TEST_CMD_ECHO,
TEST_CMD_ASK,
TEST_CMD_SLEEP,
TEST_CMD_WAKEUP,
TEST_CMD_LOOPBACK,
TEST_CMD_TX,
TEST_CMD_RX,
TEST_CMD_DEBUG,
TEST_CMD_SDIO_WR,
TEST_CMD_SDIO_RD,
TEST_CMD_ATE,
TEST_CMD_SDIOTEST,
TEST_CMD_SDIOSPEED,
__TEST_CMD_MAX,
};
#define TEST_CMD_MAX (__TEST_CMD_MAX - 1)
enum {
TEST_ATTR_UNSPEC,
TEST_ATTR_CMD_NAME,
TEST_ATTR_CMD_TYPE,
TEST_ATTR_PARA_NUM,
TEST_ATTR_PARA0,
TEST_ATTR_PARA1,
TEST_ATTR_PARA2,
TEST_ATTR_PARA3,
TEST_ATTR_PARA4,
TEST_ATTR_PARA5,
TEST_ATTR_PARA6,
TEST_ATTR_PARA7,
TEST_ATTR_STR,
__TEST_ATTR_MAX,
};
#define TEST_ATTR_MAX (__TEST_ATTR_MAX - 1)
#define TEST_ATTR_PARA(i) (TEST_ATTR_PARA0+(i))
enum {
RD_REG = 0,
WR_REG,
SET_SENSE,
SET_TX_RATE,
SET_TX_FREQ,
TKIP_MIC_ERROR,
RIFS_CTRL,
BACKOFF,
SET_RXSENSE,
CONFIGURE_TRC,
RDPER,
RDRSSI,
DBGTRC,
WRMEM,
RDMEM
};
u32 get_loopback_num(void);
u32 get_loopback_id(void);
void inc_loopback_id(void);
void esp_test_ate_done_cb(char *ep);
struct sdiotest_param {
atomic_t start;
u32 mode; //1: read 2: write 3: read&write
u32 addr;
u32 idle_period; //in msec
struct task_struct *thread;
};
#endif //__TEST_MODE