hci_vhci.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* 
  2.    BlueZ - Bluetooth protocol stack for Linux
  3.    Copyright (C) 2000-2001 Qualcomm Incorporated
  4.    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License version 2 as
  7.    published by the Free Software Foundation;
  8.    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  9.    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  10.    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
  11.    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
  12.    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
  13.    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
  14.    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
  15.    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16.    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
  17.    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
  18.    SOFTWARE IS DISCLAIMED.
  19. */
  20. /*
  21.  * BlueZ HCI virtual device driver.
  22.  *
  23.  * $Id: hci_vhci.c,v 1.3 2001/08/03 04:19:50 maxk Exp $ 
  24.  */
  25. #define VERSION "1.0"
  26. #include <linux/config.h>
  27. #include <linux/module.h>
  28. #include <linux/errno.h>
  29. #include <linux/kernel.h>
  30. #include <linux/major.h>
  31. #include <linux/sched.h>
  32. #include <linux/slab.h>
  33. #include <linux/poll.h>
  34. #include <linux/fcntl.h>
  35. #include <linux/init.h>
  36. #include <linux/random.h>
  37. #include <linux/skbuff.h>
  38. #include <linux/miscdevice.h>
  39. #include <asm/system.h>
  40. #include <asm/uaccess.h>
  41. #include <net/bluetooth/bluetooth.h>
  42. #include <net/bluetooth/bluez.h>
  43. #include <net/bluetooth/hci_core.h>
  44. #include <net/bluetooth/hci_vhci.h>
  45. /* HCI device part */
  46. int hci_vhci_open(struct hci_dev *hdev)
  47. {
  48. hdev->flags |= HCI_RUNNING;
  49. return 0;
  50. }
  51. int hci_vhci_flush(struct hci_dev *hdev)
  52. {
  53. struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
  54. skb_queue_purge(&hci_vhci->readq);
  55. return 0;
  56. }
  57. int hci_vhci_close(struct hci_dev *hdev)
  58. {
  59. hdev->flags &= ~HCI_RUNNING;
  60. hci_vhci_flush(hdev);
  61. return 0;
  62. }
  63. int hci_vhci_send_frame(struct sk_buff *skb)
  64. {
  65. struct hci_dev* hdev = (struct hci_dev *) skb->dev;
  66. struct hci_vhci_struct *hci_vhci;
  67. if (!hdev) {
  68. ERR("Frame for uknown device (hdev=NULL)");
  69. return -ENODEV;
  70. }
  71. if (!(hdev->flags & HCI_RUNNING))
  72. return -EBUSY;
  73. hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
  74. memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
  75. skb_queue_tail(&hci_vhci->readq, skb);
  76. if (hci_vhci->flags & VHCI_FASYNC)
  77. kill_fasync(&hci_vhci->fasync, SIGIO, POLL_IN);
  78. wake_up_interruptible(&hci_vhci->read_wait);
  79. return 0;
  80. }
  81. /* Character device part */
  82. /* Poll */
  83. static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait)
  84. {  
  85. struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
  86. poll_wait(file, &hci_vhci->read_wait, wait);
  87.  
  88. if (skb_queue_len(&hci_vhci->readq))
  89. return POLLIN | POLLRDNORM;
  90. return POLLOUT | POLLWRNORM;
  91. }
  92. /* Get packet from user space buffer(already verified) */
  93. static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const char *buf, size_t count)
  94. {
  95. struct sk_buff *skb;
  96. if (count > HCI_MAX_FRAME_SIZE)
  97. return -EINVAL;
  98. if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
  99. return -ENOMEM;
  100. copy_from_user(skb_put(skb, count), buf, count); 
  101. skb->dev = (void *) &hci_vhci->hdev;
  102. skb->pkt_type = *((__u8 *) skb->data);
  103. skb_pull(skb, 1);
  104. hci_recv_frame(skb);
  105. return count;
  106. /* Write */
  107. static ssize_t hci_vhci_chr_write(struct file * file, const char * buf, 
  108.      size_t count, loff_t *pos)
  109. {
  110. struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
  111. if (verify_area(VERIFY_READ, buf, count))
  112. return -EFAULT;
  113. return hci_vhci_get_user(hci_vhci, buf, count);
  114. }
  115. /* Put packet to user space buffer(already verified) */
  116. static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci,
  117.        struct sk_buff *skb, char *buf, int count)
  118. {
  119. int len = count, total = 0;
  120. char *ptr = buf;
  121. len = MIN(skb->len, len); 
  122. copy_to_user(ptr, skb->data, len); 
  123. total += len;
  124. hci_vhci->hdev.stat.byte_tx += len;
  125. switch (skb->pkt_type) {
  126. case HCI_COMMAND_PKT:
  127. hci_vhci->hdev.stat.cmd_tx++;
  128. break;
  129. case HCI_ACLDATA_PKT:
  130. hci_vhci->hdev.stat.acl_tx++;
  131. break;
  132. case HCI_SCODATA_PKT:
  133. hci_vhci->hdev.stat.cmd_tx++;
  134. break;
  135. };
  136. return total;
  137. }
  138. /* Read */
  139. static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, loff_t *pos)
  140. {
  141. struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
  142. DECLARE_WAITQUEUE(wait, current);
  143. struct sk_buff *skb;
  144. ssize_t ret = 0;
  145. add_wait_queue(&hci_vhci->read_wait, &wait);
  146. while (count) {
  147. current->state = TASK_INTERRUPTIBLE;
  148. /* Read frames from device queue */
  149. if (!(skb = skb_dequeue(&hci_vhci->readq))) {
  150. if (file->f_flags & O_NONBLOCK) {
  151. ret = -EAGAIN;
  152. break;
  153. }
  154. if (signal_pending(current)) {
  155. ret = -ERESTARTSYS;
  156. break;
  157. }
  158. /* Nothing to read, let's sleep */
  159. schedule();
  160. continue;
  161. }
  162. if (!verify_area(VERIFY_WRITE, buf, count))
  163. ret = hci_vhci_put_user(hci_vhci, skb, buf, count);
  164. else
  165. ret = -EFAULT;
  166. kfree_skb(skb);
  167. break;
  168. }
  169. current->state = TASK_RUNNING;
  170. remove_wait_queue(&hci_vhci->read_wait, &wait);
  171. return ret;
  172. }
  173. static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
  174. {
  175. return -ESPIPE;
  176. }
  177. static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  178. {
  179. return -EINVAL;
  180. }
  181. static int hci_vhci_chr_fasync(int fd, struct file *file, int on)
  182. {
  183. struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
  184. int ret;
  185. if ((ret = fasync_helper(fd, file, on, &hci_vhci->fasync)) < 0)
  186. return ret; 
  187.  
  188. if (on)
  189. hci_vhci->flags |= VHCI_FASYNC;
  190. else 
  191. hci_vhci->flags &= ~VHCI_FASYNC;
  192. return 0;
  193. }
  194. static int hci_vhci_chr_open(struct inode *inode, struct file * file)
  195. {
  196. struct hci_vhci_struct *hci_vhci = NULL; 
  197. struct hci_dev *hdev;
  198. if (!(hci_vhci = kmalloc(sizeof(struct hci_vhci_struct), GFP_KERNEL)))
  199. return -ENOMEM;
  200. memset(hci_vhci, 0, sizeof(struct hci_vhci_struct));
  201. skb_queue_head_init(&hci_vhci->readq);
  202. init_waitqueue_head(&hci_vhci->read_wait);
  203. /* Initialize and register HCI device */
  204. hdev = &hci_vhci->hdev;
  205. hdev->type = HCI_VHCI;
  206. hdev->driver_data = hci_vhci;
  207. hdev->open  = hci_vhci_open;
  208. hdev->close = hci_vhci_close;
  209. hdev->flush = hci_vhci_flush;
  210. hdev->send  = hci_vhci_send_frame;
  211. if (hci_register_dev(hdev) < 0) {
  212. kfree(hci_vhci);
  213. return -EBUSY;
  214. }
  215. file->private_data = hci_vhci;
  216. return 0;   
  217. }
  218. static int hci_vhci_chr_close(struct inode *inode, struct file *file)
  219. {
  220. struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
  221. if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
  222. ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
  223. }
  224. kfree(hci_vhci);
  225. file->private_data = NULL;
  226. return 0;
  227. }
  228. static struct file_operations hci_vhci_fops = {
  229. owner: THIS_MODULE,
  230. llseek: hci_vhci_chr_lseek,
  231. read: hci_vhci_chr_read,
  232. write: hci_vhci_chr_write,
  233. poll: hci_vhci_chr_poll,
  234. ioctl: hci_vhci_chr_ioctl,
  235. open: hci_vhci_chr_open,
  236. release:hci_vhci_chr_close,
  237. fasync: hci_vhci_chr_fasync
  238. };
  239. static struct miscdevice hci_vhci_miscdev=
  240. {
  241.         VHCI_MINOR,
  242.         "hci_vhci",
  243.         &hci_vhci_fops
  244. };
  245. int __init hci_vhci_init(void)
  246. {
  247. INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
  248. VERSION);
  249. INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
  250. if (misc_register(&hci_vhci_miscdev)) {
  251. ERR("Can't register misc device %dn", VHCI_MINOR);
  252. return -EIO;
  253. }
  254. return 0;
  255. }
  256. void hci_vhci_cleanup(void)
  257. {
  258. misc_deregister(&hci_vhci_miscdev);
  259. }
  260. module_init(hci_vhci_init);
  261. module_exit(hci_vhci_cleanup);
  262. MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
  263. MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
  264. MODULE_LICENSE("GPL");