blob: 4e781528afbaa22f65698d5356a35744fef0dcc6 [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 *
Bhasker Netiaae61462012-01-12 19:14:25 +05305 * Copyright (c) 2000-2001, 2011-2012 Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 * 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;
Bhasker Netiaae61462012-01-12 19:14:25 +053054 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070056static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057
Bhasker Netid08d9012011-09-05 19:37:54 +053058/* Rx queue monitor timer function */
59static int is_rx_q_empty(unsigned long arg)
60{
61 struct hci_dev *hdev = (struct hci_dev *) arg;
62 struct sk_buff_head *list_ = &hdev->rx_q;
63 struct sk_buff *list = ((struct sk_buff *)list_)->next;
64 BT_DBG("%s Rx timer triggered", hdev->name);
65
66 if (list == (struct sk_buff *)list_) {
67 BT_DBG("%s RX queue empty", hdev->name);
68 return 1;
69 } else{
70 BT_DBG("%s RX queue not empty", hdev->name);
71 return 0;
72 }
73}
74
75static void release_lock(void)
76{
77 struct hci_smd_data *hsmd = &hs;
78 BT_DBG("Releasing Rx Lock");
79 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
80 wake_lock_active(&hs.wake_lock_rx))
81 wake_unlock(&hs.wake_lock_rx);
82}
83
84/* Rx timer callback function */
85static void schedule_timer(unsigned long arg)
86{
87 struct hci_dev *hdev = (struct hci_dev *) arg;
88 struct hci_smd_data *hsmd = &hs;
89 BT_DBG("%s Schedule Rx timer", hdev->name);
90
91 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
92 BT_DBG("%s RX queue empty", hdev->name);
93 /*
94 * Since the queue is empty, its ideal
95 * to release the wake lock on Rx
96 */
97 wake_unlock(&hs.wake_lock_rx);
98 } else{
99 BT_DBG("%s RX queue not empty", hdev->name);
100 /*
101 * Restart the timer to monitor whether the Rx queue is
102 * empty for releasing the Rx wake lock
103 */
104 mod_timer(&hsmd->rx_q_timer,
105 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
106 }
107}
108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109static int hci_smd_open(struct hci_dev *hdev)
110{
111 set_bit(HCI_RUNNING, &hdev->flags);
112 return 0;
113}
114
115
116static int hci_smd_close(struct hci_dev *hdev)
117{
118 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
119 return 0;
120 else
121 return -EPERM;
122}
123
124
125static void hci_smd_destruct(struct hci_dev *hdev)
126{
Bhasker Neti60576c62011-12-07 18:45:51 -0800127 if (NULL != hdev->driver_data)
128 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129}
130
Bhasker Netiaae61462012-01-12 19:14:25 +0530131static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132{
Bhasker Netid08d9012011-09-05 19:37:54 +0530133 int len = 0;
134 int rc = 0;
135 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530137 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138
139 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800140 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530141 BT_ERR("Frame larger than the allowed size, flushing frame");
142 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530143 goto out_data;
144 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145
Bhasker Netiaae61462012-01-12 19:14:25 +0530146 if (len <= 0)
147 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148
Bhasker Netiaae61462012-01-12 19:14:25 +0530149 skb = bt_skb_alloc(len, GFP_ATOMIC);
150 if (!skb) {
151 BT_ERR("Error in allocating socket buffer");
152 smd_read(hsmd->data_channel, NULL, len);
153 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530154 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530155
156 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
157 if (rc < len) {
158 BT_ERR("Error in reading from the channel");
159 goto out_data;
160 }
161
162 skb->dev = (void *)hsmd->hdev;
163 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
164 skb_orphan(skb);
165
166 rc = hci_recv_frame(skb);
167 if (rc < 0) {
168 BT_ERR("Error in passing the packet to HCI Layer");
169 /*
170 * skb is getting freed in hci_recv_frame, making it
171 * to null to avoid multiple access
172 */
173 skb = NULL;
174 goto out_data;
175 }
176
177 /*
178 * Start the timer to monitor whether the Rx queue is
179 * empty for releasing the Rx wake lock
180 */
181 BT_DBG("Rx Timer is starting");
182 mod_timer(&hsmd->rx_q_timer,
183 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
184
Bhasker Netid08d9012011-09-05 19:37:54 +0530185out_data:
186 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530187 if (rc)
188 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189}
190
Bhasker Netiaae61462012-01-12 19:14:25 +0530191static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192{
Bhasker Netid08d9012011-09-05 19:37:54 +0530193 int len = 0;
194 int rc = 0;
195 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530197 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198
199 len = smd_read_avail(hsmd->event_channel);
200 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530201 BT_ERR("Frame larger than the allowed size, flushing frame");
202 rc = smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530203 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 }
205
206 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700207 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530208 if (!skb) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530209 BT_ERR("Error in allocating socket buffer");
210 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530211 goto out_event;
212 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530213
214 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530215 if (rc < len) {
216 BT_ERR("Error in reading from the event channel");
217 goto out_event;
218 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 skb->dev = (void *)hsmd->hdev;
221 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
222
223 skb_orphan(skb);
224
225 rc = hci_recv_frame(skb);
226 if (rc < 0) {
227 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530228 /*
229 * skb is getting freed in hci_recv_frame, making it
230 * to null to avoid multiple access
231 */
232 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530233 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 }
235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530237 /*
238 * Start the timer to monitor whether the Rx queue is
239 * empty for releasing the Rx wake lock
240 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800241 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530242 mod_timer(&hsmd->rx_q_timer,
243 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
244 }
245out_event:
246 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530247 if (rc)
248 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249}
250
251static int hci_smd_send_frame(struct sk_buff *skb)
252{
253 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530254 int avail;
255 int ret = 0;
256 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
258 switch (bt_cb(skb)->pkt_type) {
259 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530260 avail = smd_write_avail(hs.event_channel);
261 if (!avail) {
262 BT_ERR("No space available for smd frame");
263 ret = -ENOSPC;
264 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 len = smd_write(hs.event_channel, skb->data, skb->len);
266 if (len < skb->len) {
267 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530268 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 }
270 break;
271 case HCI_ACLDATA_PKT:
272 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700273 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530274 if (!avail) {
275 BT_ERR("No space available for smd frame");
276 ret = -ENOSPC;
277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 len = smd_write(hs.data_channel, skb->data, skb->len);
279 if (len < skb->len) {
280 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530281 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 }
283 break;
284 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800285 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530286 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 break;
288 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530289
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530290 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530291 wake_unlock(&hs.wake_lock_tx);
292 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293}
294
Bhasker Netiaae61462012-01-12 19:14:25 +0530295static void hci_smd_rx(unsigned long arg)
296{
297 struct hci_smd_data *hsmd = &hs;
298
299 while ((smd_read_avail(hsmd->event_channel) > 0) ||
300 (smd_read_avail(hsmd->data_channel) > 0)) {
301 hci_smd_recv_event();
302 hci_smd_recv_data();
303 }
304}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305
306static void hci_smd_notify_event(void *data, unsigned int event)
307{
308 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800309 struct hci_smd_data *hsmd = &hs;
310 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311
312 if (!hdev) {
313 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
314 return;
315 }
316
317 switch (event) {
318 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800319 len = smd_read_avail(hsmd->event_channel);
320 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530321 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800322 else if (len < 0)
323 BT_ERR("Failed to read event from smd %d", len);
324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325 break;
326 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800327 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 hci_smd_open(hdev);
329 break;
330 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800331 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 hci_smd_close(hdev);
333 break;
334 default:
335 break;
336 }
337}
338
339static void hci_smd_notify_data(void *data, unsigned int event)
340{
341 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800342 struct hci_smd_data *hsmd = &hs;
343 int len = 0;
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530346 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 return;
348 }
349
350 switch (event) {
351 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800352 len = smd_read_avail(hsmd->data_channel);
353 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530354 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800355 else if (len < 0)
356 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 break;
358 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800359 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 hci_smd_open(hdev);
361 break;
362 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800363 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 hci_smd_close(hdev);
365 break;
366 default:
367 break;
368 }
369
370}
371
372static int hci_smd_register_dev(struct hci_smd_data *hsmd)
373{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700374 static struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 int rc;
376
377 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800378 hdev = hci_alloc_dev();
379 if (!hdev) {
380 BT_ERR("Can't allocate HCI device");
381 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700382 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383
Bhasker Neti60576c62011-12-07 18:45:51 -0800384 hsmd->hdev = hdev;
385 hdev->bus = HCI_SMD;
386 hdev->driver_data = NULL;
387 hdev->open = hci_smd_open;
388 hdev->close = hci_smd_close;
389 hdev->send = hci_smd_send_frame;
390 hdev->destruct = hci_smd_destruct;
391 hdev->owner = THIS_MODULE;
392
Bhasker Netiaae61462012-01-12 19:14:25 +0530393
394 tasklet_init(&hsmd->rx_task,
395 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530396 /*
397 * Setup the timer to monitor whether the Rx queue is empty,
398 * to control the wake lock release
399 */
400 setup_timer(&hsmd->rx_q_timer, schedule_timer,
401 (unsigned long) hsmd->hdev);
402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 /* Open the SMD Channel and device and register the callback function */
404 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
405 &hsmd->event_channel, hdev, hci_smd_notify_event);
406 if (rc < 0) {
407 BT_ERR("Cannot open the command channel");
408 hci_free_dev(hdev);
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530409 hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 return -ENODEV;
411 }
412
413 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
414 &hsmd->data_channel, hdev, hci_smd_notify_data);
415 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800416 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 hci_free_dev(hdev);
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530418 hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 return -ENODEV;
420 }
421
422 /* Disable the read interrupts on the channel */
423 smd_disable_read_intr(hsmd->event_channel);
424 smd_disable_read_intr(hsmd->data_channel);
Bhasker Neti60576c62011-12-07 18:45:51 -0800425 if (hci_register_dev(hdev) < 0) {
426 BT_ERR("Can't register HCI device");
427 hci_free_dev(hdev);
428 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 return 0;
431}
432
Bhasker Neti60576c62011-12-07 18:45:51 -0800433static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434{
Bhasker Netiaae61462012-01-12 19:14:25 +0530435 tasklet_kill(&hs.rx_task);
436
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530437 if (hsmd->hdev) {
438 if (hci_unregister_dev(hsmd->hdev) < 0)
439 BT_ERR("Can't unregister HCI device %s",
440 hsmd->hdev->name);
441
442 hci_free_dev(hsmd->hdev);
443 hsmd->hdev = NULL;
444 }
445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530448
Ankur Nandwani327e0502011-11-11 15:47:25 -0800449 if (wake_lock_active(&hs.wake_lock_rx))
450 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800451 if (wake_lock_active(&hs.wake_lock_tx))
452 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800453
Bhasker Netid08d9012011-09-05 19:37:54 +0530454 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530455 if (hs.rx_q_timer.function) {
456 del_timer_sync(&hs.rx_q_timer);
457 hs.rx_q_timer.function = NULL;
458 hs.rx_q_timer.data = 0;
459 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460}
461
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700462static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700464 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700466 mutex_lock(&hci_smd_enable);
467
468 ret = param_set_int(val, kp);
469
470 if (ret)
471 goto done;
472
473 switch (hcismd_set) {
474
475 case 1:
476 hci_smd_register_dev(&hs);
477 break;
478 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800479 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700480 break;
481 default:
482 ret = -EFAULT;
483 }
484
485done:
486 mutex_unlock(&hci_smd_enable);
487 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488}
Bhasker Neti60576c62011-12-07 18:45:51 -0800489static int __init hci_smd_init(void)
490{
491 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
492 "msm_smd_Rx");
493 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
494 "msm_smd_Tx");
495 return 0;
496}
497module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700498
Bhasker Neti60576c62011-12-07 18:45:51 -0800499static void __exit hci_smd_exit(void)
500{
501 wake_lock_destroy(&hs.wake_lock_rx);
502 wake_lock_destroy(&hs.wake_lock_tx);
503}
504module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505
506MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
507MODULE_DESCRIPTION("Bluetooth SMD driver");
508MODULE_LICENSE("GPL v2");