blob: 101697f2d4e04da98c1b3e6eb8dadd84011bf34b [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * HCI_SMD (HCI Shared Memory Driver) is Qualcomm's Shared memory driver
3 * for the BT HCI protocol.
4 *
5 * Copyright (c) 2000-2001, 2011 Code Aurora Forum. All rights reserved.
6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
7 * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
8 *
9 * This file is based on drivers/bluetooth/hci_vhci.c
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 */
20
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/errno.h>
25#include <linux/string.h>
26#include <linux/skbuff.h>
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070027#include <linux/wakelock.h>
28#include <linux/uaccess.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/hci.h>
32#include <mach/msm_smd.h>
33
Bhasker Netid08d9012011-09-05 19:37:54 +053034#define EVENT_CHANNEL "APPS_RIVA_BT_CMD"
35#define DATA_CHANNEL "APPS_RIVA_BT_ACL"
36#define RX_Q_MONITOR (1) /* 1 milli second */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070038
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070039static int hcismd_set;
40static DEFINE_MUTEX(hci_smd_enable);
41
42static int hcismd_set_enable(const char *val, struct kernel_param *kp);
43module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
44
45
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046struct hci_smd_data {
47 struct hci_dev *hdev;
48
49 struct smd_channel *event_channel;
50 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053051 struct wake_lock wake_lock_tx;
52 struct wake_lock wake_lock_rx;
53 struct timer_list rx_q_timer;
Ankur Nandwani034ed892011-10-07 11:15:53 -070054 struct tasklet_struct hci_event_task;
55 struct tasklet_struct hci_data_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070057static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058
Bhasker Netid08d9012011-09-05 19:37:54 +053059/* Rx queue monitor timer function */
60static int is_rx_q_empty(unsigned long arg)
61{
62 struct hci_dev *hdev = (struct hci_dev *) arg;
63 struct sk_buff_head *list_ = &hdev->rx_q;
64 struct sk_buff *list = ((struct sk_buff *)list_)->next;
65 BT_DBG("%s Rx timer triggered", hdev->name);
66
67 if (list == (struct sk_buff *)list_) {
68 BT_DBG("%s RX queue empty", hdev->name);
69 return 1;
70 } else{
71 BT_DBG("%s RX queue not empty", hdev->name);
72 return 0;
73 }
74}
75
76static void release_lock(void)
77{
78 struct hci_smd_data *hsmd = &hs;
79 BT_DBG("Releasing Rx Lock");
80 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
81 wake_lock_active(&hs.wake_lock_rx))
82 wake_unlock(&hs.wake_lock_rx);
83}
84
85/* Rx timer callback function */
86static void schedule_timer(unsigned long arg)
87{
88 struct hci_dev *hdev = (struct hci_dev *) arg;
89 struct hci_smd_data *hsmd = &hs;
90 BT_DBG("%s Schedule Rx timer", hdev->name);
91
92 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
93 BT_DBG("%s RX queue empty", hdev->name);
94 /*
95 * Since the queue is empty, its ideal
96 * to release the wake lock on Rx
97 */
98 wake_unlock(&hs.wake_lock_rx);
99 } else{
100 BT_DBG("%s RX queue not empty", hdev->name);
101 /*
102 * Restart the timer to monitor whether the Rx queue is
103 * empty for releasing the Rx wake lock
104 */
105 mod_timer(&hsmd->rx_q_timer,
106 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
107 }
108}
109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110static int hci_smd_open(struct hci_dev *hdev)
111{
112 set_bit(HCI_RUNNING, &hdev->flags);
113 return 0;
114}
115
116
117static int hci_smd_close(struct hci_dev *hdev)
118{
119 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
120 return 0;
121 else
122 return -EPERM;
123}
124
125
126static void hci_smd_destruct(struct hci_dev *hdev)
127{
Bhasker Neti60576c62011-12-07 18:45:51 -0800128 if (NULL != hdev->driver_data)
129 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130}
131
132static void hci_smd_recv_data(unsigned long arg)
133{
Bhasker Netid08d9012011-09-05 19:37:54 +0530134 int len = 0;
135 int rc = 0;
136 struct sk_buff *skb = NULL;
137 unsigned char *buf = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530139 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140
141 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800142 if (len > HCI_MAX_FRAME_SIZE) {
143 BT_ERR("Frame larger than the allowed size");
Bhasker Netid08d9012011-09-05 19:37:54 +0530144 goto out_data;
145 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700147 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 if (!skb) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800149 BT_ERR("Error in allocating socket buffer");
Bhasker Netid08d9012011-09-05 19:37:54 +0530150 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 }
152
Ankur Nandwanic8150962011-08-24 13:06:23 -0700153 buf = kmalloc(len, GFP_ATOMIC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 if (!buf) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800155 BT_ERR("Error in allocating buffer");
Bhasker Netid08d9012011-09-05 19:37:54 +0530156 rc = -ENOMEM;
157 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 }
159
Ankur Nandwani531333f2011-10-25 15:47:43 -0700160 rc = smd_read(hsmd->data_channel, (void *)buf, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 if (rc < len) {
162 BT_ERR("Error in reading from the channel");
Bhasker Netid08d9012011-09-05 19:37:54 +0530163 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164 }
165
166 memcpy(skb_put(skb, len), buf, len);
167 skb->dev = (void *)hsmd->hdev;
168 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
169
170 skb_orphan(skb);
171
172 rc = hci_recv_frame(skb);
173 if (rc < 0) {
174 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530175 /*
176 * skb is getting freed in hci_recv_frame, making it
177 * to null to avoid multiple access
178 */
179 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530180 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181 }
182
183 kfree(buf);
Bhasker Netid08d9012011-09-05 19:37:54 +0530184 buf = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 len = smd_read_avail(hsmd->data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530186 /*
187 * Start the timer to monitor whether the Rx queue is
188 * empty for releasing the Rx wake lock
189 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800190 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530191 mod_timer(&hsmd->rx_q_timer,
192 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
193 }
194out_data:
195 release_lock();
196 if (rc) {
197 if (skb)
198 kfree_skb(skb);
199 kfree(buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 }
201}
202
203static void hci_smd_recv_event(unsigned long arg)
204{
Bhasker Netid08d9012011-09-05 19:37:54 +0530205 int len = 0;
206 int rc = 0;
207 struct sk_buff *skb = NULL;
208 unsigned char *buf = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530210 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211
212 len = smd_read_avail(hsmd->event_channel);
213 if (len > HCI_MAX_FRAME_SIZE) {
214 BT_ERR("Frame larger than the allowed size");
Bhasker Netid08d9012011-09-05 19:37:54 +0530215 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 }
217
218 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700219 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530220 if (!skb) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800221 BT_ERR("Error in allocating socket buffer");
Bhasker Netid08d9012011-09-05 19:37:54 +0530222 goto out_event;
223 }
Ankur Nandwanic8150962011-08-24 13:06:23 -0700224 buf = kmalloc(len, GFP_ATOMIC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 if (!buf) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800226 BT_ERR("Error in allocating buffer");
Bhasker Netid08d9012011-09-05 19:37:54 +0530227 rc = -ENOMEM;
228 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 }
Ankur Nandwani531333f2011-10-25 15:47:43 -0700230 rc = smd_read(hsmd->event_channel, (void *)buf, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530231 if (rc < len) {
232 BT_ERR("Error in reading from the event channel");
233 goto out_event;
234 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235
236 memcpy(skb_put(skb, len), buf, len);
237 skb->dev = (void *)hsmd->hdev;
238 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
239
240 skb_orphan(skb);
241
242 rc = hci_recv_frame(skb);
243 if (rc < 0) {
244 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530245 /*
246 * skb is getting freed in hci_recv_frame, making it
247 * to null to avoid multiple access
248 */
249 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530250 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 }
252
253 kfree(buf);
Bhasker Netid08d9012011-09-05 19:37:54 +0530254 buf = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530256 /*
257 * Start the timer to monitor whether the Rx queue is
258 * empty for releasing the Rx wake lock
259 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800260 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530261 mod_timer(&hsmd->rx_q_timer,
262 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
263 }
264out_event:
265 release_lock();
266 if (rc) {
267 if (skb)
268 kfree_skb(skb);
269 kfree(buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 }
271}
272
273static int hci_smd_send_frame(struct sk_buff *skb)
274{
275 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530276 int avail;
277 int ret = 0;
278 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279
280 switch (bt_cb(skb)->pkt_type) {
281 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530282 avail = smd_write_avail(hs.event_channel);
283 if (!avail) {
284 BT_ERR("No space available for smd frame");
285 ret = -ENOSPC;
286 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 len = smd_write(hs.event_channel, skb->data, skb->len);
288 if (len < skb->len) {
289 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530290 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 }
292 break;
293 case HCI_ACLDATA_PKT:
294 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700295 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530296 if (!avail) {
297 BT_ERR("No space available for smd frame");
298 ret = -ENOSPC;
299 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 len = smd_write(hs.data_channel, skb->data, skb->len);
301 if (len < skb->len) {
302 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530303 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 }
305 break;
306 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800307 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530308 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 break;
310 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530311
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530312 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530313 wake_unlock(&hs.wake_lock_tx);
314 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315}
316
317
318static void hci_smd_notify_event(void *data, unsigned int event)
319{
320 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800321 struct hci_smd_data *hsmd = &hs;
322 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323
324 if (!hdev) {
325 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
326 return;
327 }
328
329 switch (event) {
330 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800331 len = smd_read_avail(hsmd->event_channel);
332 if (len > 0)
333 tasklet_hi_schedule(&hs.hci_event_task);
334 else if (len < 0)
335 BT_ERR("Failed to read event from smd %d", len);
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 break;
338 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800339 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 hci_smd_open(hdev);
341 break;
342 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800343 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344 hci_smd_close(hdev);
345 break;
346 default:
347 break;
348 }
349}
350
351static void hci_smd_notify_data(void *data, unsigned int event)
352{
353 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800354 struct hci_smd_data *hsmd = &hs;
355 int len = 0;
356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 if (!hdev) {
358 BT_ERR("HCI device (hdev=NULL)");
359 return;
360 }
361
362 switch (event) {
363 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800364 len = smd_read_avail(hsmd->data_channel);
365 if (len > 0)
366 tasklet_hi_schedule(&hs.hci_data_task);
367 else if (len < 0)
368 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369 break;
370 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800371 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 hci_smd_open(hdev);
373 break;
374 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800375 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376 hci_smd_close(hdev);
377 break;
378 default:
379 break;
380 }
381
382}
383
384static int hci_smd_register_dev(struct hci_smd_data *hsmd)
385{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700386 static struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 int rc;
388
389 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800390 hdev = hci_alloc_dev();
391 if (!hdev) {
392 BT_ERR("Can't allocate HCI device");
393 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700394 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395
Bhasker Neti60576c62011-12-07 18:45:51 -0800396 hsmd->hdev = hdev;
397 hdev->bus = HCI_SMD;
398 hdev->driver_data = NULL;
399 hdev->open = hci_smd_open;
400 hdev->close = hci_smd_close;
401 hdev->send = hci_smd_send_frame;
402 hdev->destruct = hci_smd_destruct;
403 hdev->owner = THIS_MODULE;
404
Ankur Nandwani034ed892011-10-07 11:15:53 -0700405 tasklet_init(&hsmd->hci_event_task,
406 hci_smd_recv_event, (unsigned long) hsmd);
407 tasklet_init(&hsmd->hci_data_task,
408 hci_smd_recv_data, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530409 /*
410 * Setup the timer to monitor whether the Rx queue is empty,
411 * to control the wake lock release
412 */
413 setup_timer(&hsmd->rx_q_timer, schedule_timer,
414 (unsigned long) hsmd->hdev);
415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 /* Open the SMD Channel and device and register the callback function */
417 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
418 &hsmd->event_channel, hdev, hci_smd_notify_event);
419 if (rc < 0) {
420 BT_ERR("Cannot open the command channel");
421 hci_free_dev(hdev);
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530422 hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 return -ENODEV;
424 }
425
426 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
427 &hsmd->data_channel, hdev, hci_smd_notify_data);
428 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800429 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 hci_free_dev(hdev);
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530431 hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 return -ENODEV;
433 }
434
435 /* Disable the read interrupts on the channel */
436 smd_disable_read_intr(hsmd->event_channel);
437 smd_disable_read_intr(hsmd->data_channel);
Bhasker Neti60576c62011-12-07 18:45:51 -0800438 if (hci_register_dev(hdev) < 0) {
439 BT_ERR("Can't register HCI device");
440 hci_free_dev(hdev);
441 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 return 0;
444}
445
Bhasker Neti60576c62011-12-07 18:45:51 -0800446static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447{
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530448 if (hsmd->hdev) {
449 if (hci_unregister_dev(hsmd->hdev) < 0)
450 BT_ERR("Can't unregister HCI device %s",
451 hsmd->hdev->name);
452
453 hci_free_dev(hsmd->hdev);
454 hsmd->hdev = NULL;
455 }
456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530459
Ankur Nandwani327e0502011-11-11 15:47:25 -0800460 if (wake_lock_active(&hs.wake_lock_rx))
461 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800462 if (wake_lock_active(&hs.wake_lock_tx))
463 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800464
Bhasker Netid08d9012011-09-05 19:37:54 +0530465 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530466 if (hs.rx_q_timer.function) {
467 del_timer_sync(&hs.rx_q_timer);
468 hs.rx_q_timer.function = NULL;
469 hs.rx_q_timer.data = 0;
470 }
471
Ankur Nandwani034ed892011-10-07 11:15:53 -0700472 tasklet_kill(&hs.hci_event_task);
473 tasklet_kill(&hs.hci_data_task);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474}
475
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700476static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700478 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700480 mutex_lock(&hci_smd_enable);
481
482 ret = param_set_int(val, kp);
483
484 if (ret)
485 goto done;
486
487 switch (hcismd_set) {
488
489 case 1:
490 hci_smd_register_dev(&hs);
491 break;
492 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800493 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700494 break;
495 default:
496 ret = -EFAULT;
497 }
498
499done:
500 mutex_unlock(&hci_smd_enable);
501 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502}
Bhasker Neti60576c62011-12-07 18:45:51 -0800503static int __init hci_smd_init(void)
504{
505 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
506 "msm_smd_Rx");
507 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
508 "msm_smd_Tx");
509 return 0;
510}
511module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700512
Bhasker Neti60576c62011-12-07 18:45:51 -0800513static void __exit hci_smd_exit(void)
514{
515 wake_lock_destroy(&hs.wake_lock_rx);
516 wake_lock_destroy(&hs.wake_lock_tx);
517}
518module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519
520MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
521MODULE_DESCRIPTION("Bluetooth SMD driver");
522MODULE_LICENSE("GPL v2");