u8 data[1];
} __packed;
+struct mwifiex_fw_dump_header {
+ __le16 seq_num;
+ __le16 reserved;
+ __le16 type;
+ __le16 len;
+} __packed;
+
+#define FW_DUMP_INFO_ENDED 0x0002
+
#define MWIFIEX_FW_DNLD_CMD_1 0x1
#define MWIFIEX_FW_DNLD_CMD_5 0x5
#define MWIFIEX_FW_DNLD_CMD_6 0x6
#define EVENT_BG_SCAN_STOPPED 0x00000065
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_MULTI_CHAN_INFO 0x0000006a
+#define EVENT_FW_DUMP_INFO 0x00000073
#define EVENT_TX_STATUS_REPORT 0x00000074
#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076
adapter->if_ops.card_reset(adapter);
}
+static void fw_dump_timer_fn(struct timer_list *t)
+{
+ struct mwifiex_adapter *adapter = from_timer(adapter, t, devdump_timer);
+
+ mwifiex_upload_device_dump(adapter);
+}
+
/*
* This function initializes the private structure and sets default
* values to the members.
adapter->active_scan_triggered = false;
timer_setup(&adapter->wakeup_timer, wakeup_timer_fn, 0);
adapter->devdump_len = 0;
+ timer_setup(&adapter->devdump_timer, fw_dump_timer_fn, 0);
}
/*
mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
{
del_timer(&adapter->wakeup_timer);
+ del_timer_sync(&adapter->devdump_timer);
mwifiex_cancel_all_pending_cmd(adapter);
wake_up_interruptible(&adapter->cmd_wait_q.wait);
wake_up_interruptible(&adapter->hs_activate_wait_q);
adapter->coex_rx_win_size);
}
+static void
+mwifiex_fw_dump_info_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_fw_dump_header *fw_dump_hdr =
+ (void *)adapter->event_body;
+
+ if (adapter->iface_type != MWIFIEX_USB) {
+ mwifiex_dbg(adapter, MSG,
+ "event is not on usb interface, ignore it\n");
+ return;
+ }
+
+ if (!adapter->devdump_data) {
+ /* When receive the first event, allocate device dump
+ * buffer, dump driver info.
+ */
+ adapter->devdump_data = vzalloc(MWIFIEX_FW_DUMP_SIZE);
+ if (!adapter->devdump_data) {
+ mwifiex_dbg(adapter, ERROR,
+ "vzalloc devdump data failure!\n");
+ return;
+ }
+
+ mwifiex_drv_info_dump(adapter);
+
+ /* If no proceeded event arrive in 10s, upload device
+ * dump data, this will be useful if the end of
+ * transmission event get lost, in this cornel case,
+ * user would still get partial of the dump.
+ */
+ mod_timer(&adapter->devdump_timer,
+ jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
+ }
+
+ /* Overflow check */
+ if (adapter->devdump_len + event_skb->len >= MWIFIEX_FW_DUMP_SIZE)
+ goto upload_dump;
+
+ memmove(adapter->devdump_data + adapter->devdump_len,
+ adapter->event_skb->data, event_skb->len);
+ adapter->devdump_len += event_skb->len;
+
+ if (le16_to_cpu(fw_dump_hdr->type == FW_DUMP_INFO_ENDED)) {
+ mwifiex_dbg(adapter, MSG,
+ "receive end of transmission flag event!\n");
+ goto upload_dump;
+ }
+ return;
+
+upload_dump:
+ del_timer_sync(&adapter->devdump_timer);
+ mwifiex_upload_device_dump(adapter);
+}
+
/*
* This function handles events generated by firmware.
*
* - EVENT_DELBA
* - EVENT_BA_STREAM_TIEMOUT
* - EVENT_AMSDU_AGGR_CTRL
+ * - EVENT_FW_DUMP_INFO
*/
int mwifiex_process_sta_event(struct mwifiex_private *priv)
{
adapter->event_skb->len -
sizeof(eventcause));
break;
+ case EVENT_FW_DUMP_INFO:
+ mwifiex_dbg(adapter, EVENT, "event: firmware debug info\n");
+ mwifiex_fw_dump_info_event(priv, adapter->event_skb);
+ break;
/* Debugging event; not used, but let's not print an ERROR for it. */
case EVENT_UNKNOWN_DEBUG:
mwifiex_dbg(adapter, EVENT, "event: debug\n");