diff --git a/build_part5 b/build_part5 deleted file mode 100644 index 4f6527b..0000000 --- a/build_part5 +++ /dev/null @@ -1 +0,0 @@ -arm-none-eabi-gcc -specs=./sdk/Alpha.specs -mfloat-abi=hard -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -g3 -ggdb -Wall -Wl,-T./sdk/link.ld -L./sdk -Wl,-umalloc -fpack-struct=1 -o zerowi.elf srce/part5.c srce/zw_sdio.c srce/zw_ioctl.c srce/zw_gpio.c \ No newline at end of file diff --git a/build_part5.bat b/build_part5.bat deleted file mode 100644 index 7985fc7..0000000 --- a/build_part5.bat +++ /dev/null @@ -1 +0,0 @@ -arm-none-eabi-gcc -specs=./sdk/Alpha.specs -mfloat-abi=hard -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -g3 -ggdb -Wall -Wl,-T./sdk/link.ld -L./sdk -Wl,-umalloc -fpack-struct=1 -o zerowi.elf srce/part5.c srce/zw_sdio.c srce/zw_ioctl.c srce/zw_gpio.c diff --git a/make_join b/make_join new file mode 100644 index 0000000..5f2d9bd --- /dev/null +++ b/make_join @@ -0,0 +1 @@ +arm-none-eabi-gcc -specs=./sdk/Alpha.specs -mfloat-abi=hard -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -g3 -ggdb -Wall -Wl,-T./sdk/link.ld -L./sdk -I./whd -Wl,-umalloc -fpack-struct=1 -o zerowi.elf srce/zjoin.c srce/zw_sdio.c srce/zw_ioctl.c srce/zw_gpio.c \ No newline at end of file diff --git a/make_join.bat b/make_join.bat new file mode 100644 index 0000000..b8e2050 --- /dev/null +++ b/make_join.bat @@ -0,0 +1 @@ +arm-none-eabi-gcc -specs=./sdk/Alpha.specs -mfloat-abi=hard -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -g3 -ggdb -Wall -Wl,-T./sdk/link.ld -I./whd -I./srce -L./sdk -Wl,-umalloc -fpack-struct=1 -o zerowi.elf srce/zjoin.c srce/zw_sdio.c srce/zw_ioctl.c srce/zw_gpio.c diff --git a/make_scan b/make_scan new file mode 100644 index 0000000..02734ad --- /dev/null +++ b/make_scan @@ -0,0 +1 @@ +arm-none-eabi-gcc -specs=./sdk/Alpha.specs -mfloat-abi=hard -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -g3 -ggdb -Wall -Wl,-T./sdk/link.ld -L./sdk -I./whd -Wl,-umalloc -fpack-struct=1 -o zerowi.elf srce/zscan.c srce/zw_sdio.c srce/zw_ioctl.c srce/zw_gpio.c \ No newline at end of file diff --git a/make_scan.bat b/make_scan.bat new file mode 100644 index 0000000..834dcdd --- /dev/null +++ b/make_scan.bat @@ -0,0 +1 @@ +arm-none-eabi-gcc -specs=./sdk/Alpha.specs -mfloat-abi=hard -mfpu=vfp -march=armv6zk -mtune=arm1176jzf-s -g3 -ggdb -Wall -Wl,-T./sdk/link.ld -L./sdk -I./whd -Wl,-umalloc -fpack-struct=1 -o zerowi.elf srce/zscan.c srce/zw_sdio.c srce/zw_ioctl.c srce/zw_gpio.c diff --git a/srce/zjoin.c b/srce/zjoin.c new file mode 100644 index 0000000..25f36e9 --- /dev/null +++ b/srce/zjoin.c @@ -0,0 +1,472 @@ +// ZeroWi bare-metal WiFi driver, see https://iosoft.blog/zerowi +// Raspberry Pi WiFi network scan +// +// Copyright (c) 2020 Jeremy P Bentham +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#define VERSION "0.75" + +#include +#include +#include +#include + +#include "whd_types.h" +#include "whd_wlioctl.h" +#include "whd_events.h" + +#include "zw_gpio.h" +#include "zw_sdio.h" +#include "zw_regs.h" +#include "zw_ioctl.h" + +// SSID +#define SSID "testnet" +#define COUNTRY "GB" +#define COUNTRY_REV -1 +wlc_ssid_t ssid={sizeof(SSID)-1, SSID}; +wl_country_t country_struct = {.ccode=COUNTRY, .country_abbrev=COUNTRY, .rev=COUNTRY_REV}; + +// Security settings: 0 for none, 1 for WPA_TKIP, 2 for WPA2 +// The hard-coded password is for test purposes only!!! +#define SECURITY 2 +#define PASSPHRASE "testpass" +wsec_pmk_t wsec_pmk = {sizeof(PASSPHRASE)-1, WSEC_PASSPHRASE, PASSPHRASE}; + +// Set non-zero to include WiFi firmware in image +#define INCLUDE_FIRMWARE 1 +#define FIRMWARE_FNAME "../firmware/brcmfmac43430-sdio.c" + +// Length of firmware file (rounded up to 4-byte value) +#define FIRMWARE_LEN 0x5ee84 +#if INCLUDE_FIRMWARE +extern const unsigned char firmware_bin[FIRMWARE_LEN]; +uint32_t firmware_pos; +#endif + +// Configuration for brcmfmac43430-sdio +uint8_t config_data[] = +"manfid=0x2d0\0""prodid=0x0726\0""vendid=0x14e4\0""devid=0x43e2\0" +"boardtype=0x0726\0""boardrev=0x1202\0""boardnum=22\0""macaddr=00:90:4c:c5:12:38\0" +"sromrev=11\0""boardflags=0x00404201\0""boardflags3=0x08000000\0""xtalfreq=37400\0" +"nocrc=1\0""ag0=255\0""aa2g=1\0""ccode=ALL\0""pa0itssit=0x20\0""extpagain2g=0\0" +"pa2ga0=-168,7161,-820\0""AvVmid_c0=0x0,0xc8\0""cckpwroffset0=5\0""maxp2ga0=84\0" +"txpwrbckof=6\0""cckbw202gpo=0\0""legofdmbw202gpo=0x66111111\0" +"mcsbw202gpo=0x77711111\0""propbw202gpo=0xdd\0""ofdmdigfilttype=18\0" +"ofdmdigfilttypebe=18\0""papdmode=1\0""papdvalidtest=1\0""pacalidx2g=32\0" +"papdepsoffset=-36\0""papdendidx=61\0""il0macaddr=00:90:4c:c5:12:38\0" +"wl0id=0x431b\0""deadman_to=0xffffffff\0""muxenab=0x1\0""spurconfig=0x3 \0" +"btc_mode=1\0""btc_params8=0x4e20\0""btc_params1=0x7530\0""\0\0\0\0\xaa\x00\x55\xff"; +int config_len = sizeof(config_data) - 1; + +// SDIO Tx buffer (must be multiple of 256, and less than 32K) +uint8_t txbuffer[0x4000]; + +#define CHECK(f, a, ...) {if (!f(a, __VA_ARGS__)) \ + printf("Error: %s(%s ...)\n", #f, #a);} + +#define DISP_BLOCKLEN 32 +uint8_t eventbuff[1600]; + +// State of SDIO clock line +extern uint8_t clkval; + +// Event groups +EVT_STR join_evts[]=JOIN_EVTS, no_evts[]=NO_EVTS; + +// Event field displays +char eth_hdr_fields[] = "6:dest 6:srce 2;type"; +char event_hdr_fields[] = "2;sub 2;len 1: 3;oui 2;usr"; +char event_msg_fields[] = "2;ver 2;flags 4;type 4;status 4;reason 4:auth 4;dlen 6;addr 18:"; + +void disp_ssid(uint8_t *data); +void disp_mac_addr(uint8_t *data); +void disp_block(uint8_t *data, int len); +void gdb_break(void); +int sdio_init(void); +int write_firmware(void); +int write_nvram(void); +void disp_bytes(uint8_t *addr, int len); +void sd_setup(void); + +int main(void) +{ + int ticks=0, ledon=0, n, startime=ustime(); + uint8_t resp[128] = {0}, eth[7]={0}; + IOCTL_EVENT_HDR ieh; + ETH_EVENT_FRAME *eep = (ETH_EVENT_FRAME *)eventbuff; + + crc7_init(); + qcrc16r_init(); + ustimeout(&ticks, 0); + printf("\nZerowi network join test v" VERSION "\n"); + fflush(stdout); + osc_init(); + gpio_set(LED_PIN, GPIO_OUT, GPIO_NOPULL); + sd_setup(); + gpio_out(WLAN_ON_PIN, 1); + flash_init(10000); + usdelay(10000); + log_enable(2); + sdio_init(); + sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, resp, 64); + n = ioctl_get_data("cur_etheraddr", 0, eth, 6); + printf("MAC address "); + if (n) + disp_mac_addr(eth); + else + printf("unavailable"); + n = ioctl_get_data("ver", 0, resp, sizeof(resp)); + printf("\nFirmware %s\n", (n ? (char *)resp : "not responding")); + if (!ioctl_set_data("country", 100, &country_struct, sizeof(country_struct))) + printf("Can't set country\n"); + if (!ioctl_wr_int32(WLC_UP, 200, 0)) + { + printf("WiFi CPU not running\n"); + fflush(stdout); + gdb_break(); + } + ioctl_enable_evts(no_evts); + CHECK(ioctl_wr_int32, WLC_SET_INFRA, 50, 1); + CHECK(ioctl_wr_int32, WLC_SET_AUTH, 0, 0); +#if SECURITY + CHECK(ioctl_wr_int32, WLC_SET_WSEC, 0, SECURITY==2 ? 6 : 2); + CHECK(ioctl_set_intx2, "bsscfg:sup_wpa", 0, 0, 1); + CHECK(ioctl_set_intx2, "bsscfg:sup_wpa2_eapver", 0, 0, -1); + CHECK(ioctl_set_intx2, "bsscfg:sup_wpa_tmo", 0, 0, 2500); + CHECK(ioctl_wr_data, WLC_SET_WSEC_PMK, 0, &wsec_pmk, sizeof(wsec_pmk)); + CHECK(ioctl_wr_int32, WLC_SET_WPA_AUTH, 0, SECURITY==2 ? 0x80 : 4); +#else + CHECK(ioctl_wr_int32, WLC_SET_WSEC, 0, 0); + CHECK(ioctl_wr_int32, WLC_SET_WPA_AUTH, 0, 0); +#endif + ioctl_enable_evts(join_evts); + CHECK(ioctl_wr_data, WLC_SET_SSID, 100, &ssid, sizeof(ssid)); + + while (1) + { + usdelay(SD_CLK_DELAY); + gpio_out(SD_CLK_PIN, clkval=!clkval); + if (ustimeout(&ticks, 20000)) + { + gpio_out(LED_PIN, ledon = !ledon); + if (!ledon) + { + printf("."); + fflush(stdout); + } + else + { + if ((n=ioctl_get_event(&ieh, eventbuff, sizeof(eventbuff))) > 0) + { + printf("\n%2.3f ", (ustime() - startime) / 1e6); + disp_fields(&ieh, ioctl_event_hdr_fields, n); + printf("\n"); + disp_bytes((uint8_t *)&ieh, sizeof(ieh)); + printf("\n"); + disp_fields(&eep->eth_hdr, eth_hdr_fields, sizeof(eep->eth_hdr)); + if (SWAP16(eep->eth_hdr.ethertype) == 0x886c) + { + disp_fields(&eep->event.hdr, event_hdr_fields, sizeof(eep->event.hdr)); + printf("\n"); + disp_fields(&eep->event.msg, event_msg_fields, sizeof(eep->event.msg)); + printf("%s %s", ioctl_evt_str(SWAP32(eep->event.msg.event_type)), + ioctl_evt_status_str(SWAP32(eep->event.msg.status))); + } + printf("\n"); + disp_block(eventbuff, n); + printf("\n"); + } + } + } + } +} + +// Display SSID, prefixed with length byte +void disp_ssid(uint8_t *data) +{ + int i=*data++; + + if (i == 0 || *data == 0) + printf("[hidden]"); + else if (i <= SSID_MAXLEN) + { + while (i-- > 0) + putchar(*data++); + } + else + printf("[invalid length %u]", i); +} + +// Display MAC address +void disp_mac_addr(uint8_t *data) +{ + int i; + + for (i=0; i<6; i++) + printf("%s%02X", i?":":"", data[i]); +} + +// Display block of data +void disp_block(uint8_t *data, int len) +{ + int i=0, n; + + while (i < len) + { + if (i > 0) + printf("\n"); + n = MIN(len-i, DISP_BLOCKLEN); + disp_bytes(&data[i], n); + i += n; + fflush(stdout); + } +} + +// Dummy function to trigger debug breakpoint +void gdb_break(void) +{ +} // Trigger GDB break + +// Initialise SDIO card, return RCA +int sdio_init(void) +{ + SDIO_MSG resp; + int rca=0; + U32DATA u32d; + uint8_t data[520]; + + sdio_cmd52(SD_FUNC_BUS, 0x06, 0, SD_RD, 0, 0); + usdelay(20000); + sdio_cmd52(SD_FUNC_BUS, 0x06, 8, SD_WR, 0, 0); + usdelay(20000); + sdio_cmd(0, 0, 0); + sdio_cmd(8, 0x1aa, 0); + // Enable I/O mode + sdio_cmd(5, 0, 0); + sdio_cmd(5, 0x200000, 0); + // Assert SD device + sdio_cmd(3, 0, &resp); + rca = SWAP16(resp.rsp3.rcax); + sdio_cmd7(rca, 0); + // [0.243831] Set bus interface + sdio_cmd52_writes(SD_FUNC_BUS, BUS_SPEED_CTRL_REG, 0x03, 1); + sdio_cmd52_writes(SD_FUNC_BUS, BUS_BI_CTRL_REG, 0x42, 1); + // [17.999101] Set block sizes + sdio_cmd52_writes(SD_FUNC_BUS, BUS_BAK_BLKSIZE_REG, SD_BAK_BLK_BYTES, 2); + sdio_cmd52_writes(SD_FUNC_BUS, BUS_RAD_BLKSIZE_REG, SD_RAD_BLK_BYTES, 2); + // [17.999944] Enable I/O + sdio_cmd52_writes(SD_FUNC_BUS, BUS_IOEN_REG, 1< 0) + { + firm_read(txbuffer, nblocks*SD_BAK_BLK_BYTES); + n = sdio_write_blocks(SD_FUNC_BAK, SB_32BIT_WIN+addr, txbuffer, nblocks); + if (!n) + break; + nbytes += nblocks * SD_BAK_BLK_BYTES; + } + else + { + firm_read(txbuffer, len); + sdio_cmd53_write(SD_FUNC_BAK, SB_32BIT_WIN+addr, txbuffer, len); + nbytes += len; + } + } + firm_close(); + return(nbytes); +} + +// Upload blocks of config data to chip NVRAM +int write_nvram(void) +{ + int nbytes=0, len; + + sdio_bak_window(0x078000); + while (nbytes < config_len) + { + len = MIN(config_len-nbytes, SD_BAK_BLK_BYTES); + sdio_cmd53_write(SD_FUNC_BAK, 0xfd54+nbytes, &config_data[nbytes], len); + nbytes += len; + } + return(nbytes); +} + +// Set up SD interface +void sd_setup(void) +{ + gpio_set(SD_CLK_PIN, GPIO_OUT, GPIO_NOPULL); + gpio_set(SD_CMD_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D0_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D1_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D2_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D3_PIN, GPIO_IN, GPIO_PULLUP); +} + +#if INCLUDE_FIRMWARE +#include FIRMWARE_FNAME +#endif +// EOF diff --git a/srce/part5.c b/srce/zscan.c similarity index 89% rename from srce/part5.c rename to srce/zscan.c index 8eba2d3..271b94c 100644 --- a/srce/part5.c +++ b/srce/zscan.c @@ -1,491 +1,477 @@ -// ZeroWi bare-metal WiFi driver, see https://iosoft.blog/zerowi -// Raspberry Pi WiFi network scan -// -// Copyright (c) 2020 Jeremy P Bentham -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// v0.61 JPB 22/3/20 Tidied up for publishing on github - -#define VERSION "0.61" - -#include -#include -#include -#include - -#include "zw_gpio.h" -#include "zw_sdio.h" -#include "zw_regs.h" -#include "zw_ioctl.h" - -#include "../whd/whd_types.h" -#include "../whd/whd_events.h" -#include "../whd/whd_wlioctl.h" - -// WiFi channel number to scan (0 for all channels) -#define SCAN_CHAN 1 - -// Set non-zero to include WiFi firmware in image -#define INCLUDE_FIRMWARE 1 -#define FIRMWARE_FNAME "../firmware/brcmfmac43430-sdio.c" - -// Length of firmware file (rounded up to 4-byte value) -#define FIRMWARE_LEN 0x5ee84 -#if INCLUDE_FIRMWARE -extern const unsigned char firmware_bin[FIRMWARE_LEN]; -uint32_t firmware_pos; -#endif - -// Configuration for brcmfmac43430-sdio -uint8_t config_data[] = -"manfid=0x2d0\0""prodid=0x0726\0""vendid=0x14e4\0""devid=0x43e2\0" -"boardtype=0x0726\0""boardrev=0x1202\0""boardnum=22\0""macaddr=00:90:4c:c5:12:38\0" -"sromrev=11\0""boardflags=0x00404201\0""boardflags3=0x08000000\0""xtalfreq=37400\0" -"nocrc=1\0""ag0=255\0""aa2g=1\0""ccode=ALL\0""pa0itssit=0x20\0""extpagain2g=0\0" -"pa2ga0=-168,7161,-820\0""AvVmid_c0=0x0,0xc8\0""cckpwroffset0=5\0""maxp2ga0=84\0" -"txpwrbckof=6\0""cckbw202gpo=0\0""legofdmbw202gpo=0x66111111\0" -"mcsbw202gpo=0x77711111\0""propbw202gpo=0xdd\0""ofdmdigfilttype=18\0" -"ofdmdigfilttypebe=18\0""papdmode=1\0""papdvalidtest=1\0""pacalidx2g=32\0" -"papdepsoffset=-36\0""papdendidx=61\0""il0macaddr=00:90:4c:c5:12:38\0" -"wl0id=0x431b\0""deadman_to=0xffffffff\0""muxenab=0x1\0""spurconfig=0x3 \0" -"btc_mode=1\0""btc_params8=0x4e20\0""btc_params1=0x7530\0""\0\0\0\0\xaa\x00\x55\xff"; -int config_len = sizeof(config_data) - 1; - -// SDIO Tx buffer (must be multiple of 256, and less than 32K) -uint8_t txbuffer[0x4000]; - -// Network scan parameters -#define SCAN_CHAN_TIME 40 -#define SSID_MAXLEN 32 -#define SCANTYPE_ACTIVE 0 -#define SCANTYPE_PASSIVE 1 -typedef struct { - uint32_t version; - uint16_t action, - sync_id; - uint32_t ssidlen; - uint8_t ssid[SSID_MAXLEN], - bssid[6], - bss_type, - scan_type; - uint32_t nprobes, - active_time, - passive_time, - home_time; - uint16_t nchans, - nssids; - uint8_t chans[14][2], - ssids[1][SSID_MAXLEN]; -} SCAN_PARAMS; -SCAN_PARAMS scan_params = { - .version=1, .action=1, .sync_id=0x1234, .ssidlen=0, .ssid={0}, - .bssid={0xff,0xff,0xff,0xff,0xff,0xff}, .bss_type=2, - .scan_type=SCANTYPE_PASSIVE, .nprobes=~0, .active_time=~0, - .passive_time=~0, .home_time=~0, -#if SCAN_CHAN == 0 - .nchans=14, .nssids=0, - .chans={{1,0x2b},{2,0x2b},{3,0x2b},{4,0x2b},{5,0x2b},{6,0x2b},{7,0x2b}, - {8,0x2b},{9,0x2b},{10,0x2b},{11,0x2b},{12,0x2b},{13,0x2b},{14,0x2b}}, -#else - .nchans=1, .nssids=0, .chans={{SCAN_CHAN,0x2b}}, .ssids={{0}} -#endif -}; - -// Escan result event (excluding 12-byte IOCTL header) -typedef struct { - uint8_t pad[10]; - whd_event_t event; - wl_escan_result_t escan; -} escan_result; - -// IOCTL commands -#define IOCTL_UP 2 -#define IOCTL_SET_SCAN_CHANNEL_TIME 0xb9 - -// Event handling -#define EVENT_ESCAN_RESULT 69 -#define EVENT_MAX 160 -#define SET_EVENT(e) event_msgs[e/8] = 1 << (e & 7) -char event_msgs[EVENT_MAX / 8]; -uint8_t eventbuff[1024]; - -// State of SDIO clock line -extern uint8_t clkval; - -void disp_ssid(uint8_t *data); -void disp_mac_addr(uint8_t *data); -void disp_block(uint8_t *data, int len); -void gdb_break(void); -int sdio_init(void); -int write_firmware(void); -int write_nvram(void); -void disp_bytes(uint8_t *addr, int len); -void sd_setup(void); - -int main(void) -{ - int ticks=0, ledon=0, n; - uint32_t val=0; - uint8_t resp[256] = {0}, eth[7]={0}; - escan_result *erp = (escan_result *)eventbuff; - - crc7_init(); - qcrc16r_init(); - ustimeout(&ticks, 0); - printf("\nZerowi v" VERSION "\n"); - fflush(stdout); - osc_init(); - gpio_set(LED_PIN, GPIO_OUT, GPIO_NOPULL); - sd_setup(); - gpio_out(WLAN_ON_PIN, 1); - flash_init(10000); - usdelay(10000); - log_enable(2); - sdio_init(); - sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, resp, 64); - n = ioctl_getvar("cur_etheraddr", eth, 6); - printf("MAC address "); - if (n) - disp_mac_addr(eth); - else - printf("unavailable"); - n = ioctl_getvar("ver", resp, sizeof(resp)); - printf("\nFirmware %s\n", (n ? (char *)resp : "not responding")); - ioctl_cmd_int32(IOCTL_SET_SCAN_CHANNEL_TIME, SCAN_CHAN_TIME); - ioctl_cmd_int32(IOCTL_UP, 0); - n = 0; - while (sdio_bak_read32(SB_INT_STATUS_REG, &val) && !(val&0xff)) - { - usdelay(50000); - if (n++ == 10) - { - printf("WiFi CPU not running\n"); - fflush(stdout); - gdb_break(); - } - } - sdio_bak_write32(SB_INT_STATUS_REG, val); - sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)resp, 64); - SET_EVENT(EVENT_ESCAN_RESULT); - ioctl_set_data("event_msgs", event_msgs, sizeof(event_msgs)); - ioctl_set_data("escan", &scan_params, sizeof(scan_params)); - while (1) - { - usdelay(SD_CLK_DELAY); - gpio_out(SD_CLK_PIN, clkval=!clkval); - if (ustimeout(&ticks, 100000)) - { - gpio_out(LED_PIN, ledon = !ledon); - if (!ledon) - { - n = ioctl_get_event(eventbuff, sizeof(eventbuff)); - if (n > sizeof(escan_result)) - { - printf("%u bytes\n", n); - //disp_bytes(eventbuff, n); - //printf("\n"); - disp_mac_addr((uint8_t *)&erp->event.whd_event.addr); - printf(" %2u ", SWAP16(erp->escan.bss_info->chanspec)); - //printf(" %2lu ", SWAP32(erp->event.whd_event.status)); - disp_ssid(&erp->escan.bss_info->SSID_len); - printf("\n"); - fflush(stdout); - } - else - { - printf("."); - fflush(stdout); - } - } - } - } -} - -// Display SSID, prefixed with length byte -void disp_ssid(uint8_t *data) -{ - int i=*data++; - - if (i == 0 || *data == 0) - printf("[hidden]"); - else if (i <= SSID_MAXLEN) - { - while (i-- > 0) - putchar(*data++); - } - else - printf("[invalid length %u]", i); -} - -// Display MAC address -void disp_mac_addr(uint8_t *data) -{ - int i; - - for (i=0; i<6; i++) - printf("%s%02X", i?":":"", data[i]); -} - -// Display block of data -void disp_block(uint8_t *data, int len) -{ - int i=0, n; - - while (i < len) - { - n = MIN(len-i, 32); - disp_bytes(&eventbuff[i], n); - i += n; - printf("\n"); - fflush(stdout); - } -} - -// Dummy function to trigger debug breakpoint -void gdb_break(void) -{ -} // Trigger GDB break - -// Initialise SDIO card, return RCA -int sdio_init(void) -{ - SDIO_MSG resp; - int rca=0; - U32DATA u32d; - uint8_t data[520]; - - sdio_cmd52(SD_FUNC_BUS, 0x06, 0, SD_RD, 0, 0); - usdelay(20000); - sdio_cmd52(SD_FUNC_BUS, 0x06, 8, SD_WR, 0, 0); - usdelay(20000); - sdio_cmd(0, 0, 0); - sdio_cmd(8, 0x1aa, 0); - // Enable I/O mode - sdio_cmd(5, 0, 0); - sdio_cmd(5, 0x200000, 0); - // Assert SD device - sdio_cmd(3, 0, &resp); - rca = SWAP16(resp.rsp3.rcax); - sdio_cmd7(rca, 0); - // [0.243831] Set bus interface - sdio_cmd52_writes(SD_FUNC_BUS, BUS_SPEED_CTRL_REG, 0x03, 1); - sdio_cmd52_writes(SD_FUNC_BUS, BUS_BI_CTRL_REG, 0x42, 1); - // [17.999101] Set block sizes - sdio_cmd52_writes(SD_FUNC_BUS, BUS_BAK_BLKSIZE_REG, SD_BAK_BLK_BYTES, 2); - sdio_cmd52_writes(SD_FUNC_BUS, BUS_RAD_BLKSIZE_REG, SD_RAD_BLK_BYTES, 2); - // [17.999944] Enable I/O - sdio_cmd52_writes(SD_FUNC_BUS, BUS_IOEN_REG, 1< 0) - { - firm_read(txbuffer, nblocks*SD_BAK_BLK_BYTES); - n = sdio_write_blocks(SD_FUNC_BAK, SB_32BIT_WIN+addr, txbuffer, nblocks); - if (!n) - break; - nbytes += nblocks * SD_BAK_BLK_BYTES; - } - else - { - firm_read(txbuffer, len); - sdio_cmd53_write(SD_FUNC_BAK, SB_32BIT_WIN+addr, txbuffer, len); - nbytes += len; - } - } - firm_close(); - return(nbytes); -} - -// Upload blocks of config data to chip NVRAM -int write_nvram(void) -{ - int nbytes=0, len; - - sdio_bak_window(0x078000); - while (nbytes < config_len) - { - len = MIN(config_len-nbytes, SD_BAK_BLK_BYTES); - sdio_cmd53_write(SD_FUNC_BAK, 0xfd54+nbytes, &config_data[nbytes], len); - nbytes += len; - } - return(nbytes); -} - -// Set up SD interface -void sd_setup(void) -{ - gpio_set(SD_CLK_PIN, GPIO_OUT, GPIO_NOPULL); - gpio_set(SD_CMD_PIN, GPIO_IN, GPIO_PULLUP); - gpio_set(SD_D0_PIN, GPIO_IN, GPIO_PULLUP); - gpio_set(SD_D1_PIN, GPIO_IN, GPIO_PULLUP); - gpio_set(SD_D2_PIN, GPIO_IN, GPIO_PULLUP); - gpio_set(SD_D3_PIN, GPIO_IN, GPIO_PULLUP); -} - -#if INCLUDE_FIRMWARE -#include FIRMWARE_FNAME -#endif -// EOF - +// ZeroWi bare-metal WiFi driver, see https://iosoft.blog/zerowi +// Raspberry Pi WiFi network scan +// +// Copyright (c) 2020 Jeremy P Bentham +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define VERSION "0.76" + +#include +#include +#include +#include + +#include "whd_types.h" +#include "whd_events.h" +#include "whd_wlioctl.h" + +#include "zw_gpio.h" +#include "zw_sdio.h" +#include "zw_regs.h" +#include "zw_ioctl.h" + +// WiFi channel number to scan (0 for all channels) +#define SCAN_CHAN 1 + +// Set non-zero to include WiFi firmware in image +#define INCLUDE_FIRMWARE 1 +#define FIRMWARE_FNAME "../firmware/brcmfmac43430-sdio.c" + +// Length of firmware file (rounded up to 4-byte value) +#define FIRMWARE_LEN 0x5ee84 +#if INCLUDE_FIRMWARE +extern const unsigned char firmware_bin[FIRMWARE_LEN]; +uint32_t firmware_pos; +#endif + +// Configuration for brcmfmac43430-sdio +uint8_t config_data[] = +"manfid=0x2d0\0""prodid=0x0726\0""vendid=0x14e4\0""devid=0x43e2\0" +"boardtype=0x0726\0""boardrev=0x1202\0""boardnum=22\0""macaddr=00:90:4c:c5:12:38\0" +"sromrev=11\0""boardflags=0x00404201\0""boardflags3=0x08000000\0""xtalfreq=37400\0" +"nocrc=1\0""ag0=255\0""aa2g=1\0""ccode=ALL\0""pa0itssit=0x20\0""extpagain2g=0\0" +"pa2ga0=-168,7161,-820\0""AvVmid_c0=0x0,0xc8\0""cckpwroffset0=5\0""maxp2ga0=84\0" +"txpwrbckof=6\0""cckbw202gpo=0\0""legofdmbw202gpo=0x66111111\0" +"mcsbw202gpo=0x77711111\0""propbw202gpo=0xdd\0""ofdmdigfilttype=18\0" +"ofdmdigfilttypebe=18\0""papdmode=1\0""papdvalidtest=1\0""pacalidx2g=32\0" +"papdepsoffset=-36\0""papdendidx=61\0""il0macaddr=00:90:4c:c5:12:38\0" +"wl0id=0x431b\0""deadman_to=0xffffffff\0""muxenab=0x1\0""spurconfig=0x3 \0" +"btc_mode=1\0""btc_params8=0x4e20\0""btc_params1=0x7530\0""\0\0\0\0\xaa\x00\x55\xff"; +int config_len = sizeof(config_data) - 1; + +// SDIO Tx buffer (must be multiple of 256, and less than 32K) +uint8_t txbuffer[0x4000]; + +// Network scan parameters +#define SCAN_CHAN_TIME 40 +#define SSID_MAXLEN 32 +#define SCANTYPE_ACTIVE 0 +#define SCANTYPE_PASSIVE 1 +typedef struct { + uint32_t version; + uint16_t action, + sync_id; + uint32_t ssidlen; + uint8_t ssid[SSID_MAXLEN], + bssid[6], + bss_type, + scan_type; + uint32_t nprobes, + active_time, + passive_time, + home_time; + uint16_t nchans, + nssids; + uint8_t chans[14][2], + ssids[1][SSID_MAXLEN]; +} SCAN_PARAMS; +SCAN_PARAMS scan_params = { + .version=1, .action=1, .sync_id=0x1234, .ssidlen=0, .ssid={0}, + .bssid={0xff,0xff,0xff,0xff,0xff,0xff}, .bss_type=2, + .scan_type=SCANTYPE_PASSIVE, .nprobes=~0, .active_time=~0, + .passive_time=~0, .home_time=~0, +#if SCAN_CHAN == 0 + .nchans=14, .nssids=0, + .chans={{1,0x2b},{2,0x2b},{3,0x2b},{4,0x2b},{5,0x2b},{6,0x2b},{7,0x2b}, + {8,0x2b},{9,0x2b},{10,0x2b},{11,0x2b},{12,0x2b},{13,0x2b},{14,0x2b}}, +#else + .nchans=1, .nssids=0, .chans={{SCAN_CHAN,0x2b}}, .ssids={{0}} +#endif +}; + +// Escan result event (excluding 12-byte IOCTL header) +typedef struct { + uint8_t pad[10]; + whd_event_t event; + wl_escan_result_t escan; +} escan_result; + +// IOCTL commands +#define IOCTL_UP 2 +#define IOCTL_SET_SCAN_CHANNEL_TIME 0xb9 + +// Event handling +uint8_t eventbuff[1600]; +EVT_STR escan_evts[]=ESCAN_EVTS; + +// State of SDIO clock line +extern uint8_t clkval; + +void disp_ssid(uint8_t *data); +void disp_mac_addr(uint8_t *data); +void disp_block(uint8_t *data, int len); +void gdb_break(void); +int sdio_init(void); +int write_firmware(void); +int write_nvram(void); +void disp_bytes(uint8_t *addr, int len); +void sd_setup(void); + +int main(void) +{ + int ticks=0, ledon=0, n; + uint32_t val=0; + uint8_t resp[256] = {0}, eth[7]={0}; + IOCTL_EVENT_HDR ieh; + escan_result *erp = (escan_result *)eventbuff; + + crc7_init(); + qcrc16r_init(); + ustimeout(&ticks, 0); + printf("\nZerowi scan test v" VERSION "\n"); + fflush(stdout); + osc_init(); + gpio_set(LED_PIN, GPIO_OUT, GPIO_NOPULL); + sd_setup(); + gpio_out(WLAN_ON_PIN, 1); + flash_init(10000); + usdelay(10000); + log_enable(2); + sdio_init(); + sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, resp, 64); + n = ioctl_get_data("cur_etheraddr", 0, eth, 6); + printf("MAC address "); + if (n) + disp_mac_addr(eth); + else + printf("unavailable"); + n = ioctl_get_data("ver", 0, resp, sizeof(resp)); + printf("\nFirmware %s\n", (n ? (char *)resp : "not responding")); + ioctl_wr_int32(IOCTL_SET_SCAN_CHANNEL_TIME, 0, SCAN_CHAN_TIME); + if (!ioctl_wr_int32(WLC_UP, 200, 0)) + { + printf("WiFi CPU not running\n"); + fflush(stdout); + gdb_break(); + } + sdio_bak_write32(SB_INT_STATUS_REG, val); + sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)resp, 64); + ioctl_enable_evts(escan_evts); + ioctl_set_data("escan", 0, &scan_params, sizeof(scan_params)); + while (1) + { + usdelay(SD_CLK_DELAY); + gpio_out(SD_CLK_PIN, clkval=!clkval); + if (ustimeout(&ticks, 100000)) + { + gpio_out(LED_PIN, ledon = !ledon); + if (!ledon) + { + n = ioctl_get_event(&ieh, eventbuff, sizeof(eventbuff)); + if (n > sizeof(escan_result)) + { + printf("%u bytes\n", n); + disp_mac_addr((uint8_t *)&erp->event.whd_event.addr); + printf(" %2u ", SWAP16(erp->escan.bss_info->chanspec)); + disp_ssid(&erp->escan.bss_info->SSID_len); + printf("\n"); + fflush(stdout); + } + else + { + printf("."); + fflush(stdout); + } + } + } + } +} + +// Display SSID, prefixed with length byte +void disp_ssid(uint8_t *data) +{ + int i=*data++; + + if (i == 0 || *data == 0) + printf("[hidden]"); + else if (i <= SSID_MAXLEN) + { + while (i-- > 0) + putchar(*data++); + } + else + printf("[invalid length %u]", i); +} + +// Display MAC address +void disp_mac_addr(uint8_t *data) +{ + int i; + + for (i=0; i<6; i++) + printf("%s%02X", i?":":"", data[i]); +} + +// Display block of data +void disp_block(uint8_t *data, int len) +{ + int i=0, n; + + while (i < len) + { + n = MIN(len-i, 32); + disp_bytes(&eventbuff[i], n); + i += n; + printf("\n"); + fflush(stdout); + } +} + +// Dummy function to trigger debug breakpoint +void gdb_break(void) +{ +} // Trigger GDB break + +// Initialise SDIO card, return RCA +int sdio_init(void) +{ + SDIO_MSG resp; + int rca=0; + U32DATA u32d; + uint8_t data[520]; + + sdio_cmd52(SD_FUNC_BUS, 0x06, 0, SD_RD, 0, 0); + usdelay(20000); + sdio_cmd52(SD_FUNC_BUS, 0x06, 8, SD_WR, 0, 0); + usdelay(20000); + sdio_cmd(0, 0, 0); + sdio_cmd(8, 0x1aa, 0); + // Enable I/O mode + sdio_cmd(5, 0, 0); + sdio_cmd(5, 0x200000, 0); + // Assert SD device + sdio_cmd(3, 0, &resp); + rca = SWAP16(resp.rsp3.rcax); + sdio_cmd7(rca, 0); + // [0.243831] Set bus interface + sdio_cmd52_writes(SD_FUNC_BUS, BUS_SPEED_CTRL_REG, 0x03, 1); + sdio_cmd52_writes(SD_FUNC_BUS, BUS_BI_CTRL_REG, 0x42, 1); + // [17.999101] Set block sizes + sdio_cmd52_writes(SD_FUNC_BUS, BUS_BAK_BLKSIZE_REG, SD_BAK_BLK_BYTES, 2); + sdio_cmd52_writes(SD_FUNC_BUS, BUS_RAD_BLKSIZE_REG, SD_RAD_BLK_BYTES, 2); + // [17.999944] Enable I/O + sdio_cmd52_writes(SD_FUNC_BUS, BUS_IOEN_REG, 1< 0) + { + firm_read(txbuffer, nblocks*SD_BAK_BLK_BYTES); + n = sdio_write_blocks(SD_FUNC_BAK, SB_32BIT_WIN+addr, txbuffer, nblocks); + if (!n) + break; + nbytes += nblocks * SD_BAK_BLK_BYTES; + } + else + { + firm_read(txbuffer, len); + sdio_cmd53_write(SD_FUNC_BAK, SB_32BIT_WIN+addr, txbuffer, len); + nbytes += len; + } + } + firm_close(); + return(nbytes); +} + +// Upload blocks of config data to chip NVRAM +int write_nvram(void) +{ + int nbytes=0, len; + + sdio_bak_window(0x078000); + while (nbytes < config_len) + { + len = MIN(config_len-nbytes, SD_BAK_BLK_BYTES); + sdio_cmd53_write(SD_FUNC_BAK, 0xfd54+nbytes, &config_data[nbytes], len); + nbytes += len; + } + return(nbytes); +} + +// Set up SD interface +void sd_setup(void) +{ + gpio_set(SD_CLK_PIN, GPIO_OUT, GPIO_NOPULL); + gpio_set(SD_CMD_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D0_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D1_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D2_PIN, GPIO_IN, GPIO_PULLUP); + gpio_set(SD_D3_PIN, GPIO_IN, GPIO_PULLUP); +} + +#if INCLUDE_FIRMWARE +#include FIRMWARE_FNAME +#endif +// EOF + diff --git a/srce/zw_ioctl.c b/srce/zw_ioctl.c index 4b03f62..e7123d7 100644 --- a/srce/zw_ioctl.c +++ b/srce/zw_ioctl.c @@ -20,92 +20,149 @@ #include #include +#include "whd_types.h" +#include "whd_wlioctl.h" +#include "whd_events.h" + #include "zw_sdio.h" #include "zw_regs.h" #include "zw_ioctl.h" #include "zw_gpio.h" +#define IOCTL_POLL_MSEC 2 + IOCTL_MSG ioctl_txmsg, ioctl_rxmsg; int txglom; uint16_t ioctl_reqid=0; +uint8_t event_mask[EVENT_MAX / 8]; +EVT_STR *current_evts; +char ioctl_event_hdr_fields[] = + "2:len 2: 1:seq 1:chan 1: 1:hdrlen 1:flow 1:credit"; +#define MAX_EVENT_STATUS 16 +char *event_status[MAX_EVENT_STATUS] = { + "SUCCESS","FAIL","TIMEOUT","NO_NETWORK","ABORT","NO_ACK", + "UNSOLICITED","ATTEMPT","PARTIAL","NEWSCAN","NEWASSOC", + "11HQUIET","SUPPRESS","NOCHANS","CCXFASTRM","CS_ABORT" }; -char ioctl_cmd_fields[] = "1:seq\0" "1:chan\0" "1:nextlen\0" "1:hdrlen\0" - "1:flow\0" "1:credit\0" "1:\0" "1:\0" - "4:cmd\0" "2:outlen\0" "2:inlen\0" - "4:flags\0" "4:status\0" ""; - -// Get event data -int ioctl_get_event(uint8_t *data, int maxlen) +// Get event data, return data length excluding header +int ioctl_get_event(IOCTL_EVENT_HDR *hp, uint8_t *data, int maxlen) { - IOCTL_EVENT_HDR hdr={0}; - int n=0, dlen; + int n=0, dlen=0, blklen; - if (sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)&hdr, sizeof(IOCTL_EVENT_HDR)) && - hdr.len>0 && hdr.notlen>0 && hdr.len==(hdr.notlen^0xffff)) + hp->len = 0; + if (sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)hp, sizeof(IOCTL_EVENT_HDR)) && + hp->len>sizeof(IOCTL_EVENT_HDR) && hp->notlen>0 && hp->len==(hp->notlen^0xffff)) { - while (nlen - sizeof(IOCTL_EVENT_HDR); + while (nlen-n), IOCTL_MAX_BLKLEN); + sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)(&data[n]), blklen); + n += blklen; } - while (n < hdr.len) + while (n < dlen) { - dlen = MIN(hdr.len-n, IOCTL_MAX_DLEN); - sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, 0, dlen); - n += dlen; + blklen = MIN(hp->len-n, IOCTL_MAX_BLKLEN); + sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, 0, blklen); + n += blklen; } } - return(n); + return(dlen > maxlen ? maxlen : dlen); +} + +// Enable events +int ioctl_enable_evts(EVT_STR *evtp) +{ + current_evts = evtp; + memset(event_mask, 0, sizeof(event_mask)); + while (evtp->num >= 0) + { + if (evtp->num / 8 < sizeof(event_mask)) + SET_EVENT(event_mask, evtp->num); + evtp++; + } + return(ioctl_set_data("event_msgs", 0, event_mask, sizeof(event_mask))); } -// Get an IOCTL variable -int ioctl_getvar(char *name, uint8_t *data, int dlen) +// Return string corresponding to event number, without "WLC_E_" prefix +char *ioctl_evt_str(int event) { - return(ioctl_cmd(0, IOCTL_GETVAR, name, data, dlen)); + EVT_STR *evtp=current_evts; + + while (evtp && evtp->num>=0 && evtp->num!=event) + evtp++; + return(evtp && evtp->num>=0 && strlen(evtp->str)>6 ? &evtp->str[6] : "?"); +} + +// Return string corresponding to event status +char *ioctl_evt_status_str(int status) +{ + return(status>=0 && statusglom_cmd.cmd : &msgp->cmd; int ret=0, namelen = name ? strlen(name)+1 : 0; int txdlen = wr ? namelen + dlen : MAX(namelen, dlen); int hdrlen = cmdp->data - (uint8_t *)&ioctl_txmsg; - int txlen = ((hdrlen + txdlen + 3) / 4) * 4; - uint32_t val; + int txlen = ((hdrlen + txdlen + 3) / 4) * 4; //, rxlen; + uint32_t val=0; + // Prepare IOCTL command memset(msgp, 0, sizeof(ioctl_txmsg)); + memset(rsp, 0, sizeof(ioctl_rxmsg)); msgp->notlen = ~(msgp->len = hdrlen+txdlen); if (txglom) { @@ -121,17 +178,37 @@ int ioctl_cmd(int wr, int cmd, char *name, void *data, int dlen) memcpy(cmdp->data, name, namelen); if (wr) memcpy(&cmdp->data[namelen], data, dlen); + // Send IOCTL command sdio_cmd53_write(SD_FUNC_RAD, SB_32BIT_WIN, (void *)msgp, txlen); ioctl_wait(IOCTL_WAIT_USEC); - sdio_bak_read32(SB_INT_STATUS_REG, &val); - if (val & 0xff) + while (wait_msec>=0 && ret==0) { - sdio_bak_write32(SB_INT_STATUS_REG, val); - ret = sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)&ioctl_rxmsg, txlen); - if (ioctl_rxmsg.cmd.flags >> 16 != ioctl_reqid) - ret = 0; - else if (!wr && data && dlen) - memcpy(data, ioctl_rxmsg.cmd.data, dlen); + // Wait for response to be available + wait_msec -= IOCTL_POLL_MSEC; + sdio_bak_read32(SB_INT_STATUS_REG, &val); + // If response is waiting.. + if (val & 0xff) + { + // ..request response + sdio_bak_write32(SB_INT_STATUS_REG, val); + // Fetch response + ret = sdio_cmd53_read(SD_FUNC_RAD, SB_32BIT_WIN, (void *)rsp, txlen); + // Discard response if not matching request + if ((rsp->cmd.flags>>16) != ioctl_reqid) + ret = 0; + // Exit if error response + if (ret && (rsp->cmd.flags & 1)) + { + ret = 0; + break; + } + // If OK, copy data to buffer + if (ret && !wr && data && dlen) + memcpy(data, rsp->cmd.data, dlen); + } + // If no response, wait + else + usdelay(IOCTL_POLL_MSEC * 1000); } return(ret); } @@ -153,6 +230,47 @@ int ioctl_ready(void) return(!gpio_in(SD_D1_PIN)); } +// Display fields in structure +// Fields in descriptor are num:id (little-endian) or num;id (big_endian) +void disp_fields(void *data, char *fields, int maxlen) +{ + char *strs=fields, delim=0; + uint8_t *dp = (uint8_t *)data; + int n, dlen; + int val; + + while (*strs && dp-(uint8_t *)data='0' && *strs<='9') + dlen = dlen*10 + *strs++ - '0'; + delim = *strs++; + if (*strs > ' ') + { + while (*strs >= '0') + putchar(*strs++); + putchar('='); + if (dlen <= 4) + { + val = 0; + for (n=0; n