├── README.md ├── linux_host_usb_80211_wifi_driver ├── Makefile ├── cfg80211.c ├── link_glue.c ├── link_glue.h ├── log.h ├── main.c ├── msg.c ├── msg.h ├── usb_link.c ├── usb_link.h └── xfz_cfg80211.h ├── test_firmware └── esp32s2_usb_wifi_firmware │ ├── bootloader.bin │ ├── esp32_usb_wifi_firmware.bin │ └── partition-table.bin └── wpa_supplicant-2.9.tar.gz /README.md: -------------------------------------------------------------------------------- 1 | # esp32s2_linux_80211_wifi_driver 2 | my toy diy poroject for esp3s2 linux 802.11 wifi driver, include linux host driver & esp32s2 firmware 3 | 4 | Q:开源软件怎么说了?公用品,方便了用户,但是怎么维护开发者的权益是个问题?问题不因回避而消失。 5 | 6 | A: 持续更新,像科技树一种,不停的向前走。出第一版本,第二版本,...N版本。 7 | 8 | --- 9 | 10 | ## 1.新手使用说明: 11 | 12 | 1. 升级esp32s2固件,已经编译好了。直接下载固件到esp32s2中即可。 13 | 14 | esp32s2_linux_80211_wifi_driver\test_firmware 15 | 16 | 2. 安装Linux主机驱动, 默认是centos7.6的主机驱动。 17 | 18 | 如果是pi的话,请注释掉main.c 中这行:#define LINUX_VERSION_CODE KERNEL_VERSION(4, 4, 0) 19 | 20 | make 进行编译 21 | 22 | modprobe cfg80211 23 | 24 | insmod xfz_usb_wifi.ko 25 | 26 | 驱动安装完毕 27 | 28 | 3.升级 wpa_supplicant-2.9.tar.gz 请参考网上的编译安装步骤。本主机驱动依赖高版本的wifi认证服务 wpa_supplicant 29 | 30 | 4.使用系统GUI配置wifi网络,这个和其它usb无线网卡一样,不啰嗦。 31 | 32 | 33 | 34 | ## 2.学习Linux wifi 802.11用户使用说明 35 | 36 | esp32s2的固件源码,计划分3次发布完。 37 | 38 | 阶段1:先发一个学习版本,不影响参考学习。性能上可以看720P在线视频,~2.5Mbps的速度。 39 | 40 | (20220/3/15 已经发布) 41 | 42 | 阶段2 :高性能版本, 性能上大约可以看1080P在线视频,相比前一版本大约提高1Mbps, 即~3.5Mbps,峰值5+Mbps。(不确定时间,有空再搞吧!) 43 | 44 | 45 | 46 | ## 3.esp32s2固件编译 47 | 48 | 请使用以下命令: 49 | 50 | git clone -b esp32_usb_80211_wifi git@github.com:chuanjinpang/esp-idf-usb-80211-wifi.git 51 | 52 | git submodule init 53 | git submodule update 54 | 55 | cd esp32s2_usb_80211_wifi 56 | 57 | idf.py build 生成固件 58 | 59 | 已经编译的出固件在esp32s2_linux_80211_wifi_driver\test_firmware。 60 | 61 | 注意点: 62 | 63 | 64 | 1. tinyusb若有更新,请拉取 git@github.com:chuanjinpang/tinyusb.git 里面的分支origin/pcj_dev。 65 | 66 | 67 | 68 | ## 3.已知问题 69 | 70 | 1. rmmod host driver时会有一个警告,调查过,不影响功能。 懒得修了。 71 | 72 | 73 | 74 | ## 4.将来的计划 75 | 76 | 也许会开发一个SPI接口的80211 wifi给嵌入式Linux用。 77 | 78 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/Makefile: -------------------------------------------------------------------------------- 1 | ###################################### 2 | # 3 | # usb wifi drv for esp 4 | # 5 | ###################################### 6 | 7 | 8 | DRIVER_NAME := xfz_usb_wifi 9 | KERNEL_SOURCE_DIR ?= /lib/modules/`uname -r`/build 10 | 11 | EXTRA_CFLAGS +=-g -I$(PWD)/src -I$(PWD)/../common 12 | 13 | obj-m := $(DRIVER_NAME).o 14 | 15 | DRIVER_FILES := main.o cfg80211.o \ 16 | usb_link.o msg.o link_glue.o 17 | CFLAGS_main.o = -O0 18 | 19 | $(DRIVER_NAME)-objs:= $(DRIVER_FILES) 20 | 21 | modules: 22 | $(MAKE) -C $(KERNEL_SOURCE_DIR) KCPPFLAGS="$(EXTRA_CFLAGS)" M=$(PWD) modules 23 | 24 | modules_install: 25 | $(MAKE) -C $(KERNEL_SOURCE_DIR) M=$(PWD) modules_install 26 | 27 | install: modules_install 28 | 29 | clean: 30 | $(MAKE) -C $(KERNEL_SOURCE_DIR) M=$(PWD) clean 31 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/cfg80211.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include /* wiphy and probably everything that would required for FullMAC driver */ 10 | 11 | 12 | #include "xfz_cfg80211.h" 13 | #include "link_glue.h" 14 | #include "msg.h" 15 | #include "log.h" 16 | 17 | #define WIPHY_NAME "xwlan" 18 | 19 | 20 | struct xfz_wiphy_priv_context { 21 | struct xfz_cfg80211_adapter * apt; 22 | }; 23 | 24 | 25 | static struct xfz_wiphy_priv_context * 26 | wiphy_get_xfz_context(struct wiphy *wiphy) 27 | { return (struct xfz_wiphy_priv_context *) wiphy_priv(wiphy); } 28 | 29 | 30 | 31 | 32 | typedef enum { 33 | WIFI_SECOND_CHAN_NONE = 0, /**< the channel width is HT20 */ 34 | WIFI_SECOND_CHAN_ABOVE, /**< the channel width is HT40 and the secondary channel is above the primary channel */ 35 | WIFI_SECOND_CHAN_BELOW, /**< the channel width is HT40 and the secondary channel is below the primary channel */ 36 | } wifi_second_chan_t; 37 | 38 | typedef enum { 39 | WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */ 40 | WIFI_AUTH_WEP, /**< authenticate mode : WEP */ 41 | WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */ 42 | WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */ 43 | WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */ 44 | WIFI_AUTH_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */ 45 | WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */ 46 | WIFI_AUTH_WPA2_WPA3_PSK, /**< authenticate mode : WPA2_WPA3_PSK */ 47 | WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */ 48 | WIFI_AUTH_MAX 49 | } wifi_auth_mode_t; 50 | 51 | typedef enum { 52 | WIFI_CIPHER_TYPE_NONE = 0, /**< the cipher type is none */ 53 | WIFI_CIPHER_TYPE_WEP40, /**< the cipher type is WEP40 */ 54 | WIFI_CIPHER_TYPE_WEP104, /**< the cipher type is WEP104 */ 55 | WIFI_CIPHER_TYPE_TKIP, /**< the cipher type is TKIP */ 56 | WIFI_CIPHER_TYPE_CCMP, /**< the cipher type is CCMP */ 57 | WIFI_CIPHER_TYPE_TKIP_CCMP, /**< the cipher type is TKIP and CCMP */ 58 | WIFI_CIPHER_TYPE_AES_CMAC128,/**< the cipher type is AES-CMAC-128 */ 59 | WIFI_CIPHER_TYPE_SMS4, /**< the cipher type is SMS4 */ 60 | WIFI_CIPHER_TYPE_UNKNOWN, /**< the cipher type is unknown */ 61 | } wifi_cipher_type_t; 62 | 63 | 64 | /** 65 | * @brief WiFi antenna 66 | * 67 | */ 68 | typedef enum { 69 | WIFI_ANT_ANT0, /**< WiFi antenna 0 */ 70 | WIFI_ANT_ANT1, /**< WiFi antenna 1 */ 71 | WIFI_ANT_MAX, /**< Invalid WiFi antenna */ 72 | } wifi_ant_t; 73 | 74 | 75 | typedef enum { 76 | WIFI_COUNTRY_POLICY_AUTO, /**< Country policy is auto, use the country info of AP to which the station is connected */ 77 | WIFI_COUNTRY_POLICY_MANUAL, /**< Country policy is manual, always use the configured country info */ 78 | } wifi_country_policy_t; 79 | 80 | /** @brief Structure describing WiFi country-based regional restrictions. */ 81 | typedef struct { 82 | char cc[3]; /**< country code string */ 83 | uint8_t schan; /**< start channel */ 84 | uint8_t nchan; /**< total channel number */ 85 | int8_t max_tx_power; /**< This field is used for getting WiFi maximum transmitting power, call esp_wifi_set_max_tx_power to set the maximum transmitting power. */ 86 | wifi_country_policy_t policy; /**< country policy */ 87 | } wifi_country_t; 88 | 89 | 90 | /** @brief Description of a WiFi AP */ 91 | typedef struct { 92 | uint8_t bssid[6]; /**< MAC address of AP */ 93 | uint8_t ssid[33]; /**< SSID of AP */ 94 | uint8_t primary; /**< channel of AP */ 95 | wifi_second_chan_t second; /**< secondary channel of AP */ 96 | int8_t rssi; /**< signal strength of AP */ 97 | wifi_auth_mode_t authmode; /**< authmode of AP */ 98 | wifi_cipher_type_t pairwise_cipher; /**< pairwise cipher of AP */ 99 | wifi_cipher_type_t group_cipher; /**< group cipher of AP */ 100 | wifi_ant_t ant; /**< antenna used to receive beacon from AP */ 101 | uint32_t phy_11b:1; /**< bit: 0 flag to identify if 11b mode is enabled or not */ 102 | uint32_t phy_11g:1; /**< bit: 1 flag to identify if 11g mode is enabled or not */ 103 | uint32_t phy_11n:1; /**< bit: 2 flag to identify if 11n mode is enabled or not */ 104 | uint32_t phy_lr:1; /**< bit: 3 flag to identify if low rate is enabled or not */ 105 | uint32_t wps:1; /**< bit: 4 flag to identify if WPS is supported or not */ 106 | uint32_t ftm_responder:1; /**< bit: 5 flag to identify if FTM is supported in responder mode */ 107 | uint32_t ftm_initiator:1; /**< bit: 6 flag to identify if FTM is supported in initiator mode */ 108 | uint32_t reserved:25; /**< bit: 7..31 reserved */ 109 | wifi_country_t country; /**< country information of AP */ 110 | } wifi_ap_record_t; 111 | 112 | 113 | #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" 114 | #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] 115 | 116 | 117 | 118 | 119 | int xfz_scan_done_evt(struct xfz_cfg80211_adapter * apt ,uint8_t * resp,bool aborted); 120 | 121 | 122 | /* Just calls cfg80211_disconnected() that informs the kernel that disconnect is complete. 123 | * Overall disconnect may call cfg80211_connect_timeout() if disconnect interrupting connection routine, but for this demo I keep it simple. 124 | * This routine called through workqueue, when the kernel asks about disconnect through cfg80211_ops. */ 125 | static void xfz_disconnect_routine(struct work_struct *w) { 126 | 127 | struct xfz_cfg80211_adapter * apt = container_of(w, struct xfz_cfg80211_adapter, ws_disconnect); 128 | 129 | if(!apt->bottom_obj) 130 | return;//remove device case 131 | 132 | if(down_interruptible(&apt->sem)) { 133 | return; 134 | } 135 | 136 | //issue cmd 137 | 138 | { 139 | 140 | cmd_resp64_t cmd; 141 | cmd.cmd_op=OUT_BAND_CMD_DISCONNECT_AP; 142 | cmd.len=0; 143 | 144 | if( link_issue_cmd_resp(apt->bottom_obj, (uint8_t * )&cmd,sizeof(cmd),(uint8_t *)&cmd,sizeof(cmd))>=0) 145 | { 146 | 147 | } 148 | else{ 149 | LOGE("%s can't issue disconnect cmd\n",__FUNCTION__); 150 | } 151 | } 152 | 153 | 154 | 155 | cfg80211_disconnected(apt->ndev, apt->disconnect_reason_code, NULL, 0, true, GFP_KERNEL); 156 | 157 | apt->disconnect_reason_code = 0; 158 | 159 | 160 | up(&apt->sem); 161 | 162 | xfz_scan_done_evt(apt, NULL,true); 163 | } 164 | 165 | 166 | 167 | 168 | 169 | static void inform_single_bss(struct xfz_cfg80211_adapter * apt,wifi_ap_record_t *ap) { 170 | struct cfg80211_bss *bss = NULL; 171 | int ie_len=0; 172 | struct cfg80211_inform_bss data = { 173 | .chan = &apt->wiphy->bands[NL80211_BAND_2GHZ]->channels[0], /* the only channel for this demo */ 174 | .scan_width = NL80211_BSS_CHAN_WIDTH_20, 175 | /* signal "type" not specified in this DEMO so its basically unused, it can be some kind of percentage from 0 to 100 or mBm value*/ 176 | /* signal "type" may be specified before wiphy registration by setting wiphy->signal_type */ 177 | .signal = ap->rssi*100, 178 | }; 179 | //char bssid[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; 180 | char rsn_ie[]={0x30,0x14,0x01,0x00,0x00,0x0F,0xAC,0x04,0x01,0x00,0x00,0x0F,0xAC,0x04,0x01,0x00,0x00,0x0F,0xAC,0x02,0x00,0x00}; 181 | //char rsn_ie[]={0x30,0x14,0x01,0x00,0x00,0x0F,0xAC,0x04,0x01,0x00,0x00,0x0F,0xAC,0x04,0x01,0x00,0x00,0x0F,0xAC,0x02,0x00,0x00}; 182 | char wpa_ie[]={0xDD,0x16,0x00,0x50,0xF2,0x01,0x01,0x00,0x00,0x50,0xF2,0x04,0x01,0x00,0x00,0x50,0xF2,0x04,0x01,0x00,0x00,0x50,0xF2,0x02}; 183 | /* ie - array of tags that usually retrieved from beacon frame or probe responce. */ 184 | char ie[256] = {0}; 185 | ie[0]=WLAN_EID_SSID; 186 | ie[1]=strlen(ap->ssid); 187 | ie_len+=2; 188 | memcpy(ie + 2, ap->ssid, strlen(ap->ssid)); 189 | ie_len+=strlen(ap->ssid); 190 | memcpy(ie + ie_len, rsn_ie, sizeof(rsn_ie)); 191 | ie_len+= sizeof(rsn_ie); 192 | memcpy(ie + ie_len, wpa_ie, sizeof(wpa_ie)); 193 | ie_len+= sizeof(wpa_ie); 194 | 195 | 196 | /* also it posible to use cfg80211_inform_bss() instead of cfg80211_inform_bss_data() */ 197 | bss = cfg80211_inform_bss_data(apt->wiphy, &data, CFG80211_BSS_FTYPE_UNKNOWN, ap->bssid, 0, WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_PRIVACY, 100, 198 | ie, ie_len, GFP_KERNEL); 199 | 200 | /* free, cfg80211_inform_bss_data() returning cfg80211_bss structure refcounter of which should be decremented if its not used. */ 201 | cfg80211_put_bss(apt->wiphy, bss); 202 | } 203 | 204 | int xfz_scan_done_evt(struct xfz_cfg80211_adapter * apt ,uint8_t * resp,bool aborted){ 205 | 206 | 207 | int i=0; 208 | 209 | struct cfg80211_scan_info info = { 210 | /* if scan was aborted by user(calling cfg80211_ops->abort_scan) or by any driver/hardware issue - field should be set to "true"*/ 211 | .aborted = aborted, 212 | }; 213 | 214 | 215 | 216 | 217 | if (aborted) 218 | goto out; 219 | 220 | { 221 | 222 | cmd_resp64_t * pcmd=(cmd_resp64_t *)resp; 223 | int sta_number=pcmd->len/sizeof(wifi_ap_record_t); 224 | wifi_ap_record_t *ap_list_buffer=(wifi_ap_record_t *)pcmd->buf; 225 | 226 | for(i=0; isem)) { 233 | return -1; 234 | } 235 | if (apt->scan_request) { //atomic done it or panic 236 | 237 | /* finish scan */ 238 | cfg80211_scan_done(apt->scan_request, &info); 239 | apt->scan_request = NULL; 240 | } 241 | up(&apt->sem); 242 | 243 | } 244 | 245 | /* "Scan" routine for DEMO. It just inform the kernel about "dummy" BSS and "finishs" scan. 246 | * When scan is done it should call cfg80211_scan_done() to inform the kernel that scan is finished. 247 | * This routine called through workqueue, when the kernel asks about scan through cfg80211_ops. */ 248 | static void xfz_scan_routine(struct work_struct *w) { 249 | struct xfz_cfg80211_adapter * apt = container_of(w, struct xfz_cfg80211_adapter, ws_scan); 250 | 251 | 252 | /* pretend some work, also u can't call cfg80211_scan_done right away after cfg80211_ops->scan(), 253 | * idk why, but netlink client would not get message with "scan done", 254 | * is it because of "scan_routine" and cfg80211_ops->scan() may run in concurrent and cfg80211_scan_done() called before cfg80211_ops->scan() returns? */ 255 | #ifdef NO_USB_SIMULATOR 256 | 257 | msleep(100); 258 | 259 | wifi_ap_record_t ap_list_buffer={ 260 | .ssid="Gohighsec-2.4", 261 | .bssid={0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, 262 | }; 263 | 264 | inform_single_bss(apt,&ap_list_buffer); 265 | 266 | #else 267 | 268 | 269 | { 270 | 271 | cmd_resp64_t cmd; 272 | cmd.cmd_op=OUT_BAND_CMD_SCAN; 273 | cmd.len=0; 274 | 275 | if( link_issue_cmd_resp(apt->bottom_obj,(uint8_t *)&cmd,sizeof(cmd),(uint8_t *)&cmd,sizeof(cmd))>=0) 276 | { 277 | 278 | 279 | } 280 | else{ 281 | LOGE("%s can't issue scan cmd\n",__FUNCTION__); 282 | xfz_scan_done_evt(apt,NULL,true); 283 | return; 284 | } 285 | } 286 | #endif 287 | 288 | //wait 5s timeout scan list result 289 | { 290 | int i=0; 291 | for(i=0;i<10;i++) { 292 | msleep(500); 293 | if (NULL == apt->scan_request) 294 | break; 295 | } 296 | if (apt->scan_request) { //5s no scan done, we done it, for non-block user scan req 297 | xfz_scan_done_evt(apt,NULL,true); 298 | } 299 | } 300 | 301 | } 302 | 303 | 304 | 305 | /* callback that called by the kernel when user decided to scan. 306 | * This callback should initiate scan routine(through work_struct) and exit with 0 if everything ok. 307 | * Scan routine should be finished with cfg80211_scan_done() call. */ 308 | static int xfz_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { 309 | struct xfz_cfg80211_adapter * apt = wiphy_get_xfz_context(wiphy)->apt; 310 | 311 | 312 | if(down_interruptible(&apt->sem)) { 313 | return -ERESTARTSYS; 314 | } 315 | 316 | if (apt->scan_request != NULL) { 317 | up(&apt->sem); 318 | return -EBUSY; 319 | } 320 | apt->scan_request = request; 321 | 322 | up(&apt->sem); 323 | 324 | if (!schedule_work(&apt->ws_scan)) { 325 | return -EBUSY; 326 | } 327 | 328 | return 0; /* OK */ 329 | } 330 | 331 | 332 | 333 | /* callback that called by the kernel when there is need to "connect" to some network. 334 | * It inits connection routine through work_struct and exits with 0 if everything ok. 335 | * connect routine should be finished with cfg80211_connect_bss()/cfg80211_connect_result()/cfg80211_connect_done() or cfg80211_connect_timeout(). */ 336 | static int xfz_connect(struct wiphy *wiphy, struct net_device *dev, 337 | struct cfg80211_connect_params *sme) { 338 | struct xfz_cfg80211_adapter * apt = wiphy_get_xfz_context(wiphy)->apt; 339 | size_t ssid_len = sme->ssid_len > MAX_SSID_SIZE? MAX_SSID_SIZE : sme->ssid_len; 340 | 341 | 342 | 343 | if(down_interruptible(&apt->sem)) { 344 | return -ERESTARTSYS; 345 | } 346 | 347 | 348 | 349 | memcpy(apt->connecting_ssid, sme->ssid, ssid_len); 350 | apt->connecting_ssid[ssid_len] = 0; 351 | apt->ssid_len=sme->ssid_len; 352 | if(sme->crypto.psk){ 353 | memcpy(apt->psk,sme->crypto.psk,WLAN_PMK_LEN); 354 | 355 | } 356 | 357 | up(&apt->sem); 358 | 359 | if (!schedule_work(&apt->ws_connect)) { 360 | return -EBUSY; 361 | } 362 | return 0; 363 | } 364 | /* callback that called by the kernel when there is need to "diconnect" from currently connected network. 365 | * It inits disconnect routine through work_struct and exits with 0 if everything ok. 366 | * disconnect routine should call cfg80211_disconnected() to inform the kernel that disconnection is complete. */ 367 | static int xfz_disconnect(struct wiphy *wiphy, struct net_device *dev, 368 | u16 reason_code) { 369 | struct xfz_cfg80211_adapter * apt = wiphy_get_xfz_context(wiphy)->apt; 370 | 371 | if(down_interruptible(&apt->sem)) { 372 | return -ERESTARTSYS; 373 | } 374 | 375 | apt->disconnect_reason_code = reason_code; 376 | 377 | up(&apt->sem); 378 | 379 | if (!schedule_work(&apt->ws_disconnect)) { 380 | return -EBUSY; 381 | } 382 | return 0; 383 | } 384 | 385 | #define SSID_DUMMY "Gohighsec-2.4" 386 | #define SSID_DUMMY_SIZE (sizeof("Gohighsec-2.4") - 1) 387 | 388 | 389 | 390 | 391 | 392 | /* It just checks SSID of the ESS to connect and informs the kernel that connect is finished. 393 | * It should call cfg80211_connect_bss() when connect is finished or cfg80211_connect_timeout() when connect is failed. 394 | * This "demo" can connect only to ESS with SSID equal to SSID_DUMMY value. 395 | * This routine called through workqueue, when the kernel asks about connect through cfg80211_ops. */ 396 | static void xfz_connect_routine(struct work_struct *w) { 397 | struct xfz_cfg80211_adapter * apt = container_of(w, struct xfz_cfg80211_adapter, ws_connect); 398 | 399 | if(down_interruptible(&apt->sem)) { 400 | return; 401 | } 402 | { 403 | 404 | 405 | { 406 | 407 | cmd_resp64_t cmd; 408 | cmd.cmd_op=OUT_BAND_CMD_CONNECT_AP; 409 | cmd.seq=7841; 410 | cmd.len=0; 411 | ssid_psk_msg_t * spsk=(ssid_psk_msg_t * )cmd.buf; 412 | memcpy(spsk->psk,apt->psk,WLAN_PMK_LEN); 413 | memcpy(spsk->ssid,apt->connecting_ssid,apt->ssid_len); 414 | cmd.len=WLAN_PMK_LEN+apt->ssid_len; 415 | 416 | if( link_issue_cmd_resp(apt->bottom_obj,(uint8_t *)&cmd,sizeof(cmd),(uint8_t *)&cmd,sizeof(cmd))>=0) 417 | { 418 | 419 | } 420 | else{ 421 | LOGE("%s can't issue connect cmd\n",__FUNCTION__); 422 | 423 | } 424 | } 425 | 426 | 427 | 428 | } 429 | 430 | 431 | up(&apt->sem); 432 | } 433 | 434 | 435 | 436 | ; 437 | 438 | 439 | int xfz_connect_done_evt(struct xfz_cfg80211_adapter * apt,uint8_t * resp){ 440 | 441 | cmd_resp64_t * pcmd=(cmd_resp64_t *)resp; 442 | 443 | 444 | 445 | 446 | if(down_interruptible(&apt->sem)) { 447 | LOGE("in %s can't down sem\n",__FUNCTION__); 448 | return; 449 | } 450 | 451 | /* finish connect */ 452 | char bssid[]={0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; 453 | /* also its possible to use cfg80211_connect_result() or cfg80211_connect_done() */ 454 | memcpy(bssid, pcmd->buf,6); 455 | cfg80211_connect_bss(apt->ndev, bssid, NULL, NULL, 0, NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL, 456 | NL80211_TIMEOUT_UNSPECIFIED); 457 | apt->connecting_ssid[0] = 0; 458 | 459 | 460 | up(&apt->sem); 461 | 462 | } 463 | 464 | 465 | static void ws_evt_routine(struct work_struct *w) { 466 | struct xfz_cfg80211_adapter * apt = container_of(w, struct xfz_cfg80211_adapter, ws_evt); 467 | uint8_t msg[LINK_MSG_MAX_SIZE]; 468 | int id=-1; 469 | if(msg_queue_get_msg(&apt->msg_mgr,&id,msg,LINK_MSG_MAX_SIZE)>0){ 470 | switch(id){ 471 | case OUT_BAND_CMD_AP_LIST: 472 | xfz_scan_done_evt(apt,msg,false); 473 | break; 474 | case OUT_BAND_CMD_CONNECTED_DONE: 475 | xfz_connect_done_evt(apt,msg); 476 | break; 477 | default: 478 | ; 479 | 480 | } 481 | } 482 | } 483 | 484 | static int 485 | xfz_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, 486 | int idx, u8 *mac, struct station_info *sinfo) 487 | { 488 | 489 | return 0; 490 | } 491 | 492 | 493 | 494 | 495 | static s32 496 | xfz_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, 497 | u8 key_idx, bool pairwise, const u8 *mac_addr, 498 | struct key_params *params) 499 | { 500 | 501 | return 0; 502 | } 503 | 504 | 505 | static s32 506 | xfz_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, 507 | u8 key_idx, bool pairwise, const u8 *mac_addr) 508 | { 509 | 510 | return 0; 511 | } 512 | 513 | 514 | static s32 515 | xfz_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev, 516 | u8 key_idx, bool unicast, bool multicast) 517 | { 518 | 519 | return 0; 520 | } 521 | 522 | static s32 523 | xfz_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, 524 | bool pairwise, const u8 *mac_addr, void *cookie, 525 | void (*callback)(void *cookie, 526 | struct key_params *params)) 527 | { 528 | 529 | 530 | return 0; 531 | 532 | } 533 | 534 | int g_auth_stat=0; 535 | 536 | static int 537 | xfz_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, 538 | const u8 *mac, struct station_parameters *params) 539 | { 540 | 541 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) 542 | { 543 | g_auth_stat=1; 544 | return 0; 545 | } 546 | g_auth_stat=0; 547 | return 0; 548 | 549 | } 550 | 551 | 552 | static s32 553 | xfz_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, 554 | const u8 *mac, struct station_info *sinfo) 555 | { 556 | int rssi=-6000; 557 | 558 | if(g_auth_stat) { 559 | rssi = le32_to_cpu(-40); 560 | sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); 561 | sinfo->signal = rssi; 562 | 563 | } 564 | 565 | return 0; 566 | } 567 | 568 | 569 | 570 | /* Array of "supported" channels in 2ghz band. It's required for wiphy. 571 | * For demo - the only channel 6. */ 572 | static struct ieee80211_channel xfz_supported_channels_2ghz[] = { 573 | { 574 | .band = NL80211_BAND_2GHZ, 575 | .hw_value = 6, 576 | .center_freq = 2437, 577 | } 578 | }; 579 | 580 | 581 | /* Array of supported rates. Its required to support at least those next rates for 2ghz band. */ 582 | static struct ieee80211_rate xfz_supported_rates_2ghz[] = { 583 | { 584 | .bitrate = 10, 585 | .hw_value = 0x1, 586 | }, 587 | { 588 | .bitrate = 20, 589 | .hw_value = 0x2, 590 | }, 591 | { 592 | .bitrate = 55, 593 | .hw_value = 0x4, 594 | }, 595 | { 596 | .bitrate = 110, 597 | .hw_value = 0x8, 598 | } 599 | }; 600 | 601 | 602 | /* Structure that describes supported band of 2ghz. */ 603 | static struct ieee80211_supported_band xfz_band_2ghz = { 604 | .ht_cap.cap = IEEE80211_HT_CAP_SGI_20, /* add other band capabilities if needed, like 40 width etc. */ 605 | .ht_cap.ht_supported = false, 606 | 607 | .channels = xfz_supported_channels_2ghz, 608 | .n_channels = ARRAY_SIZE(xfz_supported_channels_2ghz), 609 | 610 | .bitrates = xfz_supported_rates_2ghz, 611 | .n_bitrates = ARRAY_SIZE(xfz_supported_rates_2ghz), 612 | }; 613 | 614 | 615 | 616 | /* Structure of functions for FullMAC 80211 drivers. 617 | * Functions that implemented along with fields/flags in wiphy structure would represent drivers features. 618 | * This DEMO can only perform "scan" and "connect". 619 | * Some functions cant be implemented alone, for example: with "connect" there is should be function "disconnect". */ 620 | static struct cfg80211_ops xfz_cfg80211_ops = { 621 | .scan = xfz_scan, 622 | .connect = xfz_connect, 623 | .disconnect = xfz_disconnect, 624 | .add_key = xfz_cfg80211_add_key, 625 | .del_key = xfz_cfg80211_del_key, 626 | .change_station = xfz_cfg80211_change_station, 627 | .get_station = xfz_cfg80211_get_station, 628 | .dump_station = xfz_cfg80211_dump_station, 629 | //.get_key = xfz_cfg80211_get_key, 630 | .set_default_key = xfz_cfg80211_config_default_key, 631 | }; 632 | 633 | 634 | 635 | 636 | 637 | 638 | int xfz_cfg80211_wiphy_init(struct xfz_cfg80211_adapter * apt) 639 | { 640 | 641 | sema_init(&apt->sem, 1); 642 | INIT_WORK(&apt->ws_connect, xfz_connect_routine); 643 | apt->connecting_ssid[0] = 0; 644 | INIT_WORK(&apt->ws_disconnect, xfz_disconnect_routine); 645 | apt->disconnect_reason_code = 0; 646 | INIT_WORK(&apt->ws_scan, xfz_scan_routine); 647 | apt->scan_request = NULL; 648 | INIT_WORK(&apt->ws_evt, ws_evt_routine); 649 | msg_queue_init(&apt->msg_mgr); 650 | apt->wiphy = wiphy_new_nm(&xfz_cfg80211_ops, sizeof(struct xfz_wiphy_priv_context), WIPHY_NAME); 651 | if (apt->wiphy == NULL) { 652 | LOGE("%s wiphy_new_nm NG\n", __FUNCTION__); 653 | goto error_wiphy; 654 | } 655 | 656 | //save apt in wiphy private data. 657 | wiphy_get_xfz_context(apt->wiphy)->apt=apt; 658 | 659 | // set device object as wiphy "parent" 660 | /* set_wiphy_dev(ret->wiphy, dev); */ 661 | 662 | /* wiphy should determinate it type */ 663 | /* add other required types like "BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)" etc. */ 664 | apt->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 665 | 666 | /* wiphy should have at least 1 band. */ 667 | /* fill also NL80211_BAND_5GHZ if required, in this small example I use only 1 band with 1 "channel" */ 668 | apt->wiphy->bands[NL80211_BAND_2GHZ] = &xfz_band_2ghz; 669 | 670 | /* scan - if ur device supports "scan" u need to define max_scan_ssids at least. */ 671 | apt->wiphy->max_scan_ssids = 18; 672 | // set cipher suite or we will got INVALID error when nl call 673 | { 674 | 675 | static const u32 cipher_suites[] = { 676 | /* keep WEP first, it may be removed below */ 677 | WLAN_CIPHER_SUITE_WEP40, 678 | WLAN_CIPHER_SUITE_WEP104, 679 | WLAN_CIPHER_SUITE_TKIP, 680 | WLAN_CIPHER_SUITE_CCMP, 681 | WLAN_CIPHER_SUITE_CCMP_256, 682 | WLAN_CIPHER_SUITE_GCMP, 683 | WLAN_CIPHER_SUITE_GCMP_256, 684 | 685 | /* keep last -- depends on hw flags! */ 686 | WLAN_CIPHER_SUITE_AES_CMAC, 687 | WLAN_CIPHER_SUITE_BIP_CMAC_256, 688 | WLAN_CIPHER_SUITE_BIP_GMAC_128, 689 | WLAN_CIPHER_SUITE_BIP_GMAC_256, 690 | }; 691 | apt->wiphy->cipher_suites= cipher_suites; 692 | apt->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 693 | 694 | 695 | } 696 | //set RSSI mode or will no display 697 | apt->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 698 | // register wiphy, if everything ok - there should be another wireless device in system. 699 | //use command: $ iw list 700 | 701 | if (wiphy_register(apt->wiphy) < 0) { 702 | LOGE("%s wiphy_register NG\n", __FUNCTION__); 703 | goto error_wiphy_register; 704 | } 705 | return 0; 706 | error_wiphy_register: 707 | wiphy_free(apt->wiphy); 708 | error_wiphy: 709 | return -1; 710 | 711 | } 712 | 713 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/link_glue.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "xfz_cfg80211.h" 12 | #include "link_glue.h" 13 | #include "msg.h" 14 | #include "log.h" 15 | #include "usb_link.h" 16 | 17 | 18 | void * xfz_cfg80211_init(void * bottom_obj); 19 | void xfz_cfg80211_exit(void); 20 | 21 | 22 | void upper_layer_status (void * uobj){ 23 | 24 | struct xfz_cfg80211_adapter *adapter=uobj; 25 | 26 | if(!uobj) 27 | return; 28 | 29 | if (netif_queue_stopped((const struct net_device *) adapter->ndev) ) { 30 | 31 | }else { 32 | } 33 | 34 | } 35 | 36 | 37 | void push_skb_upper_layer(void * uobj, struct sk_buff *skb){ 38 | 39 | struct xfz_cfg80211_adapter *apt=uobj; 40 | 41 | 42 | if(!uobj) 43 | return; 44 | 45 | skb_queue_tail(&apt->rx_queue, skb); 46 | 47 | if(apt) 48 | queue_work(apt->if_rx_workqueue, &apt->if_rx_work); 49 | 50 | } 51 | 52 | 53 | /* 54 | 55 | if we handler it, return true means we handle the msg, 56 | or the lower layer will handle it. 57 | and the msg is in irq context, so should consider it for handle 58 | */ 59 | int upper_layer_msg_handler(void * ctx, uint8_t * resp, size_t len){ 60 | cmd_resp64_t * pcmd=(cmd_resp64_t *)resp; 61 | struct xfz_cfg80211_adapter * apt = ctx; 62 | int ret=0; 63 | switch(pcmd->cmd_op) { 64 | case OUT_BAND_CMD_AP_LIST: 65 | { 66 | msg_queue_put_msg(&apt->msg_mgr,OUT_BAND_CMD_AP_LIST,resp,len); 67 | 68 | if (!schedule_work(&apt->ws_evt)) { 69 | LOGE("%s shecd evt ws NG\n",__FUNCTION__); 70 | } 71 | 72 | ret= 1;//handle it 73 | break; 74 | 75 | } 76 | case OUT_BAND_CMD_CONNECTED_DONE: 77 | { 78 | msg_queue_put_msg(&apt->msg_mgr,OUT_BAND_CMD_CONNECTED_DONE,resp,len); 79 | 80 | if (!schedule_work(&apt->ws_evt)) { 81 | LOGE("%s shecd evt ws NG\n",__FUNCTION__); 82 | } 83 | 84 | ret= 1;//handle it 85 | break; 86 | 87 | } 88 | default: 89 | ; 90 | } 91 | return ret;//0 no handle 92 | 93 | } 94 | 95 | 96 | 97 | void link_tx_msg(void * bottom_obj,const uint8_t * msg_data, int msg_len){ 98 | struct usb_link_dev * dev =bottom_obj; 99 | 100 | usb_link_send_msg(dev,msg_data,msg_len); 101 | 102 | } 103 | 104 | 105 | 106 | 107 | int link_issue_cmd_resp(void * bottom_obj, uint8_t * msg,int msg_len,uint8_t * resp,int resp_len) 108 | { 109 | 110 | struct usb_link_dev * dev=bottom_obj; 111 | 112 | return usb_link_issue_cmd_resp(dev,msg,msg_len,resp,resp_len); 113 | 114 | 115 | } 116 | 117 | 118 | 119 | void * upper_layer_init(void * bottom_obj){ 120 | 121 | return xfz_cfg80211_init(bottom_obj); 122 | 123 | 124 | } 125 | 126 | void upper_layer_deinit(void){ 127 | 128 | xfz_cfg80211_exit(); 129 | 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/link_glue.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __LINK_GLUE__H_ 3 | #define __LINK_GLUE__H_ 4 | 5 | #define OUT_BAND_CMD_GET_MAC 1 6 | #define OUT_BAND_CMD_SCAN 2 7 | #define OUT_BAND_CMD_AP_LIST 3 8 | #define OUT_BAND_CMD_CONNECT_AP 4 9 | #define OUT_BAND_CMD_DISCONNECT_AP 5 10 | #define OUT_BAND_CMD_CONNECTED_DONE 6 11 | 12 | #define LINK_MSG_MAX_SIZE 2048 13 | 14 | 15 | typedef struct { 16 | uint16_t cmd_op; 17 | uint16_t seq; 18 | uint16_t len; 19 | uint8_t buf[53]; 20 | } __attribute__((packed)) cmd_resp64_t; //should less than 60 bytes, due to usb max is 64byte. overhead 2 byte. 62 less 64 means a short packet 21 | 22 | 23 | #define WLAN_PMK_LEN 32 24 | 25 | typedef struct { 26 | uint8_t psk[WLAN_PMK_LEN]; 27 | uint8_t ssid[21]; 28 | } __attribute__((packed)) ssid_psk_msg_t; 29 | 30 | int upper_layer_msg_handler(void * ctx, uint8_t * resp, size_t len); 31 | void upper_layer_queue_wakeup(void * uobj); 32 | void upper_layer_status (void * uobj); 33 | 34 | void push_skb_upper_layer(void * uobj, struct sk_buff *skb); 35 | 36 | 37 | void link_tx_msg(void * bottom_obj,const uint8_t * msg_data, int msg_len); 38 | 39 | int link_issue_cmd_resp(void * bottom_obj, uint8_t * msg,int msg_len,uint8_t * resp,int resp_len); 40 | 41 | void * upper_layer_init(void * bottom_obj); 42 | 43 | void upper_layer_deinit(void); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_LOG_H_ 2 | #define _DEBUG_LOG_H_ 3 | 4 | //#define DEBUG_MODE 1 5 | #ifdef DEBUG_MODE 6 | 7 | #define LOGW(args...) do {printk(args);} while(0) 8 | #define LOGE(args...) do {printk(args);} while(0) 9 | 10 | #else 11 | 12 | #define LOGW(args...) do {} while(0) 13 | #define LOGE(args...) do {printk(args);} while(0) 14 | 15 | #endif 16 | 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | a diy project refer espressif hosted project for usb 802.11 wifi 4 | 1.first release on 20220129 by chuanjin 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include /* wiphy and probably everything that would required for FullMAC driver */ 16 | 17 | 18 | #include "xfz_cfg80211.h" 19 | #include "link_glue.h" 20 | #include "msg.h" 21 | #include "log.h" 22 | 23 | 24 | #if ! defined(LINUX_VERSION_CODE) 25 | #include 26 | #endif 27 | //centos7 need define Linux version code due to centos7 driver use high version code, however the kernel version is 3.10 28 | #define LINUX_VERSION_CODE KERNEL_VERSION(4, 4, 0) 29 | 30 | //#define NO_USB_SIMULATOR 1 31 | 32 | 33 | MODULE_LICENSE("GPL"); 34 | MODULE_AUTHOR("xfz1986"); 35 | MODULE_DESCRIPTION("xfz1986 diy usb 802.11 wifi solution four esp32 s2/s3 chip"); 36 | MODULE_VERSION("0.1"); 37 | 38 | 39 | 40 | 41 | 42 | int xfz_scan_done_evt(struct xfz_cfg80211_adapter * apt ,uint8_t * resp,bool aborted); 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | static int process_tx_packet (struct sk_buff *skb); 51 | int esp_send_packet(struct xfz_cfg80211_adapter *adapter, struct sk_buff *skb); 52 | 53 | 54 | 55 | 56 | struct xfz_ndev_priv_context { 57 | struct xfz_cfg80211_adapter *apt; 58 | struct wireless_dev wdev; 59 | }; 60 | 61 | 62 | #define NDEV_NAME "xwifi%d" 63 | 64 | /* helper function that will retrieve main context from "priv" data of the network device */ 65 | static struct xfz_ndev_priv_context * 66 | ndev_get_xfz_context(struct net_device *ndev) { return (struct xfz_ndev_priv_context *) netdev_priv(ndev); } 67 | 68 | 69 | 70 | 71 | int link_tx_packet(struct xfz_cfg80211_adapter *adapter, struct sk_buff *skb) 72 | { 73 | if (!adapter) 74 | return -EINVAL; 75 | 76 | 77 | if (adapter->ndev && 78 | !netif_queue_stopped((const struct net_device *) 79 | adapter->ndev)) { 80 | netif_stop_queue(adapter->ndev); 81 | } 82 | 83 | link_tx_msg(adapter->bottom_obj,skb->data,skb->len); 84 | dev_kfree_skb(skb); 85 | 86 | return 0; 87 | 88 | } 89 | 90 | 91 | 92 | 93 | static int process_tx_packet (struct sk_buff *skb) 94 | { 95 | struct xfz_cfg80211_skb_cb *cb = NULL; 96 | struct xfz_cfg80211_adapter * apt=NULL; 97 | int ret = 0; 98 | u16 len = 0; 99 | 100 | cb = (struct xfz_cfg80211_skb_cb *) skb->cb; 101 | apt = cb->priv; 102 | 103 | 104 | if (!apt) { 105 | dev_kfree_skb(skb); 106 | return NETDEV_TX_OK; 107 | } 108 | 109 | 110 | if (netif_queue_stopped((const struct net_device *) apt->ndev) ) { 111 | return NETDEV_TX_BUSY; 112 | } 113 | 114 | len = skb->len; 115 | if (1) { 116 | ret =link_tx_packet(apt, skb); 117 | 118 | if (ret) { 119 | apt->stats.tx_errors++; 120 | } else { 121 | apt->stats.tx_packets++; 122 | apt->stats.tx_bytes += skb->len; 123 | } 124 | } else { 125 | dev_kfree_skb_any(skb); 126 | apt->stats.tx_dropped++; 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | static void process_rx_packet(struct xfz_cfg80211_adapter * apt ,struct sk_buff *skb) 133 | { 134 | 135 | if (!skb) 136 | return; 137 | 138 | skb->dev = apt->ndev; 139 | skb->protocol = eth_type_trans(skb, apt->ndev); 140 | skb->ip_summed = CHECKSUM_NONE; 141 | 142 | 143 | /* Forward skb to kernel */ 144 | netif_rx_ni(skb); 145 | 146 | apt->stats.rx_bytes += skb->len; 147 | apt->stats.rx_packets++; 148 | 149 | } 150 | 151 | 152 | 153 | static struct sk_buff * link_rx_packet(struct xfz_cfg80211_adapter * apt) 154 | { 155 | struct sk_buff *skb = NULL; 156 | 157 | 158 | if (!apt ) { 159 | LOGE("%s: Invalid apt:%p\n", __func__,apt); 160 | return NULL; 161 | } 162 | 163 | skb = skb_dequeue(&(apt->rx_queue)); 164 | 165 | 166 | return skb; 167 | } 168 | 169 | 170 | static void link_rx_work (struct work_struct *work) 171 | { 172 | 173 | 174 | struct xfz_cfg80211_adapter * apt = container_of(work, struct xfz_cfg80211_adapter, if_rx_work); 175 | 176 | struct sk_buff *skb = NULL; 177 | 178 | 179 | if (!apt ) 180 | return ; 181 | 182 | 183 | 184 | skb = link_rx_packet(apt); 185 | 186 | if (!skb) 187 | return ; 188 | 189 | process_rx_packet(apt,skb); 190 | 191 | return ; 192 | 193 | 194 | } 195 | 196 | static void deinit_adapter(struct xfz_cfg80211_adapter * apt) 197 | { 198 | 199 | /* Flush workqueues */ 200 | if (apt->if_rx_workqueue) { 201 | flush_workqueue(apt->if_rx_workqueue); 202 | destroy_workqueue(apt->if_rx_workqueue); 203 | } 204 | 205 | 206 | } 207 | 208 | 209 | 210 | 211 | static netdev_tx_t xfz_ndo_start_xmit(struct sk_buff *skb, 212 | struct net_device *dev) { 213 | 214 | struct xfz_cfg80211_adapter * apt=ndev_get_xfz_context(dev)->apt; 215 | struct xfz_cfg80211_skb_cb *cb = NULL; 216 | 217 | 218 | if (!apt) { 219 | dev_kfree_skb(skb); 220 | return NETDEV_TX_OK; 221 | } 222 | 223 | 224 | if (!skb->len || (skb->len > ETH_FRAME_LEN)) { 225 | apt->stats.tx_dropped++; 226 | dev_kfree_skb(skb); 227 | return NETDEV_TX_OK; 228 | } 229 | cb = (struct xfz_cfg80211_skb_cb *) skb->cb; 230 | cb->priv = apt; 231 | 232 | 233 | 234 | return process_tx_packet(skb); 235 | } 236 | 237 | static int xfz_ndo_open(struct net_device *ndev) 238 | { 239 | 240 | netif_start_queue(ndev); 241 | return 0; 242 | } 243 | 244 | static int xfz_ndo_stop(struct net_device *ndev) 245 | { 246 | 247 | netif_stop_queue(ndev); 248 | return 0; 249 | } 250 | 251 | 252 | static struct net_device_stats* xfz_ndo_get_stats(struct net_device *ndev) 253 | { 254 | struct xfz_cfg80211_adapter * apt=ndev_get_xfz_context(ndev)->apt; 255 | return &apt->stats; 256 | } 257 | 258 | 259 | /* Structure of functions for network devices. 260 | * It should have at least ndo_start_xmit functions that called for packet to be sent. */ 261 | static struct net_device_ops xfz_ndev_ops = { 262 | .ndo_open = xfz_ndo_open, 263 | .ndo_stop = xfz_ndo_stop, 264 | .ndo_start_xmit = xfz_ndo_start_xmit, 265 | .ndo_get_stats = xfz_ndo_get_stats, 266 | 267 | }; 268 | 269 | 270 | 271 | static struct xfz_cfg80211_adapter * init_adapter(void * bottom_obj) 272 | { 273 | struct xfz_cfg80211_adapter * apt= kzalloc(sizeof(struct xfz_cfg80211_adapter),GFP_KERNEL); 274 | u8 mac_address[6]={0x7c,0xdf,0xa1,0x93,0x9f,0x96}; 275 | 276 | { 277 | 278 | 279 | #ifdef NO_USB_SIMULATOR 280 | 281 | #else 282 | 283 | cmd_resp64_t cmd; 284 | cmd.cmd_op=OUT_BAND_CMD_GET_MAC; 285 | if( link_issue_cmd_resp(bottom_obj,(uint8_t *)&cmd,sizeof(cmd),(uint8_t *)&cmd,sizeof(cmd))>=0) 286 | { 287 | memcpy(mac_address, cmd.buf,6); 288 | } 289 | else{ 290 | LOGW("%s can't get mac addr\n",__FUNCTION__); 291 | } 292 | 293 | #endif 294 | 295 | 296 | 297 | } 298 | 299 | if(xfz_cfg80211_wiphy_init(apt)<0) 300 | goto error_wiphy; 301 | /* allocate network device context. */ 302 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) 303 | apt->ndev = alloc_netdev(sizeof(struct xfz_ndev_priv_context), NDEV_NAME, ether_setup); 304 | #else 305 | apt->ndev = alloc_netdev(sizeof(struct xfz_ndev_priv_context), NDEV_NAME,0, ether_setup); 306 | #endif 307 | if (apt->ndev == NULL) { 308 | LOGE("%s alloc netdev NG\n", __FUNCTION__); 309 | goto error_alloc_ndev; 310 | } 311 | /* fill private data of network context.*/ 312 | ndev_get_xfz_context(apt->ndev)->apt=apt; 313 | struct wireless_dev * wdev=&ndev_get_xfz_context(apt->ndev)->wdev; 314 | /* fill wireless_dev context. 315 | * wireless_dev with net_device can be represented as inherited class of single net_device. */ 316 | wdev->wiphy = apt->wiphy; 317 | wdev->netdev = apt->ndev; 318 | wdev->iftype = NL80211_IFTYPE_STATION; 319 | apt->ndev->ieee80211_ptr = wdev; 320 | 321 | wiphy_ext_feature_set(apt->wiphy, 322 | NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); 323 | /* set device object for net_device */ 324 | /* SET_NETDEV_DEV(ret->ndev, wiphy_dev(ret->wiphy)); */ 325 | 326 | /* set network device hooks. It should implement ndo_start_xmit() at least. */ 327 | apt->ndev->netdev_ops = &xfz_ndev_ops; 328 | 329 | /* Add here proper net_device initialization. */ 330 | 331 | // register network device. If everything ok, there should be new network device: 332 | // $ ip link show 333 | 334 | 335 | ether_addr_copy(apt->ndev->dev_addr, mac_address); 336 | if (register_netdev(apt->ndev)) { 337 | LOGE("%s register netdev NG\n", __FUNCTION__); 338 | goto error_ndev_register; 339 | } 340 | 341 | 342 | /* Prepare interface RX work */ 343 | apt->if_rx_workqueue = create_workqueue("XFZ_WIFI_RX_WORK_QUEUE"); 344 | 345 | if (!apt->if_rx_workqueue) { 346 | deinit_adapter(apt); 347 | goto error_ndev_register; 348 | } 349 | 350 | INIT_WORK(&apt->if_rx_work, link_rx_work); 351 | 352 | 353 | return apt; 354 | error_ndev_register: 355 | free_netdev(apt->ndev); 356 | error_alloc_ndev: 357 | wiphy_unregister(apt->wiphy); 358 | error_wiphy: 359 | return NULL; 360 | } 361 | 362 | 363 | 364 | 365 | 366 | 367 | void upper_layer_queue_wakeup(void * uobj) 368 | { 369 | struct xfz_cfg80211_adapter *adapter=uobj; 370 | 371 | 372 | if(adapter && 373 | netif_queue_stopped((const struct net_device *) 374 | adapter->ndev)){ 375 | netif_wake_queue(adapter->ndev); 376 | } 377 | 378 | 379 | } 380 | 381 | struct xfz_cfg80211_adapter * gp_apt=NULL; 382 | 383 | 384 | void * xfz_cfg80211_init(void * bottom_obj){ 385 | int ret = 0; 386 | struct xfz_cfg80211_adapter * apt = NULL; 387 | 388 | 389 | 390 | { 391 | 392 | /* Init adapter */ 393 | 394 | apt = init_adapter(bottom_obj); 395 | } 396 | 397 | 398 | if (!apt) 399 | return NULL; 400 | 401 | 402 | skb_queue_head_init(&apt->rx_queue); 403 | 404 | 405 | if (ret != 0) { 406 | deinit_adapter(apt); 407 | } 408 | 409 | apt->bottom_obj=bottom_obj; 410 | 411 | gp_apt=apt; 412 | return apt; 413 | 414 | 415 | } 416 | 417 | 418 | 419 | void xfz_cfg80211_exit(void){ 420 | struct xfz_cfg80211_adapter * apt=gp_apt; 421 | 422 | netif_stop_queue(apt->ndev); //stop queue first 423 | //then wait for a skb done, we doesn't use a sync way, just wait it done 424 | xfz_scan_done_evt(apt,NULL,true); 425 | msleep(1000); 426 | // 427 | skb_queue_purge(&apt->rx_queue); 428 | deinit_adapter(apt); 429 | /* make sure that no work is queued */ 430 | 431 | apt->bottom_obj=NULL; 432 | msg_queue_uninit(&apt->msg_mgr); 433 | cancel_work_sync(&apt->ws_connect); 434 | cancel_work_sync(&apt->ws_disconnect); 435 | cancel_work_sync(&apt->ws_scan); 436 | 437 | unregister_netdev(apt->ndev); 438 | free_netdev(apt->ndev); 439 | wiphy_unregister(apt->wiphy); 440 | wiphy_free(apt->wiphy); 441 | 442 | } 443 | 444 | int __init register_usb_link(void); 445 | void __exit unregister_usb_link(void); 446 | 447 | 448 | static int __init xfz_usb_wifi_init(void) 449 | { 450 | #ifdef NO_USB_SIMULATOR 451 | xfz_cfg80211_init(NULL); 452 | 453 | #else 454 | return register_usb_link(); 455 | #endif 456 | return 0; 457 | } 458 | 459 | static void __exit xfz_usb_wifi_exit(void) 460 | { 461 | #ifdef NO_USB_SIMULATOR 462 | xfz_cfg80211_exit(); 463 | #else 464 | unregister_usb_link(); 465 | #endif 466 | 467 | } 468 | 469 | module_init(xfz_usb_wifi_init); 470 | module_exit(xfz_usb_wifi_exit); 471 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/msg.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "log.h" 7 | 8 | #include "msg.h" 9 | 10 | 11 | #define ops_sync_lock(lock,flag) spin_lock_irqsave(lock, flag) 12 | #define ops_sync_unlock(lock,flag) spin_unlock_irqrestore(lock, flag) 13 | 14 | 15 | 16 | static void msg_queue_del_all_msg(msg_queue_t * mgr) 17 | { 18 | msg_item_t * node, *n; 19 | unsigned long flag; 20 | int i = 0; 21 | ops_sync_lock(&mgr->lock, flag); 22 | 23 | list_for_each_entry_safe(node, n, &mgr->msg_tb, list) 24 | { 25 | list_del(&(node->list)); 26 | atomic_dec(&mgr->atm_cnt); 27 | kfree(node); 28 | } 29 | ops_sync_unlock(&mgr->lock, flag); 30 | 31 | } 32 | 33 | 34 | 35 | int msg_queue_put_msg(msg_queue_t * mgr,int id,uint8_t * msg, size_t len) 36 | { 37 | 38 | msg_item_t * node; 39 | unsigned long flag; 40 | 41 | node = kmalloc(sizeof(msg_item_t), GFP_ATOMIC );//call form irq 42 | if(!node) 43 | { 44 | LOGE("%d kmalloc failure\n"); 45 | return -1; 46 | } 47 | memset(node, 0, sizeof(msg_item_t)); 48 | INIT_LIST_HEAD(&(node->list)); 49 | memcpy(node->data,msg,len); 50 | node->len=len; 51 | node->id=id; 52 | ops_sync_lock(&mgr->lock, flag); 53 | list_add(&node->list, &mgr->msg_tb); 54 | ops_sync_unlock(&mgr->lock, flag); 55 | atomic_inc(&mgr->atm_cnt); 56 | 57 | return 0; 58 | } 59 | 60 | 61 | 62 | int msg_queue_get_msg(msg_queue_t * mgr,int *id,uint8_t * msg, size_t len) 63 | { 64 | msg_item_t * node, *n; 65 | int ret=-1; 66 | unsigned long flag; 67 | ops_sync_lock(&mgr->lock, flag); 68 | list_for_each_entry_safe(node, n, &mgr->msg_tb, list) 69 | { 70 | 71 | list_del(&(node->list)); 72 | atomic_dec(&mgr->atm_cnt); 73 | memcpy(msg,node->data,node->len); 74 | if(id) 75 | *id=node->id; 76 | ret=node->len; 77 | kfree(node); 78 | break; 79 | } 80 | ops_sync_unlock(&mgr->lock, flag); 81 | 82 | return ret; 83 | } 84 | 85 | 86 | int msg_queue_init(msg_queue_t * mgr) 87 | { 88 | int ret = 0; 89 | int i = 0; 90 | 91 | if(MGR_INIT_MAGIC_NUM != mgr->init_magic) 92 | { 93 | 94 | INIT_LIST_HEAD(&mgr->msg_tb); 95 | spin_lock_init(&mgr->lock); 96 | mgr->init_magic = MGR_INIT_MAGIC_NUM; 97 | atomic_set(&mgr->atm_cnt, 0); 98 | 99 | } 100 | return ret; 101 | } 102 | 103 | 104 | 105 | int msg_queue_uninit(msg_queue_t * mgr) 106 | { 107 | 108 | if(MGR_INIT_MAGIC_NUM == mgr->init_magic) 109 | { 110 | msg_queue_del_all_msg(mgr); 111 | LOGW("%s list atm:%d\n", __FUNCTION__, atomic_read(&mgr->atm_cnt)); 112 | mgr->init_magic = 0; 113 | } 114 | return 0; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/msg.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MSG_MGR__H_ 3 | #define __MSG_MGR__H_ 4 | 5 | #include 6 | 7 | 8 | #define MGR_INIT_MAGIC_NUM 0x55AA9527 9 | 10 | typedef struct 11 | { 12 | spinlock_t lock; 13 | struct list_head msg_tb; 14 | atomic_t atm_cnt; 15 | int init_magic; 16 | 17 | }msg_queue_t; 18 | 19 | #define MSG_ITEM_DATA_SIZE 2048 20 | 21 | typedef struct 22 | { 23 | int id; 24 | uint8_t data[MSG_ITEM_DATA_SIZE]; 25 | size_t len; 26 | struct list_head list; 27 | 28 | } msg_item_t; 29 | 30 | int msg_queue_init(msg_queue_t * mgr); 31 | int msg_queue_uninit(msg_queue_t * mgr); 32 | int msg_queue_get_msg(msg_queue_t * mgr,int *id,uint8_t * msg, size_t len); 33 | int msg_queue_put_msg(msg_queue_t * mgr,int id,uint8_t * msg, size_t len); 34 | 35 | 36 | 37 | 38 | #endif 39 | 40 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/usb_link.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xfz1986 Linux wifi usb layer Driver 3 | * 4 | * Copyright (C) 2022- 5 | * This file is licensed under the GPL. 6 | * 7 | * Author chaunjin 8 | * ----------------------------------------------------------------- 9 | * USB layer Driver Implementations 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "usb_link.h" 35 | #include "link_glue.h" 36 | 37 | #include "log.h" 38 | 39 | 40 | #define USB_EP_OUT_SIZE 64 41 | 42 | 43 | #define USBLINK_RX_RETRY_COUNT 3 44 | #define USBLINK_MAX_TRANSFER_SIZE (4096) 45 | 46 | 47 | #define TX_DELAY_MIN 500 48 | #define TX_DELAY_MAX 900 49 | 50 | #define RX_DELAY_MIN 500 51 | #define RX_DELAY_MAX 900 52 | 53 | 54 | #define DL_ALIGN_UP(x, a) ALIGN(x, a) 55 | #define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a) 56 | 57 | 58 | #define XFZ1986_USB_VENDOR_ID 0x303a 59 | #define XFZ1986_USB_PRODUCT_ID 0x1987 //1986 used for usb display,so we use +1=1987 60 | 61 | static const struct usb_device_id id_table[] = { 62 | { 63 | .idVendor = XFZ1986_USB_VENDOR_ID, 64 | .idProduct = XFZ1986_USB_PRODUCT_ID, 65 | .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT, 66 | }, 67 | { }, 68 | }; 69 | 70 | 71 | 72 | #include 73 | 74 | DECLARE_COMPLETION(cmd_completion); 75 | 76 | 77 | 78 | static void _usblink_rx_handler(struct usb_link_dev * dev); 79 | 80 | 81 | uint16_t crc16_calc_multi(uint16_t crc_reg, unsigned char *puchMsg, unsigned int usDataLen ) 82 | { 83 | uint16_t i,j,check; 84 | for(i=0;i>8) ^ puchMsg[i]; 87 | for(j=0;j<8;j++) 88 | { 89 | check = crc_reg & 0x0001; 90 | crc_reg >>= 1; 91 | if(check==0x0001){ 92 | crc_reg ^= 0xA001; 93 | } 94 | } 95 | } 96 | return crc_reg; 97 | } 98 | uint16_t crc16_calc(unsigned char *puchMsg, unsigned int usDataLen ) 99 | { 100 | return crc16_calc_multi(0xFFFF,puchMsg,usDataLen); 101 | } 102 | 103 | 104 | 105 | 106 | 107 | 108 | #define RAND_RANGE 3 109 | static uint32_t x_random(void) { 110 | //X(n+1) = (a * X(n) + c) % m 111 | static uint32_t a=1103515245,c=12345,m=134217728, seed=31; 112 | seed = (a*seed + c)%m; 113 | return seed; 114 | } 115 | 116 | 117 | 118 | int pop_msg_data(usblink_msg_mgr_t *mgr,uint8_t * rx_buf, int len) 119 | { 120 | if(0 == len) { 121 | return 0; 122 | } 123 | 124 | if(mgr->cur_cnt+len>USBLINK_MSG_MAX_SIZE) 125 | { 126 | return -1; 127 | } 128 | memcpy(&mgr->msg.payload[mgr->cur_cnt],rx_buf,len); 129 | mgr->cur_cnt+=len; 130 | 131 | 132 | return 0; 133 | } 134 | 135 | 136 | 137 | 138 | void push_skb( struct usb_link_dev *dev,uint8_t * msg, int len) 139 | { 140 | u8 *rx_buf; 141 | int skb_len=0; 142 | struct sk_buff *skb = dev_alloc_skb(LINK_MSG_MAX_SIZE); 143 | if (!skb) { 144 | return; 145 | } 146 | skb_reserve(skb,2); 147 | rx_buf=skb_put(skb,0); 148 | if(len>LINK_MSG_MAX_SIZE){ 149 | return; 150 | } 151 | memcpy(rx_buf,msg,len); 152 | skb_len=len; 153 | skb_put(skb,skb_len); 154 | push_skb_upper_layer(dev->upper_obj,skb); 155 | } 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | void push_cmd_resp( struct usb_link_dev *dev,uint8_t * msg, int len) 165 | { 166 | cmd_resp64_t * pcmd=(cmd_resp64_t * )dev->resp_buffer; 167 | if(len>=USBLINK_RX_BUFFER_SIZE){ 168 | return ; 169 | } 170 | memcpy(dev->resp_buffer,msg,len); 171 | dev->resp_len=len; 172 | 173 | if(upper_layer_msg_handler(dev->upper_obj, dev->resp_buffer,len))//upper layer hanle it 174 | return; 175 | switch(pcmd->cmd_op) { 176 | 177 | default: 178 | complete(&cmd_completion); 179 | } 180 | 181 | } 182 | 183 | 184 | 185 | 186 | #define XFZ_MIN(x,y) (x)<(y)?(x):(y) 187 | 188 | 189 | int decode_urb_msg(usblink_msg_mgr_t *mgr,uint8_t * rx_buf,int rx_len) 190 | { 191 | 192 | int i=0; 193 | int read_res=0; 194 | int remain=rx_len; 195 | uint16_t crc_ret=0; 196 | static int crc_total_cnt=0; 197 | static int rx_crc_cnt=0; 198 | 199 | crc_total_cnt++; 200 | 201 | while(remain) { 202 | 203 | read_res=XFZ_MIN(USB_EP_OUT_SIZE,remain); 204 | remain-=read_res; 205 | if(read_res > 0) { 206 | usblink_start_crc_msg_t * pstart = (usblink_start_crc_msg_t *)rx_buf; 207 | if(pstart->flag_total_bytes & USBLINK_PROTOCOL_HEADER_START) { 208 | mgr->flag = USBLINK_PROTOCOL_HEADER_START ; 209 | if(pstart->flag_total_bytes & USBLINK_PROTOCOL_HEADER_OPCODE) 210 | mgr->flag |= USBLINK_PROTOCOL_HEADER_OPCODE ; 211 | mgr->total = pstart->flag_total_bytes & USBLINK_PROTOCOL_HEADER_LEN_MASK; 212 | mgr->cur_cnt=0; 213 | mgr->crc=pstart->crc; 214 | if(mgr->total>USBLINK_MSG_MAX_SIZE){ 215 | LOGW("rx wrong len oversize:%d\n",mgr->total); 216 | mgr->total=0; 217 | return -2; 218 | } 219 | 220 | } 221 | //pop data 222 | if (pstart->flag_total_bytes & USBLINK_PROTOCOL_HEADER_END){ 223 | if(0==mgr->cur_cnt) { 224 | pop_msg_data(mgr,&rx_buf[sizeof(usblink_start_crc_msg_t)], read_res - sizeof(usblink_start_crc_msg_t)); 225 | 226 | } 227 | else { 228 | pop_msg_data(mgr,&rx_buf[sizeof(usblink_start_msg_t)], read_res - sizeof(usblink_start_msg_t)); 229 | } 230 | 231 | if(mgr->cur_cnttotal){ 232 | LOGW("usb rx error when end %d %d\n",mgr->cur_cnt,mgr->total); 233 | return -2;//drop the pkt 234 | } 235 | else {//ok, we got a usblink msg, the issue it 236 | mgr->msg.len= mgr->total; 237 | crc_ret=crc16_calc(mgr->msg.payload,mgr->msg.len); 238 | if(crc_ret != mgr->crc){ 239 | rx_crc_cnt++; 240 | return -1; 241 | }else { 242 | return 0; 243 | } 244 | 245 | } 246 | } 247 | else { 248 | 249 | if(0==mgr->cur_cnt) { 250 | pop_msg_data(mgr,&rx_buf[sizeof(usblink_start_crc_msg_t)], read_res - sizeof(usblink_start_crc_msg_t)); 251 | 252 | } 253 | else { 254 | pop_msg_data(mgr,&rx_buf[sizeof(usblink_start_msg_t)], read_res - sizeof(usblink_start_msg_t)); 255 | } 256 | 257 | } 258 | 259 | } 260 | rx_buf+=USB_EP_OUT_SIZE; 261 | } 262 | return -3; 263 | 264 | 265 | } 266 | void push_urb_data(struct usb_link_dev *dev,uint8_t * buf,int len) { 267 | usblink_msg_mgr_t *mgr=&dev->msg_mgr; 268 | int ret=0; 269 | 270 | upper_layer_status (dev->upper_obj); 271 | 272 | ret=decode_urb_msg(mgr,buf,len); 273 | 274 | 275 | if(ret>=0) { 276 | if(mgr->flag & USBLINK_PROTOCOL_HEADER_OPCODE){ 277 | //so it maybe wrong data, it no integrity protect it. 278 | push_cmd_resp(dev,mgr->msg.payload,mgr->msg.len); 279 | } 280 | else 281 | push_skb(dev,mgr->msg.payload,mgr->msg.len); 282 | 283 | 284 | } 285 | } 286 | 287 | 288 | 289 | static void usb_rx_routine(struct work_struct *w) { 290 | struct usb_link_dev *dev= container_of(w, struct usb_link_dev, ws_rx); 291 | 292 | if(-EPIPE == dev->usb_rx_pipe_status) { 293 | LOGW("in %s NG_cnt:%d clear halt\n",__FUNCTION__,dev->urb_status_fail_count); 294 | //usb_clear_halt(dev->udev, usb_rcvintpipe(dev->udev, dev->in_rx_ep_addr)); 295 | dev->usb_rx_pipe_status=0; 296 | dev->urb_status_fail_count=0; 297 | msleep(50); 298 | } 299 | if(dev->usb_rx_pipe_status<0){ 300 | LOGW("in %s rx urb error so wait\n",__FUNCTION__); 301 | msleep(20); 302 | } 303 | #if 1 304 | 305 | { 306 | 307 | usleep_range(RX_DELAY_MIN,RX_DELAY_MAX); 308 | 309 | } 310 | #endif 311 | 312 | _usblink_rx_handler(dev); 313 | } 314 | 315 | 316 | static void usblink_rx_finished(struct urb *urb) 317 | { 318 | struct usb_link_dev *dev = urb->context; 319 | 320 | if(!dev->is_alive) { 321 | return; 322 | } 323 | 324 | 325 | switch(urb->status) { 326 | case 0: 327 | // succeed 328 | if(urb->actual_length>2) 329 | push_urb_data(dev,dev->rx_buffer,urb->actual_length); 330 | 331 | break; 332 | case -EPIPE: 333 | LOGW("%s EPIPE\n",__FUNCTION__); 334 | dev->usb_rx_pipe_status=-EPIPE; 335 | default: 336 | dev->urb_status_fail_count++; 337 | LOGW("in %s error? %d actlen:%d\n",__FUNCTION__,urb->status,urb->actual_length); 338 | 339 | } 340 | 341 | 342 | #if 1 343 | if(dev->urb_status_fail_count < USBLINK_RX_RETRY_COUNT) { 344 | 345 | dev->usb_rx_pipe_status=urb->status; 346 | 347 | if (!schedule_work(&dev->ws_rx)) { 348 | LOGE("%s shecd evt ws for rx NG\n",__FUNCTION__); 349 | } 350 | } else { 351 | dev->usb_rx_pipe_status=-EPIPE; 352 | if (!schedule_work(&dev->ws_rx)) { 353 | LOGE("%s shecd evt ws EPIPE NG\n",__FUNCTION__); 354 | } 355 | 356 | 357 | } 358 | 359 | #endif 360 | } 361 | 362 | 363 | 364 | static void _usblink_rx_handler(struct usb_link_dev * dev) 365 | { 366 | unsigned int pipe; 367 | int status; 368 | struct usb_host_endpoint *ep; 369 | 370 | 371 | 372 | if(!dev->is_alive) { 373 | // the device is del 374 | return; 375 | } 376 | 377 | 378 | 379 | #if 1 380 | 381 | 382 | pipe = usb_rcvbulkpipe(dev->udev, dev->in_rx_ep_addr); 383 | ep = usb_pipe_endpoint(dev->udev, pipe); 384 | 385 | 386 | if(!ep) return; 387 | 388 | usb_fill_bulk_urb(dev->rx_urb, dev->udev, pipe, dev->rx_buffer, USBLINK_RX_BUFFER_SIZE, 389 | usblink_rx_finished, dev ); 390 | 391 | //submit it 392 | status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); 393 | if(status) { 394 | if(status == -EPIPE) { 395 | LOGE("in %s %d NG_cnt:%d clera halt\n",__FUNCTION__,status,dev->urb_status_fail_count); 396 | usb_clear_halt(dev->udev, pipe); 397 | } 398 | 399 | ++ dev->urb_status_fail_count; 400 | } 401 | #else 402 | 403 | return ; 404 | #endif 405 | } 406 | 407 | 408 | 409 | 410 | static int _usblink_encode_urb_msg(uint16_t cmd_flg,uint8_t * urb_msg, const uint8_t * data, size_t data_len,int out_ep_max_size ) 411 | { 412 | int encoded_pos=0; 413 | const uint8_t * payload_in_bytes = data; 414 | usblink_start_msg_t *phd=NULL; 415 | int len = 0; 416 | int count=data_len; 417 | int size_to_copy=0; 418 | int buffer_avail_length= out_ep_max_size-sizeof(usblink_start_msg_t); 419 | uint16_t crc=0; 420 | crc=crc16_calc(data,data_len); 421 | count+=2;//resv crc bytes, we can't padding crc to endof msg, it could ovf bug, so we add it at begin of encode msg. encode[crc16+msg] 422 | while(count) { 423 | // fill the buffer as much as possible... 424 | size_to_copy = count > buffer_avail_length ? buffer_avail_length : count; 425 | phd=(usblink_start_msg_t *)(urb_msg + encoded_pos); 426 | phd->flag_total_bytes=data_len; 427 | encoded_pos+=sizeof(usblink_start_msg_t); 428 | if(0 == len) {//mark start flag 429 | phd->flag_total_bytes|=USBLINK_PROTOCOL_HEADER_START|cmd_flg; 430 | memcpy(urb_msg + encoded_pos,&crc,2);//fill crc at header 431 | size_to_copy-=2; 432 | encoded_pos+=2; 433 | len+=2; 434 | count-=2; 435 | } 436 | if(size_to_copy>=count)//end case 437 | { 438 | phd->flag_total_bytes|=USBLINK_PROTOCOL_HEADER_END|cmd_flg; 439 | } 440 | 441 | 442 | memcpy(urb_msg + encoded_pos, payload_in_bytes,size_to_copy); 443 | len += size_to_copy; 444 | payload_in_bytes += size_to_copy; 445 | encoded_pos += size_to_copy; 446 | count -= size_to_copy; 447 | } 448 | 449 | 450 | return encoded_pos; 451 | } 452 | 453 | static int usblink_encode_urb_msg(uint16_t cmd_flg,uint8_t * urb_msg, const uint8_t * data, size_t count,int out_ep_max_size ){ 454 | int urb_len=0; 455 | 456 | 457 | 458 | urb_len=_usblink_encode_urb_msg(cmd_flg,urb_msg,data,count,out_ep_max_size); 459 | 460 | 461 | if(0==(urb_len%USB_EP_OUT_SIZE)){ 462 | urb_len+=4; 463 | } 464 | 465 | 466 | return urb_len; 467 | 468 | } 469 | 470 | typedef void ( *urb_tx_finished_cb )(struct urb *urb); 471 | 472 | static void _on_urb_skb_tx_finished(struct urb *urb) 473 | { 474 | struct usb_link_dev * dev= (struct usb_link_dev *)urb->context; 475 | 476 | if(urb->status) { 477 | 478 | LOGE("skb tx failed for urb %p, error code %x %d\n", urb, urb->status, urb->status); 479 | 480 | } 481 | upper_layer_queue_wakeup(dev->upper_obj); 482 | 483 | 484 | } 485 | 486 | static void _on_urb_cmd_tx_finished(struct urb *urb) 487 | { 488 | struct usb_link_dev * dev= (struct usb_link_dev *)urb->context; 489 | 490 | if(urb->status) { 491 | 492 | LOGE("cmd tx failed for urb %p, error code %x %d\n", urb, urb->status, urb->status); 493 | 494 | } 495 | 496 | 497 | } 498 | 499 | 500 | int issue_urb(struct usb_link_dev * dev, struct urb * turb,urb_tx_finished_cb cb, uint8_t * msg,size_t transfer_size ) 501 | { 502 | 503 | if(!dev->is_alive){ 504 | LOGW("%s dev is no alive\n",__FUNCTION__); 505 | return -1; 506 | } 507 | 508 | 509 | if(transfer_size) { 510 | usb_fill_bulk_urb(turb, dev->udev, usb_sndbulkpipe(dev->udev, dev->out_tx_ep_addr), msg, 511 | transfer_size, cb, dev); 512 | 513 | if(usb_submit_urb(turb, GFP_ATOMIC)) { 514 | // submit failure 515 | LOGW("submit urb NG\n"); 516 | return -1; 517 | //abort 518 | } 519 | } 520 | 521 | return 0; 522 | } 523 | 524 | static int tx_ws_cnt=0; 525 | static void usb_tx_routine(struct work_struct *w) { 526 | struct usb_link_dev *dev= container_of(w, struct usb_link_dev, ws_tx); 527 | 528 | 529 | if(dev->tx_len> 128){ 530 | 531 | //wait a while for tx 532 | usleep_range(TX_DELAY_MIN,TX_DELAY_MAX); 533 | 534 | } 535 | 536 | 537 | 538 | if(issue_urb(dev,dev->tx_urb,_on_urb_skb_tx_finished,dev->tx_buffer,dev->tx_len)<0) 539 | { 540 | upper_layer_queue_wakeup(dev->upper_obj);//upper layer stop queue, we need wakeup it. 541 | } 542 | 543 | tx_ws_cnt--; 544 | 545 | } 546 | 547 | 548 | 549 | void usb_link_send_msg(struct usb_link_dev * dev,const uint8_t * msg_data, int msg_len) 550 | { 551 | int urb_len=0; 552 | 553 | urb_len=usblink_encode_urb_msg(0,dev->tx_buffer,msg_data,msg_len,USB_EP_OUT_SIZE); 554 | dev->tx_len=urb_len; 555 | 556 | if (!schedule_work(&dev->ws_tx)) { 557 | LOGE("%s shecd evt tx NG,tx_ws_cnt:%d\n",__FUNCTION__,tx_ws_cnt); 558 | upper_layer_queue_wakeup(dev->upper_obj); 559 | } 560 | else{ 561 | tx_ws_cnt++; 562 | } 563 | 564 | 565 | 566 | } 567 | 568 | 569 | 570 | 571 | int usb_link_issue_cmd_resp(struct usb_link_dev * dev,const uint8_t * cmd, int msg_len,uint8_t * resp,int resp_len) 572 | { 573 | 574 | int i=0; 575 | uint32_t wt_cnt=0; 576 | int urb_len=0; 577 | 578 | 579 | urb_len=usblink_encode_urb_msg(USBLINK_PROTOCOL_HEADER_OPCODE,dev->tx_cmd_buffer,cmd,msg_len,USB_EP_OUT_SIZE); 580 | dev->tx_cmd_len=urb_len; 581 | 582 | 583 | 584 | reinit_completion(&cmd_completion);//need frist init completon before issue cmd,index no done before previous msg. 585 | 586 | 587 | issue_urb(dev,dev->tx_cmd_urb,_on_urb_cmd_tx_finished, dev->tx_cmd_buffer,urb_len); 588 | 589 | unsigned long time_left=wait_for_completion_timeout(&cmd_completion,3 * HZ); 590 | if(!time_left) { 591 | LOGE("wait for cmd resp timeout\n"); 592 | return -1; 593 | } 594 | else { 595 | if(dev->resp_len > resp_len ){ 596 | LOGE("got cmd resp too big %d %d\n",dev->resp_len,resp_len); 597 | return -2; 598 | } 599 | memcpy(resp,dev->resp_buffer,dev->resp_len); 600 | return 0; 601 | } 602 | 603 | } 604 | 605 | 606 | 607 | 608 | 609 | static int new_usb_link_device(struct usb_link_dev * dev) 610 | { 611 | 612 | 613 | 614 | mutex_init(&dev->op_locker); 615 | 616 | 617 | dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 618 | if(! dev->tx_urb) { 619 | LOGE("can't allocate tx urb\n"); 620 | goto urb_alloc_err; 621 | } 622 | 623 | dev->tx_cmd_urb = usb_alloc_urb(0, GFP_KERNEL); 624 | if(! dev->tx_cmd_urb) { 625 | LOGE("can't allocate tx_cmd_urb\n"); 626 | goto urb_alloc_err; 627 | } 628 | 629 | 630 | dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 631 | if(! dev->rx_urb) { 632 | LOGE("can't allocate rx urb\n"); 633 | goto urb_alloc_err; 634 | } 635 | 636 | dev->is_alive = 1; 637 | 638 | // int tx & rx work struct 639 | INIT_WORK(&dev->ws_rx, usb_rx_routine); 640 | INIT_WORK(&dev->ws_tx, usb_tx_routine); 641 | dev->usb_rx_pipe_status=0; 642 | _usblink_rx_handler(dev); 643 | 644 | dev->upper_obj=upper_layer_init(dev); 645 | return 0; 646 | 647 | 648 | urb_alloc_err: 649 | if(dev->tx_urb) 650 | usb_free_urb(dev->tx_urb); 651 | if(dev->tx_cmd_urb) 652 | usb_free_urb(dev->tx_cmd_urb); 653 | if(dev->rx_urb ) 654 | usb_free_urb(dev->rx_urb); 655 | 656 | 657 | return -ENOMEM; 658 | } 659 | 660 | 661 | static void _on_del_usb_device(struct usb_link_dev * dev) 662 | { 663 | 664 | mutex_lock(&dev->op_locker); 665 | dev->is_alive = 0; 666 | mutex_unlock(&dev->op_locker); 667 | 668 | 669 | // kill all pending urbs 670 | usb_kill_urb(dev->rx_urb); 671 | usb_free_urb(dev->rx_urb); 672 | 673 | 674 | usb_kill_urb(dev->tx_urb); 675 | usb_free_urb(dev->tx_urb); 676 | 677 | usb_kill_urb(dev->tx_cmd_urb); 678 | usb_free_urb(dev->tx_cmd_urb); 679 | 680 | 681 | dev->tx_urb = NULL; 682 | dev->rx_urb = NULL; 683 | dev->tx_cmd_urb = NULL; 684 | 685 | } 686 | 687 | 688 | 689 | static int usb_link_probe(struct usb_interface *interface, const struct usb_device_id *id) 690 | { 691 | 692 | struct usb_link_dev *dev = NULL; 693 | struct usb_host_interface *iface_desc; 694 | struct usb_endpoint_descriptor *endpoint; 695 | size_t buffer_size; 696 | int i; 697 | int retval = -ENOMEM; 698 | 699 | dev = kzalloc(sizeof(struct usb_link_dev), GFP_KERNEL); 700 | if(dev == NULL) { 701 | LOGE("out of memory\n"); 702 | goto error; 703 | } 704 | 705 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); 706 | dev->interface = interface; 707 | 708 | 709 | 710 | // check for endpoints 711 | iface_desc = interface->cur_altsetting; 712 | 713 | for(i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 714 | endpoint = &iface_desc->endpoint[i].desc; 715 | 716 | if(!dev->in_rx_ep_addr && 717 | usb_endpoint_is_bulk_in(endpoint)) { 718 | 719 | buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); 720 | dev->in_rx_ep_addr = endpoint->bEndpointAddress; 721 | 722 | } 723 | 724 | if(!dev->out_tx_ep_addr && 725 | usb_endpoint_is_bulk_out(endpoint) && endpoint->wMaxPacketSize) { 726 | 727 | dev->out_tx_ep_addr = endpoint->bEndpointAddress; 728 | dev->out_ep_tx_max_size = le16_to_cpu(endpoint->wMaxPacketSize); 729 | 730 | } 731 | } 732 | 733 | if(!(dev->in_rx_ep_addr && dev->out_tx_ep_addr)) { 734 | LOGE("we can't find the in:%x or out:%x ep\n",dev->in_rx_ep_addr,dev->out_tx_ep_addr); 735 | goto error; 736 | } 737 | 738 | 739 | // set ctx to itf 740 | usb_set_intfdata(interface, dev); 741 | 742 | // add the device 743 | if(new_usb_link_device(dev)) { 744 | goto error; 745 | } 746 | 747 | 748 | return 0; 749 | 750 | error: 751 | if(dev) { 752 | kfree(dev); 753 | } 754 | return retval; 755 | } 756 | 757 | 758 | 759 | static int usb_link_suspend(struct usb_interface *intf, pm_message_t message) 760 | { 761 | struct usb_lcd *dev = usb_get_intfdata(intf); 762 | 763 | if(!dev) 764 | return 0; 765 | // not implemented yet 766 | return 0; 767 | } 768 | 769 | 770 | static int usb_link_resume(struct usb_interface *intf) 771 | { 772 | // not implemented yet 773 | return 0; 774 | } 775 | 776 | 777 | 778 | 779 | static void usb_link_disconnect(struct usb_interface *interface) 780 | { 781 | struct usb_link_dev *dev; 782 | 783 | dev = usb_get_intfdata(interface); 784 | dev->is_alive = 0;//frist no rx usr 785 | 786 | upper_layer_deinit(); 787 | usb_set_intfdata(interface, NULL); 788 | _on_del_usb_device(dev); 789 | kfree(dev); 790 | } 791 | 792 | 793 | static struct usb_driver xfz_usblink_driver = { 794 | .name = "xfz_usb_link", 795 | .probe = usb_link_probe, 796 | .disconnect = usb_link_disconnect, 797 | .suspend = usb_link_suspend, 798 | .resume = usb_link_resume, 799 | .id_table = id_table, 800 | .supports_autosuspend = 0, 801 | }; 802 | 803 | int __init register_usb_link(void) 804 | { 805 | 806 | return usb_register(&xfz_usblink_driver); 807 | } 808 | 809 | 810 | void __exit unregister_usb_link(void) 811 | { 812 | 813 | 814 | usb_deregister(&xfz_usblink_driver); 815 | } 816 | 817 | 818 | 819 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/usb_link.h: -------------------------------------------------------------------------------- 1 | /* 2 | * xfz1986 Linux wifi usb layer Driver 3 | * 4 | * Copyright (C) 2022- 5 | * This file is licensed under the GPL. 6 | * 7 | * Author chaunjin 8 | * ----------------------------------------------------------------- 9 | * USB layer Driver Implementations 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | #ifndef __USB_LINK_H__ 31 | #define __USB_LINK_H__ 32 | 33 | 34 | #define USBLINK_PROTOCOL_HEADER_START (0x1<<15) 35 | #define USBLINK_PROTOCOL_HEADER_END (0x1<<14) 36 | #define USBLINK_PROTOCOL_HEADER_OPCODE (0x1<<13) 37 | #define USBLINK_PROTOCOL_HEADER_LEN_MASK (0x0fff) //max 4KB 38 | 39 | 40 | 41 | 42 | typedef struct { 43 | uint16_t flag_total_bytes; 44 | } __attribute__((packed)) usblink_start_msg_t; 45 | 46 | typedef struct { 47 | uint16_t flag_total_bytes; 48 | uint16_t crc; 49 | } __attribute__((packed)) usblink_start_crc_msg_t; 50 | 51 | 52 | #define USBLINK_MSG_MAX_SIZE 2048 53 | 54 | 55 | typedef struct { 56 | uint8_t payload[USBLINK_MSG_MAX_SIZE]; 57 | size_t len; 58 | } usblink_msg_t; 59 | 60 | 61 | 62 | #define USBLINK_RX_BUFFER_SIZE 1728 63 | #define USBLINK_TX_BUFFER_SIZE 1728 64 | #define USBLINK_RX_EP_SIZE 64 65 | 66 | 67 | typedef struct { 68 | int flag; 69 | int total; 70 | int cur_cnt; 71 | uint16_t crc; 72 | usblink_msg_t msg; 73 | } usblink_msg_mgr_t; 74 | 75 | 76 | struct usb_link_dev { 77 | struct mutex op_locker; 78 | int is_alive; 79 | 80 | // usb device info 81 | struct usb_device * udev; 82 | struct usb_interface * interface; 83 | void * upper_obj; 84 | 85 | usblink_msg_mgr_t msg_mgr; 86 | 87 | // status package related 88 | uint8_t resp_buffer[USBLINK_RX_BUFFER_SIZE]; 89 | 90 | int resp_len; 91 | uint8_t rx_buffer[USBLINK_RX_BUFFER_SIZE]; // data buffer for the IN endpoint 92 | 93 | uint8_t tx_buffer[USBLINK_TX_BUFFER_SIZE]; // data buffer for the OUT endpoint 94 | 95 | int tx_len; 96 | uint8_t tx_cmd_buffer[USBLINK_TX_BUFFER_SIZE]; // data buffer for the OUT endpoint 97 | 98 | int tx_cmd_len; 99 | 100 | 101 | uint8_t in_rx_ep_addr; 102 | uint8_t out_tx_ep_addr; 103 | 104 | struct urb *tx_urb; /* URB for sending data */ 105 | struct urb *tx_cmd_urb; /* URB for cmd, we use this for avoid race-cond bug */ 106 | struct urb *rx_urb; /* URB for receiving data */ 107 | 108 | int urb_status_fail_count; 109 | size_t out_ep_tx_max_size; 110 | struct work_struct ws_rx; 111 | struct work_struct ws_tx; 112 | int usb_rx_pipe_status; 113 | 114 | 115 | }; 116 | 117 | 118 | int usb_link_issue_cmd_resp(struct usb_link_dev * dev,const uint8_t * cmd, int msg_len,uint8_t * resp,int resp_len); 119 | 120 | void usb_link_send_msg(struct usb_link_dev * dev,const uint8_t * msg_data, int msg_len); 121 | 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /linux_host_usb_80211_wifi_driver/xfz_cfg80211.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | a diy project refer espressif hosted project for usb 802.11 wifi 4 | 1.first write on 20211111 by chuanjin 5 | */ 6 | 7 | 8 | #ifndef __XFZ_CFG80211_H__ 9 | #define __XFZ_CFG80211_H__ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | 17 | #include "msg.h" 18 | 19 | #define MAX_SSID_SIZE 128 20 | struct xfz_cfg80211_adapter { 21 | //cfg 802.11 22 | struct net_device *ndev; 23 | struct net_device_stats stats; 24 | struct wiphy *wiphy; 25 | struct semaphore sem; 26 | struct cfg80211_scan_request *scan_request; 27 | struct work_struct ws_scan; 28 | char connecting_ssid[MAX_SSID_SIZE]; 29 | int ssid_len; 30 | u8 psk[32]; 31 | struct work_struct ws_connect; 32 | u16 disconnect_reason_code; 33 | struct work_struct ws_disconnect; 34 | 35 | struct sk_buff_head rx_queue; 36 | 37 | struct workqueue_struct *if_rx_workqueue; 38 | struct work_struct if_rx_work; 39 | 40 | /* Process TX work */ 41 | struct work_struct ws_evt; 42 | msg_queue_t msg_mgr; 43 | 44 | void * bottom_obj; 45 | }; 46 | 47 | 48 | 49 | 50 | struct xfz_cfg80211_skb_cb { 51 | struct xfz_cfg80211_adapter *priv; 52 | }; 53 | 54 | 55 | int xfz_cfg80211_wiphy_init(struct xfz_cfg80211_adapter * apt); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /test_firmware/esp32s2_usb_wifi_firmware/bootloader.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuanjinpang/esp32s2_linux_80211_wifi_driver/14fefd870c43e057c691c82dbf8e8f84d31be08d/test_firmware/esp32s2_usb_wifi_firmware/bootloader.bin -------------------------------------------------------------------------------- /test_firmware/esp32s2_usb_wifi_firmware/esp32_usb_wifi_firmware.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuanjinpang/esp32s2_linux_80211_wifi_driver/14fefd870c43e057c691c82dbf8e8f84d31be08d/test_firmware/esp32s2_usb_wifi_firmware/esp32_usb_wifi_firmware.bin -------------------------------------------------------------------------------- /test_firmware/esp32s2_usb_wifi_firmware/partition-table.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuanjinpang/esp32s2_linux_80211_wifi_driver/14fefd870c43e057c691c82dbf8e8f84d31be08d/test_firmware/esp32s2_usb_wifi_firmware/partition-table.bin -------------------------------------------------------------------------------- /wpa_supplicant-2.9.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuanjinpang/esp32s2_linux_80211_wifi_driver/14fefd870c43e057c691c82dbf8e8f84d31be08d/wpa_supplicant-2.9.tar.gz --------------------------------------------------------------------------------