2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
5 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
26 * BlueZ HCI virtual device driver.
28 * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $
32 #include <linux/config.h>
33 #include <linux/module.h>
35 #include <linux/errno.h>
36 #include <linux/kernel.h>
37 #include <linux/major.h>
38 #include <linux/sched.h>
39 #include <linux/slab.h>
40 #include <linux/poll.h>
41 #include <linux/fcntl.h>
42 #include <linux/init.h>
43 #include <linux/random.h>
45 #include <linux/skbuff.h>
46 #include <linux/miscdevice.h>
48 #include <asm/system.h>
49 #include <asm/uaccess.h>
51 #include <net/bluetooth/bluetooth.h>
52 #include <net/bluetooth/hci_core.h>
57 static int hci_vhci_open(struct hci_dev *hdev)
59 set_bit(HCI_RUNNING, &hdev->flags);
63 static int hci_vhci_flush(struct hci_dev *hdev)
65 struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
66 skb_queue_purge(&hci_vhci->readq);
70 static int hci_vhci_close(struct hci_dev *hdev)
72 if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
79 static void hci_vhci_destruct(struct hci_dev *hdev)
81 struct hci_vhci_struct *vhci;
85 vhci = (struct hci_vhci_struct *) hdev->driver_data;
91 static int hci_vhci_send_frame(struct sk_buff *skb)
93 struct hci_dev* hdev = (struct hci_dev *) skb->dev;
94 struct hci_vhci_struct *hci_vhci;
97 BT_ERR("Frame for uknown device (hdev=NULL)");
101 if (!test_bit(HCI_RUNNING, &hdev->flags))
104 hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
106 memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
107 skb_queue_tail(&hci_vhci->readq, skb);
109 if (hci_vhci->flags & VHCI_FASYNC)
110 kill_fasync(&hci_vhci->fasync, SIGIO, POLL_IN);
111 wake_up_interruptible(&hci_vhci->read_wait);
116 /* Character device part */
119 static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait)
121 struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
123 poll_wait(file, &hci_vhci->read_wait, wait);
125 if (skb_queue_len(&hci_vhci->readq))
126 return POLLIN | POLLRDNORM;
128 return POLLOUT | POLLWRNORM;
131 /* Get packet from user space buffer(already verified) */
132 static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const char *buf, size_t count)
136 if (count > HCI_MAX_FRAME_SIZE)
139 if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
142 copy_from_user(skb_put(skb, count), buf, count);
144 skb->dev = (void *) &hci_vhci->hdev;
145 skb->pkt_type = *((__u8 *) skb->data);
154 static ssize_t hci_vhci_chr_write(struct file * file, const char * buf,
155 size_t count, loff_t *pos)
157 struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
159 if (verify_area(VERIFY_READ, buf, count))
162 return hci_vhci_get_user(hci_vhci, buf, count);
165 /* Put packet to user space buffer(already verified) */
166 static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci,
167 struct sk_buff *skb, char *buf, int count)
169 int len = count, total = 0;
172 len = MIN(skb->len, len);
173 copy_to_user(ptr, skb->data, len);
176 hci_vhci->hdev.stat.byte_tx += len;
177 switch (skb->pkt_type) {
178 case HCI_COMMAND_PKT:
179 hci_vhci->hdev.stat.cmd_tx++;
182 case HCI_ACLDATA_PKT:
183 hci_vhci->hdev.stat.acl_tx++;
186 case HCI_SCODATA_PKT:
187 hci_vhci->hdev.stat.cmd_tx++;
195 static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, loff_t *pos)
197 struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
198 DECLARE_WAITQUEUE(wait, current);
202 add_wait_queue(&hci_vhci->read_wait, &wait);
204 set_current_state(TASK_INTERRUPTIBLE);
206 /* Read frames from device queue */
207 if (!(skb = skb_dequeue(&hci_vhci->readq))) {
208 if (file->f_flags & O_NONBLOCK) {
212 if (signal_pending(current)) {
217 /* Nothing to read, let's sleep */
222 if (!verify_area(VERIFY_WRITE, buf, count))
223 ret = hci_vhci_put_user(hci_vhci, skb, buf, count);
230 set_current_state(TASK_RUNNING);
231 remove_wait_queue(&hci_vhci->read_wait, &wait);
236 static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
241 static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
246 static int hci_vhci_chr_fasync(int fd, struct file *file, int on)
248 struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
251 if ((ret = fasync_helper(fd, file, on, &hci_vhci->fasync)) < 0)
255 hci_vhci->flags |= VHCI_FASYNC;
257 hci_vhci->flags &= ~VHCI_FASYNC;
262 static int hci_vhci_chr_open(struct inode *inode, struct file * file)
264 struct hci_vhci_struct *hci_vhci = NULL;
265 struct hci_dev *hdev;
267 if (!(hci_vhci = kmalloc(sizeof(struct hci_vhci_struct), GFP_KERNEL)))
270 memset(hci_vhci, 0, sizeof(struct hci_vhci_struct));
272 skb_queue_head_init(&hci_vhci->readq);
273 init_waitqueue_head(&hci_vhci->read_wait);
275 /* Initialize and register HCI device */
276 hdev = &hci_vhci->hdev;
278 hdev->type = HCI_VHCI;
279 hdev->driver_data = hci_vhci;
281 hdev->open = hci_vhci_open;
282 hdev->close = hci_vhci_close;
283 hdev->flush = hci_vhci_flush;
284 hdev->send = hci_vhci_send_frame;
285 hdev->destruct = hci_vhci_destruct;
287 if (hci_register_dev(hdev) < 0) {
293 file->private_data = hci_vhci;
297 static int hci_vhci_chr_close(struct inode *inode, struct file *file)
299 struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
301 if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
302 BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
305 file->private_data = NULL;
309 static struct file_operations hci_vhci_fops = {
311 llseek: hci_vhci_chr_lseek,
312 read: hci_vhci_chr_read,
313 write: hci_vhci_chr_write,
314 poll: hci_vhci_chr_poll,
315 ioctl: hci_vhci_chr_ioctl,
316 open: hci_vhci_chr_open,
317 release:hci_vhci_chr_close,
318 fasync: hci_vhci_chr_fasync
321 static struct miscdevice hci_vhci_miscdev=
328 int __init hci_vhci_init(void)
330 BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
332 BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
334 if (misc_register(&hci_vhci_miscdev)) {
335 BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
342 void hci_vhci_cleanup(void)
344 misc_deregister(&hci_vhci_miscdev);
347 module_init(hci_vhci_init);
348 module_exit(hci_vhci_cleanup);
350 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
351 MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
352 MODULE_LICENSE("GPL");