input_uapi.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-3-08 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include <poll.h>
  14. #include <errno.h>
  15. #include <ktime.h>
  16. #include <dfs_file.h>
  17. #define DBG_TAG "input.uapi"
  18. #define DBG_LVL DBG_INFO
  19. #include <rtdbg.h>
  20. #define _IOC_NRBITS 8
  21. #define _IOC_TYPEBITS 8
  22. #ifndef _IOC_SIZEBITS
  23. #define _IOC_SIZEBITS 14
  24. #endif
  25. #ifndef _IOC_DIRBITS
  26. #define _IOC_DIRBITS 2
  27. #endif
  28. #define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1)
  29. #define _IOC_NRSHIFT 0
  30. #define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS)
  31. #define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS)
  32. #define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS)
  33. #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & 0xFF)
  34. #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & 0xFF)
  35. #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & 0x3FFF)
  36. #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & 0x3)
  37. #ifndef _IOC_READ
  38. #define _IOC_READ 2U
  39. #endif
  40. #ifndef _IOC
  41. #define _IOC(dir, type, nr, size) \
  42. ( \
  43. ((dir) << _IOC_DIRSHIFT) | \
  44. ((type) << _IOC_TYPESHIFT) | \
  45. ((nr) << _IOC_NRSHIFT) | \
  46. ((size) << _IOC_SIZESHIFT) \
  47. )
  48. #endif
  49. struct input_uapi
  50. {
  51. struct dfs_file *grabbed_file;
  52. rt_atomic_t write_idx;
  53. rt_atomic_t read_idx;
  54. rt_atomic_t sync_count;
  55. struct input_event events[RT_INPUT_UAPI_EVENT_MAX];
  56. };
  57. static int input_uapi_fops_open(struct dfs_file *file)
  58. {
  59. struct rt_input_device *idev = file->vnode->data;
  60. rt_device_open(&idev->parent, RT_DEVICE_OFLAG_RDWR);
  61. return 0;
  62. }
  63. static int input_uapi_fops_close(struct dfs_file *file)
  64. {
  65. struct rt_input_device *idev = file->vnode->data;
  66. struct input_uapi *uapi = idev->uapi;
  67. rt_device_close(&idev->parent);
  68. if (uapi->grabbed_file == file)
  69. {
  70. rt_spin_lock(&idev->lock);
  71. uapi->grabbed_file = RT_NULL;
  72. rt_spin_unlock(&idev->lock);
  73. }
  74. return 0;
  75. }
  76. static int input_uapi_fops_ioctl(struct dfs_file *file, int cmd, void *args)
  77. {
  78. unsigned int size;
  79. struct rt_input_device *idev = file->vnode->data;
  80. struct input_uapi *uapi = idev->uapi;
  81. switch (cmd)
  82. {
  83. case EVIOCGVERSION:
  84. {
  85. int version = EV_VERSION;
  86. rt_memcpy(args, &version, sizeof(int));
  87. return 0;
  88. }
  89. case EVIOCGID:
  90. {
  91. static struct input_id virtual_id =
  92. {
  93. .bustype = 0x06, /* BUS_VIRTUAL */
  94. .vendor = 0x5354, /* "RT" */
  95. .product = 0x4556, /* "EV" */
  96. .version = RT_VER_NUM >> 16,
  97. };
  98. rt_memcpy(args, &virtual_id, sizeof(virtual_id));
  99. return 0;
  100. }
  101. case EVIOCGRAB:
  102. rt_spin_lock(&idev->lock);
  103. if (uapi->grabbed_file && uapi->grabbed_file != file)
  104. {
  105. rt_spin_unlock(&idev->lock);
  106. return -EBUSY;
  107. }
  108. uapi->grabbed_file = args ? file : RT_NULL;
  109. rt_spin_unlock(&idev->lock);
  110. return 0;
  111. }
  112. size = _IOC_SIZE(cmd);
  113. switch (((cmd) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)))
  114. {
  115. case EVIOCGNAME(0):
  116. rt_strncpy(args, idev->parent.parent.name, rt_min_t(unsigned int, size, RT_NAME_MAX));
  117. return 0;
  118. case EVIOCGPROP(0):
  119. {
  120. rt_bitmap_t *bitmap = args;
  121. const int input_prop_direct = 0x1;
  122. rt_memset(bitmap, 0, size);
  123. if (size >= sizeof(rt_bitmap_t))
  124. {
  125. bitmap[RT_BIT_WORD(input_prop_direct)] |= RT_BIT_MASK(input_prop_direct);
  126. }
  127. return 0;
  128. }
  129. }
  130. if (_IOC_TYPE(cmd) != 'E')
  131. {
  132. return -EINVAL;
  133. }
  134. if (_IOC_DIR(cmd) == _IOC_READ)
  135. {
  136. if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
  137. {
  138. rt_size_t bit_len;
  139. rt_bitmap_t *bitmap;
  140. switch (_IOC_NR(cmd) & EV_MAX)
  141. {
  142. case 0: bitmap = idev->cap; bit_len = EV_MAX; break;
  143. case EV_KEY: bitmap = idev->key_map; bit_len = KEY_MAX; break;
  144. case EV_REL: bitmap = idev->rel_map; bit_len = REL_MAX; break;
  145. case EV_ABS: bitmap = idev->abs_map; bit_len = ABS_MAX; break;
  146. default:
  147. return -EINVAL;
  148. }
  149. size = rt_min_t(rt_size_t, size, ((bit_len + 8) / 8));
  150. rt_memcpy(args, bitmap, size);
  151. return 0;
  152. }
  153. if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0)))
  154. {
  155. rt_size_t max;
  156. if (!idev->absinfo)
  157. {
  158. return -EINVAL;
  159. }
  160. max = _IOC_NR(cmd) & ABS_MAX;
  161. rt_memcpy(args, &idev->absinfo[max], rt_min_t(rt_size_t, size, sizeof(struct input_absinfo)));
  162. return 0;
  163. }
  164. }
  165. return -EINVAL;
  166. }
  167. static ssize_t input_uapi_fops_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
  168. {
  169. int err;
  170. size_t read = 0;
  171. struct input_event *event = buf;
  172. struct rt_input_device *idev = file->vnode->data;
  173. struct input_uapi *uapi = idev->uapi;
  174. rt_spin_lock(&idev->lock);
  175. if (uapi->grabbed_file && uapi->grabbed_file != file)
  176. {
  177. rt_spin_unlock(&idev->lock);
  178. return -EAGAIN;
  179. }
  180. rt_spin_unlock(&idev->lock);
  181. if (count != 0 && count < sizeof(struct input_event))
  182. {
  183. return -EINVAL;
  184. }
  185. for (;;)
  186. {
  187. if (!rt_atomic_load(&uapi->sync_count) && (file->flags & O_NONBLOCK))
  188. {
  189. #ifdef RT_UAPI_FAKE_BLOCK
  190. static struct input_event fake_event =
  191. {
  192. .type = EV_SYN,
  193. .code = SYN_REPORT,
  194. };
  195. rt_memcpy(event, &fake_event, sizeof(struct input_event));
  196. read += sizeof(struct input_event);
  197. return read;
  198. #else
  199. return -EAGAIN;
  200. #endif
  201. }
  202. /* No IO is done but we check for error conditions */
  203. if (count == 0)
  204. {
  205. break;
  206. }
  207. while (read + sizeof(struct input_event) <= count && rt_atomic_load(&uapi->sync_count))
  208. {
  209. rt_ubase_t r_idx = rt_atomic_load(&uapi->read_idx);
  210. rt_memcpy(event, &uapi->events[r_idx], sizeof(struct input_event));
  211. rt_atomic_store(&uapi->read_idx, (r_idx + 1) % RT_ARRAY_SIZE(uapi->events));
  212. if (event->type == EV_SYN && event->code == SYN_REPORT)
  213. {
  214. rt_atomic_sub(&uapi->sync_count, 1);
  215. }
  216. ++event;
  217. read += sizeof(struct input_event);
  218. }
  219. if (read)
  220. {
  221. break;
  222. }
  223. if (!(file->flags & O_NONBLOCK))
  224. {
  225. err = rt_wqueue_wait_interruptible(&idev->parent.wait_queue, 0, RT_WAITING_FOREVER);
  226. if (err)
  227. {
  228. return err;
  229. }
  230. }
  231. }
  232. return read;
  233. }
  234. static ssize_t input_uapi_fops_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
  235. {
  236. return -ENOSYS;
  237. }
  238. static int input_uapi_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
  239. {
  240. /* Only support POLLIN */
  241. int mask = 0, flags = file->flags & O_ACCMODE;
  242. struct rt_input_device *idev = file->vnode->data;
  243. struct input_uapi *uapi = idev->uapi;
  244. if (flags == O_RDONLY || flags == O_RDWR)
  245. {
  246. rt_poll_add(&idev->parent.wait_queue, req);
  247. if (rt_atomic_load(&uapi->sync_count))
  248. {
  249. mask |= POLLIN;
  250. }
  251. }
  252. return mask;
  253. }
  254. static const struct dfs_file_ops input_uapi_fops =
  255. {
  256. .open = input_uapi_fops_open,
  257. .close = input_uapi_fops_close,
  258. .ioctl = input_uapi_fops_ioctl,
  259. .read = input_uapi_fops_read,
  260. .write = input_uapi_fops_write,
  261. .lseek = generic_dfs_lseek,
  262. .poll = input_uapi_fops_poll,
  263. };
  264. void input_uapi_init(struct rt_input_device *idev)
  265. {
  266. struct input_uapi *uapi = rt_calloc(1, sizeof(struct input_uapi));
  267. if (!uapi)
  268. {
  269. LOG_W("%s: No memory to create UAPI", rt_dm_dev_get_name(&idev->parent));
  270. return;
  271. }
  272. idev->uapi = uapi;
  273. idev->parent.fops = &input_uapi_fops;
  274. RT_ASSERT(sizeof(struct input_absinfo) == sizeof(struct rt_input_absinfo));
  275. RT_ASSERT(rt_offsetof(struct input_absinfo, value) == rt_offsetof(struct rt_input_absinfo, value));
  276. RT_ASSERT(rt_offsetof(struct input_absinfo, minimum) == rt_offsetof(struct rt_input_absinfo, minimum));
  277. RT_ASSERT(rt_offsetof(struct input_absinfo, maximum) == rt_offsetof(struct rt_input_absinfo, maximum));
  278. RT_ASSERT(rt_offsetof(struct input_absinfo, fuzz) == rt_offsetof(struct rt_input_absinfo, fuzz));
  279. RT_ASSERT(rt_offsetof(struct input_absinfo, flat) == rt_offsetof(struct rt_input_absinfo, flat));
  280. RT_ASSERT(rt_offsetof(struct input_absinfo, resolution) == rt_offsetof(struct rt_input_absinfo, resolution));
  281. }
  282. void input_uapi_finit(struct rt_input_device *idev)
  283. {
  284. if (idev->uapi)
  285. {
  286. rt_free(idev->uapi);
  287. idev->uapi = RT_NULL;
  288. idev->parent.fops = RT_NULL;
  289. }
  290. }
  291. void input_uapi_event(struct rt_input_device *idev, struct rt_input_event *event)
  292. {
  293. rt_ubase_t w_idx, next;
  294. struct input_event *uapi_event;
  295. struct input_uapi *uapi = idev->uapi;
  296. if (!idev->parent.ref_count)
  297. {
  298. return;
  299. }
  300. w_idx = rt_atomic_load(&uapi->write_idx);
  301. next = (w_idx + 1) % RT_ARRAY_SIZE(uapi->events);
  302. if (next == rt_atomic_load(&uapi->read_idx))
  303. {
  304. LOG_W("%s: Event (type: %d code: %d value: %d) dropped",
  305. rt_dm_dev_get_name(&idev->parent),
  306. event->type, event->code, event->value);
  307. return;
  308. }
  309. uapi_event = &uapi->events[w_idx];
  310. rt_ktime_boottime_get_us(&uapi_event->time);
  311. uapi_event->type = event->type;
  312. uapi_event->code = event->code;
  313. uapi_event->value = event->value;
  314. rt_atomic_store(&uapi->write_idx, next);
  315. if (event->type == EV_SYN && event->code == SYN_REPORT)
  316. {
  317. rt_atomic_add(&uapi->sync_count, 1);
  318. rt_wqueue_wakeup(&idev->parent.wait_queue, (void *)(rt_ubase_t)POLLIN);
  319. }
  320. }