xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8188fu/hal/hal_hci/hal_usb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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