Exemplo n.º 1
0
static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
{
	struct urb *urb;
	unsigned long flags;
	int err;

	if (unlikely(!IS_STARTED(&aru->common)))
		return ;

	spin_lock_irqsave(&aru->tx_urb_lock, flags);
	if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) {
		spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
		return ;
	}
	aru->tx_submitted_urbs++;

	urb = usb_get_from_anchor(&aru->tx_pending);
	if (!urb) {
		aru->tx_submitted_urbs--;
		spin_unlock_irqrestore(&aru->tx_urb_lock, flags);

		return ;
	}
	spin_unlock_irqrestore(&aru->tx_urb_lock, flags);

	aru->tx_pending_urbs--;
	usb_anchor_urb(urb, &aru->tx_submitted);

	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (unlikely(err)) {
		if (ar9170_nag_limiter(&aru->common))
			dev_err(&aru->udev->dev, "submit_urb failed (%d).\n",
				err);

		usb_unanchor_urb(urb);
		aru->tx_submitted_urbs--;
		ar9170_tx_callback(&aru->common, urb->context);
	}

	usb_free_urb(urb);
}
Exemplo n.º 2
0
static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,
			       unsigned int plen, void *payload,
			       unsigned int outlen, void *out)
{
	struct ar9170_usb *aru = (void *) ar;
	struct urb *urb = NULL;
	unsigned long flags;
	int err = -ENOMEM;

	if (unlikely(!IS_ACCEPTING_CMD(ar)))
		return -EPERM;

	if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4))
		return -EINVAL;

	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (unlikely(!urb))
		goto err_free;

	ar->cmdbuf[0] = cpu_to_le32(plen);
	ar->cmdbuf[0] |= cpu_to_le32(cmd << 8);
	/* writing multiple regs fills this buffer already */
	if (plen && payload != (u8 *)(&ar->cmdbuf[1]))
		memcpy(&ar->cmdbuf[1], payload, plen);

	spin_lock_irqsave(&aru->common.cmdlock, flags);
	aru->readbuf = (u8 *)out;
	aru->readlen = outlen;
	spin_unlock_irqrestore(&aru->common.cmdlock, flags);

	usb_fill_int_urb(urb, aru->udev,
			 usb_sndintpipe(aru->udev, AR9170_EP_CMD),
			 aru->common.cmdbuf, plen + 4,
			 ar9170_usb_tx_urb_complete, NULL, 1);

	usb_anchor_urb(urb, &aru->tx_submitted);
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (unlikely(err)) {
		usb_unanchor_urb(urb);
		usb_free_urb(urb);
		goto err_unbuf;
	}
	usb_free_urb(urb);

	err = wait_for_completion_timeout(&aru->cmd_wait, HZ);
	if (err == 0) {
		err = -ETIMEDOUT;
		goto err_unbuf;
	}

	if (aru->readlen != outlen) {
		err = -EMSGSIZE;
		goto err_unbuf;
	}

	return 0;

err_unbuf:
	/* Maybe the device was removed in the second we were waiting? */
	if (IS_STARTED(ar)) {
		dev_err(&aru->udev->dev, "no command feedback "
					 "received (%d).\n", err);

		/* provide some maybe useful debug information */
		print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE,
				     aru->common.cmdbuf, plen + 4);
		dump_stack();
	}

	/* invalidate to avoid completing the next prematurely */
	spin_lock_irqsave(&aru->common.cmdlock, flags);
	aru->readbuf = NULL;
	aru->readlen = 0;
	spin_unlock_irqrestore(&aru->common.cmdlock, flags);

err_free:

	return err;
}
Exemplo n.º 3
0
void ar9170_usb_tx( struct ar9170* ar, struct sk_buff* skb )
{
	struct ar9170_stream *tx_stream;
	uint8_t *data = (uint8_t*)smalloc(skb->len);
	if (data == NULL) {
		printf("ERROR: Could not allocate memory for data transmission.\n");
		return;
	}
	uint32_t len;

	if (!IS_STARTED(ar)) {
		printf("WARNING: Got packet tx request on a non-started device, so packet will be dropped.\n");
		goto err_drop;	
	}	

	if (ar->fw.tx_stream) {
		printf("WARNING: Firmware supports tx_stream. It should NOT enter here.\n");
		tx_stream = (void *) (skb->data - sizeof(*tx_stream));

		len = skb->len + sizeof(*tx_stream);
		tx_stream->length = cpu_to_le16(len);
		tx_stream->tag = cpu_to_le16(AR9170_TX_STREAM_TAG);
		data = (void*)tx_stream;
	} else {
		#if USB_DATA_WRAPPER_DEBUG_DEEP
		printf("DEBUG: No stream supported [default].\n");
		#endif
		if (skb->data == NULL) {
			printf("ERROR: Finally, packet data is null.\n");
			return;
		}
		memcpy(data ,skb->data, skb->len);
		len = skb->len;
	}

	/* 
	 * Prepare the tx request to be sent down as a bulk data request.
	 */
	if (len > BULK_ENDPOINT_MAX_OUT_SIZE) {
		printf("ERROR: Data chunk is too large [%u]. Drop.\n",len);
		goto err_drop;
	}
	
	if(!ar9170_write_data(data, (uint16_t)len, ZERO_PACKET_FLAG)) {
		printf("ERROR: Transferring data chunk unsuccessful.\n");
	}
	/* Do not free socket buffer resources. They will be freed by the AR9170_async_tx method. */
/*	
	if (skb->data != NULL) {
		free(skb->data);
		skb->data = NULL;
	} else {
		printf("ERROR: socket buffer content is already null.\n");
	}
*/	
	/* Socket buffer itself must be freed when the function returns.*/
	return;
	
/*	

	
	usb_fill_bulk_urb(urb, ar->udev, usb_sndbulkpipe(ar->udev,
	AR9170_USB_EP_TX), data, len,
	carl9170_usb_tx_data_complete, skb);

	urb->transfer_flags |= URB_ZERO_PACKET;

	usb_anchor_urb(urb, &ar->tx_wait);

	usb_free_urb(urb);
	
	carl9170_usb_submit_data_urb(ar);
	return;
*/
err_drop:
	printf("TX_DROP\n");
	ar9170_tx_drop(ar, skb);
	//carl9170_tx_callback(ar, skb);	
	/* Perhaps this freeing can be done in drop FIXME */
	free(skb->data);
	skb->data = NULL;
	/* Socket buffer itself must be freed when the function returns.*/
	return;
}
Exemplo n.º 4
0
static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
{
	struct ar9170_rx_head *head;
	struct ar9170_rx_macstatus *mac;
	struct ar9170_rx_phystatus *phy = NULL;
	struct ieee80211_rx_status status;
	struct sk_buff *skb;
	int mpdu_len;
	u8 mac_status;

	if (!IS_STARTED(ar))
		return;

	if (unlikely(len < sizeof(*mac)))
		goto drop;

	mpdu_len = len - sizeof(*mac);

	mac = (void *)(buf + mpdu_len);
	mac_status = mac->status;
	switch (mac_status & AR9170_RX_STATUS_MPDU) {
	case AR9170_RX_STATUS_MPDU_FIRST:
		/* Aggregated MPDUs start with an PLCP header */
		if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
			head = (void *) buf;

			/*
			 * The PLCP header needs to be cached for the
			 * following MIDDLE + LAST A-MPDU packets.
			 *
			 * So, if you are wondering why all frames seem
			 * to share a common RX status information,
			 * then you have the answer right here...
			 */
			memcpy(&ar->rx_plcp, (void *) buf,
			       sizeof(struct ar9170_rx_head));

			mpdu_len -= sizeof(struct ar9170_rx_head);
			buf += sizeof(struct ar9170_rx_head);

			ar->rx_has_plcp = true;
		} else {
			if (net_ratelimit()) {
				wiphy_err(ar->hw->wiphy, "plcp info "
					"is clipped.\n");
			}

			goto drop;
		}
		break;

	case AR9170_RX_STATUS_MPDU_LAST:
		/*
		 * The last frame of an A-MPDU has an extra tail
		 * which does contain the phy status of the whole
		 * aggregate.
		 */

		if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
			mpdu_len -= sizeof(struct ar9170_rx_phystatus);
			phy = (void *)(buf + mpdu_len);
		} else {
			if (net_ratelimit()) {
				wiphy_err(ar->hw->wiphy, "frame tail "
					"is clipped.\n");
			}

			goto drop;
		}

	case AR9170_RX_STATUS_MPDU_MIDDLE:
		/*  These are just data + mac status */
		if (unlikely(!ar->rx_has_plcp)) {
			if (!net_ratelimit())
				return;

			wiphy_err(ar->hw->wiphy, "rx stream does not start "
					"with a first_mpdu frame tag.\n");

			goto drop;
		}

		head = &ar->rx_plcp;
		break;

	case AR9170_RX_STATUS_MPDU_SINGLE:
		/* single mpdu has both: plcp (head) and phy status (tail) */
		head = (void *) buf;

		mpdu_len -= sizeof(struct ar9170_rx_head);
		mpdu_len -= sizeof(struct ar9170_rx_phystatus);

		buf += sizeof(struct ar9170_rx_head);
		phy = (void *)(buf + mpdu_len);
		break;

	default:
		BUG_ON(1);
		break;
	}

	/* FC + DU + RA + FCS */
	if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN)))
		goto drop;

	memset(&status, 0, sizeof(status));
	if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status)))
		goto drop;

	if (!carl9170_ampdu_check(ar, buf, mac_status))
		goto drop;

	if (phy)
		carl9170_rx_phy_status(ar, phy, &status);

	carl9170_ps_beacon(ar, buf, mpdu_len);

	skb = carl9170_rx_copy_data(buf, mpdu_len);
	if (!skb)
		goto drop;

	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
	ieee80211_rx(ar->hw, skb);
	return;

drop:
	ar->rx_dropped++;
}
Exemplo n.º 5
0
int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
                      unsigned int plen, void *payload, unsigned int outlen, void *out)
{
    int err = -ENOMEM;
    unsigned long time_left;

    if (!IS_ACCEPTING_CMD(ar))
        return -EIO;

    if (!(cmd & CARL9170_CMD_ASYNC_FLAG))
        might_sleep();

    ar->cmd.hdr.len = plen;
    ar->cmd.hdr.cmd = cmd;
    /* writing multiple regs fills this buffer already */
    if (plen && payload != (u8 *)(ar->cmd.data))
        memcpy(ar->cmd.data, payload, plen);

    spin_lock_bh(&ar->cmd_lock);
    ar->readbuf = (u8 *)out;
    ar->readlen = outlen;
    spin_unlock_bh(&ar->cmd_lock);

    err = __carl9170_exec_cmd(ar, &ar->cmd, false);

    if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) {
        time_left = wait_for_completion_timeout(&ar->cmd_wait, HZ);
        if (time_left == 0) {
            err = -ETIMEDOUT;
            goto err_unbuf;
        }

        if (ar->readlen != outlen) {
            err = -EMSGSIZE;
            goto err_unbuf;
        }
    }

    return 0;

err_unbuf:
    /* Maybe the device was removed in the moment we were waiting? */
    if (IS_STARTED(ar)) {
        dev_err(&ar->udev->dev, "no command feedback "
                "received (%d).\n", err);

        /* provide some maybe useful debug information */
        print_hex_dump_bytes("carl9170 cmd: ", DUMP_PREFIX_NONE,
                             &ar->cmd, plen + 4);

        carl9170_restart(ar, CARL9170_RR_COMMAND_TIMEOUT);
    }

    /* invalidate to avoid completing the next command prematurely */
    spin_lock_bh(&ar->cmd_lock);
    ar->readbuf = NULL;
    ar->readlen = 0;
    spin_unlock_bh(&ar->cmd_lock);

    return err;
}