blob: b6de881cb6eb368d40306498690e0c8fb1d4e69e [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>
Steve Mucklef132c6c2012-06-06 18:30:57 -070030#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031#include <net/bluetooth/bluetooth.h>
32#include <net/bluetooth/hci_core.h>
33#include <net/bluetooth/hci.h>
34#include <mach/msm_smd.h>
35
Bhasker Netid08d9012011-09-05 19:37:54 +053036#define EVENT_CHANNEL "APPS_RIVA_BT_CMD"
37#define DATA_CHANNEL "APPS_RIVA_BT_ACL"
Mallikarjuna GB215561d2012-01-23 13:20:38 +053038/* release wakelock in 500ms, not immediately, because higher layers
39 * don't always take wakelocks when they should
40 * This is derived from the implementation for UART transport
41 */
42
43#define RX_Q_MONITOR (500) /* 500 milli second */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070045
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070046static int hcismd_set;
47static DEFINE_MUTEX(hci_smd_enable);
48
49static int hcismd_set_enable(const char *val, struct kernel_param *kp);
50module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
51
Sunny Kapdid71fbed2012-03-15 18:20:55 -070052static void hci_dev_smd_open(struct work_struct *worker);
Sunny Kapdi02eab142012-02-01 13:52:27 -080053static void hci_dev_restart(struct work_struct *worker);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055struct hci_smd_data {
56 struct hci_dev *hdev;
57
58 struct smd_channel *event_channel;
59 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053060 struct wake_lock wake_lock_tx;
61 struct wake_lock wake_lock_rx;
62 struct timer_list rx_q_timer;
Bhasker Netiaae61462012-01-12 19:14:25 +053063 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070065static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066
Bhasker Netid08d9012011-09-05 19:37:54 +053067/* Rx queue monitor timer function */
68static int is_rx_q_empty(unsigned long arg)
69{
70 struct hci_dev *hdev = (struct hci_dev *) arg;
71 struct sk_buff_head *list_ = &hdev->rx_q;
72 struct sk_buff *list = ((struct sk_buff *)list_)->next;
73 BT_DBG("%s Rx timer triggered", hdev->name);
74
75 if (list == (struct sk_buff *)list_) {
76 BT_DBG("%s RX queue empty", hdev->name);
77 return 1;
78 } else{
79 BT_DBG("%s RX queue not empty", hdev->name);
80 return 0;
81 }
82}
83
84static void release_lock(void)
85{
86 struct hci_smd_data *hsmd = &hs;
87 BT_DBG("Releasing Rx Lock");
88 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
89 wake_lock_active(&hs.wake_lock_rx))
90 wake_unlock(&hs.wake_lock_rx);
91}
92
93/* Rx timer callback function */
94static void schedule_timer(unsigned long arg)
95{
96 struct hci_dev *hdev = (struct hci_dev *) arg;
97 struct hci_smd_data *hsmd = &hs;
98 BT_DBG("%s Schedule Rx timer", hdev->name);
99
100 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
101 BT_DBG("%s RX queue empty", hdev->name);
102 /*
103 * Since the queue is empty, its ideal
104 * to release the wake lock on Rx
105 */
106 wake_unlock(&hs.wake_lock_rx);
107 } else{
108 BT_DBG("%s RX queue not empty", hdev->name);
109 /*
110 * Restart the timer to monitor whether the Rx queue is
111 * empty for releasing the Rx wake lock
112 */
113 mod_timer(&hsmd->rx_q_timer,
114 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
115 }
116}
117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700118static int hci_smd_open(struct hci_dev *hdev)
119{
120 set_bit(HCI_RUNNING, &hdev->flags);
121 return 0;
122}
123
124
125static int hci_smd_close(struct hci_dev *hdev)
126{
127 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
128 return 0;
129 else
130 return -EPERM;
131}
132
133
134static void hci_smd_destruct(struct hci_dev *hdev)
135{
Bhasker Neti60576c62011-12-07 18:45:51 -0800136 if (NULL != hdev->driver_data)
137 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138}
139
Bhasker Netiaae61462012-01-12 19:14:25 +0530140static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141{
Bhasker Netid08d9012011-09-05 19:37:54 +0530142 int len = 0;
143 int rc = 0;
144 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530146 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147
148 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800149 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530150 BT_ERR("Frame larger than the allowed size, flushing frame");
151 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530152 goto out_data;
153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154
Bhasker Netiaae61462012-01-12 19:14:25 +0530155 if (len <= 0)
156 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157
Bhasker Netiaae61462012-01-12 19:14:25 +0530158 skb = bt_skb_alloc(len, GFP_ATOMIC);
159 if (!skb) {
160 BT_ERR("Error in allocating socket buffer");
161 smd_read(hsmd->data_channel, NULL, len);
162 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530163 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530164
165 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
166 if (rc < len) {
167 BT_ERR("Error in reading from the channel");
168 goto out_data;
169 }
170
171 skb->dev = (void *)hsmd->hdev;
172 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
173 skb_orphan(skb);
174
175 rc = hci_recv_frame(skb);
176 if (rc < 0) {
177 BT_ERR("Error in passing the packet to HCI Layer");
178 /*
179 * skb is getting freed in hci_recv_frame, making it
180 * to null to avoid multiple access
181 */
182 skb = NULL;
183 goto out_data;
184 }
185
186 /*
187 * Start the timer to monitor whether the Rx queue is
188 * empty for releasing the Rx wake lock
189 */
190 BT_DBG("Rx Timer is starting");
191 mod_timer(&hsmd->rx_q_timer,
192 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
193
Bhasker Netid08d9012011-09-05 19:37:54 +0530194out_data:
195 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530196 if (rc)
197 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198}
199
Bhasker Netiaae61462012-01-12 19:14:25 +0530200static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201{
Bhasker Netid08d9012011-09-05 19:37:54 +0530202 int len = 0;
203 int rc = 0;
204 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530206 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207
208 len = smd_read_avail(hsmd->event_channel);
209 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530210 BT_ERR("Frame larger than the allowed size, flushing frame");
211 rc = smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530212 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 }
214
215 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700216 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530217 if (!skb) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530218 BT_ERR("Error in allocating socket buffer");
219 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530220 goto out_event;
221 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530222
223 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530224 if (rc < len) {
225 BT_ERR("Error in reading from the event channel");
226 goto out_event;
227 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 skb->dev = (void *)hsmd->hdev;
230 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
231
232 skb_orphan(skb);
233
234 rc = hci_recv_frame(skb);
235 if (rc < 0) {
236 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530237 /*
238 * skb is getting freed in hci_recv_frame, making it
239 * to null to avoid multiple access
240 */
241 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530242 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 }
244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530246 /*
247 * Start the timer to monitor whether the Rx queue is
248 * empty for releasing the Rx wake lock
249 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800250 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530251 mod_timer(&hsmd->rx_q_timer,
252 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
253 }
254out_event:
255 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530256 if (rc)
257 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258}
259
260static int hci_smd_send_frame(struct sk_buff *skb)
261{
262 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530263 int avail;
264 int ret = 0;
265 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266
267 switch (bt_cb(skb)->pkt_type) {
268 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530269 avail = smd_write_avail(hs.event_channel);
270 if (!avail) {
271 BT_ERR("No space available for smd frame");
272 ret = -ENOSPC;
273 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 len = smd_write(hs.event_channel, skb->data, skb->len);
275 if (len < skb->len) {
276 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530277 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 }
279 break;
280 case HCI_ACLDATA_PKT:
281 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700282 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530283 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.data_channel, skb->data, skb->len);
288 if (len < skb->len) {
289 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530290 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 }
292 break;
293 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800294 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530295 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 break;
297 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530298
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530299 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530300 wake_unlock(&hs.wake_lock_tx);
301 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302}
303
Bhasker Netiaae61462012-01-12 19:14:25 +0530304static void hci_smd_rx(unsigned long arg)
305{
306 struct hci_smd_data *hsmd = &hs;
307
308 while ((smd_read_avail(hsmd->event_channel) > 0) ||
309 (smd_read_avail(hsmd->data_channel) > 0)) {
310 hci_smd_recv_event();
311 hci_smd_recv_data();
312 }
313}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314
315static void hci_smd_notify_event(void *data, unsigned int event)
316{
317 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800318 struct hci_smd_data *hsmd = &hs;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800319 struct work_struct *reset_worker;
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700320 struct work_struct *open_worker;
321
Bhasker Neti60734c02011-11-23 15:17:54 -0800322 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)
Bhasker Netiaae61462012-01-12 19:14:25 +0530333 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800334 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);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700341 open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
342 if (!open_worker) {
343 BT_ERR("Out of memory");
344 break;
345 }
346 INIT_WORK(open_worker, hci_dev_smd_open);
347 schedule_work(open_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 break;
349 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800350 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 hci_smd_close(hdev);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800352 reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
353 if (!reset_worker) {
354 BT_ERR("Out of memory");
355 break;
356 }
357 INIT_WORK(reset_worker, hci_dev_restart);
358 schedule_work(reset_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 break;
360 default:
361 break;
362 }
363}
364
365static void hci_smd_notify_data(void *data, unsigned int event)
366{
367 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800368 struct hci_smd_data *hsmd = &hs;
369 int len = 0;
370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530372 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 return;
374 }
375
376 switch (event) {
377 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800378 len = smd_read_avail(hsmd->data_channel);
379 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530380 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800381 else if (len < 0)
382 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 break;
384 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800385 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 hci_smd_open(hdev);
387 break;
388 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800389 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 hci_smd_close(hdev);
391 break;
392 default:
393 break;
394 }
395
396}
397
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700398static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399{
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700400 struct hci_dev *hdev;
401
402 hdev = hsmd->hdev;
403
404 if (hci_register_dev(hdev) < 0) {
405 BT_ERR("Can't register HCI device");
406 hci_free_dev(hdev);
407 hsmd->hdev = NULL;
408 return -ENODEV;
409 }
410 return 0;
411}
412
413static int hci_smd_register_smd(struct hci_smd_data *hsmd)
414{
415 struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 int rc;
417
418 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800419 hdev = hci_alloc_dev();
420 if (!hdev) {
421 BT_ERR("Can't allocate HCI device");
422 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700423 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424
Bhasker Neti60576c62011-12-07 18:45:51 -0800425 hsmd->hdev = hdev;
426 hdev->bus = HCI_SMD;
427 hdev->driver_data = NULL;
428 hdev->open = hci_smd_open;
429 hdev->close = hci_smd_close;
430 hdev->send = hci_smd_send_frame;
431 hdev->destruct = hci_smd_destruct;
432 hdev->owner = THIS_MODULE;
433
Bhasker Netiaae61462012-01-12 19:14:25 +0530434
435 tasklet_init(&hsmd->rx_task,
436 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530437 /*
438 * Setup the timer to monitor whether the Rx queue is empty,
439 * to control the wake lock release
440 */
441 setup_timer(&hsmd->rx_q_timer, schedule_timer,
442 (unsigned long) hsmd->hdev);
443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 /* Open the SMD Channel and device and register the callback function */
445 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
446 &hsmd->event_channel, hdev, hci_smd_notify_event);
447 if (rc < 0) {
448 BT_ERR("Cannot open the command channel");
449 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700450 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 return -ENODEV;
452 }
453
454 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
455 &hsmd->data_channel, hdev, hci_smd_notify_data);
456 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800457 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700459 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 return -ENODEV;
461 }
462
463 /* Disable the read interrupts on the channel */
464 smd_disable_read_intr(hsmd->event_channel);
465 smd_disable_read_intr(hsmd->data_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 return 0;
467}
468
Bhasker Neti60576c62011-12-07 18:45:51 -0800469static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470{
Bhasker Netiaae61462012-01-12 19:14:25 +0530471 tasklet_kill(&hs.rx_task);
472
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530473 if (hsmd->hdev) {
474 if (hci_unregister_dev(hsmd->hdev) < 0)
475 BT_ERR("Can't unregister HCI device %s",
476 hsmd->hdev->name);
477
478 hci_free_dev(hsmd->hdev);
479 hsmd->hdev = NULL;
480 }
481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530484
Ankur Nandwani327e0502011-11-11 15:47:25 -0800485 if (wake_lock_active(&hs.wake_lock_rx))
486 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800487 if (wake_lock_active(&hs.wake_lock_tx))
488 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800489
Bhasker Netid08d9012011-09-05 19:37:54 +0530490 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530491 if (hs.rx_q_timer.function) {
492 del_timer_sync(&hs.rx_q_timer);
493 hs.rx_q_timer.function = NULL;
494 hs.rx_q_timer.data = 0;
495 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496}
497
Sunny Kapdi02eab142012-02-01 13:52:27 -0800498static void hci_dev_restart(struct work_struct *worker)
499{
500 mutex_lock(&hci_smd_enable);
501 hci_smd_deregister_dev(&hs);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700502 hci_smd_register_smd(&hs);
503 mutex_unlock(&hci_smd_enable);
504 kfree(worker);
505}
506
507static void hci_dev_smd_open(struct work_struct *worker)
508{
509 mutex_lock(&hci_smd_enable);
510 hci_smd_hci_register_dev(&hs);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800511 mutex_unlock(&hci_smd_enable);
512 kfree(worker);
513}
514
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700515static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700517 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700519 mutex_lock(&hci_smd_enable);
520
521 ret = param_set_int(val, kp);
522
523 if (ret)
524 goto done;
525
526 switch (hcismd_set) {
527
528 case 1:
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700529 hci_smd_register_smd(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700530 break;
531 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800532 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700533 break;
534 default:
535 ret = -EFAULT;
536 }
537
538done:
539 mutex_unlock(&hci_smd_enable);
540 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541}
Bhasker Neti60576c62011-12-07 18:45:51 -0800542static int __init hci_smd_init(void)
543{
544 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
545 "msm_smd_Rx");
546 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
547 "msm_smd_Tx");
548 return 0;
549}
550module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700551
Bhasker Neti60576c62011-12-07 18:45:51 -0800552static void __exit hci_smd_exit(void)
553{
554 wake_lock_destroy(&hs.wake_lock_rx);
555 wake_lock_destroy(&hs.wake_lock_tx);
556}
557module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558
559MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
560MODULE_DESCRIPTION("Bluetooth SMD driver");
561MODULE_LICENSE("GPL v2");