video.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * Copyright (C) 2021 Alibaba Group Holding Limited
  3. * Author: liuyitong <yitong.lyt@alibaba-inc.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #include <asm/io.h>
  10. #include <linux/cdev.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/delay.h>
  14. #include <linux/clk.h>
  15. #include <linux/io.h>
  16. #include <linux/mm.h>
  17. #include <linux/timer.h>
  18. #include <linux/kernel.h>
  19. #include <linux/init.h>
  20. #include <linux/ioctl.h>
  21. #include <linux/poll.h>
  22. #include <linux/workqueue.h>
  23. #include <linux/slab.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/debugfs.h>
  26. #include <linux/miscdevice.h>
  27. #include <linux/uaccess.h>
  28. #include <linux/interrupt.h>
  29. #include <linux/of.h>
  30. #include "video.h"
  31. #include "video_ioctl.h"
  32. #define VIDEO_DRIVER_NAME "video"
  33. #define VIDEO_DRIVER_MAXCNT 100
  34. static struct class *video_driver_class;
  35. static unsigned int video_driver_major = 0;
  36. static unsigned int video_driver_minor = 0;
  37. static unsigned int device_register_index = 0;
  38. #define check_retval(x)\
  39. do {\
  40. if ((x))\
  41. return -EIO;\
  42. } while (0)
  43. static unsigned int video_poll(struct file * filp, poll_table *wait)
  44. {
  45. return 0;
  46. }
  47. void video_work(struct work_struct *work)
  48. {
  49. }
  50. irqreturn_t video_irq(int irq, void *dev_id)
  51. {
  52. video_info("enter %s\n", __func__);
  53. return IRQ_HANDLED;
  54. }
  55. static int video_open(struct inode * inode, struct file * file)
  56. {
  57. struct video_drvdata *drvdata;
  58. drvdata = container_of(inode->i_cdev, struct video_drvdata, cdev);
  59. file->private_data = drvdata;
  60. return 0;
  61. };
  62. static int video_get_pipelines(struct video_drvdata *drvdata, void *__user args)
  63. {
  64. pipline_t *usr_pip = (pipline_t *)args;
  65. pipline_t *cam_pip = drvdata->piplines;
  66. check_retval(copy_to_user(usr_pip, cam_pip, sizeof(pipline_t) * drvdata->pipline_num));
  67. video_info("%s, %d, pipeline nmu: %d\n", __func__, __LINE__, drvdata->pipline_num);
  68. return 0;
  69. }
  70. static int video_get_pipelines_num (struct video_drvdata *drvdata, void *__user args)
  71. {
  72. check_retval(copy_to_user(args, &drvdata->pipline_num, sizeof(int)));
  73. return 0;
  74. }
  75. static int video_set_path_type(struct video_drvdata *drvdata, void *__user args)
  76. {
  77. pathtype_set_t pathtype_set;
  78. check_retval(copy_from_user(&pathtype_set, args, sizeof(pathtype_set_t)));
  79. video_info("VIDEO_SET_PATH_TYPE pipeline=%d sensor=%s path_type%d \n", pathtype_set.pipeline_id , pathtype_set.sensor_name, pathtype_set.path_type);
  80. return 0;
  81. }
  82. static int video_get_mem_pool_region_id(struct video_drvdata *drvdata, void *__user args)
  83. {
  84. check_retval(copy_to_user(args, &drvdata->vi_mem_pool_region_id, sizeof(int)));
  85. return 0;
  86. }
  87. static long video_set_state(struct video_drvdata *drvdata,int *arg)
  88. {
  89. int ops;
  90. check_retval(copy_from_user(&ops,arg,sizeof(int)));
  91. if(ops ==DEVICE_OPERATION_ACTIVE)
  92. {
  93. if(drvdata->actived == true)
  94. {
  95. dev_warn(drvdata->dev,"%s,can't ative,device already active by other process(%d)\n",__func__, current->tgid);
  96. return (-EBUSY);
  97. }else
  98. {
  99. drvdata->actived =true;
  100. drvdata->actived_owner = current->tgid;
  101. dev_dbg(drvdata->dev,"%s,actived by process %d\n",__func__,current->tgid);
  102. }
  103. }
  104. else if(ops ==DEVICE_OPERATION_DEACTIVE)
  105. {
  106. if(drvdata->actived == false)
  107. {
  108. dev_warn(drvdata->dev,"%s,can't deative,device is not atived\n",__func__);
  109. return (-EPERM);
  110. }else
  111. {
  112. if(drvdata->actived_owner != current->tgid)
  113. {
  114. dev_warn(drvdata->dev,"%s,can't deative,device is active by other process(%d)\n",__func__, current->tgid);
  115. return (-EPERM);
  116. }
  117. drvdata->actived =false;
  118. drvdata->actived_owner = -1;
  119. dev_dbg(drvdata->dev,"%s de-active",__func__);
  120. }
  121. }else
  122. {
  123. dev_warn(drvdata->dev,"%s,un-defined ops\n",__func__);
  124. return (-EPERM);
  125. }
  126. return 0;
  127. }
  128. static long video_get_state(struct video_drvdata *drvdata,int *arg)
  129. {
  130. int ops;
  131. ops = drvdata->actived==true?DEVICE_OPERATION_ACTIVE:DEVICE_OPERATION_DEACTIVE;
  132. check_retval(copy_to_user(arg, &ops, sizeof(int)));
  133. return 0;
  134. }
  135. static long video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  136. {
  137. long ret = 0;
  138. struct video_drvdata *drvdata;
  139. drvdata = file->private_data;
  140. if (drvdata == NULL) {
  141. video_err("%s:file private is null point error\n", __func__);
  142. return -ENOMEM;
  143. }
  144. mutex_lock(&drvdata->mutex);
  145. switch (cmd) {
  146. case VIDEO_GET_PIPLANES:
  147. ret = video_get_pipelines(drvdata, (void *)arg);
  148. break;
  149. case VIDEO_GET_PIPLANES_NUM:
  150. ret = video_get_pipelines_num(drvdata, (void *)arg);
  151. break;
  152. case VIDEO_SET_PATH_TYPE:
  153. ret = video_set_path_type(drvdata, (void *)arg);
  154. break;
  155. case VIDEO_GET_MEM_POOL_REGION_ID:
  156. ret = video_get_mem_pool_region_id(drvdata, (void *)arg);
  157. break;
  158. case VIDEO_SET_DEVICE_STATE:
  159. ret = video_set_state(drvdata, (void *)arg);
  160. break;
  161. case VIDEO_GET_DEVICE_STATE:
  162. ret = video_get_state(drvdata, (void *)arg);
  163. break;
  164. default:
  165. ret = -EPERM;
  166. video_err("%s: unsupported command %d\n", __func__, cmd);
  167. break;
  168. }
  169. mutex_unlock(&drvdata->mutex);
  170. return ret;
  171. };
  172. static int video_release(struct inode * inode, struct file * file)
  173. {
  174. struct video_drvdata *drvdata;
  175. drvdata = container_of(inode->i_cdev, struct video_drvdata, cdev);
  176. mutex_lock(&drvdata->mutex);
  177. if(drvdata->actived == true &&
  178. drvdata->actived_owner == current->tgid)
  179. {
  180. drvdata->actived = false;
  181. drvdata->actived_owner = -1;
  182. dev_dbg(drvdata->dev,"%s de-active device\n",__func__);
  183. }
  184. mutex_unlock(&drvdata->mutex);
  185. return 0;
  186. };
  187. static int video_mmap(struct file *pFile, struct vm_area_struct *vma)
  188. {
  189. video_info("enter %s\n", __func__);
  190. return 0;
  191. };
  192. struct file_operations video_fops = {
  193. .owner = THIS_MODULE,
  194. .open = video_open,
  195. .release = video_release,
  196. .unlocked_ioctl = video_ioctl,
  197. .mmap = video_mmap,
  198. .poll = video_poll,
  199. };
  200. static int video_press_pipline(pipline_t *pipline, struct fwnode_handle *pip_node)
  201. {
  202. int ret = 0;
  203. const char *dev_name;
  204. const char *path_name;
  205. struct fwnode_handle *nodes;
  206. sub_dev_info_t *sub_dev = pipline->sub_dev;
  207. fwnode_for_each_available_child_node(pip_node, nodes) {
  208. ret = fwnode_property_read_string(nodes, "subdev_name", &dev_name);
  209. if (ret != 0) {
  210. video_err("dts press error!!!!!, %s, %d\n", __func__, __LINE__);
  211. return -1;
  212. }
  213. strcpy(sub_dev->name, dev_name);
  214. ret = fwnode_property_read_u32_array(nodes, "idx", &sub_dev->idx, 1);
  215. if (ret != 0) {
  216. video_err("dts press device :%s error!!!!!, %d, %s\n", __func__, __LINE__,dev_name);
  217. return -1;
  218. }
  219. ret = fwnode_property_read_string(nodes, "path_type", &path_name);
  220. if (ret != 0) {
  221. video_err("%s, %d, dts parse %s->%s error!!!!!\n", __func__, __LINE__, dev_name, path_name);
  222. return -1;
  223. }
  224. video_info("%s, %d, dev: %s->%s !!!!!\n", __func__, __LINE__, dev_name, path_name);
  225. sub_dev->path = vedio_get_path_type(dev_name, path_name);
  226. if(sub_dev->path < 0) {
  227. video_err("%s, %d, %s, parse path(%s) error!!!!!\n", __func__, __LINE__, dev_name, path_name);
  228. return -1;
  229. }
  230. video_info("subdev:%s-%d,path:(%s,%d)\n",dev_name,sub_dev->idx, path_name,sub_dev->path);
  231. ret = video_subdev_press_dts(nodes, sub_dev);
  232. if (ret != 0) {
  233. video_err("dts press error!!!!!, %s, %d\n", __func__, __LINE__);
  234. return -1;
  235. }
  236. sub_dev++;
  237. pipline->sub_dev_num++;
  238. }
  239. return 0;
  240. }
  241. static int video_press_dts(struct platform_device *pdev)
  242. {
  243. int ret = 0;
  244. struct device *dev = &pdev->dev;
  245. struct fwnode_handle *child;
  246. struct video_drvdata *drvdata;
  247. pipline_t *pipline;
  248. int pool_region_id;
  249. drvdata = platform_get_drvdata(pdev);
  250. pipline = drvdata->piplines;
  251. //if (device_property_read_u32(&(pdev->dev), "vi_mem_pool_region", &pool_region_id) != 0) {
  252. if (of_property_read_s32(dev->of_node, "vi_mem_pool_region", &pool_region_id) != 0) {
  253. video_warn("%s, dev(%s) can't get vi_mem_pool_region id from dts, set to default -1(cma)\n",
  254. __func__, pdev->name);
  255. pool_region_id = -1;
  256. }
  257. drvdata->vi_mem_pool_region_id = pool_region_id;
  258. device_for_each_child_node(dev, child) {
  259. video_info("pipleline(%d):",drvdata->pipline_num);
  260. ret = video_press_pipline(pipline, child);
  261. if (ret != 0) {
  262. video_err("%s, %d, dts press pipe:%d error!\n", __func__, __LINE__, drvdata->pipline_num);
  263. return -1;
  264. }
  265. pipline++;
  266. drvdata->pipline_num++;
  267. }
  268. return 0;
  269. }
  270. static int video_probe(struct platform_device *pdev)
  271. {
  272. int ret = 0;
  273. struct video_drvdata *drvdata;
  274. struct device_node *np = pdev->dev.of_node;
  275. video_info("enter %s\n", __func__);
  276. pdev->id = of_alias_get_id(np, "viv_video");
  277. video_info("%s:pdev id is %d\n", __func__, pdev->id);
  278. if (pdev->id >= VIDEO_DRIVER_MAXCNT) {
  279. video_err("%s:pdev id is %d error\n", __func__, pdev->id);
  280. return -EINVAL;
  281. }
  282. drvdata = devm_kzalloc(&pdev->dev,sizeof(struct video_drvdata), GFP_KERNEL);
  283. if (drvdata == NULL) {
  284. video_err("%s:alloc struct drvdata error\n", __func__);
  285. return -ENOMEM;
  286. }
  287. drvdata->device_idx = pdev->id;
  288. drvdata->actived = false;
  289. drvdata->actived_owner = -1;
  290. drvdata->dev = &pdev->dev;
  291. mutex_init(&drvdata->mutex);
  292. platform_set_drvdata(pdev, drvdata);
  293. if (device_register_index == 0) {
  294. if (video_driver_major == 0) {
  295. ret = alloc_chrdev_region(&drvdata->devt, 0, VIDEO_DRIVER_MAXCNT, VIDEO_DRIVER_NAME);
  296. if (ret != 0) {
  297. video_err("%s:alloc_chrdev_region error\n", __func__);
  298. return ret;
  299. }
  300. video_driver_major = MAJOR(drvdata->devt);
  301. video_driver_minor = MINOR(drvdata->devt);
  302. } else {
  303. drvdata->devt = MKDEV(video_driver_major, video_driver_minor);
  304. ret = register_chrdev_region(drvdata->devt, VIDEO_DRIVER_MAXCNT, VIDEO_DRIVER_NAME);
  305. if (ret) {
  306. video_err("%s:register_chrdev_region error\n", __func__);
  307. return ret;
  308. }
  309. }
  310. video_driver_class = class_create(THIS_MODULE, VIDEO_DRIVER_NAME);
  311. if (IS_ERR(video_driver_class)) {
  312. video_err("%s[%d]:class_create error!\n", __func__, __LINE__);
  313. return -EINVAL;
  314. }
  315. }
  316. drvdata->devt = MKDEV(video_driver_major, video_driver_minor + pdev->id);
  317. cdev_init(&drvdata->cdev, &video_fops);
  318. ret = cdev_add(&drvdata->cdev, drvdata->devt, 1);
  319. if ( ret ) {
  320. video_err("%s[%d]:cdev_add error!\n", __func__, __LINE__);
  321. return ret;
  322. } else {
  323. video_info("%s[%d]:cdev_add OK, major=%d, minor=%d\n", __func__, __LINE__,
  324. video_driver_major, video_driver_minor + pdev->id);
  325. }
  326. drvdata->class = video_driver_class;
  327. device_create(drvdata->class, NULL, drvdata->devt,
  328. drvdata, "%s%d", VIDEO_DRIVER_NAME, pdev->id);
  329. ret = video_press_dts(pdev);
  330. if (ret) {
  331. video_err("%s[%d]:dts error!\n", __func__, __LINE__);
  332. return ret;
  333. }
  334. video_create_capabilities_sysfs(pdev);
  335. device_register_index++;
  336. video_info("exit %s:[%s%d]\n", __func__, VIDEO_DRIVER_NAME, pdev->id);
  337. return 0;
  338. }
  339. static int video_remove(struct platform_device *pdev)
  340. {
  341. struct video_drvdata *drvdata;
  342. video_info("enter %s\n", __func__);
  343. device_register_index--;
  344. drvdata = platform_get_drvdata(pdev);
  345. cdev_del(&drvdata->cdev);
  346. device_destroy(drvdata->class, drvdata->devt);
  347. unregister_chrdev_region(drvdata->devt, VIDEO_DRIVER_MAXCNT);
  348. mutex_destroy(&drvdata->mutex);
  349. video_remove_capabilities_sysfs(pdev);
  350. if (device_register_index == 0) {
  351. class_destroy(drvdata->class);
  352. }
  353. devm_kfree(&pdev->dev, drvdata);
  354. video_info("exit %s\n", __func__);
  355. return 0;
  356. }
  357. static const struct of_device_id video_of_match[] = {
  358. { .compatible = "thead,video", },
  359. { /* sentinel */ },
  360. };
  361. static struct platform_driver video_driver = {
  362. .probe = video_probe,
  363. .remove = video_remove,
  364. .driver = {
  365. .name = VIDEO_DRIVER_NAME,
  366. .owner = THIS_MODULE,
  367. .of_match_table = of_match_ptr(video_of_match),
  368. }
  369. };
  370. static int __init video_init_module(void)
  371. {
  372. int ret = 0;
  373. video_info("enter %s\n", __func__);
  374. ret = platform_driver_register(&video_driver);
  375. if (ret) {
  376. video_err("register platform driver failed.\n");
  377. return ret;
  378. }
  379. return ret;
  380. }
  381. static void __exit video_exit_module(void)
  382. {
  383. video_info("enter %s\n", __func__);
  384. platform_driver_unregister(&video_driver);
  385. }
  386. module_init(video_init_module);
  387. module_exit(video_exit_module);
  388. MODULE_AUTHOR("Liu Yitong");
  389. MODULE_DESCRIPTION("THEAD-VIDEO");
  390. MODULE_LICENSE("GPL");