+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_entry *entry;
+ struct data_desc *rxd;
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ struct rxdata_entry_desc desc;
+ int header_size;
+ int align;
+ u32 word;
+
+ while (1) {
+ entry = rt2x00_get_data_entry(ring);
+ rxd = entry->priv;
+ rt2x00_desc_read(rxd, 0, &word);
+
+ if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+ break;
+
+ memset(&desc, 0x00, sizeof(desc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+ hdr = (struct ieee80211_hdr *)entry->data_addr;
+ header_size =
+ ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+
+ /*
+ * The data behind the ieee80211 header must be
+ * aligned on a 4 byte boundary.
+ */
+ align = header_size % 4;
+
+ /*
+ * Allocate the sk_buffer, initialize it and copy
+ * all data into it.
+ */
+ skb = dev_alloc_skb(desc.size + align);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, align);
+ memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, skb, &desc);
+
+ if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+ rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_inc(ring);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+