Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
ab33d507 AC |
2 | /**************************************************************************** |
3 | * | |
4 | * Filename: cpia2_v4l.c | |
5 | * | |
6 | * Copyright 2001, STMicrolectronics, Inc. | |
7 | * Contact: steve.miller@st.com | |
8 | * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> | |
9 | * | |
10 | * Description: | |
11 | * This is a USB driver for CPia2 based video cameras. | |
12 | * The infrastructure of this driver is based on the cpia usb driver by | |
13 | * Jochen Scharrlach and Johannes Erdfeldt. | |
14 | * | |
ab33d507 | 15 | * Stripped of 2.4 stuff ready for main kernel submit by |
d9b01449 | 16 | * Alan Cox <alan@lxorguk.ukuu.org.uk> |
ab33d507 AC |
17 | ****************************************************************************/ |
18 | ||
1990d50b | 19 | #define CPIA_VERSION "3.0.1" |
ab33d507 AC |
20 | |
21 | #include <linux/module.h> | |
22 | #include <linux/time.h> | |
23 | #include <linux/sched.h> | |
24 | #include <linux/slab.h> | |
25 | #include <linux/init.h> | |
873ecd8f | 26 | #include <linux/videodev2.h> |
cb63c2aa | 27 | #include <linux/stringify.h> |
35ea11ff | 28 | #include <media/v4l2-ioctl.h> |
6c493f8b | 29 | #include <media/v4l2-event.h> |
ab33d507 AC |
30 | |
31 | #include "cpia2.h" | |
ab33d507 | 32 | |
ab33d507 AC |
33 | static int video_nr = -1; |
34 | module_param(video_nr, int, 0); | |
6c493f8b | 35 | MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); |
ab33d507 | 36 | |
6c493f8b | 37 | static int buffer_size = 68 * 1024; |
ab33d507 AC |
38 | module_param(buffer_size, int, 0); |
39 | MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); | |
40 | ||
41 | static int num_buffers = 3; | |
42 | module_param(num_buffers, int, 0); | |
43 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" | |
cb63c2aa | 44 | __stringify(VIDEO_MAX_FRAME) ", default 3)"); |
ab33d507 AC |
45 | |
46 | static int alternate = DEFAULT_ALT; | |
47 | module_param(alternate, int, 0); | |
cb63c2aa TF |
48 | MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" |
49 | __stringify(USBIF_ISO_6) ", default " | |
50 | __stringify(DEFAULT_ALT) ")"); | |
ab33d507 | 51 | |
6c493f8b | 52 | static int flicker_mode; |
ab33d507 | 53 | module_param(flicker_mode, int, 0); |
6c493f8b HV |
54 | MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or " |
55 | __stringify(60) ", default 0)"); | |
ab33d507 AC |
56 | |
57 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); | |
58 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); | |
59 | MODULE_SUPPORTED_DEVICE("video"); | |
60 | MODULE_LICENSE("GPL"); | |
1990d50b | 61 | MODULE_VERSION(CPIA_VERSION); |
ab33d507 AC |
62 | |
63 | #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" | |
6c493f8b | 64 | #define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000) |
ab33d507 AC |
65 | |
66 | /****************************************************************************** | |
67 | * | |
68 | * cpia2_open | |
69 | * | |
70 | *****************************************************************************/ | |
bec43661 | 71 | static int cpia2_open(struct file *file) |
ab33d507 | 72 | { |
c170ecf4 | 73 | struct camera_data *cam = video_drvdata(file); |
d76ebb67 | 74 | int retval; |
ab33d507 | 75 | |
d76ebb67 HV |
76 | if (mutex_lock_interruptible(&cam->v4l2_lock)) |
77 | return -ERESTARTSYS; | |
78 | retval = v4l2_fh_open(file); | |
6c493f8b | 79 | if (retval) |
d76ebb67 | 80 | goto open_unlock; |
ab33d507 | 81 | |
6c493f8b HV |
82 | if (v4l2_fh_is_singular_file(file)) { |
83 | if (cpia2_allocate_buffers(cam)) { | |
84 | v4l2_fh_release(file); | |
d76ebb67 HV |
85 | retval = -ENOMEM; |
86 | goto open_unlock; | |
6c493f8b | 87 | } |
ab33d507 | 88 | |
d2db8fee | 89 | /* reset the camera */ |
6c493f8b HV |
90 | if (cpia2_reset_camera(cam) < 0) { |
91 | v4l2_fh_release(file); | |
d76ebb67 HV |
92 | retval = -EIO; |
93 | goto open_unlock; | |
6c493f8b | 94 | } |
ab33d507 | 95 | |
d2db8fee HV |
96 | cam->APP_len = 0; |
97 | cam->COM_len = 0; | |
ab33d507 AC |
98 | } |
99 | ||
ab33d507 | 100 | cpia2_dbg_dump_registers(cam); |
d76ebb67 HV |
101 | open_unlock: |
102 | mutex_unlock(&cam->v4l2_lock); | |
103 | return retval; | |
ab33d507 AC |
104 | } |
105 | ||
106 | /****************************************************************************** | |
107 | * | |
108 | * cpia2_close | |
109 | * | |
110 | *****************************************************************************/ | |
bec43661 | 111 | static int cpia2_close(struct file *file) |
ab33d507 AC |
112 | { |
113 | struct video_device *dev = video_devdata(file); | |
114 | struct camera_data *cam = video_get_drvdata(dev); | |
ab33d507 | 115 | |
d76ebb67 | 116 | mutex_lock(&cam->v4l2_lock); |
6c493f8b | 117 | if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) { |
ab33d507 AC |
118 | cpia2_usb_stream_stop(cam); |
119 | ||
6c493f8b HV |
120 | /* save camera state for later open */ |
121 | cpia2_save_camera_state(cam); | |
ab33d507 | 122 | |
6c493f8b HV |
123 | cpia2_set_low_power(cam); |
124 | cpia2_free_buffers(cam); | |
ab33d507 AC |
125 | } |
126 | ||
6c493f8b HV |
127 | if (cam->stream_fh == file->private_data) { |
128 | cam->stream_fh = NULL; | |
d2db8fee | 129 | cam->mmapped = 0; |
ab33d507 | 130 | } |
d76ebb67 | 131 | mutex_unlock(&cam->v4l2_lock); |
6c493f8b | 132 | return v4l2_fh_release(file); |
ab33d507 AC |
133 | } |
134 | ||
135 | /****************************************************************************** | |
136 | * | |
137 | * cpia2_v4l_read | |
138 | * | |
139 | *****************************************************************************/ | |
140 | static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, | |
141 | loff_t *off) | |
142 | { | |
c170ecf4 | 143 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 144 | int noblock = file->f_flags&O_NONBLOCK; |
d76ebb67 | 145 | ssize_t ret; |
ab33d507 | 146 | |
ab33d507 AC |
147 | if(!cam) |
148 | return -EINVAL; | |
149 | ||
d76ebb67 HV |
150 | if (mutex_lock_interruptible(&cam->v4l2_lock)) |
151 | return -ERESTARTSYS; | |
152 | ret = cpia2_read(cam, buf, count, noblock); | |
153 | mutex_unlock(&cam->v4l2_lock); | |
154 | return ret; | |
ab33d507 AC |
155 | } |
156 | ||
157 | ||
158 | /****************************************************************************** | |
159 | * | |
160 | * cpia2_v4l_poll | |
161 | * | |
162 | *****************************************************************************/ | |
c23e0cb8 | 163 | static __poll_t cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) |
ab33d507 | 164 | { |
c170ecf4 | 165 | struct camera_data *cam = video_drvdata(filp); |
c23e0cb8 | 166 | __poll_t res; |
ab33d507 | 167 | |
d76ebb67 HV |
168 | mutex_lock(&cam->v4l2_lock); |
169 | res = cpia2_poll(cam, filp, wait); | |
170 | mutex_unlock(&cam->v4l2_lock); | |
171 | return res; | |
ab33d507 AC |
172 | } |
173 | ||
174 | ||
ab33d507 AC |
175 | static int sync(struct camera_data *cam, int frame_nr) |
176 | { | |
177 | struct framebuf *frame = &cam->buffers[frame_nr]; | |
178 | ||
179 | while (1) { | |
180 | if (frame->status == FRAME_READY) | |
181 | return 0; | |
182 | ||
183 | if (!cam->streaming) { | |
184 | frame->status = FRAME_READY; | |
185 | frame->length = 0; | |
186 | return 0; | |
187 | } | |
188 | ||
d2db8fee | 189 | mutex_unlock(&cam->v4l2_lock); |
ab33d507 AC |
190 | wait_event_interruptible(cam->wq_stream, |
191 | !cam->streaming || | |
192 | frame->status == FRAME_READY); | |
d2db8fee | 193 | mutex_lock(&cam->v4l2_lock); |
ab33d507 AC |
194 | if (signal_pending(current)) |
195 | return -ERESTARTSYS; | |
6c493f8b | 196 | if (!video_is_registered(&cam->vdev)) |
ab33d507 AC |
197 | return -ENOTTY; |
198 | } | |
199 | } | |
200 | ||
ab33d507 AC |
201 | /****************************************************************************** |
202 | * | |
203 | * ioctl_querycap | |
204 | * | |
205 | * V4L2 device capabilities | |
206 | * | |
207 | *****************************************************************************/ | |
208 | ||
cbfb3daa | 209 | static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) |
ab33d507 | 210 | { |
cbfb3daa | 211 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 212 | |
cc1e6315 | 213 | strscpy(vc->driver, "cpia2", sizeof(vc->driver)); |
ab33d507 AC |
214 | |
215 | if (cam->params.pnp_id.product == 0x151) | |
cc1e6315 | 216 | strscpy(vc->card, "QX5 Microscope", sizeof(vc->card)); |
ab33d507 | 217 | else |
cc1e6315 | 218 | strscpy(vc->card, "CPiA2 Camera", sizeof(vc->card)); |
ab33d507 AC |
219 | switch (cam->params.pnp_id.device_type) { |
220 | case DEVICE_STV_672: | |
221 | strcat(vc->card, " (672/"); | |
222 | break; | |
223 | case DEVICE_STV_676: | |
224 | strcat(vc->card, " (676/"); | |
225 | break; | |
226 | default: | |
ed82b9c2 | 227 | strcat(vc->card, " (XXX/"); |
ab33d507 AC |
228 | break; |
229 | } | |
230 | switch (cam->params.version.sensor_flags) { | |
231 | case CPIA2_VP_SENSOR_FLAGS_404: | |
232 | strcat(vc->card, "404)"); | |
233 | break; | |
234 | case CPIA2_VP_SENSOR_FLAGS_407: | |
235 | strcat(vc->card, "407)"); | |
236 | break; | |
237 | case CPIA2_VP_SENSOR_FLAGS_409: | |
238 | strcat(vc->card, "409)"); | |
239 | break; | |
240 | case CPIA2_VP_SENSOR_FLAGS_410: | |
241 | strcat(vc->card, "410)"); | |
242 | break; | |
243 | case CPIA2_VP_SENSOR_FLAGS_500: | |
244 | strcat(vc->card, "500)"); | |
245 | break; | |
246 | default: | |
ed82b9c2 | 247 | strcat(vc->card, "XXX)"); |
ab33d507 AC |
248 | break; |
249 | } | |
250 | ||
251 | if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) | |
252 | memset(vc->bus_info,0, sizeof(vc->bus_info)); | |
ab33d507 AC |
253 | return 0; |
254 | } | |
255 | ||
256 | /****************************************************************************** | |
257 | * | |
258 | * ioctl_input | |
259 | * | |
260 | * V4L2 input get/set/enumerate | |
261 | * | |
262 | *****************************************************************************/ | |
263 | ||
cbfb3daa | 264 | static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) |
ab33d507 | 265 | { |
cbfb3daa HV |
266 | if (i->index) |
267 | return -EINVAL; | |
cc1e6315 | 268 | strscpy(i->name, "Camera", sizeof(i->name)); |
ab33d507 | 269 | i->type = V4L2_INPUT_TYPE_CAMERA; |
cbfb3daa HV |
270 | return 0; |
271 | } | |
ab33d507 | 272 | |
cbfb3daa HV |
273 | static int cpia2_g_input(struct file *file, void *fh, unsigned int *i) |
274 | { | |
275 | *i = 0; | |
ab33d507 AC |
276 | return 0; |
277 | } | |
278 | ||
cbfb3daa HV |
279 | static int cpia2_s_input(struct file *file, void *fh, unsigned int i) |
280 | { | |
281 | return i ? -EINVAL : 0; | |
282 | } | |
283 | ||
ab33d507 AC |
284 | /****************************************************************************** |
285 | * | |
286 | * ioctl_enum_fmt | |
287 | * | |
288 | * V4L2 format enumerate | |
289 | * | |
290 | *****************************************************************************/ | |
291 | ||
cbfb3daa HV |
292 | static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, |
293 | struct v4l2_fmtdesc *f) | |
ab33d507 | 294 | { |
009cb7d5 HV |
295 | if (f->index > 1) |
296 | return -EINVAL; | |
ab33d507 | 297 | |
009cb7d5 | 298 | if (f->index == 0) |
ab33d507 | 299 | f->pixelformat = V4L2_PIX_FMT_MJPEG; |
009cb7d5 | 300 | else |
ab33d507 | 301 | f->pixelformat = V4L2_PIX_FMT_JPEG; |
ab33d507 AC |
302 | return 0; |
303 | } | |
304 | ||
305 | /****************************************************************************** | |
306 | * | |
307 | * ioctl_try_fmt | |
308 | * | |
309 | * V4L2 format try | |
310 | * | |
311 | *****************************************************************************/ | |
312 | ||
cbfb3daa HV |
313 | static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, |
314 | struct v4l2_format *f) | |
ab33d507 | 315 | { |
cbfb3daa | 316 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
317 | |
318 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && | |
319 | f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | |
320 | return -EINVAL; | |
321 | ||
322 | f->fmt.pix.field = V4L2_FIELD_NONE; | |
323 | f->fmt.pix.bytesperline = 0; | |
324 | f->fmt.pix.sizeimage = cam->frame_size; | |
325 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | |
ab33d507 AC |
326 | |
327 | switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { | |
328 | case VIDEOSIZE_VGA: | |
329 | f->fmt.pix.width = 640; | |
330 | f->fmt.pix.height = 480; | |
331 | break; | |
332 | case VIDEOSIZE_CIF: | |
333 | f->fmt.pix.width = 352; | |
334 | f->fmt.pix.height = 288; | |
335 | break; | |
336 | case VIDEOSIZE_QVGA: | |
337 | f->fmt.pix.width = 320; | |
338 | f->fmt.pix.height = 240; | |
339 | break; | |
340 | case VIDEOSIZE_288_216: | |
341 | f->fmt.pix.width = 288; | |
342 | f->fmt.pix.height = 216; | |
343 | break; | |
344 | case VIDEOSIZE_256_192: | |
345 | f->fmt.pix.width = 256; | |
346 | f->fmt.pix.height = 192; | |
347 | break; | |
348 | case VIDEOSIZE_224_168: | |
349 | f->fmt.pix.width = 224; | |
350 | f->fmt.pix.height = 168; | |
351 | break; | |
352 | case VIDEOSIZE_192_144: | |
353 | f->fmt.pix.width = 192; | |
354 | f->fmt.pix.height = 144; | |
355 | break; | |
356 | case VIDEOSIZE_QCIF: | |
357 | default: | |
358 | f->fmt.pix.width = 176; | |
359 | f->fmt.pix.height = 144; | |
360 | break; | |
361 | } | |
362 | ||
363 | return 0; | |
364 | } | |
365 | ||
366 | /****************************************************************************** | |
367 | * | |
368 | * ioctl_set_fmt | |
369 | * | |
370 | * V4L2 format set | |
371 | * | |
372 | *****************************************************************************/ | |
373 | ||
cbfb3daa HV |
374 | static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, |
375 | struct v4l2_format *f) | |
ab33d507 | 376 | { |
cbfb3daa | 377 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
378 | int err, frame; |
379 | ||
cbfb3daa | 380 | err = cpia2_try_fmt_vid_cap(file, _fh, f); |
ab33d507 AC |
381 | if(err != 0) |
382 | return err; | |
383 | ||
ab33d507 AC |
384 | cam->pixelformat = f->fmt.pix.pixelformat; |
385 | ||
386 | /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle | |
387 | * the missing Huffman table properly. */ | |
388 | cam->params.compression.inhibit_htables = 0; | |
389 | /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ | |
390 | ||
391 | /* we set the video window to something smaller or equal to what | |
392 | * is requested by the user??? | |
393 | */ | |
394 | DBG("Requested width = %d, height = %d\n", | |
395 | f->fmt.pix.width, f->fmt.pix.height); | |
873ecd8f HV |
396 | if (f->fmt.pix.width != cam->width || |
397 | f->fmt.pix.height != cam->height) { | |
398 | cam->width = f->fmt.pix.width; | |
399 | cam->height = f->fmt.pix.height; | |
ab33d507 AC |
400 | cam->params.roi.width = f->fmt.pix.width; |
401 | cam->params.roi.height = f->fmt.pix.height; | |
402 | cpia2_set_format(cam); | |
403 | } | |
404 | ||
405 | for (frame = 0; frame < cam->num_frames; ++frame) { | |
406 | if (cam->buffers[frame].status == FRAME_READING) | |
407 | if ((err = sync(cam, frame)) < 0) | |
408 | return err; | |
409 | ||
410 | cam->buffers[frame].status = FRAME_EMPTY; | |
411 | } | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | /****************************************************************************** | |
417 | * | |
418 | * ioctl_get_fmt | |
419 | * | |
420 | * V4L2 format get | |
421 | * | |
422 | *****************************************************************************/ | |
423 | ||
cbfb3daa HV |
424 | static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, |
425 | struct v4l2_format *f) | |
ab33d507 | 426 | { |
cbfb3daa | 427 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 428 | |
873ecd8f HV |
429 | f->fmt.pix.width = cam->width; |
430 | f->fmt.pix.height = cam->height; | |
ab33d507 AC |
431 | f->fmt.pix.pixelformat = cam->pixelformat; |
432 | f->fmt.pix.field = V4L2_FIELD_NONE; | |
433 | f->fmt.pix.bytesperline = 0; | |
434 | f->fmt.pix.sizeimage = cam->frame_size; | |
435 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | |
ab33d507 AC |
436 | |
437 | return 0; | |
438 | } | |
439 | ||
440 | /****************************************************************************** | |
441 | * | |
442 | * ioctl_cropcap | |
443 | * | |
444 | * V4L2 query cropping capabilities | |
445 | * NOTE: cropping is currently disabled | |
446 | * | |
447 | *****************************************************************************/ | |
448 | ||
ee10dc36 HV |
449 | static int cpia2_g_selection(struct file *file, void *fh, |
450 | struct v4l2_selection *s) | |
ab33d507 | 451 | { |
cbfb3daa | 452 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 453 | |
ee10dc36 HV |
454 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
455 | return -EINVAL; | |
ab33d507 | 456 | |
ee10dc36 HV |
457 | switch (s->target) { |
458 | case V4L2_SEL_TGT_CROP_BOUNDS: | |
459 | case V4L2_SEL_TGT_CROP_DEFAULT: | |
460 | s->r.left = 0; | |
461 | s->r.top = 0; | |
462 | s->r.width = cam->width; | |
463 | s->r.height = cam->height; | |
464 | break; | |
465 | default: | |
466 | return -EINVAL; | |
467 | } | |
ab33d507 AC |
468 | return 0; |
469 | } | |
470 | ||
6c493f8b HV |
471 | struct framerate_info { |
472 | int value; | |
473 | struct v4l2_fract period; | |
474 | }; | |
ab33d507 | 475 | |
6c493f8b HV |
476 | static const struct framerate_info framerate_controls[] = { |
477 | { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } }, | |
478 | { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } }, | |
479 | { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } }, | |
480 | { CPIA2_VP_FRAMERATE_15, { 1, 15 } }, | |
481 | { CPIA2_VP_FRAMERATE_25, { 1, 25 } }, | |
482 | { CPIA2_VP_FRAMERATE_30, { 1, 30 } }, | |
483 | }; | |
484 | ||
485 | static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p) | |
ab33d507 | 486 | { |
cbfb3daa | 487 | struct camera_data *cam = video_drvdata(file); |
6c493f8b | 488 | struct v4l2_captureparm *cap = &p->parm.capture; |
ab33d507 AC |
489 | int i; |
490 | ||
6c493f8b | 491 | if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
ab33d507 AC |
492 | return -EINVAL; |
493 | ||
6c493f8b HV |
494 | cap->capability = V4L2_CAP_TIMEPERFRAME; |
495 | cap->readbuffers = cam->num_frames; | |
496 | for (i = 0; i < ARRAY_SIZE(framerate_controls); i++) | |
497 | if (cam->params.vp_params.frame_rate == framerate_controls[i].value) { | |
498 | cap->timeperframe = framerate_controls[i].period; | |
499 | break; | |
ab33d507 | 500 | } |
ab33d507 AC |
501 | return 0; |
502 | } | |
503 | ||
6c493f8b | 504 | static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p) |
ab33d507 | 505 | { |
cbfb3daa | 506 | struct camera_data *cam = video_drvdata(file); |
6c493f8b HV |
507 | struct v4l2_captureparm *cap = &p->parm.capture; |
508 | struct v4l2_fract tpf = cap->timeperframe; | |
509 | int max = ARRAY_SIZE(framerate_controls) - 1; | |
510 | int ret; | |
511 | int i; | |
ab33d507 | 512 | |
6c493f8b HV |
513 | ret = cpia2_g_parm(file, fh, p); |
514 | if (ret || !tpf.denominator || !tpf.numerator) | |
515 | return ret; | |
516 | ||
517 | /* Maximum 15 fps for this model */ | |
518 | if (cam->params.pnp_id.device_type == DEVICE_STV_672 && | |
519 | cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) | |
520 | max -= 2; | |
521 | for (i = 0; i <= max; i++) { | |
522 | struct v4l2_fract f1 = tpf; | |
523 | struct v4l2_fract f2 = framerate_controls[i].period; | |
524 | ||
525 | f1.numerator *= f2.denominator; | |
526 | f2.numerator *= f1.denominator; | |
527 | if (f1.numerator >= f2.numerator) | |
528 | break; | |
529 | } | |
530 | if (i > max) | |
531 | i = max; | |
532 | cap->timeperframe = framerate_controls[i].period; | |
533 | return cpia2_set_fps(cam, framerate_controls[i].value); | |
534 | } | |
ab33d507 | 535 | |
6c493f8b HV |
536 | static const struct { |
537 | u32 width; | |
538 | u32 height; | |
539 | } cpia2_framesizes[] = { | |
540 | { 640, 480 }, | |
541 | { 352, 288 }, | |
542 | { 320, 240 }, | |
543 | { 288, 216 }, | |
544 | { 256, 192 }, | |
545 | { 224, 168 }, | |
546 | { 192, 144 }, | |
547 | { 176, 144 }, | |
548 | }; | |
ab33d507 | 549 | |
6c493f8b HV |
550 | static int cpia2_enum_framesizes(struct file *file, void *fh, |
551 | struct v4l2_frmsizeenum *fsize) | |
552 | { | |
ab33d507 | 553 | |
6c493f8b HV |
554 | if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG && |
555 | fsize->pixel_format != V4L2_PIX_FMT_JPEG) | |
ab33d507 | 556 | return -EINVAL; |
6c493f8b HV |
557 | if (fsize->index >= ARRAY_SIZE(cpia2_framesizes)) |
558 | return -EINVAL; | |
559 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | |
560 | fsize->discrete.width = cpia2_framesizes[fsize->index].width; | |
561 | fsize->discrete.height = cpia2_framesizes[fsize->index].height; | |
ab33d507 AC |
562 | |
563 | return 0; | |
564 | } | |
565 | ||
6c493f8b HV |
566 | static int cpia2_enum_frameintervals(struct file *file, void *fh, |
567 | struct v4l2_frmivalenum *fival) | |
ab33d507 | 568 | { |
cbfb3daa | 569 | struct camera_data *cam = video_drvdata(file); |
6c493f8b HV |
570 | int max = ARRAY_SIZE(framerate_controls) - 1; |
571 | int i; | |
ab33d507 | 572 | |
6c493f8b HV |
573 | if (fival->pixel_format != V4L2_PIX_FMT_MJPEG && |
574 | fival->pixel_format != V4L2_PIX_FMT_JPEG) | |
ab33d507 | 575 | return -EINVAL; |
ab33d507 | 576 | |
6c493f8b HV |
577 | /* Maximum 15 fps for this model */ |
578 | if (cam->params.pnp_id.device_type == DEVICE_STV_672 && | |
579 | cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) | |
580 | max -= 2; | |
581 | if (fival->index > max) | |
582 | return -EINVAL; | |
583 | for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++) | |
584 | if (fival->width == cpia2_framesizes[i].width && | |
585 | fival->height == cpia2_framesizes[i].height) | |
586 | break; | |
587 | if (i == ARRAY_SIZE(cpia2_framesizes)) | |
588 | return -EINVAL; | |
589 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | |
590 | fival->discrete = framerate_controls[fival->index].period; | |
ab33d507 AC |
591 | return 0; |
592 | } | |
593 | ||
594 | /****************************************************************************** | |
595 | * | |
596 | * ioctl_s_ctrl | |
597 | * | |
598 | * V4L2 set the value of a control variable | |
599 | * | |
600 | *****************************************************************************/ | |
601 | ||
6c493f8b | 602 | static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl) |
ab33d507 | 603 | { |
6c493f8b HV |
604 | struct camera_data *cam = |
605 | container_of(ctrl->handler, struct camera_data, hdl); | |
606 | static const int flicker_table[] = { | |
607 | NEVER_FLICKER, | |
608 | FLICKER_50, | |
609 | FLICKER_60, | |
610 | }; | |
ab33d507 | 611 | |
6c493f8b | 612 | DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val); |
ab33d507 | 613 | |
6c493f8b | 614 | switch (ctrl->id) { |
ab33d507 | 615 | case V4L2_CID_BRIGHTNESS: |
6c493f8b | 616 | cpia2_set_brightness(cam, ctrl->val); |
ab33d507 AC |
617 | break; |
618 | case V4L2_CID_CONTRAST: | |
6c493f8b | 619 | cpia2_set_contrast(cam, ctrl->val); |
ab33d507 AC |
620 | break; |
621 | case V4L2_CID_SATURATION: | |
6c493f8b | 622 | cpia2_set_saturation(cam, ctrl->val); |
ab33d507 AC |
623 | break; |
624 | case V4L2_CID_HFLIP: | |
6c493f8b | 625 | cpia2_set_property_mirror(cam, ctrl->val); |
ab33d507 AC |
626 | break; |
627 | case V4L2_CID_VFLIP: | |
6c493f8b | 628 | cpia2_set_property_flip(cam, ctrl->val); |
ab33d507 | 629 | break; |
6c493f8b HV |
630 | case V4L2_CID_POWER_LINE_FREQUENCY: |
631 | return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]); | |
632 | case V4L2_CID_ILLUMINATORS_1: | |
633 | return cpia2_set_gpio(cam, (cam->top_light->val << 6) | | |
634 | (cam->bottom_light->val << 7)); | |
635 | case V4L2_CID_JPEG_ACTIVE_MARKER: | |
636 | cam->params.compression.inhibit_htables = | |
637 | !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT); | |
ab33d507 | 638 | break; |
6c493f8b HV |
639 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: |
640 | cam->params.vc_params.quality = ctrl->val; | |
ab33d507 AC |
641 | break; |
642 | case CPIA2_CID_USB_ALT: | |
6c493f8b | 643 | cam->params.camera_state.stream_mode = ctrl->val; |
ab33d507 AC |
644 | break; |
645 | default: | |
6c493f8b | 646 | return -EINVAL; |
ab33d507 AC |
647 | } |
648 | ||
6c493f8b | 649 | return 0; |
ab33d507 AC |
650 | } |
651 | ||
652 | /****************************************************************************** | |
653 | * | |
654 | * ioctl_g_jpegcomp | |
655 | * | |
656 | * V4L2 get the JPEG compression parameters | |
657 | * | |
658 | *****************************************************************************/ | |
659 | ||
cbfb3daa | 660 | static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) |
ab33d507 | 661 | { |
cbfb3daa | 662 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
663 | |
664 | memset(parms, 0, sizeof(*parms)); | |
665 | ||
666 | parms->quality = 80; // TODO: Can this be made meaningful? | |
667 | ||
668 | parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; | |
669 | if(!cam->params.compression.inhibit_htables) { | |
670 | parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; | |
671 | } | |
672 | ||
673 | parms->APPn = cam->APPn; | |
674 | parms->APP_len = cam->APP_len; | |
675 | if(cam->APP_len > 0) { | |
676 | memcpy(parms->APP_data, cam->APP_data, cam->APP_len); | |
677 | parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; | |
678 | } | |
679 | ||
680 | parms->COM_len = cam->COM_len; | |
681 | if(cam->COM_len > 0) { | |
682 | memcpy(parms->COM_data, cam->COM_data, cam->COM_len); | |
683 | parms->jpeg_markers |= JPEG_MARKER_COM; | |
684 | } | |
685 | ||
686 | DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", | |
687 | parms->APP_len, parms->COM_len); | |
688 | ||
689 | return 0; | |
690 | } | |
691 | ||
692 | /****************************************************************************** | |
693 | * | |
694 | * ioctl_s_jpegcomp | |
695 | * | |
696 | * V4L2 set the JPEG compression parameters | |
697 | * NOTE: quality and some jpeg_markers are ignored. | |
698 | * | |
699 | *****************************************************************************/ | |
700 | ||
d88aab53 HV |
701 | static int cpia2_s_jpegcomp(struct file *file, void *fh, |
702 | const struct v4l2_jpegcompression *parms) | |
ab33d507 | 703 | { |
cbfb3daa | 704 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
705 | |
706 | DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", | |
707 | parms->APP_len, parms->COM_len); | |
708 | ||
709 | cam->params.compression.inhibit_htables = | |
710 | !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); | |
711 | ||
712 | if(parms->APP_len != 0) { | |
713 | if(parms->APP_len > 0 && | |
714 | parms->APP_len <= sizeof(cam->APP_data) && | |
715 | parms->APPn >= 0 && parms->APPn <= 15) { | |
716 | cam->APPn = parms->APPn; | |
717 | cam->APP_len = parms->APP_len; | |
718 | memcpy(cam->APP_data, parms->APP_data, parms->APP_len); | |
719 | } else { | |
720 | LOG("Bad APPn Params n=%d len=%d\n", | |
721 | parms->APPn, parms->APP_len); | |
722 | return -EINVAL; | |
723 | } | |
724 | } else { | |
725 | cam->APP_len = 0; | |
726 | } | |
727 | ||
728 | if(parms->COM_len != 0) { | |
729 | if(parms->COM_len > 0 && | |
730 | parms->COM_len <= sizeof(cam->COM_data)) { | |
731 | cam->COM_len = parms->COM_len; | |
732 | memcpy(cam->COM_data, parms->COM_data, parms->COM_len); | |
733 | } else { | |
734 | LOG("Bad COM_len=%d\n", parms->COM_len); | |
735 | return -EINVAL; | |
736 | } | |
737 | } | |
738 | ||
739 | return 0; | |
740 | } | |
741 | ||
742 | /****************************************************************************** | |
743 | * | |
744 | * ioctl_reqbufs | |
745 | * | |
746 | * V4L2 Initiate memory mapping. | |
747 | * NOTE: The user's request is ignored. For now the buffers are fixed. | |
748 | * | |
749 | *****************************************************************************/ | |
750 | ||
cbfb3daa | 751 | static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) |
ab33d507 | 752 | { |
cbfb3daa | 753 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
754 | |
755 | if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
756 | req->memory != V4L2_MEMORY_MMAP) | |
757 | return -EINVAL; | |
758 | ||
759 | DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); | |
760 | req->count = cam->num_frames; | |
761 | memset(&req->reserved, 0, sizeof(req->reserved)); | |
762 | ||
763 | return 0; | |
764 | } | |
765 | ||
766 | /****************************************************************************** | |
767 | * | |
768 | * ioctl_querybuf | |
769 | * | |
770 | * V4L2 Query memory buffer status. | |
771 | * | |
772 | *****************************************************************************/ | |
773 | ||
cbfb3daa | 774 | static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
ab33d507 | 775 | { |
cbfb3daa | 776 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
777 | |
778 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
d5ac225c | 779 | buf->index >= cam->num_frames) |
ab33d507 AC |
780 | return -EINVAL; |
781 | ||
782 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | |
783 | buf->length = cam->frame_size; | |
784 | ||
785 | buf->memory = V4L2_MEMORY_MMAP; | |
786 | ||
787 | if(cam->mmapped) | |
788 | buf->flags = V4L2_BUF_FLAG_MAPPED; | |
789 | else | |
790 | buf->flags = 0; | |
791 | ||
1b18e7a0 SA |
792 | buf->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
793 | ||
ab33d507 AC |
794 | switch (cam->buffers[buf->index].status) { |
795 | case FRAME_EMPTY: | |
796 | case FRAME_ERROR: | |
797 | case FRAME_READING: | |
798 | buf->bytesused = 0; | |
799 | buf->flags = V4L2_BUF_FLAG_QUEUED; | |
800 | break; | |
801 | case FRAME_READY: | |
802 | buf->bytesused = cam->buffers[buf->index].length; | |
77cdffcb | 803 | v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts); |
ab33d507 AC |
804 | buf->sequence = cam->buffers[buf->index].seq; |
805 | buf->flags = V4L2_BUF_FLAG_DONE; | |
806 | break; | |
807 | } | |
808 | ||
809 | DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", | |
810 | buf->index, buf->m.offset, buf->flags, buf->sequence, | |
811 | buf->bytesused); | |
812 | ||
813 | return 0; | |
814 | } | |
815 | ||
816 | /****************************************************************************** | |
817 | * | |
818 | * ioctl_qbuf | |
819 | * | |
820 | * V4L2 User is freeing buffer | |
821 | * | |
822 | *****************************************************************************/ | |
823 | ||
cbfb3daa | 824 | static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
ab33d507 | 825 | { |
cbfb3daa | 826 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
827 | |
828 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
829 | buf->memory != V4L2_MEMORY_MMAP || | |
d5ac225c | 830 | buf->index >= cam->num_frames) |
ab33d507 AC |
831 | return -EINVAL; |
832 | ||
833 | DBG("QBUF #%d\n", buf->index); | |
834 | ||
835 | if(cam->buffers[buf->index].status == FRAME_READY) | |
836 | cam->buffers[buf->index].status = FRAME_EMPTY; | |
837 | ||
838 | return 0; | |
839 | } | |
840 | ||
841 | /****************************************************************************** | |
842 | * | |
843 | * find_earliest_filled_buffer | |
844 | * | |
845 | * Helper for ioctl_dqbuf. Find the next ready buffer. | |
846 | * | |
847 | *****************************************************************************/ | |
848 | ||
849 | static int find_earliest_filled_buffer(struct camera_data *cam) | |
850 | { | |
851 | int i; | |
852 | int found = -1; | |
853 | for (i=0; i<cam->num_frames; i++) { | |
854 | if(cam->buffers[i].status == FRAME_READY) { | |
855 | if(found < 0) { | |
856 | found = i; | |
857 | } else { | |
858 | /* find which buffer is earlier */ | |
597f8e9c | 859 | if (cam->buffers[i].ts < cam->buffers[found].ts) |
ab33d507 AC |
860 | found = i; |
861 | } | |
862 | } | |
863 | } | |
864 | return found; | |
865 | } | |
866 | ||
867 | /****************************************************************************** | |
868 | * | |
869 | * ioctl_dqbuf | |
870 | * | |
871 | * V4L2 User is asking for a filled buffer. | |
872 | * | |
873 | *****************************************************************************/ | |
874 | ||
cbfb3daa | 875 | static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
ab33d507 | 876 | { |
cbfb3daa | 877 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
878 | int frame; |
879 | ||
880 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
881 | buf->memory != V4L2_MEMORY_MMAP) | |
882 | return -EINVAL; | |
883 | ||
884 | frame = find_earliest_filled_buffer(cam); | |
885 | ||
886 | if(frame < 0 && file->f_flags&O_NONBLOCK) | |
887 | return -EAGAIN; | |
888 | ||
889 | if(frame < 0) { | |
890 | /* Wait for a frame to become available */ | |
891 | struct framebuf *cb=cam->curbuff; | |
d2db8fee | 892 | mutex_unlock(&cam->v4l2_lock); |
ab33d507 | 893 | wait_event_interruptible(cam->wq_stream, |
6c493f8b | 894 | !video_is_registered(&cam->vdev) || |
ab33d507 | 895 | (cb=cam->curbuff)->status == FRAME_READY); |
d2db8fee | 896 | mutex_lock(&cam->v4l2_lock); |
ab33d507 AC |
897 | if (signal_pending(current)) |
898 | return -ERESTARTSYS; | |
6c493f8b | 899 | if (!video_is_registered(&cam->vdev)) |
ab33d507 AC |
900 | return -ENOTTY; |
901 | frame = cb->num; | |
902 | } | |
903 | ||
904 | ||
905 | buf->index = frame; | |
906 | buf->bytesused = cam->buffers[buf->index].length; | |
1b18e7a0 SA |
907 | buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE |
908 | | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | |
ab33d507 | 909 | buf->field = V4L2_FIELD_NONE; |
77cdffcb | 910 | v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts); |
ab33d507 AC |
911 | buf->sequence = cam->buffers[buf->index].seq; |
912 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | |
913 | buf->length = cam->frame_size; | |
2b719d7b | 914 | buf->reserved2 = 0; |
62fed26f | 915 | buf->request_fd = 0; |
ab33d507 AC |
916 | memset(&buf->timecode, 0, sizeof(buf->timecode)); |
917 | ||
918 | DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, | |
919 | cam->buffers[buf->index].status, buf->sequence, buf->bytesused); | |
920 | ||
921 | return 0; | |
922 | } | |
923 | ||
cbfb3daa HV |
924 | static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) |
925 | { | |
926 | struct camera_data *cam = video_drvdata(file); | |
6c493f8b | 927 | int ret = -EINVAL; |
ab33d507 | 928 | |
cbfb3daa HV |
929 | DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); |
930 | if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
931 | return -EINVAL; | |
ab33d507 | 932 | |
6c493f8b HV |
933 | if (!cam->streaming) { |
934 | ret = cpia2_usb_stream_start(cam, | |
cbfb3daa | 935 | cam->params.camera_state.stream_mode); |
6c493f8b HV |
936 | if (!ret) |
937 | v4l2_ctrl_grab(cam->usb_alt, true); | |
938 | } | |
939 | return ret; | |
ab33d507 AC |
940 | } |
941 | ||
cbfb3daa | 942 | static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) |
ab33d507 | 943 | { |
cbfb3daa | 944 | struct camera_data *cam = video_drvdata(file); |
6c493f8b | 945 | int ret = -EINVAL; |
cbfb3daa HV |
946 | |
947 | DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); | |
948 | if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
949 | return -EINVAL; | |
950 | ||
6c493f8b HV |
951 | if (cam->streaming) { |
952 | ret = cpia2_usb_stream_stop(cam); | |
953 | if (!ret) | |
954 | v4l2_ctrl_grab(cam->usb_alt, false); | |
955 | } | |
956 | return ret; | |
ab33d507 AC |
957 | } |
958 | ||
959 | /****************************************************************************** | |
960 | * | |
961 | * cpia2_mmap | |
962 | * | |
963 | *****************************************************************************/ | |
964 | static int cpia2_mmap(struct file *file, struct vm_area_struct *area) | |
965 | { | |
c170ecf4 | 966 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 967 | int retval; |
ab33d507 | 968 | |
d76ebb67 HV |
969 | if (mutex_lock_interruptible(&cam->v4l2_lock)) |
970 | return -ERESTARTSYS; | |
ab33d507 AC |
971 | retval = cpia2_remap_buffer(cam, area); |
972 | ||
973 | if(!retval) | |
6c493f8b | 974 | cam->stream_fh = file->private_data; |
d76ebb67 | 975 | mutex_unlock(&cam->v4l2_lock); |
ab33d507 AC |
976 | return retval; |
977 | } | |
978 | ||
979 | /****************************************************************************** | |
980 | * | |
981 | * reset_camera_struct_v4l | |
982 | * | |
983 | * Sets all values to the defaults | |
984 | *****************************************************************************/ | |
985 | static void reset_camera_struct_v4l(struct camera_data *cam) | |
986 | { | |
873ecd8f HV |
987 | cam->width = cam->params.roi.width; |
988 | cam->height = cam->params.roi.height; | |
ab33d507 AC |
989 | |
990 | cam->frame_size = buffer_size; | |
991 | cam->num_frames = num_buffers; | |
992 | ||
6c493f8b | 993 | /* Flicker modes */ |
ab33d507 | 994 | cam->params.flicker_control.flicker_mode_req = flicker_mode; |
ab33d507 | 995 | |
6c493f8b | 996 | /* stream modes */ |
ab33d507 AC |
997 | cam->params.camera_state.stream_mode = alternate; |
998 | ||
999 | cam->pixelformat = V4L2_PIX_FMT_JPEG; | |
ab33d507 AC |
1000 | } |
1001 | ||
cbfb3daa HV |
1002 | static const struct v4l2_ioctl_ops cpia2_ioctl_ops = { |
1003 | .vidioc_querycap = cpia2_querycap, | |
1004 | .vidioc_enum_input = cpia2_enum_input, | |
1005 | .vidioc_g_input = cpia2_g_input, | |
1006 | .vidioc_s_input = cpia2_s_input, | |
1007 | .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, | |
1008 | .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, | |
1009 | .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, | |
1010 | .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, | |
cbfb3daa HV |
1011 | .vidioc_g_jpegcomp = cpia2_g_jpegcomp, |
1012 | .vidioc_s_jpegcomp = cpia2_s_jpegcomp, | |
ee10dc36 | 1013 | .vidioc_g_selection = cpia2_g_selection, |
cbfb3daa HV |
1014 | .vidioc_reqbufs = cpia2_reqbufs, |
1015 | .vidioc_querybuf = cpia2_querybuf, | |
1016 | .vidioc_qbuf = cpia2_qbuf, | |
1017 | .vidioc_dqbuf = cpia2_dqbuf, | |
1018 | .vidioc_streamon = cpia2_streamon, | |
1019 | .vidioc_streamoff = cpia2_streamoff, | |
6c493f8b HV |
1020 | .vidioc_s_parm = cpia2_s_parm, |
1021 | .vidioc_g_parm = cpia2_g_parm, | |
1022 | .vidioc_enum_framesizes = cpia2_enum_framesizes, | |
1023 | .vidioc_enum_frameintervals = cpia2_enum_frameintervals, | |
1024 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | |
1025 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
cbfb3daa HV |
1026 | }; |
1027 | ||
ab33d507 AC |
1028 | /*** |
1029 | * The v4l video device structure initialized for this device | |
1030 | ***/ | |
873ecd8f | 1031 | static const struct v4l2_file_operations cpia2_fops = { |
2ae15191 AC |
1032 | .owner = THIS_MODULE, |
1033 | .open = cpia2_open, | |
1034 | .release = cpia2_close, | |
1035 | .read = cpia2_v4l_read, | |
1036 | .poll = cpia2_v4l_poll, | |
cbfb3daa | 1037 | .unlocked_ioctl = video_ioctl2, |
2ae15191 | 1038 | .mmap = cpia2_mmap, |
ab33d507 AC |
1039 | }; |
1040 | ||
86844942 | 1041 | static const struct video_device cpia2_template = { |
ab33d507 | 1042 | /* I could not find any place for the old .initialize initializer?? */ |
873ecd8f HV |
1043 | .name = "CPiA2 Camera", |
1044 | .fops = &cpia2_fops, | |
cbfb3daa | 1045 | .ioctl_ops = &cpia2_ioctl_ops, |
6c493f8b HV |
1046 | .release = video_device_release_empty, |
1047 | }; | |
1048 | ||
1049 | void cpia2_camera_release(struct v4l2_device *v4l2_dev) | |
1050 | { | |
1051 | struct camera_data *cam = | |
1052 | container_of(v4l2_dev, struct camera_data, v4l2_dev); | |
1053 | ||
1054 | v4l2_ctrl_handler_free(&cam->hdl); | |
1055 | v4l2_device_unregister(&cam->v4l2_dev); | |
1056 | kfree(cam); | |
1057 | } | |
1058 | ||
1059 | static const struct v4l2_ctrl_ops cpia2_ctrl_ops = { | |
1060 | .s_ctrl = cpia2_s_ctrl, | |
ab33d507 AC |
1061 | }; |
1062 | ||
1063 | /****************************************************************************** | |
1064 | * | |
1065 | * cpia2_register_camera | |
1066 | * | |
1067 | *****************************************************************************/ | |
1068 | int cpia2_register_camera(struct camera_data *cam) | |
1069 | { | |
6c493f8b HV |
1070 | struct v4l2_ctrl_handler *hdl = &cam->hdl; |
1071 | struct v4l2_ctrl_config cpia2_usb_alt = { | |
1072 | .ops = &cpia2_ctrl_ops, | |
1073 | .id = CPIA2_CID_USB_ALT, | |
1074 | .name = "USB Alternate", | |
1075 | .type = V4L2_CTRL_TYPE_INTEGER, | |
1076 | .min = USBIF_ISO_1, | |
1077 | .max = USBIF_ISO_6, | |
1078 | .step = 1, | |
1079 | }; | |
1080 | int ret; | |
1081 | ||
1082 | v4l2_ctrl_handler_init(hdl, 12); | |
1083 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1084 | V4L2_CID_BRIGHTNESS, | |
1085 | cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0, | |
1086 | 255, 1, DEFAULT_BRIGHTNESS); | |
1087 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1088 | V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST); | |
1089 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1090 | V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION); | |
1091 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1092 | V4L2_CID_HFLIP, 0, 1, 1, 0); | |
1093 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1094 | V4L2_CID_JPEG_ACTIVE_MARKER, 0, | |
1095 | V4L2_JPEG_ACTIVE_MARKER_DHT, 0, | |
1096 | V4L2_JPEG_ACTIVE_MARKER_DHT); | |
1097 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1098 | V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, | |
1099 | 100, 1, 100); | |
1100 | cpia2_usb_alt.def = alternate; | |
1101 | cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL); | |
1102 | /* VP5 Only */ | |
1103 | if (cam->params.pnp_id.device_type != DEVICE_STV_672) | |
1104 | v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1105 | V4L2_CID_VFLIP, 0, 1, 1, 0); | |
1106 | /* Flicker control only valid for 672 */ | |
1107 | if (cam->params.pnp_id.device_type == DEVICE_STV_672) | |
1108 | v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops, | |
1109 | V4L2_CID_POWER_LINE_FREQUENCY, | |
1110 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0); | |
1111 | /* Light control only valid for the QX5 Microscope */ | |
1112 | if (cam->params.pnp_id.product == 0x151) { | |
1113 | cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1114 | V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0); | |
1115 | cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, | |
1116 | V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0); | |
1117 | v4l2_ctrl_cluster(2, &cam->top_light); | |
1118 | } | |
ab33d507 | 1119 | |
6c493f8b HV |
1120 | if (hdl->error) { |
1121 | ret = hdl->error; | |
1122 | v4l2_ctrl_handler_free(hdl); | |
1123 | return ret; | |
1124 | } | |
1125 | ||
1126 | cam->vdev = cpia2_template; | |
1127 | video_set_drvdata(&cam->vdev, cam); | |
1128 | cam->vdev.lock = &cam->v4l2_lock; | |
1129 | cam->vdev.ctrl_handler = hdl; | |
1130 | cam->vdev.v4l2_dev = &cam->v4l2_dev; | |
8c3854d0 HV |
1131 | cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
1132 | V4L2_CAP_STREAMING; | |
ab33d507 AC |
1133 | |
1134 | reset_camera_struct_v4l(cam); | |
1135 | ||
1136 | /* register v4l device */ | |
7fbbbc78 | 1137 | if (video_register_device(&cam->vdev, VFL_TYPE_VIDEO, video_nr) < 0) { |
ab33d507 | 1138 | ERR("video_register_device failed\n"); |
ab33d507 AC |
1139 | return -ENODEV; |
1140 | } | |
1141 | ||
1142 | return 0; | |
1143 | } | |
1144 | ||
1145 | /****************************************************************************** | |
1146 | * | |
1147 | * cpia2_unregister_camera | |
1148 | * | |
1149 | *****************************************************************************/ | |
1150 | void cpia2_unregister_camera(struct camera_data *cam) | |
1151 | { | |
6c493f8b | 1152 | video_unregister_device(&cam->vdev); |
ab33d507 AC |
1153 | } |
1154 | ||
1155 | /****************************************************************************** | |
1156 | * | |
1157 | * check_parameters | |
1158 | * | |
1159 | * Make sure that all user-supplied parameters are sensible | |
1160 | *****************************************************************************/ | |
1161 | static void __init check_parameters(void) | |
1162 | { | |
1163 | if(buffer_size < PAGE_SIZE) { | |
1164 | buffer_size = PAGE_SIZE; | |
1165 | LOG("buffer_size too small, setting to %d\n", buffer_size); | |
1166 | } else if(buffer_size > 1024*1024) { | |
1167 | /* arbitrary upper limiit */ | |
1168 | buffer_size = 1024*1024; | |
1169 | LOG("buffer_size ridiculously large, setting to %d\n", | |
1170 | buffer_size); | |
1171 | } else { | |
1172 | buffer_size += PAGE_SIZE-1; | |
1173 | buffer_size &= ~(PAGE_SIZE-1); | |
1174 | } | |
1175 | ||
1176 | if(num_buffers < 1) { | |
1177 | num_buffers = 1; | |
1178 | LOG("num_buffers too small, setting to %d\n", num_buffers); | |
1179 | } else if(num_buffers > VIDEO_MAX_FRAME) { | |
1180 | num_buffers = VIDEO_MAX_FRAME; | |
1181 | LOG("num_buffers too large, setting to %d\n", num_buffers); | |
1182 | } | |
1183 | ||
1184 | if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { | |
1185 | alternate = DEFAULT_ALT; | |
1186 | LOG("alternate specified is invalid, using %d\n", alternate); | |
1187 | } | |
1188 | ||
6c493f8b HV |
1189 | if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) { |
1190 | flicker_mode = 0; | |
ab33d507 AC |
1191 | LOG("Flicker mode specified is invalid, using %d\n", |
1192 | flicker_mode); | |
1193 | } | |
1194 | ||
ab33d507 AC |
1195 | DBG("Using %d buffers, each %d bytes, alternate=%d\n", |
1196 | num_buffers, buffer_size, alternate); | |
1197 | } | |
1198 | ||
1199 | /************ Module Stuff ***************/ | |
1200 | ||
1201 | ||
1202 | /****************************************************************************** | |
1203 | * | |
1204 | * cpia2_init/module_init | |
1205 | * | |
1206 | *****************************************************************************/ | |
8cbe84f3 | 1207 | static int __init cpia2_init(void) |
ab33d507 | 1208 | { |
1990d50b MCC |
1209 | LOG("%s v%s\n", |
1210 | ABOUT, CPIA_VERSION); | |
ab33d507 | 1211 | check_parameters(); |
dea37a97 | 1212 | return cpia2_usb_init(); |
ab33d507 AC |
1213 | } |
1214 | ||
1215 | ||
1216 | /****************************************************************************** | |
1217 | * | |
1218 | * cpia2_exit/module_exit | |
1219 | * | |
1220 | *****************************************************************************/ | |
8cbe84f3 | 1221 | static void __exit cpia2_exit(void) |
ab33d507 AC |
1222 | { |
1223 | cpia2_usb_cleanup(); | |
1224 | schedule_timeout(2 * HZ); | |
1225 | } | |
1226 | ||
ab33d507 AC |
1227 | module_init(cpia2_init); |
1228 | module_exit(cpia2_exit); |