2 * DHD BT WiFi Coex RegON Coordinator
4 * Copyright (C) 2020, Broadcom.
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
21 * <<Broadcom-WL-IPTag/Open:>>
24 #include <linux/cdev.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/device.h>
28 #include <linux/kernel.h>
29 #include <linux/slab.h>
31 #include <linux/uaccess.h>
32 #include <linux/poll.h>
33 #include <linux/eventpoll.h>
34 #include <linux/version.h>
36 #define DESCRIPTION "Broadcom WiFi BT Regon coordinator Driver"
37 #define AUTHOR "Broadcom Corporation"
39 #define DEVICE_NAME "wbrc"
40 #define CLASS_NAME "bcm"
50 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
51 typedef unsigned int __poll_t
;
55 * 4 byte message to sync with BT stack.
57 * Byte 1 - length of LTV now fixed to 2
59 * Byte 3 - command value
61 #define WBRC_MSG_LEN 4u
63 /* Below defines to be mapped in the user space. */
64 /* TODO have these as enums and define new structure with members */
66 /* Byte 0 - Define header for direction of command */
67 #define HEADER_DIR_WL2BT 0x01
68 #define HEADER_DIR_BT2WL 0x02
71 * Byte 2 - Define Type of Command (Followed LTV format)
72 * wifi/bt, signal/ack types
74 #define TYPE_WIFI_CMD 0x01
75 #define TYPE_WIFI_ACK 0x02
76 #define TYPE_BT_CMD 0x03
77 #define TYPE_BT_ACK 0x04
79 /* Byte 3 - Define Value field: commands/acks */
80 #define CMD_RESET_WIFI 0x40
81 #define CMD_RESET_WIFI_WITH_ACK 0x41
82 #define CMD_RESET_BT 0x42
83 #define CMD_RESET_BT_WITH_ACK 0x43
84 #define ACK_RESET_WIFI_COMPLETE 0x80
85 #define ACK_RESET_BT_COMPLETE 0x81
87 struct wbrc_pvt_data
{
88 int wbrc_bt_dev_major_number
; /* BT char dev major number */
89 struct class *wbrc_bt_dev_class
; /* BT char dev class */
90 struct device
*wbrc_bt_dev_device
; /* BT char dev */
91 struct mutex wbrc_mutex
; /* mutex to synchronise */
92 bool bt_dev_opened
; /* To check if bt dev open is called */
93 wait_queue_head_t bt_reset_waitq
; /* waitq to wait till bt reset is done */
94 unsigned int bt_reset_ack
; /* condition variable to be check for bt reset */
95 wait_queue_head_t wlan_reset_waitq
; /* waitq to wait till wlan reset is done */
96 unsigned int wlan_reset_ack
; /* condition variable to be check for wlan reset */
97 wait_queue_head_t outmsg_waitq
; /* wait queue for poll */
98 char wl2bt_message
[WBRC_MSG_LEN
]; /* message to communicate with Bt stack */
99 bool read_data_available
; /* condition to check if read data is present */
102 static struct wbrc_pvt_data
*g_wbrc_data
;
104 #define WBRC_LOCK(wbrc_data) {if (wbrc_data) mutex_lock(&(wbrc_data)->wbrc_mutex);}
105 #define WBRC_UNLOCK(wbrc_data) {if (wbrc_data) mutex_unlock(&(wbrc_data)->wbrc_mutex);}
107 int wbrc_wl2bt_reset(void);
108 int wbrc_bt_reset_ack(struct wbrc_pvt_data
*wbrc_data
);
110 int wbrc_bt2wl_reset(void);
111 int wbrc_wl_reset_ack(struct wbrc_pvt_data
*wbrc_data
);
113 static int wbrc_bt_dev_open(struct inode
*, struct file
*);
114 static int wbrc_bt_dev_release(struct inode
*, struct file
*);
115 static ssize_t
wbrc_bt_dev_read(struct file
*, char *, size_t, loff_t
*);
116 static ssize_t
wbrc_bt_dev_write(struct file
*, const char *, size_t, loff_t
*);
117 static __poll_t
wbrc_bt_dev_poll(struct file
*filep
, poll_table
*wait
);
119 static struct file_operations wbrc_bt_dev_fops
= {
120 .open
= wbrc_bt_dev_open
,
121 .read
= wbrc_bt_dev_read
,
122 .write
= wbrc_bt_dev_write
,
123 .release
= wbrc_bt_dev_release
,
124 .poll
= wbrc_bt_dev_poll
,
127 static ssize_t
wbrc_bt_dev_read(struct file
*filep
, char *buffer
, size_t len
,
130 struct wbrc_pvt_data
*wbrc_data
= filep
->private_data
;
134 WBRC_LOCK(wbrc_data
);
135 pr_info("%s\n", __func__
);
136 if (wbrc_data
->read_data_available
== FALSE
) {
139 if (len
< WBRC_MSG_LEN
) {
140 pr_err("%s: invalid length:%d\n", __func__
, (int)len
);
144 err_count
= copy_to_user(buffer
, &wbrc_data
->wl2bt_message
,
145 sizeof(wbrc_data
->wl2bt_message
));
146 if (err_count
== 0) {
147 pr_info("Sent %d bytes\n",
148 (int)sizeof(wbrc_data
->wl2bt_message
));
149 err_count
= sizeof(wbrc_data
->wl2bt_message
);
151 pr_err("Failed to send %d bytes\n", err_count
);
154 wbrc_data
->read_data_available
= FALSE
;
157 WBRC_UNLOCK(wbrc_data
);
161 static ssize_t
wbrc_bt_dev_write(struct file
*filep
, const char *buffer
,
162 size_t len
, loff_t
*offset
)
164 struct wbrc_pvt_data
*wbrc_data
= filep
->private_data
;
167 char message
[WBRC_MSG_LEN
] = {};
169 WBRC_LOCK(wbrc_data
);
171 pr_info("%s Received %zu bytes\n", __func__
, len
);
172 if (len
< WBRC_MSG_LEN
) {
173 pr_err("%s: Received malformed packet:%d\n", __func__
, (int)len
);
178 err_count
= copy_from_user(message
, buffer
, len
);
180 pr_err("%s: copy_from_user failed:%d\n", __func__
, err_count
);
185 if (message
[0] != HEADER_DIR_BT2WL
) {
186 pr_err("%s: invalid header:%d\n", __func__
, message
[0]);
191 if (message
[2] == TYPE_BT_CMD
) {
192 switch (message
[3]) {
194 pr_info("RCVD CMD_RESET_WIFI\n");
196 case CMD_RESET_WIFI_WITH_ACK
:
197 pr_info("RCVD CMD_RESET_WIFI_WITH_ACK\n");
202 if (message
[2] == TYPE_BT_ACK
&& message
[3] == ACK_RESET_BT_COMPLETE
) {
203 pr_info("RCVD ACK_RESET_BT_COMPLETE");
204 wbrc_bt_reset_ack(wbrc_data
);
208 WBRC_UNLOCK(wbrc_data
);
212 static __poll_t
wbrc_bt_dev_poll(struct file
*filep
, poll_table
*wait
)
214 struct wbrc_pvt_data
*wbrc_data
= filep
->private_data
;
217 poll_wait(filep
, &wbrc_data
->outmsg_waitq
, wait
);
219 if (wbrc_data
->read_data_available
)
220 mask
|= EPOLLIN
| EPOLLRDNORM
;
222 if (!wbrc_data
->bt_dev_opened
)
228 static int wbrc_bt_dev_open(struct inode
*inodep
, struct file
*filep
)
230 struct wbrc_pvt_data
*wbrc_data
= g_wbrc_data
;
232 WBRC_LOCK(wbrc_data
);
233 if (wbrc_data
->bt_dev_opened
) {
234 pr_err("%s already opened\n", __func__
);
238 wbrc_data
->bt_dev_opened
= TRUE
;
239 pr_info("%s Device opened %d time(s)\n", __func__
,
240 wbrc_data
->bt_dev_opened
);
241 filep
->private_data
= wbrc_data
;
244 WBRC_UNLOCK(wbrc_data
);
248 static int wbrc_bt_dev_release(struct inode
*inodep
, struct file
*filep
)
250 struct wbrc_pvt_data
*wbrc_data
= filep
->private_data
;
251 WBRC_LOCK(wbrc_data
);
252 pr_info("%s Device closed %d\n", __func__
, wbrc_data
->bt_dev_opened
);
253 wbrc_data
->bt_dev_opened
= FALSE
;
254 WBRC_UNLOCK(wbrc_data
);
255 wake_up_interruptible(&wbrc_data
->outmsg_waitq
);
259 void wbrc_signal_bt_reset(struct wbrc_pvt_data
*wbrc_data
)
261 pr_info("%s\n", __func__
);
263 /* Below message will be read by userspace using .read */
264 wbrc_data
->wl2bt_message
[0] = HEADER_DIR_WL2BT
; // Minimal Header
265 wbrc_data
->wl2bt_message
[1] = 2; // Length
266 wbrc_data
->wl2bt_message
[2] = TYPE_WIFI_CMD
; // Type
267 wbrc_data
->wl2bt_message
[3] = CMD_RESET_BT_WITH_ACK
; // Value
268 wbrc_data
->read_data_available
= TRUE
;
271 wake_up_interruptible(&wbrc_data
->outmsg_waitq
);
277 struct wbrc_pvt_data
*wbrc_data
;
278 pr_info("%s\n", __func__
);
279 wbrc_data
= kzalloc(sizeof(struct wbrc_pvt_data
), GFP_KERNEL
);
280 if (wbrc_data
== NULL
) {
283 mutex_init(&wbrc_data
->wbrc_mutex
);
284 init_waitqueue_head(&wbrc_data
->bt_reset_waitq
);
285 init_waitqueue_head(&wbrc_data
->wlan_reset_waitq
);
286 init_waitqueue_head(&wbrc_data
->outmsg_waitq
);
287 g_wbrc_data
= wbrc_data
;
289 wbrc_data
->wbrc_bt_dev_major_number
= register_chrdev(0, DEVICE_NAME
, &wbrc_bt_dev_fops
);
290 err
= wbrc_data
->wbrc_bt_dev_major_number
;
291 if (wbrc_data
->wbrc_bt_dev_major_number
< 0) {
292 pr_alert("wbrc_sequencer failed to register a major number\n");
296 wbrc_data
->wbrc_bt_dev_class
= class_create(THIS_MODULE
, CLASS_NAME
);
297 err
= PTR_ERR(wbrc_data
->wbrc_bt_dev_class
);
298 if (IS_ERR(wbrc_data
->wbrc_bt_dev_class
)) {
299 pr_alert("Failed to register device class\n");
303 wbrc_data
->wbrc_bt_dev_device
= device_create(
304 wbrc_data
->wbrc_bt_dev_class
, NULL
, MKDEV(wbrc_data
->wbrc_bt_dev_major_number
, 0),
306 err
= PTR_ERR(wbrc_data
->wbrc_bt_dev_device
);
307 if (IS_ERR(wbrc_data
->wbrc_bt_dev_device
)) {
308 pr_alert("Failed to create the device\n");
311 pr_info("device class created correctly\n");
316 class_destroy(wbrc_data
->wbrc_bt_dev_class
);
318 unregister_chrdev(wbrc_data
->wbrc_bt_dev_major_number
, DEVICE_NAME
);
327 struct wbrc_pvt_data
*wbrc_data
= g_wbrc_data
;
328 pr_info("%s\n", __func__
);
329 wake_up_interruptible(&wbrc_data
->outmsg_waitq
);
330 device_destroy(wbrc_data
->wbrc_bt_dev_class
, MKDEV(wbrc_data
->wbrc_bt_dev_major_number
, 0));
331 class_destroy(wbrc_data
->wbrc_bt_dev_class
);
332 unregister_chrdev(wbrc_data
->wbrc_bt_dev_major_number
, DEVICE_NAME
);
337 #ifndef BCMDHD_MODULAR
338 /* Required only for Built-in DHD */
339 module_init(wbrc_init
);
340 module_exit(wbrc_exit
);
341 #endif /* BOARD_MODULAR */
343 MODULE_LICENSE("GPL v2");
344 MODULE_DESCRIPTION(DESCRIPTION
);
345 MODULE_AUTHOR(AUTHOR
);
348 * Wait until the condition *var == condition is met.
349 * Returns 0 if the @condition evaluated to false after the timeout elapsed
350 * Returns 1 if the @condition evaluated to true
352 #define WBRC_RESET_WAIT_TIMEOUT 4000
354 wbrc_reset_wait_on_condition(wait_queue_head_t
*reset_waitq
, uint
*var
, uint condition
)
358 /* Convert timeout in millsecond to jiffies */
359 timeout
= msecs_to_jiffies(WBRC_RESET_WAIT_TIMEOUT
);
361 timeout
= wait_event_timeout(*reset_waitq
, (*var
== condition
), timeout
);
366 /* WBRC_LOCK should be held from caller */
367 int wbrc_bt_reset_ack(struct wbrc_pvt_data
*wbrc_data
)
369 pr_info("%s\n", __func__
);
370 wbrc_data
->bt_reset_ack
= TRUE
;
372 wake_up(&wbrc_data
->bt_reset_waitq
);
376 int wbrc_wl2bt_reset(void)
379 struct wbrc_pvt_data
*wbrc_data
= g_wbrc_data
;
381 pr_info("%s\n", __func__
);
383 WBRC_LOCK(wbrc_data
);
384 if (!wbrc_data
->bt_dev_opened
) {
385 pr_info("%s: no BT\n", __func__
);
386 WBRC_UNLOCK(wbrc_data
);
390 wbrc_data
->bt_reset_ack
= FALSE
;
392 wbrc_signal_bt_reset(wbrc_data
);
394 WBRC_UNLOCK(wbrc_data
);
395 /* Wait till BT reset is done */
396 wbrc_reset_wait_on_condition(&wbrc_data
->bt_reset_waitq
,
397 &wbrc_data
->bt_reset_ack
, TRUE
);
398 if (wbrc_data
->bt_reset_ack
== FALSE
) {
399 pr_err("%s: BT reset timeout\n", __func__
);
404 EXPORT_SYMBOL(wbrc_wl2bt_reset
);
406 int wbrc_signal_wlan_reset(struct wbrc_pvt_data
*wbrc_data
)
408 /* TODO call dhd reset, right now just send ack from here */
409 wbrc_wl_reset_ack(wbrc_data
);
413 /* WBRC_LOCK should be held from caller, this will be called from DHD */
414 int wbrc_wl_reset_ack(struct wbrc_pvt_data
*wbrc_data
)
416 pr_info("%s\n", __func__
);
417 wbrc_data
->wlan_reset_ack
= TRUE
;
419 wake_up(&wbrc_data
->wlan_reset_waitq
);
422 EXPORT_SYMBOL(wbrc_wl_reset_ack
);
424 int wbrc_bt2wl_reset(void)
427 struct wbrc_pvt_data
*wbrc_data
= g_wbrc_data
;
429 pr_info("%s\n", __func__
);
431 WBRC_LOCK(wbrc_data
);
432 wbrc_data
->wlan_reset_ack
= FALSE
;
433 wbrc_signal_wlan_reset(wbrc_data
);
434 /* Wait till WLAN reset is done */
435 wbrc_reset_wait_on_condition(&wbrc_data
->wlan_reset_waitq
,
436 &wbrc_data
->wlan_reset_ack
, TRUE
);
437 if (wbrc_data
->wlan_reset_ack
== FALSE
) {
438 pr_err("%s: WLAN reset timeout\n", __func__
);
441 WBRC_UNLOCK(wbrc_data
);
444 EXPORT_SYMBOL(wbrc_bt2wl_reset
);