n_tracerouter.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * n_tracerouter.c - Trace data router through tty space
  4. *
  5. * Copyright (C) Intel 2011
  6. *
  7. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  8. *
  9. * This trace router uses the Linux line discipline framework to route
  10. * trace data coming from a HW Modem to a PTI (Parallel Trace Module) port.
  11. * The solution is not specific to a HW modem and this line disciple can
  12. * be used to route any stream of data in kernel space.
  13. * This is part of a solution for the P1149.7, compact JTAG, standard.
  14. */
  15. #include <linux/init.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/types.h>
  19. #include <linux/ioctl.h>
  20. #include <linux/tty.h>
  21. #include <linux/tty_ldisc.h>
  22. #include <linux/errno.h>
  23. #include <linux/string.h>
  24. #include <linux/mutex.h>
  25. #include <linux/slab.h>
  26. #include <linux/bug.h>
  27. #include "n_tracesink.h"
  28. /*
  29. * Other ldisc drivers use 65536 which basically means,
  30. * 'I can always accept 64k' and flow control is off.
  31. * This number is deemed appropriate for this driver.
  32. */
  33. #define RECEIVE_ROOM 65536
  34. #define DRIVERNAME "n_tracerouter"
  35. /*
  36. * struct to hold private configuration data for this ldisc.
  37. * opencalled is used to hold if this ldisc has been opened.
  38. * kref_tty holds the tty reference the ldisc sits on top of.
  39. */
  40. struct tracerouter_data {
  41. u8 opencalled;
  42. struct tty_struct *kref_tty;
  43. };
  44. static struct tracerouter_data *tr_data;
  45. /* lock for when tty reference is being used */
  46. static DEFINE_MUTEX(routelock);
  47. /**
  48. * n_tracerouter_open() - Called when a tty is opened by a SW entity.
  49. * @tty: terminal device to the ldisc.
  50. *
  51. * Return:
  52. * 0 for success.
  53. *
  54. * Caveats: This should only be opened one time per SW entity.
  55. */
  56. static int n_tracerouter_open(struct tty_struct *tty)
  57. {
  58. int retval = -EEXIST;
  59. mutex_lock(&routelock);
  60. if (tr_data->opencalled == 0) {
  61. tr_data->kref_tty = tty_kref_get(tty);
  62. if (tr_data->kref_tty == NULL) {
  63. retval = -EFAULT;
  64. } else {
  65. tr_data->opencalled = 1;
  66. tty->disc_data = tr_data;
  67. tty->receive_room = RECEIVE_ROOM;
  68. tty_driver_flush_buffer(tty);
  69. retval = 0;
  70. }
  71. }
  72. mutex_unlock(&routelock);
  73. return retval;
  74. }
  75. /**
  76. * n_tracerouter_close() - close connection
  77. * @tty: terminal device to the ldisc.
  78. *
  79. * Called when a software entity wants to close a connection.
  80. */
  81. static void n_tracerouter_close(struct tty_struct *tty)
  82. {
  83. struct tracerouter_data *tptr = tty->disc_data;
  84. mutex_lock(&routelock);
  85. WARN_ON(tptr->kref_tty != tr_data->kref_tty);
  86. tty_driver_flush_buffer(tty);
  87. tty_kref_put(tr_data->kref_tty);
  88. tr_data->kref_tty = NULL;
  89. tr_data->opencalled = 0;
  90. tty->disc_data = NULL;
  91. mutex_unlock(&routelock);
  92. }
  93. /**
  94. * n_tracerouter_read() - read request from user space
  95. * @tty: terminal device passed into the ldisc.
  96. * @file: pointer to open file object.
  97. * @buf: pointer to the data buffer that gets eventually returned.
  98. * @nr: number of bytes of the data buffer that is returned.
  99. *
  100. * function that allows read() functionality in userspace. By default if this
  101. * is not implemented it returns -EIO. This module is functioning like a
  102. * router via n_tracerouter_receivebuf(), and there is no real requirement
  103. * to implement this function. However, an error return value other than
  104. * -EIO should be used just to show that there was an intent not to have
  105. * this function implemented. Return value based on read() man pages.
  106. *
  107. * Return:
  108. * -EINVAL
  109. */
  110. static ssize_t n_tracerouter_read(struct tty_struct *tty, struct file *file,
  111. unsigned char __user *buf, size_t nr) {
  112. return -EINVAL;
  113. }
  114. /**
  115. * n_tracerouter_write() - Function that allows write() in userspace.
  116. * @tty: terminal device passed into the ldisc.
  117. * @file: pointer to open file object.
  118. * @buf: pointer to the data buffer that gets eventually returned.
  119. * @nr: number of bytes of the data buffer that is returned.
  120. *
  121. * By default if this is not implemented, it returns -EIO.
  122. * This should not be implemented, ever, because
  123. * 1. this driver is functioning like a router via
  124. * n_tracerouter_receivebuf()
  125. * 2. No writes to HW will ever go through this line discpline driver.
  126. * However, an error return value other than -EIO should be used
  127. * just to show that there was an intent not to have this function
  128. * implemented. Return value based on write() man pages.
  129. *
  130. * Return:
  131. * -EINVAL
  132. */
  133. static ssize_t n_tracerouter_write(struct tty_struct *tty, struct file *file,
  134. const unsigned char *buf, size_t nr) {
  135. return -EINVAL;
  136. }
  137. /**
  138. * n_tracerouter_receivebuf() - Routing function for driver.
  139. * @tty: terminal device passed into the ldisc. It's assumed
  140. * tty will never be NULL.
  141. * @cp: buffer, block of characters to be eventually read by
  142. * someone, somewhere (user read() call or some kernel function).
  143. * @fp: flag buffer.
  144. * @count: number of characters (aka, bytes) in cp.
  145. *
  146. * This function takes the input buffer, cp, and passes it to
  147. * an external API function for processing.
  148. */
  149. static void n_tracerouter_receivebuf(struct tty_struct *tty,
  150. const unsigned char *cp,
  151. char *fp, int count)
  152. {
  153. mutex_lock(&routelock);
  154. n_tracesink_datadrain((u8 *) cp, count);
  155. mutex_unlock(&routelock);
  156. }
  157. /*
  158. * Flush buffer is not impelemented as the ldisc has no internal buffering
  159. * so the tty_driver_flush_buffer() is sufficient for this driver's needs.
  160. */
  161. static struct tty_ldisc_ops tty_ptirouter_ldisc = {
  162. .owner = THIS_MODULE,
  163. .magic = TTY_LDISC_MAGIC,
  164. .name = DRIVERNAME,
  165. .open = n_tracerouter_open,
  166. .close = n_tracerouter_close,
  167. .read = n_tracerouter_read,
  168. .write = n_tracerouter_write,
  169. .receive_buf = n_tracerouter_receivebuf
  170. };
  171. /**
  172. * n_tracerouter_init - module initialisation
  173. *
  174. * Registers this module as a line discipline driver.
  175. *
  176. * Return:
  177. * 0 for success, any other value error.
  178. */
  179. static int __init n_tracerouter_init(void)
  180. {
  181. int retval;
  182. tr_data = kzalloc(sizeof(struct tracerouter_data), GFP_KERNEL);
  183. if (tr_data == NULL)
  184. return -ENOMEM;
  185. /* Note N_TRACEROUTER is defined in linux/tty.h */
  186. retval = tty_register_ldisc(N_TRACEROUTER, &tty_ptirouter_ldisc);
  187. if (retval < 0) {
  188. pr_err("%s: Registration failed: %d\n", __func__, retval);
  189. kfree(tr_data);
  190. }
  191. return retval;
  192. }
  193. /**
  194. * n_tracerouter_exit - module unload
  195. *
  196. * Removes this module as a line discipline driver.
  197. */
  198. static void __exit n_tracerouter_exit(void)
  199. {
  200. int retval = tty_unregister_ldisc(N_TRACEROUTER);
  201. if (retval < 0)
  202. pr_err("%s: Unregistration failed: %d\n", __func__, retval);
  203. else
  204. kfree(tr_data);
  205. }
  206. module_init(n_tracerouter_init);
  207. module_exit(n_tracerouter_exit);
  208. MODULE_LICENSE("GPL");
  209. MODULE_AUTHOR("Jay Freyensee");
  210. MODULE_ALIAS_LDISC(N_TRACEROUTER);
  211. MODULE_DESCRIPTION("Trace router ldisc driver");