Commit | Line | Data |
---|---|---|
6112fd6e LL |
1 | /* |
2 | * ============================================================================ | |
3 | * Copyright (c) 1996-2002 Winbond Electronic Corporation | |
4 | * | |
5 | * Module Name: | |
6 | * Wb35Rx.c | |
7 | * | |
8 | * Abstract: | |
9 | * Processing the Rx message from down layer | |
10 | * | |
11 | * ============================================================================ | |
12 | */ | |
80aba536 | 13 | #include <linux/usb.h> |
5a0e3ad6 | 14 | #include <linux/slab.h> |
80aba536 | 15 | |
7fff1316 | 16 | #include "core.h" |
80aba536 | 17 | #include "wb35rx_f.h" |
66101de1 | 18 | |
c139a814 | 19 | static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int PacketSize) |
66101de1 | 20 | { |
7fff1316 | 21 | struct wbsoft_priv *priv = hw->priv; |
c139a814 PE |
22 | struct sk_buff *skb; |
23 | struct ieee80211_rx_status rx_status = {0}; | |
66101de1 | 24 | |
c139a814 PE |
25 | if (!priv->enabled) |
26 | return; | |
27 | ||
28 | skb = dev_alloc_skb(PacketSize); | |
29 | if (!skb) { | |
30 | printk("Not enough memory for packet, FIXME\n"); | |
31 | return; | |
32 | } | |
33 | ||
6112fd6e | 34 | memcpy(skb_put(skb, PacketSize), pRxBufferAddress, PacketSize); |
c139a814 | 35 | |
f1d58c25 JB |
36 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); |
37 | ieee80211_rx_irqsafe(hw, skb); | |
66101de1 PM |
38 | } |
39 | ||
27d46421 | 40 | static void Wb35Rx_adjust(struct wb35_descriptor *pRxDes) |
c139a814 | 41 | { |
6112fd6e | 42 | u32 *pRxBufferAddress; |
c139a814 PE |
43 | u32 DecryptionMethod; |
44 | u32 i; | |
45 | u16 BufferSize; | |
46 | ||
47 | DecryptionMethod = pRxDes->R01.R01_decryption_method; | |
48 | pRxBufferAddress = pRxDes->buffer_address[0]; | |
49 | BufferSize = pRxDes->buffer_size[0]; | |
50 | ||
6112fd6e LL |
51 | /* Adjust the last part of data. Only data left */ |
52 | BufferSize -= 4; /* For CRC-32 */ | |
c139a814 PE |
53 | if (DecryptionMethod) |
54 | BufferSize -= 4; | |
6112fd6e | 55 | if (DecryptionMethod == 3) /* For CCMP */ |
c139a814 PE |
56 | BufferSize -= 4; |
57 | ||
6112fd6e LL |
58 | /* Adjust the IV field which after 802.11 header and ICV field. */ |
59 | if (DecryptionMethod == 1) { /* For WEP */ | |
60 | for (i = 6; i > 0; i--) | |
61 | pRxBufferAddress[i] = pRxBufferAddress[i - 1]; | |
c139a814 | 62 | pRxDes->buffer_address[0] = pRxBufferAddress + 1; |
6112fd6e LL |
63 | BufferSize -= 4; /* 4 byte for IV */ |
64 | } else if (DecryptionMethod) { /* For TKIP and CCMP */ | |
65 | for (i = 7; i > 1; i--) | |
66 | pRxBufferAddress[i] = pRxBufferAddress[i - 2]; | |
67 | pRxDes->buffer_address[0] = pRxBufferAddress + 2; /* Update the descriptor, shift 8 byte */ | |
68 | BufferSize -= 8; /* 8 byte for IV + ICV */ | |
c139a814 PE |
69 | } |
70 | pRxDes->buffer_size[0] = BufferSize; | |
71 | } | |
72 | ||
73 | static u16 Wb35Rx_indicate(struct ieee80211_hw *hw) | |
66101de1 | 74 | { |
6112fd6e LL |
75 | struct wbsoft_priv *priv = hw->priv; |
76 | struct hw_data *pHwData = &priv->sHwData; | |
27d46421 | 77 | struct wb35_descriptor RxDes; |
6112fd6e LL |
78 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
79 | u8 *pRxBufferAddress; | |
80 | u16 PacketSize; | |
81 | u16 stmp, BufferSize, stmp2 = 0; | |
82 | u32 RxBufferId; | |
66101de1 | 83 | |
6112fd6e | 84 | /* Only one thread be allowed to run into the following */ |
c139a814 PE |
85 | do { |
86 | RxBufferId = pWb35Rx->RxProcessIndex; | |
6112fd6e | 87 | if (pWb35Rx->RxOwner[RxBufferId]) /* Owner by VM */ |
c139a814 | 88 | break; |
dc7e04fe | 89 | |
c139a814 PE |
90 | pWb35Rx->RxProcessIndex++; |
91 | pWb35Rx->RxProcessIndex %= MAX_USB_RX_BUFFER_NUMBER; | |
dc7e04fe | 92 | |
c139a814 | 93 | pRxBufferAddress = pWb35Rx->pDRx; |
6112fd6e | 94 | BufferSize = pWb35Rx->RxBufferSize[RxBufferId]; |
dc7e04fe | 95 | |
6112fd6e | 96 | /* Parse the bulkin buffer */ |
c139a814 | 97 | while (BufferSize >= 4) { |
6112fd6e | 98 | if ((cpu_to_le32(*(u32 *)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) /* Is ending? */ |
c139a814 | 99 | break; |
dc7e04fe | 100 | |
6112fd6e | 101 | /* Get the R00 R01 first */ |
c139a814 PE |
102 | RxDes.R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress); |
103 | PacketSize = (u16)RxDes.R00.R00_receive_byte_count; | |
6112fd6e LL |
104 | RxDes.R01.value = le32_to_cpu(*((u32 *)(pRxBufferAddress + 4))); |
105 | /* For new DMA 4k */ | |
c139a814 PE |
106 | if ((PacketSize & 0x03) > 0) |
107 | PacketSize -= 4; | |
dc7e04fe | 108 | |
6112fd6e | 109 | /* Basic check for Rx length. Is length valid? */ |
c139a814 | 110 | if (PacketSize > MAX_PACKET_SIZE) { |
2855bb79 | 111 | pr_debug("Serious ERROR : Rx data size too long, size =%d\n", PacketSize); |
c139a814 PE |
112 | pWb35Rx->EP3vm_state = VM_STOP; |
113 | pWb35Rx->Ep3ErrorCount2++; | |
114 | break; | |
115 | } | |
dc7e04fe | 116 | |
6112fd6e LL |
117 | /* |
118 | * Wb35Rx_indicate() is called synchronously so it isn't | |
119 | * necessary to set "RxDes.Desctriptor_ID = RxBufferID;" | |
120 | */ | |
121 | BufferSize -= 8; /* subtract 8 byte for 35's USB header length */ | |
c139a814 | 122 | pRxBufferAddress += 8; |
dc7e04fe | 123 | |
c139a814 PE |
124 | RxDes.buffer_address[0] = pRxBufferAddress; |
125 | RxDes.buffer_size[0] = PacketSize; | |
126 | RxDes.buffer_number = 1; | |
127 | RxDes.buffer_start_index = 0; | |
128 | RxDes.buffer_total_size = RxDes.buffer_size[0]; | |
129 | Wb35Rx_adjust(&RxDes); | |
dc7e04fe | 130 | |
c139a814 | 131 | packet_came(hw, pRxBufferAddress, PacketSize); |
dc7e04fe | 132 | |
6112fd6e | 133 | /* Move RxBuffer point to the next */ |
c139a814 | 134 | stmp = PacketSize + 3; |
6112fd6e | 135 | stmp &= ~0x03; /* 4n alignment */ |
c139a814 PE |
136 | pRxBufferAddress += stmp; |
137 | BufferSize -= stmp; | |
138 | stmp2 += stmp; | |
139 | } | |
140 | ||
6112fd6e LL |
141 | /* Reclaim resource */ |
142 | pWb35Rx->RxOwner[RxBufferId] = 1; | |
c139a814 | 143 | } while (true); |
c139a814 | 144 | return stmp2; |
66101de1 PM |
145 | } |
146 | ||
c139a814 PE |
147 | static void Wb35Rx(struct ieee80211_hw *hw); |
148 | ||
149 | static void Wb35Rx_Complete(struct urb *urb) | |
66101de1 | 150 | { |
6112fd6e LL |
151 | struct ieee80211_hw *hw = urb->context; |
152 | struct wbsoft_priv *priv = hw->priv; | |
153 | struct hw_data *pHwData = &priv->sHwData; | |
154 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; | |
155 | u8 *pRxBufferAddress; | |
156 | u32 SizeCheck; | |
157 | u16 BulkLength; | |
158 | u32 RxBufferId; | |
c4d562a9 | 159 | struct R00_descriptor R00; |
6112fd6e LL |
160 | |
161 | /* Variable setting */ | |
66101de1 | 162 | pWb35Rx->EP3vm_state = VM_COMPLETED; |
6112fd6e | 163 | pWb35Rx->EP3VM_status = urb->status; /* Store the last result of Irp */ |
66101de1 | 164 | |
dc7e04fe | 165 | RxBufferId = pWb35Rx->CurrentRxBufferId; |
66101de1 | 166 | |
dc7e04fe | 167 | pRxBufferAddress = pWb35Rx->pDRx; |
a55a89b1 | 168 | BulkLength = (u16)urb->actual_length; |
66101de1 | 169 | |
6112fd6e | 170 | /* The IRP is completed */ |
dc7e04fe | 171 | pWb35Rx->EP3vm_state = VM_COMPLETED; |
66101de1 | 172 | |
87cb9a63 | 173 | if (pHwData->SurpriseRemove) /* Must be here, or RxBufferId is invalid */ |
dc7e04fe PE |
174 | goto error; |
175 | ||
176 | if (pWb35Rx->rx_halt) | |
177 | goto error; | |
178 | ||
6112fd6e LL |
179 | /* Start to process the data only in successful condition */ |
180 | pWb35Rx->RxOwner[RxBufferId] = 0; /* Set the owner to driver */ | |
dc7e04fe PE |
181 | R00.value = le32_to_cpu(*(u32 *)pRxBufferAddress); |
182 | ||
6112fd6e | 183 | /* The URB is completed, check the result */ |
dc7e04fe | 184 | if (pWb35Rx->EP3VM_status != 0) { |
2855bb79 | 185 | pr_debug("EP3 IoCompleteRoutine return error\n"); |
dc7e04fe PE |
186 | pWb35Rx->EP3vm_state = VM_STOP; |
187 | goto error; | |
188 | } | |
189 | ||
6112fd6e | 190 | /* For recovering. check if operating in single USB mode */ |
dc7e04fe | 191 | if (!HAL_USB_MODE_BURST(pHwData)) { |
6112fd6e | 192 | SizeCheck = R00.R00_receive_byte_count; |
dc7e04fe PE |
193 | if ((SizeCheck & 0x03) > 0) |
194 | SizeCheck -= 4; | |
195 | SizeCheck = (SizeCheck + 3) & ~0x03; | |
6112fd6e | 196 | SizeCheck += 12; /* 8 + 4 badbeef */ |
dc7e04fe PE |
197 | if ((BulkLength > 1600) || |
198 | (SizeCheck > 1600) || | |
199 | (BulkLength != SizeCheck) || | |
6112fd6e | 200 | (BulkLength == 0)) { /* Add for fail Urb */ |
66101de1 | 201 | pWb35Rx->EP3vm_state = VM_STOP; |
dc7e04fe | 202 | pWb35Rx->Ep3ErrorCount2++; |
66101de1 | 203 | } |
dc7e04fe | 204 | } |
66101de1 | 205 | |
6112fd6e | 206 | /* Indicating the receiving data */ |
dc7e04fe | 207 | pWb35Rx->ByteReceived += BulkLength; |
6112fd6e | 208 | pWb35Rx->RxBufferSize[RxBufferId] = BulkLength; |
66101de1 | 209 | |
6112fd6e | 210 | if (!pWb35Rx->RxOwner[RxBufferId]) |
7fff1316 | 211 | Wb35Rx_indicate(hw); |
66101de1 | 212 | |
dc7e04fe | 213 | kfree(pWb35Rx->pDRx); |
6112fd6e | 214 | /* Do the next receive */ |
7fff1316 | 215 | Wb35Rx(hw); |
dc7e04fe | 216 | return; |
66101de1 | 217 | |
dc7e04fe | 218 | error: |
6112fd6e | 219 | pWb35Rx->RxOwner[RxBufferId] = 1; /* Set the owner to hardware */ |
44e8541c | 220 | atomic_dec(&pWb35Rx->RxFireCounter); |
66101de1 PM |
221 | pWb35Rx->EP3vm_state = VM_STOP; |
222 | } | |
223 | ||
6112fd6e | 224 | /* This function cannot reentrain */ |
c139a814 | 225 | static void Wb35Rx(struct ieee80211_hw *hw) |
66101de1 | 226 | { |
6112fd6e LL |
227 | struct wbsoft_priv *priv = hw->priv; |
228 | struct hw_data *pHwData = &priv->sHwData; | |
229 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; | |
230 | u8 *pRxBufferAddress; | |
231 | struct urb *urb = pWb35Rx->RxUrb; | |
232 | int retv; | |
233 | u32 RxBufferId; | |
234 | ||
235 | /* Issuing URB */ | |
87cb9a63 | 236 | if (pHwData->SurpriseRemove) |
c139a814 | 237 | goto error; |
66101de1 | 238 | |
c139a814 PE |
239 | if (pWb35Rx->rx_halt) |
240 | goto error; | |
66101de1 | 241 | |
6112fd6e | 242 | /* Get RxBuffer's ID */ |
c139a814 PE |
243 | RxBufferId = pWb35Rx->RxBufferId; |
244 | if (!pWb35Rx->RxOwner[RxBufferId]) { | |
6112fd6e | 245 | /* It's impossible to run here. */ |
2855bb79 | 246 | pr_debug("Rx driver fifo unavailable\n"); |
c139a814 PE |
247 | goto error; |
248 | } | |
249 | ||
6112fd6e | 250 | /* Update buffer point, then start to bulkin the data from USB */ |
c139a814 PE |
251 | pWb35Rx->RxBufferId++; |
252 | pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER; | |
253 | ||
254 | pWb35Rx->CurrentRxBufferId = RxBufferId; | |
255 | ||
256 | pWb35Rx->pDRx = kzalloc(MAX_USB_RX_BUFFER, GFP_ATOMIC); | |
257 | if (!pWb35Rx->pDRx) { | |
258 | printk("w35und: Rx memory alloc failed\n"); | |
259 | goto error; | |
260 | } | |
261 | pRxBufferAddress = pWb35Rx->pDRx; | |
262 | ||
2894c6cd PE |
263 | usb_fill_bulk_urb(urb, pHwData->udev, |
264 | usb_rcvbulkpipe(pHwData->udev, 3), | |
c139a814 PE |
265 | pRxBufferAddress, MAX_USB_RX_BUFFER, |
266 | Wb35Rx_Complete, hw); | |
267 | ||
268 | pWb35Rx->EP3vm_state = VM_RUNNING; | |
269 | ||
270 | retv = usb_submit_urb(urb, GFP_ATOMIC); | |
271 | ||
272 | if (retv != 0) { | |
273 | printk("Rx URB sending error\n"); | |
274 | goto error; | |
66101de1 | 275 | } |
c139a814 PE |
276 | return; |
277 | ||
278 | error: | |
6112fd6e | 279 | /* VM stop */ |
c139a814 PE |
280 | pWb35Rx->EP3vm_state = VM_STOP; |
281 | atomic_dec(&pWb35Rx->RxFireCounter); | |
66101de1 PM |
282 | } |
283 | ||
c139a814 | 284 | void Wb35Rx_start(struct ieee80211_hw *hw) |
66101de1 | 285 | { |
6112fd6e LL |
286 | struct wbsoft_priv *priv = hw->priv; |
287 | struct hw_data *pHwData = &priv->sHwData; | |
288 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; | |
66101de1 | 289 | |
6112fd6e | 290 | /* Allow only one thread to run into the Wb35Rx() function */ |
c139a814 PE |
291 | if (atomic_inc_return(&pWb35Rx->RxFireCounter) == 1) { |
292 | pWb35Rx->EP3vm_state = VM_RUNNING; | |
293 | Wb35Rx(hw); | |
294 | } else | |
295 | atomic_dec(&pWb35Rx->RxFireCounter); | |
66101de1 PM |
296 | } |
297 | ||
6112fd6e | 298 | static void Wb35Rx_reset_descriptor(struct hw_data *pHwData) |
66101de1 | 299 | { |
6112fd6e LL |
300 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
301 | u32 i; | |
66101de1 PM |
302 | |
303 | pWb35Rx->ByteReceived = 0; | |
304 | pWb35Rx->RxProcessIndex = 0; | |
305 | pWb35Rx->RxBufferId = 0; | |
306 | pWb35Rx->EP3vm_state = VM_STOP; | |
307 | pWb35Rx->rx_halt = 0; | |
308 | ||
6112fd6e LL |
309 | /* Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable. */ |
310 | for (i = 0; i < MAX_USB_RX_BUFFER_NUMBER; i++) | |
66101de1 PM |
311 | pWb35Rx->RxOwner[i] = 1; |
312 | } | |
313 | ||
6112fd6e | 314 | unsigned char Wb35Rx_initial(struct hw_data *pHwData) |
66101de1 | 315 | { |
eb62f3ea | 316 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
66101de1 | 317 | |
6112fd6e LL |
318 | /* Initial the Buffer Queue */ |
319 | Wb35Rx_reset_descriptor(pHwData); | |
66101de1 | 320 | |
c139a814 | 321 | pWb35Rx->RxUrb = usb_alloc_urb(0, GFP_ATOMIC); |
6112fd6e | 322 | return !!pWb35Rx->RxUrb; |
66101de1 PM |
323 | } |
324 | ||
6112fd6e | 325 | void Wb35Rx_stop(struct hw_data *pHwData) |
3cae503b | 326 | { |
eb62f3ea | 327 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
3cae503b | 328 | |
6112fd6e | 329 | /* Canceling the Irp if already sends it out. */ |
c139a814 | 330 | if (pWb35Rx->EP3vm_state == VM_RUNNING) { |
6112fd6e | 331 | usb_unlink_urb(pWb35Rx->RxUrb); /* Only use unlink, let Wb35Rx_destroy to free them */ |
2855bb79 | 332 | pr_debug("EP3 Rx stop\n"); |
3cae503b | 333 | } |
3cae503b | 334 | } |
66101de1 | 335 | |
6112fd6e LL |
336 | /* Needs process context */ |
337 | void Wb35Rx_destroy(struct hw_data *pHwData) | |
66101de1 | 338 | { |
eb62f3ea | 339 | struct wb35_rx *pWb35Rx = &pHwData->Wb35Rx; |
66101de1 | 340 | |
66101de1 | 341 | do { |
6112fd6e | 342 | msleep(10); /* Delay for waiting function enter */ |
c139a814 | 343 | } while (pWb35Rx->EP3vm_state != VM_STOP); |
6112fd6e | 344 | msleep(10); /* Delay for waiting function exit */ |
66101de1 | 345 | |
b5153e97 | 346 | usb_free_urb(pWb35Rx->RxUrb); |
2855bb79 | 347 | pr_debug("Wb35Rx_destroy OK\n"); |
66101de1 PM |
348 | } |
349 |