secwidevinemdw.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /**
  2. * @file secwidevinemdwmdw.c
  3. * @brief Open widevine modular drm secure driver and receive command from secure driver
  4. * @Author Rui Hu
  5. *
  6. **/
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/init.h>
  10. #include <linux/moduleparam.h>
  11. #include <linux/slab.h>
  12. #include <linux/unistd.h>
  13. #include <linux/sched.h>
  14. #include <linux/fs.h>
  15. #include <asm/uaccess.h>
  16. #include <linux/version.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/semaphore.h>
  19. #include <linux/delay.h>
  20. #include <linux/kthread.h>
  21. #include <linux/errno.h>
  22. #include <linux/cdev.h>
  23. #include <linux/device.h>
  24. #include <linux/mutex.h>
  25. #include <linux/string.h>
  26. /*#include <mach/memory.h>*/
  27. #include <asm/io.h>
  28. #include <linux/proc_fs.h>
  29. #include <linux/switch.h>
  30. /* only available for trustonic */
  31. #include "mobicore_driver_api.h"
  32. #include "secwidevinemdw.h"
  33. #define secwidevinemdw_NAME "secwidevinemdw"
  34. #define DEFAULT_HANDLES_NUM (64)
  35. #define MAX_OPEN_SESSIONS 10
  36. /* Debug message event */
  37. #define DBG_EVT_NONE (0) /* No event */
  38. #define DBG_EVT_CMD (1 << 0) /* SEC CMD related event */
  39. #define DBG_EVT_FUNC (1 << 1) /* SEC function event */
  40. #define DBG_EVT_INFO (1 << 2) /* SEC information event */
  41. #define DBG_EVT_WRN (1 << 30) /* Warning event */
  42. #define DBG_EVT_ERR (1 << 31) /* Error event */
  43. #define DBG_EVT_ALL (0xffffffff)
  44. #define DBG_EVT_MASK (DBG_EVT_ALL)
  45. #define MSG(evt, fmt, args...) \
  46. do { \
  47. if ((DBG_EVT_##evt) & DBG_EVT_MASK) { \
  48. pr_debug("[secwidevinemdw_normalwd][%s] "fmt, secwidevinemdw_NAME, ##args); \
  49. } \
  50. } while (0)
  51. #define MSG_FUNC() MSG(FUNC, "%s\n", __func__)
  52. #define HDCP_VERSION_ANY 0
  53. #define HDCP_VERSION_1_0 100
  54. #define HDCP_VERSION_2_0 200
  55. #define HDCP_VERSION_2_1 210
  56. #define HDCP_VERSION_2_2 220
  57. struct task_struct *secwidevinemdwDci_th;
  58. #define CMD_SEC_WIDEVINE_NOTIFY_HWC 1
  59. struct widevinemdw_req_t {
  60. u32 requiredhdcpversion;
  61. u32 currenthdcpversion;
  62. };
  63. /*
  64. * DCI message data.
  65. */
  66. struct dciMessage_t {
  67. union {
  68. int command;
  69. int response;
  70. };
  71. struct widevinemdw_req_t request;
  72. };
  73. static DEFINE_MUTEX(secwidevinemdw_lock);
  74. /*This version just load secure driver*/
  75. #define DR_SECWIDEVINEMDW_UUID {0x40, 0x18, 0x83, 0x11, 0xfa, 0xf3, 0x43, 0x48, \
  76. 0x8d, 0xb8, 0x88, 0xad, 0x39, 0x49, 0x6f, 0x9a}
  77. static const struct mc_uuid_t secwidevinemdw_uuid = { DR_SECWIDEVINEMDW_UUID };
  78. static struct mc_session_handle secwidevinemdwdr_session = { 0 };
  79. static u32 secwidevinemdw_session_ref;
  80. static u32 secwidevinemdw_devid = MC_DEVICE_ID_DEFAULT;
  81. static struct dciMessage_t *secwidevinemdw_dci;
  82. static struct switch_dev secwidevinemdw_switch_data;
  83. static int secwidevinemdw_execute(u32 cmd)
  84. {
  85. mutex_lock(&secwidevinemdw_lock);
  86. if (NULL == secwidevinemdw_dci) {
  87. mutex_unlock(&secwidevinemdw_lock);
  88. MSG(ERR, "secwidevinemdw_dci not exist\n");
  89. return -ENODEV;
  90. }
  91. switch (cmd) {
  92. case CMD_SEC_WIDEVINE_NOTIFY_HWC:
  93. MSG(INFO, "%s: switch_set_state:%u\n",
  94. __func__, secwidevinemdw_dci->request.requiredhdcpversion);
  95. switch_set_state(&secwidevinemdw_switch_data,
  96. secwidevinemdw_dci->request.requiredhdcpversion);
  97. /*Send uevent to notify hwc*/
  98. break;
  99. default:
  100. MSG(ERR, "Unkonw cmd\n");
  101. break;
  102. }
  103. mutex_unlock(&secwidevinemdw_lock);
  104. return 0;
  105. }
  106. static int secwidevinemdw_listenDci(void *data)
  107. {
  108. enum mc_result mc_ret = MC_DRV_OK;
  109. u32 cmdId;
  110. u32 currentversion = 0;
  111. u32 requiredversion = 0;
  112. int ret = 0;
  113. MSG(INFO, "%s: DCI listener.\n", __func__);
  114. for (;;) {
  115. MSG(INFO, "%s: Waiting for notification\n", __func__);
  116. /* Wait for notification from SWd */
  117. mc_ret = mc_wait_notification(&secwidevinemdwdr_session, MC_INFINITE_TIMEOUT);
  118. if (mc_ret != MC_DRV_OK) {
  119. MSG(ERR, "%s: mcWaitNotification failed, mc_ret=%d\n", __func__, mc_ret);
  120. ret = mc_ret;
  121. break;
  122. }
  123. cmdId = secwidevinemdw_dci->command;
  124. currentversion = secwidevinemdw_dci->request.currenthdcpversion;
  125. requiredversion = secwidevinemdw_dci->request.requiredhdcpversion;
  126. MSG(INFO, "%s: wait notification done!! cmdId = 0x%x, current = 0x%x, required = 0x%x\n",
  127. __func__, cmdId, currentversion, requiredversion);
  128. /* Received exception. */
  129. mc_ret = secwidevinemdw_execute(cmdId);
  130. /* Notify the STH*/
  131. mc_ret = mc_notify(&secwidevinemdwdr_session);
  132. if (mc_ret != MC_DRV_OK) {
  133. MSG(ERR, "%s: mcNotify returned: %d\n", __func__, mc_ret);
  134. ret = mc_ret;
  135. break;
  136. }
  137. }
  138. return ret;
  139. }
  140. /*Open driver in open*/
  141. static int secwidevinemdw_session_open(void)
  142. {
  143. enum mc_result mc_ret = MC_DRV_OK;
  144. mutex_lock(&secwidevinemdw_lock);
  145. do {
  146. /* sessions reach max numbers ? */
  147. if (secwidevinemdw_session_ref > MAX_OPEN_SESSIONS) {
  148. MSG(WRN, "secwidevinemdw_session > 0x%x\n", MAX_OPEN_SESSIONS);
  149. break;
  150. }
  151. if (secwidevinemdw_session_ref > 0) {
  152. MSG(WRN, "secwidevinemdw_session already open");
  153. secwidevinemdw_session_ref++;
  154. break;
  155. }
  156. /* open device */
  157. mc_ret = mc_open_device(secwidevinemdw_devid);
  158. if (MC_DRV_OK != mc_ret) {
  159. MSG(ERR, "mc_open_device failed: %d\n", mc_ret);
  160. break;
  161. }
  162. /* allocating WSM for DCI */
  163. mc_ret = mc_malloc_wsm(secwidevinemdw_devid, 0, sizeof(struct dciMessage_t),
  164. (uint8_t **) &secwidevinemdw_dci, 0);
  165. if (MC_DRV_OK != mc_ret) {
  166. mc_close_device(secwidevinemdw_devid);
  167. MSG(ERR, "mc_malloc_wsm failed: %d\n", mc_ret);
  168. break;
  169. }
  170. /*open session*/
  171. secwidevinemdwdr_session.device_id = secwidevinemdw_devid;
  172. mc_ret = mc_open_session(&secwidevinemdwdr_session, &secwidevinemdw_uuid,
  173. (uint8_t *) secwidevinemdw_dci, sizeof(struct dciMessage_t));
  174. if (MC_DRV_OK != mc_ret) {
  175. mc_free_wsm(secwidevinemdw_devid, (uint8_t *) secwidevinemdw_dci);
  176. secwidevinemdw_dci = NULL;
  177. mc_close_device(secwidevinemdw_devid);
  178. MSG(ERR, "mc_open_session failed: %d\n", mc_ret);
  179. break;
  180. }
  181. /* create a thread for listening DCI signals */
  182. secwidevinemdwDci_th = kthread_run(secwidevinemdw_listenDci, NULL, "secwidevinemdw_Dci");
  183. if (IS_ERR(secwidevinemdwDci_th)) {
  184. mc_close_session(&secwidevinemdwdr_session);
  185. mc_free_wsm(secwidevinemdw_devid, (uint8_t *) secwidevinemdw_dci);
  186. secwidevinemdw_dci = NULL;
  187. mc_close_device(secwidevinemdw_devid);
  188. MSG(ERR, "%s, init kthread_run failed!\n", __func__);
  189. break;
  190. }
  191. secwidevinemdw_session_ref = 1;
  192. } while (0);
  193. MSG(INFO, "secwidevinemdw_session_open: ret=%d, ref=%d\n", mc_ret, secwidevinemdw_session_ref);
  194. MSG(INFO, "driver sessionId = %d, deviceId = %d\n",
  195. secwidevinemdwdr_session.session_id, secwidevinemdwdr_session.device_id);
  196. mutex_unlock(&secwidevinemdw_lock);
  197. if (MC_DRV_OK != mc_ret) {
  198. MSG(ERR, "secwidevinemdw_session_open fail");
  199. return -ENXIO;
  200. }
  201. return 0;
  202. }
  203. /*Close trustlet and driver*/
  204. static int secwidevinemdw_session_close(void)
  205. {
  206. enum mc_result mc_ret = MC_DRV_OK;
  207. mutex_lock(&secwidevinemdw_lock);
  208. do {
  209. /* session is already closed ? */
  210. if (secwidevinemdw_session_ref == 0) {
  211. MSG(WRN, "secwidevinemdw_session already closed\n");
  212. break;
  213. }
  214. if (secwidevinemdw_session_ref > 1) {
  215. secwidevinemdw_session_ref--;
  216. break;
  217. }
  218. /* close session */
  219. mc_ret = mc_close_session(&secwidevinemdwdr_session);
  220. /* free WSM for DCI */
  221. mc_ret = mc_free_wsm(secwidevinemdw_devid, (uint8_t *) secwidevinemdw_dci);
  222. secwidevinemdw_dci = NULL;
  223. secwidevinemdw_session_ref = 0;
  224. /* close device */
  225. mc_ret = mc_close_device(secwidevinemdw_devid);
  226. if (MC_DRV_OK != mc_ret)
  227. MSG(ERR, "mc_close_device failed: %d\n", mc_ret);
  228. } while (0);
  229. MSG(INFO, "secwidevinemdw_session_close: ret=%d, ref=%d\n", mc_ret, secwidevinemdw_session_ref);
  230. mutex_unlock(&secwidevinemdw_lock);
  231. if (MC_DRV_OK != mc_ret)
  232. return -ENXIO;
  233. return 0;
  234. }
  235. static int secwidevinemdw_open(struct inode *inode, struct file *file)
  236. {
  237. /* open session */
  238. if (secwidevinemdw_session_open() < 0) {
  239. MSG(ERR, "secwidevinemdw_open fail - secwidevinemdw_session_open fail");
  240. return -ENXIO;
  241. }
  242. return 0;
  243. }
  244. static int secwidevinemdw_release(struct inode *inode, struct file *file)
  245. {
  246. int ret = 0;
  247. ret = secwidevinemdw_session_close();
  248. return ret;
  249. }
  250. static ssize_t secwidevinemdw_read(struct file *file, char *buf, size_t size,
  251. loff_t *offset)
  252. {
  253. /*ignore offsset*/
  254. u32 hdcpversion = secwidevinemdw_dci->request.currenthdcpversion;
  255. int ret = 0;
  256. if (size < sizeof(hdcpversion)) {
  257. /*MSG(ERR, "secwidevinemdw_read fail - buf size(%u) is small 0x%08lx",
  258. (unsigned int) size, sizeof(hdcpversion));*/
  259. return -1;
  260. }
  261. memset(buf, 0, sizeof(hdcpversion));
  262. ret = copy_to_user(buf, &hdcpversion, sizeof(hdcpversion));
  263. /*MSG(INFO, "secwidevinemdw_read: hdcpversion = %d, copy result: %d\n", hdcpversion, ret);*/
  264. return sizeof(hdcpversion);
  265. }
  266. static const struct file_operations secwidevinemdw_fops = {
  267. .owner = THIS_MODULE,
  268. .open = secwidevinemdw_open,
  269. .release = secwidevinemdw_release,
  270. .unlocked_ioctl = NULL,
  271. .write = NULL,
  272. .read = secwidevinemdw_read,
  273. };
  274. static int __init secwidevinemdw_init(void)
  275. {
  276. int ret = 0;
  277. proc_create("secwidevinemdw1", (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH),
  278. NULL, &secwidevinemdw_fops);
  279. /*To support modular drm v9, inform HWC the event*/
  280. secwidevinemdw_switch_data.name = "widevine";
  281. secwidevinemdw_switch_data.index = 0;
  282. secwidevinemdw_switch_data.state = HDCP_VERSION_ANY;
  283. MSG(INFO, "secwidevinemdw_session_open: switch_dev_register");
  284. ret = switch_dev_register(&secwidevinemdw_switch_data);
  285. if (ret)
  286. MSG(INFO, "[secwidevinemdw]switch_dev_register failed, returned:%d!\n", ret);
  287. return 0;
  288. }
  289. late_initcall(secwidevinemdw_init);