blob: 66bd7390758c468fe29c50e36b4b4d6e5804538f [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>
Sunny Kapdi2a39b802012-05-30 12:47:14 -070025#include <linux/semaphore.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/string.h>
27#include <linux/skbuff.h>
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070028#include <linux/wakelock.h>
Sunny Kapdi02eab142012-02-01 13:52:27 -080029#include <linux/workqueue.h>
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070030#include <linux/uaccess.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070031#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/hci.h>
35#include <mach/msm_smd.h>
36
Bhasker Netid08d9012011-09-05 19:37:54 +053037#define EVENT_CHANNEL "APPS_RIVA_BT_CMD"
38#define DATA_CHANNEL "APPS_RIVA_BT_ACL"
Mallikarjuna GB215561d2012-01-23 13:20:38 +053039/* release wakelock in 500ms, not immediately, because higher layers
40 * don't always take wakelocks when they should
41 * This is derived from the implementation for UART transport
42 */
43
44#define RX_Q_MONITOR (500) /* 500 milli second */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070046
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070047static int hcismd_set;
Sunny Kapdi2a39b802012-05-30 12:47:14 -070048static DEFINE_SEMAPHORE(hci_smd_enable);
49
50static int restart_in_progress;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070051
52static int hcismd_set_enable(const char *val, struct kernel_param *kp);
53module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
54
Sunny Kapdid71fbed2012-03-15 18:20:55 -070055static void hci_dev_smd_open(struct work_struct *worker);
Sunny Kapdi02eab142012-02-01 13:52:27 -080056static void hci_dev_restart(struct work_struct *worker);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058struct hci_smd_data {
59 struct hci_dev *hdev;
60
61 struct smd_channel *event_channel;
62 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053063 struct wake_lock wake_lock_tx;
64 struct wake_lock wake_lock_rx;
65 struct timer_list rx_q_timer;
Bhasker Netiaae61462012-01-12 19:14:25 +053066 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070068static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069
Bhasker Netid08d9012011-09-05 19:37:54 +053070/* Rx queue monitor timer function */
71static int is_rx_q_empty(unsigned long arg)
72{
73 struct hci_dev *hdev = (struct hci_dev *) arg;
74 struct sk_buff_head *list_ = &hdev->rx_q;
75 struct sk_buff *list = ((struct sk_buff *)list_)->next;
76 BT_DBG("%s Rx timer triggered", hdev->name);
77
78 if (list == (struct sk_buff *)list_) {
79 BT_DBG("%s RX queue empty", hdev->name);
80 return 1;
81 } else{
82 BT_DBG("%s RX queue not empty", hdev->name);
83 return 0;
84 }
85}
86
87static void release_lock(void)
88{
89 struct hci_smd_data *hsmd = &hs;
90 BT_DBG("Releasing Rx Lock");
91 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
92 wake_lock_active(&hs.wake_lock_rx))
93 wake_unlock(&hs.wake_lock_rx);
94}
95
96/* Rx timer callback function */
97static void schedule_timer(unsigned long arg)
98{
99 struct hci_dev *hdev = (struct hci_dev *) arg;
100 struct hci_smd_data *hsmd = &hs;
101 BT_DBG("%s Schedule Rx timer", hdev->name);
102
103 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
104 BT_DBG("%s RX queue empty", hdev->name);
105 /*
106 * Since the queue is empty, its ideal
107 * to release the wake lock on Rx
108 */
109 wake_unlock(&hs.wake_lock_rx);
110 } else{
111 BT_DBG("%s RX queue not empty", hdev->name);
112 /*
113 * Restart the timer to monitor whether the Rx queue is
114 * empty for releasing the Rx wake lock
115 */
116 mod_timer(&hsmd->rx_q_timer,
117 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
118 }
119}
120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121static int hci_smd_open(struct hci_dev *hdev)
122{
123 set_bit(HCI_RUNNING, &hdev->flags);
124 return 0;
125}
126
127
128static int hci_smd_close(struct hci_dev *hdev)
129{
130 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
131 return 0;
132 else
133 return -EPERM;
134}
135
136
137static void hci_smd_destruct(struct hci_dev *hdev)
138{
Bhasker Neti60576c62011-12-07 18:45:51 -0800139 if (NULL != hdev->driver_data)
140 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141}
142
Bhasker Netiaae61462012-01-12 19:14:25 +0530143static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144{
Bhasker Netid08d9012011-09-05 19:37:54 +0530145 int len = 0;
146 int rc = 0;
147 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530149 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150
151 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800152 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530153 BT_ERR("Frame larger than the allowed size, flushing frame");
154 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530155 goto out_data;
156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157
Bhasker Netiaae61462012-01-12 19:14:25 +0530158 if (len <= 0)
159 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160
Bhasker Netiaae61462012-01-12 19:14:25 +0530161 skb = bt_skb_alloc(len, GFP_ATOMIC);
162 if (!skb) {
163 BT_ERR("Error in allocating socket buffer");
164 smd_read(hsmd->data_channel, NULL, len);
165 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530166 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530167
168 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
169 if (rc < len) {
170 BT_ERR("Error in reading from the channel");
171 goto out_data;
172 }
173
174 skb->dev = (void *)hsmd->hdev;
175 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
176 skb_orphan(skb);
177
178 rc = hci_recv_frame(skb);
179 if (rc < 0) {
180 BT_ERR("Error in passing the packet to HCI Layer");
181 /*
182 * skb is getting freed in hci_recv_frame, making it
183 * to null to avoid multiple access
184 */
185 skb = NULL;
186 goto out_data;
187 }
188
189 /*
190 * Start the timer to monitor whether the Rx queue is
191 * empty for releasing the Rx wake lock
192 */
193 BT_DBG("Rx Timer is starting");
194 mod_timer(&hsmd->rx_q_timer,
195 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
196
Bhasker Netid08d9012011-09-05 19:37:54 +0530197out_data:
198 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530199 if (rc)
200 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201}
202
Bhasker Netiaae61462012-01-12 19:14:25 +0530203static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204{
Bhasker Netid08d9012011-09-05 19:37:54 +0530205 int len = 0;
206 int rc = 0;
207 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530209 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210
211 len = smd_read_avail(hsmd->event_channel);
212 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530213 BT_ERR("Frame larger than the allowed size, flushing frame");
214 rc = smd_read(hsmd->event_channel, NULL, len);
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 Netiaae61462012-01-12 19:14:25 +0530221 BT_ERR("Error in allocating socket buffer");
222 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530223 goto out_event;
224 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530225
226 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530227 if (rc < len) {
228 BT_ERR("Error in reading from the event channel");
229 goto out_event;
230 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 skb->dev = (void *)hsmd->hdev;
233 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
234
235 skb_orphan(skb);
236
237 rc = hci_recv_frame(skb);
238 if (rc < 0) {
239 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530240 /*
241 * skb is getting freed in hci_recv_frame, making it
242 * to null to avoid multiple access
243 */
244 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530245 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 }
247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530249 /*
250 * Start the timer to monitor whether the Rx queue is
251 * empty for releasing the Rx wake lock
252 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800253 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530254 mod_timer(&hsmd->rx_q_timer,
255 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
256 }
257out_event:
258 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530259 if (rc)
260 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261}
262
263static int hci_smd_send_frame(struct sk_buff *skb)
264{
265 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530266 int avail;
267 int ret = 0;
268 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269
270 switch (bt_cb(skb)->pkt_type) {
271 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530272 avail = smd_write_avail(hs.event_channel);
273 if (!avail) {
274 BT_ERR("No space available for smd frame");
275 ret = -ENOSPC;
276 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 len = smd_write(hs.event_channel, skb->data, skb->len);
278 if (len < skb->len) {
279 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530280 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 }
282 break;
283 case HCI_ACLDATA_PKT:
284 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700285 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530286 if (!avail) {
287 BT_ERR("No space available for smd frame");
288 ret = -ENOSPC;
289 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 len = smd_write(hs.data_channel, skb->data, skb->len);
291 if (len < skb->len) {
292 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530293 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 }
295 break;
296 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800297 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530298 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 break;
300 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530301
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530302 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530303 wake_unlock(&hs.wake_lock_tx);
304 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305}
306
Bhasker Netiaae61462012-01-12 19:14:25 +0530307static void hci_smd_rx(unsigned long arg)
308{
309 struct hci_smd_data *hsmd = &hs;
310
311 while ((smd_read_avail(hsmd->event_channel) > 0) ||
312 (smd_read_avail(hsmd->data_channel) > 0)) {
313 hci_smd_recv_event();
314 hci_smd_recv_data();
315 }
316}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317
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;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800322 struct work_struct *reset_worker;
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700323 struct work_struct *open_worker;
324
Bhasker Neti60734c02011-11-23 15:17:54 -0800325 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326
327 if (!hdev) {
328 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
329 return;
330 }
331
332 switch (event) {
333 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800334 len = smd_read_avail(hsmd->event_channel);
335 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530336 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800337 else if (len < 0)
338 BT_ERR("Failed to read event from smd %d", len);
339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 break;
341 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800342 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 hci_smd_open(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700344 open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
345 if (!open_worker) {
346 BT_ERR("Out of memory");
347 break;
348 }
349 INIT_WORK(open_worker, hci_dev_smd_open);
350 schedule_work(open_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 break;
352 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800353 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 hci_smd_close(hdev);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800355 reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
356 if (!reset_worker) {
357 BT_ERR("Out of memory");
358 break;
359 }
360 INIT_WORK(reset_worker, hci_dev_restart);
361 schedule_work(reset_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 break;
363 default:
364 break;
365 }
366}
367
368static void hci_smd_notify_data(void *data, unsigned int event)
369{
370 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800371 struct hci_smd_data *hsmd = &hs;
372 int len = 0;
373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530375 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376 return;
377 }
378
379 switch (event) {
380 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800381 len = smd_read_avail(hsmd->data_channel);
382 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530383 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800384 else if (len < 0)
385 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 break;
387 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800388 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 hci_smd_open(hdev);
390 break;
391 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800392 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 hci_smd_close(hdev);
394 break;
395 default:
396 break;
397 }
398
399}
400
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700401static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402{
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700403 struct hci_dev *hdev;
404
405 hdev = hsmd->hdev;
406
407 if (hci_register_dev(hdev) < 0) {
408 BT_ERR("Can't register HCI device");
409 hci_free_dev(hdev);
410 hsmd->hdev = NULL;
411 return -ENODEV;
412 }
413 return 0;
414}
415
416static int hci_smd_register_smd(struct hci_smd_data *hsmd)
417{
418 struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 int rc;
420
421 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800422 hdev = hci_alloc_dev();
423 if (!hdev) {
424 BT_ERR("Can't allocate HCI device");
425 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700426 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427
Bhasker Neti60576c62011-12-07 18:45:51 -0800428 hsmd->hdev = hdev;
429 hdev->bus = HCI_SMD;
430 hdev->driver_data = NULL;
431 hdev->open = hci_smd_open;
432 hdev->close = hci_smd_close;
433 hdev->send = hci_smd_send_frame;
434 hdev->destruct = hci_smd_destruct;
435 hdev->owner = THIS_MODULE;
436
Bhasker Netiaae61462012-01-12 19:14:25 +0530437
438 tasklet_init(&hsmd->rx_task,
439 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530440 /*
441 * Setup the timer to monitor whether the Rx queue is empty,
442 * to control the wake lock release
443 */
444 setup_timer(&hsmd->rx_q_timer, schedule_timer,
445 (unsigned long) hsmd->hdev);
446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 /* Open the SMD Channel and device and register the callback function */
448 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
449 &hsmd->event_channel, hdev, hci_smd_notify_event);
450 if (rc < 0) {
451 BT_ERR("Cannot open the command channel");
452 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700453 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 return -ENODEV;
455 }
456
457 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
458 &hsmd->data_channel, hdev, hci_smd_notify_data);
459 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800460 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700462 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463 return -ENODEV;
464 }
465
466 /* Disable the read interrupts on the channel */
467 smd_disable_read_intr(hsmd->event_channel);
468 smd_disable_read_intr(hsmd->data_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 return 0;
470}
471
Bhasker Neti60576c62011-12-07 18:45:51 -0800472static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473{
Bhasker Netiaae61462012-01-12 19:14:25 +0530474 tasklet_kill(&hs.rx_task);
475
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530476 if (hsmd->hdev) {
477 if (hci_unregister_dev(hsmd->hdev) < 0)
478 BT_ERR("Can't unregister HCI device %s",
479 hsmd->hdev->name);
480
481 hci_free_dev(hsmd->hdev);
482 hsmd->hdev = NULL;
483 }
484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530487
Ankur Nandwani327e0502011-11-11 15:47:25 -0800488 if (wake_lock_active(&hs.wake_lock_rx))
489 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800490 if (wake_lock_active(&hs.wake_lock_tx))
491 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800492
Bhasker Netid08d9012011-09-05 19:37:54 +0530493 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530494 if (hs.rx_q_timer.function) {
495 del_timer_sync(&hs.rx_q_timer);
496 hs.rx_q_timer.function = NULL;
497 hs.rx_q_timer.data = 0;
498 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499}
500
Sunny Kapdi02eab142012-02-01 13:52:27 -0800501static void hci_dev_restart(struct work_struct *worker)
502{
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700503 down(&hci_smd_enable);
504 restart_in_progress = 1;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800505 hci_smd_deregister_dev(&hs);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700506 hci_smd_register_smd(&hs);
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700507 up(&hci_smd_enable);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700508 kfree(worker);
509}
510
511static void hci_dev_smd_open(struct work_struct *worker)
512{
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700513 down(&hci_smd_enable);
514 if (restart_in_progress == 1) {
515 /* Allow wcnss to initialize */
516 restart_in_progress = 0;
517 msleep(10000);
518 }
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700519 hci_smd_hci_register_dev(&hs);
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700520 up(&hci_smd_enable);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800521 kfree(worker);
522}
523
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700524static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700526 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700528 pr_err("hcismd_set_enable %d", hcismd_set);
529
530 down(&hci_smd_enable);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700531
532 ret = param_set_int(val, kp);
533
534 if (ret)
535 goto done;
536
537 switch (hcismd_set) {
538
539 case 1:
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700540 if (hs.hdev == NULL)
541 hci_smd_register_smd(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700542 break;
543 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800544 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700545 break;
546 default:
547 ret = -EFAULT;
548 }
549
550done:
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700551 up(&hci_smd_enable);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700552 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553}
Bhasker Neti60576c62011-12-07 18:45:51 -0800554static int __init hci_smd_init(void)
555{
556 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
557 "msm_smd_Rx");
558 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
559 "msm_smd_Tx");
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700560 restart_in_progress = 0;
561 hs.hdev = NULL;
Bhasker Neti60576c62011-12-07 18:45:51 -0800562 return 0;
563}
564module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700565
Bhasker Neti60576c62011-12-07 18:45:51 -0800566static void __exit hci_smd_exit(void)
567{
568 wake_lock_destroy(&hs.wake_lock_rx);
569 wake_lock_destroy(&hs.wake_lock_tx);
570}
571module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572
573MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
574MODULE_DESCRIPTION("Bluetooth SMD driver");
575MODULE_LICENSE("GPL v2");