int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, const u16 buffer_length, const int timeout) { int status; BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex)); /* * Check for Cache availability. */ if (unlikely(!rt2x00dev->csr.cache || buffer_length > CSR_CACHE_SIZE)) { rt2x00_err(rt2x00dev, "CSR cache not available\n"); return -ENOMEM; } if (requesttype == USB_VENDOR_REQUEST_OUT) memcpy(rt2x00dev->csr.cache, buffer, buffer_length); status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype, offset, 0, rt2x00dev->csr.cache, buffer_length, timeout); if (!status && requesttype == USB_VENDOR_REQUEST_IN) memcpy(buffer, rt2x00dev->csr.cache, buffer_length); return status; }
static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) { unsigned int i; u32 reg; /* * SOC devices don't support MCU requests. */ if (rt2x00_is_soc(rt2x00dev)) return; for (i = 0; i < 200; i++) { rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD2) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD3) == token)) break; udelay(REGISTER_BUSY_DELAY); } if (i == 200) rt2x00_err(rt2x00dev, "MCU request failed, no response from hardware\n"); rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); }
static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev) { const struct firmware *ee; const char *ee_name; int retval; if (!rt2800lib_read_eeprom_mtd(rt2x00dev)) return 0; ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev); if (!ee_name) { rt2x00_err(rt2x00dev, "Invalid EEPROM filename.\n" "Please file bug report to %s.\n", DRV_PROJECT); return -EINVAL; } rt2x00_info(rt2x00dev, "Loading EEPROM data from '%s'.\n", ee_name); retval = request_firmware(&ee, ee_name, rt2x00dev->dev); if (retval) { rt2x00_err(rt2x00dev, "Failed to request EEPROM.\n"); return retval; } if (!ee || !ee->size || !ee->data) { rt2x00_err(rt2x00dev, "Failed to read EEPROM file.\n"); retval = -ENOENT; goto err_exit; } if (ee->size != rt2x00dev->ops->eeprom_size) { rt2x00_err(rt2x00dev, "EEPROM file size is invalid, it should be %d bytes\n", rt2x00dev->ops->eeprom_size); retval = -EINVAL; goto err_release_ee; } rt2x00dev->eeprom_file = ee; return 0; err_release_ee: release_firmware(ee); err_exit: return retval; }
int rt2x00pci_resume(struct pci_dev *pci_dev) { struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); struct rt2x00_dev *rt2x00dev = hw->priv; if (pci_set_power_state(pci_dev, PCI_D0) || pci_enable_device(pci_dev)) { rt2x00_err(rt2x00dev, "Failed to resume device\n"); return -EIO; } pci_restore_state(pci_dev); return rt2x00lib_resume(rt2x00dev); }
static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev) { struct usb_interface *intf = to_usb_interface(rt2x00dev->dev); struct usb_host_interface *intf_desc = intf->cur_altsetting; struct usb_endpoint_descriptor *ep_desc; struct data_queue *queue = rt2x00dev->tx; struct usb_endpoint_descriptor *tx_ep_desc = NULL; unsigned int i; /* * Walk through all available endpoints to search for "bulk in" * and "bulk out" endpoints. When we find such endpoints collect * the information we need from the descriptor and assign it * to the queue. */ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { ep_desc = &intf_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_in(ep_desc)) { rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc); } else if (usb_endpoint_is_bulk_out(ep_desc) && (queue != queue_end(rt2x00dev))) { rt2x00usb_assign_endpoint(queue, ep_desc); queue = queue_next(queue); tx_ep_desc = ep_desc; } } /* * At least 1 endpoint for RX and 1 endpoint for TX must be available. */ if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) { rt2x00_err(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n"); return -EPIPE; } /* * It might be possible not all queues have a dedicated endpoint. * Loop through all TX queues and copy the endpoint information * which we have gathered from already assigned endpoints. */ txall_queue_for_each(rt2x00dev, queue) { if (!queue->usb_endpoint) rt2x00usb_assign_endpoint(queue, tx_ep_desc); } return 0; }
/* * Interfacing with the HW. */ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, const int timeout) { struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); int status; unsigned int i; unsigned int pipe = (requesttype == USB_VENDOR_REQUEST_IN) ? usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return -ENODEV; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { status = usb_control_msg(usb_dev, pipe, request, requesttype, value, offset, buffer, buffer_length, timeout); if (status >= 0) return 0; /* * Check for errors * -ENODEV: Device has disappeared, no point continuing. * All other errors: Try again. */ else if (status == -ENODEV) { clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); break; } } rt2x00_err(rt2x00dev, "Vendor Request 0x%02x failed for offset 0x%04x with error %d\n", request, offset, status); return status; }
static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { int retval = 0; switch (state) { case STATE_RADIO_ON: retval = rt2800mmio_enable_radio(rt2x00dev); break; case STATE_RADIO_OFF: rt2800soc_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: case STATE_RADIO_IRQ_OFF: rt2800mmio_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: case STATE_SLEEP: case STATE_STANDBY: case STATE_AWAKE: /* These states are not supported, but don't report an error */ retval = 0; break; default: retval = -ENOTSUPP; break; } if (unlikely(retval)) rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n", state, retval); return retval; }
static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { int retval = 0; switch (state) { case STATE_RADIO_ON: retval = rt2800pci_enable_radio(rt2x00dev); break; case STATE_RADIO_OFF: /* * After the radio has been disabled, the device should * be put to sleep for powersaving. */ rt2800pci_disable_radio(rt2x00dev); rt2800pci_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_IRQ_ON: case STATE_RADIO_IRQ_OFF: rt2800pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: case STATE_SLEEP: case STATE_STANDBY: case STATE_AWAKE: retval = rt2800pci_set_state(rt2x00dev, state); break; default: retval = -ENOTSUPP; break; } if (unlikely(retval)) rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n", state, retval); return retval; }
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, const struct rt2x00_field32 field, u32 *reg) { unsigned int i; if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return -ENODEV; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00usb_register_read_lock(rt2x00dev, offset, reg); if (!rt2x00_get_field32(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); } rt2x00_err(rt2x00dev, "Indirect register access failed: offset=0x%.08x, value=0x%.08x\n", offset, *reg); *reg = ~0; return 0; }
/* * Interfacing with the HW. */ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, const int timeout) { struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); int status; unsigned int pipe = (requesttype == USB_VENDOR_REQUEST_IN) ? usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); unsigned long expire = jiffies + msecs_to_jiffies(timeout); if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return -ENODEV; do { status = usb_control_msg(usb_dev, pipe, request, requesttype, value, offset, buffer, buffer_length, timeout / 2); if (status >= 0) return 0; if (status == -ENODEV) { /* Device has disappeared. */ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); break; } } while (time_before(jiffies, expire)); rt2x00_err(rt2x00dev, "Vendor Request 0x%02x failed for offset 0x%04x with error %d\n", request, offset, status); return status; }
void rt2x00mac_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue = NULL; /* * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. * Note that we can only stop the TX queues inside the TX path * due to possible race conditions in mac80211. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) goto exit_free_skb; /* * Use the ATIM queue if appropriate and present. */ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) qid = QID_ATIM; queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); if (unlikely(!queue)) { rt2x00_err(rt2x00dev, "Attempt to send packet over invalid queue %d\n" "Please file bug report to %s\n", qid, DRV_PROJECT); goto exit_free_skb; } /* * If CTS/RTS is required. create and queue that frame first. * Make sure we have at least enough entries available to send * this CTS/RTS frame as well as the data frame. * Note that when the driver has set the set_rts_threshold() * callback function it doesn't need software generation of * either RTS or CTS-to-self frame and handles everything * inside the hardware. */ if (!rt2x00dev->ops->hw->set_rts_threshold && (tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | IEEE80211_TX_RC_USE_CTS_PROTECT))) { if (rt2x00queue_available(queue) <= 1) goto exit_fail; if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) goto exit_fail; } if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false))) goto exit_fail; /* * Pausing queue has to be serialized with rt2x00lib_txdone(). Note * we should not use spin_lock_bh variant as bottom halve was already * disabled before ieee80211_xmit() call. */ spin_lock(&queue->tx_lock); if (rt2x00queue_threshold(queue)) rt2x00queue_pause_queue(queue); spin_unlock(&queue->tx_lock); return; exit_fail: spin_lock(&queue->tx_lock); rt2x00queue_pause_queue(queue); spin_unlock(&queue->tx_lock); exit_free_skb: ieee80211_free_txskb(hw, skb); }
static int rt2x00lib_reject_firmware(struct rt2x00_dev *rt2x00dev) { struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); const struct firmware *fw; char *fw_name; int retval; /* * Read correct firmware from harddisk. */ fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev); if (!fw_name) { rt2x00_err(rt2x00dev, "Invalid firmware filename\n" "Please file bug report to %s\n", DRV_PROJECT); return -EINVAL; } rt2x00_info(rt2x00dev, "Loading firmware file '%s'\n", fw_name); retval = reject_firmware(&fw, fw_name, device); if (retval) { rt2x00_err(rt2x00dev, "Failed to request Firmware\n"); return retval; } if (!fw || !fw->size || !fw->data) { rt2x00_err(rt2x00dev, "Failed to read Firmware\n"); release_firmware(fw); return -ENOENT; } rt2x00_info(rt2x00dev, "Firmware detected - version: %d.%d\n", fw->data[fw->size - 4], fw->data[fw->size - 3]); snprintf(rt2x00dev->hw->wiphy->fw_version, sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d", fw->data[fw->size - 4], fw->data[fw->size - 3]); retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size); switch (retval) { case FW_OK: break; case FW_BAD_CRC: rt2x00_err(rt2x00dev, "Firmware checksum error\n"); goto exit; case FW_BAD_LENGTH: rt2x00_err(rt2x00dev, "Invalid firmware file length (len=%zu)\n", fw->size); goto exit; case FW_BAD_VERSION: rt2x00_err(rt2x00dev, "Current firmware does not support detected chipset\n"); goto exit; } rt2x00dev->fw = fw; return 0; exit: release_firmware(fw); return -ENOENT; }