tsif_chrdev.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /**
  2. * TSIF driver client
  3. *
  4. * Character device that, being read
  5. * returns stream of TSIF packets.
  6. *
  7. * Copyright (c) 2009-2011, The Linux Foundation. All rights
  8. * reserved.
  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 version 2 and
  12. * only version 2 as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. */
  19. #include <linux/module.h> /* Needed by all modules */
  20. #include <linux/kernel.h> /* Needed for KERN_INFO */
  21. #include <linux/cdev.h>
  22. #include <linux/err.h> /* IS_ERR etc. */
  23. #include <linux/fs.h>
  24. #include <linux/device.h>
  25. #include <linux/sched.h> /* TASK_INTERRUPTIBLE */
  26. #include <linux/uaccess.h> /* copy_to_user */
  27. #include <linux/tsif_api.h>
  28. struct tsif_chrdev {
  29. struct cdev cdev;
  30. struct device *dev;
  31. wait_queue_head_t wq_read;
  32. void *cookie;
  33. /* mirror for tsif data */
  34. void *data_buffer;
  35. unsigned buf_size_packets; /**< buffer size in packets */
  36. unsigned ri, wi;
  37. enum tsif_state state;
  38. unsigned rptr;
  39. };
  40. static ssize_t tsif_open(struct inode *inode, struct file *file)
  41. {
  42. int rc;
  43. struct tsif_chrdev *the_dev =
  44. container_of(inode->i_cdev, struct tsif_chrdev, cdev);
  45. if (!the_dev->cookie) /* not bound yet */
  46. return -ENODEV;
  47. file->private_data = the_dev;
  48. rc = tsif_start(the_dev->cookie);
  49. if (rc)
  50. return rc;
  51. tsif_get_info(the_dev->cookie, &the_dev->data_buffer,
  52. &the_dev->buf_size_packets);
  53. the_dev->rptr = 0;
  54. return nonseekable_open(inode, file);
  55. }
  56. static ssize_t tsif_release(struct inode *inode, struct file *filp)
  57. {
  58. struct tsif_chrdev *the_dev = filp->private_data;
  59. tsif_stop(the_dev->cookie);
  60. return 0;
  61. }
  62. static ssize_t tsif_read(struct file *filp, char __user *buf, size_t count,
  63. loff_t *f_pos)
  64. {
  65. int avail = 0;
  66. int wi;
  67. struct tsif_chrdev *the_dev = filp->private_data;
  68. tsif_get_state(the_dev->cookie, &the_dev->ri, &the_dev->wi,
  69. &the_dev->state);
  70. /* consistency check */
  71. if (the_dev->ri != (the_dev->rptr / TSIF_PKT_SIZE)) {
  72. dev_err(the_dev->dev,
  73. "%s: inconsistent read pointers: ri %d rptr %d\n",
  74. __func__, the_dev->ri, the_dev->rptr);
  75. the_dev->rptr = the_dev->ri * TSIF_PKT_SIZE;
  76. }
  77. /* ri == wi if no data */
  78. if (the_dev->ri == the_dev->wi) {
  79. /* shall I block waiting for data? */
  80. if (filp->f_flags & O_NONBLOCK) {
  81. if (the_dev->state == tsif_state_running) {
  82. return -EAGAIN;
  83. } else {
  84. /* not running -> EOF */
  85. return 0;
  86. }
  87. }
  88. if (wait_event_interruptible(the_dev->wq_read,
  89. (the_dev->ri != the_dev->wi) ||
  90. (the_dev->state != tsif_state_running))) {
  91. /* got signal -> tell FS to handle it */
  92. return -ERESTARTSYS;
  93. }
  94. if (the_dev->ri == the_dev->wi) {
  95. /* still no data -> EOF */
  96. return 0;
  97. }
  98. }
  99. /* contiguous chunk last up to wi or end of buffer */
  100. wi = (the_dev->wi > the_dev->ri) ?
  101. the_dev->wi : the_dev->buf_size_packets;
  102. avail = min(wi * TSIF_PKT_SIZE - the_dev->rptr, count);
  103. if (copy_to_user(buf, the_dev->data_buffer + the_dev->rptr, avail))
  104. return -EFAULT;
  105. the_dev->rptr = (the_dev->rptr + avail) %
  106. (TSIF_PKT_SIZE * the_dev->buf_size_packets);
  107. the_dev->ri = the_dev->rptr / TSIF_PKT_SIZE;
  108. *f_pos += avail;
  109. tsif_reclaim_packets(the_dev->cookie, the_dev->ri);
  110. return avail;
  111. }
  112. static void tsif_notify(void *data)
  113. {
  114. struct tsif_chrdev *the_dev = data;
  115. tsif_get_state(the_dev->cookie, &the_dev->ri, &the_dev->wi,
  116. &the_dev->state);
  117. wake_up_interruptible(&the_dev->wq_read);
  118. }
  119. static const struct file_operations tsif_fops = {
  120. .owner = THIS_MODULE,
  121. .read = tsif_read,
  122. .open = tsif_open,
  123. .release = tsif_release,
  124. };
  125. static struct class *tsif_class;
  126. static dev_t tsif_dev; /**< 1-st dev_t from allocated range */
  127. static dev_t tsif_dev0; /**< next not yet assigned dev_t */
  128. static int tsif_init_one(struct tsif_chrdev *the_dev, int index)
  129. {
  130. int rc;
  131. pr_info("%s[%d]\n", __func__, index);
  132. cdev_init(&the_dev->cdev, &tsif_fops);
  133. the_dev->cdev.owner = THIS_MODULE;
  134. init_waitqueue_head(&the_dev->wq_read);
  135. rc = cdev_add(&the_dev->cdev, tsif_dev0++, 1);
  136. the_dev->dev = device_create(tsif_class, NULL, the_dev->cdev.dev,
  137. the_dev, "tsif%d", index);
  138. if (IS_ERR(the_dev->dev)) {
  139. rc = PTR_ERR(the_dev->dev);
  140. pr_err("device_create failed: %d\n", rc);
  141. goto err_create;
  142. }
  143. the_dev->cookie = tsif_attach(index, tsif_notify, the_dev);
  144. if (IS_ERR(the_dev->cookie)) {
  145. rc = PTR_ERR(the_dev->cookie);
  146. pr_err("tsif_attach failed: %d\n", rc);
  147. goto err_attach;
  148. }
  149. /* now data buffer is not allocated yet */
  150. tsif_get_info(the_dev->cookie, &the_dev->data_buffer, NULL);
  151. dev_info(the_dev->dev,
  152. "Device %d.%d attached to TSIF, buffer size %d\n",
  153. MAJOR(the_dev->cdev.dev), MINOR(the_dev->cdev.dev),
  154. the_dev->buf_size_packets);
  155. return 0;
  156. err_attach:
  157. device_destroy(tsif_class, the_dev->cdev.dev);
  158. err_create:
  159. cdev_del(&the_dev->cdev);
  160. return rc;
  161. }
  162. static void tsif_exit_one(struct tsif_chrdev *the_dev)
  163. {
  164. dev_info(the_dev->dev, "%s\n", __func__);
  165. tsif_detach(the_dev->cookie);
  166. device_destroy(tsif_class, the_dev->cdev.dev);
  167. cdev_del(&the_dev->cdev);
  168. }
  169. #define TSIF_NUM_DEVS 1 /**< support this many devices */
  170. struct tsif_chrdev the_devices[TSIF_NUM_DEVS];
  171. static int __init mod_init(void)
  172. {
  173. int rc;
  174. int instance;
  175. rc = alloc_chrdev_region(&tsif_dev, 0, TSIF_NUM_DEVS, "tsif");
  176. if (rc) {
  177. pr_err("alloc_chrdev_region failed: %d\n", rc);
  178. goto err_devrgn;
  179. }
  180. tsif_dev0 = tsif_dev;
  181. tsif_class = class_create(THIS_MODULE, "tsif");
  182. if (IS_ERR(tsif_class)) {
  183. rc = PTR_ERR(tsif_class);
  184. pr_err("Error creating tsif class: %d\n", rc);
  185. goto err_class;
  186. }
  187. instance = tsif_get_active();
  188. if (instance >= 0)
  189. rc = tsif_init_one(&the_devices[0], instance);
  190. else
  191. rc = instance;
  192. if (rc)
  193. goto err_init1;
  194. return 0;
  195. err_init1:
  196. class_destroy(tsif_class);
  197. err_class:
  198. unregister_chrdev_region(tsif_dev, TSIF_NUM_DEVS);
  199. err_devrgn:
  200. return rc;
  201. }
  202. static void __exit mod_exit(void)
  203. {
  204. tsif_exit_one(&the_devices[0]);
  205. class_destroy(tsif_class);
  206. unregister_chrdev_region(tsif_dev, TSIF_NUM_DEVS);
  207. }
  208. module_init(mod_init);
  209. module_exit(mod_exit);
  210. MODULE_DESCRIPTION("TSIF character device interface");
  211. MODULE_LICENSE("GPL v2");