blob: 18cef72b2fc67b679f9f1a6a519a0f46f9de4bce [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>
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;
Sunny Kapdi2a39b802012-05-30 12:47:14 -070047static DEFINE_SEMAPHORE(hci_smd_enable);
48
49static int restart_in_progress;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070050
51static int hcismd_set_enable(const char *val, struct kernel_param *kp);
52module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
53
Sunny Kapdid71fbed2012-03-15 18:20:55 -070054static void hci_dev_smd_open(struct work_struct *worker);
Sunny Kapdi02eab142012-02-01 13:52:27 -080055static void hci_dev_restart(struct work_struct *worker);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057struct hci_smd_data {
58 struct hci_dev *hdev;
59
60 struct smd_channel *event_channel;
61 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053062 struct wake_lock wake_lock_tx;
63 struct wake_lock wake_lock_rx;
64 struct timer_list rx_q_timer;
Bhasker Netiaae61462012-01-12 19:14:25 +053065 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070067static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068
Bhasker Netid08d9012011-09-05 19:37:54 +053069/* Rx queue monitor timer function */
70static int is_rx_q_empty(unsigned long arg)
71{
72 struct hci_dev *hdev = (struct hci_dev *) arg;
73 struct sk_buff_head *list_ = &hdev->rx_q;
74 struct sk_buff *list = ((struct sk_buff *)list_)->next;
75 BT_DBG("%s Rx timer triggered", hdev->name);
76
77 if (list == (struct sk_buff *)list_) {
78 BT_DBG("%s RX queue empty", hdev->name);
79 return 1;
80 } else{
81 BT_DBG("%s RX queue not empty", hdev->name);
82 return 0;
83 }
84}
85
86static void release_lock(void)
87{
88 struct hci_smd_data *hsmd = &hs;
89 BT_DBG("Releasing Rx Lock");
90 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
91 wake_lock_active(&hs.wake_lock_rx))
92 wake_unlock(&hs.wake_lock_rx);
93}
94
95/* Rx timer callback function */
96static void schedule_timer(unsigned long arg)
97{
98 struct hci_dev *hdev = (struct hci_dev *) arg;
99 struct hci_smd_data *hsmd = &hs;
100 BT_DBG("%s Schedule Rx timer", hdev->name);
101
102 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
103 BT_DBG("%s RX queue empty", hdev->name);
104 /*
105 * Since the queue is empty, its ideal
106 * to release the wake lock on Rx
107 */
108 wake_unlock(&hs.wake_lock_rx);
109 } else{
110 BT_DBG("%s RX queue not empty", hdev->name);
111 /*
112 * Restart the timer to monitor whether the Rx queue is
113 * empty for releasing the Rx wake lock
114 */
115 mod_timer(&hsmd->rx_q_timer,
116 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
117 }
118}
119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120static int hci_smd_open(struct hci_dev *hdev)
121{
122 set_bit(HCI_RUNNING, &hdev->flags);
123 return 0;
124}
125
126
127static int hci_smd_close(struct hci_dev *hdev)
128{
129 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
130 return 0;
131 else
132 return -EPERM;
133}
134
135
136static void hci_smd_destruct(struct hci_dev *hdev)
137{
Bhasker Neti60576c62011-12-07 18:45:51 -0800138 if (NULL != hdev->driver_data)
139 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140}
141
Bhasker Netiaae61462012-01-12 19:14:25 +0530142static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143{
Bhasker Netid08d9012011-09-05 19:37:54 +0530144 int len = 0;
145 int rc = 0;
146 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530148 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149
150 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800151 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530152 BT_ERR("Frame larger than the allowed size, flushing frame");
153 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530154 goto out_data;
155 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156
Bhasker Netiaae61462012-01-12 19:14:25 +0530157 if (len <= 0)
158 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159
Bhasker Netiaae61462012-01-12 19:14:25 +0530160 skb = bt_skb_alloc(len, GFP_ATOMIC);
161 if (!skb) {
162 BT_ERR("Error in allocating socket buffer");
163 smd_read(hsmd->data_channel, NULL, len);
164 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530165 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530166
167 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
168 if (rc < len) {
169 BT_ERR("Error in reading from the channel");
170 goto out_data;
171 }
172
173 skb->dev = (void *)hsmd->hdev;
174 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
175 skb_orphan(skb);
176
177 rc = hci_recv_frame(skb);
178 if (rc < 0) {
179 BT_ERR("Error in passing the packet to HCI Layer");
180 /*
181 * skb is getting freed in hci_recv_frame, making it
182 * to null to avoid multiple access
183 */
184 skb = NULL;
185 goto out_data;
186 }
187
188 /*
189 * Start the timer to monitor whether the Rx queue is
190 * empty for releasing the Rx wake lock
191 */
192 BT_DBG("Rx Timer is starting");
193 mod_timer(&hsmd->rx_q_timer,
194 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
195
Bhasker Netid08d9012011-09-05 19:37:54 +0530196out_data:
197 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530198 if (rc)
199 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200}
201
Bhasker Netiaae61462012-01-12 19:14:25 +0530202static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203{
Bhasker Netid08d9012011-09-05 19:37:54 +0530204 int len = 0;
205 int rc = 0;
206 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530208 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209
210 len = smd_read_avail(hsmd->event_channel);
211 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530212 BT_ERR("Frame larger than the allowed size, flushing frame");
213 rc = smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530214 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 }
216
217 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700218 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530219 if (!skb) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530220 BT_ERR("Error in allocating socket buffer");
221 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530222 goto out_event;
223 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530224
225 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530226 if (rc < len) {
227 BT_ERR("Error in reading from the event channel");
228 goto out_event;
229 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 skb->dev = (void *)hsmd->hdev;
232 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
233
234 skb_orphan(skb);
235
236 rc = hci_recv_frame(skb);
237 if (rc < 0) {
238 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530239 /*
240 * skb is getting freed in hci_recv_frame, making it
241 * to null to avoid multiple access
242 */
243 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530244 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 }
246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530248 /*
249 * Start the timer to monitor whether the Rx queue is
250 * empty for releasing the Rx wake lock
251 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800252 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530253 mod_timer(&hsmd->rx_q_timer,
254 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
255 }
256out_event:
257 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530258 if (rc)
259 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260}
261
262static int hci_smd_send_frame(struct sk_buff *skb)
263{
264 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530265 int avail;
266 int ret = 0;
267 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268
269 switch (bt_cb(skb)->pkt_type) {
270 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530271 avail = smd_write_avail(hs.event_channel);
272 if (!avail) {
273 BT_ERR("No space available for smd frame");
274 ret = -ENOSPC;
275 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 len = smd_write(hs.event_channel, skb->data, skb->len);
277 if (len < skb->len) {
278 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530279 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 }
281 break;
282 case HCI_ACLDATA_PKT:
283 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700284 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530285 if (!avail) {
286 BT_ERR("No space available for smd frame");
287 ret = -ENOSPC;
288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 len = smd_write(hs.data_channel, skb->data, skb->len);
290 if (len < skb->len) {
291 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530292 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 }
294 break;
295 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800296 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530297 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 break;
299 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530300
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530301 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530302 wake_unlock(&hs.wake_lock_tx);
303 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304}
305
Bhasker Netiaae61462012-01-12 19:14:25 +0530306static void hci_smd_rx(unsigned long arg)
307{
308 struct hci_smd_data *hsmd = &hs;
309
310 while ((smd_read_avail(hsmd->event_channel) > 0) ||
311 (smd_read_avail(hsmd->data_channel) > 0)) {
312 hci_smd_recv_event();
313 hci_smd_recv_data();
314 }
315}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316
317static void hci_smd_notify_event(void *data, unsigned int event)
318{
319 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800320 struct hci_smd_data *hsmd = &hs;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800321 struct work_struct *reset_worker;
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700322 struct work_struct *open_worker;
323
Bhasker Neti60734c02011-11-23 15:17:54 -0800324 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325
326 if (!hdev) {
327 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
328 return;
329 }
330
331 switch (event) {
332 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800333 len = smd_read_avail(hsmd->event_channel);
334 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530335 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800336 else if (len < 0)
337 BT_ERR("Failed to read event from smd %d", len);
338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339 break;
340 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800341 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 hci_smd_open(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700343 open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
344 if (!open_worker) {
345 BT_ERR("Out of memory");
346 break;
347 }
348 INIT_WORK(open_worker, hci_dev_smd_open);
349 schedule_work(open_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 break;
351 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800352 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 hci_smd_close(hdev);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800354 reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
355 if (!reset_worker) {
356 BT_ERR("Out of memory");
357 break;
358 }
359 INIT_WORK(reset_worker, hci_dev_restart);
360 schedule_work(reset_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361 break;
362 default:
363 break;
364 }
365}
366
367static void hci_smd_notify_data(void *data, unsigned int event)
368{
369 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800370 struct hci_smd_data *hsmd = &hs;
371 int len = 0;
372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530374 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 return;
376 }
377
378 switch (event) {
379 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800380 len = smd_read_avail(hsmd->data_channel);
381 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530382 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800383 else if (len < 0)
384 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 break;
386 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800387 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 hci_smd_open(hdev);
389 break;
390 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800391 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 hci_smd_close(hdev);
393 break;
394 default:
395 break;
396 }
397
398}
399
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700400static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401{
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700402 struct hci_dev *hdev;
403
404 hdev = hsmd->hdev;
405
406 if (hci_register_dev(hdev) < 0) {
407 BT_ERR("Can't register HCI device");
408 hci_free_dev(hdev);
409 hsmd->hdev = NULL;
410 return -ENODEV;
411 }
412 return 0;
413}
414
415static int hci_smd_register_smd(struct hci_smd_data *hsmd)
416{
417 struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 int rc;
419
420 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800421 hdev = hci_alloc_dev();
422 if (!hdev) {
423 BT_ERR("Can't allocate HCI device");
424 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700425 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
Bhasker Neti60576c62011-12-07 18:45:51 -0800427 hsmd->hdev = hdev;
428 hdev->bus = HCI_SMD;
429 hdev->driver_data = NULL;
430 hdev->open = hci_smd_open;
431 hdev->close = hci_smd_close;
432 hdev->send = hci_smd_send_frame;
433 hdev->destruct = hci_smd_destruct;
434 hdev->owner = THIS_MODULE;
435
Bhasker Netiaae61462012-01-12 19:14:25 +0530436
437 tasklet_init(&hsmd->rx_task,
438 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530439 /*
440 * Setup the timer to monitor whether the Rx queue is empty,
441 * to control the wake lock release
442 */
443 setup_timer(&hsmd->rx_q_timer, schedule_timer,
444 (unsigned long) hsmd->hdev);
445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446 /* Open the SMD Channel and device and register the callback function */
447 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
448 &hsmd->event_channel, hdev, hci_smd_notify_event);
449 if (rc < 0) {
450 BT_ERR("Cannot open the command channel");
451 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700452 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700453 return -ENODEV;
454 }
455
456 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
457 &hsmd->data_channel, hdev, hci_smd_notify_data);
458 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800459 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700461 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 return -ENODEV;
463 }
464
465 /* Disable the read interrupts on the channel */
466 smd_disable_read_intr(hsmd->event_channel);
467 smd_disable_read_intr(hsmd->data_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 return 0;
469}
470
Bhasker Neti60576c62011-12-07 18:45:51 -0800471static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472{
Bhasker Netiaae61462012-01-12 19:14:25 +0530473 tasklet_kill(&hs.rx_task);
474
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530475 if (hsmd->hdev) {
476 if (hci_unregister_dev(hsmd->hdev) < 0)
477 BT_ERR("Can't unregister HCI device %s",
478 hsmd->hdev->name);
479
480 hci_free_dev(hsmd->hdev);
481 hsmd->hdev = NULL;
482 }
483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530486
Ankur Nandwani327e0502011-11-11 15:47:25 -0800487 if (wake_lock_active(&hs.wake_lock_rx))
488 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800489 if (wake_lock_active(&hs.wake_lock_tx))
490 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800491
Bhasker Netid08d9012011-09-05 19:37:54 +0530492 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530493 if (hs.rx_q_timer.function) {
494 del_timer_sync(&hs.rx_q_timer);
495 hs.rx_q_timer.function = NULL;
496 hs.rx_q_timer.data = 0;
497 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498}
499
Sunny Kapdi02eab142012-02-01 13:52:27 -0800500static void hci_dev_restart(struct work_struct *worker)
501{
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700502 down(&hci_smd_enable);
503 restart_in_progress = 1;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800504 hci_smd_deregister_dev(&hs);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700505 hci_smd_register_smd(&hs);
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700506 up(&hci_smd_enable);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700507 kfree(worker);
508}
509
510static void hci_dev_smd_open(struct work_struct *worker)
511{
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700512 down(&hci_smd_enable);
513 if (restart_in_progress == 1) {
514 /* Allow wcnss to initialize */
515 restart_in_progress = 0;
516 msleep(10000);
517 }
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700518 hci_smd_hci_register_dev(&hs);
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700519 up(&hci_smd_enable);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800520 kfree(worker);
521}
522
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700523static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700525 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700527 pr_err("hcismd_set_enable %d", hcismd_set);
528
529 down(&hci_smd_enable);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700530
531 ret = param_set_int(val, kp);
532
533 if (ret)
534 goto done;
535
536 switch (hcismd_set) {
537
538 case 1:
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700539 if (hs.hdev == NULL)
540 hci_smd_register_smd(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700541 break;
542 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800543 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700544 break;
545 default:
546 ret = -EFAULT;
547 }
548
549done:
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700550 up(&hci_smd_enable);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700551 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552}
Bhasker Neti60576c62011-12-07 18:45:51 -0800553static int __init hci_smd_init(void)
554{
555 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
556 "msm_smd_Rx");
557 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
558 "msm_smd_Tx");
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700559 restart_in_progress = 0;
560 hs.hdev = NULL;
Bhasker Neti60576c62011-12-07 18:45:51 -0800561 return 0;
562}
563module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700564
Bhasker Neti60576c62011-12-07 18:45:51 -0800565static void __exit hci_smd_exit(void)
566{
567 wake_lock_destroy(&hs.wake_lock_rx);
568 wake_lock_destroy(&hs.wake_lock_tx);
569}
570module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571
572MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
573MODULE_DESCRIPTION("Bluetooth SMD driver");
574MODULE_LICENSE("GPL v2");