n_tracerouter.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 *buf, size_t nr,
  112. void **cookie, unsigned long offset)
  113. {
  114. return -EINVAL;
  115. }
  116. /**
  117. * n_tracerouter_write() - Function that allows write() in userspace.
  118. * @tty: terminal device passed into the ldisc.
  119. * @file: pointer to open file object.
  120. * @buf: pointer to the data buffer that gets eventually returned.
  121. * @nr: number of bytes of the data buffer that is returned.
  122. *
  123. * By default if this is not implemented, it returns -EIO.
  124. * This should not be implemented, ever, because
  125. * 1. this driver is functioning like a router via
  126. * n_tracerouter_receivebuf()
  127. * 2. No writes to HW will ever go through this line discpline driver.
  128. * However, an error return value other than -EIO should be used
  129. * just to show that there was an intent not to have this function
  130. * implemented. Return value based on write() man pages.
  131. *
  132. * Return:
  133. * -EINVAL
  134. */
  135. static ssize_t n_tracerouter_write(struct tty_struct *tty, struct file *file,
  136. const unsigned char *buf, size_t nr) {
  137. return -EINVAL;
  138. }
  139. /**
  140. * n_tracerouter_receivebuf() - Routing function for driver.
  141. * @tty: terminal device passed into the ldisc. It's assumed
  142. * tty will never be NULL.
  143. * @cp: buffer, block of characters to be eventually read by
  144. * someone, somewhere (user read() call or some kernel function).
  145. * @fp: flag buffer.
  146. * @count: number of characters (aka, bytes) in cp.
  147. *
  148. * This function takes the input buffer, cp, and passes it to
  149. * an external API function for processing.
  150. */
  151. static void n_tracerouter_receivebuf(struct tty_struct *tty,
  152. const unsigned char *cp,
  153. char *fp, int count)
  154. {
  155. mutex_lock(&routelock);
  156. n_tracesink_datadrain((u8 *) cp, count);
  157. mutex_unlock(&routelock);
  158. }
  159. /*
  160. * Flush buffer is not impelemented as the ldisc has no internal buffering
  161. * so the tty_driver_flush_buffer() is sufficient for this driver's needs.
  162. */
  163. static struct tty_ldisc_ops tty_ptirouter_ldisc = {
  164. .owner = THIS_MODULE,
  165. .magic = TTY_LDISC_MAGIC,
  166. .name = DRIVERNAME,
  167. .open = n_tracerouter_open,
  168. .close = n_tracerouter_close,
  169. .read = n_tracerouter_read,
  170. .write = n_tracerouter_write,
  171. .receive_buf = n_tracerouter_receivebuf
  172. };
  173. /**
  174. * n_tracerouter_init - module initialisation
  175. *
  176. * Registers this module as a line discipline driver.
  177. *
  178. * Return:
  179. * 0 for success, any other value error.
  180. */
  181. static int __init n_tracerouter_init(void)
  182. {
  183. int retval;
  184. tr_data = kzalloc(sizeof(struct tracerouter_data), GFP_KERNEL);
  185. if (tr_data == NULL)
  186. return -ENOMEM;
  187. /* Note N_TRACEROUTER is defined in linux/tty.h */
  188. retval = tty_register_ldisc(N_TRACEROUTER, &tty_ptirouter_ldisc);
  189. if (retval < 0) {
  190. pr_err("%s: Registration failed: %d\n", __func__, retval);
  191. kfree(tr_data);
  192. }
  193. return retval;
  194. }
  195. /**
  196. * n_tracerouter_exit - module unload
  197. *
  198. * Removes this module as a line discipline driver.
  199. */
  200. static void __exit n_tracerouter_exit(void)
  201. {
  202. int retval = tty_unregister_ldisc(N_TRACEROUTER);
  203. if (retval < 0)
  204. pr_err("%s: Unregistration failed: %d\n", __func__, retval);
  205. else
  206. kfree(tr_data);
  207. }
  208. module_init(n_tracerouter_init);
  209. module_exit(n_tracerouter_exit);
  210. MODULE_LICENSE("GPL");
  211. MODULE_AUTHOR("Jay Freyensee");
  212. MODULE_ALIAS_LDISC(N_TRACEROUTER);
  213. MODULE_DESCRIPTION("Trace router ldisc driver");