blob: 8f51e2dba6b1f7db8efbd7896c75adc2a8983c34 [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 Kapdid71fbed2012-03-15 18:20:55 -070051static void hci_dev_smd_open(struct work_struct *worker);
Sunny Kapdi02eab142012-02-01 13:52:27 -080052static void hci_dev_restart(struct work_struct *worker);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054struct hci_smd_data {
55 struct hci_dev *hdev;
56
57 struct smd_channel *event_channel;
58 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053059 struct wake_lock wake_lock_tx;
60 struct wake_lock wake_lock_rx;
61 struct timer_list rx_q_timer;
Bhasker Netiaae61462012-01-12 19:14:25 +053062 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070064static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065
Bhasker Netid08d9012011-09-05 19:37:54 +053066/* Rx queue monitor timer function */
67static int is_rx_q_empty(unsigned long arg)
68{
69 struct hci_dev *hdev = (struct hci_dev *) arg;
70 struct sk_buff_head *list_ = &hdev->rx_q;
71 struct sk_buff *list = ((struct sk_buff *)list_)->next;
72 BT_DBG("%s Rx timer triggered", hdev->name);
73
74 if (list == (struct sk_buff *)list_) {
75 BT_DBG("%s RX queue empty", hdev->name);
76 return 1;
77 } else{
78 BT_DBG("%s RX queue not empty", hdev->name);
79 return 0;
80 }
81}
82
83static void release_lock(void)
84{
85 struct hci_smd_data *hsmd = &hs;
86 BT_DBG("Releasing Rx Lock");
87 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
88 wake_lock_active(&hs.wake_lock_rx))
89 wake_unlock(&hs.wake_lock_rx);
90}
91
92/* Rx timer callback function */
93static void schedule_timer(unsigned long arg)
94{
95 struct hci_dev *hdev = (struct hci_dev *) arg;
96 struct hci_smd_data *hsmd = &hs;
97 BT_DBG("%s Schedule Rx timer", hdev->name);
98
99 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
100 BT_DBG("%s RX queue empty", hdev->name);
101 /*
102 * Since the queue is empty, its ideal
103 * to release the wake lock on Rx
104 */
105 wake_unlock(&hs.wake_lock_rx);
106 } else{
107 BT_DBG("%s RX queue not empty", hdev->name);
108 /*
109 * Restart the timer to monitor whether the Rx queue is
110 * empty for releasing the Rx wake lock
111 */
112 mod_timer(&hsmd->rx_q_timer,
113 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
114 }
115}
116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117static int hci_smd_open(struct hci_dev *hdev)
118{
119 set_bit(HCI_RUNNING, &hdev->flags);
120 return 0;
121}
122
123
124static int hci_smd_close(struct hci_dev *hdev)
125{
126 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
127 return 0;
128 else
129 return -EPERM;
130}
131
132
133static void hci_smd_destruct(struct hci_dev *hdev)
134{
Bhasker Neti60576c62011-12-07 18:45:51 -0800135 if (NULL != hdev->driver_data)
136 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137}
138
Bhasker Netiaae61462012-01-12 19:14:25 +0530139static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140{
Bhasker Netid08d9012011-09-05 19:37:54 +0530141 int len = 0;
142 int rc = 0;
143 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530145 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146
147 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800148 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530149 BT_ERR("Frame larger than the allowed size, flushing frame");
150 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530151 goto out_data;
152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153
Bhasker Netiaae61462012-01-12 19:14:25 +0530154 if (len <= 0)
155 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156
Bhasker Netiaae61462012-01-12 19:14:25 +0530157 skb = bt_skb_alloc(len, GFP_ATOMIC);
158 if (!skb) {
159 BT_ERR("Error in allocating socket buffer");
160 smd_read(hsmd->data_channel, NULL, len);
161 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530162 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530163
164 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
165 if (rc < len) {
166 BT_ERR("Error in reading from the channel");
167 goto out_data;
168 }
169
170 skb->dev = (void *)hsmd->hdev;
171 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
172 skb_orphan(skb);
173
174 rc = hci_recv_frame(skb);
175 if (rc < 0) {
176 BT_ERR("Error in passing the packet to HCI Layer");
177 /*
178 * skb is getting freed in hci_recv_frame, making it
179 * to null to avoid multiple access
180 */
181 skb = NULL;
182 goto out_data;
183 }
184
185 /*
186 * Start the timer to monitor whether the Rx queue is
187 * empty for releasing the Rx wake lock
188 */
189 BT_DBG("Rx Timer is starting");
190 mod_timer(&hsmd->rx_q_timer,
191 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
192
Bhasker Netid08d9012011-09-05 19:37:54 +0530193out_data:
194 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530195 if (rc)
196 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197}
198
Bhasker Netiaae61462012-01-12 19:14:25 +0530199static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200{
Bhasker Netid08d9012011-09-05 19:37:54 +0530201 int len = 0;
202 int rc = 0;
203 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530205 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206
207 len = smd_read_avail(hsmd->event_channel);
208 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530209 BT_ERR("Frame larger than the allowed size, flushing frame");
210 rc = smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530211 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 }
213
214 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700215 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530216 if (!skb) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530217 BT_ERR("Error in allocating socket buffer");
218 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530219 goto out_event;
220 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530221
222 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530223 if (rc < len) {
224 BT_ERR("Error in reading from the event channel");
225 goto out_event;
226 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 skb->dev = (void *)hsmd->hdev;
229 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
230
231 skb_orphan(skb);
232
233 rc = hci_recv_frame(skb);
234 if (rc < 0) {
235 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530236 /*
237 * skb is getting freed in hci_recv_frame, making it
238 * to null to avoid multiple access
239 */
240 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530241 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242 }
243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530245 /*
246 * Start the timer to monitor whether the Rx queue is
247 * empty for releasing the Rx wake lock
248 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800249 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530250 mod_timer(&hsmd->rx_q_timer,
251 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
252 }
253out_event:
254 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530255 if (rc)
256 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257}
258
259static int hci_smd_send_frame(struct sk_buff *skb)
260{
261 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530262 int avail;
263 int ret = 0;
264 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265
266 switch (bt_cb(skb)->pkt_type) {
267 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530268 avail = smd_write_avail(hs.event_channel);
269 if (!avail) {
270 BT_ERR("No space available for smd frame");
271 ret = -ENOSPC;
272 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 len = smd_write(hs.event_channel, skb->data, skb->len);
274 if (len < skb->len) {
275 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530276 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 }
278 break;
279 case HCI_ACLDATA_PKT:
280 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700281 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530282 if (!avail) {
283 BT_ERR("No space available for smd frame");
284 ret = -ENOSPC;
285 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 len = smd_write(hs.data_channel, skb->data, skb->len);
287 if (len < skb->len) {
288 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530289 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 }
291 break;
292 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800293 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530294 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 break;
296 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530297
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530298 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530299 wake_unlock(&hs.wake_lock_tx);
300 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301}
302
Bhasker Netiaae61462012-01-12 19:14:25 +0530303static void hci_smd_rx(unsigned long arg)
304{
305 struct hci_smd_data *hsmd = &hs;
306
307 while ((smd_read_avail(hsmd->event_channel) > 0) ||
308 (smd_read_avail(hsmd->data_channel) > 0)) {
309 hci_smd_recv_event();
310 hci_smd_recv_data();
311 }
312}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313
314static void hci_smd_notify_event(void *data, unsigned int event)
315{
316 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800317 struct hci_smd_data *hsmd = &hs;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800318 struct work_struct *reset_worker;
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700319 struct work_struct *open_worker;
320
Bhasker Neti60734c02011-11-23 15:17:54 -0800321 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322
323 if (!hdev) {
324 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
325 return;
326 }
327
328 switch (event) {
329 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800330 len = smd_read_avail(hsmd->event_channel);
331 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530332 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800333 else if (len < 0)
334 BT_ERR("Failed to read event from smd %d", len);
335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 break;
337 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800338 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339 hci_smd_open(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700340 open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
341 if (!open_worker) {
342 BT_ERR("Out of memory");
343 break;
344 }
345 INIT_WORK(open_worker, hci_dev_smd_open);
346 schedule_work(open_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 break;
348 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800349 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 hci_smd_close(hdev);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800351 reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
352 if (!reset_worker) {
353 BT_ERR("Out of memory");
354 break;
355 }
356 INIT_WORK(reset_worker, hci_dev_restart);
357 schedule_work(reset_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 break;
359 default:
360 break;
361 }
362}
363
364static void hci_smd_notify_data(void *data, unsigned int event)
365{
366 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800367 struct hci_smd_data *hsmd = &hs;
368 int len = 0;
369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530371 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 return;
373 }
374
375 switch (event) {
376 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800377 len = smd_read_avail(hsmd->data_channel);
378 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530379 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800380 else if (len < 0)
381 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 break;
383 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800384 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 hci_smd_open(hdev);
386 break;
387 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800388 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 hci_smd_close(hdev);
390 break;
391 default:
392 break;
393 }
394
395}
396
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700397static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398{
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700399 struct hci_dev *hdev;
400
401 hdev = hsmd->hdev;
402
403 if (hci_register_dev(hdev) < 0) {
404 BT_ERR("Can't register HCI device");
405 hci_free_dev(hdev);
406 hsmd->hdev = NULL;
407 return -ENODEV;
408 }
409 return 0;
410}
411
412static int hci_smd_register_smd(struct hci_smd_data *hsmd)
413{
414 struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 int rc;
416
417 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800418 hdev = hci_alloc_dev();
419 if (!hdev) {
420 BT_ERR("Can't allocate HCI device");
421 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700422 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423
Bhasker Neti60576c62011-12-07 18:45:51 -0800424 hsmd->hdev = hdev;
425 hdev->bus = HCI_SMD;
426 hdev->driver_data = NULL;
427 hdev->open = hci_smd_open;
428 hdev->close = hci_smd_close;
429 hdev->send = hci_smd_send_frame;
430 hdev->destruct = hci_smd_destruct;
431 hdev->owner = THIS_MODULE;
432
Bhasker Netiaae61462012-01-12 19:14:25 +0530433
434 tasklet_init(&hsmd->rx_task,
435 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530436 /*
437 * Setup the timer to monitor whether the Rx queue is empty,
438 * to control the wake lock release
439 */
440 setup_timer(&hsmd->rx_q_timer, schedule_timer,
441 (unsigned long) hsmd->hdev);
442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 /* Open the SMD Channel and device and register the callback function */
444 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
445 &hsmd->event_channel, hdev, hci_smd_notify_event);
446 if (rc < 0) {
447 BT_ERR("Cannot open the command channel");
448 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700449 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450 return -ENODEV;
451 }
452
453 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
454 &hsmd->data_channel, hdev, hci_smd_notify_data);
455 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800456 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700458 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 return -ENODEV;
460 }
461
462 /* Disable the read interrupts on the channel */
463 smd_disable_read_intr(hsmd->event_channel);
464 smd_disable_read_intr(hsmd->data_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465 return 0;
466}
467
Bhasker Neti60576c62011-12-07 18:45:51 -0800468static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469{
Bhasker Netiaae61462012-01-12 19:14:25 +0530470 tasklet_kill(&hs.rx_task);
471
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530472 if (hsmd->hdev) {
473 if (hci_unregister_dev(hsmd->hdev) < 0)
474 BT_ERR("Can't unregister HCI device %s",
475 hsmd->hdev->name);
476
477 hci_free_dev(hsmd->hdev);
478 hsmd->hdev = NULL;
479 }
480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530483
Ankur Nandwani327e0502011-11-11 15:47:25 -0800484 if (wake_lock_active(&hs.wake_lock_rx))
485 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800486 if (wake_lock_active(&hs.wake_lock_tx))
487 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800488
Bhasker Netid08d9012011-09-05 19:37:54 +0530489 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530490 if (hs.rx_q_timer.function) {
491 del_timer_sync(&hs.rx_q_timer);
492 hs.rx_q_timer.function = NULL;
493 hs.rx_q_timer.data = 0;
494 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495}
496
Sunny Kapdi02eab142012-02-01 13:52:27 -0800497static void hci_dev_restart(struct work_struct *worker)
498{
499 mutex_lock(&hci_smd_enable);
500 hci_smd_deregister_dev(&hs);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700501 hci_smd_register_smd(&hs);
502 mutex_unlock(&hci_smd_enable);
503 kfree(worker);
504}
505
506static void hci_dev_smd_open(struct work_struct *worker)
507{
508 mutex_lock(&hci_smd_enable);
509 hci_smd_hci_register_dev(&hs);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800510 mutex_unlock(&hci_smd_enable);
511 kfree(worker);
512}
513
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700514static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700516 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700518 mutex_lock(&hci_smd_enable);
519
520 ret = param_set_int(val, kp);
521
522 if (ret)
523 goto done;
524
525 switch (hcismd_set) {
526
527 case 1:
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700528 hci_smd_register_smd(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700529 break;
530 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800531 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700532 break;
533 default:
534 ret = -EFAULT;
535 }
536
537done:
538 mutex_unlock(&hci_smd_enable);
539 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540}
Bhasker Neti60576c62011-12-07 18:45:51 -0800541static int __init hci_smd_init(void)
542{
543 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
544 "msm_smd_Rx");
545 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
546 "msm_smd_Tx");
547 return 0;
548}
549module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700550
Bhasker Neti60576c62011-12-07 18:45:51 -0800551static void __exit hci_smd_exit(void)
552{
553 wake_lock_destroy(&hs.wake_lock_rx);
554 wake_lock_destroy(&hs.wake_lock_tx);
555}
556module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557
558MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
559MODULE_DESCRIPTION("Bluetooth SMD driver");
560MODULE_LICENSE("GPL v2");