tapi-control.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include <linux/cdev.h>
  2. #include <linux/device.h>
  3. #include <linux/fs.h>
  4. #include <linux/list.h>
  5. #include <linux/kernel.h>
  6. #include <linux/module.h>
  7. #include <linux/slab.h>
  8. #include <linux/tapi/tapi.h>
  9. #include <linux/tapi/tapi-ioctl.h>
  10. /* FIXME Does it acutally make sense to allow more then one application at a
  11. * time to open the control device? For example calling sync from one app will
  12. * also sync all others. */
  13. struct tapi_control_file {
  14. struct tapi_device *tdev;
  15. struct list_head links;
  16. };
  17. static struct tapi_endpoint *tapi_lookup_endpoint(struct tapi_device *tdev,
  18. unsigned int ep_id)
  19. {
  20. struct tapi_stream *stream;
  21. if (ep_id < tdev->num_ports)
  22. return &tdev->ports[ep_id].ep;
  23. list_for_each_entry(stream, &tdev->streams, head) {
  24. if (stream->ep.id == ep_id)
  25. return &stream->ep;
  26. }
  27. return ERR_PTR(-ENOENT);
  28. }
  29. static inline struct tapi_device *inode_to_tdev(struct inode *inode)
  30. {
  31. return container_of(inode->i_cdev, struct tapi_char_device, cdev)->tdev;
  32. }
  33. static int tapi_control_open(struct inode *inode, struct file *file)
  34. {
  35. int ret;
  36. struct tapi_device *tdev = inode_to_tdev(inode);
  37. struct tapi_control_file *tctrl;
  38. get_device(&tdev->dev);
  39. tctrl = kzalloc(sizeof(*tctrl), GFP_KERNEL);
  40. if (!tctrl) {
  41. ret = -ENOMEM;
  42. goto err_put_device;
  43. }
  44. INIT_LIST_HEAD(&tctrl->links);
  45. tctrl->tdev = tdev;
  46. file->private_data = tctrl;
  47. return 0;
  48. err_put_device:
  49. put_device(&tdev->dev);
  50. return ret;
  51. }
  52. static int tapi_control_release(struct inode *inode, struct file *file)
  53. {
  54. struct tapi_control_file *tctrl = file->private_data;
  55. struct tapi_link *link;
  56. if (tctrl) {
  57. list_for_each_entry(link, &tctrl->links, head)
  58. tapi_link_free(tctrl->tdev, link);
  59. put_device(&tctrl->tdev->dev);
  60. }
  61. return 0;
  62. }
  63. static long tapi_control_ioctl_link_alloc(struct tapi_control_file *tctrl,
  64. unsigned long arg)
  65. {
  66. struct tapi_link *link;
  67. struct tapi_endpoint *ep1, *ep2;
  68. ep1 = tapi_lookup_endpoint(tctrl->tdev, arg >> 16);
  69. ep2 = tapi_lookup_endpoint(tctrl->tdev, arg & 0xffff);
  70. link = tapi_link_alloc(tctrl->tdev, ep1, ep2);
  71. if (IS_ERR(link))
  72. return PTR_ERR(link);
  73. list_add_tail(&link->head, &tctrl->links);
  74. return link->id;
  75. }
  76. struct tapi_link *tapi_control_lookup_link(struct tapi_control_file *tctrl,
  77. unsigned int id)
  78. {
  79. struct tapi_link *link;
  80. list_for_each_entry(link, &tctrl->links, head) {
  81. if (link->id == id)
  82. return link;
  83. }
  84. return NULL;
  85. }
  86. static long tapi_control_ioctl_link_free(struct tapi_control_file *tctrl,
  87. unsigned long arg)
  88. {
  89. struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
  90. if (!link)
  91. return -ENOENT;
  92. tapi_link_free(tctrl->tdev, link);
  93. list_del(&link->head);
  94. return 0;
  95. }
  96. static long tapi_control_ioctl_link_enable(struct tapi_control_file *tctrl,
  97. unsigned long arg)
  98. {
  99. struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
  100. if (!link)
  101. return -ENOENT;
  102. return tapi_link_enable(tctrl->tdev, link);
  103. }
  104. static long tapi_control_ioctl_link_disable(struct tapi_control_file *tctrl,
  105. unsigned long arg)
  106. {
  107. struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
  108. if (!link)
  109. return -ENOENT;
  110. return tapi_link_disable(tctrl->tdev, link);
  111. }
  112. static long tapi_control_ioctl_sync(struct tapi_control_file *tctrl)
  113. {
  114. return tapi_sync(tctrl->tdev);
  115. }
  116. static long tapi_control_ioctl(struct file *file, unsigned int cmd,
  117. unsigned long arg)
  118. {
  119. int ret;
  120. struct tapi_control_file *tctrl = file->private_data;
  121. switch (cmd) {
  122. case TAPI_CONTROL_IOCTL_LINK_ALLOC:
  123. ret = tapi_control_ioctl_link_alloc(tctrl, arg);
  124. break;
  125. case TAPI_CONTROL_IOCTL_LINK_FREE:
  126. ret = tapi_control_ioctl_link_free(tctrl, arg);
  127. break;
  128. case TAPI_CONTROL_IOCTL_LINK_ENABLE:
  129. ret = tapi_control_ioctl_link_enable(tctrl, arg);
  130. break;
  131. case TAPI_CONTROL_IOCTL_LINK_DISABLE:
  132. ret = tapi_control_ioctl_link_disable(tctrl, arg);
  133. break;
  134. case TAPI_CONTROL_IOCTL_SYNC:
  135. ret = tapi_control_ioctl_sync(tctrl);
  136. break;
  137. default:
  138. return -EINVAL;
  139. }
  140. return ret;
  141. }
  142. static const struct file_operations tapi_control_file_ops = {
  143. .owner = THIS_MODULE,
  144. .open = tapi_control_open,
  145. .release = tapi_control_release,
  146. .unlocked_ioctl = tapi_control_ioctl,
  147. };
  148. int tapi_register_control_device(struct tapi_device* tdev)
  149. {
  150. dev_set_name(&tdev->control_dev.dev, "tapi%uC", tdev->id);
  151. return tapi_char_device_register(tdev, &tdev->control_dev, &tapi_control_file_ops);
  152. }