Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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;
	}
}
Esempio n. 6
0
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;
	}
}