diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00usb.c')
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 129 | 
1 files changed, 108 insertions, 21 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 36f388f97d6..39e1052123e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -165,6 +165,59 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,  }  EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + +struct rt2x00_async_read_data { +	__le32 reg; +	struct usb_ctrlrequest cr; +	struct rt2x00_dev *rt2x00dev; +	bool (*callback)(struct rt2x00_dev *, int, u32); +}; + +static void rt2x00usb_register_read_async_cb(struct urb *urb) +{ +	struct rt2x00_async_read_data *rd = urb->context; +	if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) { +		if (usb_submit_urb(urb, GFP_ATOMIC) < 0) +			kfree(rd); +	} else +		kfree(rd); +} + +void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, +				   const unsigned int offset, +				   bool (*callback)(struct rt2x00_dev*, int, u32)) +{ +	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); +	struct urb *urb; +	struct rt2x00_async_read_data *rd; + +	rd = kmalloc(sizeof(*rd), GFP_ATOMIC); +	if (!rd) +		return; + +	urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (!urb) { +		kfree(rd); +		return; +	} + +	rd->rt2x00dev = rt2x00dev; +	rd->callback = callback; +	rd->cr.bRequestType = USB_VENDOR_REQUEST_IN; +	rd->cr.bRequest = USB_MULTI_READ; +	rd->cr.wValue = 0; +	rd->cr.wIndex = cpu_to_le16(offset); +	rd->cr.wLength = cpu_to_le16(sizeof(u32)); + +	usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0), +			     (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg), +			     rt2x00usb_register_read_async_cb, rd); +	if (usb_submit_urb(urb, GFP_ATOMIC) < 0) +		kfree(rd); +	usb_free_urb(urb); +} +EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async); +  /*   * TX data handlers.   */ @@ -212,6 +265,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)  	if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))  		return; +	if (rt2x00dev->ops->lib->tx_dma_done) +		rt2x00dev->ops->lib->tx_dma_done(entry); +  	/*  	 * Report the frame as DMA done  	 */ @@ -227,10 +283,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)  	 * Schedule the delayed work for reading the TX status  	 * from the device.  	 */ -	queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); +	if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) || +	    !kfifo_is_empty(&rt2x00dev->txstatus_fifo)) +		queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);  } -static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) +static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data)  {  	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;  	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -240,7 +298,7 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)  	if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||  	    test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) -		return; +		return true;  	/*  	 * USB devices cannot blindly pass the skb->len as the @@ -261,6 +319,8 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)  		set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);  		rt2x00lib_dmadone(entry);  	} + +	return false;  }  /* @@ -323,7 +383,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)  	queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);  } -static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) +static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data)  {  	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;  	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -332,7 +392,7 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)  	if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||  	    test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) -		return; +		return true;  	rt2x00lib_dmastart(entry); @@ -348,6 +408,8 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)  		set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);  		rt2x00lib_dmadone(entry);  	} + +	return false;  }  void rt2x00usb_kick_queue(struct data_queue *queue) @@ -358,12 +420,18 @@ void rt2x00usb_kick_queue(struct data_queue *queue)  	case QID_AC_BE:  	case QID_AC_BK:  		if (!rt2x00queue_empty(queue)) -			rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, +			rt2x00queue_for_each_entry(queue, +						   Q_INDEX_DONE, +						   Q_INDEX, +						   NULL,  						   rt2x00usb_kick_tx_entry);  		break;  	case QID_RX:  		if (!rt2x00queue_full(queue)) -			rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, +			rt2x00queue_for_each_entry(queue, +						   Q_INDEX_DONE, +						   Q_INDEX, +						   NULL,  						   rt2x00usb_kick_rx_entry);  		break;  	default: @@ -372,14 +440,14 @@ void rt2x00usb_kick_queue(struct data_queue *queue)  }  EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); -static void rt2x00usb_flush_entry(struct queue_entry *entry) +static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data)  {  	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;  	struct queue_entry_priv_usb *entry_priv = entry->priv_data;  	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;  	if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) -		return; +		return true;  	usb_kill_urb(entry_priv->urb); @@ -387,17 +455,20 @@ static void rt2x00usb_flush_entry(struct queue_entry *entry)  	 * Kill guardian urb (if required by driver).  	 */  	if ((entry->queue->qid == QID_BEACON) && -	    (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) +	    (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)))  		usb_kill_urb(bcn_priv->guardian_urb); + +	return false;  } -void rt2x00usb_flush_queue(struct data_queue *queue) +void rt2x00usb_flush_queue(struct data_queue *queue, bool drop)  {  	struct work_struct *completion;  	unsigned int i; -	rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, -				   rt2x00usb_flush_entry); +	if (drop) +		rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, +					   rt2x00usb_flush_entry);  	/*  	 * Obtain the queue completion handler @@ -416,7 +487,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue)  		return;  	} -	for (i = 0; i < 20; i++) { +	for (i = 0; i < 10; i++) {  		/*  		 * Check if the driver is already done, otherwise we  		 * have to sleep a little while to give the driver/hw @@ -456,15 +527,31 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)  	queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work);  } +static int rt2x00usb_status_timeout(struct data_queue *queue) +{ +	struct queue_entry *entry; + +	entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); +	return rt2x00queue_status_timeout(entry); +} + +static int rt2x00usb_dma_timeout(struct data_queue *queue) +{ +	struct queue_entry *entry; + +	entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE); +	return rt2x00queue_dma_timeout(entry); +} +  void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)  {  	struct data_queue *queue;  	tx_queue_for_each(rt2x00dev, queue) {  		if (!rt2x00queue_empty(queue)) { -			if (rt2x00queue_dma_timeout(queue)) +			if (rt2x00usb_dma_timeout(queue))  				rt2x00usb_watchdog_tx_dma(queue); -			if (rt2x00queue_status_timeout(queue)) +			if (rt2x00usb_status_timeout(queue))  				rt2x00usb_watchdog_tx_status(queue);  		}  	} @@ -489,7 +576,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)  	entry->flags = 0;  	if (entry->queue->qid == QID_RX) -		rt2x00usb_kick_rx_entry(entry); +		rt2x00usb_kick_rx_entry(entry, NULL);  }  EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); @@ -583,7 +670,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue)  	 * then we are done.  	 */  	if (queue->qid != QID_BEACON || -	    !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) +	    !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))  		return 0;  	for (i = 0; i < queue->limit; i++) { @@ -618,7 +705,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue)  	 * then we are done.  	 */  	if (queue->qid != QID_BEACON || -	    !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) +	    !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))  		return;  	for (i = 0; i < queue->limit; i++) { @@ -707,10 +794,9 @@ exit:  }  int rt2x00usb_probe(struct usb_interface *usb_intf, -		    const struct usb_device_id *id) +		    const struct rt2x00_ops *ops)  {  	struct usb_device *usb_dev = interface_to_usbdev(usb_intf); -	struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;  	struct ieee80211_hw *hw;  	struct rt2x00_dev *rt2x00dev;  	int retval; @@ -735,6 +821,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,  	INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);  	INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); +	init_timer(&rt2x00dev->txstatus_timer);  	retval = rt2x00usb_alloc_reg(rt2x00dev);  	if (retval)  |