OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [bluetooth/] [hci_vhci.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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.1.1.1 2004-04-15 02:29:43 phoenix 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");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.