import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / bluetooth / hci_vhci.c
1 /* 
2    BlueZ - Bluetooth protocol stack for Linux
3    Copyright (C) 2000-2001 Qualcomm Incorporated
4
5    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
6
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;
10
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.
19
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.
23 */
24
25 /*
26  * BlueZ HCI virtual device driver.
27  *
28  * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ 
29  */
30 #define VERSION "1.1"
31
32 #include <linux/config.h>
33 #include <linux/module.h>
34
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>
44
45 #include <linux/skbuff.h>
46 #include <linux/miscdevice.h>
47
48 #include <asm/system.h>
49 #include <asm/uaccess.h>
50
51 #include <net/bluetooth/bluetooth.h>
52 #include <net/bluetooth/hci_core.h>
53 #include "hci_vhci.h"
54
55 /* HCI device part */
56
57 static int hci_vhci_open(struct hci_dev *hdev)
58 {
59         set_bit(HCI_RUNNING, &hdev->flags);
60         return 0;
61 }
62
63 static int hci_vhci_flush(struct hci_dev *hdev)
64 {
65         struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
66         skb_queue_purge(&hci_vhci->readq);
67         return 0;
68 }
69
70 static int hci_vhci_close(struct hci_dev *hdev)
71 {
72         if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
73                 return 0;
74
75         hci_vhci_flush(hdev);
76         return 0;
77 }
78
79 static void hci_vhci_destruct(struct hci_dev *hdev)
80 {
81         struct hci_vhci_struct *vhci;
82
83         if (!hdev) return;
84
85         vhci = (struct hci_vhci_struct *) hdev->driver_data;
86         kfree(vhci);
87
88         MOD_DEC_USE_COUNT;
89 }
90
91 static int hci_vhci_send_frame(struct sk_buff *skb)
92 {
93         struct hci_dev* hdev = (struct hci_dev *) skb->dev;
94         struct hci_vhci_struct *hci_vhci;
95
96         if (!hdev) {
97                 BT_ERR("Frame for uknown device (hdev=NULL)");
98                 return -ENODEV;
99         }
100
101         if (!test_bit(HCI_RUNNING, &hdev->flags))
102                 return -EBUSY;
103
104         hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
105
106         memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
107         skb_queue_tail(&hci_vhci->readq, skb);
108
109         if (hci_vhci->flags & VHCI_FASYNC)
110                 kill_fasync(&hci_vhci->fasync, SIGIO, POLL_IN);
111         wake_up_interruptible(&hci_vhci->read_wait);
112
113         return 0;
114 }
115
116 /* Character device part */
117
118 /* Poll */
119 static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait)
120 {  
121         struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
122
123         poll_wait(file, &hci_vhci->read_wait, wait);
124  
125         if (skb_queue_len(&hci_vhci->readq))
126                 return POLLIN | POLLRDNORM;
127
128         return POLLOUT | POLLWRNORM;
129 }
130
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)
133 {
134         struct sk_buff *skb;
135
136         if (count > HCI_MAX_FRAME_SIZE)
137                 return -EINVAL;
138
139         if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
140                 return -ENOMEM;
141         
142         copy_from_user(skb_put(skb, count), buf, count); 
143
144         skb->dev = (void *) &hci_vhci->hdev;
145         skb->pkt_type = *((__u8 *) skb->data);
146         skb_pull(skb, 1);
147
148         hci_recv_frame(skb);
149
150         return count;
151
152
153 /* Write */
154 static ssize_t hci_vhci_chr_write(struct file * file, const char * buf, 
155                              size_t count, loff_t *pos)
156 {
157         struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
158
159         if (verify_area(VERIFY_READ, buf, count))
160                 return -EFAULT;
161
162         return hci_vhci_get_user(hci_vhci, buf, count);
163 }
164
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)
168 {
169         int len = count, total = 0;
170         char *ptr = buf;
171
172         len = MIN(skb->len, len); 
173         copy_to_user(ptr, skb->data, len); 
174         total += len;
175
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++;
180                         break;
181
182                 case HCI_ACLDATA_PKT:
183                         hci_vhci->hdev.stat.acl_tx++;
184                         break;
185
186                 case HCI_SCODATA_PKT:
187                         hci_vhci->hdev.stat.cmd_tx++;
188                         break;
189         };
190
191         return total;
192 }
193
194 /* Read */
195 static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, loff_t *pos)
196 {
197         struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
198         DECLARE_WAITQUEUE(wait, current);
199         struct sk_buff *skb;
200         ssize_t ret = 0;
201
202         add_wait_queue(&hci_vhci->read_wait, &wait);
203         while (count) {
204                 set_current_state(TASK_INTERRUPTIBLE);
205
206                 /* Read frames from device queue */
207                 if (!(skb = skb_dequeue(&hci_vhci->readq))) {
208                         if (file->f_flags & O_NONBLOCK) {
209                                 ret = -EAGAIN;
210                                 break;
211                         }
212                         if (signal_pending(current)) {
213                                 ret = -ERESTARTSYS;
214                                 break;
215                         }
216
217                         /* Nothing to read, let's sleep */
218                         schedule();
219                         continue;
220                 }
221
222                 if (!verify_area(VERIFY_WRITE, buf, count))
223                         ret = hci_vhci_put_user(hci_vhci, skb, buf, count);
224                 else
225                         ret = -EFAULT;
226
227                 kfree_skb(skb);
228                 break;
229         }
230         set_current_state(TASK_RUNNING);
231         remove_wait_queue(&hci_vhci->read_wait, &wait);
232
233         return ret;
234 }
235
236 static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
237 {
238         return -ESPIPE;
239 }
240
241 static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
242 {
243         return -EINVAL;
244 }
245
246 static int hci_vhci_chr_fasync(int fd, struct file *file, int on)
247 {
248         struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
249         int ret;
250
251         if ((ret = fasync_helper(fd, file, on, &hci_vhci->fasync)) < 0)
252                 return ret; 
253  
254         if (on)
255                 hci_vhci->flags |= VHCI_FASYNC;
256         else 
257                 hci_vhci->flags &= ~VHCI_FASYNC;
258
259         return 0;
260 }
261
262 static int hci_vhci_chr_open(struct inode *inode, struct file * file)
263 {
264         struct hci_vhci_struct *hci_vhci = NULL; 
265         struct hci_dev *hdev;
266
267         if (!(hci_vhci = kmalloc(sizeof(struct hci_vhci_struct), GFP_KERNEL)))
268                 return -ENOMEM;
269
270         memset(hci_vhci, 0, sizeof(struct hci_vhci_struct));
271
272         skb_queue_head_init(&hci_vhci->readq);
273         init_waitqueue_head(&hci_vhci->read_wait);
274
275         /* Initialize and register HCI device */
276         hdev = &hci_vhci->hdev;
277
278         hdev->type = HCI_VHCI;
279         hdev->driver_data = hci_vhci;
280
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;
286
287         if (hci_register_dev(hdev) < 0) {
288                 kfree(hci_vhci);
289                 return -EBUSY;
290         }
291         MOD_INC_USE_COUNT;
292
293         file->private_data = hci_vhci;
294         return 0;   
295 }
296
297 static int hci_vhci_chr_close(struct inode *inode, struct file *file)
298 {
299         struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
300
301         if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
302                 BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
303         }
304
305         file->private_data = NULL;
306         return 0;
307 }
308
309 static struct file_operations hci_vhci_fops = {
310         owner:  THIS_MODULE,    
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             
319 };
320
321 static struct miscdevice hci_vhci_miscdev=
322 {
323         VHCI_MINOR,
324         "hci_vhci",
325         &hci_vhci_fops
326 };
327
328 int __init hci_vhci_init(void)
329 {
330         BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
331                 VERSION);
332         BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
333
334         if (misc_register(&hci_vhci_miscdev)) {
335                 BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
336                 return -EIO;
337         }
338
339         return 0;
340 }
341
342 void hci_vhci_cleanup(void)
343 {
344         misc_deregister(&hci_vhci_miscdev);
345 }
346
347 module_init(hci_vhci_init);
348 module_exit(hci_vhci_cleanup);
349
350 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
351 MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
352 MODULE_LICENSE("GPL");