diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2012-02-20 00:21:00 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-05-07 15:49:09 -0400 |
commit | c6d26cfe26e475c9ddd09667dd6694b34469f4dc (patch) | |
tree | c4cc0acd78c242d5eb62d9ae922110993245d3a3 /drivers | |
parent | 5f1a12f5d03ecd920e09c08e1b9fc1312a1d6da4 (diff) |
[media] pvrusb2: convert to video_ioctl2
Note: there is one FIXME remaining: the tvnorms field of struct
video_device should be set up correctly. I have used V4L2_STD_ALL for
now, but I'm sure this can be improved. This field is used by
video_ioctl2 to implement ENUMSTD.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 1318 |
1 files changed, 679 insertions, 639 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 5e462faa272..83bc4675ec2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -150,733 +150,719 @@ static struct v4l2_format pvr_format [] = { | |||
150 | }; | 150 | }; |
151 | 151 | ||
152 | 152 | ||
153 | |||
153 | /* | 154 | /* |
154 | * pvr_ioctl() | 155 | * This is part of Video 4 Linux API. These procedures handle ioctl() calls. |
155 | * | ||
156 | * This is part of Video 4 Linux API. The procedure handles ioctl() calls. | ||
157 | * | ||
158 | */ | 156 | */ |
159 | static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 157 | static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) |
160 | { | 158 | { |
161 | struct pvr2_v4l2_fh *fh = file->private_data; | 159 | struct pvr2_v4l2_fh *fh = file->private_data; |
162 | struct pvr2_v4l2 *vp = fh->vhead; | ||
163 | struct pvr2_v4l2_dev *pdi = fh->pdi; | ||
164 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | 160 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
165 | long ret = -EINVAL; | ||
166 | |||
167 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
168 | v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd); | ||
169 | } | ||
170 | 161 | ||
171 | if (!pvr2_hdw_dev_ok(hdw)) { | 162 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); |
172 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | 163 | strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw), |
173 | "ioctl failed - bad or no context"); | 164 | sizeof(cap->bus_info)); |
174 | return -EFAULT; | 165 | strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card)); |
175 | } | 166 | return 0; |
176 | 167 | } | |
177 | /* check priority */ | ||
178 | switch (cmd) { | ||
179 | case VIDIOC_S_CTRL: | ||
180 | case VIDIOC_S_STD: | ||
181 | case VIDIOC_S_INPUT: | ||
182 | case VIDIOC_S_TUNER: | ||
183 | case VIDIOC_S_FREQUENCY: | ||
184 | ret = v4l2_prio_check(&vp->prio, fh->prio); | ||
185 | if (ret) | ||
186 | return ret; | ||
187 | } | ||
188 | 168 | ||
189 | switch (cmd) { | 169 | static int pvr2_g_priority(struct file *file, void *priv, enum v4l2_priority *p) |
190 | case VIDIOC_QUERYCAP: | 170 | { |
191 | { | 171 | struct pvr2_v4l2_fh *fh = file->private_data; |
192 | struct v4l2_capability *cap = arg; | 172 | struct pvr2_v4l2 *vp = fh->vhead; |
193 | 173 | ||
194 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); | 174 | *p = v4l2_prio_max(&vp->prio); |
195 | strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), | 175 | return 0; |
196 | sizeof(cap->bus_info)); | 176 | } |
197 | strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card)); | ||
198 | 177 | ||
199 | ret = 0; | 178 | static int pvr2_s_priority(struct file *file, void *priv, enum v4l2_priority prio) |
200 | break; | 179 | { |
201 | } | 180 | struct pvr2_v4l2_fh *fh = file->private_data; |
181 | struct pvr2_v4l2 *vp = fh->vhead; | ||
202 | 182 | ||
203 | case VIDIOC_G_PRIORITY: | 183 | return v4l2_prio_change(&vp->prio, &fh->prio, prio); |
204 | { | 184 | } |
205 | enum v4l2_priority *p = arg; | ||
206 | 185 | ||
207 | *p = v4l2_prio_max(&vp->prio); | 186 | static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) |
208 | ret = 0; | 187 | { |
209 | break; | 188 | struct pvr2_v4l2_fh *fh = file->private_data; |
210 | } | 189 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
190 | int val = 0; | ||
191 | int ret; | ||
211 | 192 | ||
212 | case VIDIOC_S_PRIORITY: | 193 | ret = pvr2_ctrl_get_value( |
213 | { | 194 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), &val); |
214 | enum v4l2_priority *prio = arg; | 195 | *std = val; |
196 | return ret; | ||
197 | } | ||
215 | 198 | ||
216 | ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio); | 199 | int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std) |
217 | break; | 200 | { |
218 | } | 201 | struct pvr2_v4l2_fh *fh = file->private_data; |
202 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
219 | 203 | ||
220 | case VIDIOC_ENUMSTD: | 204 | return pvr2_ctrl_set_value( |
221 | { | 205 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std); |
222 | struct v4l2_standard *vs = (struct v4l2_standard *)arg; | 206 | } |
223 | int idx = vs->index; | ||
224 | ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1); | ||
225 | break; | ||
226 | } | ||
227 | 207 | ||
228 | case VIDIOC_QUERYSTD: | 208 | static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) |
229 | { | 209 | { |
230 | v4l2_std_id *std = arg; | 210 | struct pvr2_v4l2_fh *fh = file->private_data; |
231 | *std = V4L2_STD_ALL; | 211 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
232 | ret = pvr2_hdw_get_detected_std(hdw, std); | 212 | struct pvr2_ctrl *cptr; |
233 | break; | 213 | struct v4l2_input tmp; |
234 | } | 214 | unsigned int cnt; |
215 | int val; | ||
216 | int ret; | ||
235 | 217 | ||
236 | case VIDIOC_G_STD: | 218 | cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT); |
237 | { | 219 | |
238 | int val = 0; | 220 | memset(&tmp, 0, sizeof(tmp)); |
239 | ret = pvr2_ctrl_get_value( | 221 | tmp.index = vi->index; |
240 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val); | 222 | ret = 0; |
241 | *(v4l2_std_id *)arg = val; | 223 | if (vi->index >= fh->input_cnt) |
224 | return -EINVAL; | ||
225 | val = fh->input_map[vi->index]; | ||
226 | switch (val) { | ||
227 | case PVR2_CVAL_INPUT_TV: | ||
228 | case PVR2_CVAL_INPUT_DTV: | ||
229 | case PVR2_CVAL_INPUT_RADIO: | ||
230 | tmp.type = V4L2_INPUT_TYPE_TUNER; | ||
242 | break; | 231 | break; |
243 | } | 232 | case PVR2_CVAL_INPUT_SVIDEO: |
244 | 233 | case PVR2_CVAL_INPUT_COMPOSITE: | |
245 | case VIDIOC_S_STD: | 234 | tmp.type = V4L2_INPUT_TYPE_CAMERA; |
246 | { | ||
247 | ret = pvr2_ctrl_set_value( | ||
248 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR), | ||
249 | *(v4l2_std_id *)arg); | ||
250 | break; | 235 | break; |
236 | default: | ||
237 | return -EINVAL; | ||
251 | } | 238 | } |
252 | 239 | ||
253 | case VIDIOC_ENUMINPUT: | 240 | cnt = 0; |
254 | { | 241 | pvr2_ctrl_get_valname(cptr, val, |
255 | struct pvr2_ctrl *cptr; | 242 | tmp.name, sizeof(tmp.name) - 1, &cnt); |
256 | struct v4l2_input *vi = (struct v4l2_input *)arg; | 243 | tmp.name[cnt] = 0; |
257 | struct v4l2_input tmp; | ||
258 | unsigned int cnt; | ||
259 | int val; | ||
260 | |||
261 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
262 | |||
263 | memset(&tmp,0,sizeof(tmp)); | ||
264 | tmp.index = vi->index; | ||
265 | ret = 0; | ||
266 | if (vi->index >= fh->input_cnt) { | ||
267 | ret = -EINVAL; | ||
268 | break; | ||
269 | } | ||
270 | val = fh->input_map[vi->index]; | ||
271 | switch (val) { | ||
272 | case PVR2_CVAL_INPUT_TV: | ||
273 | case PVR2_CVAL_INPUT_DTV: | ||
274 | case PVR2_CVAL_INPUT_RADIO: | ||
275 | tmp.type = V4L2_INPUT_TYPE_TUNER; | ||
276 | break; | ||
277 | case PVR2_CVAL_INPUT_SVIDEO: | ||
278 | case PVR2_CVAL_INPUT_COMPOSITE: | ||
279 | tmp.type = V4L2_INPUT_TYPE_CAMERA; | ||
280 | break; | ||
281 | default: | ||
282 | ret = -EINVAL; | ||
283 | break; | ||
284 | } | ||
285 | if (ret < 0) break; | ||
286 | |||
287 | cnt = 0; | ||
288 | pvr2_ctrl_get_valname(cptr,val, | ||
289 | tmp.name,sizeof(tmp.name)-1,&cnt); | ||
290 | tmp.name[cnt] = 0; | ||
291 | |||
292 | /* Don't bother with audioset, since this driver currently | ||
293 | always switches the audio whenever the video is | ||
294 | switched. */ | ||
295 | |||
296 | /* Handling std is a tougher problem. It doesn't make | ||
297 | sense in cases where a device might be multi-standard. | ||
298 | We could just copy out the current value for the | ||
299 | standard, but it can change over time. For now just | ||
300 | leave it zero. */ | ||
301 | 244 | ||
302 | memcpy(vi, &tmp, sizeof(tmp)); | 245 | /* Don't bother with audioset, since this driver currently |
246 | always switches the audio whenever the video is | ||
247 | switched. */ | ||
303 | 248 | ||
304 | ret = 0; | 249 | /* Handling std is a tougher problem. It doesn't make |
305 | break; | 250 | sense in cases where a device might be multi-standard. |
306 | } | 251 | We could just copy out the current value for the |
252 | standard, but it can change over time. For now just | ||
253 | leave it zero. */ | ||
254 | *vi = tmp; | ||
255 | return 0; | ||
256 | } | ||
307 | 257 | ||
308 | case VIDIOC_G_INPUT: | 258 | static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) |
309 | { | 259 | { |
310 | unsigned int idx; | 260 | struct pvr2_v4l2_fh *fh = file->private_data; |
311 | struct pvr2_ctrl *cptr; | 261 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
312 | struct v4l2_input *vi = (struct v4l2_input *)arg; | 262 | unsigned int idx; |
313 | int val; | 263 | struct pvr2_ctrl *cptr; |
314 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | 264 | int val; |
315 | val = 0; | 265 | int ret; |
316 | ret = pvr2_ctrl_get_value(cptr,&val); | ||
317 | vi->index = 0; | ||
318 | for (idx = 0; idx < fh->input_cnt; idx++) { | ||
319 | if (fh->input_map[idx] == val) { | ||
320 | vi->index = idx; | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | break; | ||
325 | } | ||
326 | 266 | ||
327 | case VIDIOC_S_INPUT: | 267 | cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT); |
328 | { | 268 | val = 0; |
329 | struct v4l2_input *vi = (struct v4l2_input *)arg; | 269 | ret = pvr2_ctrl_get_value(cptr, &val); |
330 | if (vi->index >= fh->input_cnt) { | 270 | *i = 0; |
331 | ret = -ERANGE; | 271 | for (idx = 0; idx < fh->input_cnt; idx++) { |
272 | if (fh->input_map[idx] == val) { | ||
273 | *i = idx; | ||
332 | break; | 274 | break; |
333 | } | 275 | } |
334 | ret = pvr2_ctrl_set_value( | ||
335 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), | ||
336 | fh->input_map[vi->index]); | ||
337 | break; | ||
338 | } | 276 | } |
277 | return ret; | ||
278 | } | ||
339 | 279 | ||
340 | case VIDIOC_ENUMAUDIO: | 280 | static int pvr2_s_input(struct file *file, void *priv, unsigned int inp) |
341 | { | 281 | { |
342 | /* pkt: FIXME: We are returning one "fake" input here | 282 | struct pvr2_v4l2_fh *fh = file->private_data; |
343 | which could very well be called "whatever_we_like". | 283 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
344 | This is for apps that want to see an audio input | ||
345 | just to feel comfortable, as well as to test if | ||
346 | it can do stereo or sth. There is actually no guarantee | ||
347 | that the actual audio input cannot change behind the app's | ||
348 | back, but most applications should not mind that either. | ||
349 | |||
350 | Hopefully, mplayer people will work with us on this (this | ||
351 | whole mess is to support mplayer pvr://), or Hans will come | ||
352 | up with a more standard way to say "we have inputs but we | ||
353 | don 't want you to change them independent of video" which | ||
354 | will sort this mess. | ||
355 | */ | ||
356 | struct v4l2_audio *vin = arg; | ||
357 | ret = -EINVAL; | ||
358 | if (vin->index > 0) break; | ||
359 | strncpy(vin->name, "PVRUSB2 Audio",14); | ||
360 | vin->capability = V4L2_AUDCAP_STEREO; | ||
361 | ret = 0; | ||
362 | break; | ||
363 | break; | ||
364 | } | ||
365 | 284 | ||
366 | case VIDIOC_G_AUDIO: | 285 | if (inp >= fh->input_cnt) |
367 | { | 286 | return -EINVAL; |
368 | /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */ | 287 | return pvr2_ctrl_set_value( |
369 | struct v4l2_audio *vin = arg; | 288 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT), |
370 | memset(vin,0,sizeof(*vin)); | 289 | fh->input_map[inp]); |
371 | vin->index = 0; | 290 | } |
372 | strncpy(vin->name, "PVRUSB2 Audio",14); | ||
373 | vin->capability = V4L2_AUDCAP_STEREO; | ||
374 | ret = 0; | ||
375 | break; | ||
376 | } | ||
377 | 291 | ||
378 | case VIDIOC_G_TUNER: | 292 | static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin) |
379 | { | 293 | { |
380 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; | 294 | /* pkt: FIXME: We are returning one "fake" input here |
295 | which could very well be called "whatever_we_like". | ||
296 | This is for apps that want to see an audio input | ||
297 | just to feel comfortable, as well as to test if | ||
298 | it can do stereo or sth. There is actually no guarantee | ||
299 | that the actual audio input cannot change behind the app's | ||
300 | back, but most applications should not mind that either. | ||
301 | |||
302 | Hopefully, mplayer people will work with us on this (this | ||
303 | whole mess is to support mplayer pvr://), or Hans will come | ||
304 | up with a more standard way to say "we have inputs but we | ||
305 | don 't want you to change them independent of video" which | ||
306 | will sort this mess. | ||
307 | */ | ||
308 | |||
309 | if (vin->index > 0) | ||
310 | return -EINVAL; | ||
311 | strncpy(vin->name, "PVRUSB2 Audio", 14); | ||
312 | vin->capability = V4L2_AUDCAP_STEREO; | ||
313 | return 0; | ||
314 | } | ||
381 | 315 | ||
382 | if (vt->index != 0) break; /* Only answer for the 1st tuner */ | 316 | static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin) |
317 | { | ||
318 | /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */ | ||
319 | vin->index = 0; | ||
320 | strncpy(vin->name, "PVRUSB2 Audio", 14); | ||
321 | vin->capability = V4L2_AUDCAP_STEREO; | ||
322 | return 0; | ||
323 | } | ||
383 | 324 | ||
384 | pvr2_hdw_execute_tuner_poll(hdw); | 325 | static int pvr2_s_audio(struct file *file, void *priv, struct v4l2_audio *vout) |
385 | ret = pvr2_hdw_get_tuner_status(hdw,vt); | 326 | { |
386 | break; | 327 | if (vout->index) |
387 | } | 328 | return -EINVAL; |
329 | return 0; | ||
330 | } | ||
388 | 331 | ||
389 | case VIDIOC_S_TUNER: | 332 | static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) |
390 | { | 333 | { |
391 | struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; | 334 | struct pvr2_v4l2_fh *fh = file->private_data; |
335 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
392 | 336 | ||
393 | if (vt->index != 0) | 337 | if (vt->index != 0) |
394 | break; | 338 | return -EINVAL; /* Only answer for the 1st tuner */ |
395 | 339 | ||
396 | ret = pvr2_ctrl_set_value( | 340 | pvr2_hdw_execute_tuner_poll(hdw); |
397 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), | 341 | return pvr2_hdw_get_tuner_status(hdw, vt); |
342 | } | ||
343 | |||
344 | static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) | ||
345 | { | ||
346 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
347 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
348 | |||
349 | if (vt->index != 0) | ||
350 | return -EINVAL; | ||
351 | |||
352 | return pvr2_ctrl_set_value( | ||
353 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_AUDIOMODE), | ||
398 | vt->audmode); | 354 | vt->audmode); |
399 | break; | 355 | } |
400 | } | ||
401 | 356 | ||
402 | case VIDIOC_S_FREQUENCY: | 357 | int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) |
403 | { | 358 | { |
404 | const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; | 359 | struct pvr2_v4l2_fh *fh = file->private_data; |
405 | unsigned long fv; | 360 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
406 | struct v4l2_tuner vt; | 361 | unsigned long fv; |
407 | int cur_input; | 362 | struct v4l2_tuner vt; |
408 | struct pvr2_ctrl *ctrlp; | 363 | int cur_input; |
409 | ret = pvr2_hdw_get_tuner_status(hdw,&vt); | 364 | struct pvr2_ctrl *ctrlp; |
410 | if (ret != 0) break; | 365 | int ret; |
411 | ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | 366 | |
412 | ret = pvr2_ctrl_get_value(ctrlp,&cur_input); | 367 | ret = pvr2_hdw_get_tuner_status(hdw, &vt); |
413 | if (ret != 0) break; | 368 | if (ret != 0) |
414 | if (vf->type == V4L2_TUNER_RADIO) { | 369 | return ret; |
415 | if (cur_input != PVR2_CVAL_INPUT_RADIO) { | 370 | ctrlp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT); |
416 | pvr2_ctrl_set_value(ctrlp, | 371 | ret = pvr2_ctrl_get_value(ctrlp, &cur_input); |
417 | PVR2_CVAL_INPUT_RADIO); | 372 | if (ret != 0) |
418 | } | 373 | return ret; |
419 | } else { | 374 | if (vf->type == V4L2_TUNER_RADIO) { |
420 | if (cur_input == PVR2_CVAL_INPUT_RADIO) { | 375 | if (cur_input != PVR2_CVAL_INPUT_RADIO) |
421 | pvr2_ctrl_set_value(ctrlp, | 376 | pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_RADIO); |
422 | PVR2_CVAL_INPUT_TV); | 377 | } else { |
423 | } | 378 | if (cur_input == PVR2_CVAL_INPUT_RADIO) |
424 | } | 379 | pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_TV); |
425 | fv = vf->frequency; | 380 | } |
426 | if (vt.capability & V4L2_TUNER_CAP_LOW) { | 381 | fv = vf->frequency; |
427 | fv = (fv * 125) / 2; | 382 | if (vt.capability & V4L2_TUNER_CAP_LOW) |
428 | } else { | 383 | fv = (fv * 125) / 2; |
429 | fv = fv * 62500; | 384 | else |
430 | } | 385 | fv = fv * 62500; |
431 | ret = pvr2_ctrl_set_value( | 386 | return pvr2_ctrl_set_value( |
432 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv); | 387 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv); |
433 | break; | 388 | } |
434 | } | ||
435 | 389 | ||
436 | case VIDIOC_G_FREQUENCY: | 390 | static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) |
437 | { | 391 | { |
438 | struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; | 392 | struct pvr2_v4l2_fh *fh = file->private_data; |
439 | int val = 0; | 393 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
440 | int cur_input; | 394 | int val = 0; |
441 | struct v4l2_tuner vt; | 395 | int cur_input; |
442 | ret = pvr2_hdw_get_tuner_status(hdw,&vt); | 396 | struct v4l2_tuner vt; |
443 | if (ret != 0) break; | 397 | int ret; |
444 | ret = pvr2_ctrl_get_value( | 398 | |
445 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), | 399 | ret = pvr2_hdw_get_tuner_status(hdw, &vt); |
400 | if (ret != 0) | ||
401 | return ret; | ||
402 | ret = pvr2_ctrl_get_value( | ||
403 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_FREQUENCY), | ||
446 | &val); | 404 | &val); |
447 | if (ret != 0) break; | 405 | if (ret != 0) |
448 | pvr2_ctrl_get_value( | 406 | return ret; |
449 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), | 407 | pvr2_ctrl_get_value( |
408 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT), | ||
450 | &cur_input); | 409 | &cur_input); |
451 | if (cur_input == PVR2_CVAL_INPUT_RADIO) { | 410 | if (cur_input == PVR2_CVAL_INPUT_RADIO) |
452 | vf->type = V4L2_TUNER_RADIO; | 411 | vf->type = V4L2_TUNER_RADIO; |
453 | } else { | 412 | else |
454 | vf->type = V4L2_TUNER_ANALOG_TV; | 413 | vf->type = V4L2_TUNER_ANALOG_TV; |
455 | } | 414 | if (vt.capability & V4L2_TUNER_CAP_LOW) |
456 | if (vt.capability & V4L2_TUNER_CAP_LOW) { | 415 | val = (val * 2) / 125; |
457 | val = (val * 2) / 125; | 416 | else |
458 | } else { | 417 | val /= 62500; |
459 | val /= 62500; | 418 | vf->frequency = val; |
460 | } | 419 | return 0; |
461 | vf->frequency = val; | 420 | } |
462 | break; | ||
463 | } | ||
464 | 421 | ||
465 | case VIDIOC_ENUM_FMT: | 422 | static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fd) |
466 | { | 423 | { |
467 | struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg; | 424 | /* Only one format is supported : mpeg.*/ |
425 | if (fd->index != 0) | ||
426 | return -EINVAL; | ||
468 | 427 | ||
469 | /* Only one format is supported : mpeg.*/ | 428 | memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc)); |
470 | if (fd->index != 0) | 429 | return 0; |
471 | break; | 430 | } |
472 | 431 | ||
473 | memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc)); | 432 | static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) |
474 | ret = 0; | 433 | { |
475 | break; | 434 | struct pvr2_v4l2_fh *fh = file->private_data; |
476 | } | 435 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
436 | int val; | ||
477 | 437 | ||
478 | case VIDIOC_G_FMT: | 438 | memcpy(vf, &pvr_format[PVR_FORMAT_PIX], sizeof(struct v4l2_format)); |
479 | { | 439 | val = 0; |
480 | struct v4l2_format *vf = (struct v4l2_format *)arg; | 440 | pvr2_ctrl_get_value( |
481 | int val; | 441 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES), |
482 | switch(vf->type) { | 442 | &val); |
483 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 443 | vf->fmt.pix.width = val; |
484 | memcpy(vf, &pvr_format[PVR_FORMAT_PIX], | 444 | val = 0; |
485 | sizeof(struct v4l2_format)); | 445 | pvr2_ctrl_get_value( |
486 | val = 0; | 446 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES), |
487 | pvr2_ctrl_get_value( | 447 | &val); |
488 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES), | 448 | vf->fmt.pix.height = val; |
489 | &val); | 449 | return 0; |
490 | vf->fmt.pix.width = val; | 450 | } |
491 | val = 0; | ||
492 | pvr2_ctrl_get_value( | ||
493 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES), | ||
494 | &val); | ||
495 | vf->fmt.pix.height = val; | ||
496 | ret = 0; | ||
497 | break; | ||
498 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
499 | // ????? Still need to figure out to do VBI correctly | ||
500 | ret = -EINVAL; | ||
501 | break; | ||
502 | default: | ||
503 | ret = -EINVAL; | ||
504 | break; | ||
505 | } | ||
506 | break; | ||
507 | } | ||
508 | 451 | ||
509 | case VIDIOC_TRY_FMT: | 452 | static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) |
510 | case VIDIOC_S_FMT: | 453 | { |
511 | { | 454 | struct pvr2_v4l2_fh *fh = file->private_data; |
512 | struct v4l2_format *vf = (struct v4l2_format *)arg; | 455 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
513 | 456 | int lmin, lmax, ldef; | |
514 | ret = 0; | 457 | struct pvr2_ctrl *hcp, *vcp; |
515 | switch(vf->type) { | 458 | int h = vf->fmt.pix.height; |
516 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { | 459 | int w = vf->fmt.pix.width; |
517 | int lmin,lmax,ldef; | 460 | |
518 | struct pvr2_ctrl *hcp,*vcp; | 461 | hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES); |
519 | int h = vf->fmt.pix.height; | 462 | vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES); |
520 | int w = vf->fmt.pix.width; | 463 | |
521 | hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES); | 464 | lmin = pvr2_ctrl_get_min(hcp); |
522 | vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES); | 465 | lmax = pvr2_ctrl_get_max(hcp); |
523 | 466 | pvr2_ctrl_get_def(hcp, &ldef); | |
524 | lmin = pvr2_ctrl_get_min(hcp); | 467 | if (w == -1) |
525 | lmax = pvr2_ctrl_get_max(hcp); | 468 | w = ldef; |
526 | pvr2_ctrl_get_def(hcp, &ldef); | 469 | else if (w < lmin) |
527 | if (w == -1) { | 470 | w = lmin; |
528 | w = ldef; | 471 | else if (w > lmax) |
529 | } else if (w < lmin) { | 472 | w = lmax; |
530 | w = lmin; | 473 | lmin = pvr2_ctrl_get_min(vcp); |
531 | } else if (w > lmax) { | 474 | lmax = pvr2_ctrl_get_max(vcp); |
532 | w = lmax; | 475 | pvr2_ctrl_get_def(vcp, &ldef); |
533 | } | 476 | if (h == -1) |
534 | lmin = pvr2_ctrl_get_min(vcp); | 477 | h = ldef; |
535 | lmax = pvr2_ctrl_get_max(vcp); | 478 | else if (h < lmin) |
536 | pvr2_ctrl_get_def(vcp, &ldef); | 479 | h = lmin; |
537 | if (h == -1) { | 480 | else if (h > lmax) |
538 | h = ldef; | 481 | h = lmax; |
539 | } else if (h < lmin) { | 482 | |
540 | h = lmin; | 483 | memcpy(vf, &pvr_format[PVR_FORMAT_PIX], |
541 | } else if (h > lmax) { | 484 | sizeof(struct v4l2_format)); |
542 | h = lmax; | 485 | vf->fmt.pix.width = w; |
543 | } | 486 | vf->fmt.pix.height = h; |
487 | return 0; | ||
488 | } | ||
544 | 489 | ||
545 | memcpy(vf, &pvr_format[PVR_FORMAT_PIX], | 490 | static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) |
546 | sizeof(struct v4l2_format)); | 491 | { |
547 | vf->fmt.pix.width = w; | 492 | struct pvr2_v4l2_fh *fh = file->private_data; |
548 | vf->fmt.pix.height = h; | 493 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
494 | struct pvr2_ctrl *hcp, *vcp; | ||
495 | int ret = pvr2_try_fmt_vid_cap(file, fh, vf); | ||
549 | 496 | ||
550 | if (cmd == VIDIOC_S_FMT) { | 497 | if (ret) |
551 | pvr2_ctrl_set_value(hcp,vf->fmt.pix.width); | 498 | return ret; |
552 | pvr2_ctrl_set_value(vcp,vf->fmt.pix.height); | 499 | hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES); |
553 | } | 500 | vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES); |
554 | } break; | 501 | pvr2_ctrl_set_value(hcp, vf->fmt.pix.width); |
555 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 502 | pvr2_ctrl_set_value(vcp, vf->fmt.pix.height); |
556 | // ????? Still need to figure out to do VBI correctly | 503 | return 0; |
557 | ret = -EINVAL; | 504 | } |
558 | break; | ||
559 | default: | ||
560 | ret = -EINVAL; | ||
561 | break; | ||
562 | } | ||
563 | break; | ||
564 | } | ||
565 | 505 | ||
566 | case VIDIOC_STREAMON: | 506 | static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
567 | { | 507 | { |
568 | if (!fh->pdi->stream) { | 508 | struct pvr2_v4l2_fh *fh = file->private_data; |
569 | /* No stream defined for this node. This means | 509 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
570 | that we're not currently allowed to stream from | 510 | struct pvr2_v4l2_dev *pdi = fh->pdi; |
571 | this node. */ | 511 | int ret; |
572 | ret = -EPERM; | 512 | |
573 | break; | 513 | if (!fh->pdi->stream) { |
574 | } | 514 | /* No stream defined for this node. This means |
575 | ret = pvr2_hdw_set_stream_type(hdw,pdi->config); | 515 | that we're not currently allowed to stream from |
576 | if (ret < 0) return ret; | 516 | this node. */ |
577 | ret = pvr2_hdw_set_streaming(hdw,!0); | 517 | return -EPERM; |
578 | break; | ||
579 | } | 518 | } |
519 | ret = pvr2_hdw_set_stream_type(hdw, pdi->config); | ||
520 | if (ret < 0) | ||
521 | return ret; | ||
522 | return pvr2_hdw_set_streaming(hdw, !0); | ||
523 | } | ||
580 | 524 | ||
581 | case VIDIOC_STREAMOFF: | 525 | static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
582 | { | 526 | { |
583 | if (!fh->pdi->stream) { | 527 | struct pvr2_v4l2_fh *fh = file->private_data; |
584 | /* No stream defined for this node. This means | 528 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
585 | that we're not currently allowed to stream from | 529 | |
586 | this node. */ | 530 | if (!fh->pdi->stream) { |
587 | ret = -EPERM; | 531 | /* No stream defined for this node. This means |
588 | break; | 532 | that we're not currently allowed to stream from |
589 | } | 533 | this node. */ |
590 | ret = pvr2_hdw_set_streaming(hdw,0); | 534 | return -EPERM; |
591 | break; | ||
592 | } | 535 | } |
536 | return pvr2_hdw_set_streaming(hdw, 0); | ||
537 | } | ||
593 | 538 | ||
594 | case VIDIOC_QUERYCTRL: | 539 | static int pvr2_queryctrl(struct file *file, void *priv, |
595 | { | 540 | struct v4l2_queryctrl *vc) |
596 | struct pvr2_ctrl *cptr; | 541 | { |
597 | int val; | 542 | struct pvr2_v4l2_fh *fh = file->private_data; |
598 | struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg; | 543 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
599 | ret = 0; | 544 | struct pvr2_ctrl *cptr; |
600 | if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) { | 545 | int val; |
601 | cptr = pvr2_hdw_get_ctrl_nextv4l( | 546 | int ret; |
602 | hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL)); | ||
603 | if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr); | ||
604 | } else { | ||
605 | cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id); | ||
606 | } | ||
607 | if (!cptr) { | ||
608 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
609 | "QUERYCTRL id=0x%x not implemented here", | ||
610 | vc->id); | ||
611 | ret = -EINVAL; | ||
612 | break; | ||
613 | } | ||
614 | 547 | ||
548 | ret = 0; | ||
549 | if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) { | ||
550 | cptr = pvr2_hdw_get_ctrl_nextv4l( | ||
551 | hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL)); | ||
552 | if (cptr) | ||
553 | vc->id = pvr2_ctrl_get_v4lid(cptr); | ||
554 | } else { | ||
555 | cptr = pvr2_hdw_get_ctrl_v4l(hdw, vc->id); | ||
556 | } | ||
557 | if (!cptr) { | ||
615 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | 558 | pvr2_trace(PVR2_TRACE_V4LIOCTL, |
616 | "QUERYCTRL id=0x%x mapping name=%s (%s)", | 559 | "QUERYCTRL id=0x%x not implemented here", |
617 | vc->id,pvr2_ctrl_get_name(cptr), | 560 | vc->id); |
618 | pvr2_ctrl_get_desc(cptr)); | 561 | return -EINVAL; |
619 | strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name)); | 562 | } |
620 | vc->flags = pvr2_ctrl_get_v4lflags(cptr); | 563 | |
621 | pvr2_ctrl_get_def(cptr, &val); | 564 | pvr2_trace(PVR2_TRACE_V4LIOCTL, |
622 | vc->default_value = val; | 565 | "QUERYCTRL id=0x%x mapping name=%s (%s)", |
623 | switch (pvr2_ctrl_get_type(cptr)) { | 566 | vc->id, pvr2_ctrl_get_name(cptr), |
624 | case pvr2_ctl_enum: | 567 | pvr2_ctrl_get_desc(cptr)); |
625 | vc->type = V4L2_CTRL_TYPE_MENU; | 568 | strlcpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name)); |
626 | vc->minimum = 0; | 569 | vc->flags = pvr2_ctrl_get_v4lflags(cptr); |
627 | vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1; | 570 | pvr2_ctrl_get_def(cptr, &val); |
628 | vc->step = 1; | 571 | vc->default_value = val; |
629 | break; | 572 | switch (pvr2_ctrl_get_type(cptr)) { |
630 | case pvr2_ctl_bool: | 573 | case pvr2_ctl_enum: |
631 | vc->type = V4L2_CTRL_TYPE_BOOLEAN; | 574 | vc->type = V4L2_CTRL_TYPE_MENU; |
632 | vc->minimum = 0; | 575 | vc->minimum = 0; |
633 | vc->maximum = 1; | 576 | vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1; |
634 | vc->step = 1; | 577 | vc->step = 1; |
635 | break; | ||
636 | case pvr2_ctl_int: | ||
637 | vc->type = V4L2_CTRL_TYPE_INTEGER; | ||
638 | vc->minimum = pvr2_ctrl_get_min(cptr); | ||
639 | vc->maximum = pvr2_ctrl_get_max(cptr); | ||
640 | vc->step = 1; | ||
641 | break; | ||
642 | default: | ||
643 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
644 | "QUERYCTRL id=0x%x name=%s not mappable", | ||
645 | vc->id,pvr2_ctrl_get_name(cptr)); | ||
646 | ret = -EINVAL; | ||
647 | break; | ||
648 | } | ||
649 | break; | 578 | break; |
650 | } | 579 | case pvr2_ctl_bool: |
651 | 580 | vc->type = V4L2_CTRL_TYPE_BOOLEAN; | |
652 | case VIDIOC_QUERYMENU: | 581 | vc->minimum = 0; |
653 | { | 582 | vc->maximum = 1; |
654 | struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg; | 583 | vc->step = 1; |
655 | unsigned int cnt = 0; | ||
656 | ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id), | ||
657 | vm->index, | ||
658 | vm->name,sizeof(vm->name)-1, | ||
659 | &cnt); | ||
660 | vm->name[cnt] = 0; | ||
661 | break; | 584 | break; |
662 | } | 585 | case pvr2_ctl_int: |
663 | 586 | vc->type = V4L2_CTRL_TYPE_INTEGER; | |
664 | case VIDIOC_G_CTRL: | 587 | vc->minimum = pvr2_ctrl_get_min(cptr); |
665 | { | 588 | vc->maximum = pvr2_ctrl_get_max(cptr); |
666 | struct v4l2_control *vc = (struct v4l2_control *)arg; | 589 | vc->step = 1; |
667 | int val = 0; | ||
668 | ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id), | ||
669 | &val); | ||
670 | vc->value = val; | ||
671 | break; | 590 | break; |
591 | default: | ||
592 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
593 | "QUERYCTRL id=0x%x name=%s not mappable", | ||
594 | vc->id, pvr2_ctrl_get_name(cptr)); | ||
595 | return -EINVAL; | ||
672 | } | 596 | } |
597 | return 0; | ||
598 | } | ||
673 | 599 | ||
674 | case VIDIOC_S_CTRL: | 600 | static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm) |
675 | { | 601 | { |
676 | struct v4l2_control *vc = (struct v4l2_control *)arg; | 602 | struct pvr2_v4l2_fh *fh = file->private_data; |
677 | ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id), | 603 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
678 | vc->value); | 604 | unsigned int cnt = 0; |
679 | break; | 605 | int ret; |
680 | } | ||
681 | 606 | ||
682 | case VIDIOC_G_EXT_CTRLS: | 607 | ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw, vm->id), |
683 | { | 608 | vm->index, |
684 | struct v4l2_ext_controls *ctls = | 609 | vm->name, sizeof(vm->name) - 1, |
685 | (struct v4l2_ext_controls *)arg; | 610 | &cnt); |
686 | struct v4l2_ext_control *ctrl; | 611 | vm->name[cnt] = 0; |
687 | unsigned int idx; | 612 | return ret; |
688 | int val; | 613 | } |
689 | ret = 0; | 614 | |
690 | for (idx = 0; idx < ctls->count; idx++) { | 615 | static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc) |
691 | ctrl = ctls->controls + idx; | 616 | { |
692 | ret = pvr2_ctrl_get_value( | 617 | struct pvr2_v4l2_fh *fh = file->private_data; |
693 | pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val); | 618 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
694 | if (ret) { | 619 | int val = 0; |
695 | ctls->error_idx = idx; | 620 | int ret; |
696 | break; | 621 | |
697 | } | 622 | ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id), |
698 | /* Ensure that if read as a 64 bit value, the user | 623 | &val); |
699 | will still get a hopefully sane value */ | 624 | vc->value = val; |
700 | ctrl->value64 = 0; | 625 | return ret; |
701 | ctrl->value = val; | 626 | } |
627 | |||
628 | static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc) | ||
629 | { | ||
630 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
631 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
632 | |||
633 | return pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id), | ||
634 | vc->value); | ||
635 | } | ||
636 | |||
637 | static int pvr2_g_ext_ctrls(struct file *file, void *priv, | ||
638 | struct v4l2_ext_controls *ctls) | ||
639 | { | ||
640 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
641 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
642 | struct v4l2_ext_control *ctrl; | ||
643 | unsigned int idx; | ||
644 | int val; | ||
645 | int ret; | ||
646 | |||
647 | ret = 0; | ||
648 | for (idx = 0; idx < ctls->count; idx++) { | ||
649 | ctrl = ctls->controls + idx; | ||
650 | ret = pvr2_ctrl_get_value( | ||
651 | pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val); | ||
652 | if (ret) { | ||
653 | ctls->error_idx = idx; | ||
654 | return ret; | ||
702 | } | 655 | } |
703 | break; | 656 | /* Ensure that if read as a 64 bit value, the user |
657 | will still get a hopefully sane value */ | ||
658 | ctrl->value64 = 0; | ||
659 | ctrl->value = val; | ||
704 | } | 660 | } |
661 | return 0; | ||
662 | } | ||
705 | 663 | ||
706 | case VIDIOC_S_EXT_CTRLS: | 664 | static int pvr2_s_ext_ctrls(struct file *file, void *priv, |
707 | { | 665 | struct v4l2_ext_controls *ctls) |
708 | struct v4l2_ext_controls *ctls = | 666 | { |
709 | (struct v4l2_ext_controls *)arg; | 667 | struct pvr2_v4l2_fh *fh = file->private_data; |
710 | struct v4l2_ext_control *ctrl; | 668 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
711 | unsigned int idx; | 669 | struct v4l2_ext_control *ctrl; |
712 | ret = 0; | 670 | unsigned int idx; |
713 | for (idx = 0; idx < ctls->count; idx++) { | 671 | int ret; |
714 | ctrl = ctls->controls + idx; | 672 | |
715 | ret = pvr2_ctrl_set_value( | 673 | ret = 0; |
716 | pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id), | 674 | for (idx = 0; idx < ctls->count; idx++) { |
675 | ctrl = ctls->controls + idx; | ||
676 | ret = pvr2_ctrl_set_value( | ||
677 | pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), | ||
717 | ctrl->value); | 678 | ctrl->value); |
718 | if (ret) { | 679 | if (ret) { |
719 | ctls->error_idx = idx; | 680 | ctls->error_idx = idx; |
720 | break; | 681 | return ret; |
721 | } | ||
722 | } | 682 | } |
723 | break; | ||
724 | } | 683 | } |
684 | return 0; | ||
685 | } | ||
725 | 686 | ||
726 | case VIDIOC_TRY_EXT_CTRLS: | 687 | static int pvr2_try_ext_ctrls(struct file *file, void *priv, |
727 | { | 688 | struct v4l2_ext_controls *ctls) |
728 | struct v4l2_ext_controls *ctls = | 689 | { |
729 | (struct v4l2_ext_controls *)arg; | 690 | struct pvr2_v4l2_fh *fh = file->private_data; |
730 | struct v4l2_ext_control *ctrl; | 691 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
731 | struct pvr2_ctrl *pctl; | 692 | struct v4l2_ext_control *ctrl; |
732 | unsigned int idx; | 693 | struct pvr2_ctrl *pctl; |
733 | /* For the moment just validate that the requested control | 694 | unsigned int idx; |
734 | actually exists. */ | 695 | int ret; |
735 | ret = 0; | ||
736 | for (idx = 0; idx < ctls->count; idx++) { | ||
737 | ctrl = ctls->controls + idx; | ||
738 | pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id); | ||
739 | if (!pctl) { | ||
740 | ret = -EINVAL; | ||
741 | ctls->error_idx = idx; | ||
742 | break; | ||
743 | } | ||
744 | } | ||
745 | break; | ||
746 | } | ||
747 | 696 | ||
748 | case VIDIOC_CROPCAP: | 697 | /* For the moment just validate that the requested control |
749 | { | 698 | actually exists. */ |
750 | struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg; | 699 | ret = 0; |
751 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 700 | for (idx = 0; idx < ctls->count; idx++) { |
752 | ret = -EINVAL; | 701 | ctrl = ctls->controls + idx; |
753 | break; | 702 | pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id); |
703 | if (!pctl) { | ||
704 | ctls->error_idx = idx; | ||
705 | return -EINVAL; | ||
754 | } | 706 | } |
755 | ret = pvr2_hdw_get_cropcap(hdw, cap); | ||
756 | cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */ | ||
757 | break; | ||
758 | } | 707 | } |
759 | case VIDIOC_G_CROP: | 708 | return 0; |
760 | { | 709 | } |
761 | struct v4l2_crop *crop = (struct v4l2_crop *)arg; | 710 | |
762 | int val = 0; | 711 | static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap) |
763 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 712 | { |
764 | ret = -EINVAL; | 713 | struct pvr2_v4l2_fh *fh = file->private_data; |
765 | break; | 714 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
766 | } | 715 | int ret; |
767 | ret = pvr2_ctrl_get_value( | 716 | |
717 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
718 | return -EINVAL; | ||
719 | ret = pvr2_hdw_get_cropcap(hdw, cap); | ||
720 | cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */ | ||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | static int pvr2_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) | ||
725 | { | ||
726 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
727 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
728 | int val = 0; | ||
729 | int ret; | ||
730 | |||
731 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
732 | return -EINVAL; | ||
733 | ret = pvr2_ctrl_get_value( | ||
768 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val); | 734 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val); |
769 | if (ret != 0) { | 735 | if (ret != 0) |
770 | ret = -EINVAL; | 736 | return -EINVAL; |
771 | break; | 737 | crop->c.left = val; |
772 | } | 738 | ret = pvr2_ctrl_get_value( |
773 | crop->c.left = val; | ||
774 | ret = pvr2_ctrl_get_value( | ||
775 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val); | 739 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val); |
776 | if (ret != 0) { | 740 | if (ret != 0) |
777 | ret = -EINVAL; | 741 | return -EINVAL; |
778 | break; | 742 | crop->c.top = val; |
779 | } | 743 | ret = pvr2_ctrl_get_value( |
780 | crop->c.top = val; | ||
781 | ret = pvr2_ctrl_get_value( | ||
782 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val); | 744 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val); |
783 | if (ret != 0) { | 745 | if (ret != 0) |
784 | ret = -EINVAL; | 746 | return -EINVAL; |
785 | break; | 747 | crop->c.width = val; |
786 | } | 748 | ret = pvr2_ctrl_get_value( |
787 | crop->c.width = val; | ||
788 | ret = pvr2_ctrl_get_value( | ||
789 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val); | 749 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val); |
790 | if (ret != 0) { | 750 | if (ret != 0) |
791 | ret = -EINVAL; | 751 | return -EINVAL; |
792 | break; | 752 | crop->c.height = val; |
793 | } | 753 | return 0; |
794 | crop->c.height = val; | 754 | } |
795 | } | 755 | |
796 | case VIDIOC_S_CROP: | 756 | static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) |
797 | { | 757 | { |
798 | struct v4l2_crop *crop = (struct v4l2_crop *)arg; | 758 | struct pvr2_v4l2_fh *fh = file->private_data; |
799 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 759 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
800 | ret = -EINVAL; | 760 | struct v4l2_cropcap cap; |
801 | break; | 761 | int ret; |
802 | } | 762 | |
803 | ret = pvr2_ctrl_set_value( | 763 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
764 | return -EINVAL; | ||
765 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
766 | ret = pvr2_ctrl_set_value( | ||
804 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), | 767 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), |
805 | crop->c.left); | 768 | crop->c.left); |
806 | if (ret != 0) { | 769 | if (ret != 0) |
807 | ret = -EINVAL; | 770 | return -EINVAL; |
808 | break; | 771 | ret = pvr2_ctrl_set_value( |
809 | } | ||
810 | ret = pvr2_ctrl_set_value( | ||
811 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), | 772 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), |
812 | crop->c.top); | 773 | crop->c.top); |
813 | if (ret != 0) { | 774 | if (ret != 0) |
814 | ret = -EINVAL; | 775 | return -EINVAL; |
815 | break; | 776 | ret = pvr2_ctrl_set_value( |
816 | } | ||
817 | ret = pvr2_ctrl_set_value( | ||
818 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), | 777 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), |
819 | crop->c.width); | 778 | crop->c.width); |
820 | if (ret != 0) { | 779 | if (ret != 0) |
821 | ret = -EINVAL; | 780 | return -EINVAL; |
822 | break; | 781 | ret = pvr2_ctrl_set_value( |
823 | } | ||
824 | ret = pvr2_ctrl_set_value( | ||
825 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), | 782 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), |
826 | crop->c.height); | 783 | crop->c.height); |
827 | if (ret != 0) { | 784 | if (ret != 0) |
828 | ret = -EINVAL; | 785 | return -EINVAL; |
829 | break; | 786 | return 0; |
830 | } | 787 | } |
831 | } | 788 | |
832 | case VIDIOC_LOG_STATUS: | 789 | static int pvr2_log_status(struct file *file, void *priv) |
833 | { | 790 | { |
834 | pvr2_hdw_trigger_module_log(hdw); | 791 | struct pvr2_v4l2_fh *fh = file->private_data; |
835 | ret = 0; | 792 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
836 | break; | 793 | |
837 | } | 794 | pvr2_hdw_trigger_module_log(hdw); |
795 | return 0; | ||
796 | } | ||
797 | |||
838 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 798 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
839 | case VIDIOC_DBG_S_REGISTER: | 799 | static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_register *req) |
840 | case VIDIOC_DBG_G_REGISTER: | 800 | { |
841 | { | 801 | struct pvr2_v4l2_fh *fh = file->private_data; |
842 | u64 val; | 802 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
843 | struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg; | 803 | u64 val; |
844 | if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val; | 804 | int ret; |
845 | ret = pvr2_hdw_register_access( | ||
846 | hdw, &req->match, req->reg, | ||
847 | cmd == VIDIOC_DBG_S_REGISTER, &val); | ||
848 | if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val; | ||
849 | break; | ||
850 | } | ||
851 | #endif | ||
852 | 805 | ||
853 | default : | 806 | ret = pvr2_hdw_register_access( |
854 | ret = -ENOTTY; | 807 | hdw, &req->match, req->reg, |
855 | break; | 808 | 0, &val); |
856 | } | 809 | req->val = val; |
810 | return ret; | ||
811 | } | ||
857 | 812 | ||
858 | pvr2_hdw_commit_ctl(hdw); | 813 | static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req) |
814 | { | ||
815 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
816 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
817 | u64 val; | ||
818 | int ret; | ||
859 | 819 | ||
860 | if (ret < 0) { | 820 | val = req->val; |
861 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | 821 | ret = pvr2_hdw_register_access( |
862 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | 822 | hdw, &req->match, req->reg, |
863 | "pvr2_v4l2_do_ioctl failure, ret=%ld", ret); | 823 | 1, &val); |
864 | } else { | ||
865 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
866 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
867 | "pvr2_v4l2_do_ioctl failure, ret=%ld" | ||
868 | " command was:", ret); | ||
869 | v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), | ||
870 | cmd); | ||
871 | } | ||
872 | } | ||
873 | } else { | ||
874 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
875 | "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)", | ||
876 | ret, ret); | ||
877 | } | ||
878 | return ret; | 824 | return ret; |
879 | } | 825 | } |
826 | #endif | ||
827 | |||
828 | static const struct v4l2_ioctl_ops pvr2_ioctl_ops = { | ||
829 | .vidioc_querycap = pvr2_querycap, | ||
830 | .vidioc_g_priority = pvr2_g_priority, | ||
831 | .vidioc_s_priority = pvr2_s_priority, | ||
832 | .vidioc_s_audio = pvr2_s_audio, | ||
833 | .vidioc_g_audio = pvr2_g_audio, | ||
834 | .vidioc_enumaudio = pvr2_enumaudio, | ||
835 | .vidioc_enum_input = pvr2_enum_input, | ||
836 | .vidioc_cropcap = pvr2_cropcap, | ||
837 | .vidioc_s_crop = pvr2_s_crop, | ||
838 | .vidioc_g_crop = pvr2_g_crop, | ||
839 | .vidioc_g_input = pvr2_g_input, | ||
840 | .vidioc_s_input = pvr2_s_input, | ||
841 | .vidioc_g_frequency = pvr2_g_frequency, | ||
842 | .vidioc_s_frequency = pvr2_s_frequency, | ||
843 | .vidioc_s_tuner = pvr2_s_tuner, | ||
844 | .vidioc_g_tuner = pvr2_g_tuner, | ||
845 | .vidioc_g_std = pvr2_g_std, | ||
846 | .vidioc_s_std = pvr2_s_std, | ||
847 | .vidioc_log_status = pvr2_log_status, | ||
848 | .vidioc_enum_fmt_vid_cap = pvr2_enum_fmt_vid_cap, | ||
849 | .vidioc_g_fmt_vid_cap = pvr2_g_fmt_vid_cap, | ||
850 | .vidioc_s_fmt_vid_cap = pvr2_s_fmt_vid_cap, | ||
851 | .vidioc_try_fmt_vid_cap = pvr2_try_fmt_vid_cap, | ||
852 | .vidioc_streamon = pvr2_streamon, | ||
853 | .vidioc_streamoff = pvr2_streamoff, | ||
854 | .vidioc_queryctrl = pvr2_queryctrl, | ||
855 | .vidioc_querymenu = pvr2_querymenu, | ||
856 | .vidioc_g_ctrl = pvr2_g_ctrl, | ||
857 | .vidioc_s_ctrl = pvr2_s_ctrl, | ||
858 | .vidioc_g_ext_ctrls = pvr2_g_ext_ctrls, | ||
859 | .vidioc_s_ext_ctrls = pvr2_s_ext_ctrls, | ||
860 | .vidioc_try_ext_ctrls = pvr2_try_ext_ctrls, | ||
861 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
862 | .vidioc_g_register = pvr2_g_register, | ||
863 | .vidioc_s_register = pvr2_s_register, | ||
864 | #endif | ||
865 | }; | ||
880 | 866 | ||
881 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) | 867 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) |
882 | { | 868 | { |
@@ -959,7 +945,56 @@ static long pvr2_v4l2_ioctl(struct file *file, | |||
959 | unsigned int cmd, unsigned long arg) | 945 | unsigned int cmd, unsigned long arg) |
960 | { | 946 | { |
961 | 947 | ||
962 | return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl); | 948 | struct pvr2_v4l2_fh *fh = file->private_data; |
949 | struct pvr2_v4l2 *vp = fh->vhead; | ||
950 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
951 | long ret = -EINVAL; | ||
952 | |||
953 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) | ||
954 | v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), cmd); | ||
955 | |||
956 | if (!pvr2_hdw_dev_ok(hdw)) { | ||
957 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
958 | "ioctl failed - bad or no context"); | ||
959 | return -EFAULT; | ||
960 | } | ||
961 | |||
962 | /* check priority */ | ||
963 | switch (cmd) { | ||
964 | case VIDIOC_S_CTRL: | ||
965 | case VIDIOC_S_STD: | ||
966 | case VIDIOC_S_INPUT: | ||
967 | case VIDIOC_S_TUNER: | ||
968 | case VIDIOC_S_FREQUENCY: | ||
969 | ret = v4l2_prio_check(&vp->prio, fh->prio); | ||
970 | if (ret) | ||
971 | return ret; | ||
972 | } | ||
973 | |||
974 | ret = video_ioctl2(file, cmd, arg); | ||
975 | |||
976 | pvr2_hdw_commit_ctl(hdw); | ||
977 | |||
978 | if (ret < 0) { | ||
979 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
980 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
981 | "pvr2_v4l2_do_ioctl failure, ret=%ld", ret); | ||
982 | } else { | ||
983 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
984 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
985 | "pvr2_v4l2_do_ioctl failure, ret=%ld" | ||
986 | " command was:", ret); | ||
987 | v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), | ||
988 | cmd); | ||
989 | } | ||
990 | } | ||
991 | } else { | ||
992 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
993 | "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)", | ||
994 | ret, ret); | ||
995 | } | ||
996 | return ret; | ||
997 | |||
963 | } | 998 | } |
964 | 999 | ||
965 | 1000 | ||
@@ -1298,6 +1333,11 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, | |||
1298 | 1333 | ||
1299 | memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template)); | 1334 | memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template)); |
1300 | dip->devbase.release = pvr2_video_device_release; | 1335 | dip->devbase.release = pvr2_video_device_release; |
1336 | dip->devbase.ioctl_ops = &pvr2_ioctl_ops; | ||
1337 | /* FIXME: tvnorms should be set to the set of supported standards | ||
1338 | by this device. Then video_ioctl2 will implement VIDIOC_ENUMSTD | ||
1339 | based on this field. */ | ||
1340 | dip->devbase.tvnorms = V4L2_STD_ALL; | ||
1301 | 1341 | ||
1302 | mindevnum = -1; | 1342 | mindevnum = -1; |
1303 | unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); | 1343 | unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); |