static int r92su_usb_init(struct r92su *r92su) { struct urb *urb; int i, err = -EINVAL; for (i = 0; i < RTL_USB_MAX_RX_URBS_NUM; i++) { urb = r92su_get_rx_urb(r92su, GFP_KERNEL); if (IS_ERR(urb)) { err = PTR_ERR(urb); break; } usb_anchor_urb(urb, &r92su->rx_submitted); err = usb_submit_urb(urb, GFP_KERNEL); if (err) { WARN_ONCE(err, "can't handle urb submit error %d", err); usb_unanchor_urb(urb); dev_kfree_skb_any(urb->context); r92su_mark_dead(r92su); break; } usb_free_urb(urb); } return err; }
static void r92su_rx_usb_cb(struct urb *urb) { struct r92su *r92su = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); void *buf = urb->context; int err; if (WARN_ONCE(r92su_deal_with_usb_errors(r92su, urb->status), "unhandled urb status %d", urb->status)) goto err_out; if (!r92su_is_probing(r92su)) goto err_out; r92su_rx(r92su, buf, urb->actual_length); usb_anchor_urb(urb, &r92su->rx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { WARN_ONCE(r92su_deal_with_usb_errors(r92su, err), "can't handle rx urb submit error %d", err); usb_unanchor_urb(urb); r92su_mark_dead(r92su); goto err_out; } return; err_out: kfree(buf); return; }
static void r92su_tx_schedule(struct r92su *r92su) { struct urb *urb; int err; if (atomic_inc_return(&r92su->tx_pending_urbs) > RTL_USB_MAX_TX_URBS_NUM) goto err_acc; urb = usb_get_from_anchor(&r92su->tx_wait); if (!urb) goto err_acc; usb_anchor_urb(urb, &r92su->tx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { WARN_ONCE(err, "can't handle urb submit error %d", err); usb_unanchor_urb(urb); r92su_mark_dead(r92su); dev_kfree_skb_any(urb->context); } usb_free_urb(urb); if (likely(err == 0)) return; err_acc: atomic_dec(&r92su->tx_pending_urbs); }
static void c2h_survey_event(struct r92su *r92su, const struct h2cc2h *c2h) { const struct h2cc2h_bss *c2h_bss = (const void *)&c2h->data; struct r92su_add_bss *bss_priv; u32 bss_len; u16 len; /* Looks like the FW just attaches the raw probe_response IEs * ... along with the FCS (since we enabled the RX flag for it */ len = le16_to_cpu(c2h->len) - FCS_LEN; bss_len = le32_to_cpu(c2h_bss->length) - FCS_LEN; if (len < sizeof(*c2h_bss) || len != bss_len || le32_to_cpu(c2h_bss->ie_length) <= 12) { R92SU_ERR(r92su, "received survey event with bad length."); r92su_mark_dead(r92su); return; } bss_priv = kmalloc(len - sizeof(*c2h_bss) + sizeof(*bss_priv), GFP_ATOMIC); if (!bss_priv) return; memcpy(&bss_priv->fw_bss, c2h_bss, len); bss_priv->fw_bss.length = cpu_to_le32(len); bss_priv->fw_bss.ie_length = cpu_to_le32( le32_to_cpu(bss_priv->fw_bss.ie_length) - FCS_LEN); llist_add(&bss_priv->head, &r92su->add_bss_list); queue_work(r92su->wq, &r92su->add_bss_work); }
void r92su_c2h_event(struct r92su *r92su, const struct h2cc2h *c2h) { unsigned int sequence = r92su->c2h_seq++; trace_r92su_c2h(wiphy_dev(r92su->wdev.wiphy), c2h); if (sequence != c2h->cmd_seq) { R92SU_DBG(r92su, "received an c2h event out of sequence.\n"); R92SU_DBG(r92su, "expected: %d, got %d\n", sequence, c2h->cmd_seq); r92su->c2h_seq = c2h->cmd_seq + 1; } R92SU_DBG(r92su, "c2h event:%x len:%d\n", c2h->event, le16_to_cpu(c2h->len)); switch (c2h->event) { case C2H_FWDBG_EVENT: c2h_fwdbg_event(r92su, c2h); break; case C2H_SURVEY_EVENT: c2h_survey_event(r92su, c2h); break; case C2H_SURVEY_DONE_EVENT: c2h_survey_done_event(r92su, c2h); break; case C2H_JOIN_BSS_EVENT: c2h_join_bss_event(r92su, c2h); break; case C2H_ADD_STA_EVENT: c2h_add_sta_event(r92su, c2h); break; case C2H_DEL_STA_EVENT: c2h_del_sta_event(r92su, c2h); break; case C2H_ATIM_DONE_EVENT: c2h_atim_done_event(r92su, c2h); break; case C2H_REPORT_PWR_STATE_EVENT: c2h_report_pwr_state_event(r92su, c2h); break; case C2H_WPS_PBC_EVENT: c2h_wps_pbc_event(r92su, c2h); break; case C2H_ADDBA_REPORT_EVENT: c2h_addba_report_event(r92su, c2h); break; default: R92SU_ERR(r92su, "received invalid c2h event:%x\n", c2h->event); print_hex_dump_bytes("C2H:", DUMP_PREFIX_OFFSET, c2h, le16_to_cpu(c2h->len) + sizeof(*c2h)); r92su_mark_dead(r92su); break; } }
static bool r92su_deal_with_usb_errors(struct r92su *r92su, int err) { if (likely(err == 0)) return false; if (r92su_is_dead(r92su)) return false; if (r92su->intf->condition == USB_INTERFACE_UNBINDING) return false; switch (err) { case -ENOENT: case -ECONNRESET: case -ENODEV: case -ESHUTDOWN: R92SU_DBG(r92su, "device was removed"); r92su_mark_dead(r92su); return false; case -EPROTO: R92SU_DBG(r92su, "usb protocol error"); r92su_mark_dead(r92su); return false; case -EMSGSIZE: R92SU_DBG(r92su, "message size mismatch"); r92su_mark_dead(r92su); return true; default: R92SU_DBG(r92su, "unhandled status %d", err); WARN_ONCE(err, "unhandled status %d", err); r92su_mark_dead(r92su); return true; } }