blob: 3afbabd739a5ef56b4370fcb99ec59cc347a7bc2 [file] [log] [blame]
Helen Fornazier5ba0ae42017-06-19 14:00:11 -03001/*
2 * vimc-common.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
18#include "vimc-common.h"
19
20static const struct vimc_pix_map vimc_pix_map_list[] = {
21 /* TODO: add all missing formats */
22
23 /* RGB formats */
24 {
25 .code = MEDIA_BUS_FMT_BGR888_1X24,
26 .pixelformat = V4L2_PIX_FMT_BGR24,
27 .bpp = 3,
28 },
29 {
30 .code = MEDIA_BUS_FMT_RGB888_1X24,
31 .pixelformat = V4L2_PIX_FMT_RGB24,
32 .bpp = 3,
33 },
34 {
35 .code = MEDIA_BUS_FMT_ARGB8888_1X32,
36 .pixelformat = V4L2_PIX_FMT_ARGB32,
37 .bpp = 4,
38 },
39
40 /* Bayer formats */
41 {
42 .code = MEDIA_BUS_FMT_SBGGR8_1X8,
43 .pixelformat = V4L2_PIX_FMT_SBGGR8,
44 .bpp = 1,
45 },
46 {
47 .code = MEDIA_BUS_FMT_SGBRG8_1X8,
48 .pixelformat = V4L2_PIX_FMT_SGBRG8,
49 .bpp = 1,
50 },
51 {
52 .code = MEDIA_BUS_FMT_SGRBG8_1X8,
53 .pixelformat = V4L2_PIX_FMT_SGRBG8,
54 .bpp = 1,
55 },
56 {
57 .code = MEDIA_BUS_FMT_SRGGB8_1X8,
58 .pixelformat = V4L2_PIX_FMT_SRGGB8,
59 .bpp = 1,
60 },
61 {
62 .code = MEDIA_BUS_FMT_SBGGR10_1X10,
63 .pixelformat = V4L2_PIX_FMT_SBGGR10,
64 .bpp = 2,
65 },
66 {
67 .code = MEDIA_BUS_FMT_SGBRG10_1X10,
68 .pixelformat = V4L2_PIX_FMT_SGBRG10,
69 .bpp = 2,
70 },
71 {
72 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
73 .pixelformat = V4L2_PIX_FMT_SGRBG10,
74 .bpp = 2,
75 },
76 {
77 .code = MEDIA_BUS_FMT_SRGGB10_1X10,
78 .pixelformat = V4L2_PIX_FMT_SRGGB10,
79 .bpp = 2,
80 },
81
82 /* 10bit raw bayer a-law compressed to 8 bits */
83 {
84 .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8,
85 .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
86 .bpp = 1,
87 },
88 {
89 .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8,
90 .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
91 .bpp = 1,
92 },
93 {
94 .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
95 .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
96 .bpp = 1,
97 },
98 {
99 .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,
100 .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
101 .bpp = 1,
102 },
103
104 /* 10bit raw bayer DPCM compressed to 8 bits */
105 {
106 .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
107 .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
108 .bpp = 1,
109 },
110 {
111 .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
112 .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
113 .bpp = 1,
114 },
115 {
116 .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
117 .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
118 .bpp = 1,
119 },
120 {
121 .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
122 .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
123 .bpp = 1,
124 },
125 {
126 .code = MEDIA_BUS_FMT_SBGGR12_1X12,
127 .pixelformat = V4L2_PIX_FMT_SBGGR12,
128 .bpp = 2,
129 },
130 {
131 .code = MEDIA_BUS_FMT_SGBRG12_1X12,
132 .pixelformat = V4L2_PIX_FMT_SGBRG12,
133 .bpp = 2,
134 },
135 {
136 .code = MEDIA_BUS_FMT_SGRBG12_1X12,
137 .pixelformat = V4L2_PIX_FMT_SGRBG12,
138 .bpp = 2,
139 },
140 {
141 .code = MEDIA_BUS_FMT_SRGGB12_1X12,
142 .pixelformat = V4L2_PIX_FMT_SRGGB12,
143 .bpp = 2,
144 },
145};
146
147const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
148{
149 unsigned int i;
150
151 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
152 if (vimc_pix_map_list[i].code == code)
153 return &vimc_pix_map_list[i];
154 }
155 return NULL;
156}
157
158const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
159{
160 unsigned int i;
161
162 for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
163 if (vimc_pix_map_list[i].pixelformat == pixelformat)
164 return &vimc_pix_map_list[i];
165 }
166 return NULL;
167}
168
169int vimc_propagate_frame(struct media_pad *src, const void *frame)
170{
171 struct media_link *link;
172
173 if (!(src->flags & MEDIA_PAD_FL_SOURCE))
174 return -EINVAL;
175
176 /* Send this frame to all sink pads that are direct linked */
177 list_for_each_entry(link, &src->entity->links, list) {
178 if (link->source == src &&
179 (link->flags & MEDIA_LNK_FL_ENABLED)) {
180 struct vimc_ent_device *ved = NULL;
181 struct media_entity *entity = link->sink->entity;
182
183 if (is_media_entity_v4l2_subdev(entity)) {
184 struct v4l2_subdev *sd =
185 container_of(entity, struct v4l2_subdev,
186 entity);
187 ved = v4l2_get_subdevdata(sd);
188 } else if (is_media_entity_v4l2_video_device(entity)) {
189 struct video_device *vdev =
190 container_of(entity,
191 struct video_device,
192 entity);
193 ved = video_get_drvdata(vdev);
194 }
195 if (ved && ved->process_frame)
196 ved->process_frame(ved, link->sink, frame);
197 }
198 }
199
200 return 0;
201}
202
203/* Helper function to allocate and initialize pads */
204struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
205{
206 struct media_pad *pads;
207 unsigned int i;
208
209 /* Allocate memory for the pads */
210 pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL);
211 if (!pads)
212 return ERR_PTR(-ENOMEM);
213
214 /* Initialize the pads */
215 for (i = 0; i < num_pads; i++) {
216 pads[i].index = i;
217 pads[i].flags = pads_flag[i];
218 }
219
220 return pads;
221}
Helen Fornazierc1495432017-06-19 14:00:12 -0300222
223static const struct media_entity_operations vimc_ent_sd_mops = {
224 .link_validate = v4l2_subdev_link_validate,
225};
226
227int vimc_ent_sd_register(struct vimc_ent_device *ved,
228 struct v4l2_subdev *sd,
229 struct v4l2_device *v4l2_dev,
230 const char *const name,
231 u32 function,
232 u16 num_pads,
233 const unsigned long *pads_flag,
234 const struct v4l2_subdev_ops *sd_ops,
235 void (*sd_destroy)(struct vimc_ent_device *))
236{
237 int ret;
238
239 /* Allocate the pads */
240 ved->pads = vimc_pads_init(num_pads, pads_flag);
241 if (IS_ERR(ved->pads))
242 return PTR_ERR(ved->pads);
243
244 /* Fill the vimc_ent_device struct */
245 ved->destroy = sd_destroy;
246 ved->ent = &sd->entity;
247
248 /* Initialize the subdev */
249 v4l2_subdev_init(sd, sd_ops);
250 sd->entity.function = function;
251 sd->entity.ops = &vimc_ent_sd_mops;
252 sd->owner = THIS_MODULE;
253 strlcpy(sd->name, name, sizeof(sd->name));
254 v4l2_set_subdevdata(sd, ved);
255
256 /* Expose this subdev to user space */
257 sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
258
259 /* Initialize the media entity */
260 ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads);
261 if (ret)
262 goto err_clean_pads;
263
264 /* Register the subdev with the v4l2 and the media framework */
265 ret = v4l2_device_register_subdev(v4l2_dev, sd);
266 if (ret) {
267 dev_err(v4l2_dev->dev,
268 "%s: subdev register failed (err=%d)\n",
269 name, ret);
270 goto err_clean_m_ent;
271 }
272
273 return 0;
274
275err_clean_m_ent:
276 media_entity_cleanup(&sd->entity);
277err_clean_pads:
278 vimc_pads_cleanup(ved->pads);
279 return ret;
280}
281
282void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)
283{
284 v4l2_device_unregister_subdev(sd);
285 media_entity_cleanup(ved->ent);
286 vimc_pads_cleanup(ved->pads);
287}