1*1b4853f5SAndroid Build Coastguard Worker // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0+
2*1b4853f5SAndroid Build Coastguard Worker
3*1b4853f5SAndroid Build Coastguard Worker /*
4*1b4853f5SAndroid Build Coastguard Worker * Ioctls implementations for the virtio-media driver.
5*1b4853f5SAndroid Build Coastguard Worker *
6*1b4853f5SAndroid Build Coastguard Worker * Copyright (c) 2023-2024 Google LLC.
7*1b4853f5SAndroid Build Coastguard Worker */
8*1b4853f5SAndroid Build Coastguard Worker
9*1b4853f5SAndroid Build Coastguard Worker #include <linux/virtio_config.h>
10*1b4853f5SAndroid Build Coastguard Worker #include <linux/vmalloc.h>
11*1b4853f5SAndroid Build Coastguard Worker #include <media/v4l2-event.h>
12*1b4853f5SAndroid Build Coastguard Worker #include <media/v4l2-ioctl.h>
13*1b4853f5SAndroid Build Coastguard Worker
14*1b4853f5SAndroid Build Coastguard Worker #include "scatterlist_filler.h"
15*1b4853f5SAndroid Build Coastguard Worker #include "virtio_media.h"
16*1b4853f5SAndroid Build Coastguard Worker
17*1b4853f5SAndroid Build Coastguard Worker /**
18*1b4853f5SAndroid Build Coastguard Worker * Send an ioctl that has no driver payload, but expects a reponse from the host (i.e. an
19*1b4853f5SAndroid Build Coastguard Worker * ioctl specified with _IOR).
20*1b4853f5SAndroid Build Coastguard Worker *
21*1b4853f5SAndroid Build Coastguard Worker * Returns 0 in case of success, or a negative error code.
22*1b4853f5SAndroid Build Coastguard Worker */
virtio_media_send_r_ioctl(struct v4l2_fh * fh,u32 ioctl,void * ioctl_data,size_t ioctl_data_len)23*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_send_r_ioctl(struct v4l2_fh *fh, u32 ioctl,
24*1b4853f5SAndroid Build Coastguard Worker void *ioctl_data, size_t ioctl_data_len)
25*1b4853f5SAndroid Build Coastguard Worker {
26*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = fh->vdev;
27*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
28*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
29*1b4853f5SAndroid Build Coastguard Worker struct scatterlist *sgs[3];
30*1b4853f5SAndroid Build Coastguard Worker struct scatterlist_filler filler = {
31*1b4853f5SAndroid Build Coastguard Worker .descs = session->command_sgs.sgl,
32*1b4853f5SAndroid Build Coastguard Worker .num_descs = DESC_CHAIN_MAX_LEN,
33*1b4853f5SAndroid Build Coastguard Worker .cur_desc = 0,
34*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer = session->shadow_buf,
35*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_size = VIRTIO_SHADOW_BUF_SIZE,
36*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_pos = 0,
37*1b4853f5SAndroid Build Coastguard Worker .sgs = sgs,
38*1b4853f5SAndroid Build Coastguard Worker .num_sgs = ARRAY_SIZE(sgs),
39*1b4853f5SAndroid Build Coastguard Worker .cur_sg = 0,
40*1b4853f5SAndroid Build Coastguard Worker };
41*1b4853f5SAndroid Build Coastguard Worker int ret;
42*1b4853f5SAndroid Build Coastguard Worker
43*1b4853f5SAndroid Build Coastguard Worker /* Command descriptor */
44*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_cmd(&filler, session, ioctl);
45*1b4853f5SAndroid Build Coastguard Worker if (ret)
46*1b4853f5SAndroid Build Coastguard Worker return ret;
47*1b4853f5SAndroid Build Coastguard Worker
48*1b4853f5SAndroid Build Coastguard Worker /* Response descriptor */
49*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_resp(&filler, session);
50*1b4853f5SAndroid Build Coastguard Worker if (ret)
51*1b4853f5SAndroid Build Coastguard Worker return ret;
52*1b4853f5SAndroid Build Coastguard Worker
53*1b4853f5SAndroid Build Coastguard Worker /* Response payload */
54*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_data(&filler, ioctl_data, ioctl_data_len);
55*1b4853f5SAndroid Build Coastguard Worker if (ret) {
56*1b4853f5SAndroid Build Coastguard Worker v4l2_err(&vv->v4l2_dev,
57*1b4853f5SAndroid Build Coastguard Worker "failed to prepare command descriptor chain\n");
58*1b4853f5SAndroid Build Coastguard Worker return ret;
59*1b4853f5SAndroid Build Coastguard Worker }
60*1b4853f5SAndroid Build Coastguard Worker
61*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_command(
62*1b4853f5SAndroid Build Coastguard Worker vv, sgs, 1, 2,
63*1b4853f5SAndroid Build Coastguard Worker sizeof(struct virtio_media_resp_ioctl) + ioctl_data_len, NULL);
64*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
65*1b4853f5SAndroid Build Coastguard Worker return ret;
66*1b4853f5SAndroid Build Coastguard Worker
67*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_retrieve_data(session, filler.sgs[2],
68*1b4853f5SAndroid Build Coastguard Worker ioctl_data, ioctl_data_len);
69*1b4853f5SAndroid Build Coastguard Worker if (ret) {
70*1b4853f5SAndroid Build Coastguard Worker v4l2_err(&vv->v4l2_dev,
71*1b4853f5SAndroid Build Coastguard Worker "failed to retrieve response descriptor chain\n");
72*1b4853f5SAndroid Build Coastguard Worker return ret;
73*1b4853f5SAndroid Build Coastguard Worker }
74*1b4853f5SAndroid Build Coastguard Worker
75*1b4853f5SAndroid Build Coastguard Worker return 0;
76*1b4853f5SAndroid Build Coastguard Worker }
77*1b4853f5SAndroid Build Coastguard Worker /**
78*1b4853f5SAndroid Build Coastguard Worker * Send an ioctl that does not expect a reply beyond an error status (i.e. an
79*1b4853f5SAndroid Build Coastguard Worker * ioctl specified with _IOW) to the host.
80*1b4853f5SAndroid Build Coastguard Worker *
81*1b4853f5SAndroid Build Coastguard Worker * Returns 0 in case of success, or a negative error code.
82*1b4853f5SAndroid Build Coastguard Worker */
virtio_media_send_w_ioctl(struct v4l2_fh * fh,u32 ioctl,const void * ioctl_data,size_t ioctl_data_len)83*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_send_w_ioctl(struct v4l2_fh *fh, u32 ioctl,
84*1b4853f5SAndroid Build Coastguard Worker const void *ioctl_data,
85*1b4853f5SAndroid Build Coastguard Worker size_t ioctl_data_len)
86*1b4853f5SAndroid Build Coastguard Worker {
87*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = fh->vdev;
88*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
89*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
90*1b4853f5SAndroid Build Coastguard Worker struct scatterlist *sgs[3];
91*1b4853f5SAndroid Build Coastguard Worker struct scatterlist_filler filler = {
92*1b4853f5SAndroid Build Coastguard Worker .descs = session->command_sgs.sgl,
93*1b4853f5SAndroid Build Coastguard Worker .num_descs = DESC_CHAIN_MAX_LEN,
94*1b4853f5SAndroid Build Coastguard Worker .cur_desc = 0,
95*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer = session->shadow_buf,
96*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_size = VIRTIO_SHADOW_BUF_SIZE,
97*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_pos = 0,
98*1b4853f5SAndroid Build Coastguard Worker .sgs = sgs,
99*1b4853f5SAndroid Build Coastguard Worker .num_sgs = ARRAY_SIZE(sgs),
100*1b4853f5SAndroid Build Coastguard Worker .cur_sg = 0,
101*1b4853f5SAndroid Build Coastguard Worker };
102*1b4853f5SAndroid Build Coastguard Worker int ret;
103*1b4853f5SAndroid Build Coastguard Worker
104*1b4853f5SAndroid Build Coastguard Worker /* Command descriptor */
105*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_cmd(&filler, session, ioctl);
106*1b4853f5SAndroid Build Coastguard Worker if (ret)
107*1b4853f5SAndroid Build Coastguard Worker return ret;
108*1b4853f5SAndroid Build Coastguard Worker
109*1b4853f5SAndroid Build Coastguard Worker /* Command payload */
110*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_data(&filler, (void *)ioctl_data,
111*1b4853f5SAndroid Build Coastguard Worker ioctl_data_len);
112*1b4853f5SAndroid Build Coastguard Worker if (ret) {
113*1b4853f5SAndroid Build Coastguard Worker v4l2_err(&vv->v4l2_dev,
114*1b4853f5SAndroid Build Coastguard Worker "failed to prepare command descriptor chain\n");
115*1b4853f5SAndroid Build Coastguard Worker return ret;
116*1b4853f5SAndroid Build Coastguard Worker }
117*1b4853f5SAndroid Build Coastguard Worker
118*1b4853f5SAndroid Build Coastguard Worker /* Response descriptor */
119*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_resp(&filler, session);
120*1b4853f5SAndroid Build Coastguard Worker if (ret)
121*1b4853f5SAndroid Build Coastguard Worker return ret;
122*1b4853f5SAndroid Build Coastguard Worker
123*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_command(
124*1b4853f5SAndroid Build Coastguard Worker vv, sgs, 2, 1, sizeof(struct virtio_media_resp_ioctl), NULL);
125*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
126*1b4853f5SAndroid Build Coastguard Worker return ret;
127*1b4853f5SAndroid Build Coastguard Worker
128*1b4853f5SAndroid Build Coastguard Worker return 0;
129*1b4853f5SAndroid Build Coastguard Worker }
130*1b4853f5SAndroid Build Coastguard Worker
131*1b4853f5SAndroid Build Coastguard Worker /**
132*1b4853f5SAndroid Build Coastguard Worker * Sends an ioctl that expects a response of exactly the same size as the
133*1b4853f5SAndroid Build Coastguard Worker * input (i.e. an ioctl specified with _IOWR) to the host.
134*1b4853f5SAndroid Build Coastguard Worker *
135*1b4853f5SAndroid Build Coastguard Worker * This corresponds to what most V4L2 ioctls do. For instance VIDIOC_ENUM_FMT
136*1b4853f5SAndroid Build Coastguard Worker * takes a partially-initialized struct v4l2_fmtdesc and returns its filled
137*1b4853f5SAndroid Build Coastguard Worker * version.
138*1b4853f5SAndroid Build Coastguard Worker *
139*1b4853f5SAndroid Build Coastguard Worker * Ioctls specified with _IOR can also use this, since the host will simply
140*1b4853f5SAndroid Build Coastguard Worker * ignore the extra input data provided.
141*1b4853f5SAndroid Build Coastguard Worker *
142*1b4853f5SAndroid Build Coastguard Worker * Returns 0 in case of success, or a negative error code.
143*1b4853f5SAndroid Build Coastguard Worker */
virtio_media_send_wr_ioctl(struct v4l2_fh * fh,u32 ioctl,void * ioctl_data,size_t ioctl_data_len,size_t min_resp_payload)144*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_send_wr_ioctl(struct v4l2_fh *fh, u32 ioctl,
145*1b4853f5SAndroid Build Coastguard Worker void *ioctl_data, size_t ioctl_data_len,
146*1b4853f5SAndroid Build Coastguard Worker size_t min_resp_payload)
147*1b4853f5SAndroid Build Coastguard Worker {
148*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = fh->vdev;
149*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
150*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
151*1b4853f5SAndroid Build Coastguard Worker struct scatterlist *sgs[4];
152*1b4853f5SAndroid Build Coastguard Worker struct scatterlist_filler filler = {
153*1b4853f5SAndroid Build Coastguard Worker .descs = session->command_sgs.sgl,
154*1b4853f5SAndroid Build Coastguard Worker .num_descs = DESC_CHAIN_MAX_LEN,
155*1b4853f5SAndroid Build Coastguard Worker .cur_desc = 0,
156*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer = session->shadow_buf,
157*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_size = VIRTIO_SHADOW_BUF_SIZE,
158*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_pos = 0,
159*1b4853f5SAndroid Build Coastguard Worker .sgs = sgs,
160*1b4853f5SAndroid Build Coastguard Worker .num_sgs = ARRAY_SIZE(sgs),
161*1b4853f5SAndroid Build Coastguard Worker .cur_sg = 0,
162*1b4853f5SAndroid Build Coastguard Worker };
163*1b4853f5SAndroid Build Coastguard Worker int ret;
164*1b4853f5SAndroid Build Coastguard Worker
165*1b4853f5SAndroid Build Coastguard Worker /* Command descriptor */
166*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_cmd(&filler, session, ioctl);
167*1b4853f5SAndroid Build Coastguard Worker if (ret)
168*1b4853f5SAndroid Build Coastguard Worker return ret;
169*1b4853f5SAndroid Build Coastguard Worker
170*1b4853f5SAndroid Build Coastguard Worker /* Command payload */
171*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_data(&filler, ioctl_data, ioctl_data_len);
172*1b4853f5SAndroid Build Coastguard Worker if (ret) {
173*1b4853f5SAndroid Build Coastguard Worker v4l2_err(&vv->v4l2_dev,
174*1b4853f5SAndroid Build Coastguard Worker "failed to prepare command descriptor chain\n");
175*1b4853f5SAndroid Build Coastguard Worker return ret;
176*1b4853f5SAndroid Build Coastguard Worker }
177*1b4853f5SAndroid Build Coastguard Worker
178*1b4853f5SAndroid Build Coastguard Worker /* Response descriptor */
179*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_resp(&filler, session);
180*1b4853f5SAndroid Build Coastguard Worker if (ret)
181*1b4853f5SAndroid Build Coastguard Worker return ret;
182*1b4853f5SAndroid Build Coastguard Worker
183*1b4853f5SAndroid Build Coastguard Worker /* Response payload, same as command */
184*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_sg(&filler, filler.sgs[1]);
185*1b4853f5SAndroid Build Coastguard Worker if (ret)
186*1b4853f5SAndroid Build Coastguard Worker return ret;
187*1b4853f5SAndroid Build Coastguard Worker
188*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_command(vv, sgs, 2, 2,
189*1b4853f5SAndroid Build Coastguard Worker sizeof(struct virtio_media_resp_ioctl) +
190*1b4853f5SAndroid Build Coastguard Worker min_resp_payload,
191*1b4853f5SAndroid Build Coastguard Worker NULL);
192*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
193*1b4853f5SAndroid Build Coastguard Worker return ret;
194*1b4853f5SAndroid Build Coastguard Worker
195*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_retrieve_data(session, filler.sgs[3],
196*1b4853f5SAndroid Build Coastguard Worker ioctl_data, ioctl_data_len);
197*1b4853f5SAndroid Build Coastguard Worker if (ret) {
198*1b4853f5SAndroid Build Coastguard Worker v4l2_err(&vv->v4l2_dev,
199*1b4853f5SAndroid Build Coastguard Worker "failed to retrieve response descriptor chain\n");
200*1b4853f5SAndroid Build Coastguard Worker return ret;
201*1b4853f5SAndroid Build Coastguard Worker }
202*1b4853f5SAndroid Build Coastguard Worker
203*1b4853f5SAndroid Build Coastguard Worker return 0;
204*1b4853f5SAndroid Build Coastguard Worker }
205*1b4853f5SAndroid Build Coastguard Worker
virtio_media_send_buffer_ioctl(struct v4l2_fh * fh,u32 ioctl_code,struct v4l2_buffer * b)206*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_send_buffer_ioctl(struct v4l2_fh *fh, u32 ioctl_code,
207*1b4853f5SAndroid Build Coastguard Worker struct v4l2_buffer *b)
208*1b4853f5SAndroid Build Coastguard Worker {
209*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = fh->vdev;
210*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
211*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
212*1b4853f5SAndroid Build Coastguard Worker struct v4l2_plane *planes_backup = NULL;
213*1b4853f5SAndroid Build Coastguard Worker u32 length_backup = 0;
214*1b4853f5SAndroid Build Coastguard Worker struct scatterlist *sgs[64];
215*1b4853f5SAndroid Build Coastguard Worker /* End of the device-readable buffer SGs, to reuse in device-writable section. */
216*1b4853f5SAndroid Build Coastguard Worker size_t num_cmd_sgs;
217*1b4853f5SAndroid Build Coastguard Worker size_t end_buf_sg;
218*1b4853f5SAndroid Build Coastguard Worker struct scatterlist_filler filler = {
219*1b4853f5SAndroid Build Coastguard Worker .descs = session->command_sgs.sgl,
220*1b4853f5SAndroid Build Coastguard Worker .num_descs = DESC_CHAIN_MAX_LEN,
221*1b4853f5SAndroid Build Coastguard Worker .cur_desc = 0,
222*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer = session->shadow_buf,
223*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_size = VIRTIO_SHADOW_BUF_SIZE,
224*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_pos = 0,
225*1b4853f5SAndroid Build Coastguard Worker .sgs = sgs,
226*1b4853f5SAndroid Build Coastguard Worker .num_sgs = ARRAY_SIZE(sgs),
227*1b4853f5SAndroid Build Coastguard Worker .cur_sg = 0,
228*1b4853f5SAndroid Build Coastguard Worker };
229*1b4853f5SAndroid Build Coastguard Worker size_t resp_len;
230*1b4853f5SAndroid Build Coastguard Worker int ret;
231*1b4853f5SAndroid Build Coastguard Worker int i;
232*1b4853f5SAndroid Build Coastguard Worker
233*1b4853f5SAndroid Build Coastguard Worker if (b->type > VIRTIO_MEDIA_LAST_QUEUE)
234*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
235*1b4853f5SAndroid Build Coastguard Worker
236*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
237*1b4853f5SAndroid Build Coastguard Worker planes_backup = b->m.planes;
238*1b4853f5SAndroid Build Coastguard Worker length_backup = b->length;
239*1b4853f5SAndroid Build Coastguard Worker }
240*1b4853f5SAndroid Build Coastguard Worker
241*1b4853f5SAndroid Build Coastguard Worker /* Command descriptor */
242*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_cmd(&filler, session, ioctl_code);
243*1b4853f5SAndroid Build Coastguard Worker if (ret)
244*1b4853f5SAndroid Build Coastguard Worker return ret;
245*1b4853f5SAndroid Build Coastguard Worker
246*1b4853f5SAndroid Build Coastguard Worker /* Command payload (struct v4l2_buffer) */
247*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_buffer(&filler, b);
248*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
249*1b4853f5SAndroid Build Coastguard Worker return ret;
250*1b4853f5SAndroid Build Coastguard Worker
251*1b4853f5SAndroid Build Coastguard Worker end_buf_sg = filler.cur_sg;
252*1b4853f5SAndroid Build Coastguard Worker
253*1b4853f5SAndroid Build Coastguard Worker /* Payload of USERPTR buffers, if relevant */
254*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_buffer_userptr(&filler, b);
255*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
256*1b4853f5SAndroid Build Coastguard Worker return ret;
257*1b4853f5SAndroid Build Coastguard Worker
258*1b4853f5SAndroid Build Coastguard Worker num_cmd_sgs = filler.cur_sg;
259*1b4853f5SAndroid Build Coastguard Worker
260*1b4853f5SAndroid Build Coastguard Worker /* Response descriptor */
261*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_resp(&filler, session);
262*1b4853f5SAndroid Build Coastguard Worker if (ret)
263*1b4853f5SAndroid Build Coastguard Worker return ret;
264*1b4853f5SAndroid Build Coastguard Worker
265*1b4853f5SAndroid Build Coastguard Worker /* Response payload (same as input, but no userptr mapping) */
266*1b4853f5SAndroid Build Coastguard Worker for (i = 1; i < end_buf_sg; i++) {
267*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_sg(&filler, filler.sgs[i]);
268*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
269*1b4853f5SAndroid Build Coastguard Worker return ret;
270*1b4853f5SAndroid Build Coastguard Worker }
271*1b4853f5SAndroid Build Coastguard Worker
272*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_command(
273*1b4853f5SAndroid Build Coastguard Worker vv, filler.sgs, num_cmd_sgs, filler.cur_sg - num_cmd_sgs,
274*1b4853f5SAndroid Build Coastguard Worker sizeof(struct virtio_media_resp_ioctl) + sizeof(*b), &resp_len);
275*1b4853f5SAndroid Build Coastguard Worker
276*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
277*1b4853f5SAndroid Build Coastguard Worker b->m.planes = planes_backup;
278*1b4853f5SAndroid Build Coastguard Worker if (b->length > length_backup)
279*1b4853f5SAndroid Build Coastguard Worker return -ENOSPC;
280*1b4853f5SAndroid Build Coastguard Worker }
281*1b4853f5SAndroid Build Coastguard Worker
282*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
283*1b4853f5SAndroid Build Coastguard Worker return ret;
284*1b4853f5SAndroid Build Coastguard Worker
285*1b4853f5SAndroid Build Coastguard Worker resp_len -= sizeof(struct virtio_media_resp_ioctl);
286*1b4853f5SAndroid Build Coastguard Worker
287*1b4853f5SAndroid Build Coastguard Worker /* Make sure that the reply's length covers our v4l2_buffer */
288*1b4853f5SAndroid Build Coastguard Worker if (resp_len < sizeof(*b))
289*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
290*1b4853f5SAndroid Build Coastguard Worker
291*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_retrieve_buffer(session, &sgs[num_cmd_sgs + 1],
292*1b4853f5SAndroid Build Coastguard Worker b, length_backup);
293*1b4853f5SAndroid Build Coastguard Worker if (ret) {
294*1b4853f5SAndroid Build Coastguard Worker v4l2_err(&vv->v4l2_dev,
295*1b4853f5SAndroid Build Coastguard Worker "failed to retrieve response descriptor chain\n");
296*1b4853f5SAndroid Build Coastguard Worker return ret;
297*1b4853f5SAndroid Build Coastguard Worker }
298*1b4853f5SAndroid Build Coastguard Worker
299*1b4853f5SAndroid Build Coastguard Worker /* TODO ideally we should not be doing this twice, but the scatterlist may screw us up here? */
300*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
301*1b4853f5SAndroid Build Coastguard Worker b->m.planes = planes_backup;
302*1b4853f5SAndroid Build Coastguard Worker if (b->length > length_backup)
303*1b4853f5SAndroid Build Coastguard Worker return -ENOSPC;
304*1b4853f5SAndroid Build Coastguard Worker }
305*1b4853f5SAndroid Build Coastguard Worker
306*1b4853f5SAndroid Build Coastguard Worker return 0;
307*1b4853f5SAndroid Build Coastguard Worker }
308*1b4853f5SAndroid Build Coastguard Worker
309*1b4853f5SAndroid Build Coastguard Worker /**
310*1b4853f5SAndroid Build Coastguard Worker * Queues an ioctl that sends a v4l2_ext_controls to the host and receives an updated version.
311*1b4853f5SAndroid Build Coastguard Worker *
312*1b4853f5SAndroid Build Coastguard Worker * v4l2_ext_controls has a pointer to an array of v4l2_ext_control, and also
313*1b4853f5SAndroid Build Coastguard Worker * potentially pointers to user-space memory that we need to map properly,
314*1b4853f5SAndroid Build Coastguard Worker * hence the dedicated function.
315*1b4853f5SAndroid Build Coastguard Worker *
316*1b4853f5SAndroid Build Coastguard Worker */
virtio_media_send_ext_controls_ioctl(struct v4l2_fh * fh,u32 ioctl_code,struct v4l2_ext_controls * ctrls)317*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_send_ext_controls_ioctl(struct v4l2_fh *fh,
318*1b4853f5SAndroid Build Coastguard Worker u32 ioctl_code,
319*1b4853f5SAndroid Build Coastguard Worker struct v4l2_ext_controls *ctrls)
320*1b4853f5SAndroid Build Coastguard Worker {
321*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = fh->vdev;
322*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
323*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
324*1b4853f5SAndroid Build Coastguard Worker size_t num_cmd_sgs;
325*1b4853f5SAndroid Build Coastguard Worker struct v4l2_ext_control *controls_backup = ctrls->controls;
326*1b4853f5SAndroid Build Coastguard Worker const u32 num_ctrls = ctrls->count;
327*1b4853f5SAndroid Build Coastguard Worker struct scatterlist *sgs[64];
328*1b4853f5SAndroid Build Coastguard Worker struct scatterlist_filler filler = {
329*1b4853f5SAndroid Build Coastguard Worker .descs = session->command_sgs.sgl,
330*1b4853f5SAndroid Build Coastguard Worker .num_descs = DESC_CHAIN_MAX_LEN,
331*1b4853f5SAndroid Build Coastguard Worker .cur_desc = 0,
332*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer = session->shadow_buf,
333*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_size = VIRTIO_SHADOW_BUF_SIZE,
334*1b4853f5SAndroid Build Coastguard Worker .shadow_buffer_pos = 0,
335*1b4853f5SAndroid Build Coastguard Worker .sgs = sgs,
336*1b4853f5SAndroid Build Coastguard Worker .num_sgs = ARRAY_SIZE(sgs),
337*1b4853f5SAndroid Build Coastguard Worker .cur_sg = 0,
338*1b4853f5SAndroid Build Coastguard Worker };
339*1b4853f5SAndroid Build Coastguard Worker size_t resp_len = 0;
340*1b4853f5SAndroid Build Coastguard Worker int ret;
341*1b4853f5SAndroid Build Coastguard Worker
342*1b4853f5SAndroid Build Coastguard Worker /* Command descriptor */
343*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_cmd(&filler, session, ioctl_code);
344*1b4853f5SAndroid Build Coastguard Worker if (ret)
345*1b4853f5SAndroid Build Coastguard Worker return ret;
346*1b4853f5SAndroid Build Coastguard Worker
347*1b4853f5SAndroid Build Coastguard Worker /* v4l2_controls and its pointees */
348*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ext_ctrls(&filler, ctrls, true);
349*1b4853f5SAndroid Build Coastguard Worker if (ret)
350*1b4853f5SAndroid Build Coastguard Worker return ret;
351*1b4853f5SAndroid Build Coastguard Worker
352*1b4853f5SAndroid Build Coastguard Worker num_cmd_sgs = filler.cur_sg;
353*1b4853f5SAndroid Build Coastguard Worker
354*1b4853f5SAndroid Build Coastguard Worker /* Response descriptor */
355*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ioctl_resp(&filler, session);
356*1b4853f5SAndroid Build Coastguard Worker if (ret)
357*1b4853f5SAndroid Build Coastguard Worker return ret;
358*1b4853f5SAndroid Build Coastguard Worker
359*1b4853f5SAndroid Build Coastguard Worker /*
360*1b4853f5SAndroid Build Coastguard Worker * Response payload (same as input but without userptrs)
361*1b4853f5SAndroid Build Coastguard Worker */
362*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_add_ext_ctrls(&filler, ctrls, false);
363*1b4853f5SAndroid Build Coastguard Worker if (ret)
364*1b4853f5SAndroid Build Coastguard Worker return ret;
365*1b4853f5SAndroid Build Coastguard Worker
366*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_command(
367*1b4853f5SAndroid Build Coastguard Worker vv, filler.sgs, num_cmd_sgs, filler.cur_sg - num_cmd_sgs,
368*1b4853f5SAndroid Build Coastguard Worker sizeof(struct virtio_media_resp_ioctl) + sizeof(*ctrls),
369*1b4853f5SAndroid Build Coastguard Worker &resp_len);
370*1b4853f5SAndroid Build Coastguard Worker
371*1b4853f5SAndroid Build Coastguard Worker /* Just in case the host touched these. */
372*1b4853f5SAndroid Build Coastguard Worker ctrls->controls = controls_backup;
373*1b4853f5SAndroid Build Coastguard Worker if (ctrls->count != num_ctrls) {
374*1b4853f5SAndroid Build Coastguard Worker v4l2_err(
375*1b4853f5SAndroid Build Coastguard Worker &vv->v4l2_dev,
376*1b4853f5SAndroid Build Coastguard Worker "device returned a number of extended controls different than submitted\n");
377*1b4853f5SAndroid Build Coastguard Worker }
378*1b4853f5SAndroid Build Coastguard Worker if (ctrls->count > num_ctrls)
379*1b4853f5SAndroid Build Coastguard Worker return -ENOSPC;
380*1b4853f5SAndroid Build Coastguard Worker
381*1b4853f5SAndroid Build Coastguard Worker /* Event if we have received an error, we may need to read our payload back */
382*1b4853f5SAndroid Build Coastguard Worker if (ret < 0 && resp_len >= sizeof(struct virtio_media_resp_ioctl) +
383*1b4853f5SAndroid Build Coastguard Worker sizeof(*ctrls)) {
384*1b4853f5SAndroid Build Coastguard Worker /* Deliberately ignore the error here as we want to return the previous one */
385*1b4853f5SAndroid Build Coastguard Worker scatterlist_filler_retrieve_ext_ctrls(
386*1b4853f5SAndroid Build Coastguard Worker session, &sgs[num_cmd_sgs + 1],
387*1b4853f5SAndroid Build Coastguard Worker filler.cur_sg - (num_cmd_sgs + 1), ctrls);
388*1b4853f5SAndroid Build Coastguard Worker return ret;
389*1b4853f5SAndroid Build Coastguard Worker }
390*1b4853f5SAndroid Build Coastguard Worker
391*1b4853f5SAndroid Build Coastguard Worker resp_len -= sizeof(struct virtio_media_resp_ioctl);
392*1b4853f5SAndroid Build Coastguard Worker
393*1b4853f5SAndroid Build Coastguard Worker /* Make sure that the reply's length covers our v4l2_ext_controls */
394*1b4853f5SAndroid Build Coastguard Worker if (resp_len < sizeof(*ctrls))
395*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
396*1b4853f5SAndroid Build Coastguard Worker
397*1b4853f5SAndroid Build Coastguard Worker ret = scatterlist_filler_retrieve_ext_ctrls(
398*1b4853f5SAndroid Build Coastguard Worker session, &sgs[num_cmd_sgs + 1],
399*1b4853f5SAndroid Build Coastguard Worker filler.cur_sg - (num_cmd_sgs + 1), ctrls);
400*1b4853f5SAndroid Build Coastguard Worker if (ret)
401*1b4853f5SAndroid Build Coastguard Worker return ret;
402*1b4853f5SAndroid Build Coastguard Worker
403*1b4853f5SAndroid Build Coastguard Worker return 0;
404*1b4853f5SAndroid Build Coastguard Worker }
405*1b4853f5SAndroid Build Coastguard Worker
406*1b4853f5SAndroid Build Coastguard Worker /**
407*1b4853f5SAndroid Build Coastguard Worker * Helper function to clear the list of buffers waiting to be dequeued on a
408*1b4853f5SAndroid Build Coastguard Worker * queue that has just been streamed off.
409*1b4853f5SAndroid Build Coastguard Worker */
virtio_media_clear_queue(struct virtio_media * vv,struct virtio_media_session * session,struct virtio_media_queue_state * queue)410*1b4853f5SAndroid Build Coastguard Worker static void virtio_media_clear_queue(struct virtio_media *vv,
411*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session,
412*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue)
413*1b4853f5SAndroid Build Coastguard Worker {
414*1b4853f5SAndroid Build Coastguard Worker struct list_head *p, *n;
415*1b4853f5SAndroid Build Coastguard Worker int i;
416*1b4853f5SAndroid Build Coastguard Worker
417*1b4853f5SAndroid Build Coastguard Worker mutex_lock(&session->dqbufs_lock);
418*1b4853f5SAndroid Build Coastguard Worker
419*1b4853f5SAndroid Build Coastguard Worker list_for_each_safe(p, n, &queue->pending_dqbufs) {
420*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_buffer *dqbuf =
421*1b4853f5SAndroid Build Coastguard Worker list_entry(p, struct virtio_media_buffer, list);
422*1b4853f5SAndroid Build Coastguard Worker
423*1b4853f5SAndroid Build Coastguard Worker list_del(&dqbuf->list);
424*1b4853f5SAndroid Build Coastguard Worker }
425*1b4853f5SAndroid Build Coastguard Worker
426*1b4853f5SAndroid Build Coastguard Worker mutex_unlock(&session->dqbufs_lock);
427*1b4853f5SAndroid Build Coastguard Worker
428*1b4853f5SAndroid Build Coastguard Worker /* All buffers are now dequeued. */
429*1b4853f5SAndroid Build Coastguard Worker for (i = 0; i < queue->allocated_bufs; i++) {
430*1b4853f5SAndroid Build Coastguard Worker queue->buffers[i].buffer.flags = 0;
431*1b4853f5SAndroid Build Coastguard Worker }
432*1b4853f5SAndroid Build Coastguard Worker
433*1b4853f5SAndroid Build Coastguard Worker queue->queued_bufs = 0;
434*1b4853f5SAndroid Build Coastguard Worker queue->streaming = false;
435*1b4853f5SAndroid Build Coastguard Worker queue->is_capture_last = false;
436*1b4853f5SAndroid Build Coastguard Worker }
437*1b4853f5SAndroid Build Coastguard Worker
438*1b4853f5SAndroid Build Coastguard Worker /*
439*1b4853f5SAndroid Build Coastguard Worker * Macros suitable for defining ioctls with a constant size payload.
440*1b4853f5SAndroid Build Coastguard Worker */
441*1b4853f5SAndroid Build Coastguard Worker
442*1b4853f5SAndroid Build Coastguard Worker #define SIMPLE_WR_IOCTL(name, ioctl, type) \
443*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_##name(struct file *file, void *fh, \
444*1b4853f5SAndroid Build Coastguard Worker type *payload) \
445*1b4853f5SAndroid Build Coastguard Worker { \
446*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_wr_ioctl(fh, ioctl, payload, \
447*1b4853f5SAndroid Build Coastguard Worker sizeof(*payload), \
448*1b4853f5SAndroid Build Coastguard Worker sizeof(*payload)); \
449*1b4853f5SAndroid Build Coastguard Worker }
450*1b4853f5SAndroid Build Coastguard Worker #define SIMPLE_R_IOCTL(name, ioctl, type) \
451*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_##name(struct file *file, void *fh, \
452*1b4853f5SAndroid Build Coastguard Worker type *payload) \
453*1b4853f5SAndroid Build Coastguard Worker { \
454*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_r_ioctl(fh, ioctl, payload, \
455*1b4853f5SAndroid Build Coastguard Worker sizeof(*payload)); \
456*1b4853f5SAndroid Build Coastguard Worker }
457*1b4853f5SAndroid Build Coastguard Worker #define SIMPLE_W_IOCTL(name, ioctl, type) \
458*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_##name(struct file *file, void *fh, \
459*1b4853f5SAndroid Build Coastguard Worker type *payload) \
460*1b4853f5SAndroid Build Coastguard Worker { \
461*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_w_ioctl(fh, ioctl, payload, \
462*1b4853f5SAndroid Build Coastguard Worker sizeof(*payload)); \
463*1b4853f5SAndroid Build Coastguard Worker }
464*1b4853f5SAndroid Build Coastguard Worker
465*1b4853f5SAndroid Build Coastguard Worker /*
466*1b4853f5SAndroid Build Coastguard Worker * V4L2 ioctl handlers.
467*1b4853f5SAndroid Build Coastguard Worker *
468*1b4853f5SAndroid Build Coastguard Worker * Most of these functions just forward the ioctl to the host, for these we can
469*1b4853f5SAndroid Build Coastguard Worker * use one of the SIMPLE_*_IOCTL macros. Exceptions that have their own
470*1b4853f5SAndroid Build Coastguard Worker * standalone function follow.
471*1b4853f5SAndroid Build Coastguard Worker */
472*1b4853f5SAndroid Build Coastguard Worker
SIMPLE_WR_IOCTL(enum_fmt,VIDIOC_ENUM_FMT,struct v4l2_fmtdesc)473*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enum_fmt, VIDIOC_ENUM_FMT, struct v4l2_fmtdesc)
474*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_fmt, VIDIOC_G_FMT, struct v4l2_format)
475*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(s_fmt, VIDIOC_S_FMT, struct v4l2_format)
476*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(try_fmt, VIDIOC_TRY_FMT, struct v4l2_format)
477*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enum_framesizes, VIDIOC_ENUM_FRAMESIZES,
478*1b4853f5SAndroid Build Coastguard Worker struct v4l2_frmsizeenum)
479*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enum_frameintervals, VIDIOC_ENUM_FRAMEINTERVALS,
480*1b4853f5SAndroid Build Coastguard Worker struct v4l2_frmivalenum)
481*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(queryctrl, VIDIOC_QUERYCTRL, struct v4l2_queryctrl)
482*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_ctrl, VIDIOC_G_CTRL, struct v4l2_control)
483*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(s_ctrl, VIDIOC_S_CTRL, struct v4l2_control)
484*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(query_ext_ctrl, VIDIOC_QUERY_EXT_CTRL,
485*1b4853f5SAndroid Build Coastguard Worker struct v4l2_query_ext_ctrl)
486*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(s_dv_timings, VIDIOC_S_DV_TIMINGS, struct v4l2_dv_timings)
487*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_dv_timings, VIDIOC_G_DV_TIMINGS, struct v4l2_dv_timings)
488*1b4853f5SAndroid Build Coastguard Worker SIMPLE_R_IOCTL(query_dv_timings, VIDIOC_QUERY_DV_TIMINGS,
489*1b4853f5SAndroid Build Coastguard Worker struct v4l2_dv_timings)
490*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enum_dv_timings, VIDIOC_ENUM_DV_TIMINGS,
491*1b4853f5SAndroid Build Coastguard Worker struct v4l2_enum_dv_timings)
492*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(dv_timings_cap, VIDIOC_DV_TIMINGS_CAP,
493*1b4853f5SAndroid Build Coastguard Worker struct v4l2_dv_timings_cap)
494*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enuminput, VIDIOC_ENUMINPUT, struct v4l2_input)
495*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(querymenu, VIDIOC_QUERYMENU, struct v4l2_querymenu)
496*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enumoutput, VIDIOC_ENUMOUTPUT, struct v4l2_output)
497*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enumaudio, VIDIOC_ENUMAUDIO, struct v4l2_audio)
498*1b4853f5SAndroid Build Coastguard Worker SIMPLE_R_IOCTL(g_audio, VIDIOC_G_AUDIO, struct v4l2_audio)
499*1b4853f5SAndroid Build Coastguard Worker SIMPLE_W_IOCTL(s_audio, VIDIOC_S_AUDIO, const struct v4l2_audio)
500*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enumaudout, VIDIOC_ENUMAUDOUT, struct v4l2_audioout)
501*1b4853f5SAndroid Build Coastguard Worker SIMPLE_R_IOCTL(g_audout, VIDIOC_G_AUDOUT, struct v4l2_audioout)
502*1b4853f5SAndroid Build Coastguard Worker SIMPLE_W_IOCTL(s_audout, VIDIOC_S_AUDOUT, const struct v4l2_audioout)
503*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_modulator, VIDIOC_G_MODULATOR, struct v4l2_modulator)
504*1b4853f5SAndroid Build Coastguard Worker SIMPLE_W_IOCTL(s_modulator, VIDIOC_S_MODULATOR, const struct v4l2_modulator)
505*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_selection, VIDIOC_G_SELECTION, struct v4l2_selection)
506*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(s_selection, VIDIOC_S_SELECTION, struct v4l2_selection)
507*1b4853f5SAndroid Build Coastguard Worker SIMPLE_R_IOCTL(g_enc_index, VIDIOC_G_ENC_INDEX, struct v4l2_enc_idx)
508*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(encoder_cmd, VIDIOC_ENCODER_CMD, struct v4l2_encoder_cmd)
509*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(try_encoder_cmd, VIDIOC_TRY_ENCODER_CMD,
510*1b4853f5SAndroid Build Coastguard Worker struct v4l2_encoder_cmd)
511*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(try_decoder_cmd, VIDIOC_TRY_DECODER_CMD,
512*1b4853f5SAndroid Build Coastguard Worker struct v4l2_decoder_cmd)
513*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_parm, VIDIOC_G_PARM, struct v4l2_streamparm)
514*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(s_parm, VIDIOC_S_PARM, struct v4l2_streamparm)
515*1b4853f5SAndroid Build Coastguard Worker SIMPLE_R_IOCTL(g_std, VIDIOC_G_STD, v4l2_std_id)
516*1b4853f5SAndroid Build Coastguard Worker SIMPLE_R_IOCTL(querystd, VIDIOC_QUERYSTD, v4l2_std_id)
517*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enumstd, VIDIOC_ENUMSTD, struct v4l2_standard)
518*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_tuner, VIDIOC_G_TUNER, struct v4l2_tuner)
519*1b4853f5SAndroid Build Coastguard Worker SIMPLE_W_IOCTL(s_tuner, VIDIOC_S_TUNER, const struct v4l2_tuner)
520*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_frequency, VIDIOC_G_FREQUENCY, struct v4l2_frequency)
521*1b4853f5SAndroid Build Coastguard Worker SIMPLE_W_IOCTL(s_frequency, VIDIOC_S_FREQUENCY, const struct v4l2_frequency)
522*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(enum_freq_bands, VIDIOC_ENUM_FREQ_BANDS,
523*1b4853f5SAndroid Build Coastguard Worker struct v4l2_frequency_band)
524*1b4853f5SAndroid Build Coastguard Worker SIMPLE_WR_IOCTL(g_sliced_vbi_cap, VIDIOC_G_SLICED_VBI_CAP,
525*1b4853f5SAndroid Build Coastguard Worker struct v4l2_sliced_vbi_cap)
526*1b4853f5SAndroid Build Coastguard Worker SIMPLE_W_IOCTL(s_hw_freq_seek, VIDIOC_S_HW_FREQ_SEEK,
527*1b4853f5SAndroid Build Coastguard Worker const struct v4l2_hw_freq_seek)
528*1b4853f5SAndroid Build Coastguard Worker
529*1b4853f5SAndroid Build Coastguard Worker /*
530*1b4853f5SAndroid Build Coastguard Worker * QUERYCAP is handled by reading the configuration area.
531*1b4853f5SAndroid Build Coastguard Worker *
532*1b4853f5SAndroid Build Coastguard Worker */
533*1b4853f5SAndroid Build Coastguard Worker
534*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_querycap(struct file *file, void *fh,
535*1b4853f5SAndroid Build Coastguard Worker struct v4l2_capability *cap)
536*1b4853f5SAndroid Build Coastguard Worker {
537*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = video_devdata(file);
538*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
539*1b4853f5SAndroid Build Coastguard Worker
540*1b4853f5SAndroid Build Coastguard Worker /* TODO add proper number? */
541*1b4853f5SAndroid Build Coastguard Worker strncpy(cap->bus_info, "platform:virtio-media0", sizeof(cap->bus_info));
542*1b4853f5SAndroid Build Coastguard Worker
543*1b4853f5SAndroid Build Coastguard Worker if (!driver_name) {
544*1b4853f5SAndroid Build Coastguard Worker strncpy(cap->driver, VIRTIO_MEDIA_DEFAULT_DRIVER_NAME,
545*1b4853f5SAndroid Build Coastguard Worker sizeof(cap->driver));
546*1b4853f5SAndroid Build Coastguard Worker } else {
547*1b4853f5SAndroid Build Coastguard Worker strncpy(cap->driver, driver_name, sizeof(cap->driver));
548*1b4853f5SAndroid Build Coastguard Worker }
549*1b4853f5SAndroid Build Coastguard Worker virtio_cread_bytes(vv->virtio_dev, 8, cap->card, sizeof(cap->card));
550*1b4853f5SAndroid Build Coastguard Worker
551*1b4853f5SAndroid Build Coastguard Worker cap->capabilities = video_dev->device_caps | V4L2_CAP_DEVICE_CAPS;
552*1b4853f5SAndroid Build Coastguard Worker cap->device_caps = video_dev->device_caps;
553*1b4853f5SAndroid Build Coastguard Worker
554*1b4853f5SAndroid Build Coastguard Worker return 0;
555*1b4853f5SAndroid Build Coastguard Worker }
556*1b4853f5SAndroid Build Coastguard Worker
557*1b4853f5SAndroid Build Coastguard Worker /*
558*1b4853f5SAndroid Build Coastguard Worker * Extended control ioctls are handled mostly identically.
559*1b4853f5SAndroid Build Coastguard Worker */
560*1b4853f5SAndroid Build Coastguard Worker
virtio_media_g_ext_ctrls(struct file * file,void * fh,struct v4l2_ext_controls * ctrls)561*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_g_ext_ctrls(struct file *file, void *fh,
562*1b4853f5SAndroid Build Coastguard Worker struct v4l2_ext_controls *ctrls)
563*1b4853f5SAndroid Build Coastguard Worker {
564*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_ext_controls_ioctl(fh, VIDIOC_G_EXT_CTRLS,
565*1b4853f5SAndroid Build Coastguard Worker ctrls);
566*1b4853f5SAndroid Build Coastguard Worker }
567*1b4853f5SAndroid Build Coastguard Worker
virtio_media_s_ext_ctrls(struct file * file,void * fh,struct v4l2_ext_controls * ctrls)568*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_s_ext_ctrls(struct file *file, void *fh,
569*1b4853f5SAndroid Build Coastguard Worker struct v4l2_ext_controls *ctrls)
570*1b4853f5SAndroid Build Coastguard Worker {
571*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_ext_controls_ioctl(fh, VIDIOC_S_EXT_CTRLS,
572*1b4853f5SAndroid Build Coastguard Worker ctrls);
573*1b4853f5SAndroid Build Coastguard Worker }
574*1b4853f5SAndroid Build Coastguard Worker
virtio_media_try_ext_ctrls(struct file * file,void * fh,struct v4l2_ext_controls * ctrls)575*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_try_ext_ctrls(struct file *file, void *fh,
576*1b4853f5SAndroid Build Coastguard Worker struct v4l2_ext_controls *ctrls)
577*1b4853f5SAndroid Build Coastguard Worker {
578*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_ext_controls_ioctl(fh, VIDIOC_TRY_EXT_CTRLS,
579*1b4853f5SAndroid Build Coastguard Worker ctrls);
580*1b4853f5SAndroid Build Coastguard Worker }
581*1b4853f5SAndroid Build Coastguard Worker
582*1b4853f5SAndroid Build Coastguard Worker /*
583*1b4853f5SAndroid Build Coastguard Worker * Subscribe/unsubscribe from an event.
584*1b4853f5SAndroid Build Coastguard Worker */
585*1b4853f5SAndroid Build Coastguard Worker
586*1b4853f5SAndroid Build Coastguard Worker static int
virtio_media_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)587*1b4853f5SAndroid Build Coastguard Worker virtio_media_subscribe_event(struct v4l2_fh *fh,
588*1b4853f5SAndroid Build Coastguard Worker const struct v4l2_event_subscription *sub)
589*1b4853f5SAndroid Build Coastguard Worker {
590*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = fh->vdev;
591*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
592*1b4853f5SAndroid Build Coastguard Worker int ret;
593*1b4853f5SAndroid Build Coastguard Worker
594*1b4853f5SAndroid Build Coastguard Worker /* First subscribe to the event in the guest. */
595*1b4853f5SAndroid Build Coastguard Worker switch (sub->type) {
596*1b4853f5SAndroid Build Coastguard Worker case V4L2_EVENT_SOURCE_CHANGE:
597*1b4853f5SAndroid Build Coastguard Worker ret = v4l2_src_change_event_subscribe(fh, sub);
598*1b4853f5SAndroid Build Coastguard Worker break;
599*1b4853f5SAndroid Build Coastguard Worker default:
600*1b4853f5SAndroid Build Coastguard Worker ret = v4l2_event_subscribe(fh, sub, 1, NULL);
601*1b4853f5SAndroid Build Coastguard Worker break;
602*1b4853f5SAndroid Build Coastguard Worker }
603*1b4853f5SAndroid Build Coastguard Worker if (ret)
604*1b4853f5SAndroid Build Coastguard Worker return ret;
605*1b4853f5SAndroid Build Coastguard Worker
606*1b4853f5SAndroid Build Coastguard Worker /* Then ask the host to signal us these events. */
607*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_w_ioctl(fh, VIDIOC_SUBSCRIBE_EVENT, sub,
608*1b4853f5SAndroid Build Coastguard Worker sizeof(*sub));
609*1b4853f5SAndroid Build Coastguard Worker if (ret < 0) {
610*1b4853f5SAndroid Build Coastguard Worker v4l2_event_unsubscribe(fh, sub);
611*1b4853f5SAndroid Build Coastguard Worker return ret;
612*1b4853f5SAndroid Build Coastguard Worker }
613*1b4853f5SAndroid Build Coastguard Worker
614*1b4853f5SAndroid Build Coastguard Worker /*
615*1b4853f5SAndroid Build Coastguard Worker * Subscribing to an event may result in that event being signaled
616*1b4853f5SAndroid Build Coastguard Worker * immediately. Process all pending events to make sure we don't miss it.
617*1b4853f5SAndroid Build Coastguard Worker */
618*1b4853f5SAndroid Build Coastguard Worker if (sub->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) {
619*1b4853f5SAndroid Build Coastguard Worker virtio_media_process_events(vv);
620*1b4853f5SAndroid Build Coastguard Worker }
621*1b4853f5SAndroid Build Coastguard Worker
622*1b4853f5SAndroid Build Coastguard Worker return 0;
623*1b4853f5SAndroid Build Coastguard Worker }
624*1b4853f5SAndroid Build Coastguard Worker
625*1b4853f5SAndroid Build Coastguard Worker static int
virtio_media_unsubscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)626*1b4853f5SAndroid Build Coastguard Worker virtio_media_unsubscribe_event(struct v4l2_fh *fh,
627*1b4853f5SAndroid Build Coastguard Worker const struct v4l2_event_subscription *sub)
628*1b4853f5SAndroid Build Coastguard Worker {
629*1b4853f5SAndroid Build Coastguard Worker int ret;
630*1b4853f5SAndroid Build Coastguard Worker
631*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_w_ioctl(fh, VIDIOC_UNSUBSCRIBE_EVENT, sub,
632*1b4853f5SAndroid Build Coastguard Worker sizeof(*sub));
633*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
634*1b4853f5SAndroid Build Coastguard Worker return ret;
635*1b4853f5SAndroid Build Coastguard Worker
636*1b4853f5SAndroid Build Coastguard Worker ret = v4l2_event_unsubscribe(fh, sub);
637*1b4853f5SAndroid Build Coastguard Worker if (ret)
638*1b4853f5SAndroid Build Coastguard Worker return ret;
639*1b4853f5SAndroid Build Coastguard Worker
640*1b4853f5SAndroid Build Coastguard Worker return 0;
641*1b4853f5SAndroid Build Coastguard Worker }
642*1b4853f5SAndroid Build Coastguard Worker
643*1b4853f5SAndroid Build Coastguard Worker /*
644*1b4853f5SAndroid Build Coastguard Worker * Streamon/off affect the local queue state.
645*1b4853f5SAndroid Build Coastguard Worker */
646*1b4853f5SAndroid Build Coastguard Worker
virtio_media_streamon(struct file * file,void * fh,enum v4l2_buf_type i)647*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_streamon(struct file *file, void *fh,
648*1b4853f5SAndroid Build Coastguard Worker enum v4l2_buf_type i)
649*1b4853f5SAndroid Build Coastguard Worker {
650*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
651*1b4853f5SAndroid Build Coastguard Worker int ret;
652*1b4853f5SAndroid Build Coastguard Worker
653*1b4853f5SAndroid Build Coastguard Worker if (i > VIRTIO_MEDIA_LAST_QUEUE)
654*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
655*1b4853f5SAndroid Build Coastguard Worker
656*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_w_ioctl(fh, VIDIOC_STREAMON, &i, sizeof(i));
657*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
658*1b4853f5SAndroid Build Coastguard Worker return ret;
659*1b4853f5SAndroid Build Coastguard Worker
660*1b4853f5SAndroid Build Coastguard Worker session->queues[i].streaming = true;
661*1b4853f5SAndroid Build Coastguard Worker
662*1b4853f5SAndroid Build Coastguard Worker return 0;
663*1b4853f5SAndroid Build Coastguard Worker }
664*1b4853f5SAndroid Build Coastguard Worker
virtio_media_streamoff(struct file * file,void * fh,enum v4l2_buf_type i)665*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_streamoff(struct file *file, void *fh,
666*1b4853f5SAndroid Build Coastguard Worker enum v4l2_buf_type i)
667*1b4853f5SAndroid Build Coastguard Worker {
668*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = video_devdata(file);
669*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
670*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
671*1b4853f5SAndroid Build Coastguard Worker int ret;
672*1b4853f5SAndroid Build Coastguard Worker
673*1b4853f5SAndroid Build Coastguard Worker if (i > VIRTIO_MEDIA_LAST_QUEUE) {
674*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
675*1b4853f5SAndroid Build Coastguard Worker }
676*1b4853f5SAndroid Build Coastguard Worker
677*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_w_ioctl(fh, VIDIOC_STREAMOFF, &i, sizeof(i));
678*1b4853f5SAndroid Build Coastguard Worker if (ret < 0)
679*1b4853f5SAndroid Build Coastguard Worker return ret;
680*1b4853f5SAndroid Build Coastguard Worker
681*1b4853f5SAndroid Build Coastguard Worker virtio_media_clear_queue(vv, session, &session->queues[i]);
682*1b4853f5SAndroid Build Coastguard Worker
683*1b4853f5SAndroid Build Coastguard Worker return 0;
684*1b4853f5SAndroid Build Coastguard Worker }
685*1b4853f5SAndroid Build Coastguard Worker
686*1b4853f5SAndroid Build Coastguard Worker /*
687*1b4853f5SAndroid Build Coastguard Worker * Buffer creation/queuing functions deal with the local driver state.
688*1b4853f5SAndroid Build Coastguard Worker */
689*1b4853f5SAndroid Build Coastguard Worker
virtio_media_reqbufs(struct file * file,void * fh,struct v4l2_requestbuffers * b)690*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_reqbufs(struct file *file, void *fh,
691*1b4853f5SAndroid Build Coastguard Worker struct v4l2_requestbuffers *b)
692*1b4853f5SAndroid Build Coastguard Worker {
693*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = video_devdata(file);
694*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
695*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
696*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue;
697*1b4853f5SAndroid Build Coastguard Worker int ret;
698*1b4853f5SAndroid Build Coastguard Worker
699*1b4853f5SAndroid Build Coastguard Worker if (b->type > VIRTIO_MEDIA_LAST_QUEUE)
700*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
701*1b4853f5SAndroid Build Coastguard Worker
702*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_wr_ioctl(fh, VIDIOC_REQBUFS, b, sizeof(*b),
703*1b4853f5SAndroid Build Coastguard Worker sizeof(*b));
704*1b4853f5SAndroid Build Coastguard Worker if (ret)
705*1b4853f5SAndroid Build Coastguard Worker return ret;
706*1b4853f5SAndroid Build Coastguard Worker
707*1b4853f5SAndroid Build Coastguard Worker queue = &session->queues[b->type];
708*1b4853f5SAndroid Build Coastguard Worker
709*1b4853f5SAndroid Build Coastguard Worker /* REQBUFS(0) is an implicit STREAMOFF. */
710*1b4853f5SAndroid Build Coastguard Worker if (b->count == 0) {
711*1b4853f5SAndroid Build Coastguard Worker virtio_media_clear_queue(vv, session, queue);
712*1b4853f5SAndroid Build Coastguard Worker }
713*1b4853f5SAndroid Build Coastguard Worker
714*1b4853f5SAndroid Build Coastguard Worker vfree(queue->buffers);
715*1b4853f5SAndroid Build Coastguard Worker queue->buffers = NULL;
716*1b4853f5SAndroid Build Coastguard Worker
717*1b4853f5SAndroid Build Coastguard Worker if (b->count > 0) {
718*1b4853f5SAndroid Build Coastguard Worker queue->buffers =
719*1b4853f5SAndroid Build Coastguard Worker vzalloc(sizeof(struct virtio_media_buffer) * b->count);
720*1b4853f5SAndroid Build Coastguard Worker if (!queue->buffers) {
721*1b4853f5SAndroid Build Coastguard Worker return -ENOMEM;
722*1b4853f5SAndroid Build Coastguard Worker }
723*1b4853f5SAndroid Build Coastguard Worker }
724*1b4853f5SAndroid Build Coastguard Worker
725*1b4853f5SAndroid Build Coastguard Worker queue->allocated_bufs = b->count;
726*1b4853f5SAndroid Build Coastguard Worker
727*1b4853f5SAndroid Build Coastguard Worker /*
728*1b4853f5SAndroid Build Coastguard Worker * If a multiplanar queue is successfully used here, this means
729*1b4853f5SAndroid Build Coastguard Worker * we are using the multiplanar interface.
730*1b4853f5SAndroid Build Coastguard Worker */
731*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
732*1b4853f5SAndroid Build Coastguard Worker session->uses_mplane = true;
733*1b4853f5SAndroid Build Coastguard Worker }
734*1b4853f5SAndroid Build Coastguard Worker
735*1b4853f5SAndroid Build Coastguard Worker /* TODO remove once we support DMABUFs */
736*1b4853f5SAndroid Build Coastguard Worker b->capabilities &= ~V4L2_BUF_CAP_SUPPORTS_DMABUF;
737*1b4853f5SAndroid Build Coastguard Worker
738*1b4853f5SAndroid Build Coastguard Worker return 0;
739*1b4853f5SAndroid Build Coastguard Worker }
740*1b4853f5SAndroid Build Coastguard Worker
virtio_media_querybuf(struct file * file,void * fh,struct v4l2_buffer * b)741*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_querybuf(struct file *file, void *fh,
742*1b4853f5SAndroid Build Coastguard Worker struct v4l2_buffer *b)
743*1b4853f5SAndroid Build Coastguard Worker {
744*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
745*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue;
746*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_buffer *buffer;
747*1b4853f5SAndroid Build Coastguard Worker int ret;
748*1b4853f5SAndroid Build Coastguard Worker
749*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_buffer_ioctl(fh, VIDIOC_QUERYBUF, b);
750*1b4853f5SAndroid Build Coastguard Worker if (ret)
751*1b4853f5SAndroid Build Coastguard Worker return ret;
752*1b4853f5SAndroid Build Coastguard Worker
753*1b4853f5SAndroid Build Coastguard Worker if (b->type > VIRTIO_MEDIA_LAST_QUEUE) {
754*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
755*1b4853f5SAndroid Build Coastguard Worker }
756*1b4853f5SAndroid Build Coastguard Worker queue = &session->queues[b->type];
757*1b4853f5SAndroid Build Coastguard Worker if (b->index >= queue->allocated_bufs) {
758*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
759*1b4853f5SAndroid Build Coastguard Worker }
760*1b4853f5SAndroid Build Coastguard Worker buffer = &queue->buffers[b->index];
761*1b4853f5SAndroid Build Coastguard Worker /* Set the DONE flag if the buffer is waiting in our own dequeue queue. */
762*1b4853f5SAndroid Build Coastguard Worker b->flags |= (buffer->buffer.flags & V4L2_BUF_FLAG_DONE);
763*1b4853f5SAndroid Build Coastguard Worker
764*1b4853f5SAndroid Build Coastguard Worker return 0;
765*1b4853f5SAndroid Build Coastguard Worker }
766*1b4853f5SAndroid Build Coastguard Worker
virtio_media_create_bufs(struct file * file,void * fh,struct v4l2_create_buffers * b)767*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_create_bufs(struct file *file, void *fh,
768*1b4853f5SAndroid Build Coastguard Worker struct v4l2_create_buffers *b)
769*1b4853f5SAndroid Build Coastguard Worker {
770*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
771*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue;
772*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_buffer *buffers;
773*1b4853f5SAndroid Build Coastguard Worker u32 type = b->format.type;
774*1b4853f5SAndroid Build Coastguard Worker int ret;
775*1b4853f5SAndroid Build Coastguard Worker
776*1b4853f5SAndroid Build Coastguard Worker if (type > VIRTIO_MEDIA_LAST_QUEUE)
777*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
778*1b4853f5SAndroid Build Coastguard Worker
779*1b4853f5SAndroid Build Coastguard Worker queue = &session->queues[type];
780*1b4853f5SAndroid Build Coastguard Worker
781*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_wr_ioctl(fh, VIDIOC_CREATE_BUFS, b, sizeof(*b),
782*1b4853f5SAndroid Build Coastguard Worker sizeof(*b));
783*1b4853f5SAndroid Build Coastguard Worker if (ret)
784*1b4853f5SAndroid Build Coastguard Worker return ret;
785*1b4853f5SAndroid Build Coastguard Worker
786*1b4853f5SAndroid Build Coastguard Worker /* If count is zero, we were just checking for format. */
787*1b4853f5SAndroid Build Coastguard Worker if (b->count == 0)
788*1b4853f5SAndroid Build Coastguard Worker return 0;
789*1b4853f5SAndroid Build Coastguard Worker
790*1b4853f5SAndroid Build Coastguard Worker buffers = queue->buffers;
791*1b4853f5SAndroid Build Coastguard Worker
792*1b4853f5SAndroid Build Coastguard Worker queue->buffers = vzalloc(sizeof(struct virtio_media_buffer) *
793*1b4853f5SAndroid Build Coastguard Worker (b->index + b->count));
794*1b4853f5SAndroid Build Coastguard Worker if (!queue->buffers) {
795*1b4853f5SAndroid Build Coastguard Worker queue->buffers = buffers;
796*1b4853f5SAndroid Build Coastguard Worker return -ENOMEM;
797*1b4853f5SAndroid Build Coastguard Worker }
798*1b4853f5SAndroid Build Coastguard Worker
799*1b4853f5SAndroid Build Coastguard Worker memcpy(queue->buffers, buffers,
800*1b4853f5SAndroid Build Coastguard Worker sizeof(*buffers) * queue->allocated_bufs);
801*1b4853f5SAndroid Build Coastguard Worker vfree(buffers);
802*1b4853f5SAndroid Build Coastguard Worker
803*1b4853f5SAndroid Build Coastguard Worker queue->allocated_bufs = b->index + b->count;
804*1b4853f5SAndroid Build Coastguard Worker
805*1b4853f5SAndroid Build Coastguard Worker return 0;
806*1b4853f5SAndroid Build Coastguard Worker }
807*1b4853f5SAndroid Build Coastguard Worker
virtio_media_prepare_buf(struct file * file,void * fh,struct v4l2_buffer * b)808*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_prepare_buf(struct file *file, void *fh,
809*1b4853f5SAndroid Build Coastguard Worker struct v4l2_buffer *b)
810*1b4853f5SAndroid Build Coastguard Worker {
811*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
812*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue;
813*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_buffer *buffer;
814*1b4853f5SAndroid Build Coastguard Worker int i, ret;
815*1b4853f5SAndroid Build Coastguard Worker
816*1b4853f5SAndroid Build Coastguard Worker if (b->type > VIRTIO_MEDIA_LAST_QUEUE)
817*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
818*1b4853f5SAndroid Build Coastguard Worker queue = &session->queues[b->type];
819*1b4853f5SAndroid Build Coastguard Worker if (b->index >= queue->allocated_bufs)
820*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
821*1b4853f5SAndroid Build Coastguard Worker buffer = &queue->buffers[b->index];
822*1b4853f5SAndroid Build Coastguard Worker
823*1b4853f5SAndroid Build Coastguard Worker buffer->buffer.m = b->m;
824*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
825*1b4853f5SAndroid Build Coastguard Worker if (b->length > VIDEO_MAX_PLANES)
826*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
827*1b4853f5SAndroid Build Coastguard Worker for (i = 0; i < b->length; i++)
828*1b4853f5SAndroid Build Coastguard Worker buffer->planes[i].m = b->m.planes[i].m;
829*1b4853f5SAndroid Build Coastguard Worker }
830*1b4853f5SAndroid Build Coastguard Worker
831*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_buffer_ioctl(fh, VIDIOC_PREPARE_BUF, b);
832*1b4853f5SAndroid Build Coastguard Worker if (ret)
833*1b4853f5SAndroid Build Coastguard Worker return ret;
834*1b4853f5SAndroid Build Coastguard Worker
835*1b4853f5SAndroid Build Coastguard Worker buffer->buffer.flags = V4L2_BUF_FLAG_PREPARED;
836*1b4853f5SAndroid Build Coastguard Worker
837*1b4853f5SAndroid Build Coastguard Worker return 0;
838*1b4853f5SAndroid Build Coastguard Worker }
839*1b4853f5SAndroid Build Coastguard Worker
virtio_media_qbuf(struct file * file,void * fh,struct v4l2_buffer * b)840*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
841*1b4853f5SAndroid Build Coastguard Worker {
842*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
843*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue;
844*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_buffer *buffer;
845*1b4853f5SAndroid Build Coastguard Worker bool prepared;
846*1b4853f5SAndroid Build Coastguard Worker u32 old_flags;
847*1b4853f5SAndroid Build Coastguard Worker int i, ret;
848*1b4853f5SAndroid Build Coastguard Worker
849*1b4853f5SAndroid Build Coastguard Worker if (b->type > VIRTIO_MEDIA_LAST_QUEUE)
850*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
851*1b4853f5SAndroid Build Coastguard Worker queue = &session->queues[b->type];
852*1b4853f5SAndroid Build Coastguard Worker if (b->index >= queue->allocated_bufs)
853*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
854*1b4853f5SAndroid Build Coastguard Worker buffer = &queue->buffers[b->index];
855*1b4853f5SAndroid Build Coastguard Worker prepared = buffer->buffer.flags & V4L2_BUF_FLAG_PREPARED;
856*1b4853f5SAndroid Build Coastguard Worker
857*1b4853f5SAndroid Build Coastguard Worker /*
858*1b4853f5SAndroid Build Coastguard Worker * Store the buffer and plane `m` information so we can retrieve it again
859*1b4853f5SAndroid Build Coastguard Worker * when DQBUF occurs.
860*1b4853f5SAndroid Build Coastguard Worker */
861*1b4853f5SAndroid Build Coastguard Worker if (!prepared) {
862*1b4853f5SAndroid Build Coastguard Worker buffer->buffer.m = b->m;
863*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
864*1b4853f5SAndroid Build Coastguard Worker if (b->length > VIDEO_MAX_PLANES)
865*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
866*1b4853f5SAndroid Build Coastguard Worker for (i = 0; i < b->length; i++)
867*1b4853f5SAndroid Build Coastguard Worker buffer->planes[i].m = b->m.planes[i].m;
868*1b4853f5SAndroid Build Coastguard Worker }
869*1b4853f5SAndroid Build Coastguard Worker }
870*1b4853f5SAndroid Build Coastguard Worker old_flags = buffer->buffer.flags;
871*1b4853f5SAndroid Build Coastguard Worker buffer->buffer.flags = V4L2_BUF_FLAG_QUEUED;
872*1b4853f5SAndroid Build Coastguard Worker
873*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_buffer_ioctl(fh, VIDIOC_QBUF, b);
874*1b4853f5SAndroid Build Coastguard Worker if (ret) {
875*1b4853f5SAndroid Build Coastguard Worker /* Rollback the previous flags as the buffer is not queued. */
876*1b4853f5SAndroid Build Coastguard Worker buffer->buffer.flags = old_flags;
877*1b4853f5SAndroid Build Coastguard Worker return ret;
878*1b4853f5SAndroid Build Coastguard Worker }
879*1b4853f5SAndroid Build Coastguard Worker
880*1b4853f5SAndroid Build Coastguard Worker queue->queued_bufs += 1;
881*1b4853f5SAndroid Build Coastguard Worker
882*1b4853f5SAndroid Build Coastguard Worker return 0;
883*1b4853f5SAndroid Build Coastguard Worker }
884*1b4853f5SAndroid Build Coastguard Worker
virtio_media_dqbuf(struct file * file,void * fh,struct v4l2_buffer * b)885*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_dqbuf(struct file *file, void *fh,
886*1b4853f5SAndroid Build Coastguard Worker struct v4l2_buffer *b)
887*1b4853f5SAndroid Build Coastguard Worker {
888*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session =
889*1b4853f5SAndroid Build Coastguard Worker fh_to_session(file->private_data);
890*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = video_devdata(file);
891*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
892*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_buffer *dqbuf;
893*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_queue_state *queue;
894*1b4853f5SAndroid Build Coastguard Worker struct list_head *buffer_queue;
895*1b4853f5SAndroid Build Coastguard Worker struct v4l2_plane *planes_backup = NULL;
896*1b4853f5SAndroid Build Coastguard Worker const bool is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(b->type);
897*1b4853f5SAndroid Build Coastguard Worker int ret;
898*1b4853f5SAndroid Build Coastguard Worker
899*1b4853f5SAndroid Build Coastguard Worker if (b->type > VIRTIO_MEDIA_LAST_QUEUE)
900*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
901*1b4853f5SAndroid Build Coastguard Worker
902*1b4853f5SAndroid Build Coastguard Worker queue = &session->queues[b->type];
903*1b4853f5SAndroid Build Coastguard Worker
904*1b4853f5SAndroid Build Coastguard Worker /*
905*1b4853f5SAndroid Build Coastguard Worker * If a buffer with the LAST flag has been returned, subsequent calls to DQBUF
906*1b4853f5SAndroid Build Coastguard Worker * must return -EPIPE until the queue is cleared.
907*1b4853f5SAndroid Build Coastguard Worker */
908*1b4853f5SAndroid Build Coastguard Worker if (queue->is_capture_last)
909*1b4853f5SAndroid Build Coastguard Worker return -EPIPE;
910*1b4853f5SAndroid Build Coastguard Worker
911*1b4853f5SAndroid Build Coastguard Worker buffer_queue = &queue->pending_dqbufs;
912*1b4853f5SAndroid Build Coastguard Worker
913*1b4853f5SAndroid Build Coastguard Worker if (session->nonblocking_dequeue) {
914*1b4853f5SAndroid Build Coastguard Worker if (list_empty(buffer_queue))
915*1b4853f5SAndroid Build Coastguard Worker return -EAGAIN;
916*1b4853f5SAndroid Build Coastguard Worker } else if (queue->allocated_bufs == 0) {
917*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
918*1b4853f5SAndroid Build Coastguard Worker } else if (!queue->streaming) {
919*1b4853f5SAndroid Build Coastguard Worker return -EINVAL;
920*1b4853f5SAndroid Build Coastguard Worker } else {
921*1b4853f5SAndroid Build Coastguard Worker mutex_unlock(&vv->vlock);
922*1b4853f5SAndroid Build Coastguard Worker ret = wait_event_interruptible(session->dqbufs_wait,
923*1b4853f5SAndroid Build Coastguard Worker !list_empty(buffer_queue));
924*1b4853f5SAndroid Build Coastguard Worker mutex_lock(&vv->vlock);
925*1b4853f5SAndroid Build Coastguard Worker if (ret)
926*1b4853f5SAndroid Build Coastguard Worker return -EINTR;
927*1b4853f5SAndroid Build Coastguard Worker }
928*1b4853f5SAndroid Build Coastguard Worker
929*1b4853f5SAndroid Build Coastguard Worker mutex_lock(&session->dqbufs_lock);
930*1b4853f5SAndroid Build Coastguard Worker dqbuf = list_first_entry(buffer_queue, struct virtio_media_buffer,
931*1b4853f5SAndroid Build Coastguard Worker list);
932*1b4853f5SAndroid Build Coastguard Worker list_del(&dqbuf->list);
933*1b4853f5SAndroid Build Coastguard Worker mutex_unlock(&session->dqbufs_lock);
934*1b4853f5SAndroid Build Coastguard Worker
935*1b4853f5SAndroid Build Coastguard Worker /* Clear the DONE flag as the buffer is now being dequeued. */
936*1b4853f5SAndroid Build Coastguard Worker dqbuf->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
937*1b4853f5SAndroid Build Coastguard Worker
938*1b4853f5SAndroid Build Coastguard Worker if (is_multiplanar) {
939*1b4853f5SAndroid Build Coastguard Worker size_t nb_planes = min(b->length, (u32)VIDEO_MAX_PLANES);
940*1b4853f5SAndroid Build Coastguard Worker memcpy(b->m.planes, dqbuf->planes,
941*1b4853f5SAndroid Build Coastguard Worker nb_planes * sizeof(struct v4l2_plane));
942*1b4853f5SAndroid Build Coastguard Worker planes_backup = b->m.planes;
943*1b4853f5SAndroid Build Coastguard Worker }
944*1b4853f5SAndroid Build Coastguard Worker
945*1b4853f5SAndroid Build Coastguard Worker memcpy(b, &dqbuf->buffer, sizeof(*b));
946*1b4853f5SAndroid Build Coastguard Worker
947*1b4853f5SAndroid Build Coastguard Worker if (is_multiplanar) {
948*1b4853f5SAndroid Build Coastguard Worker b->m.planes = planes_backup;
949*1b4853f5SAndroid Build Coastguard Worker }
950*1b4853f5SAndroid Build Coastguard Worker
951*1b4853f5SAndroid Build Coastguard Worker if (V4L2_TYPE_IS_CAPTURE(b->type) && b->flags & V4L2_BUF_FLAG_LAST) {
952*1b4853f5SAndroid Build Coastguard Worker queue->is_capture_last = true;
953*1b4853f5SAndroid Build Coastguard Worker }
954*1b4853f5SAndroid Build Coastguard Worker
955*1b4853f5SAndroid Build Coastguard Worker return 0;
956*1b4853f5SAndroid Build Coastguard Worker }
957*1b4853f5SAndroid Build Coastguard Worker
958*1b4853f5SAndroid Build Coastguard Worker /*
959*1b4853f5SAndroid Build Coastguard Worker * s/g_input/output work with an unsigned int - recast this to a u32 so the
960*1b4853f5SAndroid Build Coastguard Worker * size is unambiguous.
961*1b4853f5SAndroid Build Coastguard Worker */
962*1b4853f5SAndroid Build Coastguard Worker
virtio_media_g_input(struct file * file,void * fh,unsigned int * i)963*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_g_input(struct file *file, void *fh, unsigned int *i)
964*1b4853f5SAndroid Build Coastguard Worker {
965*1b4853f5SAndroid Build Coastguard Worker u32 input;
966*1b4853f5SAndroid Build Coastguard Worker int ret;
967*1b4853f5SAndroid Build Coastguard Worker
968*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_wr_ioctl(fh, VIDIOC_G_INPUT, &input,
969*1b4853f5SAndroid Build Coastguard Worker sizeof(input), sizeof(input));
970*1b4853f5SAndroid Build Coastguard Worker if (ret)
971*1b4853f5SAndroid Build Coastguard Worker return ret;
972*1b4853f5SAndroid Build Coastguard Worker
973*1b4853f5SAndroid Build Coastguard Worker *i = input;
974*1b4853f5SAndroid Build Coastguard Worker
975*1b4853f5SAndroid Build Coastguard Worker return 0;
976*1b4853f5SAndroid Build Coastguard Worker }
977*1b4853f5SAndroid Build Coastguard Worker
virtio_media_s_input(struct file * file,void * fh,unsigned int i)978*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_s_input(struct file *file, void *fh, unsigned int i)
979*1b4853f5SAndroid Build Coastguard Worker {
980*1b4853f5SAndroid Build Coastguard Worker u32 input = i;
981*1b4853f5SAndroid Build Coastguard Worker
982*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_wr_ioctl(fh, VIDIOC_S_INPUT, &input,
983*1b4853f5SAndroid Build Coastguard Worker sizeof(input), sizeof(input));
984*1b4853f5SAndroid Build Coastguard Worker }
985*1b4853f5SAndroid Build Coastguard Worker
virtio_media_g_output(struct file * file,void * fh,unsigned int * o)986*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_g_output(struct file *file, void *fh, unsigned int *o)
987*1b4853f5SAndroid Build Coastguard Worker {
988*1b4853f5SAndroid Build Coastguard Worker u32 output;
989*1b4853f5SAndroid Build Coastguard Worker int ret;
990*1b4853f5SAndroid Build Coastguard Worker
991*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_wr_ioctl(fh, VIDIOC_G_OUTPUT, &output,
992*1b4853f5SAndroid Build Coastguard Worker sizeof(output), sizeof(output));
993*1b4853f5SAndroid Build Coastguard Worker if (ret)
994*1b4853f5SAndroid Build Coastguard Worker return ret;
995*1b4853f5SAndroid Build Coastguard Worker
996*1b4853f5SAndroid Build Coastguard Worker *o = output;
997*1b4853f5SAndroid Build Coastguard Worker
998*1b4853f5SAndroid Build Coastguard Worker return 0;
999*1b4853f5SAndroid Build Coastguard Worker }
1000*1b4853f5SAndroid Build Coastguard Worker
virtio_media_s_output(struct file * file,void * fh,unsigned int o)1001*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_s_output(struct file *file, void *fh, unsigned int o)
1002*1b4853f5SAndroid Build Coastguard Worker {
1003*1b4853f5SAndroid Build Coastguard Worker u32 output = o;
1004*1b4853f5SAndroid Build Coastguard Worker
1005*1b4853f5SAndroid Build Coastguard Worker return virtio_media_send_wr_ioctl(fh, VIDIOC_S_OUTPUT, &output,
1006*1b4853f5SAndroid Build Coastguard Worker sizeof(output), sizeof(output));
1007*1b4853f5SAndroid Build Coastguard Worker }
1008*1b4853f5SAndroid Build Coastguard Worker
1009*1b4853f5SAndroid Build Coastguard Worker /*
1010*1b4853f5SAndroid Build Coastguard Worker * decoder_cmd can affect the state of the CAPTURE queue.
1011*1b4853f5SAndroid Build Coastguard Worker */
1012*1b4853f5SAndroid Build Coastguard Worker
virtio_media_decoder_cmd(struct file * file,void * fh,struct v4l2_decoder_cmd * cmd)1013*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_decoder_cmd(struct file *file, void *fh,
1014*1b4853f5SAndroid Build Coastguard Worker struct v4l2_decoder_cmd *cmd)
1015*1b4853f5SAndroid Build Coastguard Worker {
1016*1b4853f5SAndroid Build Coastguard Worker struct virtio_media_session *session = fh_to_session(fh);
1017*1b4853f5SAndroid Build Coastguard Worker int ret;
1018*1b4853f5SAndroid Build Coastguard Worker
1019*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_wr_ioctl(fh, VIDIOC_DECODER_CMD, cmd,
1020*1b4853f5SAndroid Build Coastguard Worker sizeof(*cmd), sizeof(*cmd));
1021*1b4853f5SAndroid Build Coastguard Worker if (ret)
1022*1b4853f5SAndroid Build Coastguard Worker return ret;
1023*1b4853f5SAndroid Build Coastguard Worker
1024*1b4853f5SAndroid Build Coastguard Worker /* A START command makes the CAPTURE queue able to dequeue again. */
1025*1b4853f5SAndroid Build Coastguard Worker if (cmd->cmd == V4L2_DEC_CMD_START) {
1026*1b4853f5SAndroid Build Coastguard Worker session->queues[V4L2_BUF_TYPE_VIDEO_CAPTURE].is_capture_last =
1027*1b4853f5SAndroid Build Coastguard Worker false;
1028*1b4853f5SAndroid Build Coastguard Worker session->queues[V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]
1029*1b4853f5SAndroid Build Coastguard Worker .is_capture_last = false;
1030*1b4853f5SAndroid Build Coastguard Worker }
1031*1b4853f5SAndroid Build Coastguard Worker
1032*1b4853f5SAndroid Build Coastguard Worker return 0;
1033*1b4853f5SAndroid Build Coastguard Worker }
1034*1b4853f5SAndroid Build Coastguard Worker
1035*1b4853f5SAndroid Build Coastguard Worker /*
1036*1b4853f5SAndroid Build Coastguard Worker * s_std doesn't work with a pointer, so we cannot use SIMPLE_W_IOCTL.
1037*1b4853f5SAndroid Build Coastguard Worker */
1038*1b4853f5SAndroid Build Coastguard Worker
virtio_media_s_std(struct file * file,void * fh,v4l2_std_id s)1039*1b4853f5SAndroid Build Coastguard Worker static int virtio_media_s_std(struct file *file, void *fh, v4l2_std_id s)
1040*1b4853f5SAndroid Build Coastguard Worker {
1041*1b4853f5SAndroid Build Coastguard Worker int ret;
1042*1b4853f5SAndroid Build Coastguard Worker
1043*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_send_w_ioctl(fh, VIDIOC_S_STD, &s, sizeof(s));
1044*1b4853f5SAndroid Build Coastguard Worker if (ret)
1045*1b4853f5SAndroid Build Coastguard Worker return ret;
1046*1b4853f5SAndroid Build Coastguard Worker
1047*1b4853f5SAndroid Build Coastguard Worker return 0;
1048*1b4853f5SAndroid Build Coastguard Worker }
1049*1b4853f5SAndroid Build Coastguard Worker
1050*1b4853f5SAndroid Build Coastguard Worker const struct v4l2_ioctl_ops virtio_media_ioctl_ops = {
1051*1b4853f5SAndroid Build Coastguard Worker /* VIDIOC_QUERYCAP handler */
1052*1b4853f5SAndroid Build Coastguard Worker .vidioc_querycap = virtio_media_querycap,
1053*1b4853f5SAndroid Build Coastguard Worker
1054*1b4853f5SAndroid Build Coastguard Worker /* VIDIOC_ENUM_FMT handlers */
1055*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_vid_cap = virtio_media_enum_fmt,
1056*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_vid_overlay = virtio_media_enum_fmt,
1057*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_vid_out = virtio_media_enum_fmt,
1058*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_sdr_cap = virtio_media_enum_fmt,
1059*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_sdr_out = virtio_media_enum_fmt,
1060*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_meta_cap = virtio_media_enum_fmt,
1061*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_fmt_meta_out = virtio_media_enum_fmt,
1062*1b4853f5SAndroid Build Coastguard Worker
1063*1b4853f5SAndroid Build Coastguard Worker /* VIDIOC_G_FMT handlers */
1064*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vid_cap = virtio_media_g_fmt,
1065*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vid_overlay = virtio_media_g_fmt,
1066*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vid_out = virtio_media_g_fmt,
1067*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vid_out_overlay = virtio_media_g_fmt,
1068*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vbi_cap = virtio_media_g_fmt,
1069*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vbi_out = virtio_media_g_fmt,
1070*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_sliced_vbi_cap = virtio_media_g_fmt,
1071*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_sliced_vbi_out = virtio_media_g_fmt,
1072*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vid_cap_mplane = virtio_media_g_fmt,
1073*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_vid_out_mplane = virtio_media_g_fmt,
1074*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_sdr_cap = virtio_media_g_fmt,
1075*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_sdr_out = virtio_media_g_fmt,
1076*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_meta_cap = virtio_media_g_fmt,
1077*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fmt_meta_out = virtio_media_g_fmt,
1078*1b4853f5SAndroid Build Coastguard Worker
1079*1b4853f5SAndroid Build Coastguard Worker /* VIDIOC_S_FMT handlers */
1080*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vid_cap = virtio_media_s_fmt,
1081*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vid_overlay = virtio_media_s_fmt,
1082*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vid_out = virtio_media_s_fmt,
1083*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vid_out_overlay = virtio_media_s_fmt,
1084*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vbi_cap = virtio_media_s_fmt,
1085*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vbi_out = virtio_media_s_fmt,
1086*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_sliced_vbi_cap = virtio_media_s_fmt,
1087*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_sliced_vbi_out = virtio_media_s_fmt,
1088*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vid_cap_mplane = virtio_media_s_fmt,
1089*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_vid_out_mplane = virtio_media_s_fmt,
1090*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_sdr_cap = virtio_media_s_fmt,
1091*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_sdr_out = virtio_media_s_fmt,
1092*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_meta_cap = virtio_media_s_fmt,
1093*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fmt_meta_out = virtio_media_s_fmt,
1094*1b4853f5SAndroid Build Coastguard Worker
1095*1b4853f5SAndroid Build Coastguard Worker /* VIDIOC_TRY_FMT handlers */
1096*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vid_cap = virtio_media_try_fmt,
1097*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vid_overlay = virtio_media_try_fmt,
1098*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vid_out = virtio_media_try_fmt,
1099*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vid_out_overlay = virtio_media_try_fmt,
1100*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vbi_cap = virtio_media_try_fmt,
1101*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vbi_out = virtio_media_try_fmt,
1102*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_sliced_vbi_cap = virtio_media_try_fmt,
1103*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_sliced_vbi_out = virtio_media_try_fmt,
1104*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vid_cap_mplane = virtio_media_try_fmt,
1105*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_vid_out_mplane = virtio_media_try_fmt,
1106*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_sdr_cap = virtio_media_try_fmt,
1107*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_sdr_out = virtio_media_try_fmt,
1108*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_meta_cap = virtio_media_try_fmt,
1109*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_fmt_meta_out = virtio_media_try_fmt,
1110*1b4853f5SAndroid Build Coastguard Worker
1111*1b4853f5SAndroid Build Coastguard Worker /* Buffer handlers */
1112*1b4853f5SAndroid Build Coastguard Worker .vidioc_reqbufs = virtio_media_reqbufs,
1113*1b4853f5SAndroid Build Coastguard Worker .vidioc_querybuf = virtio_media_querybuf,
1114*1b4853f5SAndroid Build Coastguard Worker .vidioc_qbuf = virtio_media_qbuf,
1115*1b4853f5SAndroid Build Coastguard Worker .vidioc_expbuf = NULL,
1116*1b4853f5SAndroid Build Coastguard Worker .vidioc_dqbuf = virtio_media_dqbuf,
1117*1b4853f5SAndroid Build Coastguard Worker .vidioc_create_bufs = virtio_media_create_bufs,
1118*1b4853f5SAndroid Build Coastguard Worker .vidioc_prepare_buf = virtio_media_prepare_buf,
1119*1b4853f5SAndroid Build Coastguard Worker /* Overlay interface not supported yet */
1120*1b4853f5SAndroid Build Coastguard Worker .vidioc_overlay = NULL,
1121*1b4853f5SAndroid Build Coastguard Worker /* Overlay interface not supported yet */
1122*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_fbuf = NULL,
1123*1b4853f5SAndroid Build Coastguard Worker /* Overlay interface not supported yet */
1124*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_fbuf = NULL,
1125*1b4853f5SAndroid Build Coastguard Worker
1126*1b4853f5SAndroid Build Coastguard Worker /* Stream on/off */
1127*1b4853f5SAndroid Build Coastguard Worker .vidioc_streamon = virtio_media_streamon,
1128*1b4853f5SAndroid Build Coastguard Worker .vidioc_streamoff = virtio_media_streamoff,
1129*1b4853f5SAndroid Build Coastguard Worker
1130*1b4853f5SAndroid Build Coastguard Worker /* Standard handling */
1131*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_std = virtio_media_g_std,
1132*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_std = virtio_media_s_std,
1133*1b4853f5SAndroid Build Coastguard Worker .vidioc_querystd = virtio_media_querystd,
1134*1b4853f5SAndroid Build Coastguard Worker
1135*1b4853f5SAndroid Build Coastguard Worker /* Input handling */
1136*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_input = virtio_media_enuminput,
1137*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_input = virtio_media_g_input,
1138*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_input = virtio_media_s_input,
1139*1b4853f5SAndroid Build Coastguard Worker
1140*1b4853f5SAndroid Build Coastguard Worker /* Output handling */
1141*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_output = virtio_media_enumoutput,
1142*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_output = virtio_media_g_output,
1143*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_output = virtio_media_s_output,
1144*1b4853f5SAndroid Build Coastguard Worker
1145*1b4853f5SAndroid Build Coastguard Worker /* Control handling */
1146*1b4853f5SAndroid Build Coastguard Worker .vidioc_queryctrl = virtio_media_queryctrl,
1147*1b4853f5SAndroid Build Coastguard Worker .vidioc_query_ext_ctrl = virtio_media_query_ext_ctrl,
1148*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_ctrl = virtio_media_g_ctrl,
1149*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_ctrl = virtio_media_s_ctrl,
1150*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_ext_ctrls = virtio_media_g_ext_ctrls,
1151*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_ext_ctrls = virtio_media_s_ext_ctrls,
1152*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_ext_ctrls = virtio_media_try_ext_ctrls,
1153*1b4853f5SAndroid Build Coastguard Worker .vidioc_querymenu = virtio_media_querymenu,
1154*1b4853f5SAndroid Build Coastguard Worker
1155*1b4853f5SAndroid Build Coastguard Worker /* Audio ioctls */
1156*1b4853f5SAndroid Build Coastguard Worker .vidioc_enumaudio = virtio_media_enumaudio,
1157*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_audio = virtio_media_g_audio,
1158*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_audio = virtio_media_s_audio,
1159*1b4853f5SAndroid Build Coastguard Worker
1160*1b4853f5SAndroid Build Coastguard Worker /* Audio out ioctls */
1161*1b4853f5SAndroid Build Coastguard Worker .vidioc_enumaudout = virtio_media_enumaudout,
1162*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_audout = virtio_media_g_audout,
1163*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_audout = virtio_media_s_audout,
1164*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_modulator = virtio_media_g_modulator,
1165*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_modulator = virtio_media_s_modulator,
1166*1b4853f5SAndroid Build Coastguard Worker
1167*1b4853f5SAndroid Build Coastguard Worker /* Crop ioctls */
1168*1b4853f5SAndroid Build Coastguard Worker /* Not directly an ioctl (part of VIDIOC_CROPCAP), so no need to implement */
1169*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_pixelaspect = NULL,
1170*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_selection = virtio_media_g_selection,
1171*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_selection = virtio_media_s_selection,
1172*1b4853f5SAndroid Build Coastguard Worker
1173*1b4853f5SAndroid Build Coastguard Worker /* Compression ioctls */
1174*1b4853f5SAndroid Build Coastguard Worker /* Deprecated in V4L2. */
1175*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_jpegcomp = NULL,
1176*1b4853f5SAndroid Build Coastguard Worker /* Deprecated in V4L2. */
1177*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_jpegcomp = NULL,
1178*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_enc_index = virtio_media_g_enc_index,
1179*1b4853f5SAndroid Build Coastguard Worker .vidioc_encoder_cmd = virtio_media_encoder_cmd,
1180*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_encoder_cmd = virtio_media_try_encoder_cmd,
1181*1b4853f5SAndroid Build Coastguard Worker .vidioc_decoder_cmd = virtio_media_decoder_cmd,
1182*1b4853f5SAndroid Build Coastguard Worker .vidioc_try_decoder_cmd = virtio_media_try_decoder_cmd,
1183*1b4853f5SAndroid Build Coastguard Worker
1184*1b4853f5SAndroid Build Coastguard Worker /* Stream type-dependent parameter ioctls */
1185*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_parm = virtio_media_g_parm,
1186*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_parm = virtio_media_s_parm,
1187*1b4853f5SAndroid Build Coastguard Worker
1188*1b4853f5SAndroid Build Coastguard Worker /* Tuner ioctls */
1189*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_tuner = virtio_media_g_tuner,
1190*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_tuner = virtio_media_s_tuner,
1191*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_frequency = virtio_media_g_frequency,
1192*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_frequency = virtio_media_s_frequency,
1193*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_freq_bands = virtio_media_enum_freq_bands,
1194*1b4853f5SAndroid Build Coastguard Worker
1195*1b4853f5SAndroid Build Coastguard Worker /* Sliced VBI cap */
1196*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_sliced_vbi_cap = virtio_media_g_sliced_vbi_cap,
1197*1b4853f5SAndroid Build Coastguard Worker
1198*1b4853f5SAndroid Build Coastguard Worker /* Log status ioctl */
1199*1b4853f5SAndroid Build Coastguard Worker /* Guest-only operation */
1200*1b4853f5SAndroid Build Coastguard Worker .vidioc_log_status = NULL,
1201*1b4853f5SAndroid Build Coastguard Worker
1202*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_hw_freq_seek = virtio_media_s_hw_freq_seek,
1203*1b4853f5SAndroid Build Coastguard Worker
1204*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_framesizes = virtio_media_enum_framesizes,
1205*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_frameintervals = virtio_media_enum_frameintervals,
1206*1b4853f5SAndroid Build Coastguard Worker
1207*1b4853f5SAndroid Build Coastguard Worker /* DV Timings IOCTLs */
1208*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_dv_timings = virtio_media_s_dv_timings,
1209*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_dv_timings = virtio_media_g_dv_timings,
1210*1b4853f5SAndroid Build Coastguard Worker .vidioc_query_dv_timings = virtio_media_query_dv_timings,
1211*1b4853f5SAndroid Build Coastguard Worker .vidioc_enum_dv_timings = virtio_media_enum_dv_timings,
1212*1b4853f5SAndroid Build Coastguard Worker .vidioc_dv_timings_cap = virtio_media_dv_timings_cap,
1213*1b4853f5SAndroid Build Coastguard Worker .vidioc_g_edid = NULL,
1214*1b4853f5SAndroid Build Coastguard Worker .vidioc_s_edid = NULL,
1215*1b4853f5SAndroid Build Coastguard Worker
1216*1b4853f5SAndroid Build Coastguard Worker .vidioc_subscribe_event = virtio_media_subscribe_event,
1217*1b4853f5SAndroid Build Coastguard Worker .vidioc_unsubscribe_event = virtio_media_unsubscribe_event,
1218*1b4853f5SAndroid Build Coastguard Worker
1219*1b4853f5SAndroid Build Coastguard Worker /* For other private ioctls */
1220*1b4853f5SAndroid Build Coastguard Worker .vidioc_default = NULL,
1221*1b4853f5SAndroid Build Coastguard Worker };
1222*1b4853f5SAndroid Build Coastguard Worker
virtio_media_device_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1223*1b4853f5SAndroid Build Coastguard Worker long virtio_media_device_ioctl(struct file *file, unsigned int cmd,
1224*1b4853f5SAndroid Build Coastguard Worker unsigned long arg)
1225*1b4853f5SAndroid Build Coastguard Worker {
1226*1b4853f5SAndroid Build Coastguard Worker struct video_device *video_dev = video_devdata(file);
1227*1b4853f5SAndroid Build Coastguard Worker struct virtio_media *vv = to_virtio_media(video_dev);
1228*1b4853f5SAndroid Build Coastguard Worker struct v4l2_fh *vfh = NULL;
1229*1b4853f5SAndroid Build Coastguard Worker struct v4l2_standard standard;
1230*1b4853f5SAndroid Build Coastguard Worker v4l2_std_id std_id = 0;
1231*1b4853f5SAndroid Build Coastguard Worker int ret;
1232*1b4853f5SAndroid Build Coastguard Worker
1233*1b4853f5SAndroid Build Coastguard Worker if (test_bit(V4L2_FL_USES_V4L2_FH, &video_dev->flags))
1234*1b4853f5SAndroid Build Coastguard Worker vfh = file->private_data;
1235*1b4853f5SAndroid Build Coastguard Worker
1236*1b4853f5SAndroid Build Coastguard Worker mutex_lock(&vv->vlock);
1237*1b4853f5SAndroid Build Coastguard Worker
1238*1b4853f5SAndroid Build Coastguard Worker /*
1239*1b4853f5SAndroid Build Coastguard Worker * We need to handle a few ioctls manually because their result rely on
1240*1b4853f5SAndroid Build Coastguard Worker * vfd->tvnorms, which is normally updated by the driver as S_INPUT is
1241*1b4853f5SAndroid Build Coastguard Worker * called. Since we want to just pass these ioctls through, we have to hijack
1242*1b4853f5SAndroid Build Coastguard Worker * them from here.
1243*1b4853f5SAndroid Build Coastguard Worker */
1244*1b4853f5SAndroid Build Coastguard Worker switch (cmd) {
1245*1b4853f5SAndroid Build Coastguard Worker case VIDIOC_S_STD:
1246*1b4853f5SAndroid Build Coastguard Worker ret = copy_from_user(&std_id, (void __user *)arg,
1247*1b4853f5SAndroid Build Coastguard Worker sizeof(std_id));
1248*1b4853f5SAndroid Build Coastguard Worker if (ret) {
1249*1b4853f5SAndroid Build Coastguard Worker ret = -EINVAL;
1250*1b4853f5SAndroid Build Coastguard Worker break;
1251*1b4853f5SAndroid Build Coastguard Worker }
1252*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_s_std(file, vfh, std_id);
1253*1b4853f5SAndroid Build Coastguard Worker break;
1254*1b4853f5SAndroid Build Coastguard Worker case VIDIOC_ENUMSTD:
1255*1b4853f5SAndroid Build Coastguard Worker ret = copy_from_user(&standard, (void __user *)arg,
1256*1b4853f5SAndroid Build Coastguard Worker sizeof(standard));
1257*1b4853f5SAndroid Build Coastguard Worker if (ret) {
1258*1b4853f5SAndroid Build Coastguard Worker ret = -EINVAL;
1259*1b4853f5SAndroid Build Coastguard Worker break;
1260*1b4853f5SAndroid Build Coastguard Worker }
1261*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_enumstd(file, vfh, &standard);
1262*1b4853f5SAndroid Build Coastguard Worker if (ret)
1263*1b4853f5SAndroid Build Coastguard Worker break;
1264*1b4853f5SAndroid Build Coastguard Worker ret = copy_to_user((void __user *)arg, &standard,
1265*1b4853f5SAndroid Build Coastguard Worker sizeof(standard));
1266*1b4853f5SAndroid Build Coastguard Worker if (ret)
1267*1b4853f5SAndroid Build Coastguard Worker ret = -EINVAL;
1268*1b4853f5SAndroid Build Coastguard Worker break;
1269*1b4853f5SAndroid Build Coastguard Worker case VIDIOC_QUERYSTD:
1270*1b4853f5SAndroid Build Coastguard Worker ret = virtio_media_querystd(file, vfh, &std_id);
1271*1b4853f5SAndroid Build Coastguard Worker if (ret)
1272*1b4853f5SAndroid Build Coastguard Worker break;
1273*1b4853f5SAndroid Build Coastguard Worker ret = copy_to_user((void __user *)arg, &std_id, sizeof(std_id));
1274*1b4853f5SAndroid Build Coastguard Worker if (ret)
1275*1b4853f5SAndroid Build Coastguard Worker ret = -EINVAL;
1276*1b4853f5SAndroid Build Coastguard Worker break;
1277*1b4853f5SAndroid Build Coastguard Worker default:
1278*1b4853f5SAndroid Build Coastguard Worker ret = video_ioctl2(file, cmd, arg);
1279*1b4853f5SAndroid Build Coastguard Worker break;
1280*1b4853f5SAndroid Build Coastguard Worker }
1281*1b4853f5SAndroid Build Coastguard Worker
1282*1b4853f5SAndroid Build Coastguard Worker mutex_unlock(&vv->vlock);
1283*1b4853f5SAndroid Build Coastguard Worker
1284*1b4853f5SAndroid Build Coastguard Worker return ret;
1285*1b4853f5SAndroid Build Coastguard Worker }
1286