0
0
Fork 0

Initial driver upload

This commit is contained in:
Daryl Ronningen 2023-05-16 02:13:19 -07:00
commit 7ef9e52f3a
Signed by: Daryl Ronningen
GPG key ID: FD23F0C934A5EC6B
42 changed files with 13418 additions and 0 deletions

129
Makefile Normal file
View 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
View file

@ -0,0 +1,224 @@
2022/01/12
修改bugsdio remove过程中执行hgic_core_remove时可能会rx data此时会出现死机现象。
-----------------------------------------------------
2022/01/10
固件下载功能优化在固件下载阶段屏蔽其它数据和cmd的发送, 避免干扰固件下载过程。
-----------------------------------------------------
2021/12/22
fmac: 新增eventHGIC_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 driveralive_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_staAP端主动断开指定的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
fmacwifi模块休眠后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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

13
hgic_fmac/cfg.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

71
hgic_fmac/procfs.h Normal file
View 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
View 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
View 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
View 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
View 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, &param);
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
View 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(&param->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, &param->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
View 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
View file

@ -0,0 +1,2 @@
#!/bin/sh
echo $1 > /proc/hgic/testmode;cat /proc/hgic/testmode

2
iwpriv Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
echo $* > /proc/hgic/iwpriv;cat /proc/hgic/iwpriv

34
readme.txt Normal file
View 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
View 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
View 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>&copy; 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

File diff suppressed because it is too large Load diff

196
utils/fwctrl.h Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

899
utils/if_sdio.c Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

309
utils/ota.c Normal file
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
#define SVN_VERSION "14988"