v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / drivers / bluetooth / hci_emu.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_emu.c,v 1.1 2001/06/01 08:12:10 davem Exp $ 
29  */
30
31 #include <linux/config.h>
32 #include <linux/module.h>
33
34 #include <linux/errno.h>
35 #include <linux/kernel.h>
36 #include <linux/major.h>
37 #include <linux/sched.h>
38 #include <linux/slab.h>
39 #include <linux/poll.h>
40 #include <linux/fcntl.h>
41 #include <linux/init.h>
42 #include <linux/random.h>
43
44 #include <linux/skbuff.h>
45 #include <linux/miscdevice.h>
46
47 #include <asm/system.h>
48 #include <asm/uaccess.h>
49
50 #include <net/bluetooth/bluetooth.h>
51 #include <net/bluetooth/bluez.h>
52 #include <net/bluetooth/hci_core.h>
53 #include <net/bluetooth/hci_emu.h>
54
55 /* HCI device part */
56
57 int hci_emu_open(struct hci_dev *hdev)
58 {
59         hdev->flags |= HCI_RUNNING;
60         return 0;
61 }
62
63 int hci_emu_flush(struct hci_dev *hdev)
64 {
65         struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) hdev->driver_data;
66         bluez_skb_queue_purge(&hci_emu->readq);
67         return 0;
68 }
69
70 int hci_emu_close(struct hci_dev *hdev)
71 {
72         hdev->flags &= ~HCI_RUNNING;
73         hci_emu_flush(hdev);
74         return 0;
75 }
76
77 int hci_emu_send_frame(struct sk_buff *skb)
78 {
79         struct hci_dev* hdev = (struct hci_dev *) skb->dev;
80         struct hci_emu_struct *hci_emu;
81
82         if (!hdev) {
83                 ERR("Frame for uknown device (hdev=NULL)");
84                 return -ENODEV;
85         }
86
87         if (!(hdev->flags & HCI_RUNNING))
88                 return -EBUSY;
89
90         hci_emu = (struct hci_emu_struct *) hdev->driver_data;
91
92         memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
93         skb_queue_tail(&hci_emu->readq, skb);
94
95         if (hci_emu->flags & HCI_EMU_FASYNC)
96                 kill_fasync(&hci_emu->fasync, SIGIO, POLL_IN);
97         wake_up_interruptible(&hci_emu->read_wait);
98
99         return 0;
100 }
101
102 /* Character device part */
103
104 /* Poll */
105 static unsigned int hci_emu_chr_poll(struct file *file, poll_table * wait)
106 {  
107         struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
108
109         poll_wait(file, &hci_emu->read_wait, wait);
110  
111         if (skb_queue_len(&hci_emu->readq))
112                 return POLLIN | POLLRDNORM;
113
114         return POLLOUT | POLLWRNORM;
115 }
116
117 /* Get packet from user space buffer(already verified) */
118 static __inline__ ssize_t hci_emu_get_user(struct hci_emu_struct *hci_emu, const char *buf, size_t count)
119 {
120         struct sk_buff *skb;
121
122         if (count > HCI_EMU_MAX_FRAME)
123                 return -EINVAL;
124
125         if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
126                 return -ENOMEM;
127         
128         copy_from_user(skb_put(skb, count), buf, count); 
129
130         skb->dev = (void *) &hci_emu->hdev;
131         skb->pkt_type = *((__u8 *) skb->data);
132         skb_pull(skb, 1);
133
134         hci_recv_frame(skb);
135
136         return count;
137
138
139 /* Write */
140 static ssize_t hci_emu_chr_write(struct file * file, const char * buf, 
141                              size_t count, loff_t *pos)
142 {
143         struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
144
145         if (verify_area(VERIFY_READ, buf, count))
146                 return -EFAULT;
147
148         return hci_emu_get_user(hci_emu, buf, count);
149 }
150
151 /* Put packet to user space buffer(already verified) */
152 static __inline__ ssize_t hci_emu_put_user(struct hci_emu_struct *hci_emu,
153                                        struct sk_buff *skb, char *buf, int count)
154 {
155         int len = count, total = 0;
156         char *ptr = buf;
157
158         len = MIN(skb->len, len); 
159         copy_to_user(ptr, skb->data, len); 
160         total += len;
161
162         hci_emu->hdev.stat.byte_tx += len;
163         switch (skb->pkt_type) {
164                 case HCI_COMMAND_PKT:
165                         hci_emu->hdev.stat.cmd_tx++;
166                         break;
167
168                 case HCI_ACLDATA_PKT:
169                         hci_emu->hdev.stat.acl_tx++;
170                         break;
171
172                 case HCI_SCODATA_PKT:
173                         hci_emu->hdev.stat.cmd_tx++;
174                         break;
175         };
176
177         return total;
178 }
179
180 /* Read */
181 static ssize_t hci_emu_chr_read(struct file * file, char * buf, size_t count, loff_t *pos)
182 {
183         struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
184         DECLARE_WAITQUEUE(wait, current);
185         struct sk_buff *skb;
186         ssize_t ret = 0;
187
188         add_wait_queue(&hci_emu->read_wait, &wait);
189         while (count) {
190                 current->state = TASK_INTERRUPTIBLE;
191
192                 /* Read frames from device queue */
193                 if (!(skb = skb_dequeue(&hci_emu->readq))) {
194                         if (file->f_flags & O_NONBLOCK) {
195                                 ret = -EAGAIN;
196                                 break;
197                         }
198                         if (signal_pending(current)) {
199                                 ret = -ERESTARTSYS;
200                                 break;
201                         }
202
203                         /* Nothing to read, let's sleep */
204                         schedule();
205                         continue;
206                 }
207
208                 if (!verify_area(VERIFY_WRITE, buf, count))
209                         ret = hci_emu_put_user(hci_emu, skb, buf, count);
210                 else
211                         ret = -EFAULT;
212
213                 bluez_skb_free(skb);
214                 break;
215         }
216
217         current->state = TASK_RUNNING;
218         remove_wait_queue(&hci_emu->read_wait, &wait);
219
220         return ret;
221 }
222
223 static int hci_emu_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
224 {
225         return -EINVAL;
226 }
227
228 static int hci_emu_chr_fasync(int fd, struct file *file, int on)
229 {
230         struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
231         int ret;
232
233         if ((ret = fasync_helper(fd, file, on, &hci_emu->fasync)) < 0)
234                 return ret; 
235  
236         if (on)
237                 hci_emu->flags |= HCI_EMU_FASYNC;
238         else 
239                 hci_emu->flags &= ~HCI_EMU_FASYNC;
240
241         return 0;
242 }
243
244 static int hci_emu_chr_open(struct inode *inode, struct file * file)
245 {
246         struct hci_emu_struct *hci_emu = NULL; 
247         struct hci_dev *hdev;
248
249         if (!(hci_emu = kmalloc(sizeof(struct hci_emu_struct), GFP_KERNEL)))
250                 return -ENOMEM;
251
252         memset(hci_emu, 0, sizeof(struct hci_emu_struct));
253
254         skb_queue_head_init(&hci_emu->readq);
255         init_waitqueue_head(&hci_emu->read_wait);
256
257         /* Initialize and register HCI device */
258         hdev = &hci_emu->hdev;
259
260         hdev->type = HCI_EMU;
261         hdev->driver_data = hci_emu;
262
263         hdev->open  = hci_emu_open;
264         hdev->close = hci_emu_close;
265         hdev->flush = hci_emu_flush;
266         hdev->send  = hci_emu_send_frame;
267
268         if (hci_register_dev(hdev) < 0) {
269                 kfree(hci_emu);
270                 return -EBUSY;
271         }
272
273         file->private_data = hci_emu;
274         return 0;   
275 }
276
277 static int hci_emu_chr_close(struct inode *inode, struct file *file)
278 {
279         struct hci_emu_struct *hci_emu = (struct hci_emu_struct *) file->private_data;
280
281         if (hci_unregister_dev(&hci_emu->hdev) < 0) {
282                 ERR("Can't unregister HCI device %s", hci_emu->hdev.name);
283         }
284
285         kfree(hci_emu);
286         file->private_data = NULL;
287
288         return 0;
289 }
290
291 static struct file_operations hci_emu_fops = {
292         owner:  THIS_MODULE,    
293         llseek: no_llseek,
294         read:   hci_emu_chr_read,
295         write:  hci_emu_chr_write,
296         poll:   hci_emu_chr_poll,
297         ioctl:  hci_emu_chr_ioctl,
298         open:   hci_emu_chr_open,
299         release:hci_emu_chr_close,
300         fasync: hci_emu_chr_fasync              
301 };
302
303 static struct miscdevice hci_emu_miscdev=
304 {
305         HCI_EMU_MINOR,
306         "hci_emu",
307         &hci_emu_fops
308 };
309
310 int __init hci_emu_init(void)
311 {
312         INF("BlueZ HCI EMU driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
313                 BLUEZ_VER);
314         INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
315
316         if (misc_register(&hci_emu_miscdev)) {
317                 ERR("Can't register misc device %d\n", HCI_EMU_MINOR);
318                 return -EIO;
319         }
320
321         return 0;
322 }
323
324 void hci_emu_cleanup(void)
325 {
326         misc_deregister(&hci_emu_miscdev);
327 }
328
329 module_init(hci_emu_init);
330 module_exit(hci_emu_cleanup);