1 /******************************************************************************
2 *
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
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 _HAL_USB_C_
16
17 #include <drv_types.h>
18 #include <hal_data.h>
19
usb_init_recv_priv(_adapter * padapter,u16 ini_in_buf_sz)20 int usb_init_recv_priv(_adapter *padapter, u16 ini_in_buf_sz)
21 {
22 struct registry_priv *regsty = adapter_to_regsty(padapter);
23 struct recv_priv *precvpriv = &padapter->recvpriv;
24 int i, res = _SUCCESS;
25 struct recv_buf *precvbuf;
26
27 #ifdef PLATFORM_LINUX
28 tasklet_init(&precvpriv->recv_tasklet,
29 (void(*)(unsigned long))usb_recv_tasklet,
30 (unsigned long)padapter);
31 #endif /* PLATFORM_LINUX */
32
33 #ifdef PLATFORM_FREEBSD
34 #ifdef CONFIG_RX_INDICATE_QUEUE
35 TASK_INIT(&precvpriv->rx_indicate_tasklet, 0, rtw_rx_indicate_tasklet, padapter);
36 #endif /* CONFIG_RX_INDICATE_QUEUE */
37 #endif /* PLATFORM_FREEBSD */
38
39 #ifdef CONFIG_USB_INTERRUPT_IN_PIPE
40 #ifdef PLATFORM_LINUX
41 precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
42 if (precvpriv->int_in_urb == NULL) {
43 res = _FAIL;
44 RTW_INFO("alloc_urb for interrupt in endpoint fail !!!!\n");
45 goto exit;
46 }
47 #endif /* PLATFORM_LINUX */
48 precvpriv->int_in_buf = rtw_zmalloc(ini_in_buf_sz);
49 if (precvpriv->int_in_buf == NULL) {
50 res = _FAIL;
51 RTW_INFO("alloc_mem for interrupt in endpoint fail !!!!\n");
52 goto exit;
53 }
54 #endif /* CONFIG_USB_INTERRUPT_IN_PIPE */
55
56 /* init recv_buf */
57 _rtw_init_queue(&precvpriv->free_recv_buf_queue);
58 _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
59 #ifndef CONFIG_USE_USB_BUFFER_ALLOC_RX
60 /* this is used only when RX_IOBUF is sk_buff */
61 skb_queue_head_init(&precvpriv->free_recv_skb_queue);
62 #endif
63
64 RTW_INFO("NR_RECVBUFF: %d, recvbuf_nr: %d\n", NR_RECVBUFF, regsty->recvbuf_nr);
65 RTW_INFO("MAX_RECVBUF_SZ: %d\n", MAX_RECVBUF_SZ);
66 precvpriv->pallocated_recv_buf = rtw_zmalloc(regsty->recvbuf_nr * sizeof(struct recv_buf) + 4);
67 if (precvpriv->pallocated_recv_buf == NULL) {
68 res = _FAIL;
69 goto exit;
70 }
71
72 precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
73
74 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
75
76 for (i = 0; i < regsty->recvbuf_nr ; i++) {
77 _rtw_init_listhead(&precvbuf->list);
78
79 #ifdef PLATFORM_WINDOWS
80 _rtw_spinlock_init(&precvbuf->recvbuf_lock);
81 #endif
82
83 precvbuf->alloc_sz = MAX_RECVBUF_SZ;
84
85 res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf, precvbuf->alloc_sz);
86 if (res == _FAIL)
87 break;
88
89 precvbuf->ref_cnt = 0;
90 precvbuf->adapter = padapter;
91
92 /* rtw_list_insert_tail(&precvbuf->list, &(precvpriv->free_recv_buf_queue.queue)); */
93
94 precvbuf++;
95 }
96
97 precvpriv->free_recv_buf_queue_cnt = regsty->recvbuf_nr;
98
99 #if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD)
100
101 skb_queue_head_init(&precvpriv->rx_skb_queue);
102
103 #ifdef CONFIG_RX_INDICATE_QUEUE
104 memset(&precvpriv->rx_indicate_queue, 0, sizeof(struct ifqueue));
105 mtx_init(&precvpriv->rx_indicate_queue.ifq_mtx, "rx_indicate_queue", NULL, MTX_DEF);
106 #endif /* CONFIG_RX_INDICATE_QUEUE */
107
108 #ifdef CONFIG_PREALLOC_RECV_SKB
109 {
110 int i;
111 SIZE_PTR tmpaddr = 0;
112 SIZE_PTR alignment = 0;
113 struct sk_buff *pskb = NULL;
114
115 RTW_INFO("NR_PREALLOC_RECV_SKB: %d\n", NR_PREALLOC_RECV_SKB);
116 #ifdef CONFIG_FIX_NR_BULKIN_BUFFER
117 RTW_INFO("Enable CONFIG_FIX_NR_BULKIN_BUFFER\n");
118 #endif
119
120 for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
121 #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
122 pskb = rtw_alloc_skb_premem(MAX_RECVBUF_SZ);
123 #else
124 pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
125 #endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */
126
127 if (pskb) {
128 #ifdef PLATFORM_FREEBSD
129 pskb->dev = padapter->pifp;
130 #else
131 pskb->dev = padapter->pnetdev;
132 #endif /* PLATFORM_FREEBSD */
133
134 #ifndef CONFIG_PREALLOC_RX_SKB_BUFFER
135 tmpaddr = (SIZE_PTR)pskb->data;
136 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
137 skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
138 #endif
139 skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
140 }
141 }
142 }
143 #endif /* CONFIG_PREALLOC_RECV_SKB */
144
145 #endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) */
146
147 exit:
148
149 return res;
150 }
151
usb_free_recv_priv(_adapter * padapter,u16 ini_in_buf_sz)152 void usb_free_recv_priv(_adapter *padapter, u16 ini_in_buf_sz)
153 {
154 int i;
155 struct registry_priv *regsty = &padapter->registrypriv;
156 struct recv_buf *precvbuf;
157 struct recv_priv *precvpriv = &padapter->recvpriv;
158
159 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
160
161 for (i = 0; i < regsty->recvbuf_nr ; i++) {
162 rtw_os_recvbuf_resource_free(padapter, precvbuf);
163 precvbuf++;
164 }
165
166 if (precvpriv->pallocated_recv_buf)
167 rtw_mfree(precvpriv->pallocated_recv_buf, regsty->recvbuf_nr * sizeof(struct recv_buf) + 4);
168
169 #ifdef CONFIG_USB_INTERRUPT_IN_PIPE
170 #ifdef PLATFORM_LINUX
171 if (precvpriv->int_in_urb)
172 usb_free_urb(precvpriv->int_in_urb);
173 #endif
174 if (precvpriv->int_in_buf)
175 rtw_mfree(precvpriv->int_in_buf, ini_in_buf_sz);
176 #endif /* CONFIG_USB_INTERRUPT_IN_PIPE */
177
178 #ifdef PLATFORM_LINUX
179
180 if (skb_queue_len(&precvpriv->rx_skb_queue))
181 RTW_WARN("rx_skb_queue not empty\n");
182
183 rtw_skb_queue_purge(&precvpriv->rx_skb_queue);
184
185 if (skb_queue_len(&precvpriv->free_recv_skb_queue))
186 RTW_WARN("free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue));
187
188 #if !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX)
189 #if defined(CONFIG_PREALLOC_RECV_SKB) && defined(CONFIG_PREALLOC_RX_SKB_BUFFER)
190 {
191 struct sk_buff *skb;
192
193 while ((skb = skb_dequeue(&precvpriv->free_recv_skb_queue)) != NULL) {
194 if (rtw_free_skb_premem(skb) != 0)
195 rtw_skb_free(skb);
196 }
197 }
198 #else
199 rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue);
200 #endif /* defined(CONFIG_PREALLOC_RX_SKB_BUFFER) && defined(CONFIG_PREALLOC_RECV_SKB) */
201 #endif /* !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX) */
202
203 #endif /* PLATFORM_LINUX */
204
205 #ifdef PLATFORM_FREEBSD
206 struct sk_buff *pskb;
207 while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue)))
208 rtw_skb_free(pskb);
209
210 #if !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX)
211 rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue);
212 #endif
213
214 #ifdef CONFIG_RX_INDICATE_QUEUE
215 struct mbuf *m;
216 for (;;) {
217 IF_DEQUEUE(&precvpriv->rx_indicate_queue, m);
218 if (m == NULL)
219 break;
220 rtw_os_pkt_free(m);
221 }
222 mtx_destroy(&precvpriv->rx_indicate_queue.ifq_mtx);
223 #endif /* CONFIG_RX_INDICATE_QUEUE */
224
225 #endif /* PLATFORM_FREEBSD */
226 }
227
228 #ifdef CONFIG_FW_C2H_REG
usb_c2h_hisr_hdl(_adapter * adapter,u8 * buf)229 void usb_c2h_hisr_hdl(_adapter *adapter, u8 *buf)
230 {
231 u8 *c2h_evt = buf;
232 u8 id, seq, plen;
233 u8 *payload;
234
235 if (rtw_hal_c2h_reg_hdr_parse(adapter, buf, &id, &seq, &plen, &payload) != _SUCCESS)
236 return;
237
238 if (0)
239 RTW_PRINT("%s C2H == %d\n", __func__, id);
240
241 if (rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload)) {
242 /* Handle directly */
243 rtw_hal_c2h_handler(adapter, id, seq, plen, payload);
244
245 /* Replace with special pointer to trigger c2h_evt_clear only */
246 if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)&adapter->evtpriv) != _SUCCESS)
247 RTW_ERR("%s rtw_cbuf_push fail\n", __func__);
248 } else {
249 c2h_evt = rtw_malloc(C2H_REG_LEN);
250 if (c2h_evt != NULL) {
251 _rtw_memcpy(c2h_evt, buf, C2H_REG_LEN);
252 if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)c2h_evt) != _SUCCESS)
253 RTW_ERR("%s rtw_cbuf_push fail\n", __func__);
254 } else {
255 /* Error handling for malloc fail */
256 if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)NULL) != _SUCCESS)
257 RTW_ERR("%s rtw_cbuf_push fail\n", __func__);
258 }
259 }
260 _set_workitem(&adapter->evtpriv.c2h_wk);
261 }
262 #endif
263
264 #ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ
usb_write_async(struct usb_device * udev,u32 addr,void * pdata,u16 len)265 int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len)
266 {
267 u8 request;
268 u8 requesttype;
269 u16 wvalue;
270 u16 index;
271 int ret;
272
273 requesttype = VENDOR_WRITE;/* write_out */
274 request = REALTEK_USB_VENQT_CMD_REQ;
275 index = REALTEK_USB_VENQT_CMD_IDX;/* n/a */
276
277 wvalue = (u16)(addr & 0x0000ffff);
278
279 ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype);
280
281 return ret;
282 }
283
usb_async_write8(struct intf_hdl * pintfhdl,u32 addr,u8 val)284 int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
285 {
286 u8 data;
287 int ret;
288 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
289 struct usb_device *udev = pdvobjpriv->pusbdev;
290
291 data = val;
292 ret = usb_write_async(udev, addr, &data, 1);
293
294 return ret;
295 }
296
usb_async_write16(struct intf_hdl * pintfhdl,u32 addr,u16 val)297 int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
298 {
299 u16 data;
300 int ret;
301 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
302 struct usb_device *udev = pdvobjpriv->pusbdev;
303
304 data = val;
305 ret = usb_write_async(udev, addr, &data, 2);
306
307 return ret;
308 }
309
usb_async_write32(struct intf_hdl * pintfhdl,u32 addr,u32 val)310 int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
311 {
312 u32 data;
313 int ret;
314 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev;
315 struct usb_device *udev = pdvobjpriv->pusbdev;
316
317 data = val;
318 ret = usb_write_async(udev, addr, &data, 4);
319
320 return ret;
321 }
322 #endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */
323
usb_read8(struct intf_hdl * pintfhdl,u32 addr)324 u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
325 {
326 u8 request;
327 u8 requesttype;
328 u16 wvalue;
329 u16 index;
330 u16 len;
331 u8 data = 0;
332
333
334 request = 0x05;
335 requesttype = 0x01;/* read_in */
336 index = 0;/* n/a */
337
338 wvalue = (u16)(addr & 0x0000ffff);
339 len = 1;
340
341 /* WLANON PAGE0_REG needs to add an offset 0x8000 */
342 #if defined(CONFIG_RTL8710B)
343 if(wvalue >= 0x0000 && wvalue < 0x0100)
344 wvalue |= 0x8000;
345 #endif
346
347 usbctrl_vendorreq(pintfhdl, request, wvalue, index,
348 &data, len, requesttype);
349
350
351 return data;
352 }
353
usb_read16(struct intf_hdl * pintfhdl,u32 addr)354 u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
355 {
356 u8 request;
357 u8 requesttype;
358 u16 wvalue;
359 u16 index;
360 u16 len;
361 u16 data = 0;
362
363
364 request = 0x05;
365 requesttype = 0x01;/* read_in */
366 index = 0;/* n/a */
367
368 wvalue = (u16)(addr & 0x0000ffff);
369 len = 2;
370
371 /* WLANON PAGE0_REG needs to add an offset 0x8000 */
372 #if defined(CONFIG_RTL8710B)
373 if(wvalue >= 0x0000 && wvalue < 0x0100)
374 wvalue |= 0x8000;
375 #endif
376
377 usbctrl_vendorreq(pintfhdl, request, wvalue, index,
378 &data, len, requesttype);
379
380
381 return data;
382
383 }
384
usb_read32(struct intf_hdl * pintfhdl,u32 addr)385 u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
386 {
387 u8 request;
388 u8 requesttype;
389 u16 wvalue;
390 u16 index;
391 u16 len;
392 u32 data = 0;
393
394
395 request = 0x05;
396 requesttype = 0x01;/* read_in */
397 index = 0;/* n/a */
398
399 wvalue = (u16)(addr & 0x0000ffff);
400 len = 4;
401
402 /* WLANON PAGE0_REG needs to add an offset 0x8000 */
403 #if defined(CONFIG_RTL8710B)
404 if(wvalue >= 0x0000 && wvalue < 0x0100)
405 wvalue |= 0x8000;
406 #endif
407
408 usbctrl_vendorreq(pintfhdl, request, wvalue, index,
409 &data, len, requesttype);
410
411
412 return data;
413 }
414
usb_write8(struct intf_hdl * pintfhdl,u32 addr,u8 val)415 int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
416 {
417 u8 request;
418 u8 requesttype;
419 u16 wvalue;
420 u16 index;
421 u16 len;
422 u8 data;
423 int ret;
424
425
426 request = 0x05;
427 requesttype = 0x00;/* write_out */
428 index = 0;/* n/a */
429
430 wvalue = (u16)(addr & 0x0000ffff);
431 len = 1;
432 data = val;
433
434 /* WLANON PAGE0_REG needs to add an offset 0x8000 */
435 #if defined(CONFIG_RTL8710B)
436 if(wvalue >= 0x0000 && wvalue < 0x0100)
437 wvalue |= 0x8000;
438 #endif
439
440 ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,
441 &data, len, requesttype);
442
443
444 return ret;
445 }
446
usb_write16(struct intf_hdl * pintfhdl,u32 addr,u16 val)447 int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
448 {
449 u8 request;
450 u8 requesttype;
451 u16 wvalue;
452 u16 index;
453 u16 len;
454 u16 data;
455 int ret;
456
457
458 request = 0x05;
459 requesttype = 0x00;/* write_out */
460 index = 0;/* n/a */
461
462 wvalue = (u16)(addr & 0x0000ffff);
463 len = 2;
464 data = val;
465
466 /* WLANON PAGE0_REG needs to add an offset 0x8000 */
467 #if defined(CONFIG_RTL8710B)
468 if(wvalue >= 0x0000 && wvalue < 0x0100)
469 wvalue |= 0x8000;
470 #endif
471
472 ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,
473 &data, len, requesttype);
474
475
476 return ret;
477
478 }
479
usb_write32(struct intf_hdl * pintfhdl,u32 addr,u32 val)480 int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
481 {
482 u8 request;
483 u8 requesttype;
484 u16 wvalue;
485 u16 index;
486 u16 len;
487 u32 data;
488 int ret;
489
490
491 request = 0x05;
492 requesttype = 0x00;/* write_out */
493 index = 0;/* n/a */
494
495 wvalue = (u16)(addr & 0x0000ffff);
496 len = 4;
497 data = val;
498
499 /* WLANON PAGE0_REG needs to add an offset 0x8000 */
500 #if defined(CONFIG_RTL8710B)
501 if(wvalue >= 0x0000 && wvalue < 0x0100)
502 wvalue |= 0x8000;
503 #endif
504
505 ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,
506 &data, len, requesttype);
507
508
509 return ret;
510
511 }
512
usb_writeN(struct intf_hdl * pintfhdl,u32 addr,u32 length,u8 * pdata)513 int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata)
514 {
515 u8 request;
516 u8 requesttype;
517 u16 wvalue;
518 u16 index;
519 u16 len;
520 u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
521 int ret;
522
523
524 request = 0x05;
525 requesttype = 0x00;/* write_out */
526 index = 0;/* n/a */
527
528 wvalue = (u16)(addr & 0x0000ffff);
529 len = length;
530 _rtw_memcpy(buf, pdata, len);
531 ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index,
532 buf, len, requesttype);
533
534
535 return ret;
536 }
537
usb_set_intf_ops(_adapter * padapter,struct _io_ops * pops)538 void usb_set_intf_ops(_adapter *padapter, struct _io_ops *pops)
539 {
540 _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));
541
542 pops->_read8 = &usb_read8;
543 pops->_read16 = &usb_read16;
544 pops->_read32 = &usb_read32;
545 pops->_read_mem = &usb_read_mem;
546 pops->_read_port = &usb_read_port;
547
548 pops->_write8 = &usb_write8;
549 pops->_write16 = &usb_write16;
550 pops->_write32 = &usb_write32;
551 pops->_writeN = &usb_writeN;
552
553 #ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ
554 pops->_write8_async = &usb_async_write8;
555 pops->_write16_async = &usb_async_write16;
556 pops->_write32_async = &usb_async_write32;
557 #endif
558 pops->_write_mem = &usb_write_mem;
559 pops->_write_port = &usb_write_port;
560
561 pops->_read_port_cancel = &usb_read_port_cancel;
562 pops->_write_port_cancel = &usb_write_port_cancel;
563
564 #ifdef CONFIG_USB_INTERRUPT_IN_PIPE
565 pops->_read_interrupt = &usb_read_interrupt;
566 #endif
567
568 }
569