]>
Commit | Line | Data |
---|---|---|
f7c92d2c LF |
1 | /****************************************************************************** |
2 | * | |
3 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | ******************************************************************************/ | |
15 | #define _HCI_OPS_OS_C_ | |
16 | ||
17 | #include <osdep_service.h> | |
18 | #include <drv_types.h> | |
19 | #include <osdep_intf.h> | |
20 | #include <usb_ops.h> | |
21 | #include <recv_osdep.h> | |
22 | #include <rtl8723a_hal.h> | |
23 | #include <rtl8723a_recv.h> | |
24 | ||
2786faa3 | 25 | u8 rtl8723au_read8(struct rtw_adapter *padapter, u16 addr) |
f7c92d2c | 26 | { |
f7c92d2c LF |
27 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
28 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
2786faa3 JS |
29 | int len; |
30 | u8 data; | |
f7c92d2c LF |
31 | |
32 | mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); | |
2786faa3 JS |
33 | len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), |
34 | REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ, | |
35 | addr, 0, &pdvobjpriv->usb_buf.val8, sizeof(data), | |
36 | RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 37 | |
2786faa3 | 38 | data = pdvobjpriv->usb_buf.val8; |
f7c92d2c | 39 | mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); |
f7c92d2c LF |
40 | |
41 | return data; | |
42 | } | |
43 | ||
2786faa3 | 44 | u16 rtl8723au_read16(struct rtw_adapter *padapter, u16 addr) |
f7c92d2c | 45 | { |
2786faa3 JS |
46 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
47 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
48 | int len; | |
49 | u16 data; | |
f7c92d2c | 50 | |
2786faa3 JS |
51 | mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); |
52 | len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | |
53 | REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ, | |
54 | addr, 0, &pdvobjpriv->usb_buf.val16, sizeof(data), | |
55 | RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 56 | |
2786faa3 JS |
57 | data = le16_to_cpu(pdvobjpriv->usb_buf.val16); |
58 | mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); | |
f7c92d2c | 59 | |
2786faa3 | 60 | return data; |
f7c92d2c LF |
61 | } |
62 | ||
2786faa3 | 63 | u32 rtl8723au_read32(struct rtw_adapter *padapter, u16 addr) |
f7c92d2c | 64 | { |
2786faa3 JS |
65 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
66 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
67 | int len; | |
68 | u32 data; | |
f7c92d2c | 69 | |
2786faa3 JS |
70 | mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); |
71 | len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | |
72 | REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ, | |
73 | addr, 0, &pdvobjpriv->usb_buf.val32, sizeof(data), | |
74 | RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 75 | |
2786faa3 JS |
76 | data = le32_to_cpu(pdvobjpriv->usb_buf.val32); |
77 | mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); | |
f7c92d2c | 78 | |
2786faa3 | 79 | return data; |
f7c92d2c LF |
80 | } |
81 | ||
2786faa3 | 82 | int rtl8723au_write8(struct rtw_adapter *padapter, u16 addr, u8 val) |
f7c92d2c | 83 | { |
2786faa3 JS |
84 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
85 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
f7c92d2c LF |
86 | int ret; |
87 | ||
2786faa3 JS |
88 | mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); |
89 | pdvobjpriv->usb_buf.val8 = val; | |
f7c92d2c | 90 | |
2786faa3 JS |
91 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
92 | REALTEK_USB_VENQT_CMD_REQ, | |
93 | REALTEK_USB_VENQT_WRITE, | |
94 | addr, 0, &pdvobjpriv->usb_buf.val8, sizeof(val), | |
95 | RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 96 | |
2786faa3 JS |
97 | if (ret != sizeof(val)) |
98 | ret = _FAIL; | |
99 | else | |
100 | ret = _SUCCESS; | |
f7c92d2c | 101 | |
2786faa3 | 102 | mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); |
f7c92d2c LF |
103 | return ret; |
104 | } | |
105 | ||
2786faa3 | 106 | int rtl8723au_write16(struct rtw_adapter *padapter, u16 addr, u16 val) |
f7c92d2c | 107 | { |
2786faa3 JS |
108 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
109 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
f7c92d2c LF |
110 | int ret; |
111 | ||
2786faa3 JS |
112 | mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); |
113 | pdvobjpriv->usb_buf.val16 = cpu_to_le16(val); | |
f7c92d2c | 114 | |
2786faa3 JS |
115 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
116 | REALTEK_USB_VENQT_CMD_REQ, | |
117 | REALTEK_USB_VENQT_WRITE, | |
118 | addr, 0, &pdvobjpriv->usb_buf.val16, sizeof(val), | |
119 | RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 120 | |
2786faa3 JS |
121 | if (ret != sizeof(val)) |
122 | ret = _FAIL; | |
123 | else | |
124 | ret = _SUCCESS; | |
f7c92d2c | 125 | |
2786faa3 | 126 | mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); |
f7c92d2c LF |
127 | return ret; |
128 | } | |
129 | ||
2786faa3 | 130 | int rtl8723au_write32(struct rtw_adapter *padapter, u16 addr, u32 val) |
f7c92d2c | 131 | { |
2786faa3 JS |
132 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
133 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
f7c92d2c LF |
134 | int ret; |
135 | ||
2786faa3 JS |
136 | mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); |
137 | pdvobjpriv->usb_buf.val32 = cpu_to_le32(val); | |
f7c92d2c | 138 | |
2786faa3 JS |
139 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
140 | REALTEK_USB_VENQT_CMD_REQ, | |
141 | REALTEK_USB_VENQT_WRITE, | |
142 | addr, 0, &pdvobjpriv->usb_buf.val32, sizeof(val), | |
143 | RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 144 | |
2786faa3 JS |
145 | if (ret != sizeof(val)) |
146 | ret = _FAIL; | |
147 | else | |
148 | ret = _SUCCESS; | |
f7c92d2c | 149 | |
2786faa3 | 150 | mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); |
f7c92d2c LF |
151 | return ret; |
152 | } | |
153 | ||
2786faa3 | 154 | int rtl8723au_writeN(struct rtw_adapter *padapter, u16 addr, u16 len, u8 *buf) |
f7c92d2c | 155 | { |
2786faa3 JS |
156 | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); |
157 | struct usb_device *udev = pdvobjpriv->pusbdev; | |
f7c92d2c LF |
158 | int ret; |
159 | ||
2786faa3 JS |
160 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), |
161 | REALTEK_USB_VENQT_CMD_REQ, | |
162 | REALTEK_USB_VENQT_WRITE, | |
163 | addr, 0, buf, len, RTW_USB_CONTROL_MSG_TIMEOUT); | |
f7c92d2c | 164 | |
2786faa3 JS |
165 | if (ret != len) |
166 | return _FAIL; | |
167 | return _SUCCESS; | |
f7c92d2c LF |
168 | } |
169 | ||
170 | /* | |
171 | * Description: | |
172 | * Recognize the interrupt content by reading the interrupt | |
173 | * register or content and masking interrupt mask (IMR) | |
174 | * if it is our NIC's interrupt. After recognizing, we may clear | |
175 | * the all interrupts (ISR). | |
176 | * Arguments: | |
177 | * [in] Adapter - | |
178 | * The adapter context. | |
179 | * [in] pContent - | |
180 | * Under PCI interface, this field is ignord. | |
181 | * Under USB interface, the content is the interrupt | |
182 | * content pointer. | |
183 | * Under SDIO interface, this is the interrupt type which | |
184 | * is Local interrupt or system interrupt. | |
185 | * [in] ContentLen - | |
186 | * The length in byte of pContent. | |
187 | * Return: | |
188 | * If any interrupt matches the mask (IMR), return true, and | |
189 | * return false otherwise. | |
190 | */ | |
191 | static bool | |
192 | InterruptRecognized8723AU(struct rtw_adapter *Adapter, void *pContent, | |
193 | u32 ContentLen) | |
194 | { | |
195 | struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); | |
196 | u8 *buffer = (u8 *)pContent; | |
197 | struct reportpwrstate_parm report; | |
198 | ||
199 | memcpy(&pHalData->IntArray[0], &buffer[USB_INTR_CONTENT_HISR_OFFSET], | |
200 | 4); | |
201 | pHalData->IntArray[0] &= pHalData->IntrMask[0]; | |
202 | ||
203 | /* For HISR extension. Added by tynli. 2009.10.07. */ | |
204 | memcpy(&pHalData->IntArray[1], | |
205 | &buffer[USB_INTR_CONTENT_HISRE_OFFSET], 4); | |
206 | pHalData->IntArray[1] &= pHalData->IntrMask[1]; | |
207 | ||
208 | /* We sholud remove this function later because DDK suggest | |
209 | * not to executing too many operations in MPISR */ | |
210 | ||
211 | memcpy(&report.state, &buffer[USB_INTR_CPWM_OFFSET], 1); | |
212 | ||
7438ccb9 JS |
213 | return (pHalData->IntArray[0] & pHalData->IntrMask[0]) != 0 || |
214 | (pHalData->IntArray[1] & pHalData->IntrMask[1]) != 0; | |
f7c92d2c LF |
215 | } |
216 | ||
2296fd2d | 217 | static void usb_read_interrupt_complete(struct urb *purb) |
f7c92d2c LF |
218 | { |
219 | int err; | |
220 | struct rtw_adapter *padapter = (struct rtw_adapter *)purb->context; | |
221 | ||
222 | if (padapter->bSurpriseRemoved || padapter->bDriverStopped || | |
223 | padapter->bReadPortCancel) { | |
224 | DBG_8723A("%s() RX Warning! bDriverStopped(%d) OR " | |
225 | "bSurpriseRemoved(%d) bReadPortCancel(%d)\n", | |
f8628a47 | 226 | __func__, padapter->bDriverStopped, |
f7c92d2c LF |
227 | padapter->bSurpriseRemoved, |
228 | padapter->bReadPortCancel); | |
229 | return; | |
230 | } | |
231 | ||
232 | if (purb->status == 0) { | |
233 | struct c2h_evt_hdr *c2h_evt; | |
234 | ||
235 | c2h_evt = (struct c2h_evt_hdr *)purb->transfer_buffer; | |
236 | ||
237 | if (purb->actual_length > USB_INTR_CONTENT_LENGTH) { | |
238 | DBG_8723A("usb_read_interrupt_complete: purb->actual_" | |
239 | "length > USB_INTR_CONTENT_LENGTH\n"); | |
240 | goto urb_submit; | |
241 | } | |
242 | ||
243 | InterruptRecognized8723AU(padapter, purb->transfer_buffer, | |
244 | purb->actual_length); | |
245 | ||
246 | if (c2h_evt_exist(c2h_evt)) { | |
247 | if (c2h_id_filter_ccx_8723a(c2h_evt->id)) { | |
248 | /* Handle CCX report here */ | |
7438ccb9 JS |
249 | handle_txrpt_ccx_8723a(padapter, (void *) |
250 | c2h_evt->payload); | |
980cf72a | 251 | schedule_work(&padapter->evtpriv.irq_wk); |
f7c92d2c | 252 | } else { |
980cf72a JS |
253 | struct evt_work *c2w; |
254 | int res; | |
255 | ||
f9de4a30 | 256 | c2w = kmalloc(sizeof(struct evt_work), |
980cf72a JS |
257 | GFP_ATOMIC); |
258 | ||
259 | if (!c2w) { | |
260 | printk(KERN_WARNING "%s: unable to " | |
261 | "allocate work buffer\n", | |
262 | __func__); | |
263 | goto urb_submit; | |
264 | } | |
265 | ||
266 | c2w->adapter = padapter; | |
267 | INIT_WORK(&c2w->work, rtw_evt_work); | |
268 | memcpy(c2w->u.buf, purb->transfer_buffer, 16); | |
269 | ||
270 | res = queue_work(padapter->evtpriv.wq, | |
271 | &c2w->work); | |
272 | ||
273 | if (!res) { | |
274 | printk(KERN_ERR "%s: Call to " | |
275 | "queue_work() failed\n", | |
276 | __func__); | |
277 | kfree(c2w); | |
278 | goto urb_submit; | |
279 | } | |
f7c92d2c LF |
280 | } |
281 | } | |
282 | ||
283 | urb_submit: | |
284 | err = usb_submit_urb(purb, GFP_ATOMIC); | |
285 | if (err && (err != -EPERM)) { | |
286 | DBG_8723A("cannot submit interrupt in-token(err = " | |
287 | "0x%08x), urb_status = %d\n", | |
288 | err, purb->status); | |
289 | } | |
290 | } else { | |
291 | DBG_8723A("###=> usb_read_interrupt_complete => urb " | |
292 | "status(%d)\n", purb->status); | |
293 | ||
294 | switch (purb->status) { | |
295 | case -EINVAL: | |
296 | case -EPIPE: | |
297 | case -ENODEV: | |
298 | case -ESHUTDOWN: | |
299 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 | 300 | "usb_read_port_complete:bSurpriseRemoved =true\n"); |
f7c92d2c LF |
301 | /* Fall Through here */ |
302 | case -ENOENT: | |
303 | padapter->bDriverStopped = true; | |
304 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 | 305 | "usb_read_port_complete:bDriverStopped =true\n"); |
f7c92d2c LF |
306 | break; |
307 | case -EPROTO: | |
308 | break; | |
309 | case -EINPROGRESS: | |
48039e70 | 310 | DBG_8723A("ERROR: URB IS IN PROGRESS!\n"); |
f7c92d2c LF |
311 | break; |
312 | default: | |
313 | break; | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
c6419a6d | 318 | int rtl8723au_read_interrupt(struct rtw_adapter *adapter) |
f7c92d2c LF |
319 | { |
320 | int err; | |
321 | unsigned int pipe; | |
ad899b12 | 322 | int ret = _SUCCESS; |
f7c92d2c LF |
323 | struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); |
324 | struct recv_priv *precvpriv = &adapter->recvpriv; | |
325 | struct usb_device *pusbd = pdvobj->pusbdev; | |
326 | ||
327 | /* translate DMA FIFO addr to pipehandle */ | |
97ccc3a6 | 328 | pipe = usb_rcvintpipe(pusbd, pdvobj->RtInPipe[1]); |
f7c92d2c LF |
329 | |
330 | usb_fill_int_urb(precvpriv->int_in_urb, pusbd, pipe, | |
331 | precvpriv->int_in_buf, USB_INTR_CONTENT_LENGTH, | |
332 | usb_read_interrupt_complete, adapter, 1); | |
333 | ||
334 | err = usb_submit_urb(precvpriv->int_in_urb, GFP_ATOMIC); | |
335 | if (err && (err != -EPERM)) { | |
336 | DBG_8723A("cannot submit interrupt in-token(err = 0x%08x)," | |
337 | "urb_status = %d\n", err, | |
338 | precvpriv->int_in_urb->status); | |
339 | ret = _FAIL; | |
340 | } | |
341 | ||
342 | return ret; | |
343 | } | |
344 | ||
345 | static int recvbuf2recvframe(struct rtw_adapter *padapter, struct sk_buff *pskb) | |
346 | { | |
347 | u8 *pbuf; | |
348 | u8 shift_sz = 0; | |
349 | u16 pkt_cnt; | |
350 | u32 pkt_offset, skb_len, alloc_sz; | |
7438ccb9 JS |
351 | int transfer_len; |
352 | struct recv_stat *prxstat; | |
353 | struct phy_stat *pphy_info; | |
354 | struct sk_buff *pkt_copy; | |
355 | struct recv_frame *precvframe; | |
356 | struct rx_pkt_attrib *pattrib; | |
357 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
358 | struct rtw_queue *pfree_recv_queue = &precvpriv->free_recv_queue; | |
359 | ||
360 | transfer_len = (int)pskb->len; | |
f7c92d2c LF |
361 | pbuf = pskb->data; |
362 | ||
363 | prxstat = (struct recv_stat *)pbuf; | |
364 | pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff; | |
365 | ||
366 | do { | |
367 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, | |
90403aa1 JP |
368 | "recvbuf2recvframe: rxdesc = offsset 0:0x%08x, 4:0x%08x, 8:0x%08x, C:0x%08x\n", |
369 | prxstat->rxdw0, prxstat->rxdw1, | |
370 | prxstat->rxdw2, prxstat->rxdw4); | |
f7c92d2c LF |
371 | |
372 | prxstat = (struct recv_stat *)pbuf; | |
373 | ||
374 | precvframe = rtw_alloc_recvframe23a(pfree_recv_queue); | |
375 | if (!precvframe) { | |
376 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, | |
90403aa1 | 377 | "recvbuf2recvframe: precvframe == NULL\n"); |
f7c92d2c | 378 | DBG_8723A("%s()-%d: rtw_alloc_recvframe23a() failed! RX " |
f8628a47 | 379 | "Drop!\n", __func__, __LINE__); |
f7c92d2c LF |
380 | goto _exit_recvbuf2recvframe; |
381 | } | |
382 | ||
383 | INIT_LIST_HEAD(&precvframe->list); | |
384 | ||
385 | update_recvframe_attrib(precvframe, prxstat); | |
386 | ||
387 | pattrib = &precvframe->attrib; | |
388 | ||
389 | if (pattrib->crc_err) { | |
390 | DBG_8723A("%s()-%d: RX Warning! rx CRC ERROR !!\n", | |
f8628a47 | 391 | __func__, __LINE__); |
c5779a0d | 392 | rtw_free_recvframe23a(precvframe); |
f7c92d2c LF |
393 | goto _exit_recvbuf2recvframe; |
394 | } | |
395 | ||
396 | pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + | |
397 | pattrib->shift_sz + pattrib->pkt_len; | |
398 | ||
7438ccb9 | 399 | if (pattrib->pkt_len <= 0 || pkt_offset > transfer_len) { |
f7c92d2c | 400 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, |
90403aa1 | 401 | "recvbuf2recvframe: pkt_len<= 0\n"); |
f7c92d2c | 402 | DBG_8723A("%s()-%d: RX Warning!\n", |
f8628a47 | 403 | __func__, __LINE__); |
c5779a0d | 404 | rtw_free_recvframe23a(precvframe); |
f7c92d2c LF |
405 | goto _exit_recvbuf2recvframe; |
406 | } | |
407 | ||
408 | /* Modified by Albert 20101213 */ | |
409 | /* For 8 bytes IP header alignment. */ | |
410 | /* Qos data, wireless lan header length is 26 */ | |
7438ccb9 | 411 | if (pattrib->qos) |
f7c92d2c | 412 | shift_sz = 6; |
7438ccb9 | 413 | else |
f7c92d2c | 414 | shift_sz = 0; |
f7c92d2c LF |
415 | |
416 | skb_len = pattrib->pkt_len; | |
417 | ||
418 | /* for first fragment packet, driver need allocate | |
419 | * 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. | |
420 | * modify alloc_sz for recvive crc error packet | |
421 | * by thomas 2011-06-02 */ | |
7438ccb9 | 422 | if (pattrib->mfrag == 1 && pattrib->frag_num == 0) { |
f7c92d2c LF |
423 | /* alloc_sz = 1664; 1664 is 128 alignment. */ |
424 | if (skb_len <= 1650) | |
425 | alloc_sz = 1664; | |
426 | else | |
427 | alloc_sz = skb_len + 14; | |
428 | } else { | |
429 | alloc_sz = skb_len; | |
430 | /* 6 is for IP header 8 bytes alignment in QoS packet case. */ | |
431 | /* 8 is for skb->data 4 bytes alignment. */ | |
432 | alloc_sz += 14; | |
433 | } | |
434 | ||
435 | pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz); | |
436 | if (pkt_copy) { | |
437 | pkt_copy->dev = padapter->pnetdev; | |
438 | precvframe->pkt = pkt_copy; | |
7438ccb9 JS |
439 | /* force pkt_copy->data at 8-byte alignment address */ |
440 | skb_reserve(pkt_copy, 8 - | |
441 | ((unsigned long)(pkt_copy->data) & 7)); | |
442 | /*force ip_hdr at 8-byte alignment address | |
443 | according to shift_sz. */ | |
f7c92d2c | 444 | skb_reserve(pkt_copy, shift_sz); |
7438ccb9 JS |
445 | memcpy(pkt_copy->data, pbuf + pattrib->shift_sz + |
446 | pattrib->drvinfo_sz + RXDESC_SIZE, skb_len); | |
f7c92d2c LF |
447 | skb_put(pkt_copy, skb_len); |
448 | } else { | |
7438ccb9 | 449 | if (pattrib->mfrag == 1 && pattrib->frag_num == 0) { |
f7c92d2c LF |
450 | DBG_8723A("recvbuf2recvframe: alloc_skb fail, " |
451 | "drop frag frame \n"); | |
c5779a0d | 452 | rtw_free_recvframe23a(precvframe); |
f7c92d2c LF |
453 | goto _exit_recvbuf2recvframe; |
454 | } | |
455 | ||
456 | precvframe->pkt = skb_clone(pskb, GFP_ATOMIC); | |
457 | if (!precvframe->pkt) { | |
458 | DBG_8723A("recvbuf2recvframe: skb_clone " | |
459 | "fail\n"); | |
c5779a0d | 460 | rtw_free_recvframe23a(precvframe); |
f7c92d2c LF |
461 | goto _exit_recvbuf2recvframe; |
462 | } | |
463 | } | |
464 | ||
465 | if (pattrib->physt) { | |
466 | pphy_info = (struct phy_stat *)(pbuf + RXDESC_OFFSET); | |
467 | update_recvframe_phyinfo(precvframe, pphy_info); | |
468 | } | |
469 | ||
470 | if (rtw_recv_entry23a(precvframe) != _SUCCESS) | |
471 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, | |
90403aa1 | 472 | "recvbuf2recvframe: rtw_recv_entry23a(precvframe) != _SUCCESS\n"); |
f7c92d2c LF |
473 | |
474 | pkt_cnt--; | |
475 | transfer_len -= pkt_offset; | |
476 | pbuf += pkt_offset; | |
477 | precvframe = NULL; | |
478 | pkt_copy = NULL; | |
479 | ||
480 | if (transfer_len > 0 && pkt_cnt == 0) | |
481 | pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; | |
482 | ||
7438ccb9 | 483 | } while (transfer_len > 0 && pkt_cnt > 0); |
f7c92d2c LF |
484 | |
485 | _exit_recvbuf2recvframe: | |
486 | ||
487 | return _SUCCESS; | |
488 | } | |
489 | ||
490 | void rtl8723au_recv_tasklet(void *priv) | |
491 | { | |
492 | struct sk_buff *pskb; | |
493 | struct rtw_adapter *padapter = (struct rtw_adapter *)priv; | |
494 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
495 | ||
496 | while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) { | |
7438ccb9 | 497 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { |
f7c92d2c LF |
498 | DBG_8723A("recv_tasklet => bDriverStopped or " |
499 | "bSurpriseRemoved \n"); | |
500 | dev_kfree_skb_any(pskb); | |
501 | break; | |
502 | } | |
503 | ||
504 | recvbuf2recvframe(padapter, pskb); | |
505 | skb_reset_tail_pointer(pskb); | |
506 | ||
507 | pskb->len = 0; | |
508 | ||
509 | skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); | |
510 | } | |
511 | } | |
512 | ||
2296fd2d | 513 | static void usb_read_port_complete(struct urb *purb) |
f7c92d2c LF |
514 | { |
515 | struct recv_buf *precvbuf = (struct recv_buf *)purb->context; | |
516 | struct rtw_adapter *padapter = (struct rtw_adapter *)precvbuf->adapter; | |
517 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
f7c92d2c LF |
518 | |
519 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 | 520 | "usb_read_port_complete!!!\n"); |
f7c92d2c LF |
521 | |
522 | precvpriv->rx_pending_cnt--; | |
523 | ||
524 | if (padapter->bSurpriseRemoved || padapter->bDriverStopped || | |
525 | padapter->bReadPortCancel) { | |
526 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 JP |
527 | "usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n", |
528 | padapter->bDriverStopped, padapter->bSurpriseRemoved); | |
f7c92d2c LF |
529 | |
530 | DBG_8723A("%s()-%d: RX Warning! bDriverStopped(%d) OR " | |
531 | "bSurpriseRemoved(%d) bReadPortCancel(%d)\n", | |
f8628a47 | 532 | __func__, __LINE__, padapter->bDriverStopped, |
f7c92d2c LF |
533 | padapter->bSurpriseRemoved, padapter->bReadPortCancel); |
534 | return; | |
535 | } | |
536 | ||
537 | if (purb->status == 0) { | |
7438ccb9 JS |
538 | if (purb->actual_length > MAX_RECVBUF_SZ || |
539 | purb->actual_length < RXDESC_SIZE) { | |
f7c92d2c | 540 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, |
90403aa1 | 541 | "usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n"); |
b1f43bd3 | 542 | rtl8723au_read_port(padapter, 0, precvbuf); |
f7c92d2c | 543 | DBG_8723A("%s()-%d: RX Warning!\n", |
f8628a47 | 544 | __func__, __LINE__); |
f7c92d2c LF |
545 | } else { |
546 | rtw_reset_continual_urb_error( | |
547 | adapter_to_dvobj(padapter)); | |
548 | ||
549 | skb_put(precvbuf->pskb, purb->actual_length); | |
550 | skb_queue_tail(&precvpriv->rx_skb_queue, | |
551 | precvbuf->pskb); | |
552 | ||
553 | if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1) | |
554 | tasklet_schedule(&precvpriv->recv_tasklet); | |
555 | ||
556 | precvbuf->pskb = NULL; | |
b1f43bd3 | 557 | rtl8723au_read_port(padapter, 0, precvbuf); |
f7c92d2c LF |
558 | } |
559 | } else { | |
560 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 JP |
561 | "usb_read_port_complete : purb->status(%d) != 0\n", |
562 | purb->status); | |
f7c92d2c LF |
563 | skb_put(precvbuf->pskb, purb->actual_length); |
564 | precvbuf->pskb = NULL; | |
565 | ||
566 | DBG_8723A("###=> usb_read_port_complete => urb status(%d)\n", | |
567 | purb->status); | |
568 | ||
569 | if (rtw_inc_and_chk_continual_urb_error( | |
570 | adapter_to_dvobj(padapter))) { | |
571 | padapter->bSurpriseRemoved = true; | |
572 | } | |
573 | ||
574 | switch (purb->status) { | |
575 | case -EINVAL: | |
576 | case -EPIPE: | |
577 | case -ENODEV: | |
578 | case -ESHUTDOWN: | |
579 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 | 580 | "usb_read_port_complete:bSurpriseRemoved = true\n"); |
f7c92d2c LF |
581 | /* Intentional fall through here */ |
582 | case -ENOENT: | |
583 | padapter->bDriverStopped = true; | |
584 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 | 585 | "usb_read_port_complete:bDriverStopped = true\n"); |
f7c92d2c LF |
586 | break; |
587 | case -EPROTO: | |
588 | case -EOVERFLOW: | |
b1f43bd3 | 589 | rtl8723au_read_port(padapter, 0, precvbuf); |
f7c92d2c LF |
590 | break; |
591 | case -EINPROGRESS: | |
48039e70 | 592 | DBG_8723A("ERROR: URB IS IN PROGRESS!\n"); |
f7c92d2c LF |
593 | break; |
594 | default: | |
595 | break; | |
596 | } | |
f7c92d2c LF |
597 | } |
598 | } | |
599 | ||
b1f43bd3 | 600 | int rtl8723au_read_port(struct rtw_adapter *adapter, u32 cnt, |
68552a90 | 601 | struct recv_buf *precvbuf) |
f7c92d2c | 602 | { |
b1f43bd3 JS |
603 | struct urb *purb; |
604 | struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); | |
605 | struct recv_priv *precvpriv = &adapter->recvpriv; | |
606 | struct usb_device *pusbd = pdvobj->pusbdev; | |
f7c92d2c LF |
607 | int err; |
608 | unsigned int pipe; | |
7438ccb9 JS |
609 | unsigned long tmpaddr; |
610 | unsigned long alignment; | |
ad899b12 | 611 | int ret = _SUCCESS; |
f7c92d2c | 612 | |
e976cf6f | 613 | if (adapter->bDriverStopped || adapter->bSurpriseRemoved) { |
f7c92d2c | 614 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, |
90403aa1 | 615 | "usb_read_port:(padapter->bDriverStopped ||padapter->bSurpriseRemoved)!!!\n"); |
f7c92d2c LF |
616 | return _FAIL; |
617 | } | |
618 | ||
619 | if (!precvbuf) { | |
620 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 | 621 | "usb_read_port:precvbuf == NULL\n"); |
f7c92d2c LF |
622 | return _FAIL; |
623 | } | |
624 | ||
625 | if (!precvbuf->pskb) | |
626 | precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); | |
627 | ||
f7c92d2c LF |
628 | /* re-assign for linux based on skb */ |
629 | if (!precvbuf->pskb) { | |
630 | precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); | |
631 | if (precvbuf->pskb == NULL) { | |
90403aa1 JP |
632 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, |
633 | "init_recvbuf(): alloc_skb fail!\n"); | |
f7c92d2c LF |
634 | return _FAIL; |
635 | } | |
636 | ||
637 | tmpaddr = (unsigned long)precvbuf->pskb->data; | |
638 | alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); | |
639 | skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); | |
640 | } | |
641 | ||
642 | precvpriv->rx_pending_cnt++; | |
643 | ||
644 | purb = precvbuf->purb; | |
645 | ||
646 | /* translate DMA FIFO addr to pipehandle */ | |
97ccc3a6 | 647 | pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); |
f7c92d2c LF |
648 | |
649 | usb_fill_bulk_urb(purb, pusbd, pipe, precvbuf->pskb->data, | |
650 | MAX_RECVBUF_SZ, usb_read_port_complete, | |
651 | precvbuf);/* context is precvbuf */ | |
652 | ||
653 | err = usb_submit_urb(purb, GFP_ATOMIC); | |
654 | if ((err) && (err != -EPERM)) { | |
655 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, | |
90403aa1 JP |
656 | "cannot submit rx in-token(err = 0x%.8x), URB_STATUS = 0x%.8x\n", |
657 | err, purb->status); | |
f7c92d2c LF |
658 | DBG_8723A("cannot submit rx in-token(err = 0x%08x), urb_status " |
659 | "= %d\n", err, purb->status); | |
660 | ret = _FAIL; | |
661 | } | |
662 | return ret; | |
663 | } | |
664 | ||
665 | void rtl8723au_xmit_tasklet(void *priv) | |
666 | { | |
24ed8e45 | 667 | int ret; |
f7c92d2c LF |
668 | struct rtw_adapter *padapter = (struct rtw_adapter *)priv; |
669 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
670 | ||
671 | if (check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY)) | |
672 | return; | |
673 | ||
674 | while (1) { | |
7438ccb9 JS |
675 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved || |
676 | padapter->bWritePortCancel) { | |
f7c92d2c LF |
677 | DBG_8723A("xmit_tasklet => bDriverStopped or " |
678 | "bSurpriseRemoved or bWritePortCancel\n"); | |
679 | break; | |
680 | } | |
681 | ||
682 | ret = rtl8723au_xmitframe_complete(padapter, pxmitpriv, NULL); | |
683 | ||
684 | if (!ret) | |
685 | break; | |
686 | } | |
687 | } | |
688 | ||
f7c92d2c LF |
689 | void rtl8723au_set_hw_type(struct rtw_adapter *padapter) |
690 | { | |
691 | padapter->chip_type = RTL8723A; | |
692 | padapter->HardwareType = HARDWARE_TYPE_RTL8723AU; | |
693 | DBG_8723A("CHIP TYPE: RTL8723A\n"); | |
694 | } |