blob: 6030520460c53420bb5fe3eef91c1d0a25c84672 [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 */
Bhasker Neti6d353ee2012-07-04 19:24:23 +053045#define HCI_REGISTER_SET 0
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070047
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070048static int hcismd_set;
Sunny Kapdi2a39b802012-05-30 12:47:14 -070049static DEFINE_SEMAPHORE(hci_smd_enable);
50
51static int restart_in_progress;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070052
53static int hcismd_set_enable(const char *val, struct kernel_param *kp);
54module_param_call(hcismd_set, hcismd_set_enable, NULL, &hcismd_set, 0644);
55
Sunny Kapdid71fbed2012-03-15 18:20:55 -070056static void hci_dev_smd_open(struct work_struct *worker);
Sunny Kapdi02eab142012-02-01 13:52:27 -080057static void hci_dev_restart(struct work_struct *worker);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059struct hci_smd_data {
60 struct hci_dev *hdev;
Bhasker Neti6d353ee2012-07-04 19:24:23 +053061 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062 struct smd_channel *event_channel;
63 struct smd_channel *data_channel;
Bhasker Netid08d9012011-09-05 19:37:54 +053064 struct wake_lock wake_lock_tx;
65 struct wake_lock wake_lock_rx;
66 struct timer_list rx_q_timer;
Bhasker Netiaae61462012-01-12 19:14:25 +053067 struct tasklet_struct rx_task;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068};
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -070069static struct hci_smd_data hs;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070
Bhasker Netid08d9012011-09-05 19:37:54 +053071/* Rx queue monitor timer function */
72static int is_rx_q_empty(unsigned long arg)
73{
74 struct hci_dev *hdev = (struct hci_dev *) arg;
75 struct sk_buff_head *list_ = &hdev->rx_q;
76 struct sk_buff *list = ((struct sk_buff *)list_)->next;
77 BT_DBG("%s Rx timer triggered", hdev->name);
78
79 if (list == (struct sk_buff *)list_) {
80 BT_DBG("%s RX queue empty", hdev->name);
81 return 1;
82 } else{
83 BT_DBG("%s RX queue not empty", hdev->name);
84 return 0;
85 }
86}
87
88static void release_lock(void)
89{
90 struct hci_smd_data *hsmd = &hs;
91 BT_DBG("Releasing Rx Lock");
92 if (is_rx_q_empty((unsigned long)hsmd->hdev) &&
93 wake_lock_active(&hs.wake_lock_rx))
94 wake_unlock(&hs.wake_lock_rx);
95}
96
97/* Rx timer callback function */
98static void schedule_timer(unsigned long arg)
99{
100 struct hci_dev *hdev = (struct hci_dev *) arg;
101 struct hci_smd_data *hsmd = &hs;
102 BT_DBG("%s Schedule Rx timer", hdev->name);
103
104 if (is_rx_q_empty(arg) && wake_lock_active(&hs.wake_lock_rx)) {
105 BT_DBG("%s RX queue empty", hdev->name);
106 /*
107 * Since the queue is empty, its ideal
108 * to release the wake lock on Rx
109 */
110 wake_unlock(&hs.wake_lock_rx);
111 } else{
112 BT_DBG("%s RX queue not empty", hdev->name);
113 /*
114 * Restart the timer to monitor whether the Rx queue is
115 * empty for releasing the Rx wake lock
116 */
117 mod_timer(&hsmd->rx_q_timer,
118 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
119 }
120}
121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122static int hci_smd_open(struct hci_dev *hdev)
123{
124 set_bit(HCI_RUNNING, &hdev->flags);
125 return 0;
126}
127
128
129static int hci_smd_close(struct hci_dev *hdev)
130{
131 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
132 return 0;
133 else
134 return -EPERM;
135}
136
137
138static void hci_smd_destruct(struct hci_dev *hdev)
139{
Bhasker Neti60576c62011-12-07 18:45:51 -0800140 if (NULL != hdev->driver_data)
141 kfree(hdev->driver_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142}
143
Bhasker Netiaae61462012-01-12 19:14:25 +0530144static void hci_smd_recv_data(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145{
Bhasker Netid08d9012011-09-05 19:37:54 +0530146 int len = 0;
147 int rc = 0;
148 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530150 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151
152 len = smd_read_avail(hsmd->data_channel);
Bhasker Neti60734c02011-11-23 15:17:54 -0800153 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530154 BT_ERR("Frame larger than the allowed size, flushing frame");
155 smd_read(hsmd->data_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530156 goto out_data;
157 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158
Bhasker Netiaae61462012-01-12 19:14:25 +0530159 if (len <= 0)
160 goto out_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161
Bhasker Netiaae61462012-01-12 19:14:25 +0530162 skb = bt_skb_alloc(len, GFP_ATOMIC);
163 if (!skb) {
164 BT_ERR("Error in allocating socket buffer");
165 smd_read(hsmd->data_channel, NULL, len);
166 goto out_data;
Bhasker Netid08d9012011-09-05 19:37:54 +0530167 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530168
169 rc = smd_read(hsmd->data_channel, skb_put(skb, len), len);
170 if (rc < len) {
171 BT_ERR("Error in reading from the channel");
172 goto out_data;
173 }
174
175 skb->dev = (void *)hsmd->hdev;
176 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
177 skb_orphan(skb);
178
179 rc = hci_recv_frame(skb);
180 if (rc < 0) {
181 BT_ERR("Error in passing the packet to HCI Layer");
182 /*
183 * skb is getting freed in hci_recv_frame, making it
184 * to null to avoid multiple access
185 */
186 skb = NULL;
187 goto out_data;
188 }
189
190 /*
191 * Start the timer to monitor whether the Rx queue is
192 * empty for releasing the Rx wake lock
193 */
194 BT_DBG("Rx Timer is starting");
195 mod_timer(&hsmd->rx_q_timer,
196 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
197
Bhasker Netid08d9012011-09-05 19:37:54 +0530198out_data:
199 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530200 if (rc)
201 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202}
203
Bhasker Netiaae61462012-01-12 19:14:25 +0530204static void hci_smd_recv_event(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205{
Bhasker Netid08d9012011-09-05 19:37:54 +0530206 int len = 0;
207 int rc = 0;
208 struct sk_buff *skb = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 struct hci_smd_data *hsmd = &hs;
Bhasker Netid08d9012011-09-05 19:37:54 +0530210 wake_lock(&hs.wake_lock_rx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211
212 len = smd_read_avail(hsmd->event_channel);
213 if (len > HCI_MAX_FRAME_SIZE) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530214 BT_ERR("Frame larger than the allowed size, flushing frame");
215 rc = smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530216 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217 }
218
219 while (len > 0) {
Ankur Nandwanic8150962011-08-24 13:06:23 -0700220 skb = bt_skb_alloc(len, GFP_ATOMIC);
Bhasker Netid08d9012011-09-05 19:37:54 +0530221 if (!skb) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530222 BT_ERR("Error in allocating socket buffer");
223 smd_read(hsmd->event_channel, NULL, len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530224 goto out_event;
225 }
Bhasker Netiaae61462012-01-12 19:14:25 +0530226
227 rc = smd_read(hsmd->event_channel, skb_put(skb, len), len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530228 if (rc < len) {
229 BT_ERR("Error in reading from the event channel");
230 goto out_event;
231 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 skb->dev = (void *)hsmd->hdev;
234 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
235
236 skb_orphan(skb);
237
238 rc = hci_recv_frame(skb);
239 if (rc < 0) {
240 BT_ERR("Error in passing the packet to HCI Layer");
Bhasker Neti44a792b2011-10-11 19:25:22 +0530241 /*
242 * skb is getting freed in hci_recv_frame, making it
243 * to null to avoid multiple access
244 */
245 skb = NULL;
Bhasker Netid08d9012011-09-05 19:37:54 +0530246 goto out_event;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 }
248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 len = smd_read_avail(hsmd->event_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530250 /*
251 * Start the timer to monitor whether the Rx queue is
252 * empty for releasing the Rx wake lock
253 */
Bhasker Neti60734c02011-11-23 15:17:54 -0800254 BT_DBG("Rx Timer is starting");
Bhasker Netid08d9012011-09-05 19:37:54 +0530255 mod_timer(&hsmd->rx_q_timer,
256 jiffies + msecs_to_jiffies(RX_Q_MONITOR));
257 }
258out_event:
259 release_lock();
Bhasker Netiaae61462012-01-12 19:14:25 +0530260 if (rc)
261 kfree_skb(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262}
263
264static int hci_smd_send_frame(struct sk_buff *skb)
265{
266 int len;
Bhasker Netid08d9012011-09-05 19:37:54 +0530267 int avail;
268 int ret = 0;
269 wake_lock(&hs.wake_lock_tx);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271 switch (bt_cb(skb)->pkt_type) {
272 case HCI_COMMAND_PKT:
Bhasker Netid08d9012011-09-05 19:37:54 +0530273 avail = smd_write_avail(hs.event_channel);
274 if (!avail) {
275 BT_ERR("No space available for smd frame");
276 ret = -ENOSPC;
277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 len = smd_write(hs.event_channel, skb->data, skb->len);
279 if (len < skb->len) {
280 BT_ERR("Failed to write Command %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530281 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 }
283 break;
284 case HCI_ACLDATA_PKT:
285 case HCI_SCODATA_PKT:
Ankur Nandwani23abeb22011-10-26 16:35:22 -0700286 avail = smd_write_avail(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530287 if (!avail) {
288 BT_ERR("No space available for smd frame");
289 ret = -ENOSPC;
290 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 len = smd_write(hs.data_channel, skb->data, skb->len);
292 if (len < skb->len) {
293 BT_ERR("Failed to write Data %d", len);
Bhasker Netid08d9012011-09-05 19:37:54 +0530294 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 }
296 break;
297 default:
Bhasker Neti60734c02011-11-23 15:17:54 -0800298 BT_ERR("Uknown packet type");
Bhasker Netid08d9012011-09-05 19:37:54 +0530299 ret = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 break;
301 }
Bhasker Netid08d9012011-09-05 19:37:54 +0530302
Anubhav Guptaddf48ec2011-10-03 14:24:13 +0530303 kfree_skb(skb);
Bhasker Netid08d9012011-09-05 19:37:54 +0530304 wake_unlock(&hs.wake_lock_tx);
305 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306}
307
Bhasker Netiaae61462012-01-12 19:14:25 +0530308static void hci_smd_rx(unsigned long arg)
309{
310 struct hci_smd_data *hsmd = &hs;
311
312 while ((smd_read_avail(hsmd->event_channel) > 0) ||
313 (smd_read_avail(hsmd->data_channel) > 0)) {
314 hci_smd_recv_event();
315 hci_smd_recv_data();
316 }
317}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318
319static void hci_smd_notify_event(void *data, unsigned int event)
320{
321 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800322 struct hci_smd_data *hsmd = &hs;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800323 struct work_struct *reset_worker;
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700324 struct work_struct *open_worker;
325
Bhasker Neti60734c02011-11-23 15:17:54 -0800326 int len = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327
328 if (!hdev) {
329 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
330 return;
331 }
332
333 switch (event) {
334 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800335 len = smd_read_avail(hsmd->event_channel);
336 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530337 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800338 else if (len < 0)
339 BT_ERR("Failed to read event from smd %d", len);
340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 break;
342 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800343 BT_INFO("opening HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344 hci_smd_open(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700345 open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
346 if (!open_worker) {
347 BT_ERR("Out of memory");
348 break;
349 }
350 INIT_WORK(open_worker, hci_dev_smd_open);
351 schedule_work(open_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352 break;
353 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800354 BT_INFO("Closing HCI-SMD channel :%s", EVENT_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 hci_smd_close(hdev);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800356 reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
357 if (!reset_worker) {
358 BT_ERR("Out of memory");
359 break;
360 }
361 INIT_WORK(reset_worker, hci_dev_restart);
362 schedule_work(reset_worker);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 break;
364 default:
365 break;
366 }
367}
368
369static void hci_smd_notify_data(void *data, unsigned int event)
370{
371 struct hci_dev *hdev = hs.hdev;
Bhasker Neti60734c02011-11-23 15:17:54 -0800372 struct hci_smd_data *hsmd = &hs;
373 int len = 0;
374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 if (!hdev) {
Bhasker Netiaae61462012-01-12 19:14:25 +0530376 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 return;
378 }
379
380 switch (event) {
381 case SMD_EVENT_DATA:
Bhasker Neti60734c02011-11-23 15:17:54 -0800382 len = smd_read_avail(hsmd->data_channel);
383 if (len > 0)
Bhasker Netiaae61462012-01-12 19:14:25 +0530384 tasklet_hi_schedule(&hs.rx_task);
Bhasker Neti60734c02011-11-23 15:17:54 -0800385 else if (len < 0)
386 BT_ERR("Failed to read data from smd %d", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 break;
388 case SMD_EVENT_OPEN:
Bhasker Neti60734c02011-11-23 15:17:54 -0800389 BT_INFO("opening HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 hci_smd_open(hdev);
391 break;
392 case SMD_EVENT_CLOSE:
Bhasker Neti60734c02011-11-23 15:17:54 -0800393 BT_INFO("Closing HCI-SMD channel :%s", DATA_CHANNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 hci_smd_close(hdev);
395 break;
396 default:
397 break;
398 }
399
400}
401
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700402static int hci_smd_hci_register_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403{
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700404 struct hci_dev *hdev;
405
406 hdev = hsmd->hdev;
Bhasker Neti6d353ee2012-07-04 19:24:23 +0530407 if (test_and_set_bit(HCI_REGISTER_SET, &hsmd->flags)) {
408 BT_ERR("HCI device registered already");
409 return 0;
410 } else
411 BT_INFO("HCI device registration is starting");
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700412 if (hci_register_dev(hdev) < 0) {
413 BT_ERR("Can't register HCI device");
414 hci_free_dev(hdev);
415 hsmd->hdev = NULL;
Bhasker Neti6d353ee2012-07-04 19:24:23 +0530416 clear_bit(HCI_REGISTER_SET, &hsmd->flags);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700417 return -ENODEV;
418 }
419 return 0;
420}
421
422static int hci_smd_register_smd(struct hci_smd_data *hsmd)
423{
424 struct hci_dev *hdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 int rc;
426
427 /* Initialize and register HCI device */
Bhasker Neti60576c62011-12-07 18:45:51 -0800428 hdev = hci_alloc_dev();
429 if (!hdev) {
430 BT_ERR("Can't allocate HCI device");
431 return -ENOMEM;
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700432 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433
Bhasker Neti60576c62011-12-07 18:45:51 -0800434 hsmd->hdev = hdev;
435 hdev->bus = HCI_SMD;
436 hdev->driver_data = NULL;
437 hdev->open = hci_smd_open;
438 hdev->close = hci_smd_close;
439 hdev->send = hci_smd_send_frame;
440 hdev->destruct = hci_smd_destruct;
441 hdev->owner = THIS_MODULE;
442
Bhasker Netiaae61462012-01-12 19:14:25 +0530443
444 tasklet_init(&hsmd->rx_task,
445 hci_smd_rx, (unsigned long) hsmd);
Bhasker Netid08d9012011-09-05 19:37:54 +0530446 /*
447 * Setup the timer to monitor whether the Rx queue is empty,
448 * to control the wake lock release
449 */
450 setup_timer(&hsmd->rx_q_timer, schedule_timer,
451 (unsigned long) hsmd->hdev);
452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700453 /* Open the SMD Channel and device and register the callback function */
454 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
455 &hsmd->event_channel, hdev, hci_smd_notify_event);
456 if (rc < 0) {
457 BT_ERR("Cannot open the command channel");
458 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 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
464 &hsmd->data_channel, hdev, hci_smd_notify_data);
465 if (rc < 0) {
Bhasker Neti60734c02011-11-23 15:17:54 -0800466 BT_ERR("Failed to open the Data channel");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 hci_free_dev(hdev);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700468 hsmd->hdev = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 return -ENODEV;
470 }
471
472 /* Disable the read interrupts on the channel */
473 smd_disable_read_intr(hsmd->event_channel);
474 smd_disable_read_intr(hsmd->data_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 return 0;
476}
477
Bhasker Neti60576c62011-12-07 18:45:51 -0800478static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479{
Bhasker Netiaae61462012-01-12 19:14:25 +0530480 tasklet_kill(&hs.rx_task);
481
Bhasker Neti6d353ee2012-07-04 19:24:23 +0530482 if (!test_and_clear_bit(HCI_REGISTER_SET, &hsmd->flags)) {
483 BT_ERR("HCI device un-registered already");
484 return;
485 } else
486 BT_INFO("HCI device un-registration going on");
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530487 if (hsmd->hdev) {
488 if (hci_unregister_dev(hsmd->hdev) < 0)
489 BT_ERR("Can't unregister HCI device %s",
490 hsmd->hdev->name);
491
492 hci_free_dev(hsmd->hdev);
493 hsmd->hdev = NULL;
494 }
495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496 smd_close(hs.event_channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 smd_close(hs.data_channel);
Bhasker Netid08d9012011-09-05 19:37:54 +0530498
Ankur Nandwani327e0502011-11-11 15:47:25 -0800499 if (wake_lock_active(&hs.wake_lock_rx))
500 wake_unlock(&hs.wake_lock_rx);
Bhasker Neti60576c62011-12-07 18:45:51 -0800501 if (wake_lock_active(&hs.wake_lock_tx))
502 wake_unlock(&hs.wake_lock_tx);
Ankur Nandwani327e0502011-11-11 15:47:25 -0800503
Bhasker Netid08d9012011-09-05 19:37:54 +0530504 /*Destroy the timer used to monitor the Rx queue for emptiness */
Royston Rodrigueseee6c962011-12-22 16:42:45 +0530505 if (hs.rx_q_timer.function) {
506 del_timer_sync(&hs.rx_q_timer);
507 hs.rx_q_timer.function = NULL;
508 hs.rx_q_timer.data = 0;
509 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510}
511
Sunny Kapdi02eab142012-02-01 13:52:27 -0800512static void hci_dev_restart(struct work_struct *worker)
513{
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700514 down(&hci_smd_enable);
515 restart_in_progress = 1;
Sunny Kapdi02eab142012-02-01 13:52:27 -0800516 hci_smd_deregister_dev(&hs);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700517 hci_smd_register_smd(&hs);
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700518 up(&hci_smd_enable);
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700519 kfree(worker);
520}
521
522static void hci_dev_smd_open(struct work_struct *worker)
523{
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700524 down(&hci_smd_enable);
525 if (restart_in_progress == 1) {
526 /* Allow wcnss to initialize */
527 restart_in_progress = 0;
528 msleep(10000);
529 }
Sunny Kapdid71fbed2012-03-15 18:20:55 -0700530 hci_smd_hci_register_dev(&hs);
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700531 up(&hci_smd_enable);
Sunny Kapdi02eab142012-02-01 13:52:27 -0800532 kfree(worker);
533}
534
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700535static int hcismd_set_enable(const char *val, struct kernel_param *kp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536{
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700537 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700539 pr_err("hcismd_set_enable %d", hcismd_set);
540
541 down(&hci_smd_enable);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700542
543 ret = param_set_int(val, kp);
544
545 if (ret)
546 goto done;
547
548 switch (hcismd_set) {
549
550 case 1:
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700551 if (hs.hdev == NULL)
552 hci_smd_register_smd(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700553 break;
554 case 0:
Bhasker Neti60576c62011-12-07 18:45:51 -0800555 hci_smd_deregister_dev(&hs);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700556 break;
557 default:
558 ret = -EFAULT;
559 }
560
561done:
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700562 up(&hci_smd_enable);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700563 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564}
Bhasker Neti60576c62011-12-07 18:45:51 -0800565static int __init hci_smd_init(void)
566{
567 wake_lock_init(&hs.wake_lock_rx, WAKE_LOCK_SUSPEND,
568 "msm_smd_Rx");
569 wake_lock_init(&hs.wake_lock_tx, WAKE_LOCK_SUSPEND,
570 "msm_smd_Tx");
Sunny Kapdi2a39b802012-05-30 12:47:14 -0700571 restart_in_progress = 0;
572 hs.hdev = NULL;
Bhasker Neti60576c62011-12-07 18:45:51 -0800573 return 0;
574}
575module_init(hci_smd_init);
Ankur Nandwani8ffe4e72011-10-10 21:51:48 -0700576
Bhasker Neti60576c62011-12-07 18:45:51 -0800577static void __exit hci_smd_exit(void)
578{
579 wake_lock_destroy(&hs.wake_lock_rx);
580 wake_lock_destroy(&hs.wake_lock_tx);
581}
582module_exit(hci_smd_exit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583
584MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
585MODULE_DESCRIPTION("Bluetooth SMD driver");
586MODULE_LICENSE("GPL v2");