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); }
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; }
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; }
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++; }
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; }