xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bluetooth_uart_driver/rtk_coex.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun *  Realtek Bluetooth USB driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun *  This program is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun *  it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun *  the Free Software Foundation; either version 2 of the License, or
9*4882a593Smuzhiyun *  (at your option) any later version.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun *  This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*4882a593Smuzhiyun *  GNU General Public License for more details.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun *  You should have received a copy of the GNU General Public License
17*4882a593Smuzhiyun *  along with this program; if not, write to the Free Software
18*4882a593Smuzhiyun *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun #include <linux/kernel.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun #include <linux/types.h>
26*4882a593Smuzhiyun #include <linux/sched.h>
27*4882a593Smuzhiyun #include <linux/errno.h>
28*4882a593Smuzhiyun #include <linux/skbuff.h>
29*4882a593Smuzhiyun #include <linux/dcache.h>
30*4882a593Smuzhiyun #include <linux/version.h>
31*4882a593Smuzhiyun #include <net/sock.h>
32*4882a593Smuzhiyun #include <net/bluetooth/bluetooth.h>
33*4882a593Smuzhiyun #include <net/bluetooth/hci_core.h>
34*4882a593Smuzhiyun #include <net/bluetooth/l2cap.h>
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #include "rtk_coex.h"
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /* Software coex message can be sent to and receive from WiFi driver by
39*4882a593Smuzhiyun  * UDP socket or exported symbol */
40*4882a593Smuzhiyun /* #define RTK_COEX_OVER_SYMBOL */
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #if BTRTL_HCI_IF == BTRTL_HCIUSB
43*4882a593Smuzhiyun #include <linux/usb.h>
44*4882a593Smuzhiyun #include "rtk_bt.h"
45*4882a593Smuzhiyun #undef RTKBT_DBG
46*4882a593Smuzhiyun #undef RTKBT_INFO
47*4882a593Smuzhiyun #undef RTKBT_WARN
48*4882a593Smuzhiyun #undef RTKBT_ERR
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #elif BTRTL_HCI_IF == BTRTL_HCIUART
51*4882a593Smuzhiyun /* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
52*4882a593Smuzhiyun #define HCI_VERSION_CODE LINUX_VERSION_CODE
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #else
55*4882a593Smuzhiyun #error "Please set type of HCI interface"
56*4882a593Smuzhiyun #endif
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define RTK_VERSION "1.2"
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define RTKBT_DBG(fmt, arg...) printk(KERN_INFO "rtk_btcoex: " fmt "\n" , ## arg)
61*4882a593Smuzhiyun #define RTKBT_INFO(fmt, arg...) printk(KERN_INFO "rtk_btcoex: " fmt "\n" , ## arg)
62*4882a593Smuzhiyun #define RTKBT_WARN(fmt, arg...) printk(KERN_WARNING "rtk_btcoex: " fmt "\n", ## arg)
63*4882a593Smuzhiyun #define RTKBT_ERR(fmt, arg...) printk(KERN_WARNING "rtk_btcoex: " fmt "\n", ## arg)
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static struct rtl_coex_struct btrtl_coex;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
68*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
69*4882a593Smuzhiyun static struct sk_buff_head rtw_q;
70*4882a593Smuzhiyun static struct workqueue_struct *rtw_wq;
71*4882a593Smuzhiyun static struct work_struct rtw_work;
72*4882a593Smuzhiyun static u8 rtw_coex_on;
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun #endif
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define is_profile_connected(profile)   ((btrtl_coex.profile_bitmap & BIT(profile)) > 0)
77*4882a593Smuzhiyun #define is_profile_busy(profile)        ((btrtl_coex.profile_status & BIT(profile)) > 0)
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
80*4882a593Smuzhiyun static void rtk_handle_event_from_wifi(uint8_t * msg);
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun 
rtl_alloc_buff(struct rtl_coex_struct * coex)83*4882a593Smuzhiyun static int rtl_alloc_buff(struct rtl_coex_struct *coex)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	struct rtl_hci_ev *ev;
86*4882a593Smuzhiyun 	struct rtl_l2_buff *l2;
87*4882a593Smuzhiyun 	int i;
88*4882a593Smuzhiyun 	int order;
89*4882a593Smuzhiyun 	unsigned long addr;
90*4882a593Smuzhiyun 	unsigned long addr2;
91*4882a593Smuzhiyun 	int ev_size;
92*4882a593Smuzhiyun 	int l2_size;
93*4882a593Smuzhiyun 	int n;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	spin_lock_init(&coex->buff_lock);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	INIT_LIST_HEAD(&coex->ev_used_list);
98*4882a593Smuzhiyun 	INIT_LIST_HEAD(&coex->ev_free_list);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	INIT_LIST_HEAD(&coex->l2_used_list);
101*4882a593Smuzhiyun 	INIT_LIST_HEAD(&coex->l2_free_list);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	n = NUM_RTL_HCI_EV * sizeof(struct rtl_hci_ev);
104*4882a593Smuzhiyun 	ev_size = ALIGN(n, sizeof(unsigned long));
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	n = L2_MAX_PKTS * sizeof(struct rtl_l2_buff);
107*4882a593Smuzhiyun 	l2_size = ALIGN(n, sizeof(unsigned long));
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	RTKBT_DBG("alloc buffers %d, %d for ev and l2", ev_size, l2_size);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	order = get_order(ev_size + l2_size);
112*4882a593Smuzhiyun 	addr = __get_free_pages(GFP_KERNEL, order);
113*4882a593Smuzhiyun 	if (!addr) {
114*4882a593Smuzhiyun 		RTKBT_ERR("failed to alloc buffers for ev and l2.");
115*4882a593Smuzhiyun 		return -ENOMEM;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 	memset((void *)addr, 0, ev_size + l2_size);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	coex->pages_addr = addr;
120*4882a593Smuzhiyun 	coex->buff_size = ev_size + l2_size;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	ev = (struct rtl_hci_ev *)addr;
123*4882a593Smuzhiyun 	for (i = 0; i < NUM_RTL_HCI_EV; i++) {
124*4882a593Smuzhiyun 		list_add_tail(&ev->list, &coex->ev_free_list);
125*4882a593Smuzhiyun 		ev++;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	addr2 = addr + ev_size;
129*4882a593Smuzhiyun 	l2 = (struct rtl_l2_buff *)addr2;
130*4882a593Smuzhiyun 	for (i = 0; i < L2_MAX_PKTS; i++) {
131*4882a593Smuzhiyun 		list_add_tail(&l2->list, &coex->l2_free_list);
132*4882a593Smuzhiyun 		l2++;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
rtl_free_buff(struct rtl_coex_struct * coex)138*4882a593Smuzhiyun static void rtl_free_buff(struct rtl_coex_struct *coex)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct rtl_hci_ev *ev;
141*4882a593Smuzhiyun 	struct rtl_l2_buff *l2;
142*4882a593Smuzhiyun 	unsigned long flags;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	while (!list_empty(&coex->ev_used_list)) {
147*4882a593Smuzhiyun 		ev = list_entry(coex->ev_used_list.next, struct rtl_hci_ev,
148*4882a593Smuzhiyun 				list);
149*4882a593Smuzhiyun 		list_del(&ev->list);
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	while (!list_empty(&coex->ev_free_list)) {
153*4882a593Smuzhiyun 		ev = list_entry(coex->ev_free_list.next, struct rtl_hci_ev,
154*4882a593Smuzhiyun 				list);
155*4882a593Smuzhiyun 		list_del(&ev->list);
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	while (!list_empty(&coex->l2_used_list)) {
159*4882a593Smuzhiyun 		l2 = list_entry(coex->l2_used_list.next, struct rtl_l2_buff,
160*4882a593Smuzhiyun 				list);
161*4882a593Smuzhiyun 		list_del(&l2->list);
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	while (!list_empty(&coex->l2_free_list)) {
165*4882a593Smuzhiyun 		l2 = list_entry(coex->l2_free_list.next, struct rtl_l2_buff,
166*4882a593Smuzhiyun 				list);
167*4882a593Smuzhiyun 		list_del(&l2->list);
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (coex->buff_size > 0) {
173*4882a593Smuzhiyun 		free_pages(coex->pages_addr, get_order(coex->buff_size));
174*4882a593Smuzhiyun 		coex->pages_addr = 0;
175*4882a593Smuzhiyun 		coex->buff_size = 0;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
rtl_ev_node_get(struct rtl_coex_struct * coex)179*4882a593Smuzhiyun static struct rtl_hci_ev *rtl_ev_node_get(struct rtl_coex_struct *coex)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	struct rtl_hci_ev *ev;
182*4882a593Smuzhiyun 	unsigned long flags;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (!coex->buff_size)
185*4882a593Smuzhiyun 		return NULL;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
188*4882a593Smuzhiyun 	if (!list_empty(&coex->ev_free_list)) {
189*4882a593Smuzhiyun 		ev = list_entry(coex->ev_free_list.next, struct rtl_hci_ev,
190*4882a593Smuzhiyun 				list);
191*4882a593Smuzhiyun 		list_del(&ev->list);
192*4882a593Smuzhiyun 	} else
193*4882a593Smuzhiyun 		ev = NULL;
194*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
195*4882a593Smuzhiyun 	return ev;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
rtl_ev_node_to_used(struct rtl_coex_struct * coex,struct rtl_hci_ev * ev)198*4882a593Smuzhiyun static int rtl_ev_node_to_used(struct rtl_coex_struct *coex,
199*4882a593Smuzhiyun 		struct rtl_hci_ev *ev)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	unsigned long flags;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
204*4882a593Smuzhiyun 	list_add_tail(&ev->list, &coex->ev_used_list);
205*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
rtl_l2_node_get(struct rtl_coex_struct * coex)210*4882a593Smuzhiyun static struct rtl_l2_buff *rtl_l2_node_get(struct rtl_coex_struct *coex)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	struct rtl_l2_buff *l2;
213*4882a593Smuzhiyun 	unsigned long flags;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (!coex->buff_size)
216*4882a593Smuzhiyun 		return NULL;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	if(!list_empty(&coex->l2_free_list)) {
221*4882a593Smuzhiyun 		l2 = list_entry(coex->l2_free_list.next, struct rtl_l2_buff,
222*4882a593Smuzhiyun 				list);
223*4882a593Smuzhiyun 		list_del(&l2->list);
224*4882a593Smuzhiyun 	} else
225*4882a593Smuzhiyun 		l2 = NULL;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
228*4882a593Smuzhiyun 	return l2;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
rtl_l2_node_to_used(struct rtl_coex_struct * coex,struct rtl_l2_buff * l2)231*4882a593Smuzhiyun static int rtl_l2_node_to_used(struct rtl_coex_struct *coex,
232*4882a593Smuzhiyun 		struct rtl_l2_buff *l2)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	unsigned long flags;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
237*4882a593Smuzhiyun 	list_add_tail(&l2->list, &coex->l2_used_list);
238*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	return 0;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
psm_to_profile_index(uint16_t psm)243*4882a593Smuzhiyun static int8_t psm_to_profile_index(uint16_t psm)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	switch (psm) {
246*4882a593Smuzhiyun 	case PSM_AVCTP:
247*4882a593Smuzhiyun 	case PSM_SDP:
248*4882a593Smuzhiyun 		return -1;	//ignore
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	case PSM_HID:
251*4882a593Smuzhiyun 	case PSM_HID_INT:
252*4882a593Smuzhiyun 		return profile_hid;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	case PSM_AVDTP:
255*4882a593Smuzhiyun 		return profile_a2dp;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	case PSM_PAN:
258*4882a593Smuzhiyun 	case PSM_OPP:
259*4882a593Smuzhiyun 	case PSM_FTP:
260*4882a593Smuzhiyun 	case PSM_BIP:
261*4882a593Smuzhiyun 	case PSM_RFCOMM:
262*4882a593Smuzhiyun 		return profile_pan;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	default:
265*4882a593Smuzhiyun 		return profile_pan;
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
find_by_psm(u16 psm)269*4882a593Smuzhiyun static rtk_prof_info *find_by_psm(u16 psm)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	struct list_head *head = &btrtl_coex.profile_list;
272*4882a593Smuzhiyun 	struct list_head *iter = NULL;
273*4882a593Smuzhiyun 	struct list_head *temp = NULL;
274*4882a593Smuzhiyun 	rtk_prof_info *desc = NULL;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
277*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_prof_info, list);
278*4882a593Smuzhiyun 		if (desc->psm == psm)
279*4882a593Smuzhiyun 			return desc;
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	return NULL;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
rtk_check_setup_timer(int8_t profile_index)285*4882a593Smuzhiyun static void rtk_check_setup_timer(int8_t profile_index)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	if (profile_index == profile_a2dp) {
288*4882a593Smuzhiyun 		btrtl_coex.a2dp_packet_count = 0;
289*4882a593Smuzhiyun 		btrtl_coex.a2dp_count_timer.expires =
290*4882a593Smuzhiyun 		    jiffies + msecs_to_jiffies(1000);
291*4882a593Smuzhiyun 		mod_timer(&btrtl_coex.a2dp_count_timer,
292*4882a593Smuzhiyun 			  btrtl_coex.a2dp_count_timer.expires);
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (profile_index == profile_pan) {
296*4882a593Smuzhiyun 		btrtl_coex.pan_packet_count = 0;
297*4882a593Smuzhiyun 		btrtl_coex.pan_count_timer.expires =
298*4882a593Smuzhiyun 		    jiffies + msecs_to_jiffies(1000);
299*4882a593Smuzhiyun 		mod_timer(&btrtl_coex.pan_count_timer,
300*4882a593Smuzhiyun 			  btrtl_coex.pan_count_timer.expires);
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/* hogp & voice share one timer now */
304*4882a593Smuzhiyun 	if ((profile_index == profile_hogp) || (profile_index == profile_voice)) {
305*4882a593Smuzhiyun 		if ((0 == btrtl_coex.profile_refcount[profile_hogp])
306*4882a593Smuzhiyun 		    && (0 == btrtl_coex.profile_refcount[profile_voice])) {
307*4882a593Smuzhiyun 			btrtl_coex.hogp_packet_count = 0;
308*4882a593Smuzhiyun 			btrtl_coex.voice_packet_count = 0;
309*4882a593Smuzhiyun 			btrtl_coex.hogp_count_timer.expires =
310*4882a593Smuzhiyun 			    jiffies + msecs_to_jiffies(1000);
311*4882a593Smuzhiyun 			mod_timer(&btrtl_coex.hogp_count_timer,
312*4882a593Smuzhiyun 				  btrtl_coex.hogp_count_timer.expires);
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
rtk_check_del_timer(int8_t profile_index)317*4882a593Smuzhiyun static void rtk_check_del_timer(int8_t profile_index)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	if (profile_a2dp == profile_index) {
320*4882a593Smuzhiyun 		btrtl_coex.a2dp_packet_count = 0;
321*4882a593Smuzhiyun 		del_timer_sync(&btrtl_coex.a2dp_count_timer);
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 	if (profile_pan == profile_index) {
324*4882a593Smuzhiyun 		btrtl_coex.pan_packet_count = 0;
325*4882a593Smuzhiyun 		del_timer_sync(&btrtl_coex.pan_count_timer);
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun 	if (profile_hogp == profile_index) {
328*4882a593Smuzhiyun 		btrtl_coex.hogp_packet_count = 0;
329*4882a593Smuzhiyun 		if (btrtl_coex.profile_refcount[profile_voice] == 0) {
330*4882a593Smuzhiyun 			del_timer_sync(&btrtl_coex.hogp_count_timer);
331*4882a593Smuzhiyun 		}
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 	if (profile_voice == profile_index) {
334*4882a593Smuzhiyun 		btrtl_coex.voice_packet_count = 0;
335*4882a593Smuzhiyun 		if (btrtl_coex.profile_refcount[profile_hogp] == 0) {
336*4882a593Smuzhiyun 			del_timer_sync(&btrtl_coex.hogp_count_timer);
337*4882a593Smuzhiyun 		}
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 
find_connection_by_handle(struct rtl_coex_struct * coex,uint16_t handle)343*4882a593Smuzhiyun static rtk_conn_prof *find_connection_by_handle(struct rtl_coex_struct * coex,
344*4882a593Smuzhiyun 						uint16_t handle)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	struct list_head *head = &coex->conn_hash;
347*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
348*4882a593Smuzhiyun 	rtk_conn_prof *desc = NULL;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
351*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_conn_prof, list);
352*4882a593Smuzhiyun 		if ((handle & 0xEFF) == desc->handle) {
353*4882a593Smuzhiyun 			return desc;
354*4882a593Smuzhiyun 		}
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun 	return NULL;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
allocate_connection_by_handle(uint16_t handle)359*4882a593Smuzhiyun static rtk_conn_prof *allocate_connection_by_handle(uint16_t handle)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	rtk_conn_prof *phci_conn = NULL;
362*4882a593Smuzhiyun 	phci_conn = kmalloc(sizeof(rtk_conn_prof), GFP_ATOMIC);
363*4882a593Smuzhiyun 	if (phci_conn)
364*4882a593Smuzhiyun 		phci_conn->handle = handle;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return phci_conn;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
init_connection_hash(struct rtl_coex_struct * coex)369*4882a593Smuzhiyun static void init_connection_hash(struct rtl_coex_struct * coex)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	struct list_head *head = &coex->conn_hash;
372*4882a593Smuzhiyun 	INIT_LIST_HEAD(head);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
add_connection_to_hash(struct rtl_coex_struct * coex,rtk_conn_prof * desc)375*4882a593Smuzhiyun static void add_connection_to_hash(struct rtl_coex_struct * coex,
376*4882a593Smuzhiyun 				   rtk_conn_prof * desc)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	struct list_head *head = &coex->conn_hash;
379*4882a593Smuzhiyun 	list_add_tail(&desc->list, head);
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
delete_connection_from_hash(rtk_conn_prof * desc)382*4882a593Smuzhiyun static void delete_connection_from_hash(rtk_conn_prof * desc)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	if (desc) {
385*4882a593Smuzhiyun 		list_del(&desc->list);
386*4882a593Smuzhiyun 		kfree(desc);
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
flush_connection_hash(struct rtl_coex_struct * coex)390*4882a593Smuzhiyun static void flush_connection_hash(struct rtl_coex_struct * coex)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct list_head *head = &coex->conn_hash;
393*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
394*4882a593Smuzhiyun 	rtk_conn_prof *desc = NULL;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
397*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_conn_prof, list);
398*4882a593Smuzhiyun 		if (desc) {
399*4882a593Smuzhiyun 			list_del(&desc->list);
400*4882a593Smuzhiyun 			kfree(desc);
401*4882a593Smuzhiyun 		}
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 	//INIT_LIST_HEAD(head);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
init_profile_hash(struct rtl_coex_struct * coex)406*4882a593Smuzhiyun static void init_profile_hash(struct rtl_coex_struct * coex)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct list_head *head = &coex->profile_list;
409*4882a593Smuzhiyun 	INIT_LIST_HEAD(head);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
list_allocate_add(uint16_t handle,uint16_t psm,int8_t profile_index,uint16_t dcid,uint16_t scid)412*4882a593Smuzhiyun static uint8_t list_allocate_add(uint16_t handle, uint16_t psm,
413*4882a593Smuzhiyun 				 int8_t profile_index, uint16_t dcid,
414*4882a593Smuzhiyun 				 uint16_t scid)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	rtk_prof_info *pprof_info = NULL;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (profile_index < 0) {
419*4882a593Smuzhiyun 		RTKBT_ERR("PSM 0x%x do not need parse", psm);
420*4882a593Smuzhiyun 		return FALSE;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	pprof_info = kmalloc(sizeof(rtk_prof_info), GFP_ATOMIC);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if (NULL == pprof_info) {
426*4882a593Smuzhiyun 		RTKBT_ERR("list_allocate_add: allocate error");
427*4882a593Smuzhiyun 		return FALSE;
428*4882a593Smuzhiyun 	}
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	/* Check if it is the second l2cap connection for a2dp
431*4882a593Smuzhiyun 	 * a2dp signal channel will be created first than media channel.
432*4882a593Smuzhiyun 	 */
433*4882a593Smuzhiyun 	if (psm == PSM_AVDTP) {
434*4882a593Smuzhiyun 		rtk_prof_info *pinfo = find_by_psm(psm);
435*4882a593Smuzhiyun 		if (!pinfo) {
436*4882a593Smuzhiyun 			pprof_info->flags = A2DP_SIGNAL;
437*4882a593Smuzhiyun 			RTKBT_INFO("%s: Add a2dp signal channel", __func__);
438*4882a593Smuzhiyun 		} else {
439*4882a593Smuzhiyun 			pprof_info->flags = A2DP_MEDIA;
440*4882a593Smuzhiyun 			RTKBT_INFO("%s: Add a2dp media channel", __func__);
441*4882a593Smuzhiyun 		}
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	pprof_info->handle = handle;
445*4882a593Smuzhiyun 	pprof_info->psm = psm;
446*4882a593Smuzhiyun 	pprof_info->scid = scid;
447*4882a593Smuzhiyun 	pprof_info->dcid = dcid;
448*4882a593Smuzhiyun 	pprof_info->profile_index = profile_index;
449*4882a593Smuzhiyun 	list_add_tail(&(pprof_info->list), &(btrtl_coex.profile_list));
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	return TRUE;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
delete_profile_from_hash(rtk_prof_info * desc)454*4882a593Smuzhiyun static void delete_profile_from_hash(rtk_prof_info * desc)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	RTKBT_DBG("Delete profile: hndl 0x%04x, psm 0x%04x, dcid 0x%04x, "
457*4882a593Smuzhiyun 		  "scid 0x%04x", desc->handle, desc->psm, desc->dcid,
458*4882a593Smuzhiyun 		  desc->scid);
459*4882a593Smuzhiyun 	if (desc) {
460*4882a593Smuzhiyun 		list_del(&desc->list);
461*4882a593Smuzhiyun 		kfree(desc);
462*4882a593Smuzhiyun 		desc = NULL;
463*4882a593Smuzhiyun 	}
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
flush_profile_hash(struct rtl_coex_struct * coex)466*4882a593Smuzhiyun static void flush_profile_hash(struct rtl_coex_struct * coex)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	struct list_head *head = &coex->profile_list;
469*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
470*4882a593Smuzhiyun 	rtk_prof_info *desc = NULL;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	spin_lock(&btrtl_coex.spin_lock_profile);
473*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
474*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_prof_info, list);
475*4882a593Smuzhiyun 		delete_profile_from_hash(desc);
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 	//INIT_LIST_HEAD(head);
478*4882a593Smuzhiyun 	spin_unlock(&btrtl_coex.spin_lock_profile);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun 
find_profile_by_handle_scid(struct rtl_coex_struct * coex,uint16_t handle,uint16_t scid)481*4882a593Smuzhiyun static rtk_prof_info *find_profile_by_handle_scid(struct rtl_coex_struct *
482*4882a593Smuzhiyun 						  coex, uint16_t handle,
483*4882a593Smuzhiyun 						  uint16_t scid)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct list_head *head = &coex->profile_list;
486*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
487*4882a593Smuzhiyun 	rtk_prof_info *desc = NULL;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
490*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_prof_info, list);
491*4882a593Smuzhiyun 		if (((handle & 0xFFF) == desc->handle) && (scid == desc->scid)) {
492*4882a593Smuzhiyun 			return desc;
493*4882a593Smuzhiyun 		}
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 	return NULL;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
find_profile_by_handle_dcid(struct rtl_coex_struct * coex,uint16_t handle,uint16_t dcid)498*4882a593Smuzhiyun static rtk_prof_info *find_profile_by_handle_dcid(struct rtl_coex_struct *
499*4882a593Smuzhiyun 						  coex, uint16_t handle,
500*4882a593Smuzhiyun 						  uint16_t dcid)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun 	struct list_head *head = &coex->profile_list;
503*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
504*4882a593Smuzhiyun 	rtk_prof_info *desc = NULL;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
507*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_prof_info, list);
508*4882a593Smuzhiyun 		if (((handle & 0xFFF) == desc->handle) && (dcid == desc->dcid)) {
509*4882a593Smuzhiyun 			return desc;
510*4882a593Smuzhiyun 		}
511*4882a593Smuzhiyun 	}
512*4882a593Smuzhiyun 	return NULL;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
find_profile_by_handle_dcid_scid(struct rtl_coex_struct * coex,uint16_t handle,uint16_t dcid,uint16_t scid)515*4882a593Smuzhiyun static rtk_prof_info *find_profile_by_handle_dcid_scid(struct rtl_coex_struct
516*4882a593Smuzhiyun 						       * coex, uint16_t handle,
517*4882a593Smuzhiyun 						       uint16_t dcid,
518*4882a593Smuzhiyun 						       uint16_t scid)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct list_head *head = &coex->profile_list;
521*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
522*4882a593Smuzhiyun 	rtk_prof_info *desc = NULL;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
525*4882a593Smuzhiyun 		desc = list_entry(iter, rtk_prof_info, list);
526*4882a593Smuzhiyun 		if (((handle & 0xFFF) == desc->handle) && (dcid == desc->dcid)
527*4882a593Smuzhiyun 		    && (scid == desc->scid)) {
528*4882a593Smuzhiyun 			return desc;
529*4882a593Smuzhiyun 		}
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 	return NULL;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
rtk_vendor_cmd_to_fw(uint16_t opcode,uint8_t parameter_len,uint8_t * parameter)534*4882a593Smuzhiyun static void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len,
535*4882a593Smuzhiyun 				 uint8_t * parameter)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	int len = HCI_CMD_PREAMBLE_SIZE + parameter_len;
538*4882a593Smuzhiyun 	uint8_t *p;
539*4882a593Smuzhiyun 	struct sk_buff *skb;
540*4882a593Smuzhiyun 	struct hci_dev *hdev = btrtl_coex.hdev;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (!hdev) {
543*4882a593Smuzhiyun 		RTKBT_ERR("No HCI device");
544*4882a593Smuzhiyun 		return;
545*4882a593Smuzhiyun 	} else if (!test_bit(HCI_UP, &hdev->flags)) {
546*4882a593Smuzhiyun 		RTKBT_WARN("HCI device is down");
547*4882a593Smuzhiyun 		return;
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	skb = bt_skb_alloc(len, GFP_ATOMIC);
551*4882a593Smuzhiyun 	if (!skb) {
552*4882a593Smuzhiyun 		RTKBT_DBG("there is no room for cmd 0x%x", opcode);
553*4882a593Smuzhiyun 		return;
554*4882a593Smuzhiyun 	}
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	p = (uint8_t *) skb_put(skb, HCI_CMD_PREAMBLE_SIZE);
557*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, opcode);
558*4882a593Smuzhiyun 	*p++ = parameter_len;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (parameter_len)
561*4882a593Smuzhiyun 		memcpy(skb_put(skb, parameter_len), parameter, parameter_len);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun #if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
566*4882a593Smuzhiyun #if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
567*4882a593Smuzhiyun 	bt_cb(skb)->opcode = opcode;
568*4882a593Smuzhiyun #else
569*4882a593Smuzhiyun 	bt_cb(skb)->hci.opcode = opcode;
570*4882a593Smuzhiyun #endif
571*4882a593Smuzhiyun #endif
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	/* Stand-alone HCI commands must be flagged as
574*4882a593Smuzhiyun 	 * single-command requests.
575*4882a593Smuzhiyun 	 */
576*4882a593Smuzhiyun #if HCI_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
577*4882a593Smuzhiyun #if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
578*4882a593Smuzhiyun 	bt_cb(skb)->req.start = true;
579*4882a593Smuzhiyun #else
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun #if HCI_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
582*4882a593Smuzhiyun 	bt_cb(skb)->hci.req_start = true;
583*4882a593Smuzhiyun #else
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
586*4882a593Smuzhiyun #endif
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun #endif /* 4.4.0 */
589*4882a593Smuzhiyun #endif /* 3.10.0 */
590*4882a593Smuzhiyun 	RTKBT_DBG("%s: opcode 0x%x", __func__, opcode);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	/* It is harmless if set skb->dev twice. The dev will be used in
593*4882a593Smuzhiyun 	 * btusb_send_frame() after or equal to kernel/hci 3.13.0,
594*4882a593Smuzhiyun 	 * the hdev will not come from skb->dev. */
595*4882a593Smuzhiyun #if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
596*4882a593Smuzhiyun 	skb->dev = (void *)btrtl_coex.hdev;
597*4882a593Smuzhiyun #endif
598*4882a593Smuzhiyun 	/* Put the skb to the global hdev->cmd_q */
599*4882a593Smuzhiyun 	skb_queue_tail(&hdev->cmd_q, skb);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun #if HCI_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
602*4882a593Smuzhiyun 	tasklet_schedule(&hdev->cmd_task);
603*4882a593Smuzhiyun #else
604*4882a593Smuzhiyun 	queue_work(hdev->workqueue, &hdev->cmd_work);
605*4882a593Smuzhiyun #endif
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	return;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun 
rtk_notify_profileinfo_to_fw(void)610*4882a593Smuzhiyun static void rtk_notify_profileinfo_to_fw(void)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	struct list_head *head = NULL;
613*4882a593Smuzhiyun 	struct list_head *iter = NULL;
614*4882a593Smuzhiyun 	struct list_head *temp = NULL;
615*4882a593Smuzhiyun 	rtk_conn_prof *hci_conn = NULL;
616*4882a593Smuzhiyun 	uint8_t handle_number = 0;
617*4882a593Smuzhiyun 	uint32_t buffer_size = 0;
618*4882a593Smuzhiyun 	uint8_t *p_buf = NULL;
619*4882a593Smuzhiyun 	uint8_t *p = NULL;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	head = &btrtl_coex.conn_hash;
622*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, head) {
623*4882a593Smuzhiyun 		hci_conn = list_entry(iter, rtk_conn_prof, list);
624*4882a593Smuzhiyun 		if (hci_conn && hci_conn->profile_bitmap)
625*4882a593Smuzhiyun 			handle_number++;
626*4882a593Smuzhiyun 	}
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	buffer_size = 1 + handle_number * 3 + 1;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	p_buf = kmalloc(buffer_size, GFP_ATOMIC);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	if (NULL == p_buf) {
633*4882a593Smuzhiyun 		RTKBT_ERR("%s: alloc error", __func__);
634*4882a593Smuzhiyun 		return;
635*4882a593Smuzhiyun 	}
636*4882a593Smuzhiyun 	p = p_buf;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	RTKBT_DBG("%s: BufferSize %u", __func__, buffer_size);
639*4882a593Smuzhiyun 	*p++ = handle_number;
640*4882a593Smuzhiyun 	RTKBT_DBG("%s: NumberOfHandles %u", __func__, handle_number);
641*4882a593Smuzhiyun 	head = &btrtl_coex.conn_hash;
642*4882a593Smuzhiyun 	list_for_each(iter, head) {
643*4882a593Smuzhiyun 		hci_conn = list_entry(iter, rtk_conn_prof, list);
644*4882a593Smuzhiyun 		if (hci_conn && hci_conn->profile_bitmap) {
645*4882a593Smuzhiyun 			UINT16_TO_STREAM(p, hci_conn->handle);
646*4882a593Smuzhiyun 			RTKBT_DBG("%s: handle 0x%04x", __func__,
647*4882a593Smuzhiyun 					hci_conn->handle);
648*4882a593Smuzhiyun 			*p++ = hci_conn->profile_bitmap;
649*4882a593Smuzhiyun 			RTKBT_DBG("%s: profile_bitmap 0x%02x", __func__,
650*4882a593Smuzhiyun 					hci_conn->profile_bitmap);
651*4882a593Smuzhiyun 			handle_number--;
652*4882a593Smuzhiyun 		}
653*4882a593Smuzhiyun 		if (0 == handle_number)
654*4882a593Smuzhiyun 			break;
655*4882a593Smuzhiyun 	}
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	*p++ = btrtl_coex.profile_status;
658*4882a593Smuzhiyun 	RTKBT_DBG("%s: profile_status 0x%02x", __func__,
659*4882a593Smuzhiyun 			btrtl_coex.profile_status);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size,
662*4882a593Smuzhiyun 			     p_buf);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	kfree(p_buf);
665*4882a593Smuzhiyun 	return;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun 
update_profile_state(uint8_t profile_index,uint8_t is_busy)668*4882a593Smuzhiyun static void update_profile_state(uint8_t profile_index, uint8_t is_busy)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	uint8_t need_update = FALSE;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	if ((btrtl_coex.profile_bitmap & BIT(profile_index)) == 0) {
673*4882a593Smuzhiyun 		RTKBT_ERR("%s: : ERROR!!! profile(Index: %x) does not exist",
674*4882a593Smuzhiyun 				__func__, profile_index);
675*4882a593Smuzhiyun 		return;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	if (is_busy) {
679*4882a593Smuzhiyun 		if ((btrtl_coex.profile_status & BIT(profile_index)) == 0) {
680*4882a593Smuzhiyun 			need_update = TRUE;
681*4882a593Smuzhiyun 			btrtl_coex.profile_status |= BIT(profile_index);
682*4882a593Smuzhiyun 		}
683*4882a593Smuzhiyun 	} else {
684*4882a593Smuzhiyun 		if ((btrtl_coex.profile_status & BIT(profile_index)) > 0) {
685*4882a593Smuzhiyun 			need_update = TRUE;
686*4882a593Smuzhiyun 			btrtl_coex.profile_status &= ~(BIT(profile_index));
687*4882a593Smuzhiyun 		}
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	if (need_update) {
691*4882a593Smuzhiyun 		RTKBT_DBG("%s: btrtl_coex.profie_bitmap = %x",
692*4882a593Smuzhiyun 				__func__, btrtl_coex.profile_bitmap);
693*4882a593Smuzhiyun 		RTKBT_DBG("%s: btrtl_coex.profile_status = %x",
694*4882a593Smuzhiyun 				__func__, btrtl_coex.profile_status);
695*4882a593Smuzhiyun 		rtk_notify_profileinfo_to_fw();
696*4882a593Smuzhiyun 	}
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
update_profile_connection(rtk_conn_prof * phci_conn,int8_t profile_index,uint8_t is_add)699*4882a593Smuzhiyun static void update_profile_connection(rtk_conn_prof * phci_conn,
700*4882a593Smuzhiyun 				      int8_t profile_index, uint8_t is_add)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun 	uint8_t need_update = FALSE;
703*4882a593Smuzhiyun 	uint8_t kk;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	RTKBT_DBG("%s: is_add %d, profile_index %x", __func__,
706*4882a593Smuzhiyun 			is_add, profile_index);
707*4882a593Smuzhiyun 	if (profile_index < 0)
708*4882a593Smuzhiyun 		return;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	if (is_add) {
711*4882a593Smuzhiyun 		if (btrtl_coex.profile_refcount[profile_index] == 0) {
712*4882a593Smuzhiyun 			need_update = TRUE;
713*4882a593Smuzhiyun 			btrtl_coex.profile_bitmap |= BIT(profile_index);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 			/* SCO is always busy */
716*4882a593Smuzhiyun 			if (profile_index == profile_sco)
717*4882a593Smuzhiyun 				btrtl_coex.profile_status |=
718*4882a593Smuzhiyun 				    BIT(profile_index);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 			rtk_check_setup_timer(profile_index);
721*4882a593Smuzhiyun 		}
722*4882a593Smuzhiyun 		btrtl_coex.profile_refcount[profile_index]++;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 		if (0 == phci_conn->profile_refcount[profile_index]) {
725*4882a593Smuzhiyun 			need_update = TRUE;
726*4882a593Smuzhiyun 			phci_conn->profile_bitmap |= BIT(profile_index);
727*4882a593Smuzhiyun 		}
728*4882a593Smuzhiyun 		phci_conn->profile_refcount[profile_index]++;
729*4882a593Smuzhiyun 	} else {
730*4882a593Smuzhiyun 		if (!btrtl_coex.profile_refcount[profile_index]) {
731*4882a593Smuzhiyun 			RTKBT_WARN("profile %u refcount is already zero",
732*4882a593Smuzhiyun 				   profile_index);
733*4882a593Smuzhiyun 			return;
734*4882a593Smuzhiyun 		}
735*4882a593Smuzhiyun 		btrtl_coex.profile_refcount[profile_index]--;
736*4882a593Smuzhiyun 		RTKBT_DBG("%s: btrtl_coex.profile_refcount[%x] = %x",
737*4882a593Smuzhiyun 				__func__, profile_index,
738*4882a593Smuzhiyun 				btrtl_coex.profile_refcount[profile_index]);
739*4882a593Smuzhiyun 		if (btrtl_coex.profile_refcount[profile_index] == 0) {
740*4882a593Smuzhiyun 			need_update = TRUE;
741*4882a593Smuzhiyun 			btrtl_coex.profile_bitmap &= ~(BIT(profile_index));
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 			/* if profile does not exist, status is meaningless */
744*4882a593Smuzhiyun 			btrtl_coex.profile_status &= ~(BIT(profile_index));
745*4882a593Smuzhiyun 			rtk_check_del_timer(profile_index);
746*4882a593Smuzhiyun 		}
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 		phci_conn->profile_refcount[profile_index]--;
749*4882a593Smuzhiyun 		if (0 == phci_conn->profile_refcount[profile_index]) {
750*4882a593Smuzhiyun 			need_update = TRUE;
751*4882a593Smuzhiyun 			phci_conn->profile_bitmap &= ~(BIT(profile_index));
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 			/* clear profile_hid_interval if need */
754*4882a593Smuzhiyun 			if ((profile_hid == profile_index)
755*4882a593Smuzhiyun 			    && (phci_conn->
756*4882a593Smuzhiyun 				profile_bitmap & (BIT(profile_hid_interval)))) {
757*4882a593Smuzhiyun 				phci_conn->profile_bitmap &=
758*4882a593Smuzhiyun 				    ~(BIT(profile_hid_interval));
759*4882a593Smuzhiyun 				btrtl_coex.
760*4882a593Smuzhiyun 				    profile_refcount[profile_hid_interval]--;
761*4882a593Smuzhiyun 			}
762*4882a593Smuzhiyun 		}
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	RTKBT_DBG("%s: btrtl_coex.profile_bitmap 0x%02x", __func__,
766*4882a593Smuzhiyun 			btrtl_coex.profile_bitmap);
767*4882a593Smuzhiyun 	for (kk = 0; kk < 8; kk++)
768*4882a593Smuzhiyun 		RTKBT_DBG("%s: btrtl_coex.profile_refcount[%d] = %d",
769*4882a593Smuzhiyun 				__func__, kk,
770*4882a593Smuzhiyun 				btrtl_coex.profile_refcount[kk]);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	if (need_update)
773*4882a593Smuzhiyun 		rtk_notify_profileinfo_to_fw();
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
update_hid_active_state(uint16_t handle,uint16_t interval)776*4882a593Smuzhiyun static void update_hid_active_state(uint16_t handle, uint16_t interval)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun 	uint8_t need_update = 0;
779*4882a593Smuzhiyun 	rtk_conn_prof *phci_conn =
780*4882a593Smuzhiyun 	    find_connection_by_handle(&btrtl_coex, handle);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	if (phci_conn == NULL)
783*4882a593Smuzhiyun 		return;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	RTKBT_DBG("%s: handle 0x%04x, interval %u", __func__, handle, interval);
786*4882a593Smuzhiyun 	if (((phci_conn->profile_bitmap) & (BIT(profile_hid))) == 0) {
787*4882a593Smuzhiyun 		RTKBT_DBG("HID not connected, nothing to be down");
788*4882a593Smuzhiyun 		return;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	if (interval < 60) {
792*4882a593Smuzhiyun 		if ((phci_conn->profile_bitmap & (BIT(profile_hid_interval))) ==
793*4882a593Smuzhiyun 		    0) {
794*4882a593Smuzhiyun 			need_update = 1;
795*4882a593Smuzhiyun 			phci_conn->profile_bitmap |= BIT(profile_hid_interval);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 			btrtl_coex.profile_refcount[profile_hid_interval]++;
798*4882a593Smuzhiyun 			if (btrtl_coex.
799*4882a593Smuzhiyun 			    profile_refcount[profile_hid_interval] == 1)
800*4882a593Smuzhiyun 				btrtl_coex.profile_status |=
801*4882a593Smuzhiyun 				    BIT(profile_hid);
802*4882a593Smuzhiyun 		}
803*4882a593Smuzhiyun 	} else {
804*4882a593Smuzhiyun 		if ((phci_conn->profile_bitmap & (BIT(profile_hid_interval)))) {
805*4882a593Smuzhiyun 			need_update = 1;
806*4882a593Smuzhiyun 			phci_conn->profile_bitmap &=
807*4882a593Smuzhiyun 			    ~(BIT(profile_hid_interval));
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 			btrtl_coex.profile_refcount[profile_hid_interval]--;
810*4882a593Smuzhiyun 			if (btrtl_coex.
811*4882a593Smuzhiyun 			    profile_refcount[profile_hid_interval] == 0)
812*4882a593Smuzhiyun 				btrtl_coex.profile_status &=
813*4882a593Smuzhiyun 				    ~(BIT(profile_hid));
814*4882a593Smuzhiyun 		}
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	if (need_update)
818*4882a593Smuzhiyun 		rtk_notify_profileinfo_to_fw();
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun 
handle_l2cap_con_req(uint16_t handle,uint16_t psm,uint16_t scid,uint8_t direction)821*4882a593Smuzhiyun static uint8_t handle_l2cap_con_req(uint16_t handle, uint16_t psm,
822*4882a593Smuzhiyun 				    uint16_t scid, uint8_t direction)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun 	uint8_t status = FALSE;
825*4882a593Smuzhiyun 	rtk_prof_info *prof_info = NULL;
826*4882a593Smuzhiyun 	int8_t profile_index = psm_to_profile_index(psm);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	if (profile_index < 0) {
829*4882a593Smuzhiyun 		RTKBT_DBG("PSM(0x%04x) do not need parse", psm);
830*4882a593Smuzhiyun 		return status;
831*4882a593Smuzhiyun 	}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	spin_lock(&btrtl_coex.spin_lock_profile);
834*4882a593Smuzhiyun 	if (direction)		//1: out
835*4882a593Smuzhiyun 		prof_info =
836*4882a593Smuzhiyun 		    find_profile_by_handle_scid(&btrtl_coex, handle, scid);
837*4882a593Smuzhiyun 	else			// 0:in
838*4882a593Smuzhiyun 		prof_info =
839*4882a593Smuzhiyun 		    find_profile_by_handle_dcid(&btrtl_coex, handle, scid);
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	if (prof_info) {
842*4882a593Smuzhiyun 		RTKBT_DBG("%s: this profile is already exist!", __func__);
843*4882a593Smuzhiyun 		spin_unlock(&btrtl_coex.spin_lock_profile);
844*4882a593Smuzhiyun 		return status;
845*4882a593Smuzhiyun 	}
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	if (direction)		//1: out
848*4882a593Smuzhiyun 		status = list_allocate_add(handle, psm, profile_index, 0, scid);
849*4882a593Smuzhiyun 	else			// 0:in
850*4882a593Smuzhiyun 		status = list_allocate_add(handle, psm, profile_index, scid, 0);
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	spin_unlock(&btrtl_coex.spin_lock_profile);
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	if (!status)
855*4882a593Smuzhiyun 		RTKBT_ERR("%s: list_allocate_add failed!", __func__);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	return status;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun 
handle_l2cap_con_rsp(uint16_t handle,uint16_t dcid,uint16_t scid,uint8_t direction,uint8_t result)860*4882a593Smuzhiyun static uint8_t handle_l2cap_con_rsp(uint16_t handle, uint16_t dcid,
861*4882a593Smuzhiyun 				    uint16_t scid, uint8_t direction,
862*4882a593Smuzhiyun 				    uint8_t result)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun 	rtk_prof_info *prof_info = NULL;
865*4882a593Smuzhiyun 	rtk_conn_prof *phci_conn = NULL;
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	spin_lock(&btrtl_coex.spin_lock_profile);
868*4882a593Smuzhiyun 	if (!direction)		//0, in
869*4882a593Smuzhiyun 		prof_info =
870*4882a593Smuzhiyun 		    find_profile_by_handle_scid(&btrtl_coex, handle, scid);
871*4882a593Smuzhiyun 	else			//1, out
872*4882a593Smuzhiyun 		prof_info =
873*4882a593Smuzhiyun 		    find_profile_by_handle_dcid(&btrtl_coex, handle, scid);
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	if (!prof_info) {
876*4882a593Smuzhiyun 		//RTKBT_DBG("handle_l2cap_con_rsp: prof_info Not Find!!");
877*4882a593Smuzhiyun 		spin_unlock(&btrtl_coex.spin_lock_profile);
878*4882a593Smuzhiyun 		return FALSE;
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	if (!result) {		//success
882*4882a593Smuzhiyun 		RTKBT_DBG("l2cap connection success, update connection");
883*4882a593Smuzhiyun 		if (!direction)	//0, in
884*4882a593Smuzhiyun 			prof_info->dcid = dcid;
885*4882a593Smuzhiyun 		else		//1, out
886*4882a593Smuzhiyun 			prof_info->scid = dcid;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 		phci_conn = find_connection_by_handle(&btrtl_coex, handle);
889*4882a593Smuzhiyun 		if (phci_conn)
890*4882a593Smuzhiyun 			update_profile_connection(phci_conn,
891*4882a593Smuzhiyun 						  prof_info->profile_index,
892*4882a593Smuzhiyun 						  TRUE);
893*4882a593Smuzhiyun 	}
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	spin_unlock(&btrtl_coex.spin_lock_profile);
896*4882a593Smuzhiyun 	return TRUE;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun 
handle_l2cap_discon_req(uint16_t handle,uint16_t dcid,uint16_t scid,uint8_t direction)899*4882a593Smuzhiyun static uint8_t handle_l2cap_discon_req(uint16_t handle, uint16_t dcid,
900*4882a593Smuzhiyun 				       uint16_t scid, uint8_t direction)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun 	rtk_prof_info *prof_info = NULL;
903*4882a593Smuzhiyun 	rtk_conn_prof *phci_conn = NULL;
904*4882a593Smuzhiyun 	RTKBT_DBG("%s: handle 0x%04x, dcid 0x%04x, scid 0x%04x, dir %u",
905*4882a593Smuzhiyun 			__func__, handle, dcid, scid, direction);
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	spin_lock(&btrtl_coex.spin_lock_profile);
908*4882a593Smuzhiyun 	if (!direction)		//0: in
909*4882a593Smuzhiyun 		prof_info =
910*4882a593Smuzhiyun 		    find_profile_by_handle_dcid_scid(&btrtl_coex, handle,
911*4882a593Smuzhiyun 						     scid, dcid);
912*4882a593Smuzhiyun 	else			//1: out
913*4882a593Smuzhiyun 		prof_info =
914*4882a593Smuzhiyun 		    find_profile_by_handle_dcid_scid(&btrtl_coex, handle,
915*4882a593Smuzhiyun 						     dcid, scid);
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	if (!prof_info) {
918*4882a593Smuzhiyun 		//LogMsg("handle_l2cap_discon_req: prof_info Not Find!");
919*4882a593Smuzhiyun 		spin_unlock(&btrtl_coex.spin_lock_profile);
920*4882a593Smuzhiyun 		return 0;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	phci_conn = find_connection_by_handle(&btrtl_coex, handle);
924*4882a593Smuzhiyun 	if (!phci_conn) {
925*4882a593Smuzhiyun 		spin_unlock(&btrtl_coex.spin_lock_profile);
926*4882a593Smuzhiyun 		return 0;
927*4882a593Smuzhiyun 	}
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	update_profile_connection(phci_conn, prof_info->profile_index, FALSE);
930*4882a593Smuzhiyun 	if (prof_info->profile_index == profile_a2dp &&
931*4882a593Smuzhiyun 	    (phci_conn->profile_bitmap & BIT(profile_sink)))
932*4882a593Smuzhiyun 		update_profile_connection(phci_conn, profile_sink, FALSE);
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	delete_profile_from_hash(prof_info);
935*4882a593Smuzhiyun 	spin_unlock(&btrtl_coex.spin_lock_profile);
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	return 1;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun static const char sample_freqs[4][8] = {
941*4882a593Smuzhiyun 	"16", "32", "44.1", "48"
942*4882a593Smuzhiyun };
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun static const uint8_t sbc_blocks[4] = { 4, 8, 12, 16 };
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun static const char chan_modes[4][16] = {
947*4882a593Smuzhiyun 	"MONO", "DUAL_CHANNEL", "STEREO", "JOINT_STEREO"
948*4882a593Smuzhiyun };
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun static const char alloc_methods[2][12] = {
951*4882a593Smuzhiyun 	"LOUDNESS", "SNR"
952*4882a593Smuzhiyun };
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun static const uint8_t subbands[2] = { 4, 8 };
955*4882a593Smuzhiyun 
print_sbc_header(struct sbc_frame_hdr * hdr)956*4882a593Smuzhiyun void print_sbc_header(struct sbc_frame_hdr *hdr)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun 	RTKBT_DBG("syncword: %02x", hdr->syncword);
959*4882a593Smuzhiyun 	RTKBT_DBG("freq %skHz", sample_freqs[hdr->sampling_frequency]);
960*4882a593Smuzhiyun 	RTKBT_DBG("blocks %u", sbc_blocks[hdr->blocks]);
961*4882a593Smuzhiyun 	RTKBT_DBG("channel mode %s", chan_modes[hdr->channel_mode]);
962*4882a593Smuzhiyun 	RTKBT_DBG("allocation method %s",
963*4882a593Smuzhiyun 		  alloc_methods[hdr->allocation_method]);
964*4882a593Smuzhiyun 	RTKBT_DBG("subbands %u", subbands[hdr->subbands]);
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun 
packets_count(uint16_t handle,uint16_t scid,uint16_t length,uint8_t direction,u8 * user_data)967*4882a593Smuzhiyun static void packets_count(uint16_t handle, uint16_t scid, uint16_t length,
968*4882a593Smuzhiyun 			  uint8_t direction, u8 *user_data)
969*4882a593Smuzhiyun {
970*4882a593Smuzhiyun 	rtk_prof_info *prof_info = NULL;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	rtk_conn_prof *hci_conn =
973*4882a593Smuzhiyun 	    find_connection_by_handle(&btrtl_coex, handle);
974*4882a593Smuzhiyun 	if (NULL == hci_conn)
975*4882a593Smuzhiyun 		return;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	if (0 == hci_conn->type) {
978*4882a593Smuzhiyun 		if (!direction)	//0: in
979*4882a593Smuzhiyun 			prof_info =
980*4882a593Smuzhiyun 			    find_profile_by_handle_scid(&btrtl_coex, handle,
981*4882a593Smuzhiyun 							scid);
982*4882a593Smuzhiyun 		else		//1: out
983*4882a593Smuzhiyun 			prof_info =
984*4882a593Smuzhiyun 			    find_profile_by_handle_dcid(&btrtl_coex, handle,
985*4882a593Smuzhiyun 							scid);
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 		if (!prof_info) {
988*4882a593Smuzhiyun 			//RTKBT_DBG("packets_count: prof_info Not Find!");
989*4882a593Smuzhiyun 			return;
990*4882a593Smuzhiyun 		}
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 		/* avdtp media data */
993*4882a593Smuzhiyun 		if (prof_info->profile_index == profile_a2dp &&
994*4882a593Smuzhiyun 		    prof_info->flags == A2DP_MEDIA) {
995*4882a593Smuzhiyun 			if (!is_profile_busy(profile_a2dp)) {
996*4882a593Smuzhiyun 				struct sbc_frame_hdr *sbc_header;
997*4882a593Smuzhiyun 				struct rtp_header *rtph;
998*4882a593Smuzhiyun 				u8 bitpool;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 				update_profile_state(profile_a2dp, TRUE);
1001*4882a593Smuzhiyun 				if (!direction) {
1002*4882a593Smuzhiyun 					if (!(hci_conn->profile_bitmap & BIT(profile_sink))) {
1003*4882a593Smuzhiyun 						btrtl_coex.profile_bitmap |= BIT(profile_sink);
1004*4882a593Smuzhiyun 						hci_conn->profile_bitmap |= BIT(profile_sink);
1005*4882a593Smuzhiyun 						update_profile_connection(hci_conn, profile_sink, 1);
1006*4882a593Smuzhiyun 					}
1007*4882a593Smuzhiyun 					update_profile_state(profile_sink, TRUE);
1008*4882a593Smuzhiyun 				}
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 				/* We assume it is SBC if the packet length
1011*4882a593Smuzhiyun 				 * is bigger than 100 bytes
1012*4882a593Smuzhiyun 				 */
1013*4882a593Smuzhiyun 				if (length > 100) {
1014*4882a593Smuzhiyun 					RTKBT_INFO("Length %u", length);
1015*4882a593Smuzhiyun 					rtph = (struct rtp_header *)user_data;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 					RTKBT_DBG("rtp: v %u, cc %u, pt %u",
1018*4882a593Smuzhiyun 						  rtph->v, rtph->cc, rtph->pt);
1019*4882a593Smuzhiyun 					/* move forward */
1020*4882a593Smuzhiyun 					user_data += sizeof(struct rtp_header) +
1021*4882a593Smuzhiyun 						rtph->cc * 4 + 1;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 					/* point to the sbc frame header */
1024*4882a593Smuzhiyun 					sbc_header = (struct sbc_frame_hdr *)user_data;
1025*4882a593Smuzhiyun 					bitpool = sbc_header->bitpool;
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 					print_sbc_header(sbc_header);
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 					RTKBT_DBG("bitpool %u", bitpool);
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 					rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_BITPOOL,
1032*4882a593Smuzhiyun 							1, &bitpool);
1033*4882a593Smuzhiyun 				}
1034*4882a593Smuzhiyun 			}
1035*4882a593Smuzhiyun 			btrtl_coex.a2dp_packet_count++;
1036*4882a593Smuzhiyun 		}
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 		if (prof_info->profile_index == profile_pan)
1039*4882a593Smuzhiyun 			btrtl_coex.pan_packet_count++;
1040*4882a593Smuzhiyun 	}
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
count_a2dp_packet_timeout(struct timer_list * unused)1044*4882a593Smuzhiyun static void count_a2dp_packet_timeout(struct timer_list *unused)
1045*4882a593Smuzhiyun #else
1046*4882a593Smuzhiyun static void count_a2dp_packet_timeout(unsigned long data)
1047*4882a593Smuzhiyun #endif
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun 	if (btrtl_coex.a2dp_packet_count)
1050*4882a593Smuzhiyun 		RTKBT_DBG("%s: a2dp_packet_count %d", __func__,
1051*4882a593Smuzhiyun 			  btrtl_coex.a2dp_packet_count);
1052*4882a593Smuzhiyun 	if (btrtl_coex.a2dp_packet_count == 0) {
1053*4882a593Smuzhiyun 		if (is_profile_busy(profile_a2dp)) {
1054*4882a593Smuzhiyun 			RTKBT_DBG("%s: a2dp busy->idle!", __func__);
1055*4882a593Smuzhiyun 			update_profile_state(profile_a2dp, FALSE);
1056*4882a593Smuzhiyun 			if (btrtl_coex.profile_bitmap & BIT(profile_sink))
1057*4882a593Smuzhiyun 				update_profile_state(profile_sink, FALSE);
1058*4882a593Smuzhiyun 		}
1059*4882a593Smuzhiyun 	}
1060*4882a593Smuzhiyun 	btrtl_coex.a2dp_packet_count = 0;
1061*4882a593Smuzhiyun 	mod_timer(&btrtl_coex.a2dp_count_timer,
1062*4882a593Smuzhiyun 		  jiffies + msecs_to_jiffies(1000));
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
count_pan_packet_timeout(struct timer_list * unused)1066*4882a593Smuzhiyun static void count_pan_packet_timeout(struct timer_list *unused)
1067*4882a593Smuzhiyun #else
1068*4882a593Smuzhiyun static void count_pan_packet_timeout(unsigned long data)
1069*4882a593Smuzhiyun #endif
1070*4882a593Smuzhiyun {
1071*4882a593Smuzhiyun 	if (btrtl_coex.pan_packet_count)
1072*4882a593Smuzhiyun 		RTKBT_DBG("%s: pan_packet_count %d", __func__,
1073*4882a593Smuzhiyun 			  btrtl_coex.pan_packet_count);
1074*4882a593Smuzhiyun 	if (btrtl_coex.pan_packet_count < PAN_PACKET_COUNT) {
1075*4882a593Smuzhiyun 		if (is_profile_busy(profile_pan)) {
1076*4882a593Smuzhiyun 			RTKBT_DBG("%s: pan busy->idle!", __func__);
1077*4882a593Smuzhiyun 			update_profile_state(profile_pan, FALSE);
1078*4882a593Smuzhiyun 		}
1079*4882a593Smuzhiyun 	} else {
1080*4882a593Smuzhiyun 		if (!is_profile_busy(profile_pan)) {
1081*4882a593Smuzhiyun 			RTKBT_DBG("timeout_handler: pan idle->busy!");
1082*4882a593Smuzhiyun 			update_profile_state(profile_pan, TRUE);
1083*4882a593Smuzhiyun 		}
1084*4882a593Smuzhiyun 	}
1085*4882a593Smuzhiyun 	btrtl_coex.pan_packet_count = 0;
1086*4882a593Smuzhiyun 	mod_timer(&btrtl_coex.pan_count_timer,
1087*4882a593Smuzhiyun 		  jiffies + msecs_to_jiffies(1000));
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
count_hogp_packet_timeout(struct timer_list * unused)1091*4882a593Smuzhiyun static void count_hogp_packet_timeout(struct timer_list *unused)
1092*4882a593Smuzhiyun #else
1093*4882a593Smuzhiyun static void count_hogp_packet_timeout(unsigned long data)
1094*4882a593Smuzhiyun #endif
1095*4882a593Smuzhiyun {
1096*4882a593Smuzhiyun 	if (btrtl_coex.hogp_packet_count)
1097*4882a593Smuzhiyun 		RTKBT_DBG("%s: hogp_packet_count %d", __func__,
1098*4882a593Smuzhiyun 			  btrtl_coex.hogp_packet_count);
1099*4882a593Smuzhiyun 	if (btrtl_coex.hogp_packet_count == 0) {
1100*4882a593Smuzhiyun 		if (is_profile_busy(profile_hogp)) {
1101*4882a593Smuzhiyun 			RTKBT_DBG("%s: hogp busy->idle!", __func__);
1102*4882a593Smuzhiyun 			update_profile_state(profile_hogp, FALSE);
1103*4882a593Smuzhiyun 		}
1104*4882a593Smuzhiyun 	}
1105*4882a593Smuzhiyun 	btrtl_coex.hogp_packet_count = 0;
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	if (btrtl_coex.voice_packet_count)
1108*4882a593Smuzhiyun 		RTKBT_DBG("%s: voice_packet_count %d", __func__,
1109*4882a593Smuzhiyun 			  btrtl_coex.voice_packet_count);
1110*4882a593Smuzhiyun 	if (btrtl_coex.voice_packet_count == 0) {
1111*4882a593Smuzhiyun 		if (is_profile_busy(profile_voice)) {
1112*4882a593Smuzhiyun 			RTKBT_DBG("%s: voice busy->idle!", __func__);
1113*4882a593Smuzhiyun 			update_profile_state(profile_voice, FALSE);
1114*4882a593Smuzhiyun 		}
1115*4882a593Smuzhiyun 	}
1116*4882a593Smuzhiyun 	btrtl_coex.voice_packet_count = 0;
1117*4882a593Smuzhiyun 	mod_timer(&btrtl_coex.hogp_count_timer,
1118*4882a593Smuzhiyun 		  jiffies + msecs_to_jiffies(1000));
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun #ifndef RTK_COEX_OVER_SYMBOL
udpsocket_send(char * tx_msg,int msg_size)1124*4882a593Smuzhiyun static int udpsocket_send(char *tx_msg, int msg_size)
1125*4882a593Smuzhiyun {
1126*4882a593Smuzhiyun 	u8 error = 0;
1127*4882a593Smuzhiyun 	struct msghdr udpmsg;
1128*4882a593Smuzhiyun 	mm_segment_t oldfs;
1129*4882a593Smuzhiyun 	struct iovec iov;
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 	RTKBT_DBG("send msg %s with len:%d", tx_msg, msg_size);
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	if (btrtl_coex.sock_open) {
1134*4882a593Smuzhiyun 		iov.iov_base = (void *)tx_msg;
1135*4882a593Smuzhiyun 		iov.iov_len = msg_size;
1136*4882a593Smuzhiyun 		udpmsg.msg_name = &btrtl_coex.wifi_addr;
1137*4882a593Smuzhiyun 		udpmsg.msg_namelen = sizeof(struct sockaddr_in);
1138*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
1139*4882a593Smuzhiyun 		udpmsg.msg_iov = &iov;
1140*4882a593Smuzhiyun 		udpmsg.msg_iovlen = 1;
1141*4882a593Smuzhiyun #else
1142*4882a593Smuzhiyun 		iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size);
1143*4882a593Smuzhiyun #endif
1144*4882a593Smuzhiyun 		udpmsg.msg_control = NULL;
1145*4882a593Smuzhiyun 		udpmsg.msg_controllen = 0;
1146*4882a593Smuzhiyun 		udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
1147*4882a593Smuzhiyun 		oldfs = get_fs();
1148*4882a593Smuzhiyun 		set_fs(KERNEL_DS);
1149*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
1150*4882a593Smuzhiyun 		error = sock_sendmsg(btrtl_coex.udpsock, &udpmsg, msg_size);
1151*4882a593Smuzhiyun #else
1152*4882a593Smuzhiyun 		error = sock_sendmsg(btrtl_coex.udpsock, &udpmsg);
1153*4882a593Smuzhiyun #endif
1154*4882a593Smuzhiyun 		set_fs(oldfs);
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 		if (error < 0)
1157*4882a593Smuzhiyun 			RTKBT_DBG("Error when sendimg msg, error:%d", error);
1158*4882a593Smuzhiyun 	}
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	return error;
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun #endif
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
1165*4882a593Smuzhiyun /* Receive message from WiFi */
rtw_btcoex_wifi_to_bt(u8 * msg,u8 msg_size)1166*4882a593Smuzhiyun u8 rtw_btcoex_wifi_to_bt(u8 *msg, u8 msg_size)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	struct sk_buff *nskb;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	if (!rtw_coex_on) {
1171*4882a593Smuzhiyun 		RTKBT_WARN("Bluetooth is closed");
1172*4882a593Smuzhiyun 		return 0;
1173*4882a593Smuzhiyun 	}
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	nskb = alloc_skb(msg_size, GFP_ATOMIC);
1176*4882a593Smuzhiyun 	if (!nskb) {
1177*4882a593Smuzhiyun 		RTKBT_ERR("Couldnt alloc skb for WiFi coex message");
1178*4882a593Smuzhiyun 		return 0;
1179*4882a593Smuzhiyun 	}
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 	memcpy(skb_put(nskb, msg_size), msg, msg_size);
1182*4882a593Smuzhiyun 	skb_queue_tail(&rtw_q, nskb);
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	queue_work(rtw_wq, &rtw_work);
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 	return 1;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun EXPORT_SYMBOL(rtw_btcoex_wifi_to_bt);
1189*4882a593Smuzhiyun 
rtk_send_coexmsg2wifi(u8 * msg,u8 size)1190*4882a593Smuzhiyun static int rtk_send_coexmsg2wifi(u8 *msg, u8 size)
1191*4882a593Smuzhiyun {
1192*4882a593Smuzhiyun 	u8 result;
1193*4882a593Smuzhiyun 	u8 (*btmsg_to_wifi)(u8 *, u8);
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	btmsg_to_wifi = __symbol_get(VMLINUX_SYMBOL_STR(rtw_btcoex_bt_to_wifi));
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	if (!btmsg_to_wifi) {
1198*4882a593Smuzhiyun 		/* RTKBT_ERR("Couldnt get symbol"); */
1199*4882a593Smuzhiyun 		return -1;
1200*4882a593Smuzhiyun 	}
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	result = btmsg_to_wifi(msg, size);
1203*4882a593Smuzhiyun 	__symbol_put(VMLINUX_SYMBOL_STR(rtw_btcoex_bt_to_wifi));
1204*4882a593Smuzhiyun 	if (!result) {
1205*4882a593Smuzhiyun 		RTKBT_ERR("Couldnt send coex msg to WiFi");
1206*4882a593Smuzhiyun 		return -1;
1207*4882a593Smuzhiyun 	} else if (result == 1){
1208*4882a593Smuzhiyun 		/* successful to send message */
1209*4882a593Smuzhiyun 		return 0;
1210*4882a593Smuzhiyun 	} else {
1211*4882a593Smuzhiyun 		RTKBT_ERR("Unknown result %d", result);
1212*4882a593Smuzhiyun 		return -1;
1213*4882a593Smuzhiyun 	}
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun 
rtkbt_process_coexskb(struct sk_buff * skb)1216*4882a593Smuzhiyun static int rtkbt_process_coexskb(struct sk_buff *skb)
1217*4882a593Smuzhiyun {
1218*4882a593Smuzhiyun 	rtk_handle_event_from_wifi(skb->data);
1219*4882a593Smuzhiyun 	return 0;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun 
rtw_work_func(struct work_struct * work)1222*4882a593Smuzhiyun static void rtw_work_func(struct work_struct *work)
1223*4882a593Smuzhiyun {
1224*4882a593Smuzhiyun 	struct sk_buff *skb;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	while ((skb = skb_dequeue(&rtw_q))) {
1227*4882a593Smuzhiyun 		rtkbt_process_coexskb(skb);
1228*4882a593Smuzhiyun 		kfree_skb(skb);
1229*4882a593Smuzhiyun 	}
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun #endif
1233*4882a593Smuzhiyun 
rtkbt_coexmsg_send(char * tx_msg,int msg_size)1234*4882a593Smuzhiyun static int rtkbt_coexmsg_send(char *tx_msg, int msg_size)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
1237*4882a593Smuzhiyun 	return rtk_send_coexmsg2wifi((uint8_t *)tx_msg, (u8)msg_size);
1238*4882a593Smuzhiyun #else
1239*4882a593Smuzhiyun 	return udpsocket_send(tx_msg, msg_size);
1240*4882a593Smuzhiyun #endif
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun #ifndef RTK_COEX_OVER_SYMBOL
udpsocket_recv_data(void)1244*4882a593Smuzhiyun static void udpsocket_recv_data(void)
1245*4882a593Smuzhiyun {
1246*4882a593Smuzhiyun 	u8 recv_data[512];
1247*4882a593Smuzhiyun 	u32 len = 0;
1248*4882a593Smuzhiyun 	u16 recv_length;
1249*4882a593Smuzhiyun 	struct sk_buff *skb;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	RTKBT_DBG("-");
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	spin_lock(&btrtl_coex.spin_lock_sock);
1254*4882a593Smuzhiyun 	len = skb_queue_len(&btrtl_coex.sk->sk_receive_queue);
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	while (len > 0) {
1257*4882a593Smuzhiyun 		skb = skb_dequeue(&btrtl_coex.sk->sk_receive_queue);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 		/*important: cut the udp header from skb->data! header length is 8 byte */
1260*4882a593Smuzhiyun 		recv_length = skb->len - 8;
1261*4882a593Smuzhiyun 		memset(recv_data, 0, sizeof(recv_data));
1262*4882a593Smuzhiyun 		memcpy(recv_data, skb->data + 8, recv_length);
1263*4882a593Smuzhiyun 		//RTKBT_DBG("received data: %s :with len %u", recv_data, recv_length);
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 		rtk_handle_event_from_wifi(recv_data);
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 		len--;
1268*4882a593Smuzhiyun 		kfree_skb(skb);
1269*4882a593Smuzhiyun 	}
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	spin_unlock(&btrtl_coex.spin_lock_sock);
1272*4882a593Smuzhiyun }
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
udpsocket_recv(struct sock * sk,int bytes)1275*4882a593Smuzhiyun static void udpsocket_recv(struct sock *sk, int bytes)
1276*4882a593Smuzhiyun #else
1277*4882a593Smuzhiyun static void udpsocket_recv(struct sock *sk)
1278*4882a593Smuzhiyun #endif
1279*4882a593Smuzhiyun {
1280*4882a593Smuzhiyun 	spin_lock(&btrtl_coex.spin_lock_sock);
1281*4882a593Smuzhiyun 	btrtl_coex.sk = sk;
1282*4882a593Smuzhiyun 	spin_unlock(&btrtl_coex.spin_lock_sock);
1283*4882a593Smuzhiyun 	queue_delayed_work(btrtl_coex.sock_wq, &btrtl_coex.sock_work, 0);
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun 
create_udpsocket(void)1286*4882a593Smuzhiyun static void create_udpsocket(void)
1287*4882a593Smuzhiyun {
1288*4882a593Smuzhiyun 	int err;
1289*4882a593Smuzhiyun 	RTKBT_DBG("%s: connect_port: %d", __func__, CONNECT_PORT);
1290*4882a593Smuzhiyun 	btrtl_coex.sock_open = 0;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
1293*4882a593Smuzhiyun 			&btrtl_coex.udpsock);
1294*4882a593Smuzhiyun 	if (err < 0) {
1295*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock create error, err = %d", __func__, err);
1296*4882a593Smuzhiyun 		return;
1297*4882a593Smuzhiyun 	}
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	memset(&btrtl_coex.addr, 0, sizeof(struct sockaddr_in));
1300*4882a593Smuzhiyun 	btrtl_coex.addr.sin_family = AF_INET;
1301*4882a593Smuzhiyun 	btrtl_coex.addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1302*4882a593Smuzhiyun 	btrtl_coex.addr.sin_port = htons(CONNECT_PORT);
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	memset(&btrtl_coex.wifi_addr, 0, sizeof(struct sockaddr_in));
1305*4882a593Smuzhiyun 	btrtl_coex.wifi_addr.sin_family = AF_INET;
1306*4882a593Smuzhiyun 	btrtl_coex.wifi_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1307*4882a593Smuzhiyun 	btrtl_coex.wifi_addr.sin_port = htons(CONNECT_PORT_WIFI);
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	err =
1310*4882a593Smuzhiyun 	    btrtl_coex.udpsock->ops->bind(btrtl_coex.udpsock,
1311*4882a593Smuzhiyun 					     (struct sockaddr *)&btrtl_coex.
1312*4882a593Smuzhiyun 					     addr, sizeof(struct sockaddr));
1313*4882a593Smuzhiyun 	if (err < 0) {
1314*4882a593Smuzhiyun 		sock_release(btrtl_coex.udpsock);
1315*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock bind error, err = %d",__func__,  err);
1316*4882a593Smuzhiyun 		return;
1317*4882a593Smuzhiyun 	}
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	btrtl_coex.sock_open = 1;
1320*4882a593Smuzhiyun 	btrtl_coex.udpsock->sk->sk_data_ready = udpsocket_recv;
1321*4882a593Smuzhiyun }
1322*4882a593Smuzhiyun #endif /* !RTK_COEX_OVER_SYMBOL */
1323*4882a593Smuzhiyun 
rtk_notify_extension_version_to_wifi(void)1324*4882a593Smuzhiyun static void rtk_notify_extension_version_to_wifi(void)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun 	uint8_t para_length = 2;
1327*4882a593Smuzhiyun 	char p_buf[2 + HCI_CMD_PREAMBLE_SIZE];
1328*4882a593Smuzhiyun 	char *p = p_buf;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1331*4882a593Smuzhiyun 		return;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_HCI_EXTENSION_VERSION_NOTIFY);
1334*4882a593Smuzhiyun 	*p++ = para_length;
1335*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_EXTENSION_VERSION);
1336*4882a593Smuzhiyun 	RTKBT_DBG("extension version is 0x%x", HCI_EXTENSION_VERSION);
1337*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1338*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun 
rtk_notify_btpatch_version_to_wifi(void)1341*4882a593Smuzhiyun static void rtk_notify_btpatch_version_to_wifi(void)
1342*4882a593Smuzhiyun {
1343*4882a593Smuzhiyun 	uint8_t para_length = 4;
1344*4882a593Smuzhiyun 	char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
1345*4882a593Smuzhiyun 	char *p = p_buf;
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1348*4882a593Smuzhiyun 		return;
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_HCI_BT_PATCH_VER_NOTIFY);
1351*4882a593Smuzhiyun 	*p++ = para_length;
1352*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, btrtl_coex.hci_reversion);
1353*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, btrtl_coex.lmp_subversion);
1354*4882a593Smuzhiyun 	RTKBT_DBG("btpatch ver: len %u, hci_rev 0x%04x, lmp_subver 0x%04x",
1355*4882a593Smuzhiyun 			para_length, btrtl_coex.hci_reversion,
1356*4882a593Smuzhiyun 			btrtl_coex.lmp_subversion);
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1359*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun 
rtk_notify_afhmap_to_wifi(void)1362*4882a593Smuzhiyun static void rtk_notify_afhmap_to_wifi(void)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun 	uint8_t para_length = 13;
1365*4882a593Smuzhiyun 	char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
1366*4882a593Smuzhiyun 	char *p = p_buf;
1367*4882a593Smuzhiyun 	uint8_t kk = 0;
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1370*4882a593Smuzhiyun 		return;
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_HCI_BT_AFH_MAP_NOTIFY);
1373*4882a593Smuzhiyun 	*p++ = para_length;
1374*4882a593Smuzhiyun 	*p++ = btrtl_coex.piconet_id;
1375*4882a593Smuzhiyun 	*p++ = btrtl_coex.mode;
1376*4882a593Smuzhiyun 	*p++ = 10;
1377*4882a593Smuzhiyun 	memcpy(p, btrtl_coex.afh_map, 10);
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	RTKBT_DBG("afhmap, piconet_id is 0x%x, map type is 0x%x",
1380*4882a593Smuzhiyun 		  btrtl_coex.piconet_id, btrtl_coex.mode);
1381*4882a593Smuzhiyun 	for (kk = 0; kk < 10; kk++)
1382*4882a593Smuzhiyun 		RTKBT_DBG("afhmap data[%d] is 0x%x", kk,
1383*4882a593Smuzhiyun 			  btrtl_coex.afh_map[kk]);
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1386*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun 
rtk_notify_btcoex_to_wifi(uint8_t opcode,uint8_t status)1389*4882a593Smuzhiyun static void rtk_notify_btcoex_to_wifi(uint8_t opcode, uint8_t status)
1390*4882a593Smuzhiyun {
1391*4882a593Smuzhiyun 	uint8_t para_length = 2;
1392*4882a593Smuzhiyun 	char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
1393*4882a593Smuzhiyun 	char *p = p_buf;
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1396*4882a593Smuzhiyun 		return;
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_HCI_BT_COEX_NOTIFY);
1399*4882a593Smuzhiyun 	*p++ = para_length;
1400*4882a593Smuzhiyun 	*p++ = opcode;
1401*4882a593Smuzhiyun 	if (!status)
1402*4882a593Smuzhiyun 		*p++ = 0;
1403*4882a593Smuzhiyun 	else
1404*4882a593Smuzhiyun 		*p++ = 1;
1405*4882a593Smuzhiyun 
1406*4882a593Smuzhiyun 	RTKBT_DBG("btcoex, opcode is 0x%x, status is 0x%x", opcode, status);
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1409*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1410*4882a593Smuzhiyun }
1411*4882a593Smuzhiyun 
rtk_notify_btoperation_to_wifi(uint8_t operation,uint8_t append_data_length,uint8_t * append_data)1412*4882a593Smuzhiyun static void rtk_notify_btoperation_to_wifi(uint8_t operation,
1413*4882a593Smuzhiyun 					   uint8_t append_data_length,
1414*4882a593Smuzhiyun 					   uint8_t * append_data)
1415*4882a593Smuzhiyun {
1416*4882a593Smuzhiyun 	uint8_t para_length = 3 + append_data_length;
1417*4882a593Smuzhiyun 	char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
1418*4882a593Smuzhiyun 	char *p = p_buf;
1419*4882a593Smuzhiyun 	uint8_t kk = 0;
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1422*4882a593Smuzhiyun 		return;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_BT_OPERATION_NOTIFY);
1425*4882a593Smuzhiyun 	*p++ = para_length;
1426*4882a593Smuzhiyun 	*p++ = operation;
1427*4882a593Smuzhiyun 	*p++ = append_data_length;
1428*4882a593Smuzhiyun 	if (append_data_length)
1429*4882a593Smuzhiyun 		memcpy(p, append_data, append_data_length);
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	RTKBT_DBG("btoperation: op 0x%02x, append_data_length %u",
1432*4882a593Smuzhiyun 		  operation, append_data_length);
1433*4882a593Smuzhiyun 	if (append_data_length) {
1434*4882a593Smuzhiyun 		for (kk = 0; kk < append_data_length; kk++)
1435*4882a593Smuzhiyun 			RTKBT_DBG("append data is 0x%x", *(append_data + kk));
1436*4882a593Smuzhiyun 	}
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1439*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun 
rtk_notify_info_to_wifi(uint8_t reason,uint8_t length,uint8_t * report_info)1442*4882a593Smuzhiyun static void rtk_notify_info_to_wifi(uint8_t reason, uint8_t length,
1443*4882a593Smuzhiyun 				    uint8_t *report_info)
1444*4882a593Smuzhiyun {
1445*4882a593Smuzhiyun 	uint8_t para_length = 4 + length;
1446*4882a593Smuzhiyun 	char buf[para_length + HCI_CMD_PREAMBLE_SIZE];
1447*4882a593Smuzhiyun 	char *p = buf;
1448*4882a593Smuzhiyun 	struct rtl_btinfo *report = (struct rtl_btinfo *)report_info;
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	if (length) {
1451*4882a593Smuzhiyun 		RTKBT_DBG("bt info: cmd %2.2X", report->cmd);
1452*4882a593Smuzhiyun 		RTKBT_DBG("bt info: len %2.2X", report->len);
1453*4882a593Smuzhiyun 		RTKBT_DBG("bt info: data %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X",
1454*4882a593Smuzhiyun 			  report->data[0], report->data[1], report->data[2],
1455*4882a593Smuzhiyun 			  report->data[3], report->data[4], report->data[5]);
1456*4882a593Smuzhiyun 	}
1457*4882a593Smuzhiyun 	RTKBT_DBG("bt info: reason 0x%2x, length 0x%2x", reason, length);
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1460*4882a593Smuzhiyun 		return;
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_HCI_BT_INFO_NOTIFY);
1463*4882a593Smuzhiyun 	*p++ = para_length;
1464*4882a593Smuzhiyun 	*p++ = btrtl_coex.polling_enable;
1465*4882a593Smuzhiyun 	*p++ = btrtl_coex.polling_interval;
1466*4882a593Smuzhiyun 	*p++ = reason;
1467*4882a593Smuzhiyun 	*p++ = length;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	if (length)
1470*4882a593Smuzhiyun 		memcpy(p, report_info, length);
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	RTKBT_DBG("para length %2x, polling_enable %u, poiiling_interval %u",
1473*4882a593Smuzhiyun 	     para_length, btrtl_coex.polling_enable,
1474*4882a593Smuzhiyun 	     btrtl_coex.polling_interval);
1475*4882a593Smuzhiyun 	/* send BT INFO to Wi-Fi driver */
1476*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1477*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun 
rtk_notify_regester_to_wifi(uint8_t * reg_value)1480*4882a593Smuzhiyun static void rtk_notify_regester_to_wifi(uint8_t * reg_value)
1481*4882a593Smuzhiyun {
1482*4882a593Smuzhiyun 	uint8_t para_length = 9;
1483*4882a593Smuzhiyun 	char p_buf[para_length + HCI_CMD_PREAMBLE_SIZE];
1484*4882a593Smuzhiyun 	char *p = p_buf;
1485*4882a593Smuzhiyun 	hci_mailbox_register *reg = (hci_mailbox_register *) reg_value;
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	if (!btrtl_coex.wifi_on)
1488*4882a593Smuzhiyun 		return;
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	UINT16_TO_STREAM(p, HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY);
1491*4882a593Smuzhiyun 	*p++ = para_length;
1492*4882a593Smuzhiyun 	memcpy(p, reg_value, para_length);
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	RTKBT_DBG("bt register, register type is %x", reg->type);
1495*4882a593Smuzhiyun 	RTKBT_DBG("bt register, register offset is %x", reg->offset);
1496*4882a593Smuzhiyun 	RTKBT_DBG("bt register, register value is %x", reg->value);
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	if (rtkbt_coexmsg_send(p_buf, para_length + HCI_CMD_PREAMBLE_SIZE) < 0)
1499*4882a593Smuzhiyun 		RTKBT_ERR("%s: sock send error", __func__);
1500*4882a593Smuzhiyun }
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun #endif
1503*4882a593Smuzhiyun 
rtk_btcoex_parse_cmd(uint8_t * buffer,int count)1504*4882a593Smuzhiyun void rtk_btcoex_parse_cmd(uint8_t *buffer, int count)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun 	u16 opcode = (buffer[0]) + (buffer[1] << 8);
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 	if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
1509*4882a593Smuzhiyun 		RTKBT_INFO("%s: Coex is closed, ignore", __func__);
1510*4882a593Smuzhiyun 		return;
1511*4882a593Smuzhiyun 	}
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	switch (opcode) {
1514*4882a593Smuzhiyun 	case HCI_OP_INQUIRY:
1515*4882a593Smuzhiyun 	case HCI_OP_PERIODIC_INQ:
1516*4882a593Smuzhiyun 		if (!btrtl_coex.isinquirying) {
1517*4882a593Smuzhiyun 			btrtl_coex.isinquirying = 1;
1518*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1519*4882a593Smuzhiyun 			RTKBT_DBG("hci (periodic)inq, notify wifi "
1520*4882a593Smuzhiyun 				  "inquiry start");
1521*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_START,
1522*4882a593Smuzhiyun 						       0, NULL);
1523*4882a593Smuzhiyun #else
1524*4882a593Smuzhiyun 			RTKBT_INFO("hci (periodic)inq start");
1525*4882a593Smuzhiyun #endif
1526*4882a593Smuzhiyun 		}
1527*4882a593Smuzhiyun 		break;
1528*4882a593Smuzhiyun 	case HCI_OP_INQUIRY_CANCEL:
1529*4882a593Smuzhiyun 	case HCI_OP_EXIT_PERIODIC_INQ:
1530*4882a593Smuzhiyun 		if (btrtl_coex.isinquirying) {
1531*4882a593Smuzhiyun 			btrtl_coex.isinquirying = 0;
1532*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1533*4882a593Smuzhiyun 			RTKBT_DBG("hci (periodic)inq cancel/exit, notify wifi "
1534*4882a593Smuzhiyun 				  "inquiry stop");
1535*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0,
1536*4882a593Smuzhiyun 						       NULL);
1537*4882a593Smuzhiyun #else
1538*4882a593Smuzhiyun 			RTKBT_INFO("hci (periodic)inq cancel/exit");
1539*4882a593Smuzhiyun #endif
1540*4882a593Smuzhiyun 		}
1541*4882a593Smuzhiyun 		break;
1542*4882a593Smuzhiyun 	case HCI_OP_ACCEPT_CONN_REQ:
1543*4882a593Smuzhiyun 		if (!btrtl_coex.ispaging) {
1544*4882a593Smuzhiyun 			btrtl_coex.ispaging = 1;
1545*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1546*4882a593Smuzhiyun 			RTKBT_DBG("hci accept connreq, notify wifi page start");
1547*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0,
1548*4882a593Smuzhiyun 						       NULL);
1549*4882a593Smuzhiyun #else
1550*4882a593Smuzhiyun 			RTKBT_INFO("hci accept conn req");
1551*4882a593Smuzhiyun #endif
1552*4882a593Smuzhiyun 		}
1553*4882a593Smuzhiyun 		break;
1554*4882a593Smuzhiyun 	case HCI_OP_DISCONNECT:
1555*4882a593Smuzhiyun 		RTKBT_INFO("HCI Disconnect, handle %04x, reason 0x%02x",
1556*4882a593Smuzhiyun 			   ((u16)buffer[4] << 8 | buffer[3]), buffer[5]);
1557*4882a593Smuzhiyun 		break;
1558*4882a593Smuzhiyun 	default:
1559*4882a593Smuzhiyun 		break;
1560*4882a593Smuzhiyun 	}
1561*4882a593Smuzhiyun }
1562*4882a593Smuzhiyun 
rtk_handle_inquiry_complete(void)1563*4882a593Smuzhiyun static void rtk_handle_inquiry_complete(void)
1564*4882a593Smuzhiyun {
1565*4882a593Smuzhiyun 	if (btrtl_coex.isinquirying) {
1566*4882a593Smuzhiyun 		btrtl_coex.isinquirying = 0;
1567*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1568*4882a593Smuzhiyun 		RTKBT_DBG("inq complete, notify wifi inquiry end");
1569*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0, NULL);
1570*4882a593Smuzhiyun #else
1571*4882a593Smuzhiyun 		RTKBT_INFO("inquiry complete");
1572*4882a593Smuzhiyun #endif
1573*4882a593Smuzhiyun 	}
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun 
rtk_handle_pin_code_req(void)1576*4882a593Smuzhiyun static void rtk_handle_pin_code_req(void)
1577*4882a593Smuzhiyun {
1578*4882a593Smuzhiyun 	if (!btrtl_coex.ispairing) {
1579*4882a593Smuzhiyun 		btrtl_coex.ispairing = 1;
1580*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1581*4882a593Smuzhiyun 		RTKBT_DBG("pin code req, notify wifi pair start");
1582*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL);
1583*4882a593Smuzhiyun #else
1584*4882a593Smuzhiyun 		RTKBT_INFO("pin code request");
1585*4882a593Smuzhiyun #endif
1586*4882a593Smuzhiyun 	}
1587*4882a593Smuzhiyun }
1588*4882a593Smuzhiyun 
rtk_handle_io_capa_req(void)1589*4882a593Smuzhiyun static void rtk_handle_io_capa_req(void)
1590*4882a593Smuzhiyun {
1591*4882a593Smuzhiyun 	if (!btrtl_coex.ispairing) {
1592*4882a593Smuzhiyun 		btrtl_coex.ispairing = 1;
1593*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1594*4882a593Smuzhiyun 		RTKBT_DBG("io cap req, notify wifi pair start");
1595*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_START, 0, NULL);
1596*4882a593Smuzhiyun #else
1597*4882a593Smuzhiyun 		RTKBT_INFO("io capability request");
1598*4882a593Smuzhiyun #endif
1599*4882a593Smuzhiyun 	}
1600*4882a593Smuzhiyun }
1601*4882a593Smuzhiyun 
rtk_handle_auth_request(void)1602*4882a593Smuzhiyun static void rtk_handle_auth_request(void)
1603*4882a593Smuzhiyun {
1604*4882a593Smuzhiyun 	if (btrtl_coex.ispairing) {
1605*4882a593Smuzhiyun 		btrtl_coex.ispairing = 0;
1606*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1607*4882a593Smuzhiyun 		RTKBT_DBG("auth req, notify wifi pair end");
1608*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL);
1609*4882a593Smuzhiyun #else
1610*4882a593Smuzhiyun 		RTKBT_INFO("authentication request");
1611*4882a593Smuzhiyun #endif
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun 
rtk_handle_link_key_notify(void)1615*4882a593Smuzhiyun static void rtk_handle_link_key_notify(void)
1616*4882a593Smuzhiyun {
1617*4882a593Smuzhiyun 	if (btrtl_coex.ispairing) {
1618*4882a593Smuzhiyun 		btrtl_coex.ispairing = 0;
1619*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1620*4882a593Smuzhiyun 		RTKBT_DBG("link key notify, notify wifi pair end");
1621*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL);
1622*4882a593Smuzhiyun #else
1623*4882a593Smuzhiyun 		RTKBT_INFO("link key notify");
1624*4882a593Smuzhiyun #endif
1625*4882a593Smuzhiyun 	}
1626*4882a593Smuzhiyun }
1627*4882a593Smuzhiyun 
rtk_handle_mode_change_evt(u8 * p)1628*4882a593Smuzhiyun static void rtk_handle_mode_change_evt(u8 * p)
1629*4882a593Smuzhiyun {
1630*4882a593Smuzhiyun 	u16 mode_change_handle, mode_interval;
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 	p++;
1633*4882a593Smuzhiyun 	STREAM_TO_UINT16(mode_change_handle, p);
1634*4882a593Smuzhiyun 	p++;
1635*4882a593Smuzhiyun 	STREAM_TO_UINT16(mode_interval, p);
1636*4882a593Smuzhiyun 	update_hid_active_state(mode_change_handle, mode_interval);
1637*4882a593Smuzhiyun }
1638*4882a593Smuzhiyun 
1639*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
rtk_parse_vendor_mailbox_cmd_evt(u8 * p,u8 total_len)1640*4882a593Smuzhiyun static void rtk_parse_vendor_mailbox_cmd_evt(u8 * p, u8 total_len)
1641*4882a593Smuzhiyun {
1642*4882a593Smuzhiyun 	u8 status, subcmd;
1643*4882a593Smuzhiyun 	u8 temp_cmd[10];
1644*4882a593Smuzhiyun 
1645*4882a593Smuzhiyun 	status = *p++;
1646*4882a593Smuzhiyun 	if (total_len <= 4) {
1647*4882a593Smuzhiyun 		RTKBT_DBG("receive mailbox cmd from fw, total length <= 4");
1648*4882a593Smuzhiyun 		return;
1649*4882a593Smuzhiyun 	}
1650*4882a593Smuzhiyun 	subcmd = *p++;
1651*4882a593Smuzhiyun 	RTKBT_DBG("receive mailbox cmd from fw, subcmd is 0x%x, status is 0x%x",
1652*4882a593Smuzhiyun 		  subcmd, status);
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	switch (subcmd) {
1655*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO:
1656*4882a593Smuzhiyun 		if (status == 0)	//success
1657*4882a593Smuzhiyun 			rtk_notify_info_to_wifi(POLLING_RESPONSE,
1658*4882a593Smuzhiyun 					RTL_BTINFO_LEN, (uint8_t *)p);
1659*4882a593Smuzhiyun 		break;
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD:
1662*4882a593Smuzhiyun 		rtk_notify_btcoex_to_wifi(WIFI_BW_CHNL_NOTIFY, status);
1663*4882a593Smuzhiyun 		break;
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD:
1666*4882a593Smuzhiyun 		rtk_notify_btcoex_to_wifi(BT_POWER_DECREASE_CONTROL, status);
1667*4882a593Smuzhiyun 		break;
1668*4882a593Smuzhiyun 
1669*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD:
1670*4882a593Smuzhiyun 		rtk_notify_btcoex_to_wifi(IGNORE_WLAN_ACTIVE_CONTROL, status);
1671*4882a593Smuzhiyun 		break;
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE:
1674*4882a593Smuzhiyun 		rtk_notify_btcoex_to_wifi(BT_PSD_MODE_CONTROL, status);
1675*4882a593Smuzhiyun 		break;
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT:
1678*4882a593Smuzhiyun 		rtk_notify_btcoex_to_wifi(LNA_CONSTRAIN_CONTROL, status);
1679*4882a593Smuzhiyun 		break;
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE:
1682*4882a593Smuzhiyun 		break;
1683*4882a593Smuzhiyun 
1684*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM:
1685*4882a593Smuzhiyun 		break;
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE:
1688*4882a593Smuzhiyun 		break;
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L:
1691*4882a593Smuzhiyun 		if (status == 0) {
1692*4882a593Smuzhiyun 			memcpy(btrtl_coex.afh_map, p + 4, 4);	/* cmd_idx, length, piconet_id, mode */
1693*4882a593Smuzhiyun 			temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M;
1694*4882a593Smuzhiyun 			temp_cmd[1] = 2;
1695*4882a593Smuzhiyun 			temp_cmd[2] = btrtl_coex.piconet_id;
1696*4882a593Smuzhiyun 			temp_cmd[3] = btrtl_coex.mode;
1697*4882a593Smuzhiyun 			rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4,
1698*4882a593Smuzhiyun 					     temp_cmd);
1699*4882a593Smuzhiyun 		} else {
1700*4882a593Smuzhiyun 			memset(btrtl_coex.afh_map, 0, 10);
1701*4882a593Smuzhiyun 			rtk_notify_afhmap_to_wifi();
1702*4882a593Smuzhiyun 		}
1703*4882a593Smuzhiyun 		break;
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M:
1706*4882a593Smuzhiyun 		if (status == 0) {
1707*4882a593Smuzhiyun 			memcpy(btrtl_coex.afh_map + 4, p + 4, 4);
1708*4882a593Smuzhiyun 			temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H;
1709*4882a593Smuzhiyun 			temp_cmd[1] = 2;
1710*4882a593Smuzhiyun 			temp_cmd[2] = btrtl_coex.piconet_id;
1711*4882a593Smuzhiyun 			temp_cmd[3] = btrtl_coex.mode;
1712*4882a593Smuzhiyun 			rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4,
1713*4882a593Smuzhiyun 					     temp_cmd);
1714*4882a593Smuzhiyun 		} else {
1715*4882a593Smuzhiyun 			memset(btrtl_coex.afh_map, 0, 10);
1716*4882a593Smuzhiyun 			rtk_notify_afhmap_to_wifi();
1717*4882a593Smuzhiyun 		}
1718*4882a593Smuzhiyun 		break;
1719*4882a593Smuzhiyun 
1720*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H:
1721*4882a593Smuzhiyun 		if (status == 0)
1722*4882a593Smuzhiyun 			memcpy(btrtl_coex.afh_map + 8, p + 4, 2);
1723*4882a593Smuzhiyun 		else
1724*4882a593Smuzhiyun 			memset(btrtl_coex.afh_map, 0, 10);
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 		rtk_notify_afhmap_to_wifi();
1727*4882a593Smuzhiyun 		break;
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_RD_REG_REQ:
1730*4882a593Smuzhiyun 		if (status == 0)
1731*4882a593Smuzhiyun 			rtk_notify_regester_to_wifi(p + 3);	/* cmd_idx,length,regist type */
1732*4882a593Smuzhiyun 		break;
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun 	case HCI_VENDOR_SUB_CMD_WR_REG_REQ:
1735*4882a593Smuzhiyun 		rtk_notify_btcoex_to_wifi(BT_REGISTER_ACCESS, status);
1736*4882a593Smuzhiyun 		break;
1737*4882a593Smuzhiyun 
1738*4882a593Smuzhiyun 	default:
1739*4882a593Smuzhiyun 		break;
1740*4882a593Smuzhiyun 	}
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun #endif /* RTB_SOFTWARE_MAILBOX */
1743*4882a593Smuzhiyun 
rtk_handle_cmd_complete_evt(u8 total_len,u8 * p)1744*4882a593Smuzhiyun static void rtk_handle_cmd_complete_evt(u8 total_len, u8 * p)
1745*4882a593Smuzhiyun {
1746*4882a593Smuzhiyun 	u16 opcode;
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun 	p++;
1749*4882a593Smuzhiyun 	STREAM_TO_UINT16(opcode, p);
1750*4882a593Smuzhiyun 	//RTKBT_DBG("cmd_complete, opcode is 0x%x", opcode);
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 	if (opcode == HCI_OP_PERIODIC_INQ) {
1753*4882a593Smuzhiyun 		if (*p++ && btrtl_coex.isinquirying) {
1754*4882a593Smuzhiyun 			btrtl_coex.isinquirying = 0;
1755*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1756*4882a593Smuzhiyun 			RTKBT_DBG("hci period inq, start error, notify wifi "
1757*4882a593Smuzhiyun 				  "inquiry stop");
1758*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0,
1759*4882a593Smuzhiyun 						       NULL);
1760*4882a593Smuzhiyun #else
1761*4882a593Smuzhiyun 			RTKBT_INFO("hci period inquiry start error");
1762*4882a593Smuzhiyun #endif
1763*4882a593Smuzhiyun 		}
1764*4882a593Smuzhiyun 	}
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 	if (opcode == HCI_OP_READ_LOCAL_VERSION) {
1767*4882a593Smuzhiyun 		if (!(*p++)) {
1768*4882a593Smuzhiyun 			p++;
1769*4882a593Smuzhiyun 			STREAM_TO_UINT16(btrtl_coex.hci_reversion, p);
1770*4882a593Smuzhiyun 			p += 3;
1771*4882a593Smuzhiyun 			STREAM_TO_UINT16(btrtl_coex.lmp_subversion, p);
1772*4882a593Smuzhiyun 			RTKBT_DBG("BTCOEX hci_rev 0x%04x",
1773*4882a593Smuzhiyun 				  btrtl_coex.hci_reversion);
1774*4882a593Smuzhiyun 			RTKBT_DBG("BTCOEX lmp_subver 0x%04x",
1775*4882a593Smuzhiyun 				  btrtl_coex.lmp_subversion);
1776*4882a593Smuzhiyun 		}
1777*4882a593Smuzhiyun 	}
1778*4882a593Smuzhiyun 
1779*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1780*4882a593Smuzhiyun 	if (opcode == HCI_VENDOR_MAILBOX_CMD) {
1781*4882a593Smuzhiyun 		rtk_parse_vendor_mailbox_cmd_evt(p, total_len);
1782*4882a593Smuzhiyun 	}
1783*4882a593Smuzhiyun #endif
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun 
rtk_handle_cmd_status_evt(u8 * p)1786*4882a593Smuzhiyun static void rtk_handle_cmd_status_evt(u8 * p)
1787*4882a593Smuzhiyun {
1788*4882a593Smuzhiyun 	u16 opcode;
1789*4882a593Smuzhiyun 	u8 status;
1790*4882a593Smuzhiyun 
1791*4882a593Smuzhiyun 	status = *p++;
1792*4882a593Smuzhiyun 	p++;
1793*4882a593Smuzhiyun 	STREAM_TO_UINT16(opcode, p);
1794*4882a593Smuzhiyun 	//RTKBT_DBG("cmd_status, opcode is 0x%x", opcode);
1795*4882a593Smuzhiyun 	if ((opcode == HCI_OP_INQUIRY) && (status)) {
1796*4882a593Smuzhiyun 		if (btrtl_coex.isinquirying) {
1797*4882a593Smuzhiyun 			btrtl_coex.isinquirying = 0;
1798*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1799*4882a593Smuzhiyun 			RTKBT_DBG("hci inq, start error, notify wifi inq stop");
1800*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi(BT_OPCODE_INQUIRY_END, 0,
1801*4882a593Smuzhiyun 						       NULL);
1802*4882a593Smuzhiyun #else
1803*4882a593Smuzhiyun 			RTKBT_INFO("hci inquiry start error");
1804*4882a593Smuzhiyun #endif
1805*4882a593Smuzhiyun 		}
1806*4882a593Smuzhiyun 	}
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 	if (opcode == HCI_OP_CREATE_CONN) {
1809*4882a593Smuzhiyun 		if (!status && !btrtl_coex.ispaging) {
1810*4882a593Smuzhiyun 			btrtl_coex.ispaging = 1;
1811*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1812*4882a593Smuzhiyun 			RTKBT_DBG("hci create conn, notify wifi start page");
1813*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_START, 0,
1814*4882a593Smuzhiyun 						       NULL);
1815*4882a593Smuzhiyun #else
1816*4882a593Smuzhiyun 			RTKBT_INFO("hci create connection, start paging");
1817*4882a593Smuzhiyun #endif
1818*4882a593Smuzhiyun 		}
1819*4882a593Smuzhiyun 	}
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun 
rtk_handle_connection_complete_evt(u8 * p)1822*4882a593Smuzhiyun static void rtk_handle_connection_complete_evt(u8 * p)
1823*4882a593Smuzhiyun {
1824*4882a593Smuzhiyun 	u16 handle;
1825*4882a593Smuzhiyun 	u8 status, link_type;
1826*4882a593Smuzhiyun 	rtk_conn_prof *hci_conn = NULL;
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	status = *p++;
1829*4882a593Smuzhiyun 	STREAM_TO_UINT16(handle, p);
1830*4882a593Smuzhiyun 	p += 6;
1831*4882a593Smuzhiyun 	link_type = *p++;
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	RTKBT_INFO("connected, handle %04x, status 0x%02x", handle, status);
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	if (status == 0) {
1836*4882a593Smuzhiyun 		if (btrtl_coex.ispaging) {
1837*4882a593Smuzhiyun 			btrtl_coex.ispaging = 0;
1838*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1839*4882a593Smuzhiyun 			RTKBT_DBG("notify wifi page success end");
1840*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi
1841*4882a593Smuzhiyun 			    (BT_OPCODE_PAGE_SUCCESS_END, 0, NULL);
1842*4882a593Smuzhiyun #else
1843*4882a593Smuzhiyun 			RTKBT_INFO("Page success");
1844*4882a593Smuzhiyun #endif
1845*4882a593Smuzhiyun 		}
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun 		hci_conn = find_connection_by_handle(&btrtl_coex, handle);
1848*4882a593Smuzhiyun 		if (hci_conn == NULL) {
1849*4882a593Smuzhiyun 			hci_conn = allocate_connection_by_handle(handle);
1850*4882a593Smuzhiyun 			if (hci_conn) {
1851*4882a593Smuzhiyun 				add_connection_to_hash(&btrtl_coex,
1852*4882a593Smuzhiyun 						       hci_conn);
1853*4882a593Smuzhiyun 				hci_conn->profile_bitmap = 0;
1854*4882a593Smuzhiyun 				memset(hci_conn->profile_refcount, 0, 8);
1855*4882a593Smuzhiyun 				if ((0 == link_type) || (2 == link_type)) {	//sco or esco
1856*4882a593Smuzhiyun 					hci_conn->type = 1;
1857*4882a593Smuzhiyun 					update_profile_connection(hci_conn,
1858*4882a593Smuzhiyun 								  profile_sco,
1859*4882a593Smuzhiyun 								  TRUE);
1860*4882a593Smuzhiyun 				} else
1861*4882a593Smuzhiyun 					hci_conn->type = 0;
1862*4882a593Smuzhiyun 			} else {
1863*4882a593Smuzhiyun 				RTKBT_ERR("hci connection allocate fail");
1864*4882a593Smuzhiyun 			}
1865*4882a593Smuzhiyun 		} else {
1866*4882a593Smuzhiyun 			RTKBT_DBG("hci conn handle 0x%04x already existed!",
1867*4882a593Smuzhiyun 				  handle);
1868*4882a593Smuzhiyun 			hci_conn->profile_bitmap = 0;
1869*4882a593Smuzhiyun 			memset(hci_conn->profile_refcount, 0, 8);
1870*4882a593Smuzhiyun 			if ((0 == link_type) || (2 == link_type)) {	//sco or esco
1871*4882a593Smuzhiyun 				hci_conn->type = 1;
1872*4882a593Smuzhiyun 				update_profile_connection(hci_conn, profile_sco,
1873*4882a593Smuzhiyun 							  TRUE);
1874*4882a593Smuzhiyun 			} else
1875*4882a593Smuzhiyun 				hci_conn->type = 0;
1876*4882a593Smuzhiyun 		}
1877*4882a593Smuzhiyun 	} else if (btrtl_coex.ispaging) {
1878*4882a593Smuzhiyun 		btrtl_coex.ispaging = 0;
1879*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1880*4882a593Smuzhiyun 		RTKBT_DBG("notify wifi page unsuccess end");
1881*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0,
1882*4882a593Smuzhiyun 					       NULL);
1883*4882a593Smuzhiyun #else
1884*4882a593Smuzhiyun 		RTKBT_INFO("Page failed");
1885*4882a593Smuzhiyun #endif
1886*4882a593Smuzhiyun 	}
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun 
rtk_handle_le_connection_complete_evt(u8 enhanced,u8 * p)1889*4882a593Smuzhiyun static void rtk_handle_le_connection_complete_evt(u8 enhanced, u8 * p)
1890*4882a593Smuzhiyun {
1891*4882a593Smuzhiyun 	u16 handle, interval;
1892*4882a593Smuzhiyun 	u8 status;
1893*4882a593Smuzhiyun 	rtk_conn_prof *hci_conn = NULL;
1894*4882a593Smuzhiyun 
1895*4882a593Smuzhiyun 	status = *p++;
1896*4882a593Smuzhiyun 	STREAM_TO_UINT16(handle, p);
1897*4882a593Smuzhiyun 	if (!enhanced)
1898*4882a593Smuzhiyun 		p += 8;	/* role, address type, address */
1899*4882a593Smuzhiyun 	else
1900*4882a593Smuzhiyun 		p += (8 + 12); /* plus two bluetooth addresses */
1901*4882a593Smuzhiyun 	STREAM_TO_UINT16(interval, p);
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun 	RTKBT_INFO("LE connected, handle %04x, status 0x%02x, interval %u",
1904*4882a593Smuzhiyun 		   handle, status, interval);
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 	if (status == 0) {
1907*4882a593Smuzhiyun 		if (btrtl_coex.ispaging) {
1908*4882a593Smuzhiyun 			btrtl_coex.ispaging = 0;
1909*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1910*4882a593Smuzhiyun 			RTKBT_DBG("notify wifi page success end");
1911*4882a593Smuzhiyun 			rtk_notify_btoperation_to_wifi
1912*4882a593Smuzhiyun 			    (BT_OPCODE_PAGE_SUCCESS_END, 0, NULL);
1913*4882a593Smuzhiyun #else
1914*4882a593Smuzhiyun 			RTKBT_INFO("Page success end");
1915*4882a593Smuzhiyun #endif
1916*4882a593Smuzhiyun 		}
1917*4882a593Smuzhiyun 
1918*4882a593Smuzhiyun 		hci_conn = find_connection_by_handle(&btrtl_coex, handle);
1919*4882a593Smuzhiyun 		if (hci_conn == NULL) {
1920*4882a593Smuzhiyun 			hci_conn = allocate_connection_by_handle(handle);
1921*4882a593Smuzhiyun 			if (hci_conn) {
1922*4882a593Smuzhiyun 				add_connection_to_hash(&btrtl_coex,
1923*4882a593Smuzhiyun 						       hci_conn);
1924*4882a593Smuzhiyun 				hci_conn->profile_bitmap = 0;
1925*4882a593Smuzhiyun 				memset(hci_conn->profile_refcount, 0, 8);
1926*4882a593Smuzhiyun 				hci_conn->type = 2;
1927*4882a593Smuzhiyun 				update_profile_connection(hci_conn, profile_hid, TRUE);	//for coex, le is the same as hid
1928*4882a593Smuzhiyun 				update_hid_active_state(handle, interval);
1929*4882a593Smuzhiyun 			} else {
1930*4882a593Smuzhiyun 				RTKBT_ERR("hci connection allocate fail");
1931*4882a593Smuzhiyun 			}
1932*4882a593Smuzhiyun 		} else {
1933*4882a593Smuzhiyun 			RTKBT_DBG("hci conn handle 0x%04x already existed!",
1934*4882a593Smuzhiyun 				  handle);
1935*4882a593Smuzhiyun 			hci_conn->profile_bitmap = 0;
1936*4882a593Smuzhiyun 			memset(hci_conn->profile_refcount, 0, 8);
1937*4882a593Smuzhiyun 			hci_conn->type = 2;
1938*4882a593Smuzhiyun 			update_profile_connection(hci_conn, profile_hid, TRUE);
1939*4882a593Smuzhiyun 			update_hid_active_state(handle, interval);
1940*4882a593Smuzhiyun 		}
1941*4882a593Smuzhiyun 	} else if (btrtl_coex.ispaging) {
1942*4882a593Smuzhiyun 		btrtl_coex.ispaging = 0;
1943*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
1944*4882a593Smuzhiyun 		RTKBT_DBG("notify wifi page unsuccess end");
1945*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAGE_UNSUCCESS_END, 0,
1946*4882a593Smuzhiyun 					       NULL);
1947*4882a593Smuzhiyun #else
1948*4882a593Smuzhiyun 		RTKBT_INFO("Page failed");
1949*4882a593Smuzhiyun #endif
1950*4882a593Smuzhiyun 	}
1951*4882a593Smuzhiyun }
1952*4882a593Smuzhiyun 
rtk_handle_le_connection_update_complete_evt(u8 * p)1953*4882a593Smuzhiyun static void rtk_handle_le_connection_update_complete_evt(u8 * p)
1954*4882a593Smuzhiyun {
1955*4882a593Smuzhiyun 	u16 handle, interval;
1956*4882a593Smuzhiyun 	/* u8 status; */
1957*4882a593Smuzhiyun 
1958*4882a593Smuzhiyun 	/* status = *p++; */
1959*4882a593Smuzhiyun 	p++;
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun 	STREAM_TO_UINT16(handle, p);
1962*4882a593Smuzhiyun 	STREAM_TO_UINT16(interval, p);
1963*4882a593Smuzhiyun 	update_hid_active_state(handle, interval);
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun 
rtk_handle_le_meta_evt(u8 * p)1966*4882a593Smuzhiyun static void rtk_handle_le_meta_evt(u8 * p)
1967*4882a593Smuzhiyun {
1968*4882a593Smuzhiyun 	u8 sub_event = *p++;
1969*4882a593Smuzhiyun 	switch (sub_event) {
1970*4882a593Smuzhiyun 	case HCI_EV_LE_CONN_COMPLETE:
1971*4882a593Smuzhiyun 		rtk_handle_le_connection_complete_evt(0, p);
1972*4882a593Smuzhiyun 		break;
1973*4882a593Smuzhiyun 	case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
1974*4882a593Smuzhiyun 		rtk_handle_le_connection_complete_evt(1, p);
1975*4882a593Smuzhiyun 		break;
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	case HCI_EV_LE_CONN_UPDATE_COMPLETE:
1978*4882a593Smuzhiyun 		rtk_handle_le_connection_update_complete_evt(p);
1979*4882a593Smuzhiyun 		break;
1980*4882a593Smuzhiyun 
1981*4882a593Smuzhiyun 	default:
1982*4882a593Smuzhiyun 		break;
1983*4882a593Smuzhiyun 	}
1984*4882a593Smuzhiyun }
1985*4882a593Smuzhiyun 
disconn_profile(struct rtl_hci_conn * conn,u8 pfe_index)1986*4882a593Smuzhiyun static u8 disconn_profile(struct rtl_hci_conn *conn, u8 pfe_index)
1987*4882a593Smuzhiyun {
1988*4882a593Smuzhiyun 	u8 need_update = 0;
1989*4882a593Smuzhiyun 
1990*4882a593Smuzhiyun 	if (!btrtl_coex.profile_refcount[pfe_index]) {
1991*4882a593Smuzhiyun 		RTKBT_WARN("profile %u ref is 0", pfe_index);
1992*4882a593Smuzhiyun 		return 0;
1993*4882a593Smuzhiyun 	}
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 	btrtl_coex.profile_refcount[pfe_index]--;
1996*4882a593Smuzhiyun 	RTKBT_INFO("%s: profile_ref[%u] %u", __func__, pfe_index,
1997*4882a593Smuzhiyun 		  btrtl_coex.profile_refcount[pfe_index]);
1998*4882a593Smuzhiyun 
1999*4882a593Smuzhiyun 	if (!btrtl_coex.profile_refcount[pfe_index]) {
2000*4882a593Smuzhiyun 		need_update = 1;
2001*4882a593Smuzhiyun 		btrtl_coex.profile_bitmap &= ~(BIT(pfe_index));
2002*4882a593Smuzhiyun 
2003*4882a593Smuzhiyun 		/* if profile does not exist, status is meaningless */
2004*4882a593Smuzhiyun 		btrtl_coex.profile_status &= ~(BIT(pfe_index));
2005*4882a593Smuzhiyun 		rtk_check_del_timer(pfe_index);
2006*4882a593Smuzhiyun 	}
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	if (conn->profile_refcount[pfe_index])
2009*4882a593Smuzhiyun 		conn->profile_refcount[pfe_index]--;
2010*4882a593Smuzhiyun 	else
2011*4882a593Smuzhiyun 		RTKBT_INFO("%s: conn pfe ref[%u] is 0", __func__,
2012*4882a593Smuzhiyun 			   conn->profile_refcount[pfe_index]);
2013*4882a593Smuzhiyun 	if (!conn->profile_refcount[pfe_index]) {
2014*4882a593Smuzhiyun 		need_update = 1;
2015*4882a593Smuzhiyun 		conn->profile_bitmap &= ~(BIT(pfe_index));
2016*4882a593Smuzhiyun 
2017*4882a593Smuzhiyun 		/* clear profile_hid_interval if need */
2018*4882a593Smuzhiyun 		if ((profile_hid == pfe_index) &&
2019*4882a593Smuzhiyun 		    (conn->profile_bitmap & (BIT(profile_hid_interval)))) {
2020*4882a593Smuzhiyun 			conn->profile_bitmap &= ~(BIT(profile_hid_interval));
2021*4882a593Smuzhiyun 			if (btrtl_coex.profile_refcount[profile_hid_interval])
2022*4882a593Smuzhiyun 				btrtl_coex.profile_refcount[profile_hid_interval]--;
2023*4882a593Smuzhiyun 		}
2024*4882a593Smuzhiyun 	}
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	return need_update;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun 
disconn_acl(u16 handle,struct rtl_hci_conn * conn)2029*4882a593Smuzhiyun static void disconn_acl(u16 handle, struct rtl_hci_conn *conn)
2030*4882a593Smuzhiyun {
2031*4882a593Smuzhiyun 	struct rtl_coex_struct *coex = &btrtl_coex;
2032*4882a593Smuzhiyun 	rtk_prof_info *prof_info = NULL;
2033*4882a593Smuzhiyun 	struct list_head *iter = NULL, *temp = NULL;
2034*4882a593Smuzhiyun 	u8 need_update = 0;
2035*4882a593Smuzhiyun 
2036*4882a593Smuzhiyun 	spin_lock(&coex->spin_lock_profile);
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun 	list_for_each_safe(iter, temp, &coex->profile_list) {
2039*4882a593Smuzhiyun 		prof_info = list_entry(iter, rtk_prof_info, list);
2040*4882a593Smuzhiyun 		if (handle == prof_info->handle) {
2041*4882a593Smuzhiyun 			RTKBT_DBG("hci disconn, hndl %x, psm %x, dcid %x, "
2042*4882a593Smuzhiyun 				  "scid %x, profile %u", prof_info->handle,
2043*4882a593Smuzhiyun 				  prof_info->psm, prof_info->dcid,
2044*4882a593Smuzhiyun 				  prof_info->scid, prof_info->profile_index);
2045*4882a593Smuzhiyun 			//If both scid and dcid > 0, L2cap connection is exist.
2046*4882a593Smuzhiyun 			need_update |= disconn_profile(conn,
2047*4882a593Smuzhiyun 						      prof_info->profile_index);
2048*4882a593Smuzhiyun 			if ((prof_info->flags & A2DP_MEDIA) &&
2049*4882a593Smuzhiyun 			    (conn->profile_bitmap & BIT(profile_sink)))
2050*4882a593Smuzhiyun 				need_update |= disconn_profile(conn,
2051*4882a593Smuzhiyun 							       profile_sink);
2052*4882a593Smuzhiyun 			delete_profile_from_hash(prof_info);
2053*4882a593Smuzhiyun 		}
2054*4882a593Smuzhiyun 	}
2055*4882a593Smuzhiyun 	if (need_update)
2056*4882a593Smuzhiyun 		rtk_notify_profileinfo_to_fw();
2057*4882a593Smuzhiyun 	spin_unlock(&coex->spin_lock_profile);
2058*4882a593Smuzhiyun }
2059*4882a593Smuzhiyun 
rtk_handle_disconnect_complete_evt(u8 * p)2060*4882a593Smuzhiyun static void rtk_handle_disconnect_complete_evt(u8 * p)
2061*4882a593Smuzhiyun {
2062*4882a593Smuzhiyun 	u16 handle;
2063*4882a593Smuzhiyun 	u8 status;
2064*4882a593Smuzhiyun 	u8 reason;
2065*4882a593Smuzhiyun 	rtk_conn_prof *hci_conn = NULL;
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 	if (btrtl_coex.ispairing) {	//for slave: connection will be disconnected if authentication fail
2068*4882a593Smuzhiyun 		btrtl_coex.ispairing = 0;
2069*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2070*4882a593Smuzhiyun 		RTKBT_DBG("hci disc complete, notify wifi pair end");
2071*4882a593Smuzhiyun 		rtk_notify_btoperation_to_wifi(BT_OPCODE_PAIR_END, 0, NULL);
2072*4882a593Smuzhiyun #else
2073*4882a593Smuzhiyun 		RTKBT_INFO("hci disconnection complete");
2074*4882a593Smuzhiyun #endif
2075*4882a593Smuzhiyun 	}
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun 	status = *p++;
2078*4882a593Smuzhiyun 	STREAM_TO_UINT16(handle, p);
2079*4882a593Smuzhiyun 	reason = *p;
2080*4882a593Smuzhiyun 
2081*4882a593Smuzhiyun 	RTKBT_INFO("disconn cmpl evt: status 0x%02x, handle %04x, reason 0x%02x",
2082*4882a593Smuzhiyun 		   status, handle, reason);
2083*4882a593Smuzhiyun 
2084*4882a593Smuzhiyun 	if (status == 0) {
2085*4882a593Smuzhiyun 		RTKBT_DBG("process disconn complete event.");
2086*4882a593Smuzhiyun 		hci_conn = find_connection_by_handle(&btrtl_coex, handle);
2087*4882a593Smuzhiyun 		if (hci_conn) {
2088*4882a593Smuzhiyun 			switch (hci_conn->type) {
2089*4882a593Smuzhiyun 			case 0:
2090*4882a593Smuzhiyun 				/* FIXME: If this is interrupted by l2cap rx,
2091*4882a593Smuzhiyun 				 * there may be deadlock on spin_lock_profile */
2092*4882a593Smuzhiyun 				disconn_acl(handle, hci_conn);
2093*4882a593Smuzhiyun 				break;
2094*4882a593Smuzhiyun 
2095*4882a593Smuzhiyun 			case 1:
2096*4882a593Smuzhiyun 				update_profile_connection(hci_conn, profile_sco,
2097*4882a593Smuzhiyun 							  FALSE);
2098*4882a593Smuzhiyun 				break;
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 			case 2:
2101*4882a593Smuzhiyun 				update_profile_connection(hci_conn, profile_hid,
2102*4882a593Smuzhiyun 							  FALSE);
2103*4882a593Smuzhiyun 				break;
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 			default:
2106*4882a593Smuzhiyun 				break;
2107*4882a593Smuzhiyun 			}
2108*4882a593Smuzhiyun 			delete_connection_from_hash(hci_conn);
2109*4882a593Smuzhiyun 		} else
2110*4882a593Smuzhiyun 			RTKBT_ERR("hci conn handle 0x%04x not found", handle);
2111*4882a593Smuzhiyun 	}
2112*4882a593Smuzhiyun }
2113*4882a593Smuzhiyun 
rtk_handle_specific_evt(u8 * p)2114*4882a593Smuzhiyun static void rtk_handle_specific_evt(u8 * p)
2115*4882a593Smuzhiyun {
2116*4882a593Smuzhiyun 	u16 subcode;
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	STREAM_TO_UINT16(subcode, p);
2119*4882a593Smuzhiyun 	if (subcode == HCI_VENDOR_PTA_AUTO_REPORT_EVENT) {
2120*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2121*4882a593Smuzhiyun 		RTKBT_DBG("notify wifi driver with autoreport data");
2122*4882a593Smuzhiyun 		rtk_notify_info_to_wifi(AUTO_REPORT, RTL_BTINFO_LEN,
2123*4882a593Smuzhiyun 			(uint8_t *)p);
2124*4882a593Smuzhiyun #else
2125*4882a593Smuzhiyun 		RTKBT_INFO("auto report data");
2126*4882a593Smuzhiyun #endif
2127*4882a593Smuzhiyun 	}
2128*4882a593Smuzhiyun }
2129*4882a593Smuzhiyun 
rtk_parse_event_data(struct rtl_coex_struct * coex,u8 * data,u16 len)2130*4882a593Smuzhiyun static void rtk_parse_event_data(struct rtl_coex_struct *coex,
2131*4882a593Smuzhiyun 		u8 *data, u16 len)
2132*4882a593Smuzhiyun {
2133*4882a593Smuzhiyun 	u8 *p = data;
2134*4882a593Smuzhiyun 	u8 event_code = *p++;
2135*4882a593Smuzhiyun 	u8 total_len = *p++;
2136*4882a593Smuzhiyun 
2137*4882a593Smuzhiyun 	(void)coex;
2138*4882a593Smuzhiyun 	(void)&len;
2139*4882a593Smuzhiyun 
2140*4882a593Smuzhiyun 	switch (event_code) {
2141*4882a593Smuzhiyun 	case HCI_EV_INQUIRY_COMPLETE:
2142*4882a593Smuzhiyun 		rtk_handle_inquiry_complete();
2143*4882a593Smuzhiyun 		break;
2144*4882a593Smuzhiyun 
2145*4882a593Smuzhiyun 	case HCI_EV_PIN_CODE_REQ:
2146*4882a593Smuzhiyun 		rtk_handle_pin_code_req();
2147*4882a593Smuzhiyun 		break;
2148*4882a593Smuzhiyun 
2149*4882a593Smuzhiyun 	case HCI_EV_IO_CAPA_REQUEST:
2150*4882a593Smuzhiyun 		rtk_handle_io_capa_req();
2151*4882a593Smuzhiyun 		break;
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	case HCI_EV_AUTH_COMPLETE:
2154*4882a593Smuzhiyun 		rtk_handle_auth_request();
2155*4882a593Smuzhiyun 		break;
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	case HCI_EV_LINK_KEY_NOTIFY:
2158*4882a593Smuzhiyun 		rtk_handle_link_key_notify();
2159*4882a593Smuzhiyun 		break;
2160*4882a593Smuzhiyun 
2161*4882a593Smuzhiyun 	case HCI_EV_MODE_CHANGE:
2162*4882a593Smuzhiyun 		rtk_handle_mode_change_evt(p);
2163*4882a593Smuzhiyun 		break;
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun 	case HCI_EV_CMD_COMPLETE:
2166*4882a593Smuzhiyun 		rtk_handle_cmd_complete_evt(total_len, p);
2167*4882a593Smuzhiyun 		break;
2168*4882a593Smuzhiyun 
2169*4882a593Smuzhiyun 	case HCI_EV_CMD_STATUS:
2170*4882a593Smuzhiyun 		rtk_handle_cmd_status_evt(p);
2171*4882a593Smuzhiyun 		break;
2172*4882a593Smuzhiyun 
2173*4882a593Smuzhiyun 	case HCI_EV_CONN_COMPLETE:
2174*4882a593Smuzhiyun 	case HCI_EV_SYNC_CONN_COMPLETE:
2175*4882a593Smuzhiyun 		rtk_handle_connection_complete_evt(p);
2176*4882a593Smuzhiyun 		break;
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun 	case HCI_EV_DISCONN_COMPLETE:
2179*4882a593Smuzhiyun 		rtk_handle_disconnect_complete_evt(p);
2180*4882a593Smuzhiyun 		break;
2181*4882a593Smuzhiyun 
2182*4882a593Smuzhiyun 	case HCI_EV_LE_META:
2183*4882a593Smuzhiyun 		rtk_handle_le_meta_evt(p);
2184*4882a593Smuzhiyun 		break;
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun 	case HCI_EV_VENDOR_SPECIFIC:
2187*4882a593Smuzhiyun 		rtk_handle_specific_evt(p);
2188*4882a593Smuzhiyun 		break;
2189*4882a593Smuzhiyun 
2190*4882a593Smuzhiyun 	default:
2191*4882a593Smuzhiyun 		break;
2192*4882a593Smuzhiyun 	}
2193*4882a593Smuzhiyun }
2194*4882a593Smuzhiyun 
2195*4882a593Smuzhiyun const char l2_dir_str[][4] = {
2196*4882a593Smuzhiyun 	"RX", "TX",
2197*4882a593Smuzhiyun };
2198*4882a593Smuzhiyun 
rtl_process_l2_sig(struct rtl_l2_buff * l2)2199*4882a593Smuzhiyun void rtl_process_l2_sig(struct rtl_l2_buff *l2)
2200*4882a593Smuzhiyun {
2201*4882a593Smuzhiyun 	/* u8 flag; */
2202*4882a593Smuzhiyun 	u8 code;
2203*4882a593Smuzhiyun 	/* u8 identifier; */
2204*4882a593Smuzhiyun 	u16 handle;
2205*4882a593Smuzhiyun 	/* u16 total_len; */
2206*4882a593Smuzhiyun 	/* u16 pdu_len, channel_id; */
2207*4882a593Smuzhiyun 	/* u16 command_len; */
2208*4882a593Smuzhiyun 	u16 psm, scid, dcid, result;
2209*4882a593Smuzhiyun 	/* u16 status; */
2210*4882a593Smuzhiyun 	u8 *pp = l2->data;
2211*4882a593Smuzhiyun 
2212*4882a593Smuzhiyun 	STREAM_TO_UINT16(handle, pp);
2213*4882a593Smuzhiyun 	/* flag = handle >> 12; */
2214*4882a593Smuzhiyun 	handle = handle & 0x0FFF;
2215*4882a593Smuzhiyun 	/* STREAM_TO_UINT16(total_len, pp); */
2216*4882a593Smuzhiyun 	pp += 2; /* data total length */
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 	/* STREAM_TO_UINT16(pdu_len, pp);
2219*4882a593Smuzhiyun 	 * STREAM_TO_UINT16(channel_id, pp); */
2220*4882a593Smuzhiyun 	pp += 4; /* l2 len and channel id */
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	code = *pp++;
2223*4882a593Smuzhiyun 	switch (code) {
2224*4882a593Smuzhiyun 	case L2CAP_CONN_REQ:
2225*4882a593Smuzhiyun 		/* identifier = *pp++; */
2226*4882a593Smuzhiyun 		pp++;
2227*4882a593Smuzhiyun 		/* STREAM_TO_UINT16(command_len, pp); */
2228*4882a593Smuzhiyun 		pp += 2;
2229*4882a593Smuzhiyun 		STREAM_TO_UINT16(psm, pp);
2230*4882a593Smuzhiyun 		STREAM_TO_UINT16(scid, pp);
2231*4882a593Smuzhiyun 		RTKBT_DBG("%s l2cap conn req, hndl 0x%04x, PSM 0x%04x, "
2232*4882a593Smuzhiyun 			  "scid 0x%04x", l2_dir_str[l2->out], handle, psm,
2233*4882a593Smuzhiyun 			  scid);
2234*4882a593Smuzhiyun 		handle_l2cap_con_req(handle, psm, scid, l2->out);
2235*4882a593Smuzhiyun 		break;
2236*4882a593Smuzhiyun 
2237*4882a593Smuzhiyun 	case L2CAP_CONN_RSP:
2238*4882a593Smuzhiyun 		/* identifier = *pp++; */
2239*4882a593Smuzhiyun 		pp++;
2240*4882a593Smuzhiyun 		/* STREAM_TO_UINT16(command_len, pp); */
2241*4882a593Smuzhiyun 		pp += 2;
2242*4882a593Smuzhiyun 		STREAM_TO_UINT16(dcid, pp);
2243*4882a593Smuzhiyun 		STREAM_TO_UINT16(scid, pp);
2244*4882a593Smuzhiyun 		STREAM_TO_UINT16(result, pp);
2245*4882a593Smuzhiyun 		/* STREAM_TO_UINT16(status, pp); */
2246*4882a593Smuzhiyun 		pp += 2;
2247*4882a593Smuzhiyun 		RTKBT_DBG("%s l2cap conn rsp, hndl 0x%04x, dcid 0x%04x, "
2248*4882a593Smuzhiyun 			  "scid 0x%04x, result 0x%04x", l2_dir_str[l2->out],
2249*4882a593Smuzhiyun 			  handle, dcid, scid, result);
2250*4882a593Smuzhiyun 		handle_l2cap_con_rsp(handle, dcid, scid, l2->out, result);
2251*4882a593Smuzhiyun 		break;
2252*4882a593Smuzhiyun 
2253*4882a593Smuzhiyun 	case L2CAP_DISCONN_REQ:
2254*4882a593Smuzhiyun 		/* identifier = *pp++; */
2255*4882a593Smuzhiyun 		pp++;
2256*4882a593Smuzhiyun 		/* STREAM_TO_UINT16(command_len, pp); */
2257*4882a593Smuzhiyun 		pp += 2;
2258*4882a593Smuzhiyun 		STREAM_TO_UINT16(dcid, pp);
2259*4882a593Smuzhiyun 		STREAM_TO_UINT16(scid, pp);
2260*4882a593Smuzhiyun 		RTKBT_DBG("%s l2cap disconn req, hndl 0x%04x, dcid 0x%04x, "
2261*4882a593Smuzhiyun 			  "scid 0x%04x", l2_dir_str[l2->out], handle, dcid, scid);
2262*4882a593Smuzhiyun 		handle_l2cap_discon_req(handle, dcid, scid, l2->out);
2263*4882a593Smuzhiyun 		break;
2264*4882a593Smuzhiyun 	default:
2265*4882a593Smuzhiyun 		RTKBT_DBG("undesired l2 command %u", code);
2266*4882a593Smuzhiyun 		break;
2267*4882a593Smuzhiyun 	}
2268*4882a593Smuzhiyun }
2269*4882a593Smuzhiyun 
rtl_l2_data_process(u8 * pp,u16 len,int dir)2270*4882a593Smuzhiyun static void rtl_l2_data_process(u8 *pp, u16 len, int dir)
2271*4882a593Smuzhiyun {
2272*4882a593Smuzhiyun 	u8 code;
2273*4882a593Smuzhiyun 	u8 flag;
2274*4882a593Smuzhiyun 	u16 handle, pdu_len, channel_id;
2275*4882a593Smuzhiyun 	/* u16 total_len; */
2276*4882a593Smuzhiyun 	struct rtl_l2_buff *l2 = NULL;
2277*4882a593Smuzhiyun 	u8 *hd = pp;
2278*4882a593Smuzhiyun 
2279*4882a593Smuzhiyun 	/* RTKBT_DBG("l2 sig data %p, len %u, dir %d", pp, len, dir); */
2280*4882a593Smuzhiyun 
2281*4882a593Smuzhiyun 	STREAM_TO_UINT16(handle, pp);
2282*4882a593Smuzhiyun 	flag = handle >> 12;
2283*4882a593Smuzhiyun 	handle = handle & 0x0FFF;
2284*4882a593Smuzhiyun 	/* STREAM_TO_UINT16(total_len, pp); */
2285*4882a593Smuzhiyun 	pp += 2; /* data total length */
2286*4882a593Smuzhiyun 
2287*4882a593Smuzhiyun 	STREAM_TO_UINT16(pdu_len, pp);
2288*4882a593Smuzhiyun 	STREAM_TO_UINT16(channel_id, pp);
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 	if (channel_id == 0x0001) {
2291*4882a593Smuzhiyun 		code = *pp++;
2292*4882a593Smuzhiyun 		switch (code) {
2293*4882a593Smuzhiyun 		case L2CAP_CONN_REQ:
2294*4882a593Smuzhiyun 		case L2CAP_CONN_RSP:
2295*4882a593Smuzhiyun 		case L2CAP_DISCONN_REQ:
2296*4882a593Smuzhiyun 			RTKBT_DBG("l2cap op %u, len %u, out %d", code, len,
2297*4882a593Smuzhiyun 				  dir);
2298*4882a593Smuzhiyun 			l2 = rtl_l2_node_get(&btrtl_coex);
2299*4882a593Smuzhiyun 			if (l2) {
2300*4882a593Smuzhiyun 				u16 n;
2301*4882a593Smuzhiyun 				n = min_t(uint, len, L2_MAX_SUBSEC_LEN);
2302*4882a593Smuzhiyun 				memcpy(l2->data, hd, n);
2303*4882a593Smuzhiyun 				l2->out = dir;
2304*4882a593Smuzhiyun 				rtl_l2_node_to_used(&btrtl_coex, l2);
2305*4882a593Smuzhiyun 				queue_delayed_work(btrtl_coex.fw_wq,
2306*4882a593Smuzhiyun 						&btrtl_coex.l2_work, 0);
2307*4882a593Smuzhiyun 			} else
2308*4882a593Smuzhiyun 				RTKBT_ERR("%s: failed to get l2 node",
2309*4882a593Smuzhiyun 					  __func__);
2310*4882a593Smuzhiyun 			break;
2311*4882a593Smuzhiyun 		case L2CAP_DISCONN_RSP:
2312*4882a593Smuzhiyun 			break;
2313*4882a593Smuzhiyun 		default:
2314*4882a593Smuzhiyun 			break;
2315*4882a593Smuzhiyun 		}
2316*4882a593Smuzhiyun 	} else {
2317*4882a593Smuzhiyun 		if ((flag != 0x01) && (is_profile_connected(profile_a2dp) ||
2318*4882a593Smuzhiyun 				       is_profile_connected(profile_pan)))
2319*4882a593Smuzhiyun 			/* Do not count the continuous packets */
2320*4882a593Smuzhiyun 			packets_count(handle, channel_id, pdu_len, dir, pp);
2321*4882a593Smuzhiyun 	}
2322*4882a593Smuzhiyun 	return;
2323*4882a593Smuzhiyun }
2324*4882a593Smuzhiyun 
2325*4882a593Smuzhiyun 
rtl_l2_work(struct work_struct * work)2326*4882a593Smuzhiyun static void rtl_l2_work(struct work_struct *work)
2327*4882a593Smuzhiyun {
2328*4882a593Smuzhiyun 	struct rtl_coex_struct *coex;
2329*4882a593Smuzhiyun 	struct rtl_l2_buff *l2;
2330*4882a593Smuzhiyun 	unsigned long flags;
2331*4882a593Smuzhiyun 
2332*4882a593Smuzhiyun 	coex = container_of(work, struct rtl_coex_struct, l2_work.work);
2333*4882a593Smuzhiyun 
2334*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
2335*4882a593Smuzhiyun 	while (!list_empty(&coex->l2_used_list)) {
2336*4882a593Smuzhiyun 		l2 = list_entry(coex->l2_used_list.next, struct rtl_l2_buff,
2337*4882a593Smuzhiyun 				list);
2338*4882a593Smuzhiyun 		list_del(&l2->list);
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun 		spin_unlock_irqrestore(&coex->buff_lock, flags);
2341*4882a593Smuzhiyun 
2342*4882a593Smuzhiyun 		rtl_process_l2_sig(l2);
2343*4882a593Smuzhiyun 
2344*4882a593Smuzhiyun 		spin_lock_irqsave(&coex->buff_lock, flags);
2345*4882a593Smuzhiyun 
2346*4882a593Smuzhiyun 		list_add_tail(&l2->list, &coex->l2_free_list);
2347*4882a593Smuzhiyun 	}
2348*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
2349*4882a593Smuzhiyun 
2350*4882a593Smuzhiyun 	return;
2351*4882a593Smuzhiyun }
2352*4882a593Smuzhiyun 
rtl_ev_work(struct work_struct * work)2353*4882a593Smuzhiyun static void rtl_ev_work(struct work_struct *work)
2354*4882a593Smuzhiyun {
2355*4882a593Smuzhiyun 	struct rtl_coex_struct *coex;
2356*4882a593Smuzhiyun 	struct rtl_hci_ev *ev;
2357*4882a593Smuzhiyun 	unsigned long flags;
2358*4882a593Smuzhiyun 
2359*4882a593Smuzhiyun 	coex = container_of(work, struct rtl_coex_struct, fw_work.work);
2360*4882a593Smuzhiyun 
2361*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->buff_lock, flags);
2362*4882a593Smuzhiyun 	while (!list_empty(&coex->ev_used_list)) {
2363*4882a593Smuzhiyun 		ev = list_entry(coex->ev_used_list.next, struct rtl_hci_ev,
2364*4882a593Smuzhiyun 				list);
2365*4882a593Smuzhiyun 		list_del(&ev->list);
2366*4882a593Smuzhiyun 		spin_unlock_irqrestore(&coex->buff_lock, flags);
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun 		rtk_parse_event_data(coex, ev->data, ev->len);
2369*4882a593Smuzhiyun 
2370*4882a593Smuzhiyun 		spin_lock_irqsave(&coex->buff_lock, flags);
2371*4882a593Smuzhiyun 		list_add_tail(&ev->list, &coex->ev_free_list);
2372*4882a593Smuzhiyun 	}
2373*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->buff_lock, flags);
2374*4882a593Smuzhiyun }
2375*4882a593Smuzhiyun 
cmd_cmplt_filter_out(u8 * buf)2376*4882a593Smuzhiyun static inline int cmd_cmplt_filter_out(u8 *buf)
2377*4882a593Smuzhiyun {
2378*4882a593Smuzhiyun 	u16 opcode;
2379*4882a593Smuzhiyun 
2380*4882a593Smuzhiyun 	opcode = buf[3] | (buf[4] << 8);
2381*4882a593Smuzhiyun 	switch (opcode) {
2382*4882a593Smuzhiyun 	case HCI_OP_PERIODIC_INQ:
2383*4882a593Smuzhiyun 	case HCI_OP_READ_LOCAL_VERSION:
2384*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2385*4882a593Smuzhiyun 	case HCI_VENDOR_MAILBOX_CMD:
2386*4882a593Smuzhiyun #endif
2387*4882a593Smuzhiyun 		return 0;
2388*4882a593Smuzhiyun 	default:
2389*4882a593Smuzhiyun 		return 1;
2390*4882a593Smuzhiyun 	}
2391*4882a593Smuzhiyun }
2392*4882a593Smuzhiyun 
cmd_status_filter_out(u8 * buf)2393*4882a593Smuzhiyun static inline int cmd_status_filter_out(u8 *buf)
2394*4882a593Smuzhiyun {
2395*4882a593Smuzhiyun 	u16 opcode;
2396*4882a593Smuzhiyun 
2397*4882a593Smuzhiyun 	opcode = buf[4] | (buf[5] << 8);
2398*4882a593Smuzhiyun 	switch (opcode) {
2399*4882a593Smuzhiyun 	case HCI_OP_INQUIRY:
2400*4882a593Smuzhiyun 	case HCI_OP_CREATE_CONN:
2401*4882a593Smuzhiyun 		return 0;
2402*4882a593Smuzhiyun 	default:
2403*4882a593Smuzhiyun 		return 1;
2404*4882a593Smuzhiyun 	}
2405*4882a593Smuzhiyun }
2406*4882a593Smuzhiyun 
ev_filter_out(u8 * buf)2407*4882a593Smuzhiyun int ev_filter_out(u8 *buf)
2408*4882a593Smuzhiyun {
2409*4882a593Smuzhiyun 	switch (buf[0]) {
2410*4882a593Smuzhiyun 	case HCI_EV_INQUIRY_COMPLETE:
2411*4882a593Smuzhiyun 	case HCI_EV_PIN_CODE_REQ:
2412*4882a593Smuzhiyun 	case HCI_EV_IO_CAPA_REQUEST:
2413*4882a593Smuzhiyun 	case HCI_EV_AUTH_COMPLETE:
2414*4882a593Smuzhiyun 	case HCI_EV_LINK_KEY_NOTIFY:
2415*4882a593Smuzhiyun 	case HCI_EV_MODE_CHANGE:
2416*4882a593Smuzhiyun 	case HCI_EV_CONN_COMPLETE:
2417*4882a593Smuzhiyun 	case HCI_EV_SYNC_CONN_COMPLETE:
2418*4882a593Smuzhiyun 	case HCI_EV_DISCONN_COMPLETE:
2419*4882a593Smuzhiyun 	case HCI_EV_VENDOR_SPECIFIC:
2420*4882a593Smuzhiyun 		return 0;
2421*4882a593Smuzhiyun 	case HCI_EV_LE_META:
2422*4882a593Smuzhiyun 		/* Ignore frequent but not useful events that result in
2423*4882a593Smuzhiyun 		 * costing too much space.
2424*4882a593Smuzhiyun 		 */
2425*4882a593Smuzhiyun 		switch (buf[2]) {
2426*4882a593Smuzhiyun 		case HCI_EV_LE_CONN_COMPLETE:
2427*4882a593Smuzhiyun 		case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
2428*4882a593Smuzhiyun 		case HCI_EV_LE_CONN_UPDATE_COMPLETE:
2429*4882a593Smuzhiyun 			return 0;
2430*4882a593Smuzhiyun 		}
2431*4882a593Smuzhiyun 		return 1;
2432*4882a593Smuzhiyun 	case HCI_EV_CMD_COMPLETE:
2433*4882a593Smuzhiyun 		return cmd_cmplt_filter_out(buf);
2434*4882a593Smuzhiyun 	case HCI_EV_CMD_STATUS:
2435*4882a593Smuzhiyun 		return cmd_status_filter_out(buf);
2436*4882a593Smuzhiyun 	default:
2437*4882a593Smuzhiyun 		return 1;
2438*4882a593Smuzhiyun 	}
2439*4882a593Smuzhiyun }
2440*4882a593Smuzhiyun 
rtk_btcoex_evt_enqueue(__u8 * s,__u16 count)2441*4882a593Smuzhiyun static void rtk_btcoex_evt_enqueue(__u8 *s, __u16 count)
2442*4882a593Smuzhiyun {
2443*4882a593Smuzhiyun 	struct rtl_hci_ev *ev;
2444*4882a593Smuzhiyun 
2445*4882a593Smuzhiyun 	if (ev_filter_out(s))
2446*4882a593Smuzhiyun 		return;
2447*4882a593Smuzhiyun 
2448*4882a593Smuzhiyun 	ev = rtl_ev_node_get(&btrtl_coex);
2449*4882a593Smuzhiyun 	if (!ev) {
2450*4882a593Smuzhiyun 		RTKBT_ERR("%s: no free ev node.", __func__);
2451*4882a593Smuzhiyun 		return;
2452*4882a593Smuzhiyun 	}
2453*4882a593Smuzhiyun 
2454*4882a593Smuzhiyun 	if (count > MAX_LEN_OF_HCI_EV) {
2455*4882a593Smuzhiyun 		memcpy(ev->data, s, MAX_LEN_OF_HCI_EV);
2456*4882a593Smuzhiyun 		ev->len = MAX_LEN_OF_HCI_EV;
2457*4882a593Smuzhiyun 	} else {
2458*4882a593Smuzhiyun 		memcpy(ev->data, s, count);
2459*4882a593Smuzhiyun 		ev->len = count;
2460*4882a593Smuzhiyun 	}
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 	rtl_ev_node_to_used(&btrtl_coex, ev);
2463*4882a593Smuzhiyun 
2464*4882a593Smuzhiyun 	queue_delayed_work(btrtl_coex.fw_wq, &btrtl_coex.fw_work, 0);
2465*4882a593Smuzhiyun }
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun /* Context: in_interrupt() */
rtk_btcoex_parse_event(uint8_t * buffer,int count)2468*4882a593Smuzhiyun void rtk_btcoex_parse_event(uint8_t *buffer, int count)
2469*4882a593Smuzhiyun {
2470*4882a593Smuzhiyun 	struct rtl_coex_struct *coex = &btrtl_coex;
2471*4882a593Smuzhiyun 	__u8 *tbuff;
2472*4882a593Smuzhiyun 	__u16 elen = 0;
2473*4882a593Smuzhiyun 
2474*4882a593Smuzhiyun 	/* RTKBT_DBG("%s: parse ev.", __func__); */
2475*4882a593Smuzhiyun 	if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
2476*4882a593Smuzhiyun 		/* RTKBT_INFO("%s: Coex is closed, ignore", __func__); */
2477*4882a593Smuzhiyun 		RTKBT_INFO("%s: Coex is closed, ignore %x, %x",
2478*4882a593Smuzhiyun 			   __func__, buffer[0], buffer[1]);
2479*4882a593Smuzhiyun 		return;
2480*4882a593Smuzhiyun 	}
2481*4882a593Smuzhiyun 
2482*4882a593Smuzhiyun 	spin_lock(&coex->rxlock);
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun 	/* coex->tbuff will be set to NULL when initializing or
2485*4882a593Smuzhiyun 	 * there is a complete frame or there is start of a frame */
2486*4882a593Smuzhiyun 	tbuff = coex->tbuff;
2487*4882a593Smuzhiyun 
2488*4882a593Smuzhiyun 	while (count) {
2489*4882a593Smuzhiyun 		int len;
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun 		/* Start of a frame */
2492*4882a593Smuzhiyun 		if (!tbuff) {
2493*4882a593Smuzhiyun 			tbuff = coex->back_buff;
2494*4882a593Smuzhiyun 			coex->tbuff = NULL;
2495*4882a593Smuzhiyun 			coex->elen = 0;
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun 			coex->pkt_type = HCI_EVENT_PKT;
2498*4882a593Smuzhiyun 			coex->expect = HCI_EVENT_HDR_SIZE;
2499*4882a593Smuzhiyun 		}
2500*4882a593Smuzhiyun 
2501*4882a593Smuzhiyun 		len = min_t(uint, coex->expect, count);
2502*4882a593Smuzhiyun 		memcpy(tbuff, buffer, len);
2503*4882a593Smuzhiyun 		tbuff += len;
2504*4882a593Smuzhiyun 		coex->elen += len;
2505*4882a593Smuzhiyun 
2506*4882a593Smuzhiyun 		count -= len;
2507*4882a593Smuzhiyun 		buffer += len;
2508*4882a593Smuzhiyun 		coex->expect -= len;
2509*4882a593Smuzhiyun 
2510*4882a593Smuzhiyun 		if (coex->elen == HCI_EVENT_HDR_SIZE) {
2511*4882a593Smuzhiyun 			/* Complete event header */
2512*4882a593Smuzhiyun 			coex->expect =
2513*4882a593Smuzhiyun 				((struct hci_event_hdr *)coex->back_buff)->plen;
2514*4882a593Smuzhiyun 			if (coex->expect > HCI_MAX_EVENT_SIZE - coex->elen) {
2515*4882a593Smuzhiyun 				tbuff = NULL;
2516*4882a593Smuzhiyun 				coex->elen = 0;
2517*4882a593Smuzhiyun 				RTKBT_ERR("tbuff room is not enough");
2518*4882a593Smuzhiyun 				break;
2519*4882a593Smuzhiyun 			}
2520*4882a593Smuzhiyun 		}
2521*4882a593Smuzhiyun 
2522*4882a593Smuzhiyun 		if (coex->expect == 0) {
2523*4882a593Smuzhiyun 			/* Complete frame */
2524*4882a593Smuzhiyun 			elen = coex->elen;
2525*4882a593Smuzhiyun 			spin_unlock(&coex->rxlock);
2526*4882a593Smuzhiyun 			rtk_btcoex_evt_enqueue(coex->back_buff, elen);
2527*4882a593Smuzhiyun 			spin_lock(&coex->rxlock);
2528*4882a593Smuzhiyun 
2529*4882a593Smuzhiyun 			tbuff = NULL;
2530*4882a593Smuzhiyun 			coex->elen = 0;
2531*4882a593Smuzhiyun 		}
2532*4882a593Smuzhiyun 	}
2533*4882a593Smuzhiyun 
2534*4882a593Smuzhiyun 	/* coex->tbuff would be non-NULL if there isn't a complete frame
2535*4882a593Smuzhiyun 	 * And it will be updated next time */
2536*4882a593Smuzhiyun 	coex->tbuff = tbuff;
2537*4882a593Smuzhiyun 	spin_unlock(&coex->rxlock);
2538*4882a593Smuzhiyun }
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 
rtk_btcoex_parse_l2cap_data_tx(uint8_t * buffer,int count)2541*4882a593Smuzhiyun void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count)
2542*4882a593Smuzhiyun {
2543*4882a593Smuzhiyun 	if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
2544*4882a593Smuzhiyun 		RTKBT_INFO("%s: Coex is closed, ignore", __func__);
2545*4882a593Smuzhiyun 		return;
2546*4882a593Smuzhiyun 	}
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun 	rtl_l2_data_process(buffer, count, 1);
2549*4882a593Smuzhiyun 	//u16 handle, total_len, pdu_len, channel_ID, command_len, psm, scid,
2550*4882a593Smuzhiyun 	//    dcid, result, status;
2551*4882a593Smuzhiyun 	//u8 flag, code, identifier;
2552*4882a593Smuzhiyun 	//u8 *pp = (u8 *) (skb->data);
2553*4882a593Smuzhiyun 	//STREAM_TO_UINT16(handle, pp);
2554*4882a593Smuzhiyun 	//flag = handle >> 12;
2555*4882a593Smuzhiyun 	//handle = handle & 0x0FFF;
2556*4882a593Smuzhiyun 	//STREAM_TO_UINT16(total_len, pp);
2557*4882a593Smuzhiyun 	//STREAM_TO_UINT16(pdu_len, pp);
2558*4882a593Smuzhiyun 	//STREAM_TO_UINT16(channel_ID, pp);
2559*4882a593Smuzhiyun 
2560*4882a593Smuzhiyun 	//if (channel_ID == 0x0001) {
2561*4882a593Smuzhiyun 	//	code = *pp++;
2562*4882a593Smuzhiyun 	//	switch (code) {
2563*4882a593Smuzhiyun 	//	case L2CAP_CONN_REQ:
2564*4882a593Smuzhiyun 	//		identifier = *pp++;
2565*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(command_len, pp);
2566*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(psm, pp);
2567*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(scid, pp);
2568*4882a593Smuzhiyun 	//		RTKBT_DBG("TX l2cap conn req, hndl %x, PSM %x, scid=%x",
2569*4882a593Smuzhiyun 	//			  handle, psm, scid);
2570*4882a593Smuzhiyun 	//		handle_l2cap_con_req(handle, psm, scid, 1);
2571*4882a593Smuzhiyun 	//		break;
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun 	//	case L2CAP_CONN_RSP:
2574*4882a593Smuzhiyun 	//		identifier = *pp++;
2575*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(command_len, pp);
2576*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(dcid, pp);
2577*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(scid, pp);
2578*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(result, pp);
2579*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(status, pp);
2580*4882a593Smuzhiyun 	//		RTKBT_DBG("TX l2cap conn rsp, hndl %x, dcid %x, "
2581*4882a593Smuzhiyun 	//			  "scid %x, result %x",
2582*4882a593Smuzhiyun 	//			  handle, dcid, scid, result);
2583*4882a593Smuzhiyun 	//		handle_l2cap_con_rsp(handle, dcid, scid, 1, result);
2584*4882a593Smuzhiyun 	//		break;
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun 	//	case L2CAP_DISCONN_REQ:
2587*4882a593Smuzhiyun 	//		identifier = *pp++;
2588*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(command_len, pp);
2589*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(dcid, pp);
2590*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(scid, pp);
2591*4882a593Smuzhiyun 	//		RTKBT_DBG("TX l2cap disconn req, hndl %x, dcid %x, "
2592*4882a593Smuzhiyun 	//			  "scid %x", handle, dcid, scid);
2593*4882a593Smuzhiyun 	//		handle_l2cap_discon_req(handle, dcid, scid, 1);
2594*4882a593Smuzhiyun 	//		break;
2595*4882a593Smuzhiyun 
2596*4882a593Smuzhiyun 	//	case L2CAP_DISCONN_RSP:
2597*4882a593Smuzhiyun 	//		break;
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun 	//	default:
2600*4882a593Smuzhiyun 	//		break;
2601*4882a593Smuzhiyun 	//	}
2602*4882a593Smuzhiyun 	//} else {
2603*4882a593Smuzhiyun 	//	if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan)))	//Do not count the continuous packets
2604*4882a593Smuzhiyun 	//		packets_count(handle, channel_ID, pdu_len, 1, pp);
2605*4882a593Smuzhiyun 	//}
2606*4882a593Smuzhiyun }
2607*4882a593Smuzhiyun 
rtk_btcoex_parse_l2cap_data_rx(uint8_t * buffer,int count)2608*4882a593Smuzhiyun void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count)
2609*4882a593Smuzhiyun {
2610*4882a593Smuzhiyun 	if (!test_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
2611*4882a593Smuzhiyun 		RTKBT_INFO("%s: Coex is closed, ignore", __func__);
2612*4882a593Smuzhiyun 		return;
2613*4882a593Smuzhiyun 	}
2614*4882a593Smuzhiyun 
2615*4882a593Smuzhiyun 	rtl_l2_data_process(buffer, count, 0);
2616*4882a593Smuzhiyun 	//u16 handle, total_len, pdu_len, channel_ID, command_len, psm, scid,
2617*4882a593Smuzhiyun 	//    dcid, result, status;
2618*4882a593Smuzhiyun 	//u8 flag, code, identifier;
2619*4882a593Smuzhiyun 	//u8 *pp = urb->transfer_buffer;
2620*4882a593Smuzhiyun 	//STREAM_TO_UINT16(handle, pp);
2621*4882a593Smuzhiyun 	//flag = handle >> 12;
2622*4882a593Smuzhiyun 	//handle = handle & 0x0FFF;
2623*4882a593Smuzhiyun 	//STREAM_TO_UINT16(total_len, pp);
2624*4882a593Smuzhiyun 	//STREAM_TO_UINT16(pdu_len, pp);
2625*4882a593Smuzhiyun 	//STREAM_TO_UINT16(channel_ID, pp);
2626*4882a593Smuzhiyun 
2627*4882a593Smuzhiyun 	//if (channel_ID == 0x0001) {
2628*4882a593Smuzhiyun 	//	code = *pp++;
2629*4882a593Smuzhiyun 	//	switch (code) {
2630*4882a593Smuzhiyun 	//	case L2CAP_CONN_REQ:
2631*4882a593Smuzhiyun 	//		identifier = *pp++;
2632*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(command_len, pp);
2633*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(psm, pp);
2634*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(scid, pp);
2635*4882a593Smuzhiyun 	//		RTKBT_DBG("RX l2cap conn req, hndl %x, PSM %x, scid %x",
2636*4882a593Smuzhiyun 	//			  handle, psm, scid);
2637*4882a593Smuzhiyun 	//		handle_l2cap_con_req(handle, psm, scid, 0);
2638*4882a593Smuzhiyun 	//		break;
2639*4882a593Smuzhiyun 
2640*4882a593Smuzhiyun 	//	case L2CAP_CONN_RSP:
2641*4882a593Smuzhiyun 	//		identifier = *pp++;
2642*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(command_len, pp);
2643*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(dcid, pp);
2644*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(scid, pp);
2645*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(result, pp);
2646*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(status, pp);
2647*4882a593Smuzhiyun 	//		RTKBT_DBG("RX l2cap conn rsp, hndl %x, dcid %x, "
2648*4882a593Smuzhiyun 	//			  "scid %x, result %x",
2649*4882a593Smuzhiyun 	//			  handle, dcid, scid, result);
2650*4882a593Smuzhiyun 	//		handle_l2cap_con_rsp(handle, dcid, scid, 0, result);
2651*4882a593Smuzhiyun 	//		break;
2652*4882a593Smuzhiyun 
2653*4882a593Smuzhiyun 	//	case L2CAP_DISCONN_REQ:
2654*4882a593Smuzhiyun 	//		identifier = *pp++;
2655*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(command_len, pp);
2656*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(dcid, pp);
2657*4882a593Smuzhiyun 	//		STREAM_TO_UINT16(scid, pp);
2658*4882a593Smuzhiyun 	//		RTKBT_DBG("RX l2cap disconn req, hndl %x, dcid %x, "
2659*4882a593Smuzhiyun 	//			  "scid %x", handle, dcid, scid);
2660*4882a593Smuzhiyun 	//		handle_l2cap_discon_req(handle, dcid, scid, 0);
2661*4882a593Smuzhiyun 	//		break;
2662*4882a593Smuzhiyun 
2663*4882a593Smuzhiyun 	//	case L2CAP_DISCONN_RSP:
2664*4882a593Smuzhiyun 	//		break;
2665*4882a593Smuzhiyun 
2666*4882a593Smuzhiyun 	//	default:
2667*4882a593Smuzhiyun 	//		break;
2668*4882a593Smuzhiyun 	//	}
2669*4882a593Smuzhiyun 	//} else {
2670*4882a593Smuzhiyun 	//	if ((flag != 0x01) && (is_profile_connected(profile_a2dp) || is_profile_connected(profile_pan)))	//Do not count the continuous packets
2671*4882a593Smuzhiyun 	//		packets_count(handle, channel_ID, pdu_len, 0, pp);
2672*4882a593Smuzhiyun 	//}
2673*4882a593Smuzhiyun }
2674*4882a593Smuzhiyun 
2675*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2676*4882a593Smuzhiyun 
2677*4882a593Smuzhiyun #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
polling_bt_info(struct timer_list * unused)2678*4882a593Smuzhiyun static void polling_bt_info(struct timer_list *unused)
2679*4882a593Smuzhiyun #else
2680*4882a593Smuzhiyun static void polling_bt_info(unsigned long data)
2681*4882a593Smuzhiyun #endif
2682*4882a593Smuzhiyun {
2683*4882a593Smuzhiyun 	uint8_t temp_cmd[1];
2684*4882a593Smuzhiyun 	RTKBT_DBG("polling timer");
2685*4882a593Smuzhiyun 	if (btrtl_coex.polling_enable) {
2686*4882a593Smuzhiyun 		//temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO;
2687*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO;
2688*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 1, temp_cmd);
2689*4882a593Smuzhiyun 	}
2690*4882a593Smuzhiyun 	mod_timer(&btrtl_coex.polling_timer,
2691*4882a593Smuzhiyun 		  jiffies + msecs_to_jiffies(1000 * btrtl_coex.polling_interval));
2692*4882a593Smuzhiyun }
2693*4882a593Smuzhiyun 
rtk_handle_bt_info_control(uint8_t * p)2694*4882a593Smuzhiyun static void rtk_handle_bt_info_control(uint8_t *p)
2695*4882a593Smuzhiyun {
2696*4882a593Smuzhiyun 	uint8_t temp_cmd[20];
2697*4882a593Smuzhiyun 	struct rtl_btinfo_ctl *ctl = (struct rtl_btinfo_ctl*)p;
2698*4882a593Smuzhiyun 	RTKBT_DBG("Received polling_enable %u, polling_time %u, "
2699*4882a593Smuzhiyun 		  "autoreport_enable %u", ctl->polling_enable,
2700*4882a593Smuzhiyun 		  ctl->polling_time, ctl->autoreport_enable);
2701*4882a593Smuzhiyun 	RTKBT_DBG("coex: original polling_enable %u",
2702*4882a593Smuzhiyun 		  btrtl_coex.polling_enable);
2703*4882a593Smuzhiyun 
2704*4882a593Smuzhiyun 	if (ctl->polling_enable && !btrtl_coex.polling_enable) {
2705*4882a593Smuzhiyun 		/* setup polling timer for getting bt info from firmware */
2706*4882a593Smuzhiyun 		btrtl_coex.polling_timer.expires =
2707*4882a593Smuzhiyun 		    jiffies + msecs_to_jiffies(ctl->polling_time * 1000);
2708*4882a593Smuzhiyun 		mod_timer(&btrtl_coex.polling_timer,
2709*4882a593Smuzhiyun 			  btrtl_coex.polling_timer.expires);
2710*4882a593Smuzhiyun 	}
2711*4882a593Smuzhiyun 
2712*4882a593Smuzhiyun 	/* Close bt info polling timer */
2713*4882a593Smuzhiyun 	if (!ctl->polling_enable && btrtl_coex.polling_enable)
2714*4882a593Smuzhiyun 		del_timer(&btrtl_coex.polling_timer);
2715*4882a593Smuzhiyun 
2716*4882a593Smuzhiyun 	if (btrtl_coex.autoreport != ctl->autoreport_enable) {
2717*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE;
2718*4882a593Smuzhiyun 		temp_cmd[1] = 1;
2719*4882a593Smuzhiyun 		temp_cmd[2] = ctl->autoreport_enable;
2720*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
2721*4882a593Smuzhiyun 	}
2722*4882a593Smuzhiyun 
2723*4882a593Smuzhiyun 	btrtl_coex.polling_enable = ctl->polling_enable;
2724*4882a593Smuzhiyun 	btrtl_coex.polling_interval = ctl->polling_time;
2725*4882a593Smuzhiyun 	btrtl_coex.autoreport = ctl->autoreport_enable;
2726*4882a593Smuzhiyun 
2727*4882a593Smuzhiyun 	rtk_notify_info_to_wifi(HOST_RESPONSE, 0, NULL);
2728*4882a593Smuzhiyun }
2729*4882a593Smuzhiyun 
rtk_handle_bt_coex_control(uint8_t * p)2730*4882a593Smuzhiyun static void rtk_handle_bt_coex_control(uint8_t * p)
2731*4882a593Smuzhiyun {
2732*4882a593Smuzhiyun 	uint8_t temp_cmd[20];
2733*4882a593Smuzhiyun 	uint8_t opcode, opcode_len, value, power_decrease, psd_mode,
2734*4882a593Smuzhiyun 	    access_type;
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	opcode = *p++;
2737*4882a593Smuzhiyun 	RTKBT_DBG("receive bt coex control event from wifi, op 0x%02x", opcode);
2738*4882a593Smuzhiyun 
2739*4882a593Smuzhiyun 	switch (opcode) {
2740*4882a593Smuzhiyun 	case BT_PATCH_VERSION_QUERY:
2741*4882a593Smuzhiyun 		rtk_notify_btpatch_version_to_wifi();
2742*4882a593Smuzhiyun 		break;
2743*4882a593Smuzhiyun 
2744*4882a593Smuzhiyun 	case IGNORE_WLAN_ACTIVE_CONTROL:
2745*4882a593Smuzhiyun 		opcode_len = *p++;
2746*4882a593Smuzhiyun 		value = *p++;
2747*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD;
2748*4882a593Smuzhiyun 		temp_cmd[1] = 1;
2749*4882a593Smuzhiyun 		temp_cmd[2] = value;
2750*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
2751*4882a593Smuzhiyun 		break;
2752*4882a593Smuzhiyun 
2753*4882a593Smuzhiyun 	case LNA_CONSTRAIN_CONTROL:
2754*4882a593Smuzhiyun 		opcode_len = *p++;
2755*4882a593Smuzhiyun 		value = *p++;
2756*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT;
2757*4882a593Smuzhiyun 		temp_cmd[1] = 1;
2758*4882a593Smuzhiyun 		temp_cmd[2] = value;
2759*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
2760*4882a593Smuzhiyun 		break;
2761*4882a593Smuzhiyun 
2762*4882a593Smuzhiyun 	case BT_POWER_DECREASE_CONTROL:
2763*4882a593Smuzhiyun 		opcode_len = *p++;
2764*4882a593Smuzhiyun 		power_decrease = *p++;
2765*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD;
2766*4882a593Smuzhiyun 		temp_cmd[1] = 1;
2767*4882a593Smuzhiyun 		temp_cmd[2] = power_decrease;
2768*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
2769*4882a593Smuzhiyun 		break;
2770*4882a593Smuzhiyun 
2771*4882a593Smuzhiyun 	case BT_PSD_MODE_CONTROL:
2772*4882a593Smuzhiyun 		opcode_len = *p++;
2773*4882a593Smuzhiyun 		psd_mode = *p++;
2774*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE;
2775*4882a593Smuzhiyun 		temp_cmd[1] = 1;
2776*4882a593Smuzhiyun 		temp_cmd[2] = psd_mode;
2777*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 3, temp_cmd);
2778*4882a593Smuzhiyun 		break;
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	case WIFI_BW_CHNL_NOTIFY:
2781*4882a593Smuzhiyun 		opcode_len = *p++;
2782*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD;
2783*4882a593Smuzhiyun 		temp_cmd[1] = 3;
2784*4882a593Smuzhiyun 		memcpy(temp_cmd + 2, p, 3);	//wifi_state, wifi_centralchannel, chnnels_btnotuse
2785*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 5, temp_cmd);
2786*4882a593Smuzhiyun 		break;
2787*4882a593Smuzhiyun 
2788*4882a593Smuzhiyun 	case QUERY_BT_AFH_MAP:
2789*4882a593Smuzhiyun 		opcode_len = *p++;
2790*4882a593Smuzhiyun 		btrtl_coex.piconet_id = *p++;
2791*4882a593Smuzhiyun 		btrtl_coex.mode = *p++;
2792*4882a593Smuzhiyun 		temp_cmd[0] = HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L;
2793*4882a593Smuzhiyun 		temp_cmd[1] = 2;
2794*4882a593Smuzhiyun 		temp_cmd[2] = btrtl_coex.piconet_id;
2795*4882a593Smuzhiyun 		temp_cmd[3] = btrtl_coex.mode;
2796*4882a593Smuzhiyun 		rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 4, temp_cmd);
2797*4882a593Smuzhiyun 		break;
2798*4882a593Smuzhiyun 
2799*4882a593Smuzhiyun 	case BT_REGISTER_ACCESS:
2800*4882a593Smuzhiyun 		opcode_len = *p++;
2801*4882a593Smuzhiyun 		access_type = *p++;
2802*4882a593Smuzhiyun 		if (access_type == 0) {	//read
2803*4882a593Smuzhiyun 			temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ;
2804*4882a593Smuzhiyun 			temp_cmd[1] = 5;
2805*4882a593Smuzhiyun 			temp_cmd[2] = *p++;
2806*4882a593Smuzhiyun 			memcpy(temp_cmd + 3, p, 4);
2807*4882a593Smuzhiyun 			rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 7,
2808*4882a593Smuzhiyun 					     temp_cmd);
2809*4882a593Smuzhiyun 		} else {	//write
2810*4882a593Smuzhiyun 			temp_cmd[0] = HCI_VENDOR_SUB_CMD_RD_REG_REQ;
2811*4882a593Smuzhiyun 			temp_cmd[1] = 5;
2812*4882a593Smuzhiyun 			temp_cmd[2] = *p++;
2813*4882a593Smuzhiyun 			memcpy(temp_cmd + 3, p, 8);
2814*4882a593Smuzhiyun 			rtk_vendor_cmd_to_fw(HCI_VENDOR_MAILBOX_CMD, 11,
2815*4882a593Smuzhiyun 					     temp_cmd);
2816*4882a593Smuzhiyun 		}
2817*4882a593Smuzhiyun 		break;
2818*4882a593Smuzhiyun 
2819*4882a593Smuzhiyun 	default:
2820*4882a593Smuzhiyun 		break;
2821*4882a593Smuzhiyun 	}
2822*4882a593Smuzhiyun }
2823*4882a593Smuzhiyun 
rtk_handle_event_from_wifi(uint8_t * msg)2824*4882a593Smuzhiyun static void rtk_handle_event_from_wifi(uint8_t * msg)
2825*4882a593Smuzhiyun {
2826*4882a593Smuzhiyun 	uint8_t *p = msg;
2827*4882a593Smuzhiyun 	uint8_t event_code = *p++;
2828*4882a593Smuzhiyun 	uint8_t total_length;
2829*4882a593Smuzhiyun 	uint8_t extension_event;
2830*4882a593Smuzhiyun 	uint8_t operation;
2831*4882a593Smuzhiyun 	uint16_t wifi_opcode;
2832*4882a593Smuzhiyun 	uint8_t op_status;
2833*4882a593Smuzhiyun 
2834*4882a593Smuzhiyun 	if (memcmp(msg, invite_rsp, sizeof(invite_rsp)) == 0) {
2835*4882a593Smuzhiyun 		RTKBT_DBG("receive invite rsp from wifi, wifi is already on");
2836*4882a593Smuzhiyun 		btrtl_coex.wifi_on = 1;
2837*4882a593Smuzhiyun 		rtk_notify_extension_version_to_wifi();
2838*4882a593Smuzhiyun 	}
2839*4882a593Smuzhiyun 
2840*4882a593Smuzhiyun 	if (memcmp(msg, attend_req, sizeof(attend_req)) == 0) {
2841*4882a593Smuzhiyun 		RTKBT_DBG("receive attend req from wifi, wifi turn on");
2842*4882a593Smuzhiyun 		btrtl_coex.wifi_on = 1;
2843*4882a593Smuzhiyun 		rtkbt_coexmsg_send(attend_ack, sizeof(attend_ack));
2844*4882a593Smuzhiyun 		rtk_notify_extension_version_to_wifi();
2845*4882a593Smuzhiyun 	}
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun 	if (memcmp(msg, wifi_leave, sizeof(wifi_leave)) == 0) {
2848*4882a593Smuzhiyun 		RTKBT_DBG("receive wifi leave from wifi, wifi turn off");
2849*4882a593Smuzhiyun 		btrtl_coex.wifi_on = 0;
2850*4882a593Smuzhiyun 		rtkbt_coexmsg_send(leave_ack, sizeof(leave_ack));
2851*4882a593Smuzhiyun 		if (btrtl_coex.polling_enable) {
2852*4882a593Smuzhiyun 			btrtl_coex.polling_enable = 0;
2853*4882a593Smuzhiyun 			del_timer(&btrtl_coex.polling_timer);
2854*4882a593Smuzhiyun 		}
2855*4882a593Smuzhiyun 	}
2856*4882a593Smuzhiyun 
2857*4882a593Smuzhiyun 	if (memcmp(msg, leave_ack, sizeof(leave_ack)) == 0) {
2858*4882a593Smuzhiyun 		RTKBT_DBG("receive leave ack from wifi");
2859*4882a593Smuzhiyun 	}
2860*4882a593Smuzhiyun 
2861*4882a593Smuzhiyun 	if (event_code == 0xFE) {
2862*4882a593Smuzhiyun 		total_length = *p++;
2863*4882a593Smuzhiyun 		extension_event = *p++;
2864*4882a593Smuzhiyun 		switch (extension_event) {
2865*4882a593Smuzhiyun 		case RTK_HS_EXTENSION_EVENT_WIFI_SCAN:
2866*4882a593Smuzhiyun 			operation = *p;
2867*4882a593Smuzhiyun 			RTKBT_DBG("Recv WiFi scan notify event from WiFi, "
2868*4882a593Smuzhiyun 				  "op 0x%02x", operation);
2869*4882a593Smuzhiyun 			break;
2870*4882a593Smuzhiyun 
2871*4882a593Smuzhiyun 		case RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL:
2872*4882a593Smuzhiyun 			rtk_handle_bt_info_control(p);
2873*4882a593Smuzhiyun 			break;
2874*4882a593Smuzhiyun 
2875*4882a593Smuzhiyun 		case RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL:
2876*4882a593Smuzhiyun 			rtk_handle_bt_coex_control(p);
2877*4882a593Smuzhiyun 			break;
2878*4882a593Smuzhiyun 
2879*4882a593Smuzhiyun 		default:
2880*4882a593Smuzhiyun 			break;
2881*4882a593Smuzhiyun 		}
2882*4882a593Smuzhiyun 	}
2883*4882a593Smuzhiyun 
2884*4882a593Smuzhiyun 	if (event_code == 0x0E) {
2885*4882a593Smuzhiyun 		p += 2;		//length, number of complete packets
2886*4882a593Smuzhiyun 		STREAM_TO_UINT16(wifi_opcode, p);
2887*4882a593Smuzhiyun 		op_status = *p;
2888*4882a593Smuzhiyun 		RTKBT_DBG("Recv cmd complete event from WiFi, op 0x%02x, "
2889*4882a593Smuzhiyun 			  "status 0x%02x", wifi_opcode, op_status);
2890*4882a593Smuzhiyun 	}
2891*4882a593Smuzhiyun }
2892*4882a593Smuzhiyun #endif /* RTB_SOFTWARE_MAILBOX */
2893*4882a593Smuzhiyun 
rtl_free_frags(struct rtl_coex_struct * coex)2894*4882a593Smuzhiyun static inline void rtl_free_frags(struct rtl_coex_struct *coex)
2895*4882a593Smuzhiyun {
2896*4882a593Smuzhiyun 	unsigned long flags;
2897*4882a593Smuzhiyun 
2898*4882a593Smuzhiyun 	spin_lock_irqsave(&coex->rxlock, flags);
2899*4882a593Smuzhiyun 
2900*4882a593Smuzhiyun 	coex->elen = 0;
2901*4882a593Smuzhiyun 	coex->tbuff = NULL;
2902*4882a593Smuzhiyun 
2903*4882a593Smuzhiyun 	spin_unlock_irqrestore(&coex->rxlock, flags);
2904*4882a593Smuzhiyun }
2905*4882a593Smuzhiyun 
rtk_btcoex_open(struct hci_dev * hdev)2906*4882a593Smuzhiyun void rtk_btcoex_open(struct hci_dev *hdev)
2907*4882a593Smuzhiyun {
2908*4882a593Smuzhiyun 	if (test_and_set_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
2909*4882a593Smuzhiyun 		RTKBT_WARN("RTL COEX is already running.");
2910*4882a593Smuzhiyun 		return;
2911*4882a593Smuzhiyun 	}
2912*4882a593Smuzhiyun 
2913*4882a593Smuzhiyun 	RTKBT_INFO("Open BTCOEX");
2914*4882a593Smuzhiyun 
2915*4882a593Smuzhiyun 	/* Just for test */
2916*4882a593Smuzhiyun 	//struct rtl_btinfo_ctl ctl;
2917*4882a593Smuzhiyun 
2918*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&btrtl_coex.fw_work, (void *)rtl_ev_work);
2919*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2920*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
2921*4882a593Smuzhiyun 	INIT_WORK(&rtw_work, rtw_work_func);
2922*4882a593Smuzhiyun 	skb_queue_head_init(&rtw_q);
2923*4882a593Smuzhiyun 	rtw_coex_on = 1;
2924*4882a593Smuzhiyun #else
2925*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&btrtl_coex.sock_work,
2926*4882a593Smuzhiyun 			  (void *)udpsocket_recv_data);
2927*4882a593Smuzhiyun #endif
2928*4882a593Smuzhiyun #endif /* RTB_SOFTWARE_MAILBOX */
2929*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&btrtl_coex.l2_work, (void *)rtl_l2_work);
2930*4882a593Smuzhiyun 
2931*4882a593Smuzhiyun #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
2932*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2933*4882a593Smuzhiyun 	timer_setup(&btrtl_coex.polling_timer, polling_bt_info, 0);
2934*4882a593Smuzhiyun #endif
2935*4882a593Smuzhiyun 	timer_setup(&btrtl_coex.a2dp_count_timer, count_a2dp_packet_timeout, 0);
2936*4882a593Smuzhiyun 	timer_setup(&btrtl_coex.pan_count_timer, count_pan_packet_timeout, 0);
2937*4882a593Smuzhiyun 	timer_setup(&btrtl_coex.hogp_count_timer, count_hogp_packet_timeout, 0);
2938*4882a593Smuzhiyun #else
2939*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2940*4882a593Smuzhiyun 	setup_timer(&btrtl_coex.polling_timer, polling_bt_info, 0);
2941*4882a593Smuzhiyun #endif
2942*4882a593Smuzhiyun 	setup_timer(&btrtl_coex.a2dp_count_timer, count_a2dp_packet_timeout, 0);
2943*4882a593Smuzhiyun 	setup_timer(&btrtl_coex.pan_count_timer, count_pan_packet_timeout, 0);
2944*4882a593Smuzhiyun 	setup_timer(&btrtl_coex.hogp_count_timer, count_hogp_packet_timeout, 0);
2945*4882a593Smuzhiyun #endif
2946*4882a593Smuzhiyun 
2947*4882a593Smuzhiyun 	btrtl_coex.hdev = hdev;
2948*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2949*4882a593Smuzhiyun 	btrtl_coex.wifi_on = 0;
2950*4882a593Smuzhiyun #endif
2951*4882a593Smuzhiyun 
2952*4882a593Smuzhiyun 	init_profile_hash(&btrtl_coex);
2953*4882a593Smuzhiyun 	init_connection_hash(&btrtl_coex);
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun 	btrtl_coex.pkt_type = 0;
2956*4882a593Smuzhiyun 	btrtl_coex.expect = 0;
2957*4882a593Smuzhiyun 	btrtl_coex.elen = 0;
2958*4882a593Smuzhiyun 	btrtl_coex.tbuff = NULL;
2959*4882a593Smuzhiyun 
2960*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2961*4882a593Smuzhiyun #ifndef RTK_COEX_OVER_SYMBOL
2962*4882a593Smuzhiyun 	create_udpsocket();
2963*4882a593Smuzhiyun #endif
2964*4882a593Smuzhiyun 	rtkbt_coexmsg_send(invite_req, sizeof(invite_req));
2965*4882a593Smuzhiyun #endif
2966*4882a593Smuzhiyun 
2967*4882a593Smuzhiyun 	/* Just for test */
2968*4882a593Smuzhiyun 	//ctl.polling_enable = 1;
2969*4882a593Smuzhiyun 	//ctl.polling_time = 1;
2970*4882a593Smuzhiyun 	//ctl.autoreport_enable = 1;
2971*4882a593Smuzhiyun 	//rtk_handle_bt_info_control((u8 *)&ctl);
2972*4882a593Smuzhiyun }
2973*4882a593Smuzhiyun 
rtk_btcoex_close(void)2974*4882a593Smuzhiyun void rtk_btcoex_close(void)
2975*4882a593Smuzhiyun {
2976*4882a593Smuzhiyun 	int kk = 0;
2977*4882a593Smuzhiyun 
2978*4882a593Smuzhiyun 	if (!test_and_clear_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
2979*4882a593Smuzhiyun 		RTKBT_WARN("RTL COEX is already closed.");
2980*4882a593Smuzhiyun 		return;
2981*4882a593Smuzhiyun 	}
2982*4882a593Smuzhiyun 
2983*4882a593Smuzhiyun 	RTKBT_INFO("Close BTCOEX");
2984*4882a593Smuzhiyun 
2985*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
2986*4882a593Smuzhiyun 	/* Close coex socket */
2987*4882a593Smuzhiyun 	if (btrtl_coex.wifi_on)
2988*4882a593Smuzhiyun 		rtkbt_coexmsg_send(bt_leave, sizeof(bt_leave));
2989*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
2990*4882a593Smuzhiyun 	rtw_coex_on = 0;
2991*4882a593Smuzhiyun 	skb_queue_purge(&rtw_q);
2992*4882a593Smuzhiyun 	cancel_work_sync(&rtw_work);
2993*4882a593Smuzhiyun #else
2994*4882a593Smuzhiyun 	cancel_delayed_work_sync(&btrtl_coex.sock_work);
2995*4882a593Smuzhiyun 	if (btrtl_coex.sock_open) {
2996*4882a593Smuzhiyun 		btrtl_coex.sock_open = 0;
2997*4882a593Smuzhiyun 		RTKBT_DBG("release udp socket");
2998*4882a593Smuzhiyun 		sock_release(btrtl_coex.udpsock);
2999*4882a593Smuzhiyun 	}
3000*4882a593Smuzhiyun #endif
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	/* Delete all timers */
3003*4882a593Smuzhiyun 	if (btrtl_coex.polling_enable) {
3004*4882a593Smuzhiyun 		btrtl_coex.polling_enable = 0;
3005*4882a593Smuzhiyun 		del_timer_sync(&(btrtl_coex.polling_timer));
3006*4882a593Smuzhiyun 	}
3007*4882a593Smuzhiyun #endif /* RTB_SOFTWARE_MAILBOX */
3008*4882a593Smuzhiyun 
3009*4882a593Smuzhiyun 	del_timer_sync(&btrtl_coex.a2dp_count_timer);
3010*4882a593Smuzhiyun 	del_timer_sync(&btrtl_coex.pan_count_timer);
3011*4882a593Smuzhiyun 	del_timer_sync(&btrtl_coex.hogp_count_timer);
3012*4882a593Smuzhiyun 
3013*4882a593Smuzhiyun 	cancel_delayed_work_sync(&btrtl_coex.fw_work);
3014*4882a593Smuzhiyun 	cancel_delayed_work_sync(&btrtl_coex.l2_work);
3015*4882a593Smuzhiyun 
3016*4882a593Smuzhiyun 	flush_connection_hash(&btrtl_coex);
3017*4882a593Smuzhiyun 	flush_profile_hash(&btrtl_coex);
3018*4882a593Smuzhiyun 	btrtl_coex.profile_bitmap = 0;
3019*4882a593Smuzhiyun 	btrtl_coex.profile_status = 0;
3020*4882a593Smuzhiyun 	for (kk = 0; kk < 8; kk++)
3021*4882a593Smuzhiyun 		btrtl_coex.profile_refcount[kk] = 0;
3022*4882a593Smuzhiyun 
3023*4882a593Smuzhiyun 	rtl_free_frags(&btrtl_coex);
3024*4882a593Smuzhiyun 	RTKBT_DBG("-x");
3025*4882a593Smuzhiyun }
3026*4882a593Smuzhiyun 
rtk_btcoex_probe(struct hci_dev * hdev)3027*4882a593Smuzhiyun void rtk_btcoex_probe(struct hci_dev *hdev)
3028*4882a593Smuzhiyun {
3029*4882a593Smuzhiyun 	btrtl_coex.hdev = hdev;
3030*4882a593Smuzhiyun 	spin_lock_init(&btrtl_coex.spin_lock_sock);
3031*4882a593Smuzhiyun 	spin_lock_init(&btrtl_coex.spin_lock_profile);
3032*4882a593Smuzhiyun }
3033*4882a593Smuzhiyun 
rtk_btcoex_init(void)3034*4882a593Smuzhiyun void rtk_btcoex_init(void)
3035*4882a593Smuzhiyun {
3036*4882a593Smuzhiyun 	RTKBT_DBG("%s: version: %s", __func__, RTK_VERSION);
3037*4882a593Smuzhiyun 	RTKBT_DBG("create workqueue");
3038*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
3039*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
3040*4882a593Smuzhiyun 	RTKBT_INFO("Coex over Symbol");
3041*4882a593Smuzhiyun 	rtw_wq = create_workqueue("btcoexwork");
3042*4882a593Smuzhiyun 	skb_queue_head_init(&rtw_q);
3043*4882a593Smuzhiyun #else
3044*4882a593Smuzhiyun 	RTKBT_INFO("Coex over UDP");
3045*4882a593Smuzhiyun 	btrtl_coex.sock_wq = create_workqueue("btudpwork");
3046*4882a593Smuzhiyun #endif
3047*4882a593Smuzhiyun #endif /* RTB_SOFTWARE_MAILBOX */
3048*4882a593Smuzhiyun 	btrtl_coex.fw_wq = create_workqueue("btfwwork");
3049*4882a593Smuzhiyun 	rtl_alloc_buff(&btrtl_coex);
3050*4882a593Smuzhiyun 	spin_lock_init(&btrtl_coex.rxlock);
3051*4882a593Smuzhiyun }
3052*4882a593Smuzhiyun 
rtk_btcoex_exit(void)3053*4882a593Smuzhiyun void rtk_btcoex_exit(void)
3054*4882a593Smuzhiyun {
3055*4882a593Smuzhiyun 	RTKBT_DBG("%s: destroy workqueue", __func__);
3056*4882a593Smuzhiyun #ifdef RTB_SOFTWARE_MAILBOX
3057*4882a593Smuzhiyun #ifdef RTK_COEX_OVER_SYMBOL
3058*4882a593Smuzhiyun 	flush_workqueue(rtw_wq);
3059*4882a593Smuzhiyun 	destroy_workqueue(rtw_wq);
3060*4882a593Smuzhiyun #else
3061*4882a593Smuzhiyun 	flush_workqueue(btrtl_coex.sock_wq);
3062*4882a593Smuzhiyun 	destroy_workqueue(btrtl_coex.sock_wq);
3063*4882a593Smuzhiyun #endif
3064*4882a593Smuzhiyun #endif
3065*4882a593Smuzhiyun 	flush_workqueue(btrtl_coex.fw_wq);
3066*4882a593Smuzhiyun 	destroy_workqueue(btrtl_coex.fw_wq);
3067*4882a593Smuzhiyun 	rtl_free_buff(&btrtl_coex);
3068*4882a593Smuzhiyun }
3069