vimc-core.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /*
  2. * vimc-core.c Virtual Media Controller Driver
  3. *
  4. * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. */
  17. #include <linux/init.h>
  18. #include <linux/module.h>
  19. #include <linux/platform_device.h>
  20. #include <media/media-device.h>
  21. #include <media/v4l2-device.h>
  22. #include "vimc-capture.h"
  23. #include "vimc-core.h"
  24. #include "vimc-sensor.h"
  25. #define VIMC_PDEV_NAME "vimc"
  26. #define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
  27. #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \
  28. .src_ent = src, \
  29. .src_pad = srcpad, \
  30. .sink_ent = sink, \
  31. .sink_pad = sinkpad, \
  32. .flags = link_flags, \
  33. }
  34. struct vimc_device {
  35. /*
  36. * The pipeline configuration
  37. * (filled before calling vimc_device_register)
  38. */
  39. const struct vimc_pipeline_config *pipe_cfg;
  40. /* The Associated media_device parent */
  41. struct media_device mdev;
  42. /* Internal v4l2 parent device*/
  43. struct v4l2_device v4l2_dev;
  44. /* Internal topology */
  45. struct vimc_ent_device **ved;
  46. };
  47. /**
  48. * enum vimc_ent_node - Select the functionality of a node in the topology
  49. * @VIMC_ENT_NODE_SENSOR: A node of type SENSOR simulates a camera sensor
  50. * generating internal images in bayer format and
  51. * propagating those images through the pipeline
  52. * @VIMC_ENT_NODE_CAPTURE: A node of type CAPTURE is a v4l2 video_device
  53. * that exposes the received image from the
  54. * pipeline to the user space
  55. * @VIMC_ENT_NODE_INPUT: A node of type INPUT is a v4l2 video_device that
  56. * receives images from the user space and
  57. * propagates them through the pipeline
  58. * @VIMC_ENT_NODE_DEBAYER: A node type DEBAYER expects to receive a frame
  59. * in bayer format converts it to RGB
  60. * @VIMC_ENT_NODE_SCALER: A node of type SCALER scales the received image
  61. * by a given multiplier
  62. *
  63. * This enum is used in the entity configuration struct to allow the definition
  64. * of a custom topology specifying the role of each node on it.
  65. */
  66. enum vimc_ent_node {
  67. VIMC_ENT_NODE_SENSOR,
  68. VIMC_ENT_NODE_CAPTURE,
  69. VIMC_ENT_NODE_INPUT,
  70. VIMC_ENT_NODE_DEBAYER,
  71. VIMC_ENT_NODE_SCALER,
  72. };
  73. /* Structure which describes individual configuration for each entity */
  74. struct vimc_ent_config {
  75. const char *name;
  76. size_t pads_qty;
  77. const unsigned long *pads_flag;
  78. enum vimc_ent_node node;
  79. };
  80. /* Structure which describes links between entities */
  81. struct vimc_ent_link {
  82. unsigned int src_ent;
  83. u16 src_pad;
  84. unsigned int sink_ent;
  85. u16 sink_pad;
  86. u32 flags;
  87. };
  88. /* Structure which describes the whole topology */
  89. struct vimc_pipeline_config {
  90. const struct vimc_ent_config *ents;
  91. size_t num_ents;
  92. const struct vimc_ent_link *links;
  93. size_t num_links;
  94. };
  95. /* --------------------------------------------------------------------------
  96. * Topology Configuration
  97. */
  98. static const struct vimc_ent_config ent_config[] = {
  99. {
  100. .name = "Sensor A",
  101. .pads_qty = 1,
  102. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE},
  103. .node = VIMC_ENT_NODE_SENSOR,
  104. },
  105. {
  106. .name = "Sensor B",
  107. .pads_qty = 1,
  108. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE},
  109. .node = VIMC_ENT_NODE_SENSOR,
  110. },
  111. {
  112. .name = "Debayer A",
  113. .pads_qty = 2,
  114. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK,
  115. MEDIA_PAD_FL_SOURCE},
  116. .node = VIMC_ENT_NODE_DEBAYER,
  117. },
  118. {
  119. .name = "Debayer B",
  120. .pads_qty = 2,
  121. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK,
  122. MEDIA_PAD_FL_SOURCE},
  123. .node = VIMC_ENT_NODE_DEBAYER,
  124. },
  125. {
  126. .name = "Raw Capture 0",
  127. .pads_qty = 1,
  128. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK},
  129. .node = VIMC_ENT_NODE_CAPTURE,
  130. },
  131. {
  132. .name = "Raw Capture 1",
  133. .pads_qty = 1,
  134. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK},
  135. .node = VIMC_ENT_NODE_CAPTURE,
  136. },
  137. {
  138. .name = "RGB/YUV Input",
  139. .pads_qty = 1,
  140. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE},
  141. .node = VIMC_ENT_NODE_INPUT,
  142. },
  143. {
  144. .name = "Scaler",
  145. .pads_qty = 2,
  146. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK,
  147. MEDIA_PAD_FL_SOURCE},
  148. .node = VIMC_ENT_NODE_SCALER,
  149. },
  150. {
  151. .name = "RGB/YUV Capture",
  152. .pads_qty = 1,
  153. .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK},
  154. .node = VIMC_ENT_NODE_CAPTURE,
  155. },
  156. };
  157. static const struct vimc_ent_link ent_links[] = {
  158. /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
  159. VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
  160. /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
  161. VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
  162. /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
  163. VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
  164. /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
  165. VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
  166. /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
  167. VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED),
  168. /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
  169. VIMC_ENT_LINK(3, 1, 7, 0, 0),
  170. /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
  171. VIMC_ENT_LINK(6, 0, 7, 0, 0),
  172. /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
  173. VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
  174. };
  175. static const struct vimc_pipeline_config pipe_cfg = {
  176. .ents = ent_config,
  177. .num_ents = ARRAY_SIZE(ent_config),
  178. .links = ent_links,
  179. .num_links = ARRAY_SIZE(ent_links)
  180. };
  181. /* -------------------------------------------------------------------------- */
  182. static const struct vimc_pix_map vimc_pix_map_list[] = {
  183. /* TODO: add all missing formats */
  184. /* RGB formats */
  185. {
  186. .code = MEDIA_BUS_FMT_BGR888_1X24,
  187. .pixelformat = V4L2_PIX_FMT_BGR24,
  188. .bpp = 3,
  189. },
  190. {
  191. .code = MEDIA_BUS_FMT_RGB888_1X24,
  192. .pixelformat = V4L2_PIX_FMT_RGB24,
  193. .bpp = 3,
  194. },
  195. {
  196. .code = MEDIA_BUS_FMT_ARGB8888_1X32,
  197. .pixelformat = V4L2_PIX_FMT_ARGB32,
  198. .bpp = 4,
  199. },
  200. /* Bayer formats */
  201. {
  202. .code = MEDIA_BUS_FMT_SBGGR8_1X8,
  203. .pixelformat = V4L2_PIX_FMT_SBGGR8,
  204. .bpp = 1,
  205. },
  206. {
  207. .code = MEDIA_BUS_FMT_SGBRG8_1X8,
  208. .pixelformat = V4L2_PIX_FMT_SGBRG8,
  209. .bpp = 1,
  210. },
  211. {
  212. .code = MEDIA_BUS_FMT_SGRBG8_1X8,
  213. .pixelformat = V4L2_PIX_FMT_SGRBG8,
  214. .bpp = 1,
  215. },
  216. {
  217. .code = MEDIA_BUS_FMT_SRGGB8_1X8,
  218. .pixelformat = V4L2_PIX_FMT_SRGGB8,
  219. .bpp = 1,
  220. },
  221. {
  222. .code = MEDIA_BUS_FMT_SBGGR10_1X10,
  223. .pixelformat = V4L2_PIX_FMT_SBGGR10,
  224. .bpp = 2,
  225. },
  226. {
  227. .code = MEDIA_BUS_FMT_SGBRG10_1X10,
  228. .pixelformat = V4L2_PIX_FMT_SGBRG10,
  229. .bpp = 2,
  230. },
  231. {
  232. .code = MEDIA_BUS_FMT_SGRBG10_1X10,
  233. .pixelformat = V4L2_PIX_FMT_SGRBG10,
  234. .bpp = 2,
  235. },
  236. {
  237. .code = MEDIA_BUS_FMT_SRGGB10_1X10,
  238. .pixelformat = V4L2_PIX_FMT_SRGGB10,
  239. .bpp = 2,
  240. },
  241. /* 10bit raw bayer a-law compressed to 8 bits */
  242. {
  243. .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8,
  244. .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
  245. .bpp = 1,
  246. },
  247. {
  248. .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8,
  249. .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
  250. .bpp = 1,
  251. },
  252. {
  253. .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
  254. .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
  255. .bpp = 1,
  256. },
  257. {
  258. .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,
  259. .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
  260. .bpp = 1,
  261. },
  262. /* 10bit raw bayer DPCM compressed to 8 bits */
  263. {
  264. .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
  265. .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
  266. .bpp = 1,
  267. },
  268. {
  269. .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
  270. .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
  271. .bpp = 1,
  272. },
  273. {
  274. .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
  275. .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
  276. .bpp = 1,
  277. },
  278. {
  279. .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
  280. .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
  281. .bpp = 1,
  282. },
  283. {
  284. .code = MEDIA_BUS_FMT_SBGGR12_1X12,
  285. .pixelformat = V4L2_PIX_FMT_SBGGR12,
  286. .bpp = 2,
  287. },
  288. {
  289. .code = MEDIA_BUS_FMT_SGBRG12_1X12,
  290. .pixelformat = V4L2_PIX_FMT_SGBRG12,
  291. .bpp = 2,
  292. },
  293. {
  294. .code = MEDIA_BUS_FMT_SGRBG12_1X12,
  295. .pixelformat = V4L2_PIX_FMT_SGRBG12,
  296. .bpp = 2,
  297. },
  298. {
  299. .code = MEDIA_BUS_FMT_SRGGB12_1X12,
  300. .pixelformat = V4L2_PIX_FMT_SRGGB12,
  301. .bpp = 2,
  302. },
  303. };
  304. const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
  305. {
  306. unsigned int i;
  307. for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
  308. if (vimc_pix_map_list[i].code == code)
  309. return &vimc_pix_map_list[i];
  310. }
  311. return NULL;
  312. }
  313. const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
  314. {
  315. unsigned int i;
  316. for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
  317. if (vimc_pix_map_list[i].pixelformat == pixelformat)
  318. return &vimc_pix_map_list[i];
  319. }
  320. return NULL;
  321. }
  322. int vimc_propagate_frame(struct media_pad *src, const void *frame)
  323. {
  324. struct media_link *link;
  325. if (!(src->flags & MEDIA_PAD_FL_SOURCE))
  326. return -EINVAL;
  327. /* Send this frame to all sink pads that are direct linked */
  328. list_for_each_entry(link, &src->entity->links, list) {
  329. if (link->source == src &&
  330. (link->flags & MEDIA_LNK_FL_ENABLED)) {
  331. struct vimc_ent_device *ved = NULL;
  332. struct media_entity *entity = link->sink->entity;
  333. if (is_media_entity_v4l2_subdev(entity)) {
  334. struct v4l2_subdev *sd =
  335. container_of(entity, struct v4l2_subdev,
  336. entity);
  337. ved = v4l2_get_subdevdata(sd);
  338. } else if (is_media_entity_v4l2_video_device(entity)) {
  339. struct video_device *vdev =
  340. container_of(entity,
  341. struct video_device,
  342. entity);
  343. ved = video_get_drvdata(vdev);
  344. }
  345. if (ved && ved->process_frame)
  346. ved->process_frame(ved, link->sink, frame);
  347. }
  348. }
  349. return 0;
  350. }
  351. static void vimc_device_unregister(struct vimc_device *vimc)
  352. {
  353. unsigned int i;
  354. media_device_unregister(&vimc->mdev);
  355. /* Cleanup (only initialized) entities */
  356. for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
  357. if (vimc->ved[i] && vimc->ved[i]->destroy)
  358. vimc->ved[i]->destroy(vimc->ved[i]);
  359. vimc->ved[i] = NULL;
  360. }
  361. v4l2_device_unregister(&vimc->v4l2_dev);
  362. media_device_cleanup(&vimc->mdev);
  363. }
  364. /* Helper function to allocate and initialize pads */
  365. struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
  366. {
  367. struct media_pad *pads;
  368. unsigned int i;
  369. /* Allocate memory for the pads */
  370. pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL);
  371. if (!pads)
  372. return ERR_PTR(-ENOMEM);
  373. /* Initialize the pads */
  374. for (i = 0; i < num_pads; i++) {
  375. pads[i].index = i;
  376. pads[i].flags = pads_flag[i];
  377. }
  378. return pads;
  379. }
  380. /*
  381. * TODO: remove this function when all the
  382. * entities specific code are implemented
  383. */
  384. static void vimc_raw_destroy(struct vimc_ent_device *ved)
  385. {
  386. media_device_unregister_entity(ved->ent);
  387. media_entity_cleanup(ved->ent);
  388. vimc_pads_cleanup(ved->pads);
  389. kfree(ved->ent);
  390. kfree(ved);
  391. }
  392. /*
  393. * TODO: remove this function when all the
  394. * entities specific code are implemented
  395. */
  396. static struct vimc_ent_device *vimc_raw_create(struct v4l2_device *v4l2_dev,
  397. const char *const name,
  398. u16 num_pads,
  399. const unsigned long *pads_flag)
  400. {
  401. struct vimc_ent_device *ved;
  402. int ret;
  403. /* Allocate the main ved struct */
  404. ved = kzalloc(sizeof(*ved), GFP_KERNEL);
  405. if (!ved)
  406. return ERR_PTR(-ENOMEM);
  407. /* Allocate the media entity */
  408. ved->ent = kzalloc(sizeof(*ved->ent), GFP_KERNEL);
  409. if (!ved->ent) {
  410. ret = -ENOMEM;
  411. goto err_free_ved;
  412. }
  413. /* Allocate the pads */
  414. ved->pads = vimc_pads_init(num_pads, pads_flag);
  415. if (IS_ERR(ved->pads)) {
  416. ret = PTR_ERR(ved->pads);
  417. goto err_free_ent;
  418. }
  419. /* Initialize the media entity */
  420. ved->ent->name = name;
  421. ved->ent->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
  422. ret = media_entity_pads_init(ved->ent, num_pads, ved->pads);
  423. if (ret)
  424. goto err_cleanup_pads;
  425. /* Register the media entity */
  426. ret = media_device_register_entity(v4l2_dev->mdev, ved->ent);
  427. if (ret)
  428. goto err_cleanup_entity;
  429. /* Fill out the destroy function and return */
  430. ved->destroy = vimc_raw_destroy;
  431. return ved;
  432. err_cleanup_entity:
  433. media_entity_cleanup(ved->ent);
  434. err_cleanup_pads:
  435. vimc_pads_cleanup(ved->pads);
  436. err_free_ent:
  437. kfree(ved->ent);
  438. err_free_ved:
  439. kfree(ved);
  440. return ERR_PTR(ret);
  441. }
  442. static int vimc_device_register(struct vimc_device *vimc)
  443. {
  444. unsigned int i;
  445. int ret;
  446. /* Allocate memory for the vimc_ent_devices pointers */
  447. vimc->ved = devm_kcalloc(vimc->mdev.dev, vimc->pipe_cfg->num_ents,
  448. sizeof(*vimc->ved), GFP_KERNEL);
  449. if (!vimc->ved)
  450. return -ENOMEM;
  451. /* Link the media device within the v4l2_device */
  452. vimc->v4l2_dev.mdev = &vimc->mdev;
  453. /* Register the v4l2 struct */
  454. ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev);
  455. if (ret) {
  456. dev_err(vimc->mdev.dev,
  457. "v4l2 device register failed (err=%d)\n", ret);
  458. return ret;
  459. }
  460. /* Initialize entities */
  461. for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
  462. struct vimc_ent_device *(*create_func)(struct v4l2_device *,
  463. const char *const,
  464. u16,
  465. const unsigned long *);
  466. /* Register the specific node */
  467. switch (vimc->pipe_cfg->ents[i].node) {
  468. case VIMC_ENT_NODE_SENSOR:
  469. create_func = vimc_sen_create;
  470. break;
  471. case VIMC_ENT_NODE_CAPTURE:
  472. create_func = vimc_cap_create;
  473. break;
  474. /* TODO: Instantiate the specific topology node */
  475. case VIMC_ENT_NODE_INPUT:
  476. case VIMC_ENT_NODE_DEBAYER:
  477. case VIMC_ENT_NODE_SCALER:
  478. default:
  479. /*
  480. * TODO: remove this when all the entities specific
  481. * code are implemented
  482. */
  483. create_func = vimc_raw_create;
  484. break;
  485. }
  486. vimc->ved[i] = create_func(&vimc->v4l2_dev,
  487. vimc->pipe_cfg->ents[i].name,
  488. vimc->pipe_cfg->ents[i].pads_qty,
  489. vimc->pipe_cfg->ents[i].pads_flag);
  490. if (IS_ERR(vimc->ved[i])) {
  491. ret = PTR_ERR(vimc->ved[i]);
  492. vimc->ved[i] = NULL;
  493. goto err;
  494. }
  495. }
  496. /* Initialize the links between entities */
  497. for (i = 0; i < vimc->pipe_cfg->num_links; i++) {
  498. const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i];
  499. ret = media_create_pad_link(vimc->ved[link->src_ent]->ent,
  500. link->src_pad,
  501. vimc->ved[link->sink_ent]->ent,
  502. link->sink_pad,
  503. link->flags);
  504. if (ret)
  505. goto err;
  506. }
  507. /* Register the media device */
  508. ret = media_device_register(&vimc->mdev);
  509. if (ret) {
  510. dev_err(vimc->mdev.dev,
  511. "media device register failed (err=%d)\n", ret);
  512. return ret;
  513. }
  514. /* Expose all subdev's nodes*/
  515. ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev);
  516. if (ret) {
  517. dev_err(vimc->mdev.dev,
  518. "vimc subdev nodes registration failed (err=%d)\n",
  519. ret);
  520. goto err;
  521. }
  522. return 0;
  523. err:
  524. /* Destroy the so far created topology */
  525. vimc_device_unregister(vimc);
  526. return ret;
  527. }
  528. static int vimc_probe(struct platform_device *pdev)
  529. {
  530. struct vimc_device *vimc;
  531. int ret;
  532. /* Prepare the vimc topology structure */
  533. /* Allocate memory for the vimc structure */
  534. vimc = kzalloc(sizeof(*vimc), GFP_KERNEL);
  535. if (!vimc)
  536. return -ENOMEM;
  537. /* Set the pipeline configuration struct */
  538. vimc->pipe_cfg = &pipe_cfg;
  539. /* Initialize media device */
  540. strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,
  541. sizeof(vimc->mdev.model));
  542. vimc->mdev.dev = &pdev->dev;
  543. media_device_init(&vimc->mdev);
  544. /* Create vimc topology */
  545. ret = vimc_device_register(vimc);
  546. if (ret) {
  547. dev_err(vimc->mdev.dev,
  548. "vimc device registration failed (err=%d)\n", ret);
  549. kfree(vimc);
  550. return ret;
  551. }
  552. /* Link the topology object with the platform device object */
  553. platform_set_drvdata(pdev, vimc);
  554. return 0;
  555. }
  556. static int vimc_remove(struct platform_device *pdev)
  557. {
  558. struct vimc_device *vimc = platform_get_drvdata(pdev);
  559. /* Destroy all the topology */
  560. vimc_device_unregister(vimc);
  561. kfree(vimc);
  562. return 0;
  563. }
  564. static void vimc_dev_release(struct device *dev)
  565. {
  566. }
  567. static struct platform_device vimc_pdev = {
  568. .name = VIMC_PDEV_NAME,
  569. .dev.release = vimc_dev_release,
  570. };
  571. static struct platform_driver vimc_pdrv = {
  572. .probe = vimc_probe,
  573. .remove = vimc_remove,
  574. .driver = {
  575. .name = VIMC_PDEV_NAME,
  576. },
  577. };
  578. static int __init vimc_init(void)
  579. {
  580. int ret;
  581. ret = platform_device_register(&vimc_pdev);
  582. if (ret) {
  583. dev_err(&vimc_pdev.dev,
  584. "platform device registration failed (err=%d)\n", ret);
  585. return ret;
  586. }
  587. ret = platform_driver_register(&vimc_pdrv);
  588. if (ret) {
  589. dev_err(&vimc_pdev.dev,
  590. "platform driver registration failed (err=%d)\n", ret);
  591. platform_device_unregister(&vimc_pdev);
  592. }
  593. return ret;
  594. }
  595. static void __exit vimc_exit(void)
  596. {
  597. platform_driver_unregister(&vimc_pdrv);
  598. platform_device_unregister(&vimc_pdev);
  599. }
  600. module_init(vimc_init);
  601. module_exit(vimc_exit);
  602. MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)");
  603. MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>");
  604. MODULE_LICENSE("GPL");