Root/
1 | /* |
2 | * |
3 | * Bluetooth virtual HCI driver |
4 | * |
5 | * Copyright (C) 2000-2001 Qualcomm Incorporated |
6 | * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> |
7 | * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org> |
8 | * |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. |
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 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * |
24 | */ |
25 | |
26 | #include <linux/module.h> |
27 | |
28 | #include <linux/kernel.h> |
29 | #include <linux/init.h> |
30 | #include <linux/slab.h> |
31 | #include <linux/types.h> |
32 | #include <linux/errno.h> |
33 | #include <linux/sched.h> |
34 | #include <linux/poll.h> |
35 | |
36 | #include <linux/skbuff.h> |
37 | #include <linux/miscdevice.h> |
38 | |
39 | #include <net/bluetooth/bluetooth.h> |
40 | #include <net/bluetooth/hci_core.h> |
41 | |
42 | #define VERSION "1.3" |
43 | |
44 | static bool amp; |
45 | |
46 | struct vhci_data { |
47 | struct hci_dev *hdev; |
48 | |
49 | unsigned long flags; |
50 | |
51 | wait_queue_head_t read_wait; |
52 | struct sk_buff_head readq; |
53 | }; |
54 | |
55 | static int vhci_open_dev(struct hci_dev *hdev) |
56 | { |
57 | set_bit(HCI_RUNNING, &hdev->flags); |
58 | |
59 | return 0; |
60 | } |
61 | |
62 | static int vhci_close_dev(struct hci_dev *hdev) |
63 | { |
64 | struct vhci_data *data = hci_get_drvdata(hdev); |
65 | |
66 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) |
67 | return 0; |
68 | |
69 | skb_queue_purge(&data->readq); |
70 | |
71 | return 0; |
72 | } |
73 | |
74 | static int vhci_flush(struct hci_dev *hdev) |
75 | { |
76 | struct vhci_data *data = hci_get_drvdata(hdev); |
77 | |
78 | skb_queue_purge(&data->readq); |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | static int vhci_send_frame(struct sk_buff *skb) |
84 | { |
85 | struct hci_dev* hdev = (struct hci_dev *) skb->dev; |
86 | struct vhci_data *data; |
87 | |
88 | if (!hdev) { |
89 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); |
90 | return -ENODEV; |
91 | } |
92 | |
93 | if (!test_bit(HCI_RUNNING, &hdev->flags)) |
94 | return -EBUSY; |
95 | |
96 | data = hci_get_drvdata(hdev); |
97 | |
98 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); |
99 | skb_queue_tail(&data->readq, skb); |
100 | |
101 | wake_up_interruptible(&data->read_wait); |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | static inline ssize_t vhci_get_user(struct vhci_data *data, |
107 | const char __user *buf, size_t count) |
108 | { |
109 | struct sk_buff *skb; |
110 | |
111 | if (count > HCI_MAX_FRAME_SIZE) |
112 | return -EINVAL; |
113 | |
114 | skb = bt_skb_alloc(count, GFP_KERNEL); |
115 | if (!skb) |
116 | return -ENOMEM; |
117 | |
118 | if (copy_from_user(skb_put(skb, count), buf, count)) { |
119 | kfree_skb(skb); |
120 | return -EFAULT; |
121 | } |
122 | |
123 | skb->dev = (void *) data->hdev; |
124 | bt_cb(skb)->pkt_type = *((__u8 *) skb->data); |
125 | skb_pull(skb, 1); |
126 | |
127 | hci_recv_frame(skb); |
128 | |
129 | return count; |
130 | } |
131 | |
132 | static inline ssize_t vhci_put_user(struct vhci_data *data, |
133 | struct sk_buff *skb, char __user *buf, int count) |
134 | { |
135 | char __user *ptr = buf; |
136 | int len, total = 0; |
137 | |
138 | len = min_t(unsigned int, skb->len, count); |
139 | |
140 | if (copy_to_user(ptr, skb->data, len)) |
141 | return -EFAULT; |
142 | |
143 | total += len; |
144 | |
145 | data->hdev->stat.byte_tx += len; |
146 | |
147 | switch (bt_cb(skb)->pkt_type) { |
148 | case HCI_COMMAND_PKT: |
149 | data->hdev->stat.cmd_tx++; |
150 | break; |
151 | |
152 | case HCI_ACLDATA_PKT: |
153 | data->hdev->stat.acl_tx++; |
154 | break; |
155 | |
156 | case HCI_SCODATA_PKT: |
157 | data->hdev->stat.sco_tx++; |
158 | break; |
159 | } |
160 | |
161 | return total; |
162 | } |
163 | |
164 | static ssize_t vhci_read(struct file *file, |
165 | char __user *buf, size_t count, loff_t *pos) |
166 | { |
167 | struct vhci_data *data = file->private_data; |
168 | struct sk_buff *skb; |
169 | ssize_t ret = 0; |
170 | |
171 | while (count) { |
172 | skb = skb_dequeue(&data->readq); |
173 | if (skb) { |
174 | ret = vhci_put_user(data, skb, buf, count); |
175 | if (ret < 0) |
176 | skb_queue_head(&data->readq, skb); |
177 | else |
178 | kfree_skb(skb); |
179 | break; |
180 | } |
181 | |
182 | if (file->f_flags & O_NONBLOCK) { |
183 | ret = -EAGAIN; |
184 | break; |
185 | } |
186 | |
187 | ret = wait_event_interruptible(data->read_wait, |
188 | !skb_queue_empty(&data->readq)); |
189 | if (ret < 0) |
190 | break; |
191 | } |
192 | |
193 | return ret; |
194 | } |
195 | |
196 | static ssize_t vhci_write(struct file *file, |
197 | const char __user *buf, size_t count, loff_t *pos) |
198 | { |
199 | struct vhci_data *data = file->private_data; |
200 | |
201 | return vhci_get_user(data, buf, count); |
202 | } |
203 | |
204 | static unsigned int vhci_poll(struct file *file, poll_table *wait) |
205 | { |
206 | struct vhci_data *data = file->private_data; |
207 | |
208 | poll_wait(file, &data->read_wait, wait); |
209 | |
210 | if (!skb_queue_empty(&data->readq)) |
211 | return POLLIN | POLLRDNORM; |
212 | |
213 | return POLLOUT | POLLWRNORM; |
214 | } |
215 | |
216 | static int vhci_open(struct inode *inode, struct file *file) |
217 | { |
218 | struct vhci_data *data; |
219 | struct hci_dev *hdev; |
220 | |
221 | data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL); |
222 | if (!data) |
223 | return -ENOMEM; |
224 | |
225 | skb_queue_head_init(&data->readq); |
226 | init_waitqueue_head(&data->read_wait); |
227 | |
228 | hdev = hci_alloc_dev(); |
229 | if (!hdev) { |
230 | kfree(data); |
231 | return -ENOMEM; |
232 | } |
233 | |
234 | data->hdev = hdev; |
235 | |
236 | hdev->bus = HCI_VIRTUAL; |
237 | hci_set_drvdata(hdev, data); |
238 | |
239 | if (amp) |
240 | hdev->dev_type = HCI_AMP; |
241 | |
242 | hdev->open = vhci_open_dev; |
243 | hdev->close = vhci_close_dev; |
244 | hdev->flush = vhci_flush; |
245 | hdev->send = vhci_send_frame; |
246 | |
247 | if (hci_register_dev(hdev) < 0) { |
248 | BT_ERR("Can't register HCI device"); |
249 | kfree(data); |
250 | hci_free_dev(hdev); |
251 | return -EBUSY; |
252 | } |
253 | |
254 | file->private_data = data; |
255 | nonseekable_open(inode, file); |
256 | |
257 | return 0; |
258 | } |
259 | |
260 | static int vhci_release(struct inode *inode, struct file *file) |
261 | { |
262 | struct vhci_data *data = file->private_data; |
263 | struct hci_dev *hdev = data->hdev; |
264 | |
265 | hci_unregister_dev(hdev); |
266 | hci_free_dev(hdev); |
267 | |
268 | file->private_data = NULL; |
269 | kfree(data); |
270 | |
271 | return 0; |
272 | } |
273 | |
274 | static const struct file_operations vhci_fops = { |
275 | .owner = THIS_MODULE, |
276 | .read = vhci_read, |
277 | .write = vhci_write, |
278 | .poll = vhci_poll, |
279 | .open = vhci_open, |
280 | .release = vhci_release, |
281 | .llseek = no_llseek, |
282 | }; |
283 | |
284 | static struct miscdevice vhci_miscdev= { |
285 | .name = "vhci", |
286 | .fops = &vhci_fops, |
287 | .minor = MISC_DYNAMIC_MINOR, |
288 | }; |
289 | |
290 | static int __init vhci_init(void) |
291 | { |
292 | BT_INFO("Virtual HCI driver ver %s", VERSION); |
293 | |
294 | return misc_register(&vhci_miscdev); |
295 | } |
296 | |
297 | static void __exit vhci_exit(void) |
298 | { |
299 | misc_deregister(&vhci_miscdev); |
300 | } |
301 | |
302 | module_init(vhci_init); |
303 | module_exit(vhci_exit); |
304 | |
305 | module_param(amp, bool, 0644); |
306 | MODULE_PARM_DESC(amp, "Create AMP controller device"); |
307 | |
308 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); |
309 | MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); |
310 | MODULE_VERSION(VERSION); |
311 | MODULE_LICENSE("GPL"); |
312 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9