diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/bluetooth/hci_vhci.c | 90 |
1 files changed, 19 insertions, 71 deletions
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0bbefba6469c..1df9dda2e377 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include <net/bluetooth/bluetooth.h> | 40 | #include <net/bluetooth/bluetooth.h> |
41 | #include <net/bluetooth/hci_core.h> | 41 | #include <net/bluetooth/hci_core.h> |
42 | 42 | ||
43 | #define VERSION "1.2" | 43 | #define VERSION "1.3" |
44 | 44 | ||
45 | static int minor = MISC_DYNAMIC_MINOR; | 45 | static int minor = MISC_DYNAMIC_MINOR; |
46 | 46 | ||
@@ -51,14 +51,8 @@ struct vhci_data { | |||
51 | 51 | ||
52 | wait_queue_head_t read_wait; | 52 | wait_queue_head_t read_wait; |
53 | struct sk_buff_head readq; | 53 | struct sk_buff_head readq; |
54 | |||
55 | struct fasync_struct *fasync; | ||
56 | }; | 54 | }; |
57 | 55 | ||
58 | #define VHCI_FASYNC 0x0010 | ||
59 | |||
60 | static struct miscdevice vhci_miscdev; | ||
61 | |||
62 | static int vhci_open_dev(struct hci_dev *hdev) | 56 | static int vhci_open_dev(struct hci_dev *hdev) |
63 | { | 57 | { |
64 | set_bit(HCI_RUNNING, &hdev->flags); | 58 | set_bit(HCI_RUNNING, &hdev->flags); |
@@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb) | |||
105 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); | 99 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); |
106 | skb_queue_tail(&data->readq, skb); | 100 | skb_queue_tail(&data->readq, skb); |
107 | 101 | ||
108 | if (data->flags & VHCI_FASYNC) | ||
109 | kill_fasync(&data->fasync, SIGIO, POLL_IN); | ||
110 | |||
111 | wake_up_interruptible(&data->read_wait); | 102 | wake_up_interruptible(&data->read_wait); |
112 | 103 | ||
113 | return 0; | 104 | return 0; |
@@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, | |||
179 | static ssize_t vhci_read(struct file *file, | 170 | static ssize_t vhci_read(struct file *file, |
180 | char __user *buf, size_t count, loff_t *pos) | 171 | char __user *buf, size_t count, loff_t *pos) |
181 | { | 172 | { |
182 | DECLARE_WAITQUEUE(wait, current); | ||
183 | struct vhci_data *data = file->private_data; | 173 | struct vhci_data *data = file->private_data; |
184 | struct sk_buff *skb; | 174 | struct sk_buff *skb; |
185 | ssize_t ret = 0; | 175 | ssize_t ret = 0; |
186 | 176 | ||
187 | add_wait_queue(&data->read_wait, &wait); | ||
188 | while (count) { | 177 | while (count) { |
189 | set_current_state(TASK_INTERRUPTIBLE); | ||
190 | |||
191 | skb = skb_dequeue(&data->readq); | 178 | skb = skb_dequeue(&data->readq); |
192 | if (!skb) { | 179 | if (skb) { |
193 | if (file->f_flags & O_NONBLOCK) { | 180 | ret = vhci_put_user(data, skb, buf, count); |
194 | ret = -EAGAIN; | 181 | if (ret < 0) |
195 | break; | 182 | skb_queue_head(&data->readq, skb); |
196 | } | 183 | else |
197 | 184 | kfree_skb(skb); | |
198 | if (signal_pending(current)) { | 185 | break; |
199 | ret = -ERESTARTSYS; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | schedule(); | ||
204 | continue; | ||
205 | } | 186 | } |
206 | 187 | ||
207 | if (access_ok(VERIFY_WRITE, buf, count)) | 188 | if (file->f_flags & O_NONBLOCK) { |
208 | ret = vhci_put_user(data, skb, buf, count); | 189 | ret = -EAGAIN; |
209 | else | 190 | break; |
210 | ret = -EFAULT; | 191 | } |
211 | 192 | ||
212 | kfree_skb(skb); | 193 | ret = wait_event_interruptible(data->read_wait, |
213 | break; | 194 | !skb_queue_empty(&data->readq)); |
195 | if (ret < 0) | ||
196 | break; | ||
214 | } | 197 | } |
215 | set_current_state(TASK_RUNNING); | ||
216 | remove_wait_queue(&data->read_wait, &wait); | ||
217 | 198 | ||
218 | return ret; | 199 | return ret; |
219 | } | 200 | } |
@@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file, | |||
223 | { | 204 | { |
224 | struct vhci_data *data = file->private_data; | 205 | struct vhci_data *data = file->private_data; |
225 | 206 | ||
226 | if (!access_ok(VERIFY_READ, buf, count)) | ||
227 | return -EFAULT; | ||
228 | |||
229 | return vhci_get_user(data, buf, count); | 207 | return vhci_get_user(data, buf, count); |
230 | } | 208 | } |
231 | 209 | ||
@@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file) | |||
259 | skb_queue_head_init(&data->readq); | 237 | skb_queue_head_init(&data->readq); |
260 | init_waitqueue_head(&data->read_wait); | 238 | init_waitqueue_head(&data->read_wait); |
261 | 239 | ||
262 | lock_kernel(); | ||
263 | hdev = hci_alloc_dev(); | 240 | hdev = hci_alloc_dev(); |
264 | if (!hdev) { | 241 | if (!hdev) { |
265 | kfree(data); | 242 | kfree(data); |
266 | unlock_kernel(); | ||
267 | return -ENOMEM; | 243 | return -ENOMEM; |
268 | } | 244 | } |
269 | 245 | ||
@@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file) | |||
284 | BT_ERR("Can't register HCI device"); | 260 | BT_ERR("Can't register HCI device"); |
285 | kfree(data); | 261 | kfree(data); |
286 | hci_free_dev(hdev); | 262 | hci_free_dev(hdev); |
287 | unlock_kernel(); | ||
288 | return -EBUSY; | 263 | return -EBUSY; |
289 | } | 264 | } |
290 | 265 | ||
291 | file->private_data = data; | 266 | file->private_data = data; |
292 | unlock_kernel(); | ||
293 | 267 | ||
294 | return nonseekable_open(inode, file); | 268 | return nonseekable_open(inode, file); |
295 | } | 269 | } |
@@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file) | |||
310 | return 0; | 284 | return 0; |
311 | } | 285 | } |
312 | 286 | ||
313 | static int vhci_fasync(int fd, struct file *file, int on) | ||
314 | { | ||
315 | struct vhci_data *data = file->private_data; | ||
316 | int err = 0; | ||
317 | |||
318 | lock_kernel(); | ||
319 | err = fasync_helper(fd, file, on, &data->fasync); | ||
320 | if (err < 0) | ||
321 | goto out; | ||
322 | |||
323 | if (on) | ||
324 | data->flags |= VHCI_FASYNC; | ||
325 | else | ||
326 | data->flags &= ~VHCI_FASYNC; | ||
327 | |||
328 | out: | ||
329 | unlock_kernel(); | ||
330 | return err; | ||
331 | } | ||
332 | |||
333 | static const struct file_operations vhci_fops = { | 287 | static const struct file_operations vhci_fops = { |
334 | .owner = THIS_MODULE, | ||
335 | .read = vhci_read, | 288 | .read = vhci_read, |
336 | .write = vhci_write, | 289 | .write = vhci_write, |
337 | .poll = vhci_poll, | 290 | .poll = vhci_poll, |
338 | .ioctl = vhci_ioctl, | 291 | .ioctl = vhci_ioctl, |
339 | .open = vhci_open, | 292 | .open = vhci_open, |
340 | .release = vhci_release, | 293 | .release = vhci_release, |
341 | .fasync = vhci_fasync, | ||
342 | }; | 294 | }; |
343 | 295 | ||
344 | static struct miscdevice vhci_miscdev= { | 296 | static struct miscdevice vhci_miscdev= { |
345 | .name = "vhci", | 297 | .name = "vhci", |
346 | .fops = &vhci_fops, | 298 | .fops = &vhci_fops, |
299 | .minor = MISC_DYNAMIC_MINOR, | ||
347 | }; | 300 | }; |
348 | 301 | ||
349 | static int __init vhci_init(void) | 302 | static int __init vhci_init(void) |
350 | { | 303 | { |
351 | BT_INFO("Virtual HCI driver ver %s", VERSION); | 304 | BT_INFO("Virtual HCI driver ver %s", VERSION); |
352 | 305 | ||
353 | vhci_miscdev.minor = minor; | ||
354 | |||
355 | if (misc_register(&vhci_miscdev) < 0) { | 306 | if (misc_register(&vhci_miscdev) < 0) { |
356 | BT_ERR("Can't register misc device with minor %d", minor); | 307 | BT_ERR("Can't register misc device with minor %d", minor); |
357 | return -EIO; | 308 | return -EIO; |
@@ -369,9 +320,6 @@ static void __exit vhci_exit(void) | |||
369 | module_init(vhci_init); | 320 | module_init(vhci_init); |
370 | module_exit(vhci_exit); | 321 | module_exit(vhci_exit); |
371 | 322 | ||
372 | module_param(minor, int, 0444); | ||
373 | MODULE_PARM_DESC(minor, "Miscellaneous minor device number"); | ||
374 | |||
375 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | 323 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); |
376 | MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); | 324 | MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); |
377 | MODULE_VERSION(VERSION); | 325 | MODULE_VERSION(VERSION); |