blob: 332922e82edb08cace1fa6332b8cd3fd3e1184e2 [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>
Sunny Kapdi02eab142012-02-01 13:52:27 -080028#include <linux/workqueue.h>
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070029#include <linux/uaccess.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/hci.h>
33#include <mach/msm_smd.h>
34
Bhasker Netid08d9012011-09-05 19:37:54 +053035#define EVENT_CHANNEL "APPS_RIVA_BT_CMD"
36#define DATA_CHANNEL "APPS_RIVA_BT_ACL"
Mallikarjuna GB215561d2012-01-23 13:20:38 +053037/* release wakelock in 500ms, not immediately, because higher layers
38 * don't always take wakelocks when they should
39 * This is derived from the implementation for UART transport
40 */
41
42#define RX_Q_MONITOR (500) /* 500 milli second */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070044
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070045static int hcismd_set;
46static DEFINE_MUTEX(hci_smd_enable);
47
48static int hcismd_set_enable(const char *val, struct kernel_param *kp);
49module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
50
Sunny Kapdi02eab142012-02-01 13:52:27 -080051static void hci_dev_restart(struct work_struct *worker);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053struct hci_smd_data {
54 struct hci_dev *hdev;
55
56 struct smd_channel *event_channel;
57 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053058 struct wake_lock wake_lock_tx;
59 struct wake_lock wake_lock_rx;
60 struct timer_list rx_q_timer;
Bhasker Netiaae61462012-01-12 19:14:25 +053061 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070063static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
Bhasker Netid08d9012011-09-05 19:37:54 +053065/* Rx queue monitor timer function */
66static int is_rx_q_empty(unsigned long arg)
67{
68 struct hci_dev *hdev = (struct hci_dev *) arg;
69 struct sk_buff_head *list_ = &hdev->rx_q;
70 struct sk_buff *list = ((struct sk_buff *)list_)->next;
71 BT_DBG("%s Rx timer triggered", hdev->name);
72
73 if (list == (struct sk_buff *)list_) {
74 BT_DBG("%s RX queue empty", hdev->name);
75 return 1;
76 } else{
77 BT_DBG("%s RX queue not empty", hdev->name);
78 return 0;
79 }
80}
81
82static void release_lock(void)
83{
84 struct hci_smd_data *hsmd = &hs;
85 BT_DBG("Releasing Rx Lock");
86 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
87 wake_lock_active(&hs.wake_lock_rx))
88 wake_unlock(&hs.wake_lock_rx);
89}
90
91/* Rx timer callback function */
92static void schedule_timer(unsigned long arg)
93{
94 struct hci_dev *hdev = (struct hci_dev *) arg;
95 struct hci_smd_data *hsmd = &hs;
96 BT_DBG("%s Schedule Rx timer", hdev->name);
97
98 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
99 BT_DBG("%s RX queue empty", hdev->name);
100 /*
101 * Since the queue is empty, its ideal
102 * to release the wake lock on Rx
103 */
104 wake_unlock(&hs.wake_lock_rx);
105 } else{
106 BT_DBG("%s RX queue not empty", hdev->name);
107 /*
108 * Restart the timer to monitor whether the Rx queue is
109 * empty for releasing the Rx wake lock
110 */
111 mod_timer(&hsmd->rx_q_timer,
112 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
113 }
114}
115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116static int hci_smd_open(struct hci_dev *hdev)
117{
118 set_bit(HCI_RUNNING, &hdev->flags);
119 return 0;
120}
121
122
123static int hci_smd_close(struct hci_dev *hdev)
124{
125 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
126 return 0;
127 else
128 return -EPERM;
129}
130
131
132static void hci_smd_destruct(struct hci_dev *hdev)
133{
Bhasker Neti60576c62011-12-07 18:45:51 -0800134 if (NULL != hdev->driver_data)
135 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136}
137
Bhasker Netiaae61462012-01-12 19:14:25 +0530138static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139{
Bhasker Netid08d9012011-09-05 19:37:54 +0530140 int len = 0;
141 int rc = 0;
142 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530144 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145
146 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800147 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530148 BT_ERR("Frame larger than the allowed size, flushing frame");
149 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530150 goto out_data;
151 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152
Bhasker Netiaae61462012-01-12 19:14:25 +0530153 if (len <= 0)
154 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155
Bhasker Netiaae61462012-01-12 19:14:25 +0530156 skb = bt_skb_alloc(len, GFP_ATOMIC);
157 if (!skb) {
158 BT_ERR("Error in allocating socket buffer");
159 smd_read(hsmd->data_channel, NULL, len);
160 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530161 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530162
163 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
164 if (rc < len) {
165 BT_ERR("Error in reading from the channel");
166 goto out_data;
167 }
168
169 skb->dev = (void *)hsmd->hdev;
170 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
171 skb_orphan(skb);
172
173 rc = hci_recv_frame(skb);
174 if (rc < 0) {
175 BT_ERR("Error in passing the packet to HCI Layer");
176 /*
177 * skb is getting freed in hci_recv_frame, making it
178 * to null to avoid multiple access
179 */
180 skb = NULL;
181 goto out_data;
182 }
183
184 /*
185 * Start the timer to monitor whether the Rx queue is
186 * empty for releasing the Rx wake lock
187 */
188 BT_DBG("Rx Timer is starting");
189 mod_timer(&hsmd->rx_q_timer,
190 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
191
Bhasker Netid08d9012011-09-05 19:37:54 +0530192out_data:
193 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530194 if (rc)
195 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196}
197
Bhasker Netiaae61462012-01-12 19:14:25 +0530198static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199{
Bhasker Netid08d9012011-09-05 19:37:54 +0530200 int len = 0;
201 int rc = 0;
202 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530204 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205
206 len = smd_read_avail(hsmd->event_channel);
207 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530208 BT_ERR("Frame larger than the allowed size, flushing frame");
209 rc = smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530210 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 }
212
213 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700214 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530215 if (!skb) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530216 BT_ERR("Error in allocating socket buffer");
217 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530218 goto out_event;
219 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530220
221 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530222 if (rc < len) {
223 BT_ERR("Error in reading from the event channel");
224 goto out_event;
225 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 skb->dev = (void *)hsmd->hdev;
228 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
229
230 skb_orphan(skb);
231
232 rc = hci_recv_frame(skb);
233 if (rc < 0) {
234 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530235 /*
236 * skb is getting freed in hci_recv_frame, making it
237 * to null to avoid multiple access
238 */
239 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530240 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 }
242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530244 /*
245 * Start the timer to monitor whether the Rx queue is
246 * empty for releasing the Rx wake lock
247 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800248 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530249 mod_timer(&hsmd->rx_q_timer,
250 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
251 }
252out_event:
253 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530254 if (rc)
255 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256}
257
258static int hci_smd_send_frame(struct sk_buff *skb)
259{
260 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530261 int avail;
262 int ret = 0;
263 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264
265 switch (bt_cb(skb)->pkt_type) {
266 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530267 avail = smd_write_avail(hs.event_channel);
268 if (!avail) {
269 BT_ERR("No space available for smd frame");
270 ret = -ENOSPC;
271 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 len = smd_write(hs.event_channel, skb->data, skb->len);
273 if (len < skb->len) {
274 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530275 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 }
277 break;
278 case HCI_ACLDATA_PKT:
279 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700280 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530281 if (!avail) {
282 BT_ERR("No space available for smd frame");
283 ret = -ENOSPC;
284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 len = smd_write(hs.data_channel, skb->data, skb->len);
286 if (len < skb->len) {
287 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530288 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 }
290 break;
291 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800292 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530293 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 break;
295 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530296
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530297 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530298 wake_unlock(&hs.wake_lock_tx);
299 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300}
301
Bhasker Netiaae61462012-01-12 19:14:25 +0530302static void hci_smd_rx(unsigned long arg)
303{
304 struct hci_smd_data *hsmd = &hs;
305
306 while ((smd_read_avail(hsmd->event_channel) > 0) ||
307 (smd_read_avail(hsmd->data_channel) > 0)) {
308 hci_smd_recv_event();
309 hci_smd_recv_data();
310 }
311}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312
313static void hci_smd_notify_event(void *data, unsigned int event)
314{
315 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800316 struct hci_smd_data *hsmd = &hs;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800317 struct work_struct *reset_worker;
Bhasker Neti60734c02011-11-23 15:17:54 -0800318 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319
320 if (!hdev) {
321 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
322 return;
323 }
324
325 switch (event) {
326 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800327 len = smd_read_avail(hsmd->event_channel);
328 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530329 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800330 else if (len < 0)
331 BT_ERR("Failed to read event from smd %d", len);
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 break;
334 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800335 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 hci_smd_open(hdev);
337 break;
338 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800339 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 hci_smd_close(hdev);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800341 reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
342 if (!reset_worker) {
343 BT_ERR("Out of memory");
344 break;
345 }
346 INIT_WORK(reset_worker, hci_dev_restart);
347 schedule_work(reset_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 break;
349 default:
350 break;
351 }
352}
353
354static void hci_smd_notify_data(void *data, unsigned int event)
355{
356 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800357 struct hci_smd_data *hsmd = &hs;
358 int len = 0;
359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530361 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 return;
363 }
364
365 switch (event) {
366 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800367 len = smd_read_avail(hsmd->data_channel);
368 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530369 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800370 else if (len < 0)
371 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 break;
373 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800374 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 hci_smd_open(hdev);
376 break;
377 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800378 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379 hci_smd_close(hdev);
380 break;
381 default:
382 break;
383 }
384
385}
386
387static int hci_smd_register_dev(struct hci_smd_data *hsmd)
388{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700389 static struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 int rc;
391
392 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800393 hdev = hci_alloc_dev();
394 if (!hdev) {
395 BT_ERR("Can't allocate HCI device");
396 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700397 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398
Bhasker Neti60576c62011-12-07 18:45:51 -0800399 hsmd->hdev = hdev;
400 hdev->bus = HCI_SMD;
401 hdev->driver_data = NULL;
402 hdev->open = hci_smd_open;
403 hdev->close = hci_smd_close;
404 hdev->send = hci_smd_send_frame;
405 hdev->destruct = hci_smd_destruct;
406 hdev->owner = THIS_MODULE;
407
Bhasker Netiaae61462012-01-12 19:14:25 +0530408
409 tasklet_init(&hsmd->rx_task,
410 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530411 /*
412 * Setup the timer to monitor whether the Rx queue is empty,
413 * to control the wake lock release
414 */
415 setup_timer(&hsmd->rx_q_timer, schedule_timer,
416 (unsigned long) hsmd->hdev);
417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 /* Open the SMD Channel and device and register the callback function */
419 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
420 &hsmd->event_channel, hdev, hci_smd_notify_event);
421 if (rc < 0) {
422 BT_ERR("Cannot open the command channel");
423 hci_free_dev(hdev);
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530424 hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 return -ENODEV;
426 }
427
428 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
429 &hsmd->data_channel, hdev, hci_smd_notify_data);
430 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800431 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 hci_free_dev(hdev);
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530433 hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 return -ENODEV;
435 }
436
437 /* Disable the read interrupts on the channel */
438 smd_disable_read_intr(hsmd->event_channel);
439 smd_disable_read_intr(hsmd->data_channel);
Bhasker Neti60576c62011-12-07 18:45:51 -0800440 if (hci_register_dev(hdev) < 0) {
441 BT_ERR("Can't register HCI device");
442 hci_free_dev(hdev);
443 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 return 0;
446}
447
Bhasker Neti60576c62011-12-07 18:45:51 -0800448static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449{
Bhasker Netiaae61462012-01-12 19:14:25 +0530450 tasklet_kill(&hs.rx_task);
451
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530452 if (hsmd->hdev) {
453 if (hci_unregister_dev(hsmd->hdev) < 0)
454 BT_ERR("Can't unregister HCI device %s",
455 hsmd->hdev->name);
456
457 hci_free_dev(hsmd->hdev);
458 hsmd->hdev = NULL;
459 }
460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530463
Ankur Nandwani327e0502011-11-11 15:47:25 -0800464 if (wake_lock_active(&hs.wake_lock_rx))
465 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800466 if (wake_lock_active(&hs.wake_lock_tx))
467 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800468
Bhasker Netid08d9012011-09-05 19:37:54 +0530469 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530470 if (hs.rx_q_timer.function) {
471 del_timer_sync(&hs.rx_q_timer);
472 hs.rx_q_timer.function = NULL;
473 hs.rx_q_timer.data = 0;
474 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475}
476
Sunny Kapdi02eab142012-02-01 13:52:27 -0800477static void hci_dev_restart(struct work_struct *worker)
478{
479 mutex_lock(&hci_smd_enable);
480 hci_smd_deregister_dev(&hs);
481 hci_smd_register_dev(&hs);
482 mutex_unlock(&hci_smd_enable);
483 kfree(worker);
484}
485
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700486static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700488 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700490 mutex_lock(&hci_smd_enable);
491
492 ret = param_set_int(val, kp);
493
494 if (ret)
495 goto done;
496
497 switch (hcismd_set) {
498
499 case 1:
500 hci_smd_register_dev(&hs);
501 break;
502 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800503 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700504 break;
505 default:
506 ret = -EFAULT;
507 }
508
509done:
510 mutex_unlock(&hci_smd_enable);
511 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512}
Bhasker Neti60576c62011-12-07 18:45:51 -0800513static int __init hci_smd_init(void)
514{
515 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
516 "msm_smd_Rx");
517 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
518 "msm_smd_Tx");
519 return 0;
520}
521module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700522
Bhasker Neti60576c62011-12-07 18:45:51 -0800523static void __exit hci_smd_exit(void)
524{
525 wake_lock_destroy(&hs.wake_lock_rx);
526 wake_lock_destroy(&hs.wake_lock_tx);
527}
528module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529
530MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
531MODULE_DESCRIPTION("Bluetooth SMD driver");
532MODULE_LICENSE("GPL v2");