~ubuntu-branches/ubuntu/trusty/linux-backports-modules-3.2.0/trusty

« back to all changes in this revision

Viewing changes to updates/cw-3.3/drivers/bluetooth/hci_vhci.c

  • Committer: Package Import Robot
  • Author(s): Leann Ogasawara
  • Date: 2012-02-15 08:42:08 UTC
  • Revision ID: package-import@ubuntu.com-20120215084208-2gcs2zosufz014pi
Tags: 3.2.0-18.1
* Open Precise LBM
* Add compat-wireless v3.3
* Consolidated amd64 server flavour into generic
* Remove lpia control file
* Update Vcs-Git to ubuntu-preicse-lbm

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 = hdev->driver_data;
 
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 = hdev->driver_data;
 
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 = hdev->driver_data;
 
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 void vhci_destruct(struct hci_dev *hdev)
 
107
{
 
108
        kfree(hdev->driver_data);
 
109
}
 
110
 
 
111
static inline ssize_t vhci_get_user(struct vhci_data *data,
 
112
                                        const char __user *buf, size_t count)
 
113
{
 
114
        struct sk_buff *skb;
 
115
 
 
116
        if (count > HCI_MAX_FRAME_SIZE)
 
117
                return -EINVAL;
 
118
 
 
119
        skb = bt_skb_alloc(count, GFP_KERNEL);
 
120
        if (!skb)
 
121
                return -ENOMEM;
 
122
 
 
123
        if (copy_from_user(skb_put(skb, count), buf, count)) {
 
124
                kfree_skb(skb);
 
125
                return -EFAULT;
 
126
        }
 
127
 
 
128
        skb->dev = (void *) data->hdev;
 
129
        bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
 
130
        skb_pull(skb, 1);
 
131
 
 
132
        hci_recv_frame(skb);
 
133
 
 
134
        return count;
 
135
}
 
136
 
 
137
static inline ssize_t vhci_put_user(struct vhci_data *data,
 
138
                        struct sk_buff *skb, char __user *buf, int count)
 
139
{
 
140
        char __user *ptr = buf;
 
141
        int len, total = 0;
 
142
 
 
143
        len = min_t(unsigned int, skb->len, count);
 
144
 
 
145
        if (copy_to_user(ptr, skb->data, len))
 
146
                return -EFAULT;
 
147
 
 
148
        total += len;
 
149
 
 
150
        data->hdev->stat.byte_tx += len;
 
151
 
 
152
        switch (bt_cb(skb)->pkt_type) {
 
153
        case HCI_COMMAND_PKT:
 
154
                data->hdev->stat.cmd_tx++;
 
155
                break;
 
156
 
 
157
        case HCI_ACLDATA_PKT:
 
158
                data->hdev->stat.acl_tx++;
 
159
                break;
 
160
 
 
161
        case HCI_SCODATA_PKT:
 
162
                data->hdev->stat.sco_tx++;
 
163
                break;
 
164
        };
 
165
 
 
166
        return total;
 
167
}
 
168
 
 
169
static ssize_t vhci_read(struct file *file,
 
170
                                char __user *buf, size_t count, loff_t *pos)
 
171
{
 
172
        struct vhci_data *data = file->private_data;
 
173
        struct sk_buff *skb;
 
174
        ssize_t ret = 0;
 
175
 
 
176
        while (count) {
 
177
                skb = skb_dequeue(&data->readq);
 
178
                if (skb) {
 
179
                        ret = vhci_put_user(data, skb, buf, count);
 
180
                        if (ret < 0)
 
181
                                skb_queue_head(&data->readq, skb);
 
182
                        else
 
183
                                kfree_skb(skb);
 
184
                        break;
 
185
                }
 
186
 
 
187
                if (file->f_flags & O_NONBLOCK) {
 
188
                        ret = -EAGAIN;
 
189
                        break;
 
190
                }
 
191
 
 
192
                ret = wait_event_interruptible(data->read_wait,
 
193
                                        !skb_queue_empty(&data->readq));
 
194
                if (ret < 0)
 
195
                        break;
 
196
        }
 
197
 
 
198
        return ret;
 
199
}
 
200
 
 
201
static ssize_t vhci_write(struct file *file,
 
202
                        const char __user *buf, size_t count, loff_t *pos)
 
203
{
 
204
        struct vhci_data *data = file->private_data;
 
205
 
 
206
        return vhci_get_user(data, buf, count);
 
207
}
 
208
 
 
209
static unsigned int vhci_poll(struct file *file, poll_table *wait)
 
210
{
 
211
        struct vhci_data *data = file->private_data;
 
212
 
 
213
        poll_wait(file, &data->read_wait, wait);
 
214
 
 
215
        if (!skb_queue_empty(&data->readq))
 
216
                return POLLIN | POLLRDNORM;
 
217
 
 
218
        return POLLOUT | POLLWRNORM;
 
219
}
 
220
 
 
221
static int vhci_open(struct inode *inode, struct file *file)
 
222
{
 
223
        struct vhci_data *data;
 
224
        struct hci_dev *hdev;
 
225
 
 
226
        data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
 
227
        if (!data)
 
228
                return -ENOMEM;
 
229
 
 
230
        skb_queue_head_init(&data->readq);
 
231
        init_waitqueue_head(&data->read_wait);
 
232
 
 
233
        hdev = hci_alloc_dev();
 
234
        if (!hdev) {
 
235
                kfree(data);
 
236
                return -ENOMEM;
 
237
        }
 
238
 
 
239
        data->hdev = hdev;
 
240
 
 
241
        hdev->bus = HCI_VIRTUAL;
 
242
        hdev->driver_data = data;
 
243
 
 
244
        if (amp)
 
245
                hdev->dev_type = HCI_AMP;
 
246
 
 
247
        hdev->open     = vhci_open_dev;
 
248
        hdev->close    = vhci_close_dev;
 
249
        hdev->flush    = vhci_flush;
 
250
        hdev->send     = vhci_send_frame;
 
251
        hdev->destruct = vhci_destruct;
 
252
 
 
253
        hdev->owner = THIS_MODULE;
 
254
 
 
255
        if (hci_register_dev(hdev) < 0) {
 
256
                BT_ERR("Can't register HCI device");
 
257
                kfree(data);
 
258
                hci_free_dev(hdev);
 
259
                return -EBUSY;
 
260
        }
 
261
 
 
262
        file->private_data = data;
 
263
 
 
264
        return nonseekable_open(inode, file);
 
265
}
 
266
 
 
267
static int vhci_release(struct inode *inode, struct file *file)
 
268
{
 
269
        struct vhci_data *data = file->private_data;
 
270
        struct hci_dev *hdev = data->hdev;
 
271
 
 
272
        hci_unregister_dev(hdev);
 
273
        hci_free_dev(hdev);
 
274
 
 
275
        file->private_data = NULL;
 
276
 
 
277
        return 0;
 
278
}
 
279
 
 
280
static const struct file_operations vhci_fops = {
 
281
        .owner          = THIS_MODULE,
 
282
        .read           = vhci_read,
 
283
        .write          = vhci_write,
 
284
        .poll           = vhci_poll,
 
285
        .open           = vhci_open,
 
286
        .release        = vhci_release,
 
287
        .llseek         = no_llseek,
 
288
};
 
289
 
 
290
static struct miscdevice vhci_miscdev= {
 
291
        .name   = "vhci",
 
292
        .fops   = &vhci_fops,
 
293
        .minor  = MISC_DYNAMIC_MINOR,
 
294
};
 
295
 
 
296
static int __init vhci_init(void)
 
297
{
 
298
        BT_INFO("Virtual HCI driver ver %s", VERSION);
 
299
 
 
300
        return misc_register(&vhci_miscdev);
 
301
}
 
302
 
 
303
static void __exit vhci_exit(void)
 
304
{
 
305
        misc_deregister(&vhci_miscdev);
 
306
}
 
307
 
 
308
module_init(vhci_init);
 
309
module_exit(vhci_exit);
 
310
 
 
311
module_param(amp, bool, 0644);
 
312
MODULE_PARM_DESC(amp, "Create AMP controller device");
 
313
 
 
314
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 
315
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
 
316
MODULE_VERSION(VERSION);
 
317
MODULE_LICENSE("GPL");