blob: 7132c7c30569e945687c38612d2aa9565e7ab7fe [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 *
5 * Copyright (c) 2000-2001, 2011 Code Aurora Forum. All rights reserved.
6 * 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>
27#include <net/bluetooth/bluetooth.h>
28#include <net/bluetooth/hci_core.h>
29#include <net/bluetooth/hci.h>
30#include <mach/msm_smd.h>
31
32#define EVENT_CHANNEL "APPS_RIVA_BT_CMD"
33#define DATA_CHANNEL "APPS_RIVA_BT_ACL"
34
35struct hci_smd_data {
36 struct hci_dev *hdev;
37
38 struct smd_channel *event_channel;
39 struct smd_channel *data_channel;
40};
41struct hci_smd_data hs;
42
43static int hci_smd_open(struct hci_dev *hdev)
44{
45 set_bit(HCI_RUNNING, &hdev->flags);
46 return 0;
47}
48
49
50static int hci_smd_close(struct hci_dev *hdev)
51{
52 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
53 return 0;
54 else
55 return -EPERM;
56}
57
58
59static void hci_smd_destruct(struct hci_dev *hdev)
60{
61 kfree(hdev->driver_data);
62}
63
64static void hci_smd_recv_data(unsigned long arg)
65{
66 int len;
67 int rc;
68 struct sk_buff *skb;
69 unsigned char *buf;
70 struct hci_smd_data *hsmd = &hs;
71
72 len = smd_read_avail(hsmd->data_channel);
73
74 while (len > 0) {
75 skb = bt_skb_alloc(len, GFP_KERNEL);
76 if (!skb) {
77 BT_ERR("Error in allocating socket buffer\n");
78 return;
79 }
80
81 buf = kmalloc(len, GFP_KERNEL);
82 if (!buf) {
83 BT_ERR("Error in allocating buffer\n");
84 kfree_skb(skb);
85 return;
86 }
87
88 rc = smd_read_from_cb(hsmd->data_channel, (void *)buf, len);
89 if (rc < len) {
90 BT_ERR("Error in reading from the channel");
91 return;
92 }
93
94 memcpy(skb_put(skb, len), buf, len);
95 skb->dev = (void *)hsmd->hdev;
96 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
97
98 skb_orphan(skb);
99
100 rc = hci_recv_frame(skb);
101 if (rc < 0) {
102 BT_ERR("Error in passing the packet to HCI Layer");
103 return;
104 }
105
106 kfree(buf);
107 len = smd_read_avail(hsmd->data_channel);
108 }
109}
110
111static void hci_smd_recv_event(unsigned long arg)
112{
113 int len;
114 int rc;
115 struct sk_buff *skb;
116 unsigned char *buf;
117 struct hci_smd_data *hsmd = &hs;
118
119 len = smd_read_avail(hsmd->event_channel);
120 if (len > HCI_MAX_FRAME_SIZE) {
121 BT_ERR("Frame larger than the allowed size");
122 return;
123 }
124
125 while (len > 0) {
126 skb = bt_skb_alloc(len, GFP_KERNEL);
127 if (!skb)
128 return;
129
130 buf = kmalloc(len, GFP_KERNEL);
131 if (!buf) {
132 kfree_skb(skb);
133 return;
134 }
135
136 rc = smd_read_from_cb(hsmd->event_channel, (void *)buf, len);
137
138 memcpy(skb_put(skb, len), buf, len);
139 skb->dev = (void *)hsmd->hdev;
140 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
141
142 skb_orphan(skb);
143
144 rc = hci_recv_frame(skb);
145 if (rc < 0) {
146 BT_ERR("Error in passing the packet to HCI Layer");
147 return;
148 }
149
150 kfree(buf);
151 len = smd_read_avail(hsmd->event_channel);
152 }
153}
154
155static int hci_smd_send_frame(struct sk_buff *skb)
156{
157 int len;
158
159 switch (bt_cb(skb)->pkt_type) {
160 case HCI_COMMAND_PKT:
161 len = smd_write(hs.event_channel, skb->data, skb->len);
162 if (len < skb->len) {
163 BT_ERR("Failed to write Command %d", len);
164 return -ENODEV;
165 }
166 break;
167 case HCI_ACLDATA_PKT:
168 case HCI_SCODATA_PKT:
169 len = smd_write(hs.data_channel, skb->data, skb->len);
170 if (len < skb->len) {
171 BT_ERR("Failed to write Data %d", len);
172 return -ENODEV;
173 }
174 break;
175 default:
176 BT_ERR("Uknown packet type\n");
177 return -ENODEV;
178 break;
179 }
180 return 0;
181}
182
183
184static void hci_smd_notify_event(void *data, unsigned int event)
185{
186 struct hci_dev *hdev = hs.hdev;
187
188 if (!hdev) {
189 BT_ERR("Frame for unknown HCI device (hdev=NULL)");
190 return;
191 }
192
193 switch (event) {
194 case SMD_EVENT_DATA:
195 hci_smd_recv_event(event);
196 break;
197 case SMD_EVENT_OPEN:
198 hci_smd_open(hdev);
199 break;
200 case SMD_EVENT_CLOSE:
201 hci_smd_close(hdev);
202 break;
203 default:
204 break;
205 }
206}
207
208static void hci_smd_notify_data(void *data, unsigned int event)
209{
210 struct hci_dev *hdev = hs.hdev;
211 if (!hdev) {
212 BT_ERR("HCI device (hdev=NULL)");
213 return;
214 }
215
216 switch (event) {
217 case SMD_EVENT_DATA:
218 hci_smd_recv_data(event);
219 break;
220 case SMD_EVENT_OPEN:
221 hci_smd_open(hdev);
222 break;
223 case SMD_EVENT_CLOSE:
224 hci_smd_close(hdev);
225 break;
226 default:
227 break;
228 }
229
230}
231
232static int hci_smd_register_dev(struct hci_smd_data *hsmd)
233{
234 struct hci_dev *hdev;
235 int rc;
236
237 /* Initialize and register HCI device */
238 hdev = hci_alloc_dev();
239 if (!hdev) {
240 BT_ERR("Can't allocate HCI device");
241 return -ENOMEM;
242 }
243
244 hsmd->hdev = hdev;
245 hdev->bus = HCI_SMD;
246 hdev->driver_data = hsmd;
247 hdev->open = hci_smd_open;
248 hdev->close = hci_smd_close;
249 hdev->send = hci_smd_send_frame;
250 hdev->destruct = hci_smd_destruct;
251 hdev->owner = THIS_MODULE;
252
253 /* Open the SMD Channel and device and register the callback function */
254 rc = smd_named_open_on_edge(EVENT_CHANNEL, SMD_APPS_WCNSS,
255 &hsmd->event_channel, hdev, hci_smd_notify_event);
256 if (rc < 0) {
257 BT_ERR("Cannot open the command channel");
258 hci_free_dev(hdev);
259 return -ENODEV;
260 }
261
262 rc = smd_named_open_on_edge(DATA_CHANNEL, SMD_APPS_WCNSS,
263 &hsmd->data_channel, hdev, hci_smd_notify_data);
264 if (rc < 0) {
265 BT_ERR("Failed to open the Data channel\n");
266 hci_free_dev(hdev);
267 return -ENODEV;
268 }
269
270 /* Disable the read interrupts on the channel */
271 smd_disable_read_intr(hsmd->event_channel);
272 smd_disable_read_intr(hsmd->data_channel);
273
274 if (hci_register_dev(hdev) < 0) {
275 BT_ERR("Can't register HCI device");
276 hci_free_dev(hdev);
277 return -ENODEV;
278 }
279
280 return 0;
281}
282
283static void hci_smd_deregister(void)
284{
285 smd_close(hs.event_channel);
286 hs.event_channel = 0;
287 smd_close(hs.data_channel);
288 hs.data_channel = 0;
289}
290
291static int hci_smd_init(void)
292{
293 return hci_smd_register_dev(&hs);
294}
295module_init(hci_smd_init);
296
297static void __exit hci_smd_exit(void)
298{
299 hci_smd_deregister();
300}
301module_exit(hci_smd_exit);
302
303MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
304MODULE_DESCRIPTION("Bluetooth SMD driver");
305MODULE_LICENSE("GPL v2");