diag_mux.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/slab.h>
  13. #include <linux/init.h>
  14. #include <linux/uaccess.h>
  15. #include <linux/diagchar.h>
  16. #include <linux/sched.h>
  17. #include <linux/err.h>
  18. #include <linux/delay.h>
  19. #include <linux/workqueue.h>
  20. #include <linux/pm_runtime.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/spinlock.h>
  23. #include <linux/ratelimit.h>
  24. #include "diagchar.h"
  25. #include "diagfwd.h"
  26. #include "diag_mux.h"
  27. #include "diag_usb.h"
  28. #include "diag_memorydevice.h"
  29. #include "diagfwd_peripheral.h"
  30. #include "diag_ipc_logging.h"
  31. struct diag_mux_state_t *diag_mux;
  32. static struct diag_logger_t usb_logger;
  33. static struct diag_logger_t md_logger;
  34. static struct diag_logger_ops usb_log_ops = {
  35. .open = diag_usb_connect_all,
  36. .close = diag_usb_disconnect_all,
  37. .queue_read = diag_usb_queue_read,
  38. .write = diag_usb_write,
  39. .close_peripheral = NULL
  40. };
  41. static struct diag_logger_ops md_log_ops = {
  42. .open = diag_md_open_all,
  43. .close = diag_md_close_all,
  44. .queue_read = NULL,
  45. .write = diag_md_write,
  46. .close_peripheral = diag_md_close_peripheral,
  47. };
  48. int diag_mux_init(void)
  49. {
  50. diag_mux = kzalloc(sizeof(struct diag_mux_state_t),
  51. GFP_KERNEL);
  52. if (!diag_mux)
  53. return -ENOMEM;
  54. kmemleak_not_leak(diag_mux);
  55. usb_logger.mode = DIAG_USB_MODE;
  56. usb_logger.log_ops = &usb_log_ops;
  57. md_logger.mode = DIAG_MEMORY_DEVICE_MODE;
  58. md_logger.log_ops = &md_log_ops;
  59. diag_md_init();
  60. /*
  61. * Set USB logging as the default logger. This is the mode
  62. * Diag should be in when it initializes.
  63. */
  64. diag_mux->usb_ptr = &usb_logger;
  65. diag_mux->md_ptr = &md_logger;
  66. diag_mux->logger = &usb_logger;
  67. diag_mux->mux_mask = 0;
  68. diag_mux->mode = DIAG_USB_MODE;
  69. return 0;
  70. }
  71. void diag_mux_exit(void)
  72. {
  73. kfree(diag_mux);
  74. }
  75. int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops)
  76. {
  77. int err = 0;
  78. if (!ops)
  79. return -EINVAL;
  80. if (proc < 0 || proc >= NUM_MUX_PROC)
  81. return 0;
  82. /* Register with USB logger */
  83. usb_logger.ops[proc] = ops;
  84. err = diag_usb_register(proc, ctx, ops);
  85. if (err) {
  86. pr_err("diag: MUX: unable to register usb operations for proc: %d, err: %d\n",
  87. proc, err);
  88. return err;
  89. }
  90. md_logger.ops[proc] = ops;
  91. err = diag_md_register(proc, ctx, ops);
  92. if (err) {
  93. pr_err("diag: MUX: unable to register md operations for proc: %d, err: %d\n",
  94. proc, err);
  95. return err;
  96. }
  97. return 0;
  98. }
  99. int diag_mux_queue_read(int proc)
  100. {
  101. struct diag_logger_t *logger = NULL;
  102. if (proc < 0 || proc >= NUM_MUX_PROC)
  103. return -EINVAL;
  104. if (!diag_mux)
  105. return -EIO;
  106. if (diag_mux->mode == DIAG_MULTI_MODE)
  107. logger = diag_mux->usb_ptr;
  108. else
  109. logger = diag_mux->logger;
  110. if (logger && logger->log_ops && logger->log_ops->queue_read)
  111. return logger->log_ops->queue_read(proc);
  112. return 0;
  113. }
  114. int diag_mux_write(int proc, unsigned char *buf, int len, int ctx)
  115. {
  116. struct diag_logger_t *logger = NULL;
  117. int peripheral;
  118. if (proc < 0 || proc >= NUM_MUX_PROC)
  119. return -EINVAL;
  120. if (!diag_mux)
  121. return -EIO;
  122. peripheral = diag_md_get_peripheral(ctx);
  123. if (peripheral < 0) {
  124. DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
  125. "diag:%s:%d invalid peripheral = %d\n",
  126. __func__, __LINE__, peripheral);
  127. return -EINVAL;
  128. }
  129. if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
  130. logger = diag_mux->md_ptr;
  131. else
  132. logger = diag_mux->usb_ptr;
  133. if (logger && logger->log_ops && logger->log_ops->write)
  134. return logger->log_ops->write(proc, buf, len, ctx);
  135. return 0;
  136. }
  137. int diag_mux_close_peripheral(int proc, uint8_t peripheral)
  138. {
  139. struct diag_logger_t *logger = NULL;
  140. if (proc < 0 || proc >= NUM_MUX_PROC)
  141. return -EINVAL;
  142. /* Peripheral should account for Apps data as well */
  143. if (peripheral > NUM_PERIPHERALS) {
  144. if (!driver->num_pd_session)
  145. return -EINVAL;
  146. if (peripheral > NUM_MD_SESSIONS)
  147. return -EINVAL;
  148. }
  149. if (!diag_mux)
  150. return -EIO;
  151. if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
  152. logger = diag_mux->md_ptr;
  153. else
  154. logger = diag_mux->logger;
  155. if (logger && logger->log_ops && logger->log_ops->close_peripheral)
  156. return logger->log_ops->close_peripheral(proc, peripheral);
  157. return 0;
  158. }
  159. int diag_mux_switch_logging(int *req_mode, int *peripheral_mask)
  160. {
  161. unsigned int new_mask = 0;
  162. if (!req_mode)
  163. return -EINVAL;
  164. if (*peripheral_mask <= 0 ||
  165. (*peripheral_mask > (DIAG_CON_ALL | DIAG_CON_UPD_ALL))) {
  166. pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__);
  167. return -EINVAL;
  168. }
  169. switch (*req_mode) {
  170. case DIAG_USB_MODE:
  171. new_mask = ~(*peripheral_mask) & diag_mux->mux_mask;
  172. if (new_mask != DIAG_CON_NONE)
  173. *req_mode = DIAG_MULTI_MODE;
  174. if (new_mask == DIAG_CON_ALL)
  175. *req_mode = DIAG_MEMORY_DEVICE_MODE;
  176. break;
  177. case DIAG_MEMORY_DEVICE_MODE:
  178. new_mask = (*peripheral_mask) | diag_mux->mux_mask;
  179. if (new_mask != DIAG_CON_ALL)
  180. *req_mode = DIAG_MULTI_MODE;
  181. break;
  182. default:
  183. pr_err("diag: Invalid mode %d in %s\n", *req_mode, __func__);
  184. return -EINVAL;
  185. }
  186. switch (diag_mux->mode) {
  187. case DIAG_USB_MODE:
  188. if (*req_mode == DIAG_MEMORY_DEVICE_MODE) {
  189. diag_mux->usb_ptr->log_ops->close();
  190. diag_mux->logger = diag_mux->md_ptr;
  191. diag_mux->md_ptr->log_ops->open();
  192. } else if (*req_mode == DIAG_MULTI_MODE) {
  193. diag_mux->md_ptr->log_ops->open();
  194. diag_mux->logger = NULL;
  195. }
  196. break;
  197. case DIAG_MEMORY_DEVICE_MODE:
  198. if (*req_mode == DIAG_USB_MODE) {
  199. diag_mux->md_ptr->log_ops->close();
  200. diag_mux->logger = diag_mux->usb_ptr;
  201. diag_mux->usb_ptr->log_ops->open();
  202. } else if (*req_mode == DIAG_MULTI_MODE) {
  203. diag_mux->usb_ptr->log_ops->open();
  204. diag_mux->logger = NULL;
  205. }
  206. break;
  207. case DIAG_MULTI_MODE:
  208. if (*req_mode == DIAG_USB_MODE) {
  209. diag_mux->md_ptr->log_ops->close();
  210. diag_mux->logger = diag_mux->usb_ptr;
  211. } else if (*req_mode == DIAG_MEMORY_DEVICE_MODE) {
  212. diag_mux->usb_ptr->log_ops->close();
  213. diag_mux->logger = diag_mux->md_ptr;
  214. }
  215. break;
  216. }
  217. diag_mux->mode = *req_mode;
  218. diag_mux->mux_mask = new_mask;
  219. *peripheral_mask = new_mask;
  220. return 0;
  221. }