From: Christian Lamparter Date: Fri, 13 May 2011 23:42:39 +0000 (+0200) Subject: carl9170 firmware: initial WoWLAN support X-Git-Tag: 1.9.4~12 X-Git-Url: https://jxself.org/git/?p=carl9170fw.git;a=commitdiff_plain;h=af915846d44d23adc02c7ded807282d607b46faa carl9170 firmware: initial WoWLAN support Unlike the previous proof-of-concept implementation, this one supports nl80211's magic packet & disconnect wakeup triggers. Furthermore, the trigger can be enabled from userspace with "iw", so there's no need for a custom firmware anymore. Signed-off-by: Christian Lamparter --- diff --git a/carlfw/Kconfig b/carlfw/Kconfig index cd236ba..a122f80 100644 --- a/carlfw/Kconfig +++ b/carlfw/Kconfig @@ -113,13 +113,15 @@ config CARL9170FW_WOL def_bool n depends on CARL9170FW_WOL_OPTION -config CARL9170FW_WOL_MAGIC_PACKET +config CARL9170FW_WOL_NL80211_TRIGGERS def_bool n - prompt "Magic Packet(tm)" + prompt "Standard NL80211 wakeup triggers" depends on CARL9170FW_WOL_OPTION select CARL9170FW_WOL ---help--- - Sniff all incoming data frames for the magic packet pattern. + Available triggers: + * Magic Packet(tm) pattern + * disconnect event config CARL9170FW_WOL_PROBE_REQUEST def_bool n diff --git a/carlfw/include/carl9170.h b/carlfw/include/carl9170.h index b4a7fe7..4b0738d 100644 --- a/carlfw/include/carl9170.h +++ b/carlfw/include/carl9170.h @@ -141,6 +141,16 @@ struct firmware_context_struct { struct carl9170_bar_ctx ba_cache[CONFIG_CARL9170FW_BACK_REQS_NUM]; unsigned int ba_tail_idx, ba_head_idx; + +#ifdef CONFIG_CARL9170FW_WOL + struct { + struct carl9170_wol_cmd cmd; + unsigned int last_beacon; + unsigned int lost_null; + unsigned int last_null; + bool wake_up; + } wol; +#endif /* CONFIG_CARL9170FW_WOL */ } wlan; struct { diff --git a/carlfw/include/cmd.h b/carlfw/include/cmd.h index a400cfa..54dd350 100644 --- a/carlfw/include/cmd.h +++ b/carlfw/include/cmd.h @@ -47,6 +47,7 @@ static inline void __check(void) BUILD_BUG_ON(sizeof(struct _carl9170_tx_status) != CARL9170_TX_STATUS_SIZE); BUILD_BUG_ON(sizeof(struct carl9170_gpio) != CARL9170_GPIO_SIZE); BUILD_BUG_ON(sizeof(struct carl9170_rx_filter_cmd) != CARL9170_RX_FILTER_CMD_SIZE); + BUILD_BUG_ON(sizeof(struct carl9170_wol_cmd) != CARL9170_WOL_CMD_SIZE); } void handle_cmd(struct carl9170_rsp *resp); diff --git a/carlfw/include/dma.h b/carlfw/include/dma.h index 07d06d6..51d0db4 100644 --- a/carlfw/include/dma.h +++ b/carlfw/include/dma.h @@ -75,6 +75,16 @@ struct carl9170_tx_ba_superframe { struct ar9170_tx_ba_frame f; } __packed; +struct ar9170_tx_null_frame { + struct ar9170_tx_hwdesc hdr; + struct ieee80211_hdr null; +} __packed; + +struct carl9170_tx_null_superframe { + struct carl9170_tx_superdesc s; + struct ar9170_tx_null_frame f; +} __packed; + #define CARL9170_BA_BUFFER_LEN (__roundup(sizeof(struct carl9170_tx_ba_superframe), 16)) #define CARL9170_RSP_BUFFER_LEN AR9170_BLOCK_SIZE @@ -87,6 +97,10 @@ struct carl9170_sram_reserved { union { uint32_t buf[CARL9170_MAX_CMD_LEN / sizeof(uint32_t)]; struct carl9170_cmd cmd; + +#ifdef CONFIG_CARL9170FW_WOL + struct carl9170_tx_null_superframe null; +#endif /* CONFIG_CARL9170FW_WOL */ } cmd; union { @@ -123,6 +137,7 @@ struct carl9170_sram_reserved { * | BA buffer (128 bytes) * +-- * | CMD buffer (128 bytes) + * | - used as NULLFRAME buffer (128 bytes) for WOL * +-- * | RSP buffer (320 bytes) * +-- @@ -328,6 +343,7 @@ static inline void __check_desc(void) BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, cmd.buf) & (BLOCK_ALIGNMENT - 1)); BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, rsp.buf) & (BLOCK_ALIGNMENT - 1)); BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, bcn.buf) & (BLOCK_ALIGNMENT - 1)); + BUILD_BUG_ON(sizeof(struct carl9170_tx_null_superframe) > CARL9170_MAX_CMD_LEN); } #endif /* __CARL9170FW_DMA_H */ diff --git a/carlfw/include/fwdsc.h b/carlfw/include/fwdsc.h index b521c7d..936bfed 100644 --- a/carlfw/include/fwdsc.h +++ b/carlfw/include/fwdsc.h @@ -31,6 +31,9 @@ struct carl9170_firmware_descriptor { struct carl9170fw_otus_desc otus; struct carl9170fw_txsq_desc txsq; +#ifdef CONFIG_CARL9170FW_WOL + struct carl9170fw_wol_desc wol; +#endif /* CONFIG_CARL9170FW_WOL */ struct carl9170fw_motd_desc motd; struct carl9170fw_dbg_desc dbg; struct carl9170fw_last_desc last; diff --git a/carlfw/include/wl.h b/carlfw/include/wl.h index e1c8bbd..7152de0 100644 --- a/carlfw/include/wl.h +++ b/carlfw/include/wl.h @@ -266,14 +266,7 @@ void wlan_modify_beacon(const unsigned int vif, void wlan_tx_complete(struct carl9170_tx_superframe *super, bool txs); -static inline void wlan_prepare_wol(void) -{ - /* set filter policy to: discard everything */ - fw.wlan.rx_filter = CARL9170_RX_FILTER_EVERYTHING; - - /* reenable rx dma */ - wlan_trigger(AR9170_DMA_TRIGGER_RXQ); -} +void wlan_prepare_wol(void); static inline void __check_wlantx(void) { diff --git a/carlfw/src/cmd.c b/carlfw/src/cmd.c index 2bbfcff..13081c2 100644 --- a/carlfw/src/cmd.c +++ b/carlfw/src/cmd.c @@ -86,6 +86,12 @@ void handle_cmd(struct carl9170_rsp *resp) fw.wlan.rx_filter = cmd->rx_filter.rx_filter; break; +#ifdef CONFIG_CARL9170FW_WOL + case CARL9170_CMD_WOL: + memcpy(&fw.wlan.wol.cmd, &cmd->wol, sizeof(cmd->wol)); + break; +#endif /* CONFIG_CARL9170FW_WOL */ + #ifdef CONFIG_CARL9170FW_CAB_QUEUE case CARL9170_CMD_BCN_CTRL: resp->hdr.len = 0; diff --git a/carlfw/src/dma.c b/carlfw/src/dma.c index 8630f98..c33608c 100644 --- a/carlfw/src/dma.c +++ b/carlfw/src/dma.c @@ -120,7 +120,6 @@ void dma_init_descriptors(void) set_wlan_txq_dma_addr(i, (uint32_t) fw.wlan.tx_queue[i].head); set(AR9170_MAC_REG_DMA_RXQ_ADDR, (uint32_t) fw.wlan.rx_queue.head); - fw.usb.int_desc->dataSize = AR9170_BLOCK_SIZE; fw.usb.int_desc->dataAddr = (void *) &dma_mem.reserved.rsp; diff --git a/carlfw/src/fw.c b/carlfw/src/fw.c index 94c52d1..b621813 100644 --- a/carlfw/src/fw.c +++ b/carlfw/src/fw.c @@ -83,6 +83,14 @@ const struct carl9170_firmware_descriptor __section(fwdsc) carl9170fw_desc = { .seq_table_addr = cpu_to_le32(&fw.wlan.sequence), ), +#ifdef CONFIG_CARL9170FW_WOL + FILL(wol, WOL, + .supported_triggers = BIT(CARL9170_WOL_DISCONNECT) | + BIT(CARL9170_WOL_MAGIC_PKT), + ), +#endif /* CONFIG_CARL9170FW_WOL */ + + FILL(motd, MOTD, .fw_year_month_day = cpu_to_le32( CARL9170FW_SET_DAY(CARL9170FW_VERSION_DAY) + diff --git a/carlfw/src/wlan.c b/carlfw/src/wlan.c index 942df83..6c73b48 100644 --- a/carlfw/src/wlan.c +++ b/carlfw/src/wlan.c @@ -31,7 +31,6 @@ #include "printf.h" #include "rf.h" #include "linux/ieee80211.h" -#include "rom.h" static void wlan_txunstuck(unsigned int queue) { @@ -441,6 +440,7 @@ static bool wlan_tx_status(struct dma_queue *queue, if (unlikely(super == fw.wlan.fw_desc_data)) { fw.wlan.fw_desc = desc; fw.wlan.fw_desc_available = 1; + if (fw.wlan.fw_desc_callback) fw.wlan.fw_desc_callback(super, success); @@ -503,7 +503,7 @@ void __hot wlan_tx(struct dma_desc *desc) wlan_trigger(BIT(super->s.queue)); } -static void wlan_tx_fw(struct carl9170_tx_superdesc *super) +static void wlan_tx_fw(struct carl9170_tx_superdesc *super, fw_desc_callback_t cb) { if (!fw.wlan.fw_desc_available) return; @@ -511,13 +511,14 @@ static void wlan_tx_fw(struct carl9170_tx_superdesc *super) fw.wlan.fw_desc_available = 0; /* Format BlockAck */ - fw.wlan.fw_desc->status = AR9170_OWN_BITS_SW; fw.wlan.fw_desc->ctrl = AR9170_CTRL_FS_BIT | AR9170_CTRL_LS_BIT; + fw.wlan.fw_desc->status = AR9170_OWN_BITS_SW; + fw.wlan.fw_desc->totalLen = fw.wlan.fw_desc->dataSize = super->len; fw.wlan.fw_desc_data = fw.wlan.fw_desc->dataAddr = super; fw.wlan.fw_desc->nextAddr = fw.wlan.fw_desc->lastAddr = fw.wlan.fw_desc; - + fw.wlan.fw_desc_callback = cb; wlan_tx(fw.wlan.fw_desc); } @@ -542,6 +543,7 @@ static void wlan_send_buffered_ba(void) sizeof(struct ar9170_tx_hwdesc) + sizeof(struct ieee80211_ba); baf->s.ri[0].tries = 1; + baf->s.cookie = 0; baf->s.queue = AR9170_TXQ_VO; baf->f.hdr.length = sizeof(struct ieee80211_ba) + FCS_LEN; @@ -554,7 +556,7 @@ static void wlan_send_buffered_ba(void) baf->f.hdr.phy.tx_power = 29; /* 14.5 dBm */ /* format outgoing BA */ - ba->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK); + ba->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_NULLFUNC); ba->duration = cpu_to_le16(0); memcpy(ba->ta, ctx->ta, 6); memcpy(ba->ra, ctx->ra, 6); @@ -572,7 +574,7 @@ static void wlan_send_buffered_ba(void) */ ba->control = ctx->control | cpu_to_le16(1); ba->start_seq_num = ctx->start_seq_num; - wlan_tx_fw(&baf->s); + wlan_tx_fw(&baf->s, NULL); } static struct carl9170_bar_ctx *wlan_get_bar_cache_buffer(void) @@ -655,8 +657,24 @@ static void wlan_check_rx_overrun(void) } #ifdef CONFIG_CARL9170FW_WOL +void wlan_prepare_wol(void) +{ + /* set MAC filter */ + memcpy((void *)AR9170_MAC_REG_MAC_ADDR_L, fw.wlan.wol.cmd.mac, 6); + memcpy((void *)AR9170_MAC_REG_BSSID_L, fw.wlan.wol.cmd.bssid, 6); + set(AR9170_MAC_REG_RX_CONTROL, AR9170_MAC_RX_CTRL_DEAGG); -#ifdef CONFIG_CARL9170FW_WOL_MAGIC_PACKET + /* set filter policy to: discard everything */ + fw.wlan.rx_filter = CARL9170_RX_FILTER_EVERYTHING; + + /* reenable rx dma */ + wlan_trigger(AR9170_DMA_TRIGGER_RXQ); + + /* initialize the last_beacon timer */ + fw.wlan.wol.last_null = fw.wlan.wol.last_beacon = get_clock_counter(); +} + +#ifdef CONFIG_CARL9170FW_WOL_NL80211_TRIGGERS static bool wlan_rx_wol_magic_packet(struct ieee80211_hdr *hdr, unsigned int len) { const unsigned char *data, *end, *mac; @@ -668,16 +686,7 @@ static bool wlan_rx_wol_magic_packet(struct ieee80211_hdr *hdr, unsigned int len * for MAGIC patterns! */ - /* - * TODO: - * Currently, the MAGIC MAC Address is fixed to the EEPROM default. - * It's possible to make it fully configurable, e.g: - * - * mac = (const unsigned char *) AR9170_MAC_REG_MAC_ADDR_L; - * But this will clash with the driver's suspend path, because it - * needs to reset the registers. - */ - mac = rom.sys.mac_address; + mac = (const unsigned char *) AR9170_MAC_REG_MAC_ADDR_L; data = (u8 *)((unsigned long)hdr + ieee80211_hdrlen(hdr->frame_control)); end = (u8 *)((unsigned long)hdr + len); @@ -730,7 +739,77 @@ static bool wlan_rx_wol_magic_packet(struct ieee80211_hdr *hdr, unsigned int len return false; } -#endif /* CONFIG_CARL9170FW_WOL_MAGIC_PACKET */ + +static void wlan_wol_connect_callback(void __unused *dummy, bool success) +{ + if (success) + fw.wlan.wol.lost_null = 0; + else + fw.wlan.wol.lost_null++; +} + +static void wlan_wol_connection_monitor(void) +{ + struct carl9170_tx_null_superframe *nullf = &dma_mem.reserved.cmd.null; + struct ieee80211_hdr *null = (struct ieee80211_hdr *) &nullf->f.null; + + if (!fw.wlan.fw_desc_available) + return; + + memset(nullf, 0, sizeof(nullf)); + + nullf->s.len = sizeof(struct carl9170_tx_superdesc) + + sizeof(struct ar9170_tx_hwdesc) + + sizeof(struct ieee80211_hdr); + nullf->s.ri[0].tries = 3; + nullf->s.assign_seq = true; + nullf->s.queue = AR9170_TXQ_VO; + nullf->f.hdr.length = sizeof(struct ieee80211_hdr) + FCS_LEN; + + nullf->f.hdr.mac.backoff = 1; + nullf->f.hdr.mac.hw_duration = 1; + nullf->f.hdr.mac.erp_prot = AR9170_TX_MAC_PROT_RTS; + + nullf->f.hdr.phy.modulation = AR9170_TX_PHY_MOD_OFDM; + nullf->f.hdr.phy.bandwidth = AR9170_TX_PHY_BW_20MHZ; + nullf->f.hdr.phy.chains = AR9170_TX_PHY_TXCHAIN_2; + nullf->f.hdr.phy.tx_power = 29; /* 14.5 dBm */ + nullf->f.hdr.phy.mcs = AR9170_TXRX_PHY_RATE_OFDM_6M; + + /* format outgoing nullfunc */ + null->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS); + + memcpy(null->addr1, fw.wlan.wol.cmd.bssid, 6); + memcpy(null->addr2, fw.wlan.wol.cmd.mac, 6); + memcpy(null->addr3, fw.wlan.wol.cmd.bssid, 6); + + wlan_tx_fw(&nullf->s, wlan_wol_connect_callback); +} + +static bool wlan_rx_wol_disconnect(const unsigned int rx_filter, + struct ieee80211_hdr *hdr, + unsigned int __unused len) +{ + const unsigned char *bssid; + bssid = (const unsigned char *) AR9170_MAC_REG_BSSID_L; + + /* should catch both broadcast and unicast MLMEs */ + if (!(rx_filter & CARL9170_RX_FILTER_OTHER_RA)) { + if (ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control)) + return true; + } + + if (ieee80211_is_beacon(hdr->frame_control) && + compare_ether_address(hdr->addr3, bssid)) { + fw.wlan.wol.last_beacon = get_clock_counter(); + } + + return false; +} + +#endif /* CARL9170FW_WOL_NL80211_TRIGGERS */ #ifdef CONFIG_CARL9170FW_WOL_PROBE_REQUEST @@ -781,21 +860,46 @@ static bool wlan_rx_wol_probe_ssid(struct ieee80211_hdr *hdr, unsigned int len) static void wlan_rx_wol(unsigned int rx_filter __unused, struct ieee80211_hdr *hdr __unused, unsigned int len __unused) { - bool __unused wake_up = false; +#ifdef CONFIG_CARL9170FW_WOL_NL80211_TRIGGERS + /* Disconnect is always enabled */ + if (fw.wlan.wol.cmd.flags & CARL9170_WOL_DISCONNECT && + rx_filter & CARL9170_RX_FILTER_MGMT) + fw.wlan.wol.wake_up |= wlan_rx_wol_disconnect(rx_filter, hdr, len); -#ifdef CONFIG_CARL9170FW_WOL_MAGIC_PACKET - if (rx_filter & CARL9170_RX_FILTER_DATA) - wake_up |= wlan_rx_wol_magic_packet(hdr, len); -#endif /* CONFIG_CARL9170FW_WOL_MAGIC_PACKET */ + if (fw.wlan.wol.cmd.flags & CARL9170_WOL_MAGIC_PKT && + rx_filter & CARL9170_RX_FILTER_DATA) + fw.wlan.wol.wake_up |= wlan_rx_wol_magic_packet(hdr, len); +#endif /* CONFIG_CARL9170FW_WOL_NL80211_TRIGGERS */ #ifdef CONFIG_CARL9170FW_WOL_PROBE_REQUEST if (rx_filter & CARL9170_RX_FILTER_MGMT) - wake_up |= wlan_rx_wol_probe_ssid(hdr, len); + fw.wlan.wol.wake_up |= wlan_rx_wol_probe_ssid(hdr, len); #endif /* CONFIG_CARL9170FW_WOL_PROBE_REQUEST */ +} - if (wake_up) { - fw.suspend_mode = CARL9170_AWAKE_HOST; - set(AR9170_USB_REG_WAKE_UP, AR9170_USB_WAKE_UP_WAKE); +static void wlan_wol_janitor(void) +{ + if (unlikely(fw.suspend_mode == CARL9170_HOST_SUSPENDED)) { + if (fw.wlan.wol.cmd.flags & CARL9170_WOL_DISCONNECT) { + /* + * connection lost after 10sec without receiving + * a beacon + */ + if (is_after_msecs(fw.wlan.wol.last_beacon, 10000)) + fw.wlan.wol.wake_up |= true; + + if (fw.wlan.wol.cmd.null_interval && + is_after_msecs(fw.wlan.wol.last_null, fw.wlan.wol.cmd.null_interval)) + wlan_wol_connection_monitor(); + + if (fw.wlan.wol.lost_null >= 5) + fw.wlan.wol.wake_up |= true; + } + + if (fw.wlan.wol.wake_up) { + fw.suspend_mode = CARL9170_AWAKE_HOST; + set(AR9170_USB_REG_WAKE_UP, AR9170_USB_WAKE_UP_WAKE); + } } } #endif /* CONFIG_CARL9170FW_WOL */ @@ -855,7 +959,7 @@ static unsigned int wlan_rx_filter(struct dma_desc *desc) #ifdef CONFIG_CARL9170FW_WOL if (unlikely(fw.suspend_mode == CARL9170_HOST_SUSPENDED)) { wlan_rx_wol(rx_filter, hdr, min(data_len, - (unsigned int)AR9170_BLOCK_SIZE)); + (unsigned int)AR9170_BLOCK_SIZE)); } #endif /* CONFIG_CARL9170FW_WOL */ @@ -1052,6 +1156,10 @@ static void wlan_janitor(void) wlan_send_buffered_tx_status(); wlan_send_buffered_ba(); + +#ifdef CONFIG_CARL9170FW_WOL + wlan_wol_janitor(); +#endif /* CONFIG_CARL9170FW_WOL */ } void handle_wlan(void) diff --git a/carlfw/usb/main.c b/carlfw/usb/main.c index 5c09476..649dc4b 100644 --- a/carlfw/usb/main.c +++ b/carlfw/usb/main.c @@ -384,7 +384,9 @@ static void usb_handler(uint8_t usb_interrupt_level1) fw.suspend_mode = CARL9170_HOST_SUSPENDED; - if (!(fw.usb.device_feature & USB_DEVICE_REMOTE_WAKEUP)) { +#ifdef CONFIG_CARL9170FW_WOL + if (!(fw.usb.device_feature & USB_DEVICE_REMOTE_WAKEUP) || + !fw.wlan.wol.cmd.flags) { disable_watchdog(); /* GO_TO_SUSPEND stops the CPU clock too. */ @@ -392,6 +394,12 @@ static void usb_handler(uint8_t usb_interrupt_level1) } else { wlan_prepare_wol(); } +#else /* CONFIG_CARL9170FW_WOL */ + disable_watchdog(); + + /* GO_TO_SUSPEND stops the CPU clock too. */ + orb(AR9170_USB_REG_MAIN_CTRL, AR9170_USB_MAIN_CTRL_GO_TO_SUSPEND); +#endif /* CONFIG_CARL9170FW_WOL */ } if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_USB_RESUME) { diff --git a/include/shared/fwcmd.h b/include/shared/fwcmd.h index 0e66519..8fea629 100644 --- a/include/shared/fwcmd.h +++ b/include/shared/fwcmd.h @@ -54,6 +54,7 @@ enum carl9170_cmd_oids { CARL9170_CMD_BCN_CTRL = 0x05, CARL9170_CMD_READ_TSF = 0x06, CARL9170_CMD_RX_FILTER = 0x07, + CARL9170_CMD_WOL = 0x08, /* CAM */ CARL9170_CMD_EKEY = 0x10, @@ -180,6 +181,21 @@ struct carl9170_bcn_ctrl_cmd { #define CARL9170_BCN_CTRL_DRAIN 0 #define CARL9170_BCN_CTRL_CAB_TRIGGER 1 +struct carl9170_wol_cmd { + __le32 flags; + u8 mac[6]; + u8 bssid[6]; + __le32 null_interval; + __le32 free_for_use2; + __le32 mask; + u8 pattern[32]; +} __packed; + +#define CARL9170_WOL_CMD_SIZE 60 + +#define CARL9170_WOL_DISCONNECT 1 +#define CARL9170_WOL_MAGIC_PKT 2 + struct carl9170_cmd_head { union { struct { @@ -203,6 +219,7 @@ struct carl9170_cmd { struct carl9170_write_reg wreg; struct carl9170_rf_init rf_init; struct carl9170_psm psm; + struct carl9170_wol_cmd wol; struct carl9170_bcn_ctrl_cmd bcn_ctrl; struct carl9170_rx_filter_cmd rx_filter; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; diff --git a/include/shared/fwdesc.h b/include/shared/fwdesc.h index 9cfe366..a4769e9 100644 --- a/include/shared/fwdesc.h +++ b/include/shared/fwdesc.h @@ -82,6 +82,7 @@ enum carl9170fw_feature_list { #define DBG_MAGIC "DBG\0" #define CHK_MAGIC "CHK\0" #define TXSQ_MAGIC "TXSQ" +#define WOL_MAGIC "WOL\0" #define LAST_MAGIC "LAST" #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31) @@ -186,6 +187,16 @@ struct carl9170fw_txsq_desc { #define CARL9170FW_TXSQ_DESC_SIZE \ (sizeof(struct carl9170fw_txsq_desc)) +#define CARL9170FW_WOL_DESC_MIN_VER 1 +#define CARL9170FW_WOL_DESC_CUR_VER 1 +struct carl9170fw_wol_desc { + struct carl9170fw_desc_head head; + + __le32 supported_triggers; /* CARL9170_WOL_ */ +} __packed; +#define CARL9170FW_WOL_DESC_SIZE \ + (sizeof(struct carl9170fw_wol_desc)) + #define CARL9170FW_LAST_DESC_MIN_VER 1 #define CARL9170FW_LAST_DESC_CUR_VER 2 struct carl9170fw_last_desc { diff --git a/include/shared/version.h b/include/shared/version.h index e3afc95..4a1bdab 100644 --- a/include/shared/version.h +++ b/include/shared/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 11 -#define CARL9170FW_VERSION_MONTH 3 -#define CARL9170FW_VERSION_DAY 4 +#define CARL9170FW_VERSION_MONTH 5 +#define CARL9170FW_VERSION_DAY 7 #define CARL9170FW_VERSION_GIT "1.9.3" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/toolchain/Makefile b/toolchain/Makefile index 492f017..81c5de4 100644 --- a/toolchain/Makefile +++ b/toolchain/Makefile @@ -38,14 +38,14 @@ binutils: src/binutils-$(BINUTILS_VER) mkdir -p build/binutils cd build/binutils; \ $(BASEDIR)/$seq_table_addr)); } + +static const struct feature_list wol_triggers_v1[] = { + CHECK_FOR_FEATURE(CARL9170_WOL_DISCONNECT), + CHECK_FOR_FEATURE(CARL9170_WOL_MAGIC_PKT), +}; + +static void show_wol_desc(const struct carl9170fw_desc_head *head, + struct carlfw *fw __unused) +{ + const struct carl9170fw_wol_desc *wol = (const void *) head; + + fprintf(stdout, "\tSupported WOWLAN triggers: (raw:%.08x)\n", + le32_to_cpu(wol->supported_triggers)); + + check_feature_list(head, wol->supported_triggers, wol_triggers_v1, + ARRAY_SIZE(wol_triggers_v1), fw); +} + static void show_chk_desc(const struct carl9170fw_desc_head *head, - struct carlfw *fw __unused) + struct carlfw *fw __unused) { const struct carl9170fw_chk_desc *chk = (const void *) head; @@ -214,6 +233,7 @@ static const struct { ADD_HANDLER(DBG, show_dbg_desc), ADD_HANDLER(FIX, show_fix_desc), ADD_HANDLER(CHK, show_chk_desc), + ADD_HANDLER(WOL, show_wol_desc), ADD_HANDLER(LAST, show_last_desc), };