Initial driver upload
This commit is contained in:
commit
7ef9e52f3a
42 changed files with 13418 additions and 0 deletions
129
Makefile
Normal file
129
Makefile
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
CURRENT_PATH := $(shell pwd)
|
||||||
|
|
||||||
|
#Hi3516
|
||||||
|
#ARCH := arm
|
||||||
|
#COMPILER := arm-himix100-linux-
|
||||||
|
#LINUX_KERNEL_PATH := /home/matt/Hi3516/Hi3516EV200_SDK_V1.0.0.1/osdrv/opensource/kernel/linux-4.9.y
|
||||||
|
|
||||||
|
#Hi3518
|
||||||
|
#ARCH := arm
|
||||||
|
#COMPILER := arm-hisiv300-linux-uclibcgnueabi-
|
||||||
|
#LINUX_KERNEL_PATH := /home/matt/Hi3518/hi3518/linux-3.4.y
|
||||||
|
|
||||||
|
#FH8852
|
||||||
|
#ARCH := arm
|
||||||
|
#COMPILER := arm-fullhan-linux-uclibcgnueabi-
|
||||||
|
#LINUX_KERNEL_PATH := /home/matt/FH8852/FH8856_IPC_V1.1.0_20190125/board_support/kernel/linux-3.0.8
|
||||||
|
|
||||||
|
#Hi3536d
|
||||||
|
#ARCH := arm
|
||||||
|
#COMPILER := arm-hisiv510-linux-uclibcgnueabi-
|
||||||
|
#LINUX_KERNEL_PATH := /home/matt/Hi3536d/Hi3536DV100_SDK_V1.0.2.0/osdrv/opensource/kernel/linux-4.9.y
|
||||||
|
|
||||||
|
#OpenWRT MT7628
|
||||||
|
#ARCH := mips
|
||||||
|
#COMPILER := /home/matt/openwrt/openwrt/staging_dir/toolchain-mipsel_24kc_gcc-7.3.0_musl/bin/mipsel-openwrt-linux-
|
||||||
|
#LINUX_KERNEL_PATH := /home/matt/openwrt/openwrt/build_dir/target-mipsel_24kc_musl/linux-ramips_mt76x8/linux-4.14.151
|
||||||
|
#export STAGING_DIR = $(COMPILER)
|
||||||
|
|
||||||
|
#MTK SDK
|
||||||
|
ARCH := mips
|
||||||
|
COMPILER := /opt/buildroot-gcc463/usr/bin/mipsel-linux-
|
||||||
|
LINUX_KERNEL_PATH := /home/dongyun/work/disk4/AH6001/RT288x_AHv1.2/source/linux-3.10.14.x
|
||||||
|
|
||||||
|
#Raspberry Pi
|
||||||
|
#ARCH := arm
|
||||||
|
#LINUX_KERNEL := $(shell uname -r)
|
||||||
|
#LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS += -DCONFIG_HGIC_AH
|
||||||
|
#CFLAGS += -DCONFIG_HGIC_2G
|
||||||
|
|
||||||
|
export CONFIG_HGIC_AH = y
|
||||||
|
#export CONFIG_HGIC_2G = y
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "-------------------------------------------------------------------------------------------------------------------"
|
||||||
|
@echo "usage:"
|
||||||
|
@echo " make smac : compile SMAC driver. generate 3 ko files : hgics.ko, hgic_sdio.ko hgic_usb.ko."
|
||||||
|
@echo " make smac_usb : compile SMAC driver. generate 1 ko file : hgics_usb.ko (combined hgics.ko and hgic_usb.ko)."
|
||||||
|
@echo " make smac_sdio: compile SMAC driver. generate 1 ko file : hgics_sdio.ko (combined hgics.ko and hgic_sdio.ko)."
|
||||||
|
@echo ""
|
||||||
|
@echo " make fmac : compile FMAC driver. generate 3 ko files : hgicf.ko, hgic_sdio.ko hgic_usb.ko."
|
||||||
|
@echo " make fmac_usb : compile FMAC driver. generate 1 ko file : hgicf_usb.ko (combined hgicf.ko and hgic_usb.ko)."
|
||||||
|
@echo " make fmac_sdio: compile FMAC driver. generate 1 ko file : hgicf_sdio.ko (combined hgicf.ko and hgic_sdio.ko)."
|
||||||
|
@echo ""
|
||||||
|
@echo " make clean"
|
||||||
|
@echo "-------------------------------------------------------------------------------------------------------------------"
|
||||||
|
|
||||||
|
smac: prepare _smac _driver_smac
|
||||||
|
|
||||||
|
fmac: prepare _fmac _driver_fmac
|
||||||
|
|
||||||
|
smac_usb: prepare _smac_usb
|
||||||
|
|
||||||
|
smac_sdio: prepare _smac_sdio
|
||||||
|
|
||||||
|
fmac_usb: prepare _fmac_usb
|
||||||
|
|
||||||
|
fmac_sdio: prepare _fmac_sdio
|
||||||
|
|
||||||
|
prepare:
|
||||||
|
mkdir -p ko
|
||||||
|
|
||||||
|
_fmac:
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/hgic_fmac ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) CONFIG_HGICF=hgicf EXTRA_CFLAGS=$(CFLAGS) modules
|
||||||
|
cp -f hgic_fmac/hgicf.ko ko/hgicf.ko
|
||||||
|
$(COMPILER)strip -g ko/hgicf.ko
|
||||||
|
|
||||||
|
_smac:
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/hgic_smac ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) CONFIG_HGICS=hgics EXTRA_CFLAGS=$(CFLAGS) modules
|
||||||
|
cp -f hgic_smac/hgics.ko ko/hgics.ko
|
||||||
|
$(COMPILER)strip -g ko/hgics.ko
|
||||||
|
|
||||||
|
_fmac_sdio:
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/hgic_fmac ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) CONFIG_HGICF=hgicf_sdio EXTRA_CFLAGS="$(CFLAGS) -DCONFIG_HGIC_SDIOIN" modules
|
||||||
|
cp -f hgic_fmac/hgicf_sdio.ko ko/hgicf_sdio.ko
|
||||||
|
$(COMPILER)strip -g ko/hgicf_sdio.ko
|
||||||
|
|
||||||
|
_fmac_usb:
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/hgic_fmac ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) CONFIG_HGICF=hgicf_usb EXTRA_CFLAGS="$(CFLAGS) -DCONFIG_HGIC_USBIN" modules
|
||||||
|
cp -f hgic_fmac/hgicf_usb.ko ko/hgicf_usb.ko
|
||||||
|
$(COMPILER)strip -g ko/hgicf_usb.ko
|
||||||
|
|
||||||
|
_smac_sdio:
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/hgic_smac ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) CONFIG_HGICS=hgics_sdio EXTRA_CFLAGS="$(CFLAGS) -DCONFIG_HGIC_SDIOIN" modules
|
||||||
|
cp -f hgic_smac/hgics_sdio.ko ko/hgics_sdio.ko
|
||||||
|
$(COMPILER)strip -g ko/hgics_sdio.ko
|
||||||
|
|
||||||
|
_smac_usb:
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/hgic_smac ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) CONFIG_HGICS=hgics_usb EXTRA_CFLAGS="$(CFLAGS) -DCONFIG_HGIC_USBIN" modules
|
||||||
|
cp -f hgic_smac/hgics_usb.ko ko/hgics_usb.ko
|
||||||
|
$(COMPILER)strip -g ko/hgics_usb.ko
|
||||||
|
|
||||||
|
_driver_fmac:
|
||||||
|
cp -f hgic_fmac/Module.symvers utils/Module.symvers
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/utils ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) EXTRA_CFLAGS=$(CFLAGS) modules
|
||||||
|
cp -f utils/hgic_usb.ko ko/hgic_usb.ko
|
||||||
|
cp -f utils/hgic_sdio.ko ko/hgic_sdio.ko
|
||||||
|
$(COMPILER)strip -g ko/hgic_usb.ko
|
||||||
|
$(COMPILER)strip -g ko/hgic_sdio.ko
|
||||||
|
|
||||||
|
_driver_smac:
|
||||||
|
cp -f hgic_smac/Module.symvers utils/Module.symvers
|
||||||
|
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)/utils ARCH=$(ARCH) CROSS_COMPILE=$(COMPILER) EXTRA_CFLAGS=$(CFLAGS) modules
|
||||||
|
cp -f utils/hgic_usb.ko ko/hgic_usb.ko
|
||||||
|
cp -f utils/hgic_sdio.ko ko/hgic_sdio.ko
|
||||||
|
$(COMPILER)strip -g ko/hgic_usb.ko
|
||||||
|
$(COMPILER)strip -g ko/hgic_sdio.ko
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order
|
||||||
|
cd hgic_fmac ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko Module.symvers modules.order
|
||||||
|
cd hgic_smac ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko Module.symvers modules.order
|
||||||
|
cd hgic_smac/umac ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
|
||||||
|
cd hgic_smac/umac/cfg80211 ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
|
||||||
|
cd hgic_smac/umac/mac80211 ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
|
||||||
|
cd utils ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko Module.symvers modules.order
|
||||||
|
rm -rf ko
|
224
changelog.txt
Normal file
224
changelog.txt
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
2022/01/12
|
||||||
|
修改bug:sdio remove过程中,执行hgic_core_remove时可能会rx data,此时会出现死机现象。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2022/01/10
|
||||||
|
固件下载功能优化:在固件下载阶段,屏蔽其它数据和cmd的发送, 避免干扰固件下载过程。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/12/22
|
||||||
|
fmac: 新增event:HGIC_EVENT_UNPAIR_STA, 解除配对时,固件产生此event。
|
||||||
|
新增:tx maxcnt 命令,用于设置最大帧重传次数。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/11/19
|
||||||
|
fmac: 添加AP隐藏功能, iwpriv hg0 set ap_hide 1
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/11/08
|
||||||
|
解决驱动卸载死机问题。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/11/01
|
||||||
|
fmac: 添加漫游功能设置接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/09/28
|
||||||
|
smac:
|
||||||
|
1. 修改bug: remove 时 先 确保 alive_timer/alive_work/delay_init 已经停止运行
|
||||||
|
2. hgic_frm_hdr.tx_info : 清零
|
||||||
|
3. ETH_P_PAE 类型数据使用最高优先级
|
||||||
|
fmac:
|
||||||
|
1. 修改bug: remove 时 先 确保 alive_timer/alive_work/delay_init 已经停止运行
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/09/27
|
||||||
|
添加 macfilter/atcmd 命令接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/09/23
|
||||||
|
1. 优化固件下载功能,减少对 memory 的需求。
|
||||||
|
2. 模块监测功能修改:接口只要支持reinit,就默认开启该功能,用于监测是否需要重新下载固件。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/09/13
|
||||||
|
get module_type 修改,定义了 struct hgic_module_hwinfo 结构体。
|
||||||
|
使用方法参考: hgic_fmac.c
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/08/26
|
||||||
|
添加 HGIC_HDR_TYPE_CMD2 和 HGIC_HDR_TYPE_EVENT2,扩展 cmd id 和 event id 到 uint16.
|
||||||
|
添加 reset sta 接口:用于复位remote sta。
|
||||||
|
添加 set freqinfo接口:用于设置remote sta的频点信息。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/07/05
|
||||||
|
fmac: 添加 proc pairing_sta接口,读取当前配对sta的mac地址
|
||||||
|
添加 hgic_fmac.c 驱动接口封装API。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/06/17
|
||||||
|
fmac: 添加 iwpriv acktmo 命令。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/06/10
|
||||||
|
fmac: 添加 iwpriv dcdc13 命令。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/05/28
|
||||||
|
fmac: 添加 /proc/hgic/battery_soc 接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/05/26
|
||||||
|
fix bug: 使用驱动包iwpriv脚本执行get命令时驱动崩溃。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/05/06
|
||||||
|
fix bug: AH模块卸载时,wifi driver 死机问题。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/04/16
|
||||||
|
fix bug: fmac driver,alive_work 设置 HGICF_DEV_FLAGS_SUSPEND 后,在 delay_init 中需要清除该标识。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/03/23
|
||||||
|
fmac: 添加 /proc/hgic/evm 接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/03/10
|
||||||
|
fmac: 添加 iwpriv get key_mgmt 接口,获取加密方式。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/25
|
||||||
|
fmac: 添加 iwpriv autosleep_time 接口,设置auto sleep时间。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/25
|
||||||
|
if_sdio: 支持 NON_POLL 模式下载固件和模块复位检测。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/25
|
||||||
|
hgic_sdio: 支持 sdio spi boot
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/18
|
||||||
|
hgic_sdio: 支持 sdio spi模式。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/18
|
||||||
|
fmac: 添加 iwpriv sysdbg接口,设置调试信息的开关。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/04
|
||||||
|
fmac: 添加 iwpriv dbginfo接口,调试信息重定向。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/04
|
||||||
|
fmac: 添加 iwpriv wakeup_io接口,自定义唤醒IO。
|
||||||
|
fmac: 添加 procfs event接口,用于查询固件产生的event。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2021/02/02
|
||||||
|
fmac:
|
||||||
|
iwpriv hg0 set loaddef=0 恢复出厂参数后不重启
|
||||||
|
iwpriv hg0 set loaddef=1 恢复出厂参数后重启
|
||||||
|
fmac: 添加 iwpriv reassoc_wkhost 设置断线重连后唤醒主控。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/31
|
||||||
|
fmac: 添加 iwpriv mcast_key 设置组播数据加密key.
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/31
|
||||||
|
fix bug: 解析mac字符串出错,造成wakesta 地址不对。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/21
|
||||||
|
fmac: 添加 iwpriv unpair 命令,解除配对信息。
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/17
|
||||||
|
fmac: 驱动参数默认值修改。
|
||||||
|
添加 /proc/hgic/wkreason 接口,查询WiFi模块唤醒原因。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/15
|
||||||
|
fmac: 解决驱动remove时出现的死机问题。
|
||||||
|
添加 iwpriv aplost_time 参数,设置sta检测ap lost的超时时间,默认90秒。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/14
|
||||||
|
fmac: fw_ver procfs接口,获取WiFi模块固件版本信息。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/14
|
||||||
|
fmac: 增加ps_mode参数接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/11
|
||||||
|
fmac: iwpriv添加命令接口:
|
||||||
|
dtim_period:设置DTIM周期
|
||||||
|
disassoc_sta:AP端主动断开指定的sta。
|
||||||
|
loaddef:恢复出厂参数。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/07
|
||||||
|
添加 wkio_mode 设置接口, 设置wakeup IO的触发模式。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/12/02
|
||||||
|
fmac: 添加 /proc/hgic/pair_state接口,用于查看配对状态:1-配对成功,0-配对未成功。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/11/28
|
||||||
|
添加 max_idle_period 设置接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/11/18
|
||||||
|
fmac:wifi模块休眠后,Host端wifi驱动不再发送数据。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/11/11
|
||||||
|
新增功能: for 电池摄像机,添加建立连接的省电模式。在AP异常时,避免频繁重连耗尽电池。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/11/07
|
||||||
|
新增功能: 支持客户自定义低功耗模式下的心跳包和唤醒包。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/10/14
|
||||||
|
解决驱动处理request param消息存在内存泄露的问题。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/09/30
|
||||||
|
部分参数添加互斥机制。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/09/29
|
||||||
|
fmac: 添加 get bss_bw/freq_range/chan_list/agg_cnt 接口。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/09/27
|
||||||
|
fmac: 添加 /etc/hgicf.conf 文件,驱动自动加载参数。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/09/17
|
||||||
|
1. 添加了驱动重新下载参数到固件;wifi模块重启后参数丢失,可以通知host重新加载参数。
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/09/02
|
||||||
|
1. smac 添加 /proc/hgic/recfg 接口,支持重新加载驱动参数。
|
||||||
|
2. smac 添加 /proc/hgic/radio_off 接口,用于控制 radio on/off.
|
||||||
|
3. fmac 添加 iwpriv radio_off 命令,用于控制radio on/off
|
||||||
|
4. fmac 添加 JOIN_GROUP/SET_ETHERTYPE 命令。
|
||||||
|
5. fmac 添加 proc/hgic/sta_count 接口。
|
||||||
|
6. fix 空指针异常bug.
|
||||||
|
7. Update : AX218 usb bootdl max packet length is 2048,so reduce usb boot packet length
|
||||||
|
8. fix usb 固件下载运行的bug。
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------
|
||||||
|
2020/08/04
|
||||||
|
fmac: 添加 iwpriv get ssid/wpapsk 命令.
|
83
fmac.sh
Executable file
83
fmac.sh
Executable file
|
@ -0,0 +1,83 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
#interface name
|
||||||
|
IFNAME="hg0"
|
||||||
|
|
||||||
|
# ko file path
|
||||||
|
FMAC_KO_PATH="/lib/modules/3.10.14/kernel/drivers/net/wireless/hugeic/hgic_fmac/hgicf.ko"
|
||||||
|
USB_KO_PATH="/lib/modules/3.10.14/kernel/drivers/net/wireless/hugeic/utils/hgic_usb.ko"
|
||||||
|
SDIO_KO_PATH="/lib/modules/3.10.14/kernel/drivers/net/wireless/hugeic/utils/hgic_sdio.ko"
|
||||||
|
|
||||||
|
#read paramters from system.
|
||||||
|
AH_MODE=ap
|
||||||
|
AH_SSID=ah_test_ssid
|
||||||
|
AH_PSK=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
|
||||||
|
AH_KEY_MGMT=NONE
|
||||||
|
AH_FREQ_START=7600
|
||||||
|
AH_FREQ_END=7680
|
||||||
|
AH_BSS_BW=8
|
||||||
|
AH_TX_MCS=255
|
||||||
|
AH_CHAN_LIST=
|
||||||
|
|
||||||
|
#set default values
|
||||||
|
[ -z "$AH_MODE" ] && AH_MODE="ap"
|
||||||
|
[ -z "$AH_FREQ_START" ] && AH_FREQ_START="7800"
|
||||||
|
[ -z "$AH_FREQ_END" ] && AH_FREQ_END="8000"
|
||||||
|
[ -z "$AH_BSS_BW" ] && AH_BSS_BW="8"
|
||||||
|
[ -z "$AH_TX_MCS" ] && AH_TX_MCS="7"
|
||||||
|
[ -z "$AH_CHANNEL" ] && AH_CHANNEL="1"
|
||||||
|
[ -z "$AH_ACS" ] && AH_ACS="0"
|
||||||
|
[ -z "$AH_ACS_TM" ] && AH_ACS_TM="10"
|
||||||
|
[ -z "$AH_TX_POWER" ] && AH_TX_POWER="1"
|
||||||
|
[ "$AH_MODE" == "sta" ] && AH_ACS="0"
|
||||||
|
[ "$AH_ACS" == "1" ] && AH_CHANNEL="1"
|
||||||
|
|
||||||
|
#insmod driver
|
||||||
|
ko_exist=$(lsmod|grep hgicf)
|
||||||
|
if [ -z "$ko_exist" ]; then
|
||||||
|
[ -n "$FMAC_KO_PATH" ] && insmod $FMAC_KO_PATH $ARG_IF_TEST
|
||||||
|
[ -n "$SDIO_KO_PATH" ] && insmod $SDIO_KO_PATH
|
||||||
|
[ -n "$USB_KO_PATH" ] && insmod $USB_KO_PATH
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#set param
|
||||||
|
CONN_STATE=$(cat /proc/hgic/conn_state|grep CONNECTED)
|
||||||
|
if [ -z "$CONN_STATE" ]; then
|
||||||
|
ifconfig $IFNAME down
|
||||||
|
iwpriv $IFNAME set freq_range=$AH_FREQ_START,$AH_FREQ_END,$AH_BSS_BW
|
||||||
|
iwpriv $IFNAME set mode=$AH_MODE
|
||||||
|
iwpriv $IFNAME set bss_bw=$AH_BSS_BW
|
||||||
|
iwpriv $IFNAME set tx_mcs=$AH_TX_MCS
|
||||||
|
iwpriv $IFNAME set tx_power=$AH_TX_POWER
|
||||||
|
iwpriv $IFNAME set channel=$AH_CHANNEL
|
||||||
|
iwpriv $IFNAME set acs="$AH_ACS,$AH_ACS_TM"
|
||||||
|
if [ x"$AH_KEY_MGMT" == "xWPA-PSK" ]; then
|
||||||
|
iwpriv $IFNAME set key_mgmt=WPA-PSK
|
||||||
|
iwpriv $IFNAME set wpa_psk=$AH_PSK
|
||||||
|
else
|
||||||
|
iwpriv $IFNAME set key_mgmt=NONE
|
||||||
|
fi
|
||||||
|
iwpriv $IFNAME set ssid=$AH_SSID
|
||||||
|
#save config
|
||||||
|
iwpriv $IFNAME save
|
||||||
|
[ "$AH_BSS_BW" == "1" ] && ifconfig $IFNAME mtu 380
|
||||||
|
fi
|
||||||
|
|
||||||
|
#up interface
|
||||||
|
ifconfig $IFNAME up
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# 可以设置驱动参数文件,由驱动自动加载参数,需要如下3个步骤:
|
||||||
|
# 1. 生成参数文件:/etc/hgicf.conf,内容如下:
|
||||||
|
# freq_range=9000,9240,8
|
||||||
|
# mode=ap
|
||||||
|
# ssid=ah_test_ssid
|
||||||
|
# key_mgmt=WPA-PSK
|
||||||
|
# wpa_psk=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
|
||||||
|
# [以上参数是最基本的参数设置,其他参数设置请参考 Linux开发指南]
|
||||||
|
#
|
||||||
|
# 2. insmod 驱动
|
||||||
|
# 3. ifconfig up 接口
|
||||||
|
###########################################################
|
255
hgic.h
Normal file
255
hgic.h
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
#ifndef _HUGE_IC_H_
|
||||||
|
#define _HUGE_IC_H_
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#define HGIC_CMD_START 100
|
||||||
|
#else
|
||||||
|
#define HGIC_CMD_START 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*hgic_init_cb)(void *args);
|
||||||
|
typedef void (*hgic_event_cb)(char *ifname, int event, int param1, int param2);
|
||||||
|
|
||||||
|
struct hgic_bss_info {
|
||||||
|
unsigned char bssid[6];
|
||||||
|
unsigned char ssid[32];
|
||||||
|
unsigned char encrypt;
|
||||||
|
char signal;
|
||||||
|
unsigned short freq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fw_info {
|
||||||
|
unsigned int version;
|
||||||
|
unsigned int svn_version;
|
||||||
|
unsigned short chip_id;
|
||||||
|
unsigned short cpu_id;
|
||||||
|
unsigned char mac[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_sta_info {
|
||||||
|
unsigned char aid;
|
||||||
|
unsigned char ps:1;
|
||||||
|
unsigned char addr[6];
|
||||||
|
char rssi;
|
||||||
|
char evm;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_freqinfo {
|
||||||
|
unsigned char bss_bw, chan_cnt;
|
||||||
|
unsigned short freq_start, freq_end;
|
||||||
|
unsigned short chan_list[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_module_hwinfo{
|
||||||
|
union{
|
||||||
|
struct{
|
||||||
|
unsigned char type;
|
||||||
|
unsigned char saw:1, rev:7;
|
||||||
|
};
|
||||||
|
unsigned short v;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hgic_cmd {
|
||||||
|
HGIC_CMD_DEV_OPEN = HGIC_CMD_START + 0x01, // 1
|
||||||
|
HGIC_CMD_DEV_CLOSE, // 2
|
||||||
|
HGIC_CMD_SET_MAC, // 3
|
||||||
|
HGIC_CMD_SET_SSID, // 4
|
||||||
|
HGIC_CMD_SET_BSSID, // 5
|
||||||
|
HGIC_CMD_SET_COUNTERY, // 6
|
||||||
|
HGIC_CMD_SET_CHANNEL, // 7
|
||||||
|
HGIC_CMD_SET_CENTER_FREQ, // 8
|
||||||
|
HGIC_CMD_SET_RTS_THRESHOLD, // 9
|
||||||
|
HGIC_CMD_SET_FRG_THRESHOLD, // 10
|
||||||
|
HGIC_CMD_SET_KEY_MGMT, // 11
|
||||||
|
HGIC_CMD_SET_WPA_PSK, // 12
|
||||||
|
HGIC_CMD_SET_KEY, // 13
|
||||||
|
HGIC_CMD_SCAN, // 14
|
||||||
|
HGIC_CMD_GET_SCAN_LIST, // 15
|
||||||
|
HGIC_CMD_SET_BSSID_FILTER, // 16
|
||||||
|
HGIC_CMD_DISCONNECT, // 17
|
||||||
|
HGIC_CMD_GET_BSSID, // 18
|
||||||
|
HGIC_CMD_SET_WBNAT, // 19
|
||||||
|
HGIC_CMD_GET_STATUS, // 20
|
||||||
|
HGIC_CMD_SET_LISTEN_INTERVAL, // 21
|
||||||
|
HGIC_CMD_SET_TX_POWER, // 22
|
||||||
|
HGIC_CMD_GET_TX_POWER, // 23
|
||||||
|
HGIC_CMD_SET_TX_LCOUNT, // 24
|
||||||
|
HGIC_CMD_SET_TX_SCOUNT, // 25
|
||||||
|
HGIC_CMD_ADD_STA, // 26
|
||||||
|
HGIC_CMD_REMOVE_STA, // 27
|
||||||
|
HGIC_CMD_SET_TX_BW, // 28
|
||||||
|
HGIC_CMD_SET_TX_MCS, // 29
|
||||||
|
HGIC_CMD_SET_FREQ_RANGE, // 30
|
||||||
|
HGIC_CMD_ACS_ENABLE, // 31
|
||||||
|
HGIC_CMD_SET_PRIMARY_CHAN, // 32
|
||||||
|
HGIC_CMD_SET_BG_RSSI, // 33
|
||||||
|
HGIC_CMD_SET_BSS_BW, // 34
|
||||||
|
HGIC_CMD_TESTMODE_CMD, // 35
|
||||||
|
HGIC_CMD_SET_AID, // 36
|
||||||
|
HGIC_CMD_GET_FW_STATE, // 37
|
||||||
|
HGIC_CMD_SET_TXQ_PARAM, // 38
|
||||||
|
HGIC_CMD_SET_CHAN_LIST, // 39
|
||||||
|
HGIC_CMD_GET_CONN_STATE, // 40
|
||||||
|
HGIC_CMD_SET_WORK_MODE, // 41
|
||||||
|
HGIC_CMD_SET_PAIRED_STATIONS, // 42
|
||||||
|
HGIC_CMD_GET_FW_INFO, // 43
|
||||||
|
HGIC_CMD_PAIRING, // 44
|
||||||
|
HGIC_CMD_GET_TEMPERATURE, // 45
|
||||||
|
HGIC_CMD_ENTER_SLEEP, // 46
|
||||||
|
HGIC_CMD_OTA, // 47
|
||||||
|
HGIC_CMD_GET_SSID, // 48
|
||||||
|
HGIC_CMD_GET_WPA_PSK, // 49
|
||||||
|
HGIC_CMD_GET_SIGNAL, // 50
|
||||||
|
HGIC_CMD_GET_TX_BITRATE, // 51
|
||||||
|
HGIC_CMD_SET_BEACON_INT, // 52
|
||||||
|
HGIC_CMD_GET_STA_LIST, // 53
|
||||||
|
HGIC_CMD_SAVE_CFG, // 54
|
||||||
|
HGIC_CMD_JOIN_GROUP, // 55
|
||||||
|
HGIC_CMD_SET_ETHER_TYPE, // 56
|
||||||
|
HGIC_CMD_GET_STA_COUNT, // 57
|
||||||
|
HGIC_CMD_SET_HEARTBEAT_INT, // 58
|
||||||
|
HGIC_CMD_SET_MCAST_KEY, // 59
|
||||||
|
HGIC_CMD_SET_AGG_CNT, // 60
|
||||||
|
HGIC_CMD_GET_AGG_CNT, // 61
|
||||||
|
HGIC_CMD_GET_BSS_BW , // 62
|
||||||
|
HGIC_CMD_GET_FREQ_RANGE, // 63
|
||||||
|
HGIC_CMD_GET_CHAN_LIST, // 64
|
||||||
|
HGIC_CMD_RADIO_ONOFF, // 65
|
||||||
|
HGIC_CMD_SET_PS_HEARTBEAT, // 66
|
||||||
|
HGIC_CMD_SET_WAKEUP_STA, // 67
|
||||||
|
HGIC_CMD_SET_PS_HEARTBEAT_RESP, // 68
|
||||||
|
HGIC_CMD_SET_PS_WAKEUP_DATA, // 69
|
||||||
|
HGIC_CMD_SET_PS_CONNECT, // 70
|
||||||
|
HGIC_CMD_SET_BSS_MAX_IDLE, // 71
|
||||||
|
HGIC_CMD_SET_WKIO_MODE, // 72
|
||||||
|
HGIC_CMD_SET_DTIM_PERIOD, // 73
|
||||||
|
HGIC_CMD_SET_PS_MODE, // 74
|
||||||
|
HGIC_CMD_LOAD_DEF, // 75
|
||||||
|
HGIC_CMD_DISASSOC_STA, // 76
|
||||||
|
HGIC_CMD_SET_APLOST_TIME, // 77
|
||||||
|
HGIC_CMD_GET_WAKEUP_REASON, // 78
|
||||||
|
HGIC_CMD_UNPAIR, // 79
|
||||||
|
HGIC_CMD_SET_AUTO_CHAN_SWITCH, // 80
|
||||||
|
HGIC_CMD_SET_REASSOC_WKHOST, // 81
|
||||||
|
HGIC_CMD_SET_WAKEUP_IO, // 82
|
||||||
|
HGIC_CMD_DBGINFO_OUTPUT, // 83
|
||||||
|
HGIC_CMD_SET_SYSDBG, // 84
|
||||||
|
HGIC_CMD_SET_AUTO_SLEEP_TIME, // 85
|
||||||
|
HGIC_CMD_GET_KEY_MGMT, // 86
|
||||||
|
HGIC_CMD_SET_PAIR_AUTOSTOP, // 87
|
||||||
|
HGIC_CMD_SET_SUPPER_PWR, // 88
|
||||||
|
HGIC_CMD_SET_REPEATER_SSID, // 89
|
||||||
|
HGIC_CMD_SET_REPEATER_PSK, // 90
|
||||||
|
HGIC_CMD_CFG_AUTO_SAVE, // 91
|
||||||
|
HGIC_CMD_SEND_CUST_MGMT, // 92
|
||||||
|
HGIC_CMD_GET_BATTERY_LEVEL, // 93
|
||||||
|
HGIC_CMD_SET_DCDC13, // 94
|
||||||
|
HGIC_CMD_SET_ACKTMO, // 95
|
||||||
|
HGIC_CMD_GET_MODULETYPE, // 96
|
||||||
|
HGIC_CMD_PA_PWRCTRL_DIS, // 97
|
||||||
|
HGIC_CMD_SET_DHCPC, // 98
|
||||||
|
HGIC_CMD_GET_DHCPC_RESULT, // 99
|
||||||
|
HGIC_CMD_SET_WKUPDATA_MASK, // 100
|
||||||
|
HGIC_CMD_GET_WKDATA_BUFF, // 101
|
||||||
|
HGIC_CMD_GET_DISASSOC_REASON, // 102
|
||||||
|
HGIC_CMD_SET_WKUPDATA_SAVEEN, // 103
|
||||||
|
HGIC_CMD_SET_CUST_DRIVER_DATA, // 104
|
||||||
|
HGIC_CMD_SET_MCAST_TXPARAM, // 105
|
||||||
|
HGIC_CMD_SET_STA_FREQINFO, // 106
|
||||||
|
HGIC_CMD_SET_RESET_STA, // 107
|
||||||
|
HGIC_CMD_SET_UART_FIXLEN, // 108
|
||||||
|
HGIC_CMD_GET_UART_FIXLEN, // 109
|
||||||
|
HGIC_CMD_SET_ANT_AUTO, // 110
|
||||||
|
HGIC_CMD_SET_ANT_SEL, // 111
|
||||||
|
HGIC_CMD_GET_ANT_SEL, // 112
|
||||||
|
HGIC_CMD_SET_WKUP_HOST_REASON, // 113
|
||||||
|
HGIC_CMD_SET_MAC_FILTER_EN, // 114
|
||||||
|
HGIC_CMD_SET_ATCMD, // 115
|
||||||
|
HGIC_CMD_SET_ROAMING, // 116
|
||||||
|
HGIC_CMD_SET_AP_HIDE, // 117
|
||||||
|
HGIC_CMD_SET_DUAL_ANT, // 118
|
||||||
|
HGIC_CMD_SET_MAX_TCNT, // 119
|
||||||
|
HGIC_CMD_SET_ASSERT_HOLDUP, // 120
|
||||||
|
HGIC_CMD_SET_AP_PSMODE_EN, // 121
|
||||||
|
HGIC_CMD_SET_DUPFILTER_EN, // 122
|
||||||
|
HGIC_CMD_SET_DIS_1V1_M2U, // 123
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hgic_event {
|
||||||
|
HGIC_EVENT_STATE_CHG = 0x1, // 1
|
||||||
|
HGIC_EVENT_CH_SWICH, // 2
|
||||||
|
HGIC_EVENT_DISCONNECT_REASON, // 3
|
||||||
|
HGIC_EVENT_ASSOC_STATUS, // 4
|
||||||
|
HGIC_EVENT_SCANNING, // 5
|
||||||
|
HGIC_EVENT_SCAN_DONE, // 6
|
||||||
|
HGIC_EVENT_TX_BITRATE, // 7
|
||||||
|
HGIC_EVENT_PAIR_START, // 8
|
||||||
|
HGIC_EVENT_PAIR_SUCCESS, // 9
|
||||||
|
HGIC_EVENT_PAIR_DONE, // 10
|
||||||
|
HGIC_EVENT_CONECT_START, // 11
|
||||||
|
HGIC_EVENT_CONECTED, // 12
|
||||||
|
HGIC_EVENT_DISCONECTED, // 13
|
||||||
|
HGIC_EVENT_SIGNAL, // 14
|
||||||
|
HGIC_EVENT_DISCONNET_LOG, // 15
|
||||||
|
HGIC_EVENT_REQUEST_PARAM, // 16
|
||||||
|
HGIC_EVENT_TESTMODE_STATE, // 17
|
||||||
|
HGIC_EVENT_FWDBG_INFO, // 18
|
||||||
|
HGIC_EVENT_CUSTOMER_MGMT, // 19
|
||||||
|
HGIC_EVENT_SLEEP_FAIL, // 20
|
||||||
|
HGIC_EVENT_DHCPC_DONE, // 21
|
||||||
|
HGIC_EVENT_CONNECT_FAIL, // 22
|
||||||
|
HGIC_EVENT_CUST_DRIVER_DATA, // 23
|
||||||
|
HGIC_EVENT_UNPAIR_STA, // 24
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int hgic_sdio_init(void);
|
||||||
|
extern void hgic_sdio_exit(void);
|
||||||
|
extern int hgic_usb_init(void);
|
||||||
|
extern void hgic_usb_exit(void);
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
struct firmware {
|
||||||
|
unsigned char *data;
|
||||||
|
unsigned int size;
|
||||||
|
};
|
||||||
|
int request_firmware(const struct firmware **fw, const char *name, void *dev);
|
||||||
|
void release_firmware(struct firmware *fw);
|
||||||
|
|
||||||
|
extern int hgicf_init(void);
|
||||||
|
extern int hgicf_cmd(char *ifname, unsigned int cmd, unsigned int param1, unsigned int param2);
|
||||||
|
extern int hgics_init(void);
|
||||||
|
extern void hgics_exit(void);
|
||||||
|
extern int wpas_init(void);
|
||||||
|
extern int wpas_start(char *ifname);
|
||||||
|
extern int wpas_stop(char *ifname);
|
||||||
|
extern int wpas_cli(char *ifname, char *cmd, char *reply_buff, int reply_len);
|
||||||
|
extern int wpas_passphrase(char *ssid, char *passphrase, char psk[32]);
|
||||||
|
extern int hapd_init(void);
|
||||||
|
extern int hapd_start(char *ifname);
|
||||||
|
extern int hapd_stop(char *ifname);
|
||||||
|
extern int hapd_cli(char *ifname, char *cmd, char *reply_buff, int reply_len);
|
||||||
|
extern void hgic_param_iftest(int iftest);
|
||||||
|
extern const char *hgic_param_ifname(const char *name);
|
||||||
|
extern char *hgic_param_fwfile(const char *fw);
|
||||||
|
extern int hgic_param_ifcount(int count);
|
||||||
|
extern void hgic_param_initcb(hgic_init_cb cb);
|
||||||
|
extern void hgic_param_eventcb(hgic_event_cb cb);
|
||||||
|
extern int hgic_ota_start(char *ifname, char *fw_name);
|
||||||
|
|
||||||
|
void hgic_raw_init(void);
|
||||||
|
int hgic_raw_send(char *dest, char *data, int len);
|
||||||
|
int hgic_raw_rcev(char *buf, int size, char *src);
|
||||||
|
|
||||||
|
#ifdef HGIC_SMAC
|
||||||
|
#include "umac_config.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
386
hgic_def.h
Normal file
386
hgic_def.h
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
#ifndef _HUGE_IC_DEF_H_
|
||||||
|
#define _HUGE_IC_DEF_H_
|
||||||
|
#include "hgic.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#define HGIC_VERSION "v1.3.0"
|
||||||
|
|
||||||
|
#ifndef SVN_VERSION
|
||||||
|
#error "SVN_VERSION undefined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VERSOIN_SHOW(name) do{\
|
||||||
|
printk("** HUGE-IC WLAN Card Driver("name") "HGIC_VERSION"-"SVN_VERSION"\r\n");\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define HGIC_WDEV_ID_AP 0
|
||||||
|
#define HGIC_WDEV_ID_STA 1
|
||||||
|
#define HGIC_SCAN_MAX_NUM 32
|
||||||
|
|
||||||
|
#define HGIC_HDR_TX_MAGIC 0x1A2B
|
||||||
|
#define HGIC_HDR_RX_MAGIC 0x2B1A
|
||||||
|
|
||||||
|
#define HGIC_VENDOR_ID (0xA012)
|
||||||
|
#define HGIC_WLAN_AH_4001 (0x4001)
|
||||||
|
#define HGIC_WLAN_AH_4002 (0x4002)
|
||||||
|
#define HGIC_WLAN_AH_4102 (0x4102)
|
||||||
|
|
||||||
|
#define HGIC_CTRL_TIMEOUT 100
|
||||||
|
#define HGIC_CMD_PRIORITY 0
|
||||||
|
#define HGIC_TX_WINDOW 20
|
||||||
|
#define HGIC_TX_COOKIE_MASK 0x7FFF
|
||||||
|
#define HGIC_BLOCK_ACK_CNT 256
|
||||||
|
|
||||||
|
#define hgic_dbg(fmt, ...) printk("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#define hgic_err(fmt, ...) printk("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define hgic_enter() printk("enter %s\r\n", __FUNCTION__)
|
||||||
|
#define hgic_leave() printk("leave %s\r\n", __FUNCTION__)
|
||||||
|
|
||||||
|
#define HGIC_CMD_TIMEOUT 500
|
||||||
|
#define HGIC_TX_TIMEOUT 10
|
||||||
|
#define HGIC_ALIVE_TIMER 5000
|
||||||
|
|
||||||
|
enum hgic_bus_type {
|
||||||
|
HGIC_BUS_SDIO = 0x1,
|
||||||
|
HGIC_BUS_USB,
|
||||||
|
HGIC_BUS_HWSIM,
|
||||||
|
HGIC_BUS_WLOE,
|
||||||
|
HGIC_BUS_SDSPI,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum hgic_hdr_type {
|
||||||
|
HGIC_HDR_TYPE_ACK = 0x1,
|
||||||
|
HGIC_HDR_TYPE_FRM,
|
||||||
|
HGIC_HDR_TYPE_CMD,
|
||||||
|
HGIC_HDR_TYPE_EVENT,
|
||||||
|
HGIC_HDR_TYPE_FIRMWARE,
|
||||||
|
HGIC_HDR_TYPE_NLMSG,
|
||||||
|
HGIC_HDR_TYPE_BOOTDL,
|
||||||
|
HGIC_HDR_TYPE_TEST,
|
||||||
|
HGIC_HDR_TYPE_FRM2,
|
||||||
|
HGIC_HDR_TYPE_TEST2,
|
||||||
|
HGIC_HDR_TYPE_SOFTFC,
|
||||||
|
HGIC_HDR_TYPE_OTA,
|
||||||
|
HGIC_HDR_TYPE_CMD2,
|
||||||
|
HGIC_HDR_TYPE_EVENT2,
|
||||||
|
HGIC_HDR_TYPE_BOOTDL_DATA,
|
||||||
|
|
||||||
|
HGIC_HDR_TYPE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum hgic_hdr_flags2 {
|
||||||
|
HGIC_HDR_FLAGS2_AFT_BEACON = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hgic_bus_flag {
|
||||||
|
HGIC_BUS_FLAGS_DISABLE_REINIT,
|
||||||
|
HGIC_BUS_FLAGS_SLEEP,
|
||||||
|
HGIC_BUS_FLAGS_INBOOT,
|
||||||
|
HGIC_BUS_FLAGS_NOPOLL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_txq_param {
|
||||||
|
unsigned short txop;
|
||||||
|
unsigned short cw_min;
|
||||||
|
unsigned short cw_max;
|
||||||
|
unsigned char aifs;
|
||||||
|
unsigned char acm;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_mcast_txparam {
|
||||||
|
unsigned char dupcnt;
|
||||||
|
unsigned char tx_bw;
|
||||||
|
unsigned char tx_mcs;
|
||||||
|
unsigned char clearch;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*data packet header*/
|
||||||
|
struct hgic_hdr {
|
||||||
|
unsigned short magic;
|
||||||
|
unsigned char type;
|
||||||
|
unsigned char ifidx: 4, flags: 4;
|
||||||
|
unsigned short length;
|
||||||
|
unsigned short cookie;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct hgic_rx_info {
|
||||||
|
unsigned char band;
|
||||||
|
unsigned char mcs: 4, bw: 4;
|
||||||
|
char evm;
|
||||||
|
char signal;
|
||||||
|
unsigned short freq;
|
||||||
|
s16 freq_off;
|
||||||
|
unsigned char rx_flags;
|
||||||
|
unsigned char antenna;
|
||||||
|
unsigned char nss : 4, s1g_nss : 4;
|
||||||
|
unsigned char vht_flag : 3, s1g_flag : 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_tx_info {
|
||||||
|
unsigned char band;
|
||||||
|
unsigned char tx_bw;
|
||||||
|
unsigned char tx_mcs;
|
||||||
|
unsigned char antenna;
|
||||||
|
unsigned int tx_flags;
|
||||||
|
unsigned int tx_flags2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_key_info {
|
||||||
|
unsigned int cipher;
|
||||||
|
unsigned char icv_len;
|
||||||
|
unsigned char iv_len;
|
||||||
|
unsigned char hw_key_idx;
|
||||||
|
unsigned char flags;
|
||||||
|
char keyidx;
|
||||||
|
unsigned char keylen;
|
||||||
|
unsigned char key[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_frm_hdr {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
union {
|
||||||
|
struct hgic_rx_info rx_info;
|
||||||
|
struct hgic_tx_info tx_info;
|
||||||
|
unsigned char rev[24];
|
||||||
|
};
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct hgic_frm_hdr2 {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HDR_CMDID(ctl) ((ctl)->hdr.type==HGIC_HDR_TYPE_CMD2?(ctl)->cmd2.cmd_id:(ctl)->cmd.cmd_id)
|
||||||
|
#define HDR_EVTID(ctl) ((ctl)->hdr.type==HGIC_HDR_TYPE_EVENT2?(ctl)->event2.event_id:(ctl)->event.event_id)
|
||||||
|
#define HDR_CMDID_SET(ctl, id) if(id>255){\
|
||||||
|
(ctl)->hdr.type =HGIC_HDR_TYPE_CMD2;\
|
||||||
|
(ctl)->cmd2.cmd_id = id;\
|
||||||
|
}else{\
|
||||||
|
(ctl)->hdr.type =HGIC_HDR_TYPE_CMD;\
|
||||||
|
(ctl)->cmd.cmd_id = id;\
|
||||||
|
}
|
||||||
|
#define HDR_EVTID_SET(ctl, id) if(id>255){\
|
||||||
|
(ctl)->hdr.type =HGIC_HDR_TYPE_EVENT2;\
|
||||||
|
(ctl)->event2.event_id = id;\
|
||||||
|
}else{\
|
||||||
|
(ctl)->hdr.type =HGIC_HDR_TYPE_EVENT;\
|
||||||
|
(ctl)->event.event_id = id;\
|
||||||
|
}
|
||||||
|
|
||||||
|
/*contro pakcet header*/
|
||||||
|
struct hgic_ctrl_hdr {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
unsigned char cmd_id;
|
||||||
|
short status;
|
||||||
|
} cmd;
|
||||||
|
struct {
|
||||||
|
unsigned short cmd_id;
|
||||||
|
short status;
|
||||||
|
} cmd2;
|
||||||
|
struct {
|
||||||
|
unsigned char event_id;
|
||||||
|
short value;
|
||||||
|
} event;
|
||||||
|
struct {
|
||||||
|
unsigned short event_id;
|
||||||
|
short value;
|
||||||
|
} event2;
|
||||||
|
unsigned char info[4];
|
||||||
|
};
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
//ack packet
|
||||||
|
struct hgic_dack_hdr {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
uint16_t cookies[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct hgic_nlmsg_hdr {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
uint32_t group;
|
||||||
|
uint32_t portid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_bootdl_resp_hdr {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned char rsp;
|
||||||
|
unsigned char rsp_data[4];
|
||||||
|
unsigned char reserved;
|
||||||
|
unsigned char check;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
|
struct hgic_bootdl_cmd_hdr {
|
||||||
|
struct hgic_hdr hdr;
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned char cmd_len;
|
||||||
|
unsigned char cmd_flag;
|
||||||
|
unsigned char addr[4];
|
||||||
|
unsigned char len[4];
|
||||||
|
unsigned char check;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hgic_ota_hdr {
|
||||||
|
unsigned int version;
|
||||||
|
unsigned int off;
|
||||||
|
unsigned int tot_len;
|
||||||
|
unsigned short len;
|
||||||
|
unsigned short checksum;
|
||||||
|
unsigned short chipid;
|
||||||
|
unsigned short err_code;
|
||||||
|
unsigned char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum hgic_rom_cmd {
|
||||||
|
HGIC_ROM_CMD_ENTER = 0,
|
||||||
|
HGIC_ROM_CMD_LDFW,
|
||||||
|
HGIC_ROM_CMD_RUN,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fw_ldinfo {
|
||||||
|
unsigned int run_addr;
|
||||||
|
unsigned int encrypt: 1,
|
||||||
|
resv: 31;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_rom_hdr {
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned char subcmd;
|
||||||
|
unsigned char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_sta_status {
|
||||||
|
unsigned short aid;
|
||||||
|
unsigned char addr[6];
|
||||||
|
char rssi;
|
||||||
|
char evm;
|
||||||
|
char evm_std;
|
||||||
|
unsigned char tx_mcs;
|
||||||
|
unsigned char tx_bw;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fw_status {
|
||||||
|
unsigned short rxq;
|
||||||
|
unsigned short txq;
|
||||||
|
unsigned short acq[4];
|
||||||
|
unsigned short sta_count;
|
||||||
|
struct hgic_sta_status sta[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HGIC_BUS_BOOTDL_CKSUM{
|
||||||
|
HGIC_BUS_BOOTDL_CHECK_SUM = 0,
|
||||||
|
HGIC_BUS_BOOTDL_CHECK_CRC8,
|
||||||
|
HGIC_BUS_BOOTDL_CHECK_0XFD,
|
||||||
|
HGIC_BUS_BOOTDL_CHECK_OFF = 0xFF
|
||||||
|
} ;
|
||||||
|
|
||||||
|
struct hgic_bus {
|
||||||
|
int type;
|
||||||
|
int dev_id;
|
||||||
|
int drv_tx_headroom;
|
||||||
|
void *bus_priv;
|
||||||
|
unsigned long flags;
|
||||||
|
int bootdl_pktlen;
|
||||||
|
int bootdl_cksum;
|
||||||
|
int blk_size;
|
||||||
|
int (*tx_packet)(void *bus, struct sk_buff *skb);
|
||||||
|
void (*tx_complete)(void *hg, struct sk_buff *skb, int success);
|
||||||
|
int (*rx_packet)(void *hg, struct sk_buff *skb, int len);
|
||||||
|
int (*reinit)(void *bus);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int hgic_core_probe(void *dev, struct hgic_bus *bus);
|
||||||
|
extern void hgic_core_probe_post(void *priv);
|
||||||
|
extern int hgic_core_remove(void *arg);
|
||||||
|
extern int hgic_core_suspend(void *hgobj);
|
||||||
|
extern int hgic_core_resume(void *hgobj);
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#define ALLOC_ORDERED_WORKQUEUE alloc_ordered_workqueue
|
||||||
|
#define ALLOC_NETDEV_MQS alloc_netdev_mqs
|
||||||
|
#define netif_queue_stopped(n) (0)
|
||||||
|
#define netif_start_queue(n)
|
||||||
|
#define netif_stop_queue(n)
|
||||||
|
#else
|
||||||
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)
|
||||||
|
#define ALLOC_ORDERED_WORKQUEUE alloc_ordered_workqueue
|
||||||
|
#else
|
||||||
|
#define ALLOC_ORDERED_WORKQUEUE(n,f) create_singlethread_workqueue(n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
|
||||||
|
#define ALLOC_NETDEV_MQS(size,name,setup,txqs,rxqs) alloc_netdev_mqs(size,name,0,setup,txqs,rxqs)
|
||||||
|
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
|
||||||
|
#define ALLOC_NETDEV_MQS(size,name,setup,txqs,rxqs) alloc_netdev_mq(size,name,setup,txqs)
|
||||||
|
#else
|
||||||
|
#define ALLOC_NETDEV_MQS(size,name,setup,txqs,rxqs) alloc_netdev_mqs(size,name,setup,txqs,rxqs)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,1)
|
||||||
|
#define _KERNEL_READ(fp, buff, size, off) kernel_read(fp, buff, size, off)
|
||||||
|
#define _KERNEL_WRITE(fp, buff, size, off) kernel_write(fp, buff, size, off)
|
||||||
|
#else
|
||||||
|
#define _KERNEL_READ(fp, buff, size, off) kernel_read(fp, 0, buff, size)
|
||||||
|
#define _KERNEL_WRITE(fp, buff, size, off) kernel_write(fp, buff, size, off)
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
|
||||||
|
#define setup_timer(a, b, c) timer_setup(a, b, 0)
|
||||||
|
#define init_timer(...)
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
|
||||||
|
#define ACCESS_OK(type, addr, size) access_ok(addr, size)
|
||||||
|
#define DEV_OPEN(x) dev_open(x, NULL)
|
||||||
|
#else
|
||||||
|
#define ACCESS_OK(type, addr, size) access_ok(type, addr, size)
|
||||||
|
#define DEV_OPEN(x) dev_open(x)
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) && defined CONFIG_HGIC_2G
|
||||||
|
#define IEEE80211_NUM_BANDS NUM_NL80211_BANDS
|
||||||
|
#define IEEE80211_BAND_2GHZ NL80211_BAND_2GHZ
|
||||||
|
#define IEEE80211_BAND_5GHZ NL80211_BAND_5GHZ
|
||||||
|
#endif
|
||||||
|
#ifndef IEEE80211_NUM_ACS
|
||||||
|
#define IEEE80211_NUM_ACS 4
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) && defined CONFIG_HGIC_2G
|
||||||
|
#define vht_nss nss
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) && defined CONFIG_HGIC_2G
|
||||||
|
#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
|
||||||
|
#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,5,0)
|
||||||
|
#define proc_ops file_operations
|
||||||
|
#define proc_open open
|
||||||
|
#define proc_read read
|
||||||
|
#define proc_lseek llseek
|
||||||
|
#define proc_write write
|
||||||
|
#define proc_release release
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
|
||||||
|
#define ieee80211_free_txskb(hw, skb) dev_kfree_skb_any(skb)
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
|
||||||
|
#define RX_FLAG_MACTIME_START RX_FLAG_MACTIME_MPDU
|
||||||
|
#define IEEE80211_ITERATE_ACTIVE_INTERFACES_ATOMIC(hw, flags, iterator, vif) ieee80211_iterate_active_interfaces_atomic(hw, iterator, vif)
|
||||||
|
#else
|
||||||
|
#define IEEE80211_ITERATE_ACTIVE_INTERFACES_ATOMIC(hw, flags, iterator, vif) ieee80211_iterate_active_interfaces_atomic(hw, flags, iterator, vif)
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
|
||||||
|
static inline void *__PDE_DATA(const struct inode *inode)
|
||||||
|
{
|
||||||
|
return PDE(inode)->data;
|
||||||
|
}
|
||||||
|
static inline void *PDE_DATA(const struct inode *inode)
|
||||||
|
{
|
||||||
|
return __PDE_DATA(inode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
23
hgic_fmac/Makefile
Normal file
23
hgic_fmac/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
$(CONFIG_HGICF)-objs += cfg.o
|
||||||
|
$(CONFIG_HGICF)-objs += ctrl.o
|
||||||
|
$(CONFIG_HGICF)-objs += core.o
|
||||||
|
$(CONFIG_HGICF)-objs += event.o
|
||||||
|
$(CONFIG_HGICF)-objs += procfs.o
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/fwdl.o
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/utils.o
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/fwctrl.o
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/ota.o
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/fwinfo.o
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_HGICF), hgicf_sdio)
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/if_sdio.o
|
||||||
|
obj-m += hgicf_sdio.o
|
||||||
|
else ifeq ($(CONFIG_HGICF), hgicf_usb)
|
||||||
|
$(CONFIG_HGICF)-objs += ../utils/if_usb.o
|
||||||
|
obj-m += hgicf_usb.o
|
||||||
|
else
|
||||||
|
obj-m += hgicf.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
1178
hgic_fmac/cfg.c
Normal file
1178
hgic_fmac/cfg.c
Normal file
File diff suppressed because it is too large
Load diff
13
hgic_fmac/cfg.h
Normal file
13
hgic_fmac/cfg.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#ifndef _HGICF_CFG_H_
|
||||||
|
#define _HGICF_CFG_H_
|
||||||
|
#ifndef __RTOS__
|
||||||
|
int hgicf_ioctl_set_proc(struct net_device *dev, struct iwreq *wrqin);
|
||||||
|
int hgicf_ioctl_get_proc(struct net_device *dev, struct iwreq *wrqin);
|
||||||
|
int hgicf_ioctl_stat(struct net_device *dev, struct iwreq *wrqin);
|
||||||
|
int hgicf_ioctl_e2p(struct net_device *dev, struct iwreq *wrqin);
|
||||||
|
int hgicf_ioctl_scan(struct net_device *dev, struct iwreq *wrqin);
|
||||||
|
int hgicf_ioctl_savecfg(struct net_device *dev, struct iwreq *wrqin);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
993
hgic_fmac/core.c
Normal file
993
hgic_fmac/core.c
Normal file
|
@ -0,0 +1,993 @@
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/unaligned.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/rcu.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hgicf.h"
|
||||||
|
#include "ctrl.h"
|
||||||
|
#include "cfg.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
static int txq_size = 1024;
|
||||||
|
static char *conf_file = "/etc/hgicf.conf";
|
||||||
|
static char *fw_file = "hgicf.bin";
|
||||||
|
static int if_test = 0;
|
||||||
|
static int soft_fc = 1;
|
||||||
|
static int no_bootdl = 0;
|
||||||
|
static int qc_mode = 0;
|
||||||
|
static char *ifname = "hg%d";
|
||||||
|
static hgic_init_cb init_cb = NULL;
|
||||||
|
#ifdef __RTOS__
|
||||||
|
static hgic_event_cb event_cb = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TXWND_INIT_VAL (2)
|
||||||
|
#define MATCH_NDEV(fwidx,hg) ((fwidx) == HGIC_WDEV_ID_STA ? (hg->sta ? hg->sta->ndev : NULL) : \
|
||||||
|
(hg->ap ? hg->ap->ndev : NULL))
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
static int iface_cnt = 1;
|
||||||
|
void dev_queue_xmit(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = skb->dev;
|
||||||
|
if (ndev) {
|
||||||
|
ndev->netdev_ops->ndo_start_xmit(skb, ndev);
|
||||||
|
} else {
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
u16 hgicf_data_cookie(struct hgicf_wdev *hg)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
uint16_t cookie = 0;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hg->lock, flags);
|
||||||
|
cookie = hg->data_cookie++;
|
||||||
|
spin_unlock_irqrestore(&hg->lock, flags);
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgicf_load_config(struct hgicf_wdev *hg)
|
||||||
|
{
|
||||||
|
#ifndef __RTOS__
|
||||||
|
struct file *fp = NULL;
|
||||||
|
struct iwreq wrqin;
|
||||||
|
struct net_device *ndev = NULL;
|
||||||
|
ssize_t ret = 0;
|
||||||
|
unsigned long long __maybe_unused offset = 0 ;
|
||||||
|
char *conf = kzalloc(2048, GFP_KERNEL);
|
||||||
|
char *ptr, *str;
|
||||||
|
|
||||||
|
if (hg->sta) {ndev = hg->sta->ndev; }
|
||||||
|
else if (hg->ap) {ndev = hg->ap->ndev; }
|
||||||
|
else {
|
||||||
|
hgic_err("No netdev!! \r\n");
|
||||||
|
goto __out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = filp_open(conf_file, O_RDONLY, 0);
|
||||||
|
if (!IS_ERR(fp) && conf) {
|
||||||
|
ret = _KERNEL_READ(fp, conf, 2048, &offset);
|
||||||
|
str = conf;
|
||||||
|
|
||||||
|
hgic_fwctrl_close_dev(&(hg->ctrl));
|
||||||
|
while (str) {
|
||||||
|
ptr = strstr(str, "\r\n");
|
||||||
|
if (ptr) {
|
||||||
|
*ptr = 0;
|
||||||
|
ptr += 2;
|
||||||
|
} else {
|
||||||
|
ptr = strstr(str, "\n");
|
||||||
|
if (ptr) { *ptr++ = 0;}
|
||||||
|
}
|
||||||
|
wrqin.u.data.length = strlen(str);
|
||||||
|
if (wrqin.u.data.length > 0) {
|
||||||
|
hgic_dbg("param: [%s]\r\n", str);
|
||||||
|
wrqin.u.data.pointer = str;
|
||||||
|
ret = hgicf_ioctl_set_proc(ndev, &wrqin);
|
||||||
|
if (ret < 0) {
|
||||||
|
hgic_err("invalid param:[%s]\r\n", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str = ptr;
|
||||||
|
}
|
||||||
|
hgic_fwctrl_open_dev(&(hg->ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
__out:
|
||||||
|
if (!IS_ERR(fp)) { filp_close(fp, NULL); }
|
||||||
|
if (conf) { kfree(conf); }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_netif_open(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
vif->hg->radio_off = 0;
|
||||||
|
return hgic_fwctrl_open_dev(&(vif->hg->ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_netif_stop(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
vif->hg->radio_off = 1;
|
||||||
|
return hgic_fwctrl_close_dev(&(vif->hg->ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_netif_uninit(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static netdev_tx_t hgicf_netif_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
struct hgic_frm_hdr2 *hdr = NULL;
|
||||||
|
u8 pad = ((ulong)skb->data & 0x3) ? (4 - ((ulong)skb->data & 0x3)) : 0;
|
||||||
|
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags) ||
|
||||||
|
(vif->hg->tx_dataq.qlen > txq_size) ||
|
||||||
|
test_bit(HGIC_BUS_FLAGS_SLEEP, &vif->hg->bus->flags)) {
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
return NETDEV_TX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __RTOS__
|
||||||
|
if (skb_headroom(skb) < sizeof(struct hgic_frm_hdr2)) {
|
||||||
|
struct sk_buff *nskb = skb_copy_expand(skb, skb->dev->needed_headroom,
|
||||||
|
skb->dev->needed_tailroom, GFP_KERNEL);
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
if (nskb == NULL) {
|
||||||
|
return NETDEV_TX_OK;
|
||||||
|
}
|
||||||
|
skb = nskb;
|
||||||
|
pad = ((ulong)skb->data & 0x3) ? (4 - ((ulong)skb->data & 0x3)) : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hdr = (struct hgic_frm_hdr2 *)skb_push(skb, sizeof(struct hgic_frm_hdr2) + pad);
|
||||||
|
hdr->hdr.ifidx = vif->fwifidx;
|
||||||
|
hdr->hdr.length = skb->len;
|
||||||
|
hdr->hdr.magic = HGIC_HDR_TX_MAGIC;
|
||||||
|
hdr->hdr.type = HGIC_HDR_TYPE_FRM2;
|
||||||
|
hdr->hdr.flags = pad;
|
||||||
|
hdr->hdr.cookie = hgicf_data_cookie(vif->hg);
|
||||||
|
skb_queue_tail(&vif->hg->tx_dataq, skb);
|
||||||
|
queue_work(vif->hg->tx_wq, &vif->hg->tx_work);
|
||||||
|
return NETDEV_TX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_netif_change_mac(struct net_device *dev, void *addr)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
#ifdef __RTOS__
|
||||||
|
ret = hgicf_ioctl(dev, HGIC_CMD_SET_MAC, addr, 0);
|
||||||
|
#else
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
struct sockaddr *sa = (struct sockaddr *)addr;
|
||||||
|
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret = hgic_fwctrl_set_mac(&(vif->hg->ctrl), sa->sa_data);
|
||||||
|
if (!ret) {
|
||||||
|
ret = eth_mac_addr(dev, addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_netif_set_multicast_list(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
static int hgicf_netif_ioctl(struct net_device *dev, u32 cmd, u32 param1, u32 param2)
|
||||||
|
{
|
||||||
|
return hgicf_ioctl(dev, cmd, param1, param2);
|
||||||
|
}
|
||||||
|
int hgicf_cmd(char *ifname, unsigned int cmd, unsigned int param1, unsigned int param2)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = net_device_get_by_name(ifname);
|
||||||
|
if (ndev == NULL) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
return hgicf_netif_ioctl(ndev, cmd, param1, param2);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int hgicf_netif_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return hgicf_ioctl(dev, ifr, cmd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct net_device_ops hgicf_netif_ops = {
|
||||||
|
.ndo_open = hgicf_netif_open,
|
||||||
|
.ndo_stop = hgicf_netif_stop,
|
||||||
|
.ndo_uninit = hgicf_netif_uninit,
|
||||||
|
.ndo_start_xmit = hgicf_netif_xmit,
|
||||||
|
.ndo_set_rx_mode = hgicf_netif_set_multicast_list,
|
||||||
|
.ndo_set_mac_address = hgicf_netif_change_mac,
|
||||||
|
.ndo_do_ioctl = hgicf_netif_ioctl,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void hgicf_netif_setup(struct net_device *dev)
|
||||||
|
{
|
||||||
|
#ifdef __RTOS__
|
||||||
|
dev->netdev_ops = &hgicf_netif_ops;
|
||||||
|
#else
|
||||||
|
ether_setup(dev);
|
||||||
|
dev->netdev_ops = &hgicf_netif_ops;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
|
||||||
|
dev->priv_destructor = free_netdev;
|
||||||
|
#else
|
||||||
|
dev->destructor = free_netdev;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_request_txwnd(struct hgic_bus *bus)
|
||||||
|
{
|
||||||
|
struct hgic_hdr *hdr = NULL;
|
||||||
|
struct sk_buff *skb = dev_alloc_skb(sizeof(struct hgic_hdr) + 2);
|
||||||
|
|
||||||
|
if (skb == NULL) { return -ENOMEM; }
|
||||||
|
hdr = (struct hgic_hdr *)skb->data;
|
||||||
|
hdr->magic = HGIC_HDR_TX_MAGIC;
|
||||||
|
hdr->type = HGIC_HDR_TYPE_SOFTFC;
|
||||||
|
hdr->length = sizeof(struct hgic_hdr) + 2;
|
||||||
|
hdr->ifidx = 0;
|
||||||
|
hdr->flags = 0;
|
||||||
|
hdr->cookie = 0;
|
||||||
|
skb_put(skb, sizeof(struct hgic_hdr) + 2);
|
||||||
|
return bus->tx_packet(bus, skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_check_txwnd(struct hgicf_wdev *hg)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!hg->soft_fc || test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (hg->soft_fc && atomic_read(&hg->txwnd) < TXWND_INIT_VAL &&
|
||||||
|
test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) &&
|
||||||
|
!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) &&
|
||||||
|
!test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags) &&
|
||||||
|
!test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) {
|
||||||
|
|
||||||
|
err = hgicf_request_txwnd(hg->bus);
|
||||||
|
if (!err) {
|
||||||
|
wait_for_completion_timeout(&hg->txwnd_cp, msecs_to_jiffies(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(atomic_read(&hg->txwnd) < TXWND_INIT_VAL)
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hg->soft_fc || test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atomic_read(&hg->txwnd) < TXWND_INIT_VAL) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
atomic_dec(&hg->txwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_test_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u32 diff_jiff = 0;
|
||||||
|
struct hgicf_wdev *hg = NULL;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgic_frm_hdr *frmhdr = NULL;
|
||||||
|
|
||||||
|
printk("start if test ...\r\n");
|
||||||
|
hg = container_of(work, struct hgicf_wdev, test_work);
|
||||||
|
hg->test_jiff = jiffies;
|
||||||
|
|
||||||
|
//set_bit(HGIC_BUS_FLAGS_DISABLE_REINIT, &hg->bus->flags);
|
||||||
|
while (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
|
||||||
|
if (time_after(jiffies, hg->test_jiff + msecs_to_jiffies(5000))) {
|
||||||
|
diff_jiff = jiffies_to_msecs(jiffies - hg->test_jiff);
|
||||||
|
diff_jiff /= 1000;
|
||||||
|
if (diff_jiff == 0) { diff_jiff = 0xffff; }
|
||||||
|
printk("HGIC IF TEST: tx:%d KB/s, rx:%d KB/s (%d %d %d)\r\n",
|
||||||
|
(hg->test_tx_len / 1024) / diff_jiff,
|
||||||
|
(hg->test_rx_len / 1024) / diff_jiff,
|
||||||
|
hg->test_tx_len, hg->test_rx_len, diff_jiff);
|
||||||
|
hg->test_rx_len = 0;
|
||||||
|
hg->test_tx_len = 0;
|
||||||
|
hg->test_jiff = jiffies;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = dev_alloc_skb(1500 + hg->bus->drv_tx_headroom);
|
||||||
|
if (skb) {
|
||||||
|
skb_reserve(skb, hg->bus->drv_tx_headroom);
|
||||||
|
frmhdr = (struct hgic_frm_hdr *)skb->data;
|
||||||
|
frmhdr->hdr.magic = HGIC_HDR_TX_MAGIC;
|
||||||
|
frmhdr->hdr.type = (hg->if_test == 1 ? HGIC_HDR_TYPE_TEST : HGIC_HDR_TYPE_TEST2);
|
||||||
|
frmhdr->hdr.length = 1500;
|
||||||
|
frmhdr->hdr.ifidx = 0;
|
||||||
|
frmhdr->hdr.cookie = hgicf_data_cookie(hg);
|
||||||
|
if(hg->if_test == 3) memset(skb->data+8, 0xAA, 1500-8);
|
||||||
|
skb_put(skb, 1500);
|
||||||
|
while (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && hgicf_check_txwnd(hg)) {
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
ret = hg->bus->tx_packet(hg->bus, skb);
|
||||||
|
if (ret) {
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk("if test stop!\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_tx_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, tx_work);
|
||||||
|
struct hgic_hdr *hdr = NULL;
|
||||||
|
|
||||||
|
//hgic_dbg("Enter\n");
|
||||||
|
_CTRLQ_TX:
|
||||||
|
while (!skb_queue_empty(&hg->ctrl.txq)) {
|
||||||
|
if (test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) ||
|
||||||
|
!test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
|
||||||
|
hgic_clear_queue(&hg->ctrl.txq);
|
||||||
|
goto _CTRLQ_TX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgicf_check_txwnd(hg)) {
|
||||||
|
msleep(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = skb_dequeue(&hg->ctrl.txq);
|
||||||
|
if(skb){
|
||||||
|
hdr = (struct hgic_hdr *)skb->data;
|
||||||
|
switch(hdr->type){
|
||||||
|
case HGIC_HDR_TYPE_BOOTDL:
|
||||||
|
break;
|
||||||
|
case HGIC_HDR_TYPE_BOOTDL_DATA:
|
||||||
|
skb_pull(skb, sizeof(struct hgic_bootdl_cmd_hdr));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)){
|
||||||
|
kfree_skb(skb);
|
||||||
|
skb = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(skb){
|
||||||
|
hg->bus->tx_packet(hg->bus, skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!skb_queue_empty(&hg->tx_dataq) &&
|
||||||
|
test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) &&
|
||||||
|
!test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags)) {
|
||||||
|
|
||||||
|
if (test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) ||
|
||||||
|
test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) {
|
||||||
|
hgic_clear_queue(&hg->tx_dataq);
|
||||||
|
goto _CTRLQ_TX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgicf_check_txwnd(hg)) {
|
||||||
|
msleep(10);
|
||||||
|
goto _CTRLQ_TX;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = skb_dequeue(&hg->tx_dataq);
|
||||||
|
hg->bus->tx_packet(hg->bus, skb);
|
||||||
|
if (!skb_queue_empty(&hg->ctrl.txq)) {
|
||||||
|
goto _CTRLQ_TX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//hgic_dbg("Leave\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hgicf_vif *hgicf_create_iface(struct hgicf_wdev *hg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct net_device *ndev = NULL;
|
||||||
|
struct hgicf_vif *vif = NULL;
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
ndev = ALLOC_NETDEV_MQS(sizeof(struct hgicf_vif), ifname, hgicf_netif_setup, 1, 1);
|
||||||
|
if (!ndev) {
|
||||||
|
hgic_err("%s: alloc_netdev_mqs failed\n", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
vif = (struct hgicf_vif *)netdev_priv(ndev);
|
||||||
|
vif->ndev = ndev;
|
||||||
|
vif->hg = hg;
|
||||||
|
vif->state = 0;
|
||||||
|
ndev->needed_headroom += (hg->bus->drv_tx_headroom + sizeof(struct hgic_frm_hdr2));
|
||||||
|
memcpy(ndev->dev_addr, hg->fwinfo.mac, ETH_ALEN);
|
||||||
|
ret = register_netdev(ndev);
|
||||||
|
if (ret) {
|
||||||
|
free_netdev(ndev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#ifndef __RTOS__
|
||||||
|
rtnl_lock();
|
||||||
|
DEV_OPEN(ndev);
|
||||||
|
rtnl_unlock();
|
||||||
|
#endif
|
||||||
|
return vif;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_rx_data(void *hgobj, struct sk_buff *skb, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
struct hgic_frm_hdr2 *hdr = NULL;
|
||||||
|
struct hgicf_wdev *hg = hgobj;
|
||||||
|
|
||||||
|
hgic_skip_padding(skb);
|
||||||
|
hdr = (struct hgic_frm_hdr2 *) skb->data;
|
||||||
|
skb->dev = MATCH_NDEV(hdr->hdr.ifidx, hg);
|
||||||
|
if (hdr->hdr.magic != HGIC_HDR_RX_MAGIC) {
|
||||||
|
hgic_err("invalid magic unmber:%x\r\n", hdr->hdr.magic);
|
||||||
|
hgic_print_hex(skb->data, 16);
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->hdr.type != HGIC_HDR_TYPE_BOOTDL) {
|
||||||
|
if (len < hdr->hdr.length) {
|
||||||
|
hgic_err("invalid data length: %x/%x,cookie:%d\r\n", len, hdr->hdr.length, hdr->hdr.cookie);
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skb_put(skb, len > hdr->hdr.length ? hdr->hdr.length : len);
|
||||||
|
switch (hdr->hdr.type) {
|
||||||
|
case HGIC_HDR_TYPE_FRM2:
|
||||||
|
hg->last_rx = jiffies;
|
||||||
|
if (skb->dev == NULL || hg->if_test) {
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
skb_pull(skb, sizeof(struct hgic_frm_hdr2));
|
||||||
|
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||||
|
if (in_interrupt()) {
|
||||||
|
netif_rx(skb);
|
||||||
|
} else {
|
||||||
|
netif_rx_ni(skb);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HGIC_HDR_TYPE_CMD:
|
||||||
|
case HGIC_HDR_TYPE_CMD2:
|
||||||
|
case HGIC_HDR_TYPE_EVENT:
|
||||||
|
case HGIC_HDR_TYPE_EVENT2:
|
||||||
|
case HGIC_HDR_TYPE_OTA:
|
||||||
|
case HGIC_HDR_TYPE_BOOTDL:
|
||||||
|
if (hg->if_test) {
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hgic_fwctrl_rx(&hg->ctrl, skb);
|
||||||
|
break;
|
||||||
|
case HGIC_HDR_TYPE_TEST2:
|
||||||
|
hg->last_rx = jiffies;
|
||||||
|
hg->test_rx_len += len;
|
||||||
|
if (hg->if_test == 3) {
|
||||||
|
for (i = 8; i < 1500; i++) {
|
||||||
|
if (skb->data[i] != 0xAA) {
|
||||||
|
printk("data verify fail\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
break;
|
||||||
|
case HGIC_HDR_TYPE_SOFTFC:
|
||||||
|
hg->last_rx = jiffies;
|
||||||
|
atomic_set(&hg->txwnd, hdr->hdr.cookie);
|
||||||
|
complete(&hg->txwnd_cp);
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hgic_err("invalid data:%d\r\n", hdr->hdr.type);
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_tx_complete(void *hgobj, struct sk_buff *skb, int success)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = hgobj;
|
||||||
|
|
||||||
|
if (hg->if_test) {
|
||||||
|
hg->test_tx_len += skb->len;
|
||||||
|
}
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
if (!success) {
|
||||||
|
hgic_err("tx failed\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgicf_download_fw(struct hgicf_wdev *hg)
|
||||||
|
{
|
||||||
|
int err = -1;
|
||||||
|
int retry = 10;
|
||||||
|
int status = -1;
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
if (no_bootdl || qc_mode) { status = STATE_FW; }
|
||||||
|
|
||||||
|
set_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags);
|
||||||
|
while (status != STATE_FW && retry-- > 0 && err) {
|
||||||
|
status = hgic_bootdl_cmd_enter(&hg->bootdl);
|
||||||
|
if (status == STATE_BOOT) {
|
||||||
|
err = hgic_bootdl_download(&hg->bootdl, fw_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clear_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags);
|
||||||
|
|
||||||
|
if (status == STATE_BOOT && !err) {
|
||||||
|
set_bit(HGICF_DEV_FLAGS_BOOTDL, &hg->flags);
|
||||||
|
if (hg->bus->reinit && test_bit(HGIC_BUS_FLAGS_NOPOLL, &hg->bus->flags)) {
|
||||||
|
msleep(100);
|
||||||
|
retry = 4;
|
||||||
|
if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && !hg->bus->reinit(hg->bus)) {
|
||||||
|
while (retry-- > 0 && (STATE_FW != status)) {
|
||||||
|
status = hgic_bootdl_cmd_enter(&hg->bootdl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!no_bootdl && hg->bus->reinit){
|
||||||
|
mod_timer(&hg->alive_tmr, jiffies + msecs_to_jiffies(HGIC_ALIVE_TIMER*4));
|
||||||
|
}
|
||||||
|
return (status == STATE_FW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_delay_init(struct work_struct *work)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u8 retry = 0;
|
||||||
|
int conn_stat = 0;
|
||||||
|
struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, delay_init);
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
while(!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) && test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)){
|
||||||
|
if((retry & 0xf) == 0){
|
||||||
|
ret = hgicf_download_fw(hg);
|
||||||
|
if(ret) break;
|
||||||
|
}
|
||||||
|
msleep(10);
|
||||||
|
retry++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
clear_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags);
|
||||||
|
hg->last_rx = jiffies;
|
||||||
|
hg->soft_fc = soft_fc;
|
||||||
|
conn_stat = hgic_fwctrl_get_conn_state(&hg->ctrl);
|
||||||
|
#ifndef __RTOS__
|
||||||
|
hgic_fwctrl_get_dhcpc_result(&hg->ctrl, (u8 *)&hg->dhcpc, sizeof(hg->dhcpc));
|
||||||
|
#endif
|
||||||
|
hgic_fwctrl_get_fwinfo(&hg->ctrl, &hg->fwinfo);
|
||||||
|
printk("hgic fw info:%d.%d.%d.%d, svn version:%d, %pM, conn_state:%d\r\n",
|
||||||
|
(hg->fwinfo.version >> 24) & 0xff, (hg->fwinfo.version >> 16) & 0xff,
|
||||||
|
(hg->fwinfo.version >> 8) & 0xff, (hg->fwinfo.version & 0xff),
|
||||||
|
hg->fwinfo.svn_version, hg->fwinfo.mac, conn_stat);
|
||||||
|
if (!test_bit(HGICF_DEV_FLAGS_INITED, &hg->flags)) {
|
||||||
|
hg->sta = hgicf_create_iface(hg);
|
||||||
|
if (!hg->sta) {
|
||||||
|
hgic_err("create iface fail, ret:%d\r\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hg->sta->fwifidx = HGIC_WDEV_ID_STA;
|
||||||
|
hg->sta->hw_state = conn_stat;
|
||||||
|
hgicf_create_procfs(hg);
|
||||||
|
if (init_cb) { init_cb(0); }
|
||||||
|
if (if_test) {
|
||||||
|
hg->if_test = if_test;
|
||||||
|
queue_work(hg->tx_wq, &hg->test_work);
|
||||||
|
}
|
||||||
|
set_bit(HGICF_DEV_FLAGS_INITED, &hg->flags);
|
||||||
|
}
|
||||||
|
if ((test_bit(HGICF_DEV_FLAGS_BOOTDL, &hg->flags) || conn_stat != HGICF_HW_CONNECTED) && !qc_mode) {
|
||||||
|
hgicf_load_config(hg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hgic_dbg("Leave, ret=%d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgicf_alive_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
int retry = 4;
|
||||||
|
int status = -1;
|
||||||
|
struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, alive_work);
|
||||||
|
|
||||||
|
//hgic_dbg("SLEEP:%d\r\n", test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags));
|
||||||
|
if(!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags)){
|
||||||
|
if(time_after(jiffies, hg->last_rx + msecs_to_jiffies(HGIC_ALIVE_TIMER))){
|
||||||
|
//hgic_dbg("detect device status ...\r\n");
|
||||||
|
while(retry-- > 0 && status != STATE_FW){
|
||||||
|
status = hgic_bootdl_cmd_enter(&hg->bootdl);
|
||||||
|
}
|
||||||
|
if (status != STATE_FW) {
|
||||||
|
hgic_dbg("need reload firmware ...\r\n");
|
||||||
|
hg->soft_fc = 0;
|
||||||
|
set_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags);
|
||||||
|
hgic_clear_queue(&hg->ctrl.txq);
|
||||||
|
hgic_clear_queue(&hg->tx_dataq);
|
||||||
|
hg->bus->reinit(hg->bus);
|
||||||
|
schedule_work(&hg->delay_init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//hgic_dbg("next detect after %d sec.\r\n", HGIC_ALIVE_TIMER);
|
||||||
|
mod_timer(&hg->alive_tmr, jiffies + msecs_to_jiffies(HGIC_ALIVE_TIMER));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
static void hgicf_alive_timer(unsigned long arg)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = (struct hgicf_wdev *) arg;
|
||||||
|
schedule_work(&hg->alive_work);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
|
||||||
|
static void hgicf_alive_timer(struct timer_list *t)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = from_timer(hg, t, alive_tmr);
|
||||||
|
schedule_work(&hg->alive_work);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void hgicf_alive_timer(unsigned long arg)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = (struct hgicf_wdev *) arg;
|
||||||
|
schedule_work(&hg->alive_work);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void hgic_schedule(struct hgic_fwctrl *ctrl)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = container_of(ctrl, struct hgicf_wdev, ctrl);
|
||||||
|
queue_work(hg->tx_wq, &hg->tx_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_rx_fw_event(struct hgic_fwctrl *ctrl, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = container_of(ctrl, struct hgicf_wdev, ctrl);
|
||||||
|
hgicf_rx_fw_event(hg, skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgic_core_remove(void *hgobj)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = hgobj;
|
||||||
|
|
||||||
|
if (hg) {
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
clear_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags);
|
||||||
|
|
||||||
|
del_timer_sync(&hg->alive_tmr);
|
||||||
|
cancel_work_sync(&hg->alive_work);
|
||||||
|
cancel_work_sync(&hg->delay_init);
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
if (hg->ap) {
|
||||||
|
netif_stop_queue(hg->ap->ndev);
|
||||||
|
}
|
||||||
|
if (hg->sta) {
|
||||||
|
netif_stop_queue(hg->sta->ndev);
|
||||||
|
}
|
||||||
|
hgicf_delete_procfs(hg);
|
||||||
|
hgic_fwctrl_release(&hg->ctrl);
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
hgic_ota_release(&hg->ota);
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
hgic_bootdl_release(&hg->bootdl, 0);
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
//while (!test_bit(HGICF_DEV_FLAGS_STOP, &hg->flags));
|
||||||
|
cancel_work_sync(&hg->tx_work);
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
cancel_work_sync(&hg->test_work);
|
||||||
|
hgic_dbg(" trace ... %p\r\n", hg->ap);
|
||||||
|
if (hg->ap) {
|
||||||
|
unregister_netdev(hg->ap->ndev);
|
||||||
|
}
|
||||||
|
hgic_dbg(" trace ... %p\r\n", hg->sta);
|
||||||
|
if (hg->sta) {
|
||||||
|
unregister_netdev(hg->sta->ndev);
|
||||||
|
}
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
hgic_clear_queue(&hg->tx_dataq);
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
#ifdef __RTOS__
|
||||||
|
skb_queue_head_deinit(&hg->tx_dataq);
|
||||||
|
#else
|
||||||
|
hgic_clear_queue(&hg->custmgmt_q);
|
||||||
|
hgic_clear_queue(&hg->dbginfo_q);
|
||||||
|
hgic_clear_queue(&hg->cust_driverdata_q);
|
||||||
|
#endif
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
if (hg->tx_wq) {
|
||||||
|
flush_workqueue(hg->tx_wq);
|
||||||
|
destroy_workqueue(hg->tx_wq);
|
||||||
|
}
|
||||||
|
hgic_dbg(" trace ...\r\n");
|
||||||
|
#ifdef __RTOS__
|
||||||
|
deinit_completion(&hg->txwnd_cp);
|
||||||
|
spin_lock_deinit(&hg->lock);
|
||||||
|
#endif
|
||||||
|
if(hg->paired_stas)
|
||||||
|
kfree(hg->paired_stas);
|
||||||
|
kfree(hg);
|
||||||
|
hgic_dbg("Leave\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_core_remove);
|
||||||
|
|
||||||
|
int hgic_core_probe(void *dev, struct hgic_bus *bus)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = NULL;
|
||||||
|
|
||||||
|
hgic_dbg("Enter,qc_mode=%d, no_bootdl=%d\n", qc_mode, no_bootdl);
|
||||||
|
hg = kzalloc(sizeof(struct hgicf_wdev), GFP_KERNEL);
|
||||||
|
if (hg) {
|
||||||
|
memset(hg, 0, sizeof(struct hgicf_wdev));
|
||||||
|
hg->ctrl.qc_mode = qc_mode;
|
||||||
|
hg->bus = bus;
|
||||||
|
hg->dev = dev;
|
||||||
|
hg->dev_id = bus->dev_id;
|
||||||
|
hgic_fwctrl_init(&hg->ctrl, dev);
|
||||||
|
hgic_ota_init(&hg->ota, &hg->ctrl, &hg->fwinfo);
|
||||||
|
spin_lock_init(&hg->lock);
|
||||||
|
INIT_WORK(&hg->tx_work, hgicf_tx_work);
|
||||||
|
INIT_WORK(&hg->delay_init, hgicf_delay_init);
|
||||||
|
INIT_WORK(&hg->alive_work, hgicf_alive_work);
|
||||||
|
INIT_WORK(&hg->test_work, hgicf_test_work);
|
||||||
|
init_timer(&hg->alive_tmr);
|
||||||
|
setup_timer(&hg->alive_tmr, hgicf_alive_timer, (unsigned long)hg);
|
||||||
|
skb_queue_head_init(&hg->tx_dataq);
|
||||||
|
init_completion(&hg->txwnd_cp);
|
||||||
|
hgic_bootdl_init(&hg->bootdl, hg->bus, &hg->ctrl);
|
||||||
|
#ifndef __RTOS__
|
||||||
|
skb_queue_head_init(&hg->custmgmt_q);
|
||||||
|
skb_queue_head_init(&hg->dbginfo_q);
|
||||||
|
skb_queue_head_init(&hg->cust_driverdata_q);
|
||||||
|
sema_init(&hg->evtq.sema, 0);
|
||||||
|
#endif
|
||||||
|
atomic_set(&hg->txwnd, TXWND_INIT_VAL);
|
||||||
|
bus->rx_packet = hgicf_rx_data;
|
||||||
|
bus->tx_complete = hgicf_tx_complete;
|
||||||
|
bus->bus_priv = hg;
|
||||||
|
hg->tx_wq = ALLOC_ORDERED_WORKQUEUE("hgicf_tx", 4096);
|
||||||
|
if (!hg->tx_wq) {
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
set_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags);
|
||||||
|
hgic_dbg("ok\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__failed:
|
||||||
|
bus->rx_packet = NULL;
|
||||||
|
bus->tx_complete = NULL;
|
||||||
|
bus->bus_priv = NULL;
|
||||||
|
hgic_core_remove(hg);
|
||||||
|
hgic_dbg("fail\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_core_probe);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
int hgic_core_suspend(void *hgobj)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
struct hgicf_wdev *hg = (struct hgicf_wdev *)hgobj;
|
||||||
|
err = hgic_fwctrl_enter_sleep(&hg->ctrl, 1);
|
||||||
|
set_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_core_suspend);
|
||||||
|
|
||||||
|
int hgic_core_resume(void *hgobj)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
struct hgicf_wdev *hg = (struct hgicf_wdev *)hgobj;
|
||||||
|
clear_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags);
|
||||||
|
if (hg->bus->reinit) {
|
||||||
|
hg->bus->reinit(hg->bus);
|
||||||
|
}
|
||||||
|
err = hgic_fwctrl_enter_sleep(&hg->ctrl, 0);
|
||||||
|
if(err)
|
||||||
|
hgic_err("exit sleep fail, ret=%d\r\n", err);
|
||||||
|
schedule_work(&hg->alive_work);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_core_resume);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void hgic_core_probe_post(void *priv)
|
||||||
|
{
|
||||||
|
struct hgicf_wdev *hg = (struct hgicf_wdev *)priv;
|
||||||
|
schedule_work(&hg->delay_init);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_core_probe_post);
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
int hgic_ifbus_reinit(const char *ifname)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = NULL;
|
||||||
|
struct net_device *ndev = net_device_get_by_name(ifname);
|
||||||
|
if (ndev) {
|
||||||
|
vif = (struct hgicf_vif *)netdev_priv(ndev);
|
||||||
|
if (vif->hg->bus->reinit) {
|
||||||
|
return vif->hg->bus->reinit(vif->hg->bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
struct hgic_ota *hgic_devota(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct hgicf_vif *vif = NULL;
|
||||||
|
|
||||||
|
if (dev == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
vif = (struct hgicf_vif *)netdev_priv(dev);
|
||||||
|
return &(vif->hg->ota);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int __init hgicf_init(void)
|
||||||
|
{
|
||||||
|
VERSOIN_SHOW("fmac");
|
||||||
|
#ifdef __RTOS__
|
||||||
|
rcu_init();
|
||||||
|
tasklet_core_init();
|
||||||
|
net_device_init();
|
||||||
|
#else
|
||||||
|
#ifdef CONFIG_HGIC_USBIN
|
||||||
|
hgic_usb_init();
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_HGIC_SDIOIN
|
||||||
|
hgic_sdio_init();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
hgic_leave();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __exit hgicf_exit(void)
|
||||||
|
{
|
||||||
|
#ifndef __RTOS__
|
||||||
|
#ifdef CONFIG_HGIC_USBIN
|
||||||
|
hgic_usb_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_HGIC_SDIOIN
|
||||||
|
hgic_sdio_exit();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
net_device_exit();
|
||||||
|
tasklet_core_exit();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *hgic_param_ifname(const char *name)
|
||||||
|
{
|
||||||
|
if (name) ifname = (char *)name;
|
||||||
|
return ifname;
|
||||||
|
}
|
||||||
|
#ifdef __RTOS__
|
||||||
|
void hgic_param_iftest(int iftest)
|
||||||
|
{
|
||||||
|
if_test = iftest;
|
||||||
|
}
|
||||||
|
char *hgic_param_fwfile(const char *fw)
|
||||||
|
{
|
||||||
|
if (fw) fw_file = fw;
|
||||||
|
return fw_file;
|
||||||
|
}
|
||||||
|
int hgic_param_ifcount(int count)
|
||||||
|
{
|
||||||
|
if (count) iface_cnt = count;
|
||||||
|
return iface_cnt;
|
||||||
|
}
|
||||||
|
void hgic_param_initcb(hgic_init_cb cb)
|
||||||
|
{
|
||||||
|
init_cb = cb;
|
||||||
|
}
|
||||||
|
void hgic_param_eventcb(hgic_event_cb cb)
|
||||||
|
{
|
||||||
|
event_cb = cb;
|
||||||
|
}
|
||||||
|
void hgic_param_bootdl(int enable)
|
||||||
|
{
|
||||||
|
no_bootdl = !enable;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void hgicf_event(struct hgicf_wdev *hg, char *name, int event, int param1, int param2)
|
||||||
|
{
|
||||||
|
#ifdef __RTOS__
|
||||||
|
if(event_cb)
|
||||||
|
event_cb(name, event, param1, param2);
|
||||||
|
#else
|
||||||
|
FWEVTQ_SET(&hg->evtq, event);
|
||||||
|
up(&hg->evtq.sema);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(hgicf_init);
|
||||||
|
module_exit(hgicf_exit);
|
||||||
|
module_param(txq_size, int, 0);
|
||||||
|
module_param(fw_file, charp, 0644);
|
||||||
|
module_param(if_test, int, 0);
|
||||||
|
module_param(soft_fc, int, 0);
|
||||||
|
module_param(ifname, charp, 0644);
|
||||||
|
module_param(conf_file, charp, 0644);
|
||||||
|
module_param(no_bootdl, int, 0);
|
||||||
|
module_param(qc_mode, int, 0);
|
||||||
|
MODULE_DESCRIPTION("HUGE-IC FullMAC Wireless Card Driver");
|
||||||
|
MODULE_AUTHOR("Dongyun");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
70
hgic_fmac/ctrl.c
Normal file
70
hgic_fmac/ctrl.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
|
||||||
|
#include "hgicf.h"
|
||||||
|
#include "ctrl.h"
|
||||||
|
#include "cfg.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
/* cmd id, Odd : get (world access), even : set (root access) */
|
||||||
|
#define HG_PRIV_IOCTL_GET (SIOCIWFIRSTPRIV + 0x01)
|
||||||
|
#define HG_PRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
|
||||||
|
#define HG_PRIV_IOCTL_STAT (SIOCIWFIRSTPRIV + 0x03)
|
||||||
|
#define HG_PRIV_IOCTL_SCAN (SIOCIWFIRSTPRIV + 0x04)
|
||||||
|
#define HG_PRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x05)
|
||||||
|
#define HG_PRIV_IOCTL_SAVE (SIOCIWFIRSTPRIV + 0x06)
|
||||||
|
|
||||||
|
struct iw_priv_args hgicf_privtab[] = {
|
||||||
|
{HG_PRIV_IOCTL_SET , IW_PRIV_TYPE_CHAR | 1536, 0, "set"},
|
||||||
|
{HG_PRIV_IOCTL_GET , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, "get"},
|
||||||
|
{HG_PRIV_IOCTL_SCAN, IW_PRIV_TYPE_CHAR | 1536, 0, "scan"},
|
||||||
|
{HG_PRIV_IOCTL_E2P , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, "e2p"},
|
||||||
|
{HG_PRIV_IOCTL_STAT, 0, IW_PRIV_TYPE_CHAR | 1024, "stat"},
|
||||||
|
{HG_PRIV_IOCTL_SAVE, IW_PRIV_TYPE_CHAR | 1024, 0, "save"},
|
||||||
|
};
|
||||||
|
|
||||||
|
int hgicf_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct iwreq *wrqin = (struct iwreq *) ifr;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case SIOCGIWPRIV:
|
||||||
|
if (wrqin->u.data.pointer) {
|
||||||
|
if (!ACCESS_OK(VERIFY_WRITE, wrqin->u.data.pointer, sizeof(hgicf_privtab))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((sizeof(hgicf_privtab) / sizeof(hgicf_privtab[0])) <= wrqin->u.data.length) {
|
||||||
|
wrqin->u.data.length = sizeof(hgicf_privtab) / sizeof(hgicf_privtab[0]);
|
||||||
|
ret = copy_to_user(wrqin->u.data.pointer, hgicf_privtab, sizeof(hgicf_privtab));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HG_PRIV_IOCTL_SET:
|
||||||
|
ret = hgicf_ioctl_set_proc(dev, wrqin);
|
||||||
|
break;
|
||||||
|
case HG_PRIV_IOCTL_GET:
|
||||||
|
ret = hgicf_ioctl_get_proc(dev, wrqin);
|
||||||
|
break;
|
||||||
|
case HG_PRIV_IOCTL_SCAN:
|
||||||
|
ret = hgicf_ioctl_scan(dev, wrqin);
|
||||||
|
break;
|
||||||
|
case HG_PRIV_IOCTL_E2P:
|
||||||
|
ret = hgicf_ioctl_e2p(dev, wrqin);
|
||||||
|
break;
|
||||||
|
case HG_PRIV_IOCTL_STAT:
|
||||||
|
ret = hgicf_ioctl_stat(dev, wrqin);
|
||||||
|
break;
|
||||||
|
case HG_PRIV_IOCTL_SAVE:
|
||||||
|
ret = hgicf_ioctl_savecfg(dev, wrqin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
11
hgic_fmac/ctrl.h
Normal file
11
hgic_fmac/ctrl.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
#ifndef _HGICF_CTRL_H_
|
||||||
|
#define _HGICF_CTRL_H_
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
int hgicf_ioctl(struct net_device *dev, u32 cmd, u32 param1, u32 param2);
|
||||||
|
#else
|
||||||
|
int hgicf_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
196
hgic_fmac/event.c
Normal file
196
hgic_fmac/event.c
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/unaligned.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hgicf.h"
|
||||||
|
#include "../utils/fwctrl.h"
|
||||||
|
#include "cfg.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
char *hgicf_hw_state(int state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case HGICF_HW_DISCONNECTED:
|
||||||
|
return "Disconnect";
|
||||||
|
case HGICF_HW_DISABLED:
|
||||||
|
return "DISABLED";
|
||||||
|
case HGICF_HW_INACTIVE:
|
||||||
|
return "INACTIVE";
|
||||||
|
case HGICF_HW_SCANNING:
|
||||||
|
return "SCANNING";
|
||||||
|
case HGICF_HW_AUTHENTICATING:
|
||||||
|
return "AUTHENTICATING";
|
||||||
|
case HGICF_HW_ASSOCIATING:
|
||||||
|
return "ASSOCIATING";
|
||||||
|
case HGICF_HW_ASSOCIATED:
|
||||||
|
return "ASSOCIATED";
|
||||||
|
case HGICF_HW_4WAY_HANDSHAKE:
|
||||||
|
return "4WAY_HANDSHAKE";
|
||||||
|
case HGICF_HW_GROUP_HANDSHAKE:
|
||||||
|
return "GROUP_HANDSHAKE";
|
||||||
|
case HGICF_HW_CONNECTED:
|
||||||
|
return "CONNECTED";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgicf_rx_fw_event(struct hgicf_wdev *hg, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
char drop = 1;
|
||||||
|
char *data = NULL;
|
||||||
|
u32 evt_id = 0;
|
||||||
|
struct hgic_ctrl_hdr *evt = NULL;
|
||||||
|
struct hgicf_vif *vif = NULL;
|
||||||
|
|
||||||
|
if (skb == NULL || skb->dev == NULL || skb->len < sizeof(struct hgic_ctrl_hdr)) {
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vif = (struct hgicf_vif *)netdev_priv(skb->dev);
|
||||||
|
evt = (struct hgic_ctrl_hdr *)skb->data;
|
||||||
|
skb_pull(skb, sizeof(struct hgic_ctrl_hdr));
|
||||||
|
data = skb->data;
|
||||||
|
evt_id = HDR_EVTID(evt);
|
||||||
|
|
||||||
|
//hgic_dbg("event id:%d\r\n", evt->event.event_id);
|
||||||
|
switch (evt_id) {
|
||||||
|
case HGIC_EVENT_STATE_CHG:
|
||||||
|
vif->hw_state = data[0];
|
||||||
|
switch (vif->hw_state) {
|
||||||
|
case HGICF_HW_CONNECTED:
|
||||||
|
memcpy(vif->hw_bssid, data + 1, ETH_ALEN);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_DISCONNECT_REASON:
|
||||||
|
memcpy(&vif->disconnect_reason, data, sizeof(int));
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_ASSOC_STATUS:
|
||||||
|
memcpy(&vif->assoc_status_code, data, sizeof(int));
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_SCANNING:
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_SCANNING, 0, 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_SCAN_DONE:
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_SCAN_DONE, 0, 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_TX_BITRATE:
|
||||||
|
hg->status.tx_bitrate = get_unaligned_le32((u8 *)(evt + 1));
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_TX_BITRATE, hg->status.tx_bitrate, 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_PAIR_START:
|
||||||
|
hg->status.pair_state = 0;
|
||||||
|
memset(hg->pairing_sta, 0, 6);
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_PAIR_START, 0, 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_PAIR_SUCCESS:
|
||||||
|
hg->status.pair_state = 1;
|
||||||
|
if(skb->len >= 6) memcpy(hg->pairing_sta, data, 6);
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_PAIR_SUCCESS, (long)hg->pairing_sta, 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_PAIR_DONE:
|
||||||
|
hg->paired_stas_cnt = (evt->hdr.length - sizeof(struct hgic_ctrl_hdr)) / 6;
|
||||||
|
if (hg->paired_stas) {
|
||||||
|
kfree(hg->paired_stas);
|
||||||
|
}
|
||||||
|
hg->paired_stas = kzalloc(evt->hdr.length, GFP_KERNEL);
|
||||||
|
if (hg->paired_stas) {
|
||||||
|
memcpy(hg->paired_stas, data, hg->paired_stas_cnt * 6);
|
||||||
|
}
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_PAIR_DONE, (long)hg->paired_stas, (long)hg->paired_stas_cnt);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_CONECT_START:
|
||||||
|
vif->hw_state = HGICF_HW_ASSOCIATING;
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_CONECT_START, 0, 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_CONECTED:
|
||||||
|
vif->hw_state = HGICF_HW_CONNECTED;
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_CONECTED, (long)skb->data, skb->len);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_DISCONECTED:
|
||||||
|
vif->hw_state = HGICF_HW_DISCONNECTED;
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_DISCONECTED, (long)skb->data, skb->len);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_SIGNAL:
|
||||||
|
hg->status.signal = (s8)data[0];
|
||||||
|
hg->status.evm = (s8)data[1];
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_SIGNAL, hg->status.signal, hg->status.evm);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_FWDBG_INFO:
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_FWDBG_INFO, (long)skb->data, skb->len);
|
||||||
|
#ifndef __RTOS__
|
||||||
|
printk("%s", skb->data);
|
||||||
|
if (skb_queue_len(&hg->dbginfo_q) > 4) {
|
||||||
|
kfree_skb(skb_dequeue(&hg->dbginfo_q));
|
||||||
|
}
|
||||||
|
skb_queue_tail(&hg->dbginfo_q, skb);
|
||||||
|
drop = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_REQUEST_PARAM:
|
||||||
|
schedule_work(&hg->ctrl.flush_work);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_CUSTOMER_MGMT:
|
||||||
|
hgic_dbg("rx mgmt from %pM, %d bytes\r\n", data, skb->len - 6);
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_CUSTOMER_MGMT, (long)skb->data, skb->len);
|
||||||
|
#ifndef __RTOS__
|
||||||
|
if (skb_queue_len(&hg->custmgmt_q) > 16) {
|
||||||
|
kfree_skb(skb_dequeue(&hg->custmgmt_q));
|
||||||
|
}
|
||||||
|
skb_queue_tail(&hg->custmgmt_q, skb);
|
||||||
|
drop = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_CUST_DRIVER_DATA:
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_CUST_DRIVER_DATA, (long)skb->data, skb->len);
|
||||||
|
#ifndef __RTOS__
|
||||||
|
if (skb_queue_len(&hg->cust_driverdata_q) > 16) {
|
||||||
|
kfree_skb(skb_dequeue(&hg->cust_driverdata_q));
|
||||||
|
}
|
||||||
|
skb_queue_tail(&hg->cust_driverdata_q, skb);
|
||||||
|
drop = 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_DHCPC_DONE:
|
||||||
|
#ifndef __RTOS__
|
||||||
|
memcpy(&hg->dhcpc, skb->data, sizeof(hg->dhcpc));
|
||||||
|
#endif
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_DHCPC_DONE, (long)skb->data, skb->len);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_CONNECT_FAIL:
|
||||||
|
hg->status.conntect_fail = data[0];
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_CONNECT_FAIL, data[0], 0);
|
||||||
|
break;
|
||||||
|
case HGIC_EVENT_UNPAIR_STA:
|
||||||
|
hgic_dbg("unpair sta: %pM\r\n", data);
|
||||||
|
hgicf_event(hg, skb->dev->name, HGIC_EVENT_UNPAIR_STA, data, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (drop) { dev_kfree_skb(skb); }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
9
hgic_fmac/event.h
Normal file
9
hgic_fmac/event.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
#ifndef _HGICF_EVENT_H_
|
||||||
|
#define _HGICF_EVENT_H_
|
||||||
|
|
||||||
|
int hgicf_rx_fw_event(struct hgicf_wdev *hg, struct sk_buff *skb);
|
||||||
|
void hgicf_event(struct hgicf_wdev *hg, char *name, int event, int param1, int param2);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
156
hgic_fmac/hgicf.h
Normal file
156
hgic_fmac/hgicf.h
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
|
||||||
|
#ifndef _HGIC_FMAC_H_
|
||||||
|
#define _HGIC_FMAC_H_
|
||||||
|
|
||||||
|
#ifndef __RTOS__
|
||||||
|
#include <linux/version.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
#include "../utils/fwdl.h"
|
||||||
|
#include "../utils/fwctrl.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
#include "../utils/ota.h"
|
||||||
|
|
||||||
|
#define FWEVNTQ_SIZE (128)
|
||||||
|
enum hgicf_dev_flags {
|
||||||
|
HGICF_DEV_FLAGS_INITED,
|
||||||
|
HGICF_DEV_FLAGS_RUNNING,
|
||||||
|
HGICF_DEV_FLAGS_SUSPEND,
|
||||||
|
HGICF_DEV_FLAGS_BOOTDL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hgicf_state {
|
||||||
|
HGICF_STATE_NONE = 0,
|
||||||
|
HGICF_STATE_START,
|
||||||
|
HGICF_STATE_FW_LD,
|
||||||
|
HGICF_STATE_STOP,
|
||||||
|
HGICF_STATE_PAUSE,
|
||||||
|
HGICF_STATE_QUEUE_STOPPED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hgicf_hw_state {
|
||||||
|
HGICF_HW_DISCONNECTED,
|
||||||
|
HGICF_HW_DISABLED,
|
||||||
|
HGICF_HW_INACTIVE,
|
||||||
|
HGICF_HW_SCANNING,
|
||||||
|
HGICF_HW_AUTHENTICATING,
|
||||||
|
HGICF_HW_ASSOCIATING,
|
||||||
|
HGICF_HW_ASSOCIATED,
|
||||||
|
HGICF_HW_4WAY_HANDSHAKE,
|
||||||
|
HGICF_HW_GROUP_HANDSHAKE,
|
||||||
|
HGICF_HW_CONNECTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgicf_wdev;
|
||||||
|
|
||||||
|
struct hgicf_vif {
|
||||||
|
u8 fwifidx;
|
||||||
|
unsigned long state;
|
||||||
|
struct net_device *ndev;
|
||||||
|
struct hgicf_wdev *hg;
|
||||||
|
int hw_state;
|
||||||
|
char hw_ssid[32];
|
||||||
|
char hw_bssid[ETH_ALEN];
|
||||||
|
int disconnect_reason;
|
||||||
|
int assoc_status_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgicf_status {
|
||||||
|
u32 tx_bitrate;
|
||||||
|
s8 signal;
|
||||||
|
s8 evm;
|
||||||
|
s8 pair_state;
|
||||||
|
u8 conntect_fail;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgicf_wdev {
|
||||||
|
void *dev;
|
||||||
|
u32 dev_id;
|
||||||
|
unsigned long flags;
|
||||||
|
u16 data_cookie;
|
||||||
|
u16 ctrl_cookie;
|
||||||
|
u16 rx_cookie;
|
||||||
|
spinlock_t lock;
|
||||||
|
struct hgic_fw_info fwinfo;
|
||||||
|
struct hgic_bus *bus;
|
||||||
|
struct hgicf_vif *ap;
|
||||||
|
struct hgicf_vif *sta;
|
||||||
|
struct sk_buff_head tx_dataq;
|
||||||
|
struct work_struct tx_work;
|
||||||
|
struct work_struct delay_init; /*delay init work*/
|
||||||
|
struct work_struct alive_work;
|
||||||
|
struct workqueue_struct *tx_wq;
|
||||||
|
struct delayed_work status_work; /*status print work*/
|
||||||
|
struct hgic_fwctrl ctrl;
|
||||||
|
struct hgic_bootdl bootdl;
|
||||||
|
struct hgicf_procfs proc;
|
||||||
|
struct hgicf_status status;
|
||||||
|
struct timer_list alive_tmr;
|
||||||
|
unsigned long last_rx;
|
||||||
|
/*if test*/
|
||||||
|
struct work_struct test_work;
|
||||||
|
u32 test_rx_len, test_tx_len;
|
||||||
|
u32 test_jiff, if_test;
|
||||||
|
/*soft fc*/
|
||||||
|
int soft_fc;
|
||||||
|
atomic_t txwnd;
|
||||||
|
struct completion txwnd_cp;
|
||||||
|
#ifndef __RTOS__
|
||||||
|
struct sk_buff_head custmgmt_q;
|
||||||
|
struct sk_buff_head dbginfo_q;
|
||||||
|
struct sk_buff_head cust_driverdata_q;
|
||||||
|
#endif
|
||||||
|
struct hgic_ota ota;
|
||||||
|
u8 pairing_sta[6];
|
||||||
|
u8 *paired_stas;
|
||||||
|
u32 paired_stas_cnt;
|
||||||
|
u8 radio_off;
|
||||||
|
#ifndef __RTOS__
|
||||||
|
struct {
|
||||||
|
u8 buf[FWEVNTQ_SIZE];
|
||||||
|
u8 wpos, rpos;
|
||||||
|
struct semaphore sema;
|
||||||
|
}evtq;
|
||||||
|
struct {
|
||||||
|
u32 ipaddr, netmask, svrip, router, dns1, dns2;
|
||||||
|
}dhcpc;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgicf_hw_status {
|
||||||
|
uint32_t rssi;
|
||||||
|
uint32_t per;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
extern void hgic_print_hex(char *buf, int len);
|
||||||
|
extern char *hgicf_hw_state(int state);
|
||||||
|
u16 hgicf_data_cookie(struct hgicf_wdev *hg);
|
||||||
|
|
||||||
|
#ifndef __RTOS__
|
||||||
|
#define FWEVTQ_NPOS(evtq,pos) ((((evtq)->pos)+1 >= FWEVNTQ_SIZE) ? (0) : (((evtq)->pos)+1))
|
||||||
|
#define FWEVTQ_EMPTY(evtq) ((evtq)->wpos == (evtq)->rpos)
|
||||||
|
#define FWEVTQ_FULL(evtq) (FWEVTQ_NPOS(evtq, wpos) == (evtq)->rpos)
|
||||||
|
#define FWEVTQ_COUNT(evtq) (((evtq)->rpos <= (evtq)->wpos)?\
|
||||||
|
((evtq)->wpos - (evtq)->rpos):\
|
||||||
|
(FWEVNTQ_SIZE-(evtq)->rpos + (evtq)->wpos))
|
||||||
|
|
||||||
|
#define FWEVTQ_GET(evtq, val) do{\
|
||||||
|
if(!FWEVTQ_EMPTY(evtq)){\
|
||||||
|
val = (evtq)->buf[(evtq)->rpos];\
|
||||||
|
(evtq)->rpos = FWEVTQ_NPOS((evtq), rpos);\
|
||||||
|
}\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define FWEVTQ_SET(evtq, val) do{\
|
||||||
|
if(FWEVTQ_FULL(evtq)){\
|
||||||
|
(evtq)->rpos = FWEVTQ_NPOS((evtq), rpos);\
|
||||||
|
}\
|
||||||
|
(evtq)->buf[(evtq)->wpos] = val;\
|
||||||
|
(evtq)->wpos = FWEVTQ_NPOS((evtq), wpos);\
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
1204
hgic_fmac/procfs.c
Normal file
1204
hgic_fmac/procfs.c
Normal file
File diff suppressed because it is too large
Load diff
71
hgic_fmac/procfs.h
Normal file
71
hgic_fmac/procfs.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
|
||||||
|
#ifndef _HGICF_PROCFS_H_
|
||||||
|
#define _HGICF_PROCFS_H_
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
struct hgicf_procfs {};
|
||||||
|
#define hgicf_create_procfs(hg)
|
||||||
|
#define hgicf_delete_procfs(hg)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
|
struct hgicf_wdev;
|
||||||
|
|
||||||
|
#define HGIC_TESTMODE_BUFF_SIZE (4096)
|
||||||
|
struct hgicf_procfs {
|
||||||
|
struct proc_dir_entry *rootdir;
|
||||||
|
struct proc_dir_entry *tx_bitrate;
|
||||||
|
struct proc_dir_entry *testmode;
|
||||||
|
struct proc_dir_entry *status;
|
||||||
|
struct proc_dir_entry *signal;
|
||||||
|
struct proc_dir_entry *evm;
|
||||||
|
struct proc_dir_entry *conn_state;
|
||||||
|
u8 testmode_buf[HGIC_TESTMODE_BUFF_SIZE];
|
||||||
|
struct proc_dir_entry *ota;
|
||||||
|
struct proc_dir_entry *temp;
|
||||||
|
struct proc_dir_entry *sleep;
|
||||||
|
struct proc_dir_entry *iwpriv;
|
||||||
|
u8 iwpriv_buf[4096];
|
||||||
|
struct proc_dir_entry *paired_stas;
|
||||||
|
struct proc_dir_entry *radio_off;
|
||||||
|
struct proc_dir_entry *sta_count;
|
||||||
|
struct proc_dir_entry *wakeup;
|
||||||
|
struct proc_dir_entry *wakeup_data;
|
||||||
|
struct proc_dir_entry *heartbeat;
|
||||||
|
struct proc_dir_entry *heartbeat_resp;
|
||||||
|
struct proc_dir_entry *pair_state;
|
||||||
|
struct proc_dir_entry *fw_ver;
|
||||||
|
struct proc_dir_entry *wkreason;
|
||||||
|
struct proc_dir_entry *fwevent;
|
||||||
|
struct proc_dir_entry *mgmt;
|
||||||
|
struct proc_dir_entry *battery_level;
|
||||||
|
struct proc_dir_entry *fwdbginfo;
|
||||||
|
struct proc_dir_entry *pairing_sta;
|
||||||
|
struct proc_dir_entry *dhcpc;
|
||||||
|
struct proc_dir_entry *wkdata_buff;
|
||||||
|
struct proc_dir_entry *wkdata_mask;
|
||||||
|
struct proc_dir_entry *cust_driverdata;
|
||||||
|
struct proc_dir_entry *freqinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hgicf_create_procfs(struct hgicf_wdev *hg);
|
||||||
|
void hgicf_delete_procfs(struct hgicf_wdev *hg);
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
|
||||||
|
static inline struct proc_dir_entry *PDE(const struct inode *inode)
|
||||||
|
{
|
||||||
|
return PROC_I(inode)->pde;
|
||||||
|
}
|
||||||
|
static inline void *PDE_DATA(const struct inode *inode)
|
||||||
|
{
|
||||||
|
return PDE(inode)->data;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
8
hgicf.conf
Normal file
8
hgicf.conf
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
freq_range=9080,9240,8
|
||||||
|
bss_bw=8
|
||||||
|
tx_mcs=255
|
||||||
|
chan_list=
|
||||||
|
key_mgmt=NONE
|
||||||
|
wpa_psk=
|
||||||
|
ssid=hgic_ah_test
|
||||||
|
mode=ap
|
343
hgota/fwinfo.c
Normal file
343
hgota/fwinfo.c
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
#include <error.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "libota.h"
|
||||||
|
#include "fwinfo.h"
|
||||||
|
|
||||||
|
static void print_hex(char *data, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
printf("\r\n");
|
||||||
|
for(i=0;i<len;i++){
|
||||||
|
if(i && (i%8)==0) printf(" ");
|
||||||
|
if(i && (i%16)==0) printf("\r\n");
|
||||||
|
printf("%02x ", data[i]&0xff);
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Name: CRC-16/MODBUS x16+x15+x2+1
|
||||||
|
* Poly: 0x8005
|
||||||
|
* Init: 0xFFFF
|
||||||
|
* Refin: True
|
||||||
|
* Refout: True
|
||||||
|
* Xorout: 0x0000
|
||||||
|
* Note:
|
||||||
|
*****************************************************************************/
|
||||||
|
uint16 fwinfo_crc16(const uint8 *data, uint32 length)
|
||||||
|
{
|
||||||
|
uint8 i;
|
||||||
|
uint16 crc = 0xffff; // Initial value
|
||||||
|
while (length--) {
|
||||||
|
crc ^= *data++; // crc ^= *data; data++;
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (crc & 1)
|
||||||
|
{ crc = (crc >> 1) ^ 0xA001; } // 0xA001 = reverse 0x8005
|
||||||
|
else
|
||||||
|
{ crc = (crc >> 1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Name: CRC-32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
|
||||||
|
* Poly: 0x4C11DB7
|
||||||
|
* Init: 0xFFFFFFF
|
||||||
|
* Refin: True
|
||||||
|
* Refout: True
|
||||||
|
* Xorout: 0xFFFFFFF
|
||||||
|
* Alias: CRC_32/ADCCP
|
||||||
|
* Use: WinRAR,ect.
|
||||||
|
*****************************************************************************/
|
||||||
|
uint32 fwinfo_crc32(const uint8 *data, uint32 length)
|
||||||
|
{
|
||||||
|
uint8 i;
|
||||||
|
uint32 crc = 0xffffffff; // Initial value
|
||||||
|
while (length--) {
|
||||||
|
crc ^= *data++; // crc ^= *data; data++;
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (crc & 1) {
|
||||||
|
crc = (crc >> 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7
|
||||||
|
} else {
|
||||||
|
crc = (crc >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32 fwinfo_check_fwinfo_hdr(const uint8 *data)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
fwinfo_err("%s:Input para error!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//print_hex(data, 64);
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
if (fw_hdr->boot.boot_flag != FWINFO_BOOT_HDR) {
|
||||||
|
fwinfo_err("%s:Can not find boot header!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;;
|
||||||
|
}
|
||||||
|
if (fw_hdr->fw_infor.func_code != FWINFO_CODE_HDR) {
|
||||||
|
fwinfo_err("%s:Can not find fw infor header %x!\n", __FUNCTION__, fw_hdr->fw_infor.func_code);
|
||||||
|
return -EINVAL;;
|
||||||
|
}
|
||||||
|
if (fw_hdr->spi_infor.func_code != FWINFO_SPI_HDR) {
|
||||||
|
fwinfo_err("%s:Can not find spi info header!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 fwinfo_get_fw_aes_en(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:aes_en:%d\n", __FUNCTION__, fw_hdr->boot.mode.aes_en);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.mode.aes_en;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 fwinfo_get_fw_crc_en(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:crc_en:%d\n", __FUNCTION__, fw_hdr->boot.mode.crc_en);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.mode.crc_en;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_dl_addr(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:download addr:%x\n", __FUNCTION__, fw_hdr->boot.boot_to_sram_addr);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.boot_to_sram_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_run_addr(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:run addr:%x\n", __FUNCTION__, fw_hdr->boot.run_sram_addr);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.run_sram_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_code_offset(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:code offset:%d\n", __FUNCTION__, fw_hdr->boot.boot_code_offset_addr);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.boot_code_offset_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_local_crc32(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:local crc:%x\n", __FUNCTION__, fw_hdr->fw_infor.code_crc32);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.code_crc32;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_sdk_version(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Current file sdk info:%d.%d.%d.%d\r\n", __FUNCTION__,
|
||||||
|
(fw_hdr->fw_infor.sdk_version >> 24) & 0xff, (fw_hdr->fw_infor.sdk_version >> 16) & 0xff,
|
||||||
|
(fw_hdr->fw_infor.sdk_version >> 8) & 0xff, (fw_hdr->fw_infor.sdk_version & 0xff));
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.sdk_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_svn_version(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Current file svn info:%d\n", __FUNCTION__, fw_hdr->fw_infor.svn_version);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.svn_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16 fwinfo_get_fw_chipid(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:fw chipid:%x\n", __FUNCTION__, fw_hdr->fw_infor.chip_id);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.chip_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 fwinfo_get_fw_cpuid(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
struct fwinfo_hdr *fw_hdr = NULL;
|
||||||
|
int32 ret = 0;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
fwinfo_dbg("%s:Check Para:cpu_id:%d\n", __FUNCTION__, fw_hdr->fw_infor.cpu_id);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.cpu_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 fwinfo_get_fw_length(const uint8 *data, int32 *err_code)
|
||||||
|
{
|
||||||
|
int32 ret = 0;
|
||||||
|
struct fwinfo_hdr *fw_hdr = (struct fwinfo_hdr *)data;
|
||||||
|
|
||||||
|
ret = fwinfo_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
fwinfo_err("%s:fwinfo_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.boot_from_flash_len + fw_hdr->boot.boot_code_offset_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 fwinfo_get_fw_code_checksum(const uint8 *data, int32 len)
|
||||||
|
{
|
||||||
|
uint32 local_chksum = 0;
|
||||||
|
uint32 cur_crc = 0;
|
||||||
|
int32 err_code = 0;
|
||||||
|
uint32 code_offset = 0;
|
||||||
|
const uint8 *code_data = NULL;
|
||||||
|
int32 code_len = 0;
|
||||||
|
|
||||||
|
local_chksum = fwinfo_get_fw_local_crc32(data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
fwinfo_err("%s:fwinfo_get_fw_local_crc32 error!\n", __FUNCTION__);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
code_offset = fwinfo_get_fw_code_offset(data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
fwinfo_err("%s:fwinfo_get_fw_code_offset error!\n", __FUNCTION__);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
code_data = data + code_offset;
|
||||||
|
code_len = len - code_offset;
|
||||||
|
|
||||||
|
if (code_len < 0) {
|
||||||
|
fwinfo_err("%s:Input para error!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_crc = fwinfo_crc32(code_data, code_len);
|
||||||
|
if (cur_crc != local_chksum && ~cur_crc != local_chksum) {
|
||||||
|
fwinfo_err("%s:Check crc32 with hdr crc error,local crc:%x,cur_crc:%x\r\n",
|
||||||
|
__FUNCTION__, local_chksum, cur_crc);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
fwinfo_dbg("%s:Checksum Success!\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
111
hgota/fwinfo.h
Normal file
111
hgota/fwinfo.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#ifndef _HGIC_FWINFO_H_
|
||||||
|
#define _HGIC_FWINFO_H_
|
||||||
|
|
||||||
|
#define fwinfo_dbg(fmt, ...) //printf("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#define fwinfo_err(fmt, ...) printf("%s:%d::"fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define FWINFO_BOOT_HDR 0x5a69
|
||||||
|
#define FWINFO_SPI_HDR 0x1
|
||||||
|
#define FWINFO_CODE_HDR 0x2
|
||||||
|
|
||||||
|
struct fwinfo_spiflash_header_boot {
|
||||||
|
uint16 boot_flag; /* 0 : 0x5a69, header boot flag */
|
||||||
|
uint8 version; /* 2 : version */
|
||||||
|
uint8 size; /* 3 : Link to Next Header */
|
||||||
|
uint32 boot_to_sram_addr; /* 4 : spi data load to sram addr */
|
||||||
|
uint32 run_sram_addr; /* 8 : code execute start addr */
|
||||||
|
uint32 boot_code_offset_addr; /* 12 : HeaderLen+ParamLen=4096+512 */
|
||||||
|
uint32 boot_from_flash_len; /* 16 : */
|
||||||
|
uint16 boot_data_crc; /* 20 : boot data crc check */
|
||||||
|
uint16 flash_blk_size; /* 22 : flash size in 64KB(version > 1), 512B(version== 0) */
|
||||||
|
uint16 boot_baud_mhz : 14, /* 24 : spi clk freq in mhz(version > 1), khz(version== 0) */
|
||||||
|
driver_strength : 2; /* io driver strength */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16 pll_src : 8, /* pll src in Mhz */
|
||||||
|
pll_en : 1, /* PLL enable */
|
||||||
|
debug : 1, /* debug info uart output enable */
|
||||||
|
aes_en : 1, /* AES enable */
|
||||||
|
crc_en : 1, /* CRC check enable */
|
||||||
|
reserved : 4;
|
||||||
|
} mode; /* 26 : boot option */
|
||||||
|
uint16 reserved; /* 28 : */
|
||||||
|
uint16 head_crc16; /* (size+4) byte CRC16 check value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* format : cmd + dummys_flags + dat_len + dat */
|
||||||
|
struct fwinfo_spiflash_spec_sequnce {
|
||||||
|
uint8 cmd_nums;
|
||||||
|
uint8 cmd;
|
||||||
|
uint8 dummy;
|
||||||
|
uint8 dat_len;
|
||||||
|
uint8 dat;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct fwinfo_spiflash_read_cfg {
|
||||||
|
uint8 read_cmd; /* read_cmd */
|
||||||
|
uint8 cmd_dummy_cycles : 4, /* read dummy cycles */
|
||||||
|
clock_mode : 2, /* clock polarity & phase */
|
||||||
|
spec_sequnce_en : 1, /* spec sequnce to execute, maybe same with quad_wire_en */
|
||||||
|
quad_wire_en : 1; /* spi D2/D3 enable */
|
||||||
|
|
||||||
|
uint8 wire_mode_cmd : 2,
|
||||||
|
wire_mode_addr : 2,
|
||||||
|
wire_mode_data : 2,
|
||||||
|
quad_wire_select : 2; /* spi D2/D3 group select */
|
||||||
|
|
||||||
|
uint8 reserved3;
|
||||||
|
|
||||||
|
uint16 sample_delay; /* RX sample dalay time: 0 ~ clk_divor */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fwinfo_spiflash_header_spi_info {
|
||||||
|
uint8 func_code; /* 0 : header function(0x1) */
|
||||||
|
uint8 size; /* 1: Link to Next Header */
|
||||||
|
|
||||||
|
struct fwinfo_spiflash_read_cfg read_cfg;
|
||||||
|
uint8 fwinfo_spiflash_spec_sequnce[64];
|
||||||
|
|
||||||
|
uint16 header_crc16; /* (size+2) byte CRC16 check value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* fwinfo_ah_fw_v1.0.1.1_2020.2.20.bin ?*/
|
||||||
|
|
||||||
|
struct fwinfo_spiflash_header_firmware_info {
|
||||||
|
uint8 func_code; /* 0 : header function(0x2) */
|
||||||
|
uint8 size; /* 1: Link to Next Header */
|
||||||
|
uint32 sdk_version; /* version */
|
||||||
|
uint32 svn_version;
|
||||||
|
uint32 date; /* date */
|
||||||
|
uint16 chip_id; /* chip_id */
|
||||||
|
uint8 cpu_id; /* cpu id, fix 0 */
|
||||||
|
uint32 code_crc32; /* code CRC32 */
|
||||||
|
uint16 param_crc16; /* param CRC16 */
|
||||||
|
uint16 crc16; /* (size+2) byte CRC16 check value */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fwinfo_hdr {
|
||||||
|
struct fwinfo_spiflash_header_boot boot;
|
||||||
|
struct fwinfo_spiflash_header_spi_info spi_infor; /* func1*/
|
||||||
|
struct fwinfo_spiflash_header_firmware_info fw_infor ; /* func2*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
uint16 fwinfo_crc16(const uint8 *data, uint32 length);
|
||||||
|
uint32 fwinfo_crc32(const uint8 *data, uint32 length);
|
||||||
|
uint16 fwinfo_get_fw_aes_en(const uint8 *data, int32 *err_code);
|
||||||
|
uint16 fwinfo_get_fw_crc_en(const uint8 *data, int32 *err_code);
|
||||||
|
uint32 fwinfo_get_fw_dl_addr(const uint8 *data, int32 *err_code);
|
||||||
|
uint32 fwinfo_get_fw_run_addr(const uint8 *data, int32 *err_code);
|
||||||
|
uint32 fwinfo_get_fw_code_offset(const uint8 *data, int32 *err_code);
|
||||||
|
uint32 fwinfo_get_fw_local_crc32(const uint8 *data, int32 *err_code);
|
||||||
|
uint32 fwinfo_get_fw_sdk_version(const uint8 *data, int32 *err_code);
|
||||||
|
uint32 fwinfo_get_fw_svn_version(const uint8 *data, int32 *err_code);
|
||||||
|
uint16 fwinfo_get_fw_chipid(const uint8 *data, int32 *err_code);
|
||||||
|
uint8 fwinfo_get_fw_cpuid(const uint8 *data, int32 *err_code);
|
||||||
|
int32 fwinfo_get_fw_code_checksum(const uint8 *data, int32 len);
|
||||||
|
uint32 fwinfo_get_fw_lenght(const uint8 *data, int32 *err_code);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
349
hgota/hgota.c
Normal file
349
hgota/hgota.c
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
#include <error.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include "libota.h"
|
||||||
|
|
||||||
|
struct hgicOTA {
|
||||||
|
uint8 rxbuf[2048];
|
||||||
|
uint8 mac_addr[6];
|
||||||
|
int sock;
|
||||||
|
int if_index;
|
||||||
|
} hgOTA;
|
||||||
|
|
||||||
|
|
||||||
|
static void hgic_show_device(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
printf("\r\n------------------------------------------------------------------\r\n");
|
||||||
|
for (i = 0; i < OTA_STA_COUNT; i++) {
|
||||||
|
if (LIBOTA.stas[i].online) {
|
||||||
|
printf("| "MACSTR", chipid:%x, version:%d.%d.%d.%d-%d |\r\n",
|
||||||
|
MAC2STR(LIBOTA.stas[i].addr),
|
||||||
|
LIBOTA.stas[i].chipid,
|
||||||
|
(LIBOTA.stas[i].version >> 24) & 0xff,
|
||||||
|
(LIBOTA.stas[i].version >> 16) & 0xff,
|
||||||
|
(LIBOTA.stas[i].version >> 8) & 0xff,
|
||||||
|
(LIBOTA.stas[i].version) & 0xff,
|
||||||
|
LIBOTA.stas[i].svn_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("------------------------------------------------------------------\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hgota_sta *hgic_get_device(u8 *addr)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < OTA_STA_COUNT; i++) {
|
||||||
|
if (memcmp(LIBOTA.stas[i].addr, addr, 6) ==0) {
|
||||||
|
return &LIBOTA.stas[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hgic_save_device(void)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen("/tmp/hgota.tmp", "w+");
|
||||||
|
if (fp) {
|
||||||
|
fwrite(LIBOTA.stas, 1, sizeof(LIBOTA.stas), fp);
|
||||||
|
fclose(fp);
|
||||||
|
printf("save scan result into /tmp/hgota.tmp\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_read_device(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
FILE *fp = fopen("/tmp/hgota.tmp", "r");
|
||||||
|
if (fp) {
|
||||||
|
fread(LIBOTA.stas, 1, sizeof(LIBOTA.stas), fp);
|
||||||
|
fclose(fp);
|
||||||
|
printf("load device info from /tmp/hgota.tmp\r\n");
|
||||||
|
hgic_show_device();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sock_init(char *ifname)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct ifreq req;
|
||||||
|
|
||||||
|
int sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock == -1) {
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
memset(&req, 0, sizeof(struct ifreq));
|
||||||
|
strncpy(req.ifr_name, ifname, strlen(ifname));
|
||||||
|
ret = ioctl(sock, SIOCGIFINDEX, &req);
|
||||||
|
if (sock == -1) {
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
hgOTA.if_index = req.ifr_ifindex;
|
||||||
|
|
||||||
|
ret = ioctl(sock, SIOCGIFHWADDR, &req);
|
||||||
|
if (sock == -1) {
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
memcpy(hgOTA.mac_addr, req.ifr_hwaddr.sa_data, 6);
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_OTA));
|
||||||
|
hgOTA.sock = sock;
|
||||||
|
//printf("%d, %s: "MACSTR"\r\n", hgOTA.if_index, ifname, MAC2STR(hgOTA.mac_addr));
|
||||||
|
return (sock != -1);
|
||||||
|
__fail:
|
||||||
|
if (sock != -1) {
|
||||||
|
close(sock);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sock_recv(int tmo)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int recv_len = 0;
|
||||||
|
fd_set rfd;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
FD_ZERO(&rfd);
|
||||||
|
FD_SET(hgOTA.sock, &rfd);
|
||||||
|
timeout.tv_sec = tmo / 1000;
|
||||||
|
timeout.tv_usec = (tmo % 1000) * 1000;
|
||||||
|
ret = select(hgOTA.sock + 1, &rfd, NULL, NULL, &timeout);
|
||||||
|
if (ret > 0 && FD_ISSET(hgOTA.sock, &rfd)) {
|
||||||
|
recv_len = recvfrom(hgOTA.sock, hgOTA.rxbuf, 2048, 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
return (recv_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int raw_sock_send(char *data, int len)
|
||||||
|
{
|
||||||
|
struct sockaddr_ll dest;
|
||||||
|
memset(&dest, 0, sizeof(struct sockaddr_ll));
|
||||||
|
dest.sll_family = AF_PACKET;
|
||||||
|
dest.sll_protocol = htons(ETH_P_OTA);
|
||||||
|
dest.sll_ifindex = hgOTA.if_index;
|
||||||
|
dest.sll_pkttype = PACKET_OUTGOING;
|
||||||
|
dest.sll_halen = 6;
|
||||||
|
memcpy(dest.sll_addr, data, 6);
|
||||||
|
memcpy(data + 6, hgOTA.mac_addr, 6);
|
||||||
|
return sendto(hgOTA.sock, data, len, 0, (const struct sockaddr *)&dest, sizeof(struct sockaddr_ll));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_scan_device(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int recv_len = 0;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
libota_scan(1);
|
||||||
|
while (i++ < 10) {
|
||||||
|
if ((i & 0xf) == 0) { libota_scan(0); }
|
||||||
|
recv_len = hgic_sock_recv(50);
|
||||||
|
if (recv_len > 0) {
|
||||||
|
libota_rx_proc(hgOTA.rxbuf, recv_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hgic_save_device();
|
||||||
|
printf("OTA SCAN:%d devices:\r\n", LIBOTA.sta_count);
|
||||||
|
hgic_show_device();
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_reboot_device(char *addr)
|
||||||
|
{
|
||||||
|
uint8 mac[6];
|
||||||
|
printf("reboot sta %s\r\n", addr);
|
||||||
|
if (6 == sscanf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5)) {
|
||||||
|
libota_reboot(mac, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_loaddef_device(char *addr)
|
||||||
|
{
|
||||||
|
uint8 mac[6];
|
||||||
|
|
||||||
|
printf("load default sta %s config\r\n", addr);
|
||||||
|
if (6 == sscanf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5)) {
|
||||||
|
libota_reboot(mac, ETH_P_REBOOT_FLAGS_LOADDEF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8 *hgic_read_firmware(char *path, struct hgota_fw_info *fwinfo)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
uint32 file_len = 0;
|
||||||
|
uint8 *fwdata = NULL;
|
||||||
|
uint32 rlen = 0;
|
||||||
|
FILE *fp = fopen(path, "r");
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
file_len = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
fwdata = malloc(file_len);
|
||||||
|
if (fwdata) {
|
||||||
|
rlen = fread(fwdata, 1, file_len, fp);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (file_len == rlen && fwdata) {
|
||||||
|
fwinfo->chipid = fwinfo_get_fw_chipid(fwdata, &err);
|
||||||
|
fwinfo->tot_len = fwinfo_get_fw_length(fwdata, &err);
|
||||||
|
fwinfo->version = fwinfo_get_fw_sdk_version(fwdata, &err);
|
||||||
|
fwinfo->svn_version = fwinfo_get_fw_svn_version(fwdata, &err);
|
||||||
|
if (!fwinfo_get_fw_code_checksum(fwdata, fwinfo->tot_len)) {
|
||||||
|
printf("firmware Info:\r\n");
|
||||||
|
printf(" chipid:%x\r\n", fwinfo->chipid);
|
||||||
|
printf(" version:%d.%d.%d.%d-%d\r\n", (fwinfo->version >> 24) & 0xff,
|
||||||
|
(fwinfo->version >> 16) & 0xff,
|
||||||
|
(fwinfo->version >> 8) & 0xff,
|
||||||
|
(fwinfo->version) & 0xff,
|
||||||
|
fwinfo->svn_version);
|
||||||
|
printf(" size:%d\r\n", fwinfo->tot_len);
|
||||||
|
return fwdata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("invalid firmware\r\n");
|
||||||
|
} else {
|
||||||
|
printf("open file %s fail\r\n", path);
|
||||||
|
}
|
||||||
|
if (fwdata) {
|
||||||
|
free(fwdata);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_ota_device(char *addr, char *fw)
|
||||||
|
{
|
||||||
|
uint8 mac[6];
|
||||||
|
uint32 ota_off = 0;
|
||||||
|
uint8 *fwdata = NULL;
|
||||||
|
uint32 rx_len = 0;
|
||||||
|
uint32 err = 0;
|
||||||
|
int32 retry = 0;
|
||||||
|
struct hgota_fw_info fwinfo;
|
||||||
|
struct hgota_sta *sta = NULL;
|
||||||
|
|
||||||
|
printf("ota sta %s, fw:%s\r\n", addr, fw);
|
||||||
|
memset(&fwinfo, 0, sizeof(fwinfo));
|
||||||
|
if (6 == sscanf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5)) {
|
||||||
|
sta = hgic_get_device(mac);
|
||||||
|
fwdata = hgic_read_firmware(fw, &fwinfo);
|
||||||
|
if (fwdata) {
|
||||||
|
if(sta && sta->svn_version == fwinfo.svn_version){
|
||||||
|
printf("same version, do not OTA\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (ota_off < fwinfo.tot_len && retry < 10) {
|
||||||
|
libota_send_fw_data(mac, &fwinfo, ota_off, fwdata + ota_off,
|
||||||
|
(fwinfo.tot_len - ota_off) > 1460 ? 1460 : (fwinfo.tot_len - ota_off));
|
||||||
|
rx_len = hgic_sock_recv(500);
|
||||||
|
if (rx_len > 0 && (libota_rx_proc(hgOTA.rxbuf, rx_len) == HGOTA_STATUS_FW_STATUS)) {
|
||||||
|
retry = 0;
|
||||||
|
} else {
|
||||||
|
retry++;
|
||||||
|
}
|
||||||
|
ota_off = libota_sta_nexoff(mac);
|
||||||
|
printf("OTA: %d%%\r", (ota_off * 100) / fwinfo.tot_len);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
free(fwdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
if (fwinfo.tot_len > 0) {
|
||||||
|
printf("OTA Exit: %d%% upgraded\r\n", (ota_off * 100) / fwinfo.tot_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_get_config(char *addr)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
char mac[6];
|
||||||
|
uint32 rx_len = 0;
|
||||||
|
struct eth_ota_fwparam param;
|
||||||
|
|
||||||
|
if (6 == sscanf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5)) {
|
||||||
|
libota_query_config(mac);
|
||||||
|
rx_len = hgic_sock_recv(500);
|
||||||
|
if (rx_len > 0) {
|
||||||
|
if (HGOTA_STATUS_CONFIG_GOT == libota_rx_proc(hgOTA.rxbuf, rx_len)) {
|
||||||
|
libota_sta_config(mac, ¶m);
|
||||||
|
printf("BSS BW :%d\r\n", param.bss_bw);
|
||||||
|
printf("TX MCS :%d\r\n", param.tx_mcs);
|
||||||
|
printf("ENCRYPT:%d\r\n", param.encrypt);
|
||||||
|
printf("FORWARD:%d\r\n", param.forward);
|
||||||
|
printf("SSID :%s\r\n", param.ssid);
|
||||||
|
printf("KEY_SET:%d\r\n", param.key_set);
|
||||||
|
printf("MACST_KEY_SET:%d\r\n", param.mkey_set);
|
||||||
|
printf("FREQ RANGE:%d - %d\r\n", param.freq_start, param.freq_end);
|
||||||
|
printf("CHAN LIST:");
|
||||||
|
for (i = 0; i < param.chan_cnt; i++) {
|
||||||
|
if (param.chan_list[0]) { printf("%d ", param.chan_list[0]); }
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *ifname;
|
||||||
|
char *cmd;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("invalid params\r\n hgota ifname cmd [args]\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ifname = argv[1];
|
||||||
|
cmd = argv[2];
|
||||||
|
|
||||||
|
libota_init(raw_sock_send);
|
||||||
|
hgic_read_device();
|
||||||
|
|
||||||
|
if (!hgic_sock_init(ifname)) {
|
||||||
|
printf("create socket fail\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(cmd, "SCAN") == 0) {
|
||||||
|
hgic_scan_device();
|
||||||
|
} else if (strcmp(cmd, "REBOOT") == 0) {
|
||||||
|
if (argc == 3 + 1) {
|
||||||
|
hgic_reboot_device(argv[3]);
|
||||||
|
}
|
||||||
|
} else if (strcmp(cmd, "LDDEF") == 0) {
|
||||||
|
if (argc == 3 + 1) {
|
||||||
|
hgic_loaddef_device(argv[3]);
|
||||||
|
}
|
||||||
|
} else if (strcmp(cmd, "OTA") == 0) {
|
||||||
|
if (argc == 3 + 2) {
|
||||||
|
hgic_ota_device(argv[3], argv[4]);
|
||||||
|
}
|
||||||
|
} else if (strcmp(cmd, "GETCFG") == 0) {
|
||||||
|
if (argc == 3 + 1) {
|
||||||
|
hgic_get_config(argv[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(hgOTA.sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
251
hgota/libota.c
Normal file
251
hgota/libota.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "libota.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct libota LIBOTA;
|
||||||
|
|
||||||
|
static uint16 libota_check_sum(int8 *addr, int32 count)
|
||||||
|
{
|
||||||
|
int32 sum = 0;
|
||||||
|
while (count > 1) {
|
||||||
|
sum = sum + *(uint16 *)addr;
|
||||||
|
addr += 2;
|
||||||
|
count -= 2;
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
sum += *addr;
|
||||||
|
}
|
||||||
|
while (sum >> 16) {
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
}
|
||||||
|
return (uint16)~sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hgota_sta *libota_new_sta(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < OTA_STA_COUNT; i++) {
|
||||||
|
if (!LIBOTA.stas[i].online) {
|
||||||
|
return &LIBOTA.stas[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hgota_sta *libota_find_sta(char *mac)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (mac == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < OTA_STA_COUNT; i++) {
|
||||||
|
if (memcmp(LIBOTA.stas[i].addr, mac, 6) == 0) {
|
||||||
|
return &LIBOTA.stas[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int libota_add_sta(struct eth_ota_scan_report *report)
|
||||||
|
{
|
||||||
|
struct hgota_sta *sta = libota_find_sta(report->hdr.src);
|
||||||
|
if (sta) {
|
||||||
|
sta->chipid = ntohs(report->chipid);
|
||||||
|
sta->version = ntohl(report->version);
|
||||||
|
sta->svn_version = ntohl(report->svn_version);
|
||||||
|
sta->online = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sta = libota_new_sta();
|
||||||
|
if (sta) {
|
||||||
|
memset(sta, 0, sizeof(struct hgota_sta));
|
||||||
|
sta->chipid = ntohs(report->chipid);
|
||||||
|
sta->version = ntohl(report->version);
|
||||||
|
sta->svn_version = ntohl(report->svn_version);
|
||||||
|
sta->online = 1;
|
||||||
|
memcpy(sta->addr, report->hdr.src, 6);
|
||||||
|
LIBOTA.sta_count++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libota_clear_sta(void)
|
||||||
|
{
|
||||||
|
LIBOTA.sta_count = 0;
|
||||||
|
memset(LIBOTA.stas, 0, sizeof(LIBOTA.stas));
|
||||||
|
}
|
||||||
|
|
||||||
|
void libota_clear_sta_nexoff(char *sta_mac)
|
||||||
|
{
|
||||||
|
struct hgota_sta *sta = libota_find_sta(sta_mac);
|
||||||
|
if (sta != NULL) {
|
||||||
|
sta->next_off = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_sta_nexoff(char *sta_mac)
|
||||||
|
{
|
||||||
|
struct hgota_sta *sta = libota_find_sta(sta_mac);
|
||||||
|
return sta ? sta->next_off : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_reboot(char *sta_mac, int flags)
|
||||||
|
{
|
||||||
|
struct eth_ota_reboot reboot;
|
||||||
|
|
||||||
|
if (sta_mac) {
|
||||||
|
memset(&reboot, 0, sizeof(reboot));
|
||||||
|
memcpy(reboot.hdr.dest, sta_mac, 6);
|
||||||
|
reboot.hdr.proto = htons(ETH_P_OTA);
|
||||||
|
reboot.hdr.stype = ETH_P_OTA_REBOOT;
|
||||||
|
reboot.flags = flags;
|
||||||
|
return LIBOTA.send(&reboot, sizeof(reboot));
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_scan(int clear)
|
||||||
|
{
|
||||||
|
struct eth_ota_hdr scan;
|
||||||
|
|
||||||
|
if (clear) {
|
||||||
|
libota_clear_sta();
|
||||||
|
}
|
||||||
|
memset(&scan, 0, sizeof(scan));
|
||||||
|
memset(scan.dest, 0xff, 6);
|
||||||
|
scan.proto = htons(ETH_P_OTA);
|
||||||
|
scan.stype = ETH_P_OTA_SCAN;
|
||||||
|
return LIBOTA.send(&scan, sizeof(scan));
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_send_fw_data(char *sta_mac, struct hgota_fw_info *info, int off, char *data, int len)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct eth_ota_fw_data *fw = NULL;
|
||||||
|
struct hgota_sta *sta = libota_find_sta(sta_mac);
|
||||||
|
|
||||||
|
if ((data == NULL) || (sta_mac == NULL) || (info == NULL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta) { sta->next_off = 0; }
|
||||||
|
fw = malloc(sizeof(struct eth_ota_fw_data) + len);
|
||||||
|
if (fw) {
|
||||||
|
memcpy(fw->hdr.dest, sta ? sta->addr : sta_mac, 6);
|
||||||
|
fw->hdr.proto = htons(ETH_P_OTA);
|
||||||
|
fw->hdr.stype = ETH_P_OTA_FW_DATA;
|
||||||
|
fw->hdr.status = 0;
|
||||||
|
fw->version = htonl(info->version);
|
||||||
|
fw->tot_len = htonl(info->tot_len);
|
||||||
|
fw->off = htonl(off);
|
||||||
|
fw->len = htons(len);
|
||||||
|
fw->chipid = htons(info->chipid);
|
||||||
|
fw->checksum = htons(libota_check_sum(data, len));
|
||||||
|
memcpy(fw->data, data, len);
|
||||||
|
ret = LIBOTA.send(fw, sizeof(struct eth_ota_fw_data) + len);
|
||||||
|
free(fw);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_query_config(char *sta_mac)
|
||||||
|
{
|
||||||
|
struct eth_ota_hdr req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
memset(req.dest, 0xff, 6);
|
||||||
|
req.proto = htons(ETH_P_OTA);
|
||||||
|
req.stype = ETH_P_OTA_FW_GET_PARAM;
|
||||||
|
return LIBOTA.send(&req, sizeof(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_update_config(char *sta_mac, struct eth_ota_fwparam *param)
|
||||||
|
{
|
||||||
|
uint16 checksum = 0;
|
||||||
|
int data_len = sizeof(struct eth_ota_fwparam);
|
||||||
|
struct eth_ota_fwparam_hdr req;
|
||||||
|
|
||||||
|
checksum = libota_check_sum((unsigned char *)param, data_len);
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
memcpy(req.hdr.dest, sta_mac, 6);
|
||||||
|
req.hdr.proto = htons(ETH_P_OTA);
|
||||||
|
req.hdr.stype = ETH_P_OTA_FW_SET_PARAM;
|
||||||
|
req.hdr.status = 0;
|
||||||
|
req.len = htons(data_len);
|
||||||
|
req.checksum = htons(checksum);
|
||||||
|
memcpy(&req.param, param, data_len);
|
||||||
|
return LIBOTA.send(&req, sizeof(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_sta_config(char *sta_mac, struct eth_ota_fwparam *param)
|
||||||
|
{
|
||||||
|
struct hgota_sta *sta = libota_find_sta(sta_mac);
|
||||||
|
if (sta) {
|
||||||
|
memcpy(param, &sta->param, sizeof(struct eth_ota_fwparam));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_rx_proc(char *buff, int len)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint16 checksum = 0;
|
||||||
|
struct hgota_sta *sta = NULL;
|
||||||
|
struct eth_ota_hdr *hdr = buff;
|
||||||
|
struct eth_ota_fw_data *data = buff;
|
||||||
|
struct eth_ota_fwparam_hdr *param = buff;
|
||||||
|
|
||||||
|
if (buff == NULL || len <= 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta = libota_find_sta(hdr->src);
|
||||||
|
if (ETH_P_OTA == ntohs(hdr->proto)) {
|
||||||
|
switch (hdr->stype) {
|
||||||
|
case ETH_P_OTA_SCAN_REPORT:
|
||||||
|
//printf("scan resp\r\n");
|
||||||
|
if (libota_add_sta((struct eth_ota_scan_report *)buff)) {
|
||||||
|
ret = HGOTA_STATUS_NEW_STA;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ETH_P_OTA_FW_DATA_RESPONE:
|
||||||
|
//printf("fw data resp\r\n");
|
||||||
|
if (sta && data->hdr.status != 0xff) {
|
||||||
|
sta->next_off = ntohl(data->off) + ntohs(data->len);
|
||||||
|
}
|
||||||
|
ret = HGOTA_STATUS_FW_STATUS;
|
||||||
|
break;
|
||||||
|
case ETH_P_OTA_FW_GET_PARAM_RESP:
|
||||||
|
checksum = libota_check_sum(¶m->param, sizeof(struct eth_ota_fwparam));
|
||||||
|
//printf("get param, sta:"MACSTR", checksum:%x,%x\r\n", MAC2STR(hdr->src), checksum, ntohs(param->checksum));
|
||||||
|
if (ntohs(param->checksum) == checksum && sta) {
|
||||||
|
memcpy(&sta->param, ¶m->param, sizeof(struct eth_ota_fwparam));
|
||||||
|
ret = HGOTA_STATUS_CONFIG_GOT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ETH_P_OTA_FW_SET_PARAM_RESP:
|
||||||
|
//printf("set param resp\r\n");
|
||||||
|
if (sta && hdr->status != 0xff) {
|
||||||
|
ret = HGOTA_STATUS_CONFIG_UPDATED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libota_init(raw_send_hdl send)
|
||||||
|
{
|
||||||
|
memset(&LIBOTA, 0, sizeof(struct libota));
|
||||||
|
LIBOTA.send = send;
|
||||||
|
}
|
||||||
|
|
156
hgota/libota.h
Normal file
156
hgota/libota.h
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
#ifndef _HGOTA_H_
|
||||||
|
#define _HGOTA_H_
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef char s8;
|
||||||
|
typedef char int8;
|
||||||
|
typedef short s16;
|
||||||
|
typedef short int16;
|
||||||
|
typedef int s32;
|
||||||
|
typedef int int32;
|
||||||
|
typedef long long s64;
|
||||||
|
typedef long long int64;
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
|
||||||
|
#define OTA_STA_COUNT (32)
|
||||||
|
#define ETH_P_OTA 0x4847
|
||||||
|
#define IS_ETH_OTA(p) ((p)==0x4748)
|
||||||
|
|
||||||
|
#ifndef MAC2STR
|
||||||
|
#define MAC2STR(a) (a)[0]&0xff, (a)[1]&0xff, (a)[2]&0xff, (a)[3]&0xff, (a)[4]&0xff, (a)[5]&0xff
|
||||||
|
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum ETH_P_OTA_STYPE {
|
||||||
|
ETH_P_OTA_REBOOT = 1,
|
||||||
|
ETH_P_OTA_SCAN,
|
||||||
|
ETH_P_OTA_SCAN_REPORT,
|
||||||
|
ETH_P_OTA_FW_DATA,
|
||||||
|
ETH_P_OTA_FW_DATA_RESPONE,
|
||||||
|
ETH_P_OTA_FW_GET_PARAM,
|
||||||
|
ETH_P_OTA_FW_GET_PARAM_RESP,
|
||||||
|
ETH_P_OTA_FW_SET_PARAM,
|
||||||
|
ETH_P_OTA_FW_SET_PARAM_RESP,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HGIC_OTA_RESP_ERR_CODE{
|
||||||
|
HGIC_OTA_RESP_ERR_OK=0,
|
||||||
|
HGIC_OTA_RESP_ERR_CHECKSUM,
|
||||||
|
HGIC_OTA_RESP_ERR_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (*raw_send_hdl)(char *data, int len);
|
||||||
|
|
||||||
|
struct eth_ota_hdr {
|
||||||
|
uint8 dest[6];
|
||||||
|
uint8 src[6];
|
||||||
|
uint16 proto;
|
||||||
|
uint8 stype, status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eth_ota_scan_report {
|
||||||
|
struct eth_ota_hdr hdr;
|
||||||
|
uint32 version;
|
||||||
|
uint16 chipid;
|
||||||
|
uint8 mode, rev;
|
||||||
|
uint32 svn_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eth_ota_fw_data {
|
||||||
|
struct eth_ota_hdr hdr;
|
||||||
|
uint32 version;
|
||||||
|
uint32 off, tot_len;
|
||||||
|
uint16 len, checksum;
|
||||||
|
uint16 chipid;
|
||||||
|
uint8 data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgota_fw_info {
|
||||||
|
u16 chipid;
|
||||||
|
u32 version;
|
||||||
|
u32 svn_version;
|
||||||
|
u32 tot_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eth_ota_fwparam{
|
||||||
|
uint8 bss_bw;
|
||||||
|
uint8 encrypt: 1,
|
||||||
|
forward: 1,
|
||||||
|
key_set: 1,
|
||||||
|
mkey_set: 1;
|
||||||
|
uint8 chan_cnt;
|
||||||
|
uint16 freq_start, freq_end;
|
||||||
|
uint16 chan_list[16];
|
||||||
|
uint8 ssid[32+2];
|
||||||
|
uint8 key[32];
|
||||||
|
uint8 mcast_key[32];
|
||||||
|
uint8 tx_mcs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eth_ota_fwparam_hdr{
|
||||||
|
struct eth_ota_hdr hdr;
|
||||||
|
uint16 len, checksum;
|
||||||
|
struct eth_ota_fwparam param;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BIT(a) ((u16)1 << (a))
|
||||||
|
enum ETH_P_REBOOT_FLAGS {
|
||||||
|
ETH_P_REBOOT_FLAGS_LOADDEF = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eth_ota_reboot {
|
||||||
|
struct eth_ota_hdr hdr;
|
||||||
|
uint32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgota_sta {
|
||||||
|
char addr[6];
|
||||||
|
int chipid;
|
||||||
|
int version;
|
||||||
|
int svn_version;
|
||||||
|
int online;
|
||||||
|
int next_off;
|
||||||
|
struct eth_ota_fwparam param;
|
||||||
|
};
|
||||||
|
struct libota {
|
||||||
|
struct hgota_sta stas[OTA_STA_COUNT];
|
||||||
|
int sta_count;
|
||||||
|
raw_send_hdl send;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum{
|
||||||
|
HGOTA_STATUS_NEW_STA = 0x1,
|
||||||
|
HGOTA_STATUS_FW_STATUS,
|
||||||
|
HGOTA_STATUS_CONFIG_GOT,
|
||||||
|
HGOTA_STATUS_CONFIG_UPDATED,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct libota LIBOTA;
|
||||||
|
|
||||||
|
void libota_clear_sta_nexoff(char *sta_mac);
|
||||||
|
|
||||||
|
int libota_sta_nexoff(char *sta_mac);
|
||||||
|
|
||||||
|
int libota_reboot(char *sta_mac, int flags);
|
||||||
|
|
||||||
|
int libota_scan(int clear);
|
||||||
|
|
||||||
|
int libota_send_fw_data(char *sta_mac, struct hgota_fw_info *info, int off, char *data, int len);
|
||||||
|
|
||||||
|
int libota_rx_proc(char *buff, int len);
|
||||||
|
|
||||||
|
int libota_init(raw_send_hdl send);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
2
hgtest
Executable file
2
hgtest
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
echo $1 > /proc/hgic/testmode;cat /proc/hgic/testmode
|
2
iwpriv
Executable file
2
iwpriv
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
echo $* > /proc/hgic/iwpriv;cat /proc/hgic/iwpriv
|
34
readme.txt
Normal file
34
readme.txt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
编译fmac驱动:
|
||||||
|
1.修改Makefile: 修改编译器相关设置。
|
||||||
|
例如 mtk 编译环境下:
|
||||||
|
#MTK SDK
|
||||||
|
ARCH := mips
|
||||||
|
COMPILER := /opt/buildroot-gcc463/usr/bin/mipsel-linux-
|
||||||
|
LINUX_KERNEL_PATH := /home/dongyun/work/disk4/RT288x_AHv1.2/source/linux-3.10.14.x
|
||||||
|
|
||||||
|
2. 执行: make fmac
|
||||||
|
|
||||||
|
|
||||||
|
常见编译错误处理:
|
||||||
|
1. error implicit declaration of function 'PDE_DATA'
|
||||||
|
该编译错误是由于Linux kernel版本差异,proc fs 缺失了 PDE_DATA 小函数。
|
||||||
|
遇到此error,请打开 hgic_fmac/procfs.f 文件,查看下面这段代码,如果 LINUX_VERSION_CODE 不满足条件,则修改一下version code判断条件。
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
|
||||||
|
static inline struct proc_dir_entry *PDE(const struct inode *inode)
|
||||||
|
{
|
||||||
|
return PROC_I(inode)->pde;
|
||||||
|
}
|
||||||
|
static inline void *PDE_DATA(const struct inode *inode)
|
||||||
|
{
|
||||||
|
return PDE(inode)->data;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hgicf.conf : fmac驱动参数文件(ap模式)
|
||||||
|
fmac.sh : fmac驱动启动脚本。
|
||||||
|
hgtest : 测试模式tool,用于发送测试模式命令。
|
||||||
|
iwpriv : 泰芯专用的iwpriv工具。原系统如果没有iwpriv命令,则可以使用此工具。
|
5
utils/Makefile
Normal file
5
utils/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
obj-m += hgic_usb.o
|
||||||
|
obj-m += hgic_sdio.o
|
||||||
|
|
||||||
|
hgic_usb-objs += if_usb.o
|
||||||
|
hgic_sdio-objs += if_sdio.o
|
218
utils/ah_freqinfo.c
Normal file
218
utils/ah_freqinfo.c
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file ah_freqinfo.c
|
||||||
|
* @author HUGE-IC Application Team
|
||||||
|
* @version V1.0.0
|
||||||
|
* @date 2021-06-23
|
||||||
|
* @brief IEEE802.11 AH Frequency defines
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* <h2><center>© COPYRIGHT 2021 HUGE-IC</center></h2>
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
struct ieee80211_ah_freqinfo {
|
||||||
|
uint8 s1g_opclass, type, max_txpower, rev;
|
||||||
|
uint16 freqlist[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct ieee80211_ah_freqinfo ah_freqs[] = {
|
||||||
|
{1, 1, 30, 0, { 9020+5*1, 9020+5*3, 9020+5*37, 9020+5*39, 9020+5*41, 9020+5*43,
|
||||||
|
9020+5*45, 9020+5*47, 9020+5*49, 9020+5*51}}, /*U.S., 1M, type1*/
|
||||||
|
{1, 2, 30, 0, { 9020+5*5, 9020+5*7, 9020+5*9, 9020+5*11, 9020+5*13, 9020+5*15,
|
||||||
|
9020+5*17, 9020+5*19, 9020+5*21, 9020+5*23, 9020+5*25, 9020+5*27,
|
||||||
|
9020+5*29, 9020+5*31, 9020+5*33, 9020+5*35}}, /*U.S., 1M, type2*/
|
||||||
|
{2, 1, 30, 0, { 9020+5*2, 9020+5*38, 9020+5*42, 9020+5*46, 9020+5*50}}, /*U.S., 2M, type1*/
|
||||||
|
{2, 2, 30, 0, { 9020+5*6, 9020+5*10, 9020+5*14, 9020+5*18, 9020+5*22, 9020+5*26, 9020+5*30, 9020+5*34}}, /*U.S., 2M, type2*/
|
||||||
|
{3, 1, 30, 0, { 9020+5*40, 9020+5*48}}, /*U.S., 4M, type1*/
|
||||||
|
{3, 2, 30, 0, { 9020+5*8, 9020+5*16, 9020+5*24, 9020+5*32}}, /*U.S., 4M, type2*/
|
||||||
|
{4, 1, 30, 0, { 9020+5*44}}, /*U.S., 8M, type1*/
|
||||||
|
{4, 2, 30, 0, { 9020+5*12, 9020+5*28}}, /*U.S., 8M, type2*/
|
||||||
|
{5, 2, 30, 0, { 9020+5*20}}, /*U.S., 16M, type2*/
|
||||||
|
|
||||||
|
{6, 1, 14, 0, { 8630+5*1, 8630+5*3, 8630+5*5, 8630+5*7, 8630+5*9}}, /*Europe, 1M, type1*/
|
||||||
|
{7, 1, 14, 0, { 8630+5*2, 8630+5*6}}, /*Europe, 2M, type1*/
|
||||||
|
|
||||||
|
{8, 1, 23, 0, { 9165+5*1, 9165+5*3, 9165+5*5, 9165+5*7, 9165+5*9, 9165+5*11,
|
||||||
|
9165+5*13, 9165+5*15, 9165+5*17, 9165+5*19, 9165+5*21}}, /*Japan, 1M, type1*/
|
||||||
|
|
||||||
|
{9, 1, 10, 0, { 7550+5*1, 7550+5*3, 7550+5*5, 7550+5*7, 7550+5*9,
|
||||||
|
7550+5*11, 7550+5*13, 7550+5*15, 7550+5*17, 7550+5*19,
|
||||||
|
7550+5*21, 7550+5*23, 7550+5*25, 7550+5*27,
|
||||||
|
7550+5*29, 7550+5*31}}, /*China, 1M, type1*/
|
||||||
|
/*{10, 1, 10, 0, { 7790+5*1, 7790+5*3, 7790+5*5, 7790+5*7, 7790+5*9,
|
||||||
|
7790+5*11, 7790+5*13, 7790+5*15}},*/ /*China, 1M, type1*/
|
||||||
|
{11, 2, 10, 0, { 7790+5*2, 7790+5*6, 7790+5*10, 7790+5*14}}, /*China, 2M, type2*/
|
||||||
|
{12, 2, 10, 0, { 7790+5*4, 7790+5*12}}, /*China, 4M, type2*/
|
||||||
|
{13, 2, 10, 0, { 7790+5*8}}, /*China, 8M, type2*/
|
||||||
|
|
||||||
|
{14, 1, 10, 0, { 9175+5*1, 9175+5*3, 9175+5*5, 9175+5*7, 9175+5*9, 9175+5*11}}, /*Korea, 1M, type1*/
|
||||||
|
{15, 1, 10, 0, { 9175+5*2, 9175+5*6, 9175+5*10}}, /*Korea, 2M, type1*/
|
||||||
|
{16, 1, 10, 0, { 9175+5*8}}, /*Korea, 4M, type1*/
|
||||||
|
|
||||||
|
{17, 1, 26, 0, { 8630+5*7, 8630+5*9, 8630+5*11, 9020+5*37, 9020+5*39, 9020+5*41, 9020+5*43, 9020+5*45}}, /*Singapore, 1M, type1*/
|
||||||
|
{19, 1, 26, 0, { 8630+5*10, 9020+5*38, 9020+5*42}}, /*Singapore, 2M, type1*/
|
||||||
|
{21, 1, 26, 0, { 9020+5*40}}, /*Singapore, 4M, type1*/
|
||||||
|
|
||||||
|
{22, 1, 30, 0, { 9020+5*27, 9020+5*29, 9020+5*31, 9020+5*33, 9020+5*35}}, /*Australia, 1M, type1*/
|
||||||
|
{22, 2, 30, 0, { 9020+5*37, 9020+5*39, 9020+5*41, 9020+5*43, 9020+5*45, 9020+5*47, 9020+5*49, 9020+5*51}}, /*Australia, 1M, type2*/
|
||||||
|
{23, 1, 30, 0, { 9020+5*28, 9020+5*32}}, /*Australia, 2M, type1*/
|
||||||
|
{23, 2, 30, 0, { 9020+5*38, 9020+5*42, 9020+5*46, 9020+5*50}}, /*Australia, 2M, type2*/
|
||||||
|
{24, 1, 30, 0, { 9020+5*30}}, /*Australia, 4M, type1*/
|
||||||
|
{24, 2, 30, 0, { 9020+5*40, 9020+5*48}}, /*Australia, 4M, type2*/
|
||||||
|
{25, 2, 30, 0, { 9020+5*44}}, /*Australia, 8M, type2*/
|
||||||
|
|
||||||
|
{26, 1, 36, 0, { 9020+5*27, 9020+5*29, 9020+5*31, 9020+5*33, 9020+5*35, 9020+5*37, 9020+5*39, 9020+5*41, 9020+5*43}}, /*New Zealand, 1M, type1*/
|
||||||
|
{26, 2, 36, 0, { 9020+5*45, 9020+5*47, 9020+5*49, 9020+5*51}}, /*New Zealand, 1M, type2*/
|
||||||
|
{27, 1, 36, 0, { 9020+5*28, 9020+5*32, 9020+5*36, 9020+5*40}}, /*New Zealand, 2M, type1*/
|
||||||
|
{27, 2, 36, 0, { 9020+5*46, 9020+5*50}}, /*New Zealand, 2M, type2*/
|
||||||
|
{28, 1, 36, 0, { 9020+5*30, 9020+5*38}}, /*New Zealand, 4M, type1*/
|
||||||
|
{28, 2, 36, 0, { 9020+5*48}}, /*New Zealand, 4M, type2*/
|
||||||
|
{29, 1, 36, 0, { 9020+5*34}}, /*New Zealand, 8M, type1*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee80211_ah_freqinfo *hgic_get_ah_freqinfo(char *country_code, char bw, char type)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
uint8 s1g_opclass = 0;
|
||||||
|
|
||||||
|
if(country_code == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (strcmp(country_code, "US") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 1; break;
|
||||||
|
case 2: s1g_opclass = 2; break;
|
||||||
|
case 4: s1g_opclass = 3; break;
|
||||||
|
case 8: s1g_opclass = 4; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "EU") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 6; break;
|
||||||
|
case 2: s1g_opclass = 7; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "JP") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 8; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "CN") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 9; break;
|
||||||
|
case 2: s1g_opclass = 11; break;
|
||||||
|
case 4: s1g_opclass = 12; break;
|
||||||
|
case 8: s1g_opclass = 13; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "KR") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 14; break;
|
||||||
|
case 2: s1g_opclass = 15; break;
|
||||||
|
case 4: s1g_opclass = 16; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "SG") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 17; break;
|
||||||
|
case 2: s1g_opclass = 19; break;
|
||||||
|
case 4: s1g_opclass = 21; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "AZ") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 22; break;
|
||||||
|
case 2: s1g_opclass = 23; break;
|
||||||
|
case 4: s1g_opclass = 24; break;
|
||||||
|
case 8: s1g_opclass = 25; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
} else if (strcmp(country_code, "NZ") == 0) {
|
||||||
|
switch (bw) {
|
||||||
|
case 1: s1g_opclass = 26; break;
|
||||||
|
case 2: s1g_opclass = 27; break;
|
||||||
|
case 4: s1g_opclass = 28; break;
|
||||||
|
case 8: s1g_opclass = 29; break;
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; s1g_opclass && i < ARRAYSIZE(ah_freqs); i++) {
|
||||||
|
if (ah_freqs[i].s1g_opclass == s1g_opclass && ah_freqs[i].type == type){
|
||||||
|
return &ah_freqs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__ /*for linux*/
|
||||||
|
void hgic_ah_set_country_region(char *country_code, char bw, char type)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
char *ptr = NULL;
|
||||||
|
char cmd[128];
|
||||||
|
struct ieee80211_ah_freqinfo *freqinfo = NULL;
|
||||||
|
|
||||||
|
freqinfo = hgic_get_ah_freqinfo(country_code, bw, type);
|
||||||
|
if (freqinfo == NULL) {
|
||||||
|
printf("invalid country region: %s, bw:%d, type:%d", country_code, bw, type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set freq list*/
|
||||||
|
ptr = cmd;
|
||||||
|
memset(cmd, 0, sizeof(cmd));
|
||||||
|
strcpy(ptr, "iwpriv hg0 set chan_list=");
|
||||||
|
ptr += strlen(ptr);
|
||||||
|
for (i = 0; i < 16 && freqinfo->freqlist[i]; i++) {
|
||||||
|
sprintf(ptr, "%d,", freqinfo->freqlist[i]);
|
||||||
|
ptr += strlen(ptr);
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
*(ptr--) = 0;
|
||||||
|
system(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set bw*/
|
||||||
|
memset(cmd, 0, sizeof(cmd));
|
||||||
|
sprintf(cmd, "iwpriv hg0 set bss_bw=%d", bw);
|
||||||
|
system(cmd);
|
||||||
|
|
||||||
|
/*set tx power*/
|
||||||
|
memset(cmd, 0, sizeof(cmd));
|
||||||
|
sprintf(cmd, "iwpriv hg0 set txpower=%d", freqinfo->max_txpower);
|
||||||
|
system(cmd);
|
||||||
|
}
|
||||||
|
#else /*for rtos*/
|
||||||
|
void hgic_ah_set_country_region(char *country_code, char bw, char type)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
struct ieee80211_ah_freqinfo *freqinfo = NULL;
|
||||||
|
|
||||||
|
freqinfo = hgic_get_ah_freqinfo(country_code, bw, type);
|
||||||
|
if (freqinfo == NULL) {
|
||||||
|
printf("invalid country region: %s, bw:%d, type:%d", country_code, bw, type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set freq list*/
|
||||||
|
while (i < 16 && freqinfo->freqlist[i]) i++;
|
||||||
|
if (i > 0) {
|
||||||
|
hgicf_cmd("w0", HGIC_CMD_SET_CHAN_LIST, (unsigned int)&freqinfo->freqlist, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*set bw*/
|
||||||
|
hgicf_cmd("w0", HGIC_CMD_SET_BSS_BW, bw, 0);
|
||||||
|
|
||||||
|
/*set max power*/
|
||||||
|
hgicf_cmd("w0", HGIC_CMD_SET_TX_POWER, freqinfo->max_txpower, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
1159
utils/fwctrl.c
Normal file
1159
utils/fwctrl.c
Normal file
File diff suppressed because it is too large
Load diff
196
utils/fwctrl.h
Normal file
196
utils/fwctrl.h
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
|
||||||
|
#ifndef _HGIC_FWCTRL_H_
|
||||||
|
#define _HGIC_FWCTRL_H_
|
||||||
|
|
||||||
|
struct hgic_fw_info;
|
||||||
|
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
|
//command response
|
||||||
|
struct hgic_cmd_response {
|
||||||
|
struct list_head list;
|
||||||
|
unsigned short cookie;
|
||||||
|
struct completion cmpl;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fwctrl_params {
|
||||||
|
u8 *country_code;
|
||||||
|
u8 *ssid;
|
||||||
|
u8 *bssid;
|
||||||
|
u8 *bssid_filter;
|
||||||
|
u8 *key_mgmt;
|
||||||
|
u8 *wpa_psk;
|
||||||
|
u8 *mcast_key;
|
||||||
|
u8 *mode;
|
||||||
|
u8 *mac_addr;
|
||||||
|
u8 *paired_stas;
|
||||||
|
u8 *chan_list;
|
||||||
|
u8 channel, chan_bw, bss_bw, tx_mcs, tx_bw;
|
||||||
|
u16 rts_threshold, frag_threshold;
|
||||||
|
u16 freq_start, freq_end;
|
||||||
|
u16 listen_interval;
|
||||||
|
u16 center_freq;
|
||||||
|
u16 beacon_int;
|
||||||
|
u16 ethertype;
|
||||||
|
u8 acs: 2, acs_tmo: 6;
|
||||||
|
u8 chan_cnt, txpower, primary_chan, agg_cnt;
|
||||||
|
u8 ps_mode, wkio_mode, ps_connect, ps_connect_roundup;
|
||||||
|
u32 dtim_period, bss_max_idle;
|
||||||
|
u16 aplost_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fwctrl {
|
||||||
|
struct device *dev;
|
||||||
|
u16 cookie;
|
||||||
|
spinlock_t lock; /*ctrl packet pending lock*/
|
||||||
|
struct list_head pd_list; /*ctrl packet pending queue (for sync cmd)*/
|
||||||
|
struct sk_buff_head rxq; /*fw ctrl packet rx queue*/
|
||||||
|
struct sk_buff_head txq; /*fw ctrl packet tx queue*/
|
||||||
|
struct work_struct work; /*fw ctrl rx packet process work*/
|
||||||
|
struct workqueue_struct *wq;
|
||||||
|
struct hgic_fwctrl_params param;
|
||||||
|
struct work_struct flush_work;
|
||||||
|
u8 qc_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
int hgic_fwctrl_set_byte(struct hgic_fwctrl *ctrl, int cmd_id, u8 val);
|
||||||
|
int hgic_fwctrl_set_int_val(struct hgic_fwctrl *ctrl, int cmd_id, int val);
|
||||||
|
int hgic_fwctrl_get_int_val(struct hgic_fwctrl *ctrl, int cmd_id);
|
||||||
|
int hgic_fwctrl_get_bytes(struct hgic_fwctrl *ctrl, int cmd_id, char *buff, int len);
|
||||||
|
int hgic_fwctrl_do_cmd(struct hgic_fwctrl *ctrl, int cmd_id, char *data, int len, char *buff, int size);
|
||||||
|
int hgic_fwctrl_rx_proc(struct hgic_fwctrl *ctrl, struct sk_buff *skb);
|
||||||
|
struct sk_buff *hgic_fwctrl_send_data(struct hgic_fwctrl *ctrl, struct sk_buff *skb, struct hgic_cmd_response *resp, u32 timeout);
|
||||||
|
void hgic_fwctrl_clear_pdlist(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_bytes(struct hgic_fwctrl *ctrl, int cmd_id, char *data, int len);
|
||||||
|
*/
|
||||||
|
u16 hgic_ctrl_cookie(struct hgic_fwctrl *ctrl);
|
||||||
|
struct sk_buff *hgic_fwctrl_send_data(struct hgic_fwctrl *ctrl, struct sk_buff *skb, struct hgic_cmd_response *resp, u32 timeout);
|
||||||
|
|
||||||
|
void hgic_fwctrl_init(struct hgic_fwctrl *ctrl, void *dev);
|
||||||
|
void hgic_fwctrl_release(struct hgic_fwctrl *ctrl);
|
||||||
|
void hgic_fwctrl_rx(struct hgic_fwctrl *ctrl, struct sk_buff *skb);
|
||||||
|
void hgic_rx_fw_event(struct hgic_fwctrl *ctrl, struct sk_buff *skb);
|
||||||
|
void hgic_schedule(struct hgic_fwctrl *ctrl);
|
||||||
|
void hgic_fwctrl_flush_param(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_testmode_cmd(struct hgic_fwctrl *ctrl, u8 *cmd, u32 size);
|
||||||
|
int hgic_fwctrl_get_status(struct hgic_fwctrl *ctrl, u8 *buff, u32 len);
|
||||||
|
int hgic_fwctrl_get_conn_state(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_get_fwinfo(struct hgic_fwctrl *ctrl, struct hgic_fw_info *info);
|
||||||
|
int hgic_fwctrl_set_countryregion(struct hgic_fwctrl *ctrl, u8 *country_code);
|
||||||
|
int hgic_fwctrl_set_ssid(struct hgic_fwctrl *ctrl, u8 *ssid);
|
||||||
|
int hgic_fwctrl_set_bssid(struct hgic_fwctrl *ctrl, u8 *bssid);
|
||||||
|
int hgic_fwctrl_set_channel(struct hgic_fwctrl *ctrl, u32 channel);
|
||||||
|
int hgic_fwctrl_set_bssid_filter(struct hgic_fwctrl *ctrl, u8 *filter);
|
||||||
|
int hgic_fwctrl_set_rts_threshold(struct hgic_fwctrl *ctrl, u32 rts_threshold);
|
||||||
|
int hgic_fwctrl_set_frag_threshold(struct hgic_fwctrl *ctrl, u32 frag_threshold);
|
||||||
|
int hgic_fwctrl_set_key_mgmt(struct hgic_fwctrl *ctrl, u8 *key_mgmt);
|
||||||
|
int hgic_fwctrl_set_wpa_psk(struct hgic_fwctrl *ctrl, u8 *psk);
|
||||||
|
int hgic_fwctrl_set_wbnat(struct hgic_fwctrl *ctrl, u32 enable);
|
||||||
|
int hgic_fwctrl_set_freq_range(struct hgic_fwctrl *ctrl, u32 freq_start, u32 freq_end, u32 bss_bw);
|
||||||
|
int hgic_fwctrl_set_bss_bw(struct hgic_fwctrl *ctrl, u8 bss_bw);
|
||||||
|
int hgic_fwctrl_set_tx_bw(struct hgic_fwctrl *ctrl, u8 tx_bw);
|
||||||
|
int hgic_fwctrl_set_tx_mcs(struct hgic_fwctrl *ctrl, u8 tx_mcs);
|
||||||
|
int hgic_fwctrl_set_acs(struct hgic_fwctrl *ctrl, u8 acs, u8 acs_tm);
|
||||||
|
int hgic_fwctrl_set_bgrssi(struct hgic_fwctrl *ctrl, u8 bgrssi);
|
||||||
|
int hgic_fwctrl_set_chan_list(struct hgic_fwctrl *ctrl, u16 *chan_list, u32 cnt);
|
||||||
|
int hgic_fwctrl_set_mode(struct hgic_fwctrl *ctrl, u8 *mode);
|
||||||
|
int hgic_fwctrl_set_paired_stas(struct hgic_fwctrl *ctrl, u8 *stas, u32 len);
|
||||||
|
int hgic_fwctrl_set_pairing(struct hgic_fwctrl *ctrl, u8 start);
|
||||||
|
int hgic_fwctrl_open_dev(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_close_dev(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_txpower(struct hgic_fwctrl *ctrl, u32 tx_power);
|
||||||
|
int hgic_fwctrl_get_txpower(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_listen_interval(struct hgic_fwctrl *ctrl, u32 listen_interval);
|
||||||
|
int hgic_fwctrl_set_center_freq(struct hgic_fwctrl *ctrl, u32 channel);
|
||||||
|
int hgic_fwctrl_set_tx_count(struct hgic_fwctrl *ctrl, u32 short_frm_tx_count, u32 long_frm_tx_count);
|
||||||
|
int hgic_fwctrl_set_key(struct hgic_fwctrl *ctrl, u8 cmd, u16 aid, u8 *key, u8 len);
|
||||||
|
int hgic_fwctrl_add_sta(struct hgic_fwctrl *ctrl, u16 aid, u8 *addr);
|
||||||
|
int hgic_fwctrl_del_sta(struct hgic_fwctrl *ctrl, u32 aid);
|
||||||
|
int hgic_fwctrl_set_primary_chan(struct hgic_fwctrl *ctrl, u8 primary_chan);
|
||||||
|
int hgic_fwctrl_set_aid(struct hgic_fwctrl *ctrl, u32 aid);
|
||||||
|
int hgic_fwctrl_set_mac(struct hgic_fwctrl *ctrl, u8 *mac);
|
||||||
|
int hgic_fwctrl_get_scan_list(struct hgic_fwctrl *ctrl, u8 *buff, u32 size);
|
||||||
|
int hgic_fwctrl_scan(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_txq_param(struct hgic_fwctrl *ctrl, u8 *txq, u32 size);
|
||||||
|
int hgic_fwctrl_get_temperature(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_enter_sleep(struct hgic_fwctrl *ctrl, u8 sleep);
|
||||||
|
int hgic_fwctrl_get_sta_list(struct hgic_fwctrl *ctrl, struct hgic_sta_info *sta_list, u32 size);
|
||||||
|
int hgic_fwctrl_set_beacon_int(struct hgic_fwctrl *ctrl, u32 beacon_int);
|
||||||
|
int hgic_fwctrl_get_ssid(struct hgic_fwctrl *ctrl, u8 *ssid, u32 size);
|
||||||
|
int hgic_fwctrl_get_wpapsk(struct hgic_fwctrl *ctrl, u8 *psk, u32 size);
|
||||||
|
int hgic_fwctrl_save_cfg(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_join_group(struct hgic_fwctrl *ctrl, u8 *addr, u8 aid);
|
||||||
|
int hgic_fwctrl_set_ethertype(struct hgic_fwctrl *ctrl, u16 type);
|
||||||
|
int hgic_fwctrl_get_sta_count(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_get_bss_bw(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_get_freq_range(struct hgic_fwctrl *ctrl, u32 *freq_start, u32 *freq_end, u32 *bss_bw);
|
||||||
|
int hgic_fwctrl_get_chan_list(struct hgic_fwctrl *ctrl, u16 *chan_list, u16 count);
|
||||||
|
int hgic_fwctrl_get_agg_cnt(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_agg_cnt(struct hgic_fwctrl *ctrl, u8 agg_cnt);
|
||||||
|
int hgic_fwctrl_set_ps_addr(struct hgic_fwctrl *ctrl, u32 dport);
|
||||||
|
int hgic_fwctrl_wakeup_sta(struct hgic_fwctrl *ctrl, u8 *addr);
|
||||||
|
int hgic_fwctrl_set_ps_heartbeat(struct hgic_fwctrl *ctrl, u32 ipaddr, u32 dport, u32 period, u32 hb_tmo);
|
||||||
|
int hgic_fwctrl_set_ps_heartbeat_resp(struct hgic_fwctrl *ctrl, u8 *data, u32 size);
|
||||||
|
int hgic_fwctrl_set_ps_wakeup_data(struct hgic_fwctrl *ctrl, u8 *data, u32 size);
|
||||||
|
int hgic_fwctrl_set_ps_connect(struct hgic_fwctrl *ctrl, u8 period, u8 roundup);
|
||||||
|
int hgic_fwctrl_set_ps_connect_count(struct hgic_fwctrl *ctrl, u8 try_cnt);
|
||||||
|
int hgic_fwctrl_set_ps_connect_time(struct hgic_fwctrl *ctrl, u32 time);
|
||||||
|
int hgic_fwctrl_get_ps_connect(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_get_ps_connect_count(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_get_ps_connect_time(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_radio_onoff(struct hgic_fwctrl *ctrl, u8 onoff);
|
||||||
|
int hgic_fwctrl_set_bss_max_idle(struct hgic_fwctrl *ctrl, u32 max_idle);
|
||||||
|
int hgic_fwctrl_set_wkio_mode(struct hgic_fwctrl *ctrl, u8 mode);
|
||||||
|
int hgic_fwctrl_set_ps_mode(struct hgic_fwctrl *ctrl, u8 mode);
|
||||||
|
int hgic_fwctrl_set_load_def(struct hgic_fwctrl *ctrl, u8 rst);
|
||||||
|
int hgic_fwctrl_disassoc_sta(struct hgic_fwctrl *ctrl, u8 *addr);
|
||||||
|
int hgic_fwctrl_set_dtim_period(struct hgic_fwctrl *ctrl, u32 period);
|
||||||
|
int hgic_fwctrl_set_aplost_time(struct hgic_fwctrl *ctrl, u32 aplost_time);
|
||||||
|
int hgic_fwctrl_get_wkreason(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_unpair(struct hgic_fwctrl *ctrl, u8 *addr);
|
||||||
|
int hgic_fwctrl_set_auto_chswitch(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_set_mcast_key(struct hgic_fwctrl *ctrl, u8 *mcast_key);
|
||||||
|
int hgic_fwctrl_set_reassoc_wkhost(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_set_wakeup_io(struct hgic_fwctrl *ctrl, u8 io, u8 edge);
|
||||||
|
int hgic_fwctrl_set_dbginfo_output(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_set_sysdbg(struct hgic_fwctrl *ctrl, u8 *cmd);
|
||||||
|
int hgic_fwctrl_set_autosleep_time(struct hgic_fwctrl *ctrl, u8 time);
|
||||||
|
int hgic_fwctrl_get_key_mgmt(struct hgic_fwctrl *ctrl, u8 *ssid, u32 size);
|
||||||
|
int hgic_fwctrl_get_bssid(struct hgic_fwctrl *ctrl, u8 *bssid);
|
||||||
|
int hgic_fwctrl_set_supper_pwr(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_set_repeater_ssid(struct hgic_fwctrl *ctrl, u8 *ssid);
|
||||||
|
int hgic_fwctrl_set_repeater_psk(struct hgic_fwctrl *ctrl, u8 *wpa_psk);
|
||||||
|
int hgic_fwctrl_set_auto_save(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_set_pair_autostop(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_send_cust_mgmt(struct hgic_fwctrl *ctrl, u8 *data, u32 len);
|
||||||
|
int hgic_fwctrl_get_battery_level(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_dcdc13v(struct hgic_fwctrl *ctrl, u8 enable);
|
||||||
|
int hgic_fwctrl_set_acktmo(struct hgic_fwctrl *ctrl, u32 tmo);
|
||||||
|
int hgic_fwctrl_get_module_type(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_pa_pwrctl_dis(struct hgic_fwctrl *ctrl, u8 dis);
|
||||||
|
int hgic_fwctrl_set_dhcpc(struct hgic_fwctrl *ctrl, u8 en);
|
||||||
|
int hgic_fwctrl_get_dhcpc_result(struct hgic_fwctrl *ctrl, u8* buff, int len);
|
||||||
|
int hgic_fwctrl_set_wkdata_mask(struct hgic_fwctrl *ctrl, u16 offset, u8 *mask, u8 mask_len);
|
||||||
|
int hgic_fwctrl_get_wkdata_buff(struct hgic_fwctrl *ctrl, u8* buff, int len);
|
||||||
|
int hgic_fwctrl_get_disassoc_reason(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_wkdata_save(struct hgic_fwctrl *ctrl, u8 save);
|
||||||
|
int hgic_fwctrl_set_cust_driver_data(struct hgic_fwctrl *ctrl, u8 *data, u32 len);
|
||||||
|
int hgic_fwctrl_set_mcast_txparam(struct hgic_fwctrl *ctrl, struct hgic_mcast_txparam *param);
|
||||||
|
int hgic_fwctrl_set_freqinfo(struct hgic_fwctrl *ctrl, u8 *data, u32 len);
|
||||||
|
int hgic_fwctrl_reset_sta(struct hgic_fwctrl *ctrl, u8 *addr);
|
||||||
|
int hgic_fwctrl_set_ant_auto(struct hgic_fwctrl *ctrl, u8 en);
|
||||||
|
int hgic_fwctrl_select_ant(struct hgic_fwctrl *ctrl, u8 ant);
|
||||||
|
int hgic_fwctrl_get_ant_sel(struct hgic_fwctrl *ctrl);
|
||||||
|
int hgic_fwctrl_set_wkhost_reasons(struct hgic_fwctrl *ctrl, u8 *reasons, u8 len);
|
||||||
|
int hgic_fwctrl_set_mac_filter(struct hgic_fwctrl *ctrl, u8 en);
|
||||||
|
int hgic_fwctrl_set_atcmd(struct hgic_fwctrl *ctrl, char *atcmd);
|
||||||
|
int hgic_fwctrl_set_roaming(struct hgic_fwctrl *ctrl, u8 en, u8 same_freq);
|
||||||
|
int hgic_fwctrl_set_ap_hide(struct hgic_fwctrl *ctrl, u8 hide);
|
||||||
|
int hgic_fwctrl_set_frm_tx_maxcnt(struct hgic_fwctrl *ctrl, u8 txcnt);
|
||||||
|
int hgic_fwctrl_set_assert_holdup(struct hgic_fwctrl *ctrl, u8 holdup);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
438
utils/fwdl.c
Normal file
438
utils/fwdl.c
Normal file
|
@ -0,0 +1,438 @@
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
#include "fwinfo.h"
|
||||||
|
#include "fwctrl.h"
|
||||||
|
#include "fwdl.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define BOOT_CMD_KEY "@huge-ic"
|
||||||
|
#define BOOT_CMD_KEY_SIZE 8
|
||||||
|
|
||||||
|
void hgic_bootdl_release(struct hgic_bootdl *hg, int mode)
|
||||||
|
{
|
||||||
|
if (hg == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_dbg("Enter ...\n");
|
||||||
|
|
||||||
|
hgic_dbg("Leave ...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_bootdl_init(struct hgic_bootdl *hg_fwdl, struct hgic_bus *bus, struct hgic_fwctrl *ctrl)
|
||||||
|
{
|
||||||
|
if (hg_fwdl == NULL) {
|
||||||
|
printk("%s:%d:Input para error!\n", __FUNCTION__, __LINE__);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_dbg("Enter ...\n");
|
||||||
|
memset(hg_fwdl, 0, sizeof(struct hgic_bootdl));
|
||||||
|
hg_fwdl->checksum_mode = bus->bootdl_cksum;
|
||||||
|
hg_fwdl->frag_size = bus->bootdl_pktlen;
|
||||||
|
hg_fwdl->ctrl = ctrl;
|
||||||
|
hg_fwdl->bus = bus;
|
||||||
|
hgic_dbg("Leave ...each packet len:%d\n", hg_fwdl->frag_size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 crc8(char *p_buf, u32 len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *hgic_bootdl_alloc_cmd_skb(struct hgic_bootdl *hg, u8 cmd_id)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgic_bootdl_cmd_hdr *cmd_hdr = NULL;
|
||||||
|
|
||||||
|
skb = dev_alloc_skb(sizeof(struct hgic_bootdl_cmd_hdr) + 4);
|
||||||
|
if (!skb) {
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
cmd_hdr = (struct hgic_bootdl_cmd_hdr *)skb->data;
|
||||||
|
cmd_hdr->cmd = cmd_id;
|
||||||
|
cmd_hdr->cmd_len = 12;
|
||||||
|
cmd_hdr->cmd_flag = hg->checksum_mode;
|
||||||
|
skb_put(skb, sizeof(struct hgic_bootdl_cmd_hdr));
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 hgic_bootdl_cmd_check_val(u8 check_mode, u8 *p_buf, u32 len)
|
||||||
|
{
|
||||||
|
u8 check_value = 0;
|
||||||
|
u32 i = 0;
|
||||||
|
|
||||||
|
if (HGIC_BUS_BOOTDL_CHECK_SUM == check_mode) {
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
check_value += *p_buf++;
|
||||||
|
}
|
||||||
|
} else if (HGIC_BUS_BOOTDL_CHECK_CRC8 == check_mode) {
|
||||||
|
check_value = crc8(p_buf, len);
|
||||||
|
} else if (HGIC_BUS_BOOTDL_CHECK_0XFD == check_mode) {
|
||||||
|
check_value = 0xFD;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return check_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_bootdl_cmd_rsp_handle(unsigned char cmd_flag, unsigned char cmd, struct hgic_bootdl_resp_hdr *resp)
|
||||||
|
{
|
||||||
|
if (resp->check != hgic_bootdl_cmd_check_val(cmd_flag, (u8 *)&resp->cmd, 8)) {
|
||||||
|
hgic_dbg("Checksum error,return HG_BOOTDL_ERR_RSP_PACKET!\r\n");
|
||||||
|
return HG_BOOTDL_ERR_RSP_PACKET;
|
||||||
|
}
|
||||||
|
if (resp->cmd != cmd) {
|
||||||
|
hgic_dbg("Cmd not match,resp_cmd:<%d>,cmd:<%d>\n", resp->cmd, cmd);
|
||||||
|
return HG_BOOTDL_ERR_RSP_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp->rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct sk_buff *hgic_bootdl_send_cmd(struct hgic_bootdl *hg_fwdl, struct sk_buff *skb, u32 timeout)
|
||||||
|
{
|
||||||
|
struct hgic_bootdl_cmd_hdr *hdr = NULL;
|
||||||
|
struct hgic_cmd_response resp;
|
||||||
|
|
||||||
|
hdr = (struct hgic_bootdl_cmd_hdr *)skb->data;
|
||||||
|
hdr->hdr.magic = HGIC_HDR_TX_MAGIC;
|
||||||
|
hdr->hdr.type = HGIC_HDR_TYPE_BOOTDL;
|
||||||
|
hdr->hdr.length = skb->len;
|
||||||
|
hdr->hdr.cookie = hgic_ctrl_cookie(hg_fwdl->ctrl);
|
||||||
|
|
||||||
|
//printk("hg_fwdl->ctrl=%p\r\n", hg_fwdl->ctrl);
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
resp.cookie = hdr->hdr.cookie;
|
||||||
|
hg_fwdl->last_cookie = resp.cookie;
|
||||||
|
return hgic_fwctrl_send_data(hg_fwdl->ctrl, skb, &resp, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sk_buff *hgic_bootdl_send_data(struct hgic_bootdl *hg_fwdl, struct sk_buff *skb, u32 timeout)
|
||||||
|
{
|
||||||
|
struct hgic_bootdl_cmd_hdr *hdr = NULL;
|
||||||
|
struct hgic_cmd_response resp;
|
||||||
|
|
||||||
|
hdr = (struct hgic_bootdl_cmd_hdr *)skb_push(skb, sizeof(struct hgic_bootdl_cmd_hdr));
|
||||||
|
hdr->hdr.magic = HGIC_HDR_TX_MAGIC;
|
||||||
|
hdr->hdr.type = HGIC_HDR_TYPE_BOOTDL_DATA;
|
||||||
|
memset(&resp, 0, sizeof(struct hgic_cmd_response));
|
||||||
|
resp.cookie = hg_fwdl->last_cookie;
|
||||||
|
return hgic_fwctrl_send_data(hg_fwdl->ctrl, skb, &resp, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_bootdl_parse_fw(struct hgic_bootdl *hg, const char *fw_name)
|
||||||
|
{
|
||||||
|
const struct firmware *fw;
|
||||||
|
int ret = 0;
|
||||||
|
s32 err_code = 0;
|
||||||
|
|
||||||
|
ret = request_firmware(&fw, fw_name, hg->ctrl->dev);
|
||||||
|
if (ret) {
|
||||||
|
printk("%s,%d:request_firmware failed!ret:%d\n", __FUNCTION__, __LINE__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
hg->fw = (struct firmware *)fw;
|
||||||
|
|
||||||
|
hg->fw_info.write_addr = hgic_get_fw_dl_addr(fw->data, &err_code);
|
||||||
|
if (err_code) {
|
||||||
|
hgic_dbg("hgic_get_fw_dl_addr error!\n");
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
hg->fw_info.aes_en = hgic_get_fw_aes_en(fw->data, &err_code);
|
||||||
|
if (err_code) {
|
||||||
|
hgic_dbg("hgic_get_aes_en error!\n");
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
hg->fw_info.crc_en = hgic_get_fw_crc_en(fw->data, &err_code);
|
||||||
|
if (err_code) {
|
||||||
|
hgic_dbg("hgic_get_fw_crc_en error!\n");
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
hg->fw_info.local_crc32 = hgic_get_fw_local_crc32(fw->data, &err_code);
|
||||||
|
if (err_code) {
|
||||||
|
hgic_dbg("hgic_get_fw_local_crc32 error!\n");
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
hg->fw_info.hdr_len = hgic_get_fw_code_offset(fw->data, &err_code);
|
||||||
|
if (err_code) {
|
||||||
|
hgic_dbg("hgic_get_fw_code_offset error!\n");
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
hg->fw_info.sp_cfg = 1;
|
||||||
|
hg->fw_info.fw_len = fw->size - hg->fw_info.hdr_len;
|
||||||
|
|
||||||
|
hgic_dbg("firmware hdr len : %d\r\n", hg->fw_info.hdr_len);
|
||||||
|
hgic_dbg("firmware run addr : %x\r\n", hg->fw_info.write_addr);
|
||||||
|
hgic_dbg("firmware size : %d\r\n", hg->fw_info.fw_len);
|
||||||
|
hgic_dbg("firmware aes_en:%d,crc_en:%d\r\n", hg->fw_info.aes_en, hg->fw_info.crc_en);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_bootdl_send_fw(struct hgic_bootdl *hg, struct sk_buff *skb, u32 tmo)
|
||||||
|
{
|
||||||
|
struct sk_buff *resp_skb = NULL;
|
||||||
|
struct hgic_bootdl_resp_hdr *data_resp = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (skb == NULL || hg == NULL) {
|
||||||
|
hgic_dbg("input para error\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
resp_skb = hgic_bootdl_send_data(hg, skb, tmo);
|
||||||
|
if (resp_skb) {
|
||||||
|
data_resp = (struct hgic_bootdl_resp_hdr *)resp_skb->data;
|
||||||
|
ret = data_resp->rsp;
|
||||||
|
if (ret != 0) {
|
||||||
|
hgic_dbg("Send fw data error!ret:<%d>\n", ret);
|
||||||
|
} else {
|
||||||
|
hgic_dbg("Send fw data success!\n");
|
||||||
|
}
|
||||||
|
dev_kfree_skb_any(resp_skb);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
hgic_dbg("send fw data error, no resp!\n");
|
||||||
|
return EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_bootdl_send_cmd_tmo(struct hgic_bootdl *hg,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
u32 timeout,
|
||||||
|
u32 *resp_data)
|
||||||
|
{
|
||||||
|
struct sk_buff *resp = NULL;
|
||||||
|
struct hgic_bootdl_cmd_hdr *cmd_hdr = (struct hgic_bootdl_cmd_hdr *)skb->data;
|
||||||
|
struct hgic_bootdl_resp_hdr *boot_resp = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned char cmd_flag = 0;
|
||||||
|
unsigned char cmd = 0;
|
||||||
|
|
||||||
|
if (hg == NULL || skb == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_flag = cmd_hdr->cmd_flag;
|
||||||
|
cmd = cmd_hdr->cmd;
|
||||||
|
resp = hgic_bootdl_send_cmd(hg, skb, timeout);
|
||||||
|
if (resp) {
|
||||||
|
boot_resp = (struct hgic_bootdl_resp_hdr *)resp->data;
|
||||||
|
ret = hgic_bootdl_cmd_rsp_handle(cmd_flag, cmd, boot_resp);
|
||||||
|
if (ret != 0 && ret != HG_BOOTDL_RSP_ERR_IN_FW) {
|
||||||
|
hgic_err("cmd %d, error:%d\n", cmd, ret);
|
||||||
|
dev_kfree_skb_any(resp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (resp_data != NULL) {
|
||||||
|
*resp_data = get_unaligned_le32(boot_resp->rsp_data);
|
||||||
|
}
|
||||||
|
dev_kfree_skb_any(resp);
|
||||||
|
} else {
|
||||||
|
hgic_err("cmd: %d, no responce!!\r\n", cmd);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgic_bootdl_cmd_enter(struct hgic_bootdl *hg)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgic_bootdl_cmd_hdr *cmd_hdr = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
skb = hgic_bootdl_alloc_cmd_skb(hg, HG_BOOTDL_CMD_ENTER);
|
||||||
|
if (skb) {
|
||||||
|
cmd_hdr = (struct hgic_bootdl_cmd_hdr *)skb->data;
|
||||||
|
memcpy((void *)cmd_hdr->addr, (void *)BOOT_CMD_KEY, BOOT_CMD_KEY_SIZE);
|
||||||
|
cmd_hdr->check = hgic_bootdl_cmd_check_val(hg->checksum_mode, (u8 *)&cmd_hdr->cmd, 11);
|
||||||
|
} else {
|
||||||
|
hgic_err("malloc skb failed!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
ret = hgic_bootdl_send_cmd_tmo(hg, skb, HG_BOOTDL_CMD_NORMAL_TMO, NULL);
|
||||||
|
if (ret == 0 || ret == HG_BOOTDL_RSP_ERR_IN_FW) {
|
||||||
|
if (ret == HG_BOOTDL_RSP_ERR_IN_FW) {
|
||||||
|
//hgic_err("In firmware state\n");
|
||||||
|
return STATE_FW;
|
||||||
|
} else {
|
||||||
|
//hgic_err("In bootdl state\n");
|
||||||
|
return STATE_BOOT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hgic_err("failed! ret:%d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_bootdl_cmd_write_memory(struct hgic_bootdl *hg, u32 write_addr, u32 data_len)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgic_bootdl_cmd_hdr *cmd_hdr = NULL;
|
||||||
|
|
||||||
|
skb = hgic_bootdl_alloc_cmd_skb(hg, HG_BOOTDL_CMD_WRITE_MEM);
|
||||||
|
if (skb) {
|
||||||
|
cmd_hdr = (struct hgic_bootdl_cmd_hdr *)skb->data;
|
||||||
|
put_unaligned_le32(write_addr, cmd_hdr->addr);
|
||||||
|
if (hg->bus->type == HGIC_BUS_SDIO) {
|
||||||
|
put_unaligned_le32(data_len, cmd_hdr->len);
|
||||||
|
} else {
|
||||||
|
put_unaligned_le32((data_len + 1024), cmd_hdr->len);
|
||||||
|
}
|
||||||
|
cmd_hdr->check = hgic_bootdl_cmd_check_val(hg->checksum_mode, (u8 *)&cmd_hdr->cmd, 11);
|
||||||
|
} else {
|
||||||
|
hgic_dbg("malloc skb failed!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
return hgic_bootdl_send_cmd_tmo(hg, skb, HG_BOOTDL_CMD_NORMAL_TMO, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_bootdl_cmd_run(struct hgic_bootdl *hg)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgic_bootdl_cmd_hdr *cmd_hdr = NULL;
|
||||||
|
u32 temp = 0;
|
||||||
|
|
||||||
|
skb = hgic_bootdl_alloc_cmd_skb(hg, HG_BOOTDL_CMD_RUN);
|
||||||
|
if (skb) {
|
||||||
|
cmd_hdr = (struct hgic_bootdl_cmd_hdr *)skb->data;
|
||||||
|
put_unaligned_le32(hg->fw_info.write_addr, cmd_hdr->addr);
|
||||||
|
|
||||||
|
temp = hg->fw_info.fw_len;
|
||||||
|
if (hg->fw_info.aes_en) {
|
||||||
|
temp |= HG_BOOT_CMD_RUN_PREACT_AES_DEC;
|
||||||
|
}
|
||||||
|
if (hg->fw_info.crc_en) {
|
||||||
|
temp |= HG_BOOT_CMD_RUN_PREACT_CRC_CHK;
|
||||||
|
}
|
||||||
|
if (hg->fw_info.sp_cfg) {
|
||||||
|
temp |= HG_BOOT_CMD_RUN_PREACT_SP_CFG;
|
||||||
|
}
|
||||||
|
put_unaligned_le32(temp, cmd_hdr->len);
|
||||||
|
|
||||||
|
cmd_hdr->check = hgic_bootdl_cmd_check_val(hg->checksum_mode, (u8 *)&cmd_hdr->cmd, 11);
|
||||||
|
} else {
|
||||||
|
hgic_dbg("malloc skb failed!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
return hgic_bootdl_send_cmd_tmo(hg, skb, HG_BOOTDL_CMD_NORMAL_TMO, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int hgic_bootdl_fragment_proc(struct hgic_bootdl *hg, unsigned int copy_len)
|
||||||
|
{
|
||||||
|
unsigned int xfer_len = 0;
|
||||||
|
unsigned int blk = 0;
|
||||||
|
|
||||||
|
if (hg->bus->type == HGIC_BUS_SDIO) {
|
||||||
|
if (copy_len < hg->frag_size) {
|
||||||
|
blk = copy_len / hg->bus->blk_size;
|
||||||
|
if (blk) {
|
||||||
|
xfer_len = blk * hg->bus->blk_size;
|
||||||
|
} else {
|
||||||
|
//xfer_len = copy_len;
|
||||||
|
xfer_len = ALIGN(copy_len, 4);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xfer_len = hg->frag_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xfer_len = copy_len > hg->frag_size ? hg->frag_size : copy_len;
|
||||||
|
}
|
||||||
|
return xfer_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgic_bootdl_download(struct hgic_bootdl *hg, const char *fw_path)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
u32 write_addr = 0;
|
||||||
|
u32 copy_len = 0;
|
||||||
|
u32 xfer_len = 0;
|
||||||
|
u32 addr_offset = 0;
|
||||||
|
char *data = NULL;
|
||||||
|
|
||||||
|
if (hg == NULL || fw_path == NULL) {
|
||||||
|
printk("%s,%d:input para error!\n", __FUNCTION__, __LINE__);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_enter();
|
||||||
|
ret = hgic_bootdl_parse_fw(hg, fw_path);
|
||||||
|
if (ret != 0 || !hg->fw) {
|
||||||
|
hgic_dbg("hgic_bootdl_parse_fw error,ret:<%d>,path:%s\n", ret, fw_path);
|
||||||
|
goto __finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_len = hg->fw_info.fw_len;
|
||||||
|
write_addr = hg->fw_info.write_addr;
|
||||||
|
data = (char *)(hg->fw->data + hg->fw_info.hdr_len);
|
||||||
|
while (copy_len) {
|
||||||
|
//xfer_len = copy_len > hg->frag_size ? hg->frag_size : copy_len;
|
||||||
|
xfer_len = hgic_bootdl_fragment_proc(hg, copy_len);
|
||||||
|
skb = dev_alloc_skb(xfer_len + sizeof(struct hgic_bootdl_cmd_hdr));
|
||||||
|
if (skb == NULL) {
|
||||||
|
printk("%s: no memory\r\n", __FUNCTION__);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto __finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb_reserve(skb, sizeof(struct hgic_bootdl_cmd_hdr));
|
||||||
|
memcpy(skb->data, data + addr_offset, xfer_len);
|
||||||
|
skb_put(skb, xfer_len);
|
||||||
|
|
||||||
|
ret = hgic_bootdl_cmd_write_memory(hg, write_addr, skb->len);
|
||||||
|
if (ret != 0) {
|
||||||
|
hgic_dbg("hgic_bootdl_cmd_write_memory error!\n");
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
goto __finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_bootdl_send_fw(hg, skb, HG_BOOTDL_CMD_WRITE_MEM_TMO);
|
||||||
|
if (ret != 0) {
|
||||||
|
hgic_dbg("hgic_bootdl_send_fw error!\n");
|
||||||
|
goto __finish;
|
||||||
|
}
|
||||||
|
write_addr += xfer_len;
|
||||||
|
copy_len -= xfer_len;
|
||||||
|
addr_offset += xfer_len;
|
||||||
|
skb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_bootdl_cmd_run(hg);
|
||||||
|
if (ret) {
|
||||||
|
printk("%s: Cmd run failed:%d\r\n", __FUNCTION__, ret);
|
||||||
|
}
|
||||||
|
__finish:
|
||||||
|
if (hg->fw) {
|
||||||
|
hgic_dbg("Release boot download firmware...\n");
|
||||||
|
release_firmware(hg->fw);
|
||||||
|
hg->fw = NULL;
|
||||||
|
}
|
||||||
|
hgic_leave();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
91
utils/fwdl.h
Normal file
91
utils/fwdl.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#ifndef _HGIC_BOOT_HOST_H_
|
||||||
|
#define _HGIC_BOOT_HOST_H_
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
|
||||||
|
#define HG_BOOTDL_CMD_ENTER (0x00)
|
||||||
|
#define HG_BOOTDL_CMD_GET_SC (0x01)
|
||||||
|
#define HG_BOOTDL_CMD_WRITE_MEM (0x02)
|
||||||
|
#define HG_BOOTDL_CMD_READ_MEM (0x03)
|
||||||
|
#define HG_BOOTDL_CMD_RUN (0x04)
|
||||||
|
#define HG_BOOTDL_CMD_VERIFY_MEM (0x05)
|
||||||
|
#define HG_BOOTDL_CMD_CHIP_RESET (0x06)
|
||||||
|
#define HG_BOOTDL_CMD_WRITE_REG (0x07)
|
||||||
|
#define HG_BOOTDL_CMD_READ_REG (0x08)
|
||||||
|
#define HG_BOOTDL_CMD_SPEED (0x09)
|
||||||
|
#define HG_BOOTDL_CMD_EXIT (0xFF)
|
||||||
|
|
||||||
|
#define HG_BOOT_CMD_RUN_PREACT_AES_DEC BIT(31)
|
||||||
|
#define HG_BOOT_CMD_RUN_PREACT_CRC_CHK BIT(30)
|
||||||
|
#define HG_BOOT_CMD_RUN_PREACT_SP_CFG BIT(29)
|
||||||
|
|
||||||
|
#define HG_BOOTDL_CMD_LEN 12
|
||||||
|
#define HG_BOOTDL_CMD_WRITE_MEM_TMO 1000
|
||||||
|
#define HG_BOOTDL_CMD_NORMAL_TMO 100
|
||||||
|
#define HG_BOOTDL_INFO_HDR_SIZE 512
|
||||||
|
|
||||||
|
enum hg_device_state {
|
||||||
|
STATE_FW = 0,
|
||||||
|
STATE_BOOT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hg_boot_host_check{
|
||||||
|
HG_BOOTDL_CHECK_SUM = 0,
|
||||||
|
HG_BOOTDL_CHECK_CRC8,
|
||||||
|
HG_BOOTDL_CHECK_0XFD,
|
||||||
|
HG_BOOTDL_CHECK_OFF = 0xFF
|
||||||
|
} ;
|
||||||
|
|
||||||
|
enum hg_boot_host_rsp_err{
|
||||||
|
HG_BOOTDL_RSP_OK = 0,
|
||||||
|
HG_BOOTDL_RSP_ERR_CMD,
|
||||||
|
HG_BOOTDL_RSP_ERR_ADDR,
|
||||||
|
HG_BOOTDL_RSP_ERR_LEN,
|
||||||
|
HG_BOOTDL_RSP_ERR_PERMISSION,
|
||||||
|
HG_BOOTDL_RSP_ERR_CMD_CHECK,
|
||||||
|
HG_BOOTDL_RSP_ERR_DATA_CHECK,
|
||||||
|
HG_BOOTDL_RSP_ERR_TO,
|
||||||
|
HG_BOOTDL_RSP_ERR_IN_FW = 0xFF,
|
||||||
|
} ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief huge-ic boot state machine
|
||||||
|
*/
|
||||||
|
enum hg_boot_host_err {
|
||||||
|
HG_BOOTDL_ERR_NONE = 0,
|
||||||
|
HG_BOOTDL_ERR_UNSUPPORT_CMD,
|
||||||
|
HG_BOOTDL_ERR_RSP_PACKET,
|
||||||
|
HG_BOOTDL_ERR_XFER,
|
||||||
|
HG_BOOTDL_ERR_TO,
|
||||||
|
} ;
|
||||||
|
|
||||||
|
struct hgic_bootdl_fw_info {
|
||||||
|
u32 write_addr;
|
||||||
|
u8 aes_en;
|
||||||
|
u8 crc_en;
|
||||||
|
u8 sp_cfg;
|
||||||
|
u32 fw_version;
|
||||||
|
u32 fw_len;
|
||||||
|
u32 local_crc32;
|
||||||
|
u32 hdr_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_bootdl {
|
||||||
|
struct hgic_bootdl_fw_info fw_info;
|
||||||
|
u8 checksum_mode;
|
||||||
|
u16 last_cookie;
|
||||||
|
u32 frag_size;
|
||||||
|
//struct sk_buff_head fw_dataq;
|
||||||
|
struct hgic_bus *bus;
|
||||||
|
struct hgic_fwctrl *ctrl;
|
||||||
|
struct firmware *fw;
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 hgic_bootdl_init(struct hgic_bootdl *hg_fwdl, struct hgic_bus *bus, struct hgic_fwctrl *ctrl);
|
||||||
|
void hgic_bootdl_release(struct hgic_bootdl *hg,int mode);
|
||||||
|
int hgic_bootdl_download(struct hgic_bootdl *hg, const char *fw_path);
|
||||||
|
int hgic_bootdl_cmd_enter(struct hgic_bootdl *hg);
|
||||||
|
struct sk_buff *hgic_bootdl_send_cmd(struct hgic_bootdl *hg_fwdl,struct sk_buff *skb,u32 timeout);
|
||||||
|
struct sk_buff *hgic_bootdl_send_data(struct hgic_bootdl *hg_fwdl,struct sk_buff *skb,u32 timeout);
|
||||||
|
|
||||||
|
#endif
|
322
utils/fwinfo.c
Normal file
322
utils/fwinfo.c
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
#include "fwinfo.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Name: CRC-16/MODBUS x16+x15+x2+1
|
||||||
|
* Poly: 0x8005
|
||||||
|
* Init: 0xFFFF
|
||||||
|
* Refin: True
|
||||||
|
* Refout: True
|
||||||
|
* Xorout: 0x0000
|
||||||
|
* Note:
|
||||||
|
*****************************************************************************/
|
||||||
|
u16 hgic_crc16(const u8 *data, u32 length)
|
||||||
|
{
|
||||||
|
u8 i;
|
||||||
|
u16 crc = 0xffff; // Initial value
|
||||||
|
while (length--)
|
||||||
|
{
|
||||||
|
crc ^= *data++; // crc ^= *data; data++;
|
||||||
|
for (i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if (crc & 1)
|
||||||
|
crc = (crc >> 1) ^ 0xA001; // 0xA001 = reverse 0x8005
|
||||||
|
else
|
||||||
|
crc = (crc >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Name: CRC-32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
|
||||||
|
* Poly: 0x4C11DB7
|
||||||
|
* Init: 0xFFFFFFF
|
||||||
|
* Refin: True
|
||||||
|
* Refout: True
|
||||||
|
* Xorout: 0xFFFFFFF
|
||||||
|
* Alias: CRC_32/ADCCP
|
||||||
|
* Use: WinRAR,ect.
|
||||||
|
*****************************************************************************/
|
||||||
|
u32 hgic_crc32(const u8 *data, u32 length)
|
||||||
|
{
|
||||||
|
u8 i;
|
||||||
|
u32 crc = 0xffffffff; // Initial value
|
||||||
|
while (length--)
|
||||||
|
{
|
||||||
|
crc ^= *data++; // crc ^= *data; data++;
|
||||||
|
for (i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if (crc & 1)
|
||||||
|
crc = (crc >> 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7
|
||||||
|
else
|
||||||
|
crc = (crc >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s32 hgic_check_fwinfo_hdr(const u8 *data)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
hgic_err("%s:Input para error!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
if (fw_hdr->boot.boot_flag != HGIC_FWINFO_BOOT_HDR) {
|
||||||
|
hgic_err("%s:Can not find boot header!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;;
|
||||||
|
}
|
||||||
|
if (fw_hdr->fw_infor.func_code != HGIC_FWINFO_CODE_HDR) {
|
||||||
|
hgic_err("%s:Can not find fw infor header!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;;
|
||||||
|
}
|
||||||
|
if (fw_hdr->spi_infor.func_code != HGIC_FWINFO_SPI_HDR) {
|
||||||
|
hgic_err("%s:Can not find spi info header!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 hgic_get_fw_aes_en(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:aes_en:%d\n", __FUNCTION__, fw_hdr->boot.mode.aes_en);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.mode.aes_en;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 hgic_get_fw_crc_en(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:crc_en:%d\n", __FUNCTION__, fw_hdr->boot.mode.crc_en);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.mode.crc_en;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_get_fw_dl_addr(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:download addr:%x\n", __FUNCTION__, fw_hdr->boot.boot_to_sram_addr);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.boot_to_sram_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_get_fw_run_addr(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:run addr:%x\n", __FUNCTION__, fw_hdr->boot.run_sram_addr);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.run_sram_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_get_fw_code_offset(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:code offset:%d\n", __FUNCTION__, fw_hdr->boot.boot_code_offset_addr);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->boot.boot_code_offset_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_get_fw_local_crc32(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:local crc:%x\n", __FUNCTION__, fw_hdr->fw_infor.code_crc32);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.code_crc32;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_get_fw_sdk_version(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Current file sdk info:%d.%d.%d.%d\r\n", __FUNCTION__,
|
||||||
|
(fw_hdr->fw_infor.sdk_version >> 24) & 0xff, (fw_hdr->fw_infor.sdk_version >> 16) & 0xff,
|
||||||
|
(fw_hdr->fw_infor.sdk_version >> 8) & 0xff, (fw_hdr->fw_infor.sdk_version & 0xff));
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.sdk_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hgic_get_fw_svn_version(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Current file svn info:%d\n", __FUNCTION__,fw_hdr->fw_infor.svn_version);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.svn_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u16 hgic_get_fw_chipid(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:fw chipid:%x\n", __FUNCTION__, fw_hdr->fw_infor.chip_id);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.chip_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 hgic_get_fw_cpuid(const u8 *data, s32 *err_code)
|
||||||
|
{
|
||||||
|
struct hgic_fw_info_hdr *fw_hdr = NULL;
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = hgic_check_fwinfo_hdr(data);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("%s:hgic_check_fwinfo_hdr error!\n", __FUNCTION__);
|
||||||
|
*err_code = ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr = (struct hgic_fw_info_hdr *)data;
|
||||||
|
hgic_dbg("%s:Check Para:cpu_id:%d\n", __FUNCTION__, fw_hdr->fw_infor.cpu_id);
|
||||||
|
*err_code = 0;
|
||||||
|
return fw_hdr->fw_infor.cpu_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 hgic_get_fw_code_checksum(const u8 *data,s32 len)
|
||||||
|
{
|
||||||
|
u32 local_chksum = 0;
|
||||||
|
u32 cur_crc = 0;
|
||||||
|
s32 err_code = 0;
|
||||||
|
u32 code_offset = 0;
|
||||||
|
const u8 *code_data = NULL;
|
||||||
|
s32 code_len = 0;
|
||||||
|
|
||||||
|
local_chksum = hgic_get_fw_local_crc32(data, &err_code);
|
||||||
|
if(err_code != 0) {
|
||||||
|
hgic_err("%s:hgic_get_fw_local_crc32 error!\n", __FUNCTION__);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
code_offset = hgic_get_fw_code_offset(data, &err_code);
|
||||||
|
if(err_code != 0) {
|
||||||
|
hgic_err("%s:hgic_get_fw_code_offset error!\n", __FUNCTION__);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
code_data = data + code_offset;
|
||||||
|
code_len = len - code_offset;
|
||||||
|
|
||||||
|
if(code_len < 0) {
|
||||||
|
hgic_err("%s:Input para error!\n", __FUNCTION__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_crc = hgic_crc32(code_data, code_len);
|
||||||
|
if(cur_crc != local_chksum && ~cur_crc != local_chksum) {
|
||||||
|
hgic_err("%s:Check crc32 with hdr crc error,local crc:%x,cur_crc:%x\r\n",
|
||||||
|
__FUNCTION__, local_chksum,cur_crc);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
hgic_dbg("%s:Checksum Success!\n",__FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
98
utils/fwinfo.h
Normal file
98
utils/fwinfo.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#ifndef _HGIC_FWINFO_H_
|
||||||
|
#define _HGIC_FWINFO_H_
|
||||||
|
|
||||||
|
#include "../hgic.h"
|
||||||
|
|
||||||
|
#define HGIC_FWINFO_BOOT_HDR 0x5a69
|
||||||
|
#define HGIC_FWINFO_SPI_HDR 0x1
|
||||||
|
#define HGIC_FWINFO_CODE_HDR 0x2
|
||||||
|
|
||||||
|
struct hgic_spiflash_header_boot {
|
||||||
|
u16 boot_flag; /* 0 : 0x5a69, header boot flag */
|
||||||
|
u8 version; /* 2 : version */
|
||||||
|
u8 size; /* 3 : Link to Next Header */
|
||||||
|
u32 boot_to_sram_addr; /* 4 : spi data load to sram addr */
|
||||||
|
u32 run_sram_addr; /* 8 : code execute start addr */
|
||||||
|
u32 boot_code_offset_addr; /* 12 : HeaderLen+ParamLen=4096+512 */
|
||||||
|
u32 boot_from_flash_len; /* 16 : */
|
||||||
|
u16 boot_data_crc; /* 20 : boot data crc check */
|
||||||
|
u16 flash_blk_size; /* 22 : flash size in 64KB(version > 1), 512B(version== 0) */
|
||||||
|
u16 boot_baud_mhz : 14, /* 24 : spi clk freq in mhz(version > 1), khz(version== 0) */
|
||||||
|
driver_strength : 2; /* io driver strength */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u16 pll_src : 8, /* pll src in Mhz */
|
||||||
|
pll_en : 1, /* PLL enable */
|
||||||
|
debug : 1, /* debug info uart output enable */
|
||||||
|
aes_en : 1, /* AES enable */
|
||||||
|
crc_en : 1, /* CRC check enable */
|
||||||
|
reserved : 4;
|
||||||
|
} mode; /* 26 : boot option */
|
||||||
|
u16 reserved; /* 28 : */
|
||||||
|
u16 head_crc16; /* (size+4) byte CRC16 check value */
|
||||||
|
}__packed;
|
||||||
|
|
||||||
|
struct hgic_spiflash_read_cfg {
|
||||||
|
u8 read_cmd; /* read_cmd */
|
||||||
|
u8 cmd_dummy_cycles : 4, /* read dummy cycles */
|
||||||
|
clock_mode : 2, /* clock polarity & phase */
|
||||||
|
spec_sequnce_en : 1, /* spec sequnce to execute, maybe same with quad_wire_en */
|
||||||
|
quad_wire_en : 1; /* spi D2/D3 enable */
|
||||||
|
|
||||||
|
u8 wire_mode_cmd : 2,
|
||||||
|
wire_mode_addr : 2,
|
||||||
|
wire_mode_data : 2,
|
||||||
|
quad_wire_select : 2; /* spi D2/D3 group select */
|
||||||
|
|
||||||
|
u8 reserved3;
|
||||||
|
|
||||||
|
u16 sample_delay; /* RX sample dalay time: 0 ~ clk_divor */
|
||||||
|
}__packed;
|
||||||
|
|
||||||
|
struct hgic_spiflash_header_spi_info {
|
||||||
|
u8 func_code; /* 0 : header function(0x1) */
|
||||||
|
u8 size; /* 1: Link to Next Header */
|
||||||
|
|
||||||
|
struct hgic_spiflash_read_cfg read_cfg;
|
||||||
|
u8 hgic_spiflash_spec_sequnce[64];
|
||||||
|
|
||||||
|
u16 header_crc16; /* (size+2) byte CRC16 check value */
|
||||||
|
}__packed;
|
||||||
|
|
||||||
|
/* hgic_ah_fw_v1.0.1.1_2020.2.20.bin ?*/
|
||||||
|
|
||||||
|
struct hgic_spiflash_header_firmware_info {
|
||||||
|
u8 func_code; /* 0 : header function(0x2) */
|
||||||
|
u8 size; /* 1: Link to Next Header */
|
||||||
|
u32 sdk_version; /* version */
|
||||||
|
u32 svn_version;
|
||||||
|
u32 date; /* date */
|
||||||
|
u16 chip_id; /* chip_id */
|
||||||
|
u8 cpu_id; /* cpu id, fix 0 */
|
||||||
|
u32 code_crc32; /* code CRC32 */
|
||||||
|
u16 param_crc16; /* param CRC16 */
|
||||||
|
u16 crc16; /* (size+2) byte CRC16 check value */
|
||||||
|
}__packed;
|
||||||
|
|
||||||
|
struct hgic_fw_info_hdr {
|
||||||
|
struct hgic_spiflash_header_boot boot;
|
||||||
|
struct hgic_spiflash_header_spi_info spi_infor; /* func1*/
|
||||||
|
struct hgic_spiflash_header_firmware_info fw_infor ; /* func2*/
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
u16 hgic_crc16(const u8 *data, u32 length);
|
||||||
|
u32 hgic_crc32(const u8 *data, u32 length);
|
||||||
|
u16 hgic_get_fw_aes_en(const u8 *data, s32 *err_code);
|
||||||
|
u16 hgic_get_fw_crc_en(const u8 *data, s32 *err_code);
|
||||||
|
u32 hgic_get_fw_dl_addr(const u8 *data, s32 *err_code);
|
||||||
|
u32 hgic_get_fw_run_addr(const u8 *data, s32 *err_code);
|
||||||
|
u32 hgic_get_fw_code_offset(const u8 *data, s32 *err_code);
|
||||||
|
u32 hgic_get_fw_local_crc32(const u8 *data, s32 *err_code);
|
||||||
|
u32 hgic_get_fw_sdk_version(const u8 *data, s32 *err_code);
|
||||||
|
u32 hgic_get_fw_svn_version(const u8 *data, s32 *err_code);
|
||||||
|
u16 hgic_get_fw_chipid(const u8 *data, s32 *err_code);
|
||||||
|
u8 hgic_get_fw_cpuid(const u8 *data, s32 *err_code);
|
||||||
|
s32 hgic_get_fw_code_checksum(const u8 *data,s32 len);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
1141
utils/hgic_fmac.c
Normal file
1141
utils/hgic_fmac.c
Normal file
File diff suppressed because it is too large
Load diff
899
utils/if_sdio.c
Normal file
899
utils/if_sdio.c
Normal file
|
@ -0,0 +1,899 @@
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include "porting/sdio.h"
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/semaphore.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/netdevice.h>
|
||||||
|
|
||||||
|
#define sdio_func_t sdio_func
|
||||||
|
#define mmc_command_t mmc_command
|
||||||
|
#define sdio_device_id_t sdio_device_id
|
||||||
|
#define sdio_driver_t sdio_driver
|
||||||
|
#define vendor_id vendor
|
||||||
|
#define device_id device
|
||||||
|
#define f_num num
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define SDIO_BLOCK_SIZE 64
|
||||||
|
#define SDIO_DATA_ADDR 0x0
|
||||||
|
#define SDIO_TRANS_COUNT_ADDR 0x1C
|
||||||
|
#define SDIO_INIT_STATUS_ADDR 0x04
|
||||||
|
#define SDIO_INIT_STATUS_ADDR2 0x48
|
||||||
|
#define SDIO_TRANS_COUNT_ADDR2 0x49
|
||||||
|
#define SDIO_INIT_STATUS_DATA_READY 0x01
|
||||||
|
#define SDIO_STATUS_STOP BIT(0)
|
||||||
|
#define SDIO_STATUS_ERROR BIT(1)
|
||||||
|
#define SDIO_TX_HEADROM (4)
|
||||||
|
|
||||||
|
struct hgic_sdio {
|
||||||
|
struct sdio_func_t *func;
|
||||||
|
u32 status;
|
||||||
|
u32 data_addr; /*sdio data register address*/
|
||||||
|
u32 trans_cnt_addr; /*sdio data length register address*/
|
||||||
|
u32 int_status_addr; /*interrupt status register address*/
|
||||||
|
struct hgic_bus bus;
|
||||||
|
u32 rx_retry;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct sdio_device_id_t hgic_sdio_wdev_ids[] = {
|
||||||
|
{SDIO_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_AH_4001)},
|
||||||
|
{SDIO_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_AH_4002)},
|
||||||
|
{SDIO_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_AH_4102)},
|
||||||
|
{ /* end: all zeroes */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef __RTOS__
|
||||||
|
#ifndef SDIO_BUS_WIDTH_MASK
|
||||||
|
#define SDIO_BUS_WIDTH_MASK 3
|
||||||
|
#endif
|
||||||
|
#ifndef mmc_card_highspeed
|
||||||
|
#define mmc_card_highspeed mmc_card_hs
|
||||||
|
#endif
|
||||||
|
#ifndef mmc_card_set_highspeed
|
||||||
|
#define mmc_card_set_highspeed(func)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FUNC_DEV(f) (&((f)->dev))
|
||||||
|
|
||||||
|
#define SDIO_CAP_IRQ(func) ((func)->card->host->caps & MMC_CAP_SDIO_IRQ)
|
||||||
|
#define SDIO_CAP_POLL(func) ((func)->card->host->caps & MMC_CAP_NEEDS_POLL)
|
||||||
|
#define HOST_SPI_CRC(func, crc) (func)->card->host->use_spi_crc=crc
|
||||||
|
|
||||||
|
//#define mmc_card_disable_cd(c) (1)
|
||||||
|
#define hgic_card_disable_cd(func) mmc_card_disable_cd((func)->card)
|
||||||
|
#define hgic_card_set_highspeed(func) mmc_card_set_highspeed((func)->card)
|
||||||
|
#define hgic_host_is_spi(func) mmc_host_is_spi((func)->card->host)
|
||||||
|
#define hgic_card_cccr_widebus(func) ((func)->card->cccr.low_speed && !(func)->card->cccr.wide_bus)
|
||||||
|
#define hgic_card_cccr_highspeed(func) ((func)->card->cccr.high_speed)
|
||||||
|
#define hgic_host_highspeed(func) ((func)->card->host->caps & MMC_CAP_SD_HIGHSPEED)
|
||||||
|
#define hgic_host_supp_4bit(func) ((func)->card->host->caps & MMC_CAP_4_BIT_DATA)
|
||||||
|
#define hgic_card_highspeed(func) mmc_card_highspeed((func)->card)
|
||||||
|
#define hgic_func_rca(func) ((func)->card->rca)
|
||||||
|
#define hgic_card_max_clock(func) ((func)->card->cis.max_dtr)
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,14)
|
||||||
|
#define hgic_card_ocr(func) ((func)->card->host->ocr)
|
||||||
|
#else
|
||||||
|
#define hgic_card_ocr(func) ((func)->card->ocr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void hgic_mmc_set_timing(struct sdio_func_t *func, unsigned int timing)
|
||||||
|
{
|
||||||
|
func->card->host->ios.timing = timing;
|
||||||
|
func->card->host->ops->set_ios(func->card->host, &func->card->host->ios);
|
||||||
|
}
|
||||||
|
static inline void hgic_mmc_set_bus_width(struct sdio_func_t *func, unsigned int width)
|
||||||
|
{
|
||||||
|
func->card->host->ios.bus_width = width;
|
||||||
|
func->card->host->ops->set_ios(func->card->host, &func->card->host->ios);
|
||||||
|
}
|
||||||
|
static inline void hgic_mmc_set_clock(struct sdio_func_t *func, unsigned int hz)
|
||||||
|
{
|
||||||
|
if (func->card->host->f_max && hz > func->card->host->f_max) {
|
||||||
|
hz = func->card->host->f_max;
|
||||||
|
}
|
||||||
|
func->card->host->ios.clock = hz;
|
||||||
|
func->card->host->ops->set_ios(func->card->host, &func->card->host->ios);
|
||||||
|
}
|
||||||
|
static inline int hgic_mmc_send_cmd(struct sdio_func_t *func, struct mmc_command_t *cmd, int retries)
|
||||||
|
{
|
||||||
|
return mmc_wait_for_cmd(func->card->host, cmd, retries);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int hgic_mmc_io_rw_direct(struct sdio_func_t *func, int write, unsigned fn,
|
||||||
|
unsigned addr, u8 in, u8 *out)
|
||||||
|
{
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (addr & ~0x1FFFF) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.opcode = SD_IO_RW_DIRECT;
|
||||||
|
cmd.arg = write ? 0x80000000 : 0x00000000;
|
||||||
|
cmd.arg |= fn << 28;
|
||||||
|
cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
|
||||||
|
cmd.arg |= addr << 9;
|
||||||
|
cmd.arg |= in;
|
||||||
|
cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
|
||||||
|
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 0);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgic_host_is_spi(func)) {
|
||||||
|
/* host driver already reported errors */
|
||||||
|
} else {
|
||||||
|
if (cmd.resp[0] & R5_ERROR) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (cmd.resp[0] & R5_OUT_OF_RANGE) {
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
if (hgic_host_is_spi(func)) {
|
||||||
|
*out = (cmd.resp[0] >> 8) & 0xFF;
|
||||||
|
} else {
|
||||||
|
*out = cmd.resp[0] & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_reset(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u8 abort;
|
||||||
|
|
||||||
|
/* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
|
||||||
|
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
|
||||||
|
if (ret) {
|
||||||
|
abort = 0x08;
|
||||||
|
} else {
|
||||||
|
abort |= 0x08;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_go_idle(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
cmd.opcode = MMC_GO_IDLE_STATE;
|
||||||
|
cmd.arg = 0;
|
||||||
|
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 0);
|
||||||
|
msleep(1);
|
||||||
|
HOST_SPI_CRC(func, 0);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_mmc_send_if_cond(struct sdio_func_t *func, u32 ocr)
|
||||||
|
{
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
int err;
|
||||||
|
static const u8 test_pattern = 0xAA;
|
||||||
|
u8 result_pattern;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
|
||||||
|
* before SD_APP_OP_COND. This command will harmlessly fail for
|
||||||
|
* SD 1.0 cards.
|
||||||
|
*/
|
||||||
|
cmd.opcode = SD_SEND_IF_COND;
|
||||||
|
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
|
||||||
|
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
|
||||||
|
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 0);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgic_host_is_spi(func)) {
|
||||||
|
result_pattern = cmd.resp[1] & 0xFF;
|
||||||
|
} else {
|
||||||
|
result_pattern = cmd.resp[0] & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result_pattern != test_pattern) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_send_io_op_cond(struct sdio_func_t *func, u32 ocr, u32 *rocr)
|
||||||
|
{
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
int i, err = 0;
|
||||||
|
|
||||||
|
BUG_ON(!func);
|
||||||
|
|
||||||
|
cmd.opcode = SD_IO_SEND_OP_COND;
|
||||||
|
cmd.arg = ocr;
|
||||||
|
cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
|
||||||
|
|
||||||
|
for (i = 10; i; i--) {
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 3);
|
||||||
|
if (err) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we're just probing, do a single pass */
|
||||||
|
if (ocr == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise wait until reset completes */
|
||||||
|
if (hgic_host_is_spi(func)) {
|
||||||
|
/*
|
||||||
|
* Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
|
||||||
|
* an initialized card under SPI, but some cards
|
||||||
|
* (Marvell's) only behave when looking at this
|
||||||
|
* one.
|
||||||
|
*/
|
||||||
|
if (cmd.resp[1] & MMC_CARD_BUSY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cmd.resp[0] & MMC_CARD_BUSY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = -ETIMEDOUT;
|
||||||
|
|
||||||
|
mdelay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rocr) {
|
||||||
|
*rocr = cmd.resp[hgic_host_is_spi(func) ? 1 : 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hgic_sdio_get_card_addr(struct sdio_func_t *func, u32 *rca)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
cmd.opcode = SD_SEND_RELATIVE_ADDR;
|
||||||
|
cmd.arg = 0;
|
||||||
|
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 3);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
*rca = cmd.resp[0] >> 16;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 hgic_sdio_set_highspeed(struct sdio_func_t *func, int enable)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u8 speed;
|
||||||
|
|
||||||
|
if (!hgic_host_highspeed(func)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hgic_card_cccr_highspeed(func)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
speed |= SDIO_SPEED_EHS;
|
||||||
|
} else {
|
||||||
|
speed &= ~SDIO_SPEED_EHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_card_set_highspeed(func);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_disable_cd(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u8 ctrl;
|
||||||
|
|
||||||
|
if (!hgic_card_disable_cd(func)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ctrl |= SDIO_BUS_CD_DISABLE;
|
||||||
|
return hgic_mmc_io_rw_direct(func, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_set_wire_width(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u8 ctrl;
|
||||||
|
|
||||||
|
if (!hgic_host_supp_4bit(func)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgic_card_cccr_widebus(func)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set as 4-bit bus width */
|
||||||
|
ctrl &= ~ SDIO_BUS_WIDTH_MASK;
|
||||||
|
ctrl |= SDIO_BUS_WIDTH_4BIT;
|
||||||
|
ret = hgic_mmc_io_rw_direct(func, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_mmc_set_bus_width(func, MMC_BUS_WIDTH_4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 hgic_sdio_select_card(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
|
||||||
|
cmd.opcode = MMC_SELECT_CARD;
|
||||||
|
if (func) {
|
||||||
|
cmd.arg = hgic_func_rca(func) << 16;
|
||||||
|
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||||
|
} else {
|
||||||
|
cmd.arg = 0;
|
||||||
|
cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 3);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_int_enable(struct sdio_func_t *func, u8 enable)
|
||||||
|
{
|
||||||
|
u8 temp;
|
||||||
|
u8 dat;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
dat = (1 << func->f_num) | 0x1;
|
||||||
|
} else {
|
||||||
|
dat = 0x1;
|
||||||
|
}
|
||||||
|
return hgic_mmc_io_rw_direct(func, 1, 0, SDIO_CCCR_IENx, dat, &temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_mmc_spi_set_crc(struct sdio_func_t *func, int use_crc)
|
||||||
|
{
|
||||||
|
struct mmc_command_t cmd = {0};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
cmd.opcode = MMC_SPI_CRC_ON_OFF;
|
||||||
|
cmd.flags = MMC_RSP_SPI_R1;
|
||||||
|
cmd.arg = use_crc;
|
||||||
|
|
||||||
|
err = hgic_mmc_send_cmd(func, &cmd, 0);
|
||||||
|
if (!err) {
|
||||||
|
HOST_SPI_CRC(func, use_crc);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hgic_sdio_reinit_card(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int i = 3;
|
||||||
|
u32 ocr = 0;
|
||||||
|
int retry = 0;
|
||||||
|
struct hgic_sdio *sdiodev = sdio_get_drvdata(func);
|
||||||
|
u32 rca = 0;
|
||||||
|
|
||||||
|
hgic_enter();
|
||||||
|
__RETRY:
|
||||||
|
if (!sdiodev ||
|
||||||
|
test_bit(HGIC_BUS_FLAGS_DISABLE_REINIT, &sdiodev->bus.flags) ||
|
||||||
|
test_bit(HGIC_BUS_FLAGS_SLEEP, &sdiodev->bus.flags)) {
|
||||||
|
hgic_err("leave, can not reinit\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (retry++ > 2) {
|
||||||
|
hgic_err("leave, reinit fail\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 5;
|
||||||
|
ocr = 0;
|
||||||
|
hgic_mmc_set_clock(func, 400000);
|
||||||
|
hgic_mmc_set_timing(func, MMC_TIMING_LEGACY);
|
||||||
|
hgic_mmc_set_bus_width(func, MMC_BUS_WIDTH_1);
|
||||||
|
|
||||||
|
hgic_sdio_reset(func);
|
||||||
|
hgic_sdio_go_idle(func);
|
||||||
|
hgic_mmc_send_if_cond(func, ocr);
|
||||||
|
|
||||||
|
if (hgic_send_io_op_cond(func, 0, (u32 *)&ocr)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
if (hgic_send_io_op_cond(func, hgic_card_ocr(func), (u32 *)&ocr)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgic_host_is_spi(func)) {
|
||||||
|
if (hgic_mmc_spi_set_crc(func, 1)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rca = hgic_func_rca(func);
|
||||||
|
if (hgic_sdio_get_card_addr(func, (u32 *)&rca)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
if (hgic_sdio_select_card(func)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
if (hgic_sdio_disable_cd(func) < 0) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hgic_sdio_set_highspeed(func, 1) < 0) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_mmc_set_clock(func, hgic_card_highspeed(func) ? 50000000 : hgic_card_max_clock(func));
|
||||||
|
hgic_mmc_set_timing(func, MMC_TIMING_SD_HS);
|
||||||
|
if (hgic_sdio_set_wire_width(func) < 0) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
if (sdio_set_block_size(func, SDIO_BLOCK_SIZE)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
if (hgic_sdio_int_enable(func, 1)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
if (sdio_enable_func(func)) {
|
||||||
|
goto __RETRY;
|
||||||
|
}
|
||||||
|
hgic_leave();
|
||||||
|
#ifndef __RTOS__
|
||||||
|
if (func->card->host->sdio_irq_thread) {
|
||||||
|
wake_up_process(func->card->host->sdio_irq_thread);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_reinit(void *bus)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct hgic_sdio *sdiodev = container_of(bus, struct hgic_sdio, bus);
|
||||||
|
sdio_claim_host(sdiodev->func);
|
||||||
|
ret = hgic_sdio_reinit_card(sdiodev->func);
|
||||||
|
sdio_release_host(sdiodev->func);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_readb(struct sdio_func_t *func, u32 addr, int *err)
|
||||||
|
{
|
||||||
|
u8 val = 0;
|
||||||
|
int retry = 2;
|
||||||
|
|
||||||
|
val = sdio_readb(func, addr, err);
|
||||||
|
if (val == 0) { *err = -1; } //if read 0, try again.
|
||||||
|
while (*err && retry-- > 0) {
|
||||||
|
val = sdio_readb(func, addr, err);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_sdio_writeb(struct sdio_func_t *func, u8 b, u32 addr, int *err)
|
||||||
|
{
|
||||||
|
int retry = 4;
|
||||||
|
do {
|
||||||
|
sdio_writeb(func, b, addr, err);
|
||||||
|
} while (*err && retry-- > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_copy_fromio(struct sdio_func_t *func, u8 *dest, u32 addr, int count)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
err = sdio_memcpy_fromio(func, dest, addr, count);
|
||||||
|
if (err) {
|
||||||
|
hgic_err("err=%d\r\n", err);
|
||||||
|
hgic_sdio_reinit_card(func);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_copy_toio(struct sdio_func_t *func, u32 addr, u8 *src, int count)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
err = sdio_memcpy_toio(func, addr, src, count);
|
||||||
|
if (err) {
|
||||||
|
hgic_err("err=%d\r\n", err);
|
||||||
|
if (!hgic_sdio_reinit_card(func)) {
|
||||||
|
err = sdio_memcpy_toio(func, addr, src, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_abort(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int err_ret = 0;
|
||||||
|
struct sdio_func_t func0;
|
||||||
|
memcpy(&func0, func, sizeof(func0));
|
||||||
|
func0.f_num = 0;
|
||||||
|
hgic_sdio_writeb(&func0, 1, 6, &err_ret);
|
||||||
|
return err_ret;
|
||||||
|
}
|
||||||
|
static int hgic_sdio_read_cccr(struct sdio_func_t *func, u8 *pending)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct sdio_func_t func0;
|
||||||
|
memcpy(&func0, func, sizeof(func0));
|
||||||
|
func0.f_num = 0;
|
||||||
|
*pending = hgic_sdio_readb(&func0, 0x5, &ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 hgic_sdio_data_len(struct hgic_sdio *sdiodev)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
u32 len = 0;
|
||||||
|
u8 ret = 0;
|
||||||
|
u16 addr = test_bit(HGIC_BUS_FLAGS_INBOOT, &sdiodev->bus.flags) ?
|
||||||
|
sdiodev->trans_cnt_addr : SDIO_TRANS_COUNT_ADDR2;
|
||||||
|
|
||||||
|
ret = hgic_sdio_readb(sdiodev->func, addr, &err);
|
||||||
|
if (err) { return 0xffffffff; }
|
||||||
|
len = ret;
|
||||||
|
ret = hgic_sdio_readb(sdiodev->func, addr + 1, &err);
|
||||||
|
if (err) { return 0xffffffff; }
|
||||||
|
len |= ret << 8;
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
if (test_bit(HGIC_BUS_FLAGS_INBOOT, &sdiodev->bus.flags)) {
|
||||||
|
len = 16;
|
||||||
|
} else {
|
||||||
|
len = 0xFFFFFFFF;
|
||||||
|
hgic_err("get len error\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hgic_sdio_is_data_ready(struct hgic_sdio *sdiodev, struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u8 pending = 0;
|
||||||
|
u8 int_status1 = 0;
|
||||||
|
u8 int_status2 = 0;
|
||||||
|
|
||||||
|
ret = hgic_sdio_read_cccr(func, &pending);
|
||||||
|
if (!ret && (pending & 02)) {
|
||||||
|
int_status1 = sdio_readb(func, sdiodev->int_status_addr, &ret);
|
||||||
|
if (ret) { int_status1 = sdio_readb(func, sdiodev->int_status_addr, &ret); }
|
||||||
|
int_status1 &= SDIO_INIT_STATUS_DATA_READY;
|
||||||
|
if (!ret && !int_status1 && !test_bit(HGIC_BUS_FLAGS_INBOOT, &sdiodev->bus.flags)) {
|
||||||
|
int_status2 = hgic_sdio_readb(func, SDIO_INIT_STATUS_ADDR2, &ret);
|
||||||
|
if (int_status1 != int_status2) {
|
||||||
|
hgic_err("INTID(%x:%x)\r\n", int_status1, int_status2);
|
||||||
|
int_status1 = int_status2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!int_status1) { hgic_sdio_abort(func); }
|
||||||
|
}
|
||||||
|
return int_status1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_sdio_interrupt(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u32 len = 0;
|
||||||
|
int read_more = 0;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct hgic_sdio *sdiodev = sdio_get_drvdata(func);
|
||||||
|
|
||||||
|
if (sdiodev == NULL || (sdiodev->status&SDIO_STATUS_STOP) || test_bit(HGIC_BUS_FLAGS_SLEEP, &sdiodev->bus.flags)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
read_more = sdiodev->rx_retry;
|
||||||
|
do {
|
||||||
|
if (hgic_sdio_is_data_ready(sdiodev, func)) {
|
||||||
|
read_more = sdiodev->rx_retry;
|
||||||
|
len = hgic_sdio_data_len(sdiodev);
|
||||||
|
if (len == 0xFFFFFFFF) {
|
||||||
|
hgic_err("data len error\r\n");
|
||||||
|
hgic_sdio_abort(func);
|
||||||
|
hgic_sdio_reinit_card(func);
|
||||||
|
return;
|
||||||
|
} else if (len > 0) {
|
||||||
|
skb = dev_alloc_skb(len);
|
||||||
|
if (skb == NULL) {
|
||||||
|
hgic_err("no memory\r\n");
|
||||||
|
hgic_sdio_abort(func);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = hgic_sdio_copy_fromio(sdiodev->func, skb->data,
|
||||||
|
sdiodev->data_addr, len);
|
||||||
|
if (ret) {
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
hgic_err("sdio_copy_fromio err!, ret:%d\r\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = sdiodev->bus.rx_packet(sdiodev->bus.bus_priv, skb, len);
|
||||||
|
if (ret) {
|
||||||
|
hgic_sdio_abort(func);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hgic_sdio_abort(func);
|
||||||
|
}
|
||||||
|
} else if (read_more > 0) {
|
||||||
|
udelay(20);
|
||||||
|
}
|
||||||
|
} while (!ret && read_more-- > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_sdio_tx_packet(void *bus, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct hgic_sdio *sdiodev = container_of(bus, struct hgic_sdio, bus);
|
||||||
|
int len = skb->len > SDIO_BLOCK_SIZE ? ALIGN(skb->len, SDIO_BLOCK_SIZE) : ALIGN(skb->len, 4);
|
||||||
|
|
||||||
|
sdio_claim_host(sdiodev->func);
|
||||||
|
if ((sdiodev->status & SDIO_STATUS_STOP) || test_bit(HGIC_BUS_FLAGS_SLEEP, &sdiodev->bus.flags)) {
|
||||||
|
sdiodev->bus.tx_complete(sdiodev->bus.bus_priv, skb, 0);
|
||||||
|
sdio_release_host(sdiodev->func);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = hgic_sdio_copy_toio(sdiodev->func, sdiodev->data_addr, skb->data, len);
|
||||||
|
sdio_release_host(sdiodev->func);
|
||||||
|
sdiodev->bus.tx_complete(sdiodev->bus.bus_priv, skb, !ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hgic_bus hgic_ifbus_sdio = {
|
||||||
|
.type = HGIC_BUS_SDIO,
|
||||||
|
.drv_tx_headroom = SDIO_TX_HEADROM,
|
||||||
|
.tx_packet = hgic_sdio_tx_packet,
|
||||||
|
.reinit = hgic_sdio_reinit,
|
||||||
|
.bootdl_pktlen = 32704,
|
||||||
|
.bootdl_cksum = HGIC_BUS_BOOTDL_CHECK_0XFD,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hgic_sdio_enable(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
sdio_claim_host(func);
|
||||||
|
ret = sdio_set_block_size(func, SDIO_BLOCK_SIZE);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("Set sdio block size %d failed: %d)\n", SDIO_BLOCK_SIZE, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = sdio_claim_irq(func, hgic_sdio_interrupt);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("Set sdio interrupte handle failed: %d\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = sdio_enable_func(func);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("enable sdio function failed: %d)\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hgic_dbg("ok\n");
|
||||||
|
|
||||||
|
out:
|
||||||
|
sdio_release_host(func);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgic_sdio_probe(struct sdio_func_t *func, const struct sdio_device_id_t *id)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct hgic_sdio *sdiodev = NULL;
|
||||||
|
|
||||||
|
hgic_dbg("Enter, func->num:%d, devid:%x\r\n", func->f_num, func->device_id);
|
||||||
|
if (func->f_num != 1) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdiodev = kzalloc(sizeof(struct hgic_sdio), GFP_KERNEL);
|
||||||
|
if (!sdiodev) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_dbg("new sdio card: vendor:%x, id:%x\n", id->vendor_id, id->device_id);
|
||||||
|
sdiodev->func = func;
|
||||||
|
sdiodev->data_addr = SDIO_DATA_ADDR;
|
||||||
|
sdiodev->trans_cnt_addr = SDIO_TRANS_COUNT_ADDR;
|
||||||
|
sdiodev->int_status_addr = SDIO_INIT_STATUS_ADDR;
|
||||||
|
sdiodev->status = SDIO_STATUS_STOP;
|
||||||
|
sdiodev->bus = hgic_ifbus_sdio;
|
||||||
|
sdiodev->bus.dev_id = id->device_id;
|
||||||
|
sdiodev->bus.blk_size = SDIO_BLOCK_SIZE;
|
||||||
|
sdiodev->rx_retry = SDIO_CAP_IRQ(func) ? 0 : 5;
|
||||||
|
if (!SDIO_CAP_POLL(func)) {
|
||||||
|
set_bit(HGIC_BUS_FLAGS_NOPOLL, &sdiodev->bus.flags);
|
||||||
|
}
|
||||||
|
if (hgic_host_is_spi(func)) {
|
||||||
|
sdiodev->bus.bootdl_pktlen = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_core_probe(FUNC_DEV(func), &sdiodev->bus);
|
||||||
|
if (sdiodev->bus.bus_priv == NULL) {
|
||||||
|
hgic_err("err\r\n");
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdio_set_drvdata(func, sdiodev);
|
||||||
|
ret = hgic_sdio_enable(func);
|
||||||
|
if (ret) {
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdiodev->status &= ~SDIO_STATUS_STOP;
|
||||||
|
hgic_core_probe_post(sdiodev->bus.bus_priv);
|
||||||
|
hgic_dbg("ok\n");
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
__failed:
|
||||||
|
hgic_dbg("failed\n");
|
||||||
|
sdio_set_drvdata(func, NULL);
|
||||||
|
hgic_core_remove(sdiodev->bus.bus_priv);
|
||||||
|
kfree(sdiodev);
|
||||||
|
hgic_dbg("failed 2\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_sdio_remove(struct sdio_func_t *func)
|
||||||
|
{
|
||||||
|
struct hgic_sdio *sdiodev = NULL;
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
sdiodev = (struct hgic_sdio *)sdio_get_drvdata(func);
|
||||||
|
if (sdiodev) {
|
||||||
|
set_bit(HGIC_BUS_FLAGS_DISABLE_REINIT, &sdiodev->bus.flags);
|
||||||
|
sdiodev->status |= SDIO_STATUS_STOP;
|
||||||
|
hgic_dbg("remove ... 1\n");
|
||||||
|
sdio_claim_host(func);
|
||||||
|
sdio_release_irq(func);
|
||||||
|
sdio_release_host(func);
|
||||||
|
hgic_dbg("remove ... 2\n");
|
||||||
|
hgic_core_remove(sdiodev->bus.bus_priv);
|
||||||
|
hgic_dbg("remove ... 3\n");
|
||||||
|
sdio_claim_host(func);
|
||||||
|
sdio_set_drvdata(func, NULL);
|
||||||
|
kfree(sdiodev);
|
||||||
|
sdio_release_host(func);
|
||||||
|
hgic_dbg("remove ... 4\n");
|
||||||
|
}
|
||||||
|
hgic_dbg("Leave\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int hgic_sdio_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct sdio_func_t *func = dev_to_sdio_func(dev);
|
||||||
|
struct hgic_sdio *sdiodev = (struct hgic_sdio *)sdio_get_drvdata(func);
|
||||||
|
ret = hgic_core_suspend(sdiodev->bus.bus_priv);
|
||||||
|
sdio_claim_host(func);
|
||||||
|
ret = sdio_release_irq(func);
|
||||||
|
sdio_release_host(func);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static int hgic_sdio_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct sdio_func_t *func = dev_to_sdio_func(dev);
|
||||||
|
struct hgic_sdio *sdiodev = (struct hgic_sdio *)sdio_get_drvdata(func);
|
||||||
|
sdio_claim_host(func);
|
||||||
|
ret = sdio_claim_irq(func, hgic_sdio_interrupt);
|
||||||
|
sdio_release_host(func);
|
||||||
|
ret = hgic_core_resume(sdiodev->bus.bus_priv);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static const struct dev_pm_ops hgic_sdio_pm_ops = {
|
||||||
|
.suspend = hgic_sdio_suspend,
|
||||||
|
.resume = hgic_sdio_resume,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef SDIO_DRIVER_EXT
|
||||||
|
extern struct sdio_driver_t hgic_sdio_driver;
|
||||||
|
#else
|
||||||
|
static struct sdio_driver_t hgic_sdio_driver = {
|
||||||
|
.name = "hgic_sdio_wlan",
|
||||||
|
.id_table = hgic_sdio_wdev_ids,
|
||||||
|
.probe = hgic_sdio_probe,
|
||||||
|
.remove = hgic_sdio_remove,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.drv = {
|
||||||
|
.pm = &hgic_sdio_pm_ops,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int __init hgic_sdio_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
ret = sdio_register_driver(&hgic_sdio_driver);
|
||||||
|
hgic_dbg("Leave\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __exit hgic_sdio_exit(void)
|
||||||
|
{
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
sdio_unregister_driver(&hgic_sdio_driver);
|
||||||
|
hgic_dbg("Leave\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_HGIC_SDIOIN
|
||||||
|
module_init(hgic_sdio_init);
|
||||||
|
module_exit(hgic_sdio_exit);
|
||||||
|
MODULE_DESCRIPTION("HUGE-IC WLAN Driver");
|
||||||
|
MODULE_AUTHOR("Dongyun");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
#endif
|
||||||
|
|
378
utils/if_usb.c
Normal file
378
utils/if_usb.c
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(3,0,0)
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#else
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define HGIC_PKT_MAX_LEN 2048
|
||||||
|
#define HGIC_TX_URB_CNT 64
|
||||||
|
#define HGIC_RX_URB_CNT 64
|
||||||
|
|
||||||
|
#define HGIC_USB_STATUS_STOP BIT(0)
|
||||||
|
#define HGIC_USB_STATUS_ERR BIT(1)
|
||||||
|
|
||||||
|
#define HGIC_USB_BUF_FLAG_USED 0x00000001
|
||||||
|
#define USB_TX_HEADROM 4
|
||||||
|
|
||||||
|
struct hgic_usb_buf {
|
||||||
|
struct list_head list;
|
||||||
|
struct hgic_usb *usbdev;
|
||||||
|
struct urb *urb;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_usb {
|
||||||
|
struct usb_device *udev;
|
||||||
|
uint ep_in, ep_out;
|
||||||
|
uint ep_out_size, ep_in_size;
|
||||||
|
uint status;
|
||||||
|
struct list_head tx_freeq;
|
||||||
|
struct list_head rx_freeq;
|
||||||
|
struct list_head used;
|
||||||
|
struct semaphore tx_sema;
|
||||||
|
spinlock_t qlock;
|
||||||
|
struct hgic_bus bus;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int txq_cnt = HGIC_TX_URB_CNT;
|
||||||
|
static int rxq_cnt = HGIC_RX_URB_CNT;
|
||||||
|
|
||||||
|
static const struct usb_device_id hgic_usb_wdev_ids[] = {
|
||||||
|
{ USB_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_AH_4001) },
|
||||||
|
{ USB_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_AH_4002) },
|
||||||
|
{ USB_DEVICE(HGIC_VENDOR_ID, HGIC_WLAN_AH_4102) },
|
||||||
|
{ /* end: all zeroes */ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(usb, hgic_usb_wdev_ids);
|
||||||
|
static void hgic_usb_receive(struct urb *urb);
|
||||||
|
|
||||||
|
static void hgic_usb_free(struct hgic_usb *usbdev)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct hgic_usb_buf *buf, *n;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&usbdev->qlock, flags);
|
||||||
|
list_for_each_entry_safe(buf, n, &usbdev->tx_freeq, list) {
|
||||||
|
list_del(&buf->list);
|
||||||
|
usb_free_urb(buf->urb);
|
||||||
|
kfree(buf);
|
||||||
|
//hgic_dbg("free usb tx buff\r\n");
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(buf, n, &usbdev->rx_freeq, list) {
|
||||||
|
list_del(&buf->list);
|
||||||
|
usb_free_urb(buf->urb);
|
||||||
|
kfree(buf);
|
||||||
|
//hgic_dbg("free usb rx buff\r\n");
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(buf, n, &usbdev->used, list) {
|
||||||
|
usb_kill_urb(buf->urb);
|
||||||
|
list_del(&buf->list);
|
||||||
|
usb_free_urb(buf->urb);
|
||||||
|
kfree(buf);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&usbdev->qlock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_usb_qinit(struct hgic_usb *usb, struct list_head *q, int qsize)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
struct hgic_usb_buf *buf = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < qsize; i++) {
|
||||||
|
buf = kzalloc(sizeof(struct hgic_usb_buf), GFP_ATOMIC);
|
||||||
|
if (buf == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->usbdev = usb;
|
||||||
|
buf->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (buf->urb) {
|
||||||
|
list_add_tail(&buf->list, q);
|
||||||
|
} else {
|
||||||
|
kfree(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hgic_usb_buf *hgic_usb_deq(struct hgic_usb *usbdev, struct list_head *q)
|
||||||
|
{
|
||||||
|
struct hgic_usb_buf *buf = NULL;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&usbdev->qlock, flags);
|
||||||
|
if (!list_empty(q)) {
|
||||||
|
buf = list_first_entry(q, struct hgic_usb_buf, list);
|
||||||
|
buf->flag |= HGIC_USB_BUF_FLAG_USED;
|
||||||
|
list_del(&buf->list);
|
||||||
|
list_add_tail(&buf->list, &usbdev->used);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&usbdev->qlock, flags);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_usb_enq(struct hgic_usb_buf *buf, struct list_head *q)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&buf->usbdev->qlock, flags);
|
||||||
|
buf->skb = NULL;
|
||||||
|
buf->flag &= ~HGIC_USB_BUF_FLAG_USED;
|
||||||
|
list_del(&buf->list);
|
||||||
|
list_add_tail(&buf->list, q);
|
||||||
|
spin_unlock_irqrestore(&buf->usbdev->qlock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_usb_submit_rx_urb(struct hgic_usb_buf *buf)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
buf->skb = dev_alloc_skb(HGIC_PKT_MAX_LEN);
|
||||||
|
if (!buf->skb) {
|
||||||
|
hgic_err("alloc skb failed\r\n");
|
||||||
|
hgic_usb_enq(buf, &buf->usbdev->rx_freeq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
usb_fill_bulk_urb(buf->urb, buf->usbdev->udev,
|
||||||
|
usb_rcvbulkpipe(buf->usbdev->udev, buf->usbdev->ep_in),
|
||||||
|
buf->skb->data, HGIC_PKT_MAX_LEN, hgic_usb_receive, buf);
|
||||||
|
ret = usb_submit_urb(buf->urb, GFP_ATOMIC);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("submit rx urb failed: %d\n", ret);
|
||||||
|
dev_kfree_skb_any(buf->skb);
|
||||||
|
hgic_usb_enq(buf, &buf->usbdev->rx_freeq);
|
||||||
|
buf->usbdev->status |= HGIC_USB_STATUS_ERR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_usb_submit_rx_urbs(struct hgic_usb *usbdev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct hgic_usb_buf *buf = NULL;
|
||||||
|
|
||||||
|
while ((buf = hgic_usb_deq(usbdev, &usbdev->rx_freeq))) {
|
||||||
|
ret = hgic_usb_submit_rx_urb(buf);
|
||||||
|
if (ret) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_usb_receive(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct hgic_usb_buf *buf = (struct hgic_usb_buf *)urb->context;
|
||||||
|
|
||||||
|
if (buf->usbdev->status & (HGIC_USB_STATUS_STOP | HGIC_USB_STATUS_ERR)) {
|
||||||
|
dev_kfree_skb_any(buf->skb);
|
||||||
|
hgic_usb_enq(buf, &buf->usbdev->rx_freeq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urb->actual_length > 0) {
|
||||||
|
buf->usbdev->bus.rx_packet(buf->usbdev->bus.bus_priv, buf->skb, urb->actual_length);
|
||||||
|
} else {
|
||||||
|
dev_kfree_skb_any(buf->skb);
|
||||||
|
}
|
||||||
|
hgic_usb_submit_rx_urb(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_usb_tx_complete(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct hgic_usb_buf *buf = (struct hgic_usb_buf *)urb->context;
|
||||||
|
//hgic_skip_padding(buf->skb);
|
||||||
|
buf->usbdev->bus.tx_complete(buf->usbdev->bus.bus_priv, buf->skb, !urb->status);
|
||||||
|
hgic_usb_enq(buf, &buf->usbdev->tx_freeq);
|
||||||
|
up(&buf->usbdev->tx_sema);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hgic_usb_tx_packet(void *bus, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int len = ALIGN(skb->len, 4);
|
||||||
|
struct hgic_usb_buf *buf = NULL;
|
||||||
|
struct hgic_usb *usbdev = container_of(bus, struct hgic_usb, bus);
|
||||||
|
|
||||||
|
if ((len & (usbdev->ep_out_size - 1)) == 0) {
|
||||||
|
len += 4;
|
||||||
|
}
|
||||||
|
if (usbdev->status & (HGIC_USB_STATUS_STOP | HGIC_USB_STATUS_ERR)) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = down_timeout(&usbdev->tx_sema, 1000);
|
||||||
|
if(ret){
|
||||||
|
ret = -EIO;
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = hgic_usb_deq(usbdev, &usbdev->tx_freeq);
|
||||||
|
if (buf == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
buf->skb = skb;
|
||||||
|
usb_fill_bulk_urb(buf->urb, usbdev->udev,
|
||||||
|
usb_sndbulkpipe(usbdev->udev, usbdev->ep_out),
|
||||||
|
skb->data, len, /*ALIGN(skb->len, 4)*/
|
||||||
|
hgic_usb_tx_complete, buf);
|
||||||
|
buf->urb->transfer_flags |= URB_ZERO_PACKET;
|
||||||
|
ret = usb_submit_urb(buf->urb, GFP_ATOMIC);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("usb_submit_urb failed, ret:%d\n", ret);
|
||||||
|
goto __fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
__fail:
|
||||||
|
if (buf) {
|
||||||
|
hgic_usb_enq(buf, &usbdev->tx_freeq);
|
||||||
|
}
|
||||||
|
usbdev->bus.tx_complete(usbdev->bus.bus_priv, skb, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hgic_bus hgic_bus_usb = {
|
||||||
|
.type = HGIC_BUS_USB,
|
||||||
|
.drv_tx_headroom = USB_TX_HEADROM,
|
||||||
|
.tx_packet = hgic_usb_tx_packet,
|
||||||
|
.bootdl_pktlen = 2048,
|
||||||
|
.bootdl_cksum = HGIC_BUS_BOOTDL_CHECK_0XFD,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hgic_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int ret = 0;
|
||||||
|
struct usb_device *udev = NULL;
|
||||||
|
struct hgic_usb *usbdev = NULL;
|
||||||
|
struct usb_host_interface *iface_desc = NULL;
|
||||||
|
struct usb_endpoint_descriptor *endpoint = NULL;
|
||||||
|
|
||||||
|
hgic_dbg("new usb card: vendor:%x, id:%x\n", id->idVendor, id->idProduct);
|
||||||
|
udev = interface_to_usbdev(intf);
|
||||||
|
iface_desc = intf->cur_altsetting;
|
||||||
|
usbdev = kzalloc(sizeof(struct hgic_usb), GFP_KERNEL);
|
||||||
|
if (!usbdev) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(usbdev, 0, sizeof(struct hgic_usb));
|
||||||
|
usbdev->udev = udev;
|
||||||
|
usbdev->bus = hgic_bus_usb;
|
||||||
|
usbdev->bus.dev_id = id->idProduct;
|
||||||
|
usbdev->status = HGIC_USB_STATUS_STOP;
|
||||||
|
|
||||||
|
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||||
|
endpoint = &iface_desc->endpoint[i].desc;
|
||||||
|
if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||||
|
usbdev->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||||
|
usbdev->ep_in = usb_endpoint_num(endpoint);
|
||||||
|
hgic_dbg("IN BULK: ep_in_size:%x, ep_in:%x\n", usbdev->ep_in_size, usbdev->ep_in);
|
||||||
|
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
||||||
|
usbdev->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||||
|
usbdev->ep_out = usb_endpoint_num(endpoint);
|
||||||
|
hgic_dbg("OUT BULK: ep_out_size:%x, ep_out:%x\n", usbdev->ep_out_size, usbdev->ep_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usbdev->bus.blk_size = usbdev->ep_out_size;
|
||||||
|
|
||||||
|
spin_lock_init(&usbdev->qlock);
|
||||||
|
INIT_LIST_HEAD(&usbdev->tx_freeq);
|
||||||
|
INIT_LIST_HEAD(&usbdev->rx_freeq);
|
||||||
|
INIT_LIST_HEAD(&usbdev->used);
|
||||||
|
ret = hgic_usb_qinit(usbdev, &usbdev->tx_freeq, txq_cnt);
|
||||||
|
sema_init(&usbdev->tx_sema, ret);
|
||||||
|
hgic_dbg("usb txq:%d\r\n", ret);
|
||||||
|
ret = hgic_usb_qinit(usbdev, &usbdev->rx_freeq, rxq_cnt);
|
||||||
|
hgic_dbg("usb rxq:%d\r\n", ret);
|
||||||
|
|
||||||
|
hgic_core_probe(&udev->dev, &usbdev->bus);
|
||||||
|
if (!usbdev->bus.bus_priv) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_usb_submit_rx_urbs(usbdev);
|
||||||
|
if (ret) {
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
usb_get_dev(udev);
|
||||||
|
usb_set_intfdata(intf, usbdev);
|
||||||
|
usbdev->status &= ~HGIC_USB_STATUS_STOP;
|
||||||
|
hgic_core_probe_post(usbdev->bus.bus_priv);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
__failed:
|
||||||
|
hgic_core_remove(usbdev->bus.bus_priv);
|
||||||
|
hgic_usb_free(usbdev);
|
||||||
|
kfree(usbdev);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_usb_disconnect(struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct hgic_usb *usbdev = usb_get_intfdata(intf);
|
||||||
|
hgic_dbg("hgic_usb_disconnect>>>>\r\n");
|
||||||
|
if (usbdev) {
|
||||||
|
usbdev->status |= HGIC_USB_STATUS_STOP;
|
||||||
|
hgic_core_remove(usbdev->bus.bus_priv);
|
||||||
|
hgic_usb_free(usbdev);
|
||||||
|
kfree(usbdev);
|
||||||
|
usb_set_intfdata(intf, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct usb_driver hgic_usb_driver = {
|
||||||
|
.name = KBUILD_MODNAME,
|
||||||
|
.probe = hgic_usb_probe,
|
||||||
|
.disconnect = hgic_usb_disconnect,
|
||||||
|
.id_table = hgic_usb_wdev_ids,
|
||||||
|
.suspend = NULL,
|
||||||
|
.resume = NULL,
|
||||||
|
.supports_autosuspend = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
int __init hgic_usb_init(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
ret = usb_register(&hgic_usb_driver);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("driver register failed: %d\n", ret);
|
||||||
|
}
|
||||||
|
hgic_dbg("Leave\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __exit hgic_usb_exit(void)
|
||||||
|
{
|
||||||
|
hgic_dbg("Enter\n");
|
||||||
|
usb_deregister(&hgic_usb_driver);
|
||||||
|
hgic_dbg("Leave\n");
|
||||||
|
}
|
||||||
|
#ifndef CONFIG_HGIC_USBIN
|
||||||
|
module_init(hgic_usb_init);
|
||||||
|
module_exit(hgic_usb_exit);
|
||||||
|
MODULE_DESCRIPTION("HUGE-IC WLAN Driver");
|
||||||
|
MODULE_AUTHOR("Dongyun");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
#endif
|
||||||
|
|
1428
utils/mmc_spi.c
Normal file
1428
utils/mmc_spi.c
Normal file
File diff suppressed because it is too large
Load diff
309
utils/ota.c
Normal file
309
utils/ota.c
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
#include "fwinfo.h"
|
||||||
|
#include "fwctrl.h"
|
||||||
|
#include "ota.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
static u16 hgic_ota_check_sum(u8 *addr, s32 count)
|
||||||
|
{
|
||||||
|
s32 sum = 0;
|
||||||
|
while (count > 1) {
|
||||||
|
sum = sum + *(u16 *)addr;
|
||||||
|
addr += 2;
|
||||||
|
count -= 2;
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
sum += *addr;
|
||||||
|
}
|
||||||
|
while (sum >> 16) {
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
}
|
||||||
|
return (u16)~sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *hgic_ota_send_packet_tmo(struct hgic_ota *ota, struct sk_buff *skb, u32 tmo)
|
||||||
|
{
|
||||||
|
struct hgic_cmd_response resp;
|
||||||
|
struct hgic_hdr *hdr = NULL;
|
||||||
|
|
||||||
|
hdr = (struct hgic_hdr *)skb_push(skb, sizeof(struct hgic_hdr));
|
||||||
|
hdr->magic = HGIC_HDR_TX_MAGIC;
|
||||||
|
hdr->type = HGIC_HDR_TYPE_OTA;
|
||||||
|
hdr->ifidx = HGIC_WDEV_ID_STA;
|
||||||
|
hdr->length = skb->len;
|
||||||
|
hdr->cookie = hgic_ctrl_cookie(ota->ctrl);
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
resp.cookie = hdr->cookie;
|
||||||
|
hgic_fwctrl_send_data(ota->ctrl, skb, &resp, tmo);
|
||||||
|
return resp.skb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hgic_ota_release_data(struct hgic_ota *ota)
|
||||||
|
{
|
||||||
|
hgic_dbg("Enter ...\n");
|
||||||
|
hgic_clear_queue(&ota->fw_dataq);
|
||||||
|
hgic_dbg("Leave ...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void hgic_ota_release(struct hgic_ota *ota)
|
||||||
|
{
|
||||||
|
hgic_dbg("Enter ...\n");
|
||||||
|
if (ota->inited) {
|
||||||
|
hgic_clear_queue(&ota->fw_dataq);
|
||||||
|
#ifdef __RTOS__
|
||||||
|
skb_queue_head_deinit(&ota->fw_dataq);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
hgic_dbg("Leave ...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 hgic_ota_init(struct hgic_ota *ota, struct hgic_fwctrl *ctrl, struct hgic_fw_info *fw_info)
|
||||||
|
{
|
||||||
|
hgic_dbg("Enter ...\n");
|
||||||
|
memset(ota, 0, sizeof(struct hgic_ota));
|
||||||
|
ota->frag_size = HG_OTA_FW_FLAGMENT_SIZE;
|
||||||
|
ota->ctrl = ctrl;
|
||||||
|
ota->ori_fw_info = fw_info;
|
||||||
|
ota->inited = 1;
|
||||||
|
skb_queue_head_init(&ota->fw_dataq);
|
||||||
|
hgic_dbg("Leave ...\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 hgic_ota_fill_hdr(struct hgic_ota *ota, struct sk_buff *skb, u32 offset)
|
||||||
|
{
|
||||||
|
struct hgic_ota_hdr *hdr = NULL;
|
||||||
|
u32 payload_len = 0;
|
||||||
|
|
||||||
|
if (ota == NULL || skb == NULL || skb->len > ota->frag_size) {
|
||||||
|
hgic_err("Input para error!\r\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (ota->fw_len == 0) {
|
||||||
|
hgic_err("ERROR:fw len is zero!\r\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
payload_len = skb->len;
|
||||||
|
|
||||||
|
hdr = (struct hgic_ota_hdr *)skb_push(skb, sizeof(struct hgic_ota_hdr));
|
||||||
|
memset(hdr, 0, sizeof(struct hgic_ota_hdr));
|
||||||
|
hdr->chipid = ota->ori_fw_info->chip_id;
|
||||||
|
hdr->len = payload_len;
|
||||||
|
hdr->tot_len = ota->fw_len;
|
||||||
|
hdr->off = offset;
|
||||||
|
hdr->version = ota->ori_fw_info->version;
|
||||||
|
hdr->checksum = hgic_ota_check_sum(hdr->data, hdr->len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 hgic_ota_check_hdr_info(struct hgic_ota *ota, const u8 *data)
|
||||||
|
{
|
||||||
|
u32 sdk_version = 0;
|
||||||
|
u32 svn_version = 0;
|
||||||
|
u16 chip_id = 0;
|
||||||
|
u8 cpu_id = 0;
|
||||||
|
s32 err_code = 0;
|
||||||
|
|
||||||
|
hgic_dbg("%s:Original fw info:%d.%d.%d.%d\r\n", __FUNCTION__,
|
||||||
|
(ota->ori_fw_info->version >> 24) & 0xff, (ota->ori_fw_info->version >> 16) & 0xff,
|
||||||
|
(ota->ori_fw_info->version >> 8) & 0xff, (ota->ori_fw_info->version & 0xff));
|
||||||
|
|
||||||
|
hgic_dbg("%s:Chip id:%x,cpu id:%d\r\n", __FUNCTION__,
|
||||||
|
ota->ori_fw_info->chip_id, ota->ori_fw_info->cpu_id);
|
||||||
|
|
||||||
|
sdk_version = hgic_get_fw_sdk_version(data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
hgic_err("%s:Get ota fw sdk version error!ret:%d\n", __FUNCTION__, err_code);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
if ((sdk_version & 0xff) != (ota->ori_fw_info->version & 0xff)) {
|
||||||
|
hgic_err("%s:firmware version not match!%x vs %x\n", __FUNCTION__, sdk_version & 0xff, ota->ori_fw_info->version & 0xff);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
svn_version = hgic_get_fw_svn_version(data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
hgic_err("%s:Get ota fw svn version error!ret:%d\n", __FUNCTION__, err_code);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip_id = hgic_get_fw_chipid(data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
hgic_err("%s:Get ota fw chip_id error!ret:%d\n", __FUNCTION__, err_code);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
if (chip_id != ota->ori_fw_info->chip_id) {
|
||||||
|
hgic_err("%s:firmware version not match!\n", __FUNCTION__);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_id = hgic_get_fw_cpuid(data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
hgic_err("%s:Get ota fw CPU id error!ret:%d\n", __FUNCTION__, err_code);
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
if (cpu_id != ota->ori_fw_info->cpu_id) {
|
||||||
|
hgic_err("%s:firmware CPU id not match!\n", __FUNCTION__);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 hgic_ota_parse_fw(struct hgic_ota *ota, char *fw_name)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
const struct firmware *fw;
|
||||||
|
u32 copy_len = 0;
|
||||||
|
u32 xfer_len = 0;
|
||||||
|
u32 addr_offset = 0;
|
||||||
|
s32 ret = 0;
|
||||||
|
const u8 *data;
|
||||||
|
const u32 hdr_len = sizeof(struct hgic_ota_hdr) + sizeof(struct hgic_hdr);
|
||||||
|
u32 fw_hdr_len = 0;
|
||||||
|
s32 err_code = 0;
|
||||||
|
s32 crc_result = 0;
|
||||||
|
|
||||||
|
if (ota == NULL) {
|
||||||
|
hgic_err("Input para error!\r\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hgic_dbg("Check para:fw_name:%s,hdr_len:%d\n", fw_name, hdr_len);
|
||||||
|
|
||||||
|
ret = request_firmware(&fw, (const char *)fw_name, ota->ctrl->dev);
|
||||||
|
if (ret) {
|
||||||
|
hgic_dbg("request_firmware failed!ret:%d\n", ret);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_ota_check_hdr_info(ota, fw->data);
|
||||||
|
if (ret != 0) {
|
||||||
|
hgic_err("hgic_ota_check_info error!\r\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
crc_result = hgic_get_fw_code_checksum(fw->data, fw->size);
|
||||||
|
if (crc_result) {
|
||||||
|
hgic_err("hgic_get_fw_code_checksum error!\r\n");
|
||||||
|
return crc_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_hdr_len = hgic_get_fw_code_offset(fw->data, &err_code);
|
||||||
|
if (err_code != 0) {
|
||||||
|
hgic_err("hgic_get_fw_code_offset error!\r\n");
|
||||||
|
return err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ota->fw_len = fw->size - fw_hdr_len;
|
||||||
|
ota->fw_len = fw->size;
|
||||||
|
copy_len = ota->fw_len;
|
||||||
|
data = (char *)fw->data;
|
||||||
|
hgic_dbg("Check fw para:fw_len:%d,each fragment size:%d\n", ota->fw_len, ota->frag_size);
|
||||||
|
|
||||||
|
while (copy_len) {
|
||||||
|
xfer_len = copy_len > ota->frag_size ? ota->frag_size : copy_len;
|
||||||
|
//hgic_dbg("Check xfer para:xfer_len:%d,offset:%d\n", xfer_len, addr_offset);
|
||||||
|
skb = dev_alloc_skb(xfer_len + hdr_len + 4);
|
||||||
|
if (skb == NULL) {
|
||||||
|
printk("%s: no memory\r\n", __FUNCTION__);
|
||||||
|
release_firmware(fw);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
skb_reserve(skb, hdr_len);
|
||||||
|
memcpy(skb->data, data + addr_offset, xfer_len);
|
||||||
|
skb_put(skb, xfer_len);
|
||||||
|
|
||||||
|
ret = hgic_ota_fill_hdr(ota, skb, addr_offset);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("hgic_ota_fill_frame_hdr error!\n");
|
||||||
|
release_firmware(fw);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb_queue_tail(&ota->fw_dataq, skb);
|
||||||
|
copy_len -= xfer_len;
|
||||||
|
addr_offset += xfer_len;
|
||||||
|
}
|
||||||
|
release_firmware(fw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 hgic_ota_send_fw(struct hgic_ota *ota, char *fw_name, u32 tmo)
|
||||||
|
{
|
||||||
|
s32 ret = 0;
|
||||||
|
struct sk_buff *resp = NULL;
|
||||||
|
struct hgic_ota_hdr *hdr = NULL;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
|
||||||
|
if (ota == NULL) {
|
||||||
|
printk("%s: Input para error!\r\n", __FUNCTION__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hgic_ota_parse_fw(ota, fw_name);
|
||||||
|
if (ret) {
|
||||||
|
hgic_err("Firmware parse error!\n");
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!skb_queue_empty(&ota->fw_dataq)) {
|
||||||
|
skb = skb_dequeue(&ota->fw_dataq);
|
||||||
|
resp = hgic_ota_send_packet_tmo(ota, skb, tmo);
|
||||||
|
if (resp) {
|
||||||
|
skb_pull(resp, sizeof(struct hgic_hdr));
|
||||||
|
hdr = (struct hgic_ota_hdr *)resp->data;
|
||||||
|
if (hdr->err_code) {
|
||||||
|
hgic_err("Responce Error:Error code:%d\n", hdr->err_code);
|
||||||
|
ret = hdr->err_code;
|
||||||
|
goto __failed;
|
||||||
|
} else {
|
||||||
|
hgic_dbg("OTA write to flash success!\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hgic_err("Get responce timeout or no responce!\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto __failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hgic_ota_release_data(ota);
|
||||||
|
hgic_dbg("hgic_ota_send_fw success!!!\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
__failed:
|
||||||
|
hgic_ota_release_data(ota);
|
||||||
|
hgic_dbg("hgic_ota_send_fw failed!!!\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __RTOS__
|
||||||
|
int hgic_ota_start(char *ifname, char *fw_name)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = net_device_get_by_name(ifname);
|
||||||
|
|
||||||
|
if (ndev) {
|
||||||
|
return hgic_ota_send_fw(hgic_devota(ndev), fw_name, HG_OTA_WRITE_MEM_TMO);
|
||||||
|
} else {
|
||||||
|
hgic_dbg("Can not find netdev name:%s\n",ifname);
|
||||||
|
}
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
29
utils/ota.h
Normal file
29
utils/ota.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef _HGIC_OTA_H_
|
||||||
|
#define _HGIC_OTA_H_
|
||||||
|
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
|
||||||
|
#define HG_OTA_WRITE_MEM_TMO 5000
|
||||||
|
#define HG_OTA_NORMAL_TMO 100
|
||||||
|
#define HG_OTA_FW_FLAGMENT_SIZE 1500
|
||||||
|
|
||||||
|
enum HGIC_OTA_RESP_ERR_CODE{
|
||||||
|
HGIC_OTA_RESP_ERR_OK=0,
|
||||||
|
HGIC_OTA_RESP_ERR_CHECKSUM,
|
||||||
|
HGIC_OTA_RESP_ERR_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_ota {
|
||||||
|
u32 inited;
|
||||||
|
struct sk_buff_head fw_dataq;
|
||||||
|
u32 frag_size;
|
||||||
|
u32 fw_len;
|
||||||
|
struct hgic_fwctrl *ctrl;
|
||||||
|
struct hgic_fw_info *ori_fw_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
s32 hgic_ota_init(struct hgic_ota *ota, struct hgic_fwctrl *ctrl, struct hgic_fw_info *fw_info);
|
||||||
|
void hgic_ota_release(struct hgic_ota *ota);
|
||||||
|
s32 hgic_ota_send_fw(struct hgic_ota *hg, char *fw_name, u32 tmo);
|
||||||
|
|
||||||
|
#endif
|
269
utils/utils.c
Normal file
269
utils/utils.c
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
#ifdef __RTOS__
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#ifdef HGIC_SMAC
|
||||||
|
#include "umac_config.h"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#endif
|
||||||
|
#include "utils.h"
|
||||||
|
#include "../hgic_def.h"
|
||||||
|
|
||||||
|
#define aSymbolLength 40
|
||||||
|
#define STATBUF_SIZE (64*1024)
|
||||||
|
#define SAFE_DIV(a, b) (((b) == 0) ? 0 : ((a) / (b)))
|
||||||
|
|
||||||
|
int hgic_skip_padding(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 3 && skb->data[i] == 0xFF; i++);
|
||||||
|
if (i) {
|
||||||
|
if (skb->len > 0) {
|
||||||
|
skb_pull(skb, i);
|
||||||
|
} else {
|
||||||
|
skb->data += i;
|
||||||
|
skb->tail += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_skip_padding);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int hgic_aligned_padding(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
uint32_t count = 0;
|
||||||
|
uint8_t *data = skb->data - 4;
|
||||||
|
if (!IS_ALIGNED((uint32_t)skb->data, 4)) {
|
||||||
|
count = (uint32_t)skb->data - (uint32_t)ALIGN((uint32_t)data, 4);
|
||||||
|
if (count > 0) {
|
||||||
|
skb_push(skb, count);
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
skb->data[i] = 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_aligned_padding);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void hgic_print_hex(char *buf, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (i > 0 && i % 16 == 0) { printk("\r\n"); }
|
||||||
|
else if (i > 0 && i % 8 == 0) { printk(" "); }
|
||||||
|
printk("%02x ", buf[i] & 0xff);
|
||||||
|
}
|
||||||
|
printk("\r\n\r\n");
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_print_hex);
|
||||||
|
|
||||||
|
int hgic_config_read_int(char *conf, char *field)
|
||||||
|
{
|
||||||
|
char *ptr = strstr(conf, field);
|
||||||
|
if (ptr) {
|
||||||
|
return simple_strtol(ptr + strlen(field) + 1, 0, 10);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_config_read_int);
|
||||||
|
|
||||||
|
int hgic_config_read_str(char *conf, char *field, char *str, int size)
|
||||||
|
{
|
||||||
|
char *ptr = strstr(conf, field);
|
||||||
|
if (ptr) {
|
||||||
|
ptr += strlen(field) + 1;
|
||||||
|
while (*ptr && *ptr != '\r' && *ptr != '\n' && size > 0) {
|
||||||
|
*str++ = *ptr++;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_config_read_str);
|
||||||
|
|
||||||
|
int hgic_config_read_u32_array(char *conf, char *field, u32 *arr, int count)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
int val = 0;
|
||||||
|
char *ptr = strstr(conf, field);
|
||||||
|
|
||||||
|
if (ptr) {
|
||||||
|
ptr += strlen(field) + 1;
|
||||||
|
while (cnt < count) {
|
||||||
|
while (*ptr >= '0' && *ptr <= '9') {
|
||||||
|
val *= 10;
|
||||||
|
val += (*ptr - 0x30);
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
if (val) {
|
||||||
|
arr[cnt++] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr != ',' || val == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_config_read_u32_array);
|
||||||
|
|
||||||
|
int hgic_config_read_u16_array(char *conf, char *field, u16 *arr, int count)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
int val = 0;
|
||||||
|
char *ptr = strstr(conf, field);
|
||||||
|
|
||||||
|
if (ptr) {
|
||||||
|
ptr += strlen(field) + 1;
|
||||||
|
while (cnt < count) {
|
||||||
|
while (*ptr >= '0' && *ptr <= '9') {
|
||||||
|
val *= 10;
|
||||||
|
val += (*ptr - 0x30);
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
if (val) {
|
||||||
|
arr[cnt++] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr != ',' || val == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(hgic_config_read_u16_array);
|
||||||
|
|
||||||
|
void hgic_clear_queue(struct sk_buff_head *q)
|
||||||
|
{
|
||||||
|
ulong flags = 0;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct sk_buff *tmp = NULL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&q->lock, flags);
|
||||||
|
if (!skb_queue_empty(q)) {
|
||||||
|
skb_queue_walk_safe(q, skb, tmp) {
|
||||||
|
__skb_unlink(skb, q);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&q->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgic_hex2num(char c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
return c - '0';
|
||||||
|
}
|
||||||
|
if (c >= 'a' && c <= 'f') {
|
||||||
|
return c - 'a' + 10;
|
||||||
|
}
|
||||||
|
if (c >= 'A' && c <= 'F') {
|
||||||
|
return c - 'A' + 10;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hgic_hex2byte(const char *hex)
|
||||||
|
{
|
||||||
|
int a, b;
|
||||||
|
a = hgic_hex2num(*hex++);
|
||||||
|
if (a < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
b = hgic_hex2num(*hex++);
|
||||||
|
if (b < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (a << 4) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hgic_pick_macaddr(char *mac_str, u8 *addr)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int val = 0;
|
||||||
|
const char *ptr = (const char *)mac_str;
|
||||||
|
|
||||||
|
memset(addr, 0, 6);
|
||||||
|
while (ptr && i < 6 && strlen(mac_str) >= 17) {
|
||||||
|
if (i < 5 && ptr[2] != ':') { break; }
|
||||||
|
val = hgic_hex2byte(ptr);
|
||||||
|
if (val < 0) { break; }
|
||||||
|
addr[i++] = (u8)val;
|
||||||
|
ptr += 3;
|
||||||
|
}
|
||||||
|
return (i == 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__RTOS__) && defined(HGIC_SMAC)
|
||||||
|
int umac_config_read(const char *name, char *buff, int size)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct umac_config *cfg = sys_get_umaccfg();
|
||||||
|
struct net_device *ndev = net_device_get_by_name(name);
|
||||||
|
|
||||||
|
if (ndev == NULL) {
|
||||||
|
PRINTF("dev:%s is not exist!\r\n", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ndev->ifindex == 0) {
|
||||||
|
strcpy(buff, (const char *)cfg->hg0);
|
||||||
|
buff[strlen(cfg->hg0)] = 0;
|
||||||
|
} else if (ndev->ifindex == 1) {
|
||||||
|
strcpy(buff, (const char *)cfg->hg1);
|
||||||
|
buff[strlen(cfg->hg1)] = 0;
|
||||||
|
} else {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
PRINTF("read %s:\r\n%s\r\n", name, buff);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int umac_config_write(const char *name, char *buff, int size)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct umac_config *cfg = sys_get_umaccfg();
|
||||||
|
struct net_device *ndev = net_device_get_by_name(name);
|
||||||
|
|
||||||
|
PRINTF("write %s:\r\n%s\r\n", name, buff);
|
||||||
|
if (ndev == NULL) {
|
||||||
|
PRINTF("dev:%s is not exist!\r\n", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((ndev->ifindex == 0) && size < sizeof(cfg->hg0)) {
|
||||||
|
strcpy((char *)cfg->hg0, buff);
|
||||||
|
} else if ((ndev->ifindex == 1) && size < sizeof(cfg->hg1)) {
|
||||||
|
strcpy((char *)cfg->hg1, buff);
|
||||||
|
} else {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
ret = sys_save_umaccfg(cfg);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
180
utils/utils.h
Normal file
180
utils/utils.h
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
#ifndef _HGIC_UTILS_H_
|
||||||
|
#define _HGIC_UTILS_H_
|
||||||
|
|
||||||
|
#define AC_NUM 4
|
||||||
|
#define MAX_CHANS_NUM 16
|
||||||
|
|
||||||
|
struct hgic_fwstat_chaninfo {
|
||||||
|
u32 freq;
|
||||||
|
u8 pri_chan;
|
||||||
|
s8 bgrssi_min;
|
||||||
|
s8 bgrssi_max;
|
||||||
|
s8 bgrssi_avg;
|
||||||
|
s32 bgrssi_acc;
|
||||||
|
s32 cnt;
|
||||||
|
s32 rxsync_cnt;
|
||||||
|
s32 noise_factor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fwstat_testmode {
|
||||||
|
u32 test_tx_start : 1, bss_freq : 24;
|
||||||
|
s32 freq_dev;
|
||||||
|
s32 chip_temp;
|
||||||
|
s32 tx_frms;
|
||||||
|
s32 tx_fail;
|
||||||
|
s32 tx_mcs;
|
||||||
|
s32 tx_sig_bw;
|
||||||
|
s32 rx_pkts;
|
||||||
|
s32 rx_firm;
|
||||||
|
s32 rx_err;
|
||||||
|
s32 rx_rssi;
|
||||||
|
s32 agc;
|
||||||
|
s32 rx_evm;
|
||||||
|
u8 chip_vcc[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fwstat_qa {
|
||||||
|
u8 dut_mac[6];
|
||||||
|
u16 svn_version;
|
||||||
|
s8 result_per;
|
||||||
|
s8 cfg_per;
|
||||||
|
s8 rssi;
|
||||||
|
s8 tssi;
|
||||||
|
s8 rx_evm;
|
||||||
|
s8 tx_evm;
|
||||||
|
s8 rx_freq_dev;
|
||||||
|
s8 tx_freq_dev;
|
||||||
|
s8 rx_rssi_th;
|
||||||
|
s8 tx_tssi_th;
|
||||||
|
s8 rx_evm_th;
|
||||||
|
s8 tx_evm_th;
|
||||||
|
s8 rx_freq_dev_th;
|
||||||
|
s8 tx_freq_dev_th;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fwstat_stainfo {
|
||||||
|
u8 addr[6];
|
||||||
|
s32 tx_frms;
|
||||||
|
s32 tx_frms_success;
|
||||||
|
s32 tx_cnt;
|
||||||
|
s32 tx_apep;
|
||||||
|
s32 tx_cca;
|
||||||
|
s32 tx_apep_success;
|
||||||
|
s32 tx_apep_droped;
|
||||||
|
s32 tx_frms_droped;
|
||||||
|
s32 tx_symbols;
|
||||||
|
s32 freq_offset;
|
||||||
|
u32 rx_cnt;
|
||||||
|
u32 rx_pkts;
|
||||||
|
u32 rx_bytes;
|
||||||
|
u32 rx_fcs_err;
|
||||||
|
u32 rx_symbols;
|
||||||
|
|
||||||
|
u8 tx_bw : 3, tx_mcs : 4;
|
||||||
|
u8 rx_bw : 4, rx_mcs : 4;
|
||||||
|
s8 evm_avg, evm_std, rssi, tx_snr;
|
||||||
|
u16 aid, agc;
|
||||||
|
u16 fade_bw_ind[4];
|
||||||
|
u64 tx_jiffies;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hgic_fwstat {
|
||||||
|
u8 mode;
|
||||||
|
u8 mac_address[6];
|
||||||
|
u16 aid;
|
||||||
|
u32 bss_freq_idx : 8, bss_freq : 24;
|
||||||
|
u32 pri1m_start : 16, pri2m_start : 16;
|
||||||
|
u32 pri1m_mid : 16, pri2m_mid : 16;
|
||||||
|
u32 sec2m_mid : 16, sec4m_mid : 16;
|
||||||
|
u32 pri1m_ed : 16, pri2m_ed : 16;
|
||||||
|
u32 sec2m_ed : 16, sec4m_ed : 16;
|
||||||
|
u8 tx_power_auto_adjust_en : 1, tx_pwr_adj : 5;
|
||||||
|
u8 chan_cnt;
|
||||||
|
u8 rx_duty_cycle;
|
||||||
|
u8 tx_pwr;
|
||||||
|
s8 bg_rssi;
|
||||||
|
s32 bgrssi_iqacc;
|
||||||
|
s32 demod_dly_max;
|
||||||
|
s32 sifs_dly_max;
|
||||||
|
s32 resp_dly_max;
|
||||||
|
s32 resp_sifs_to;
|
||||||
|
s32 resp_ack_to;
|
||||||
|
s32 frms_ack_to;
|
||||||
|
s32 rx_ovf_cnt;
|
||||||
|
s32 rx_nobuf_cnt;
|
||||||
|
s32 rx_bus_max;
|
||||||
|
s16 bgrssi_spur_thd;
|
||||||
|
s16 bgrssi_spur_det;
|
||||||
|
s16 bgrssi_spurs;
|
||||||
|
s16 bgrssi_iqmax;
|
||||||
|
s16 rx_dc_i;
|
||||||
|
s16 rx_dc_q;
|
||||||
|
u32 lo_kick_cnt : 16, chan_switch_cnt : 16;
|
||||||
|
s32 soft_rest;
|
||||||
|
u32 lmac_txsq_count;
|
||||||
|
u32 lmac_txq_count;
|
||||||
|
u32 lmac_acq_count[AC_NUM];
|
||||||
|
u32 lmac_txagg_count[AC_NUM];
|
||||||
|
u32 lmac_statq_count;
|
||||||
|
s32 lmac_rx_data_queue_count;
|
||||||
|
s32 ac_irq_cnt;
|
||||||
|
s32 ac_dly_max;
|
||||||
|
s32 tx_irq_rts;
|
||||||
|
s32 bo_irq_cnt[AC_NUM];
|
||||||
|
s32 cts_tmo_cnt;
|
||||||
|
s32 resp_tmo_cnt;
|
||||||
|
s32 rx_irq_cnt;
|
||||||
|
s32 tx_cnt;
|
||||||
|
s32 tx_cts_bw_acc;
|
||||||
|
s32 tx_cts_cnt;
|
||||||
|
s32 tx_cts_evm_acc;
|
||||||
|
s32 tx_frms;
|
||||||
|
s32 tx_sq_empty;
|
||||||
|
s32 agg_no_data;
|
||||||
|
s32 agg_check_fail;
|
||||||
|
s32 tx_apep;
|
||||||
|
s32 tx_symbols;
|
||||||
|
s32 tx_cca;
|
||||||
|
s32 tx_fail;
|
||||||
|
s32 tx_drop;
|
||||||
|
s32 rx_cnt;
|
||||||
|
s32 rx_cts_bw_acc;
|
||||||
|
s32 rx_cts_cnt;
|
||||||
|
s32 rx_cts_mcs_acc;
|
||||||
|
s32 rx_pkts;
|
||||||
|
s32 rx_bytes;
|
||||||
|
s32 rx_symbols;
|
||||||
|
s32 rx_phy_err;
|
||||||
|
s32 rx_fcs_err;
|
||||||
|
s32 phy_err_code;
|
||||||
|
s32 tx_irq_bkn;
|
||||||
|
|
||||||
|
u8 lmac_doze : 1, cca_obsv_dur : 3;
|
||||||
|
|
||||||
|
s32 sta_tx_syms;
|
||||||
|
s32 sta_rx_syms;
|
||||||
|
u32 est_tx_bitrate;
|
||||||
|
u32 sta_num;
|
||||||
|
u8 fixed_tx_mcs;
|
||||||
|
int skb_free_count;
|
||||||
|
|
||||||
|
struct hgic_fwstat_chaninfo chan_list[MAX_CHANS_NUM];
|
||||||
|
struct hgic_fwstat_testmode test_mode;
|
||||||
|
struct hgic_fwstat_qa qa_stat;
|
||||||
|
struct hgic_fwstat_stainfo sta_info[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
char *hgic_fwstat_print(u8 *stat_buf);
|
||||||
|
int hgic_skip_padding(struct sk_buff *skb);
|
||||||
|
int hgic_aligned_padding(struct sk_buff *skb);
|
||||||
|
void hgic_print_hex(char *buf, int len);
|
||||||
|
int hgic_config_read_u32_array(char *conf, char *field, u32 *arr, int count);
|
||||||
|
int hgic_config_read_u16_array(char *conf, char *field, u16 *arr, int count);
|
||||||
|
int hgic_config_read_str(char *conf, char *field, char *str, int size);
|
||||||
|
int hgic_config_read_int(char *conf, char *field);
|
||||||
|
void hgic_clear_queue(struct sk_buff_head *q);
|
||||||
|
int hgic_hex2num(char c);
|
||||||
|
int hgic_hex2byte(const char *hex);
|
||||||
|
int hgic_pick_macaddr(char *mac_str, u8 *addr);
|
||||||
|
|
||||||
|
#endif
|
1
version.h
Normal file
1
version.h
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#define SVN_VERSION "14988"
|
Loading…
Reference in a new issue