Commit | Line | Data |
---|---|---|
ab33d507 AC |
1 | /**************************************************************************** |
2 | * | |
3 | * Filename: cpia2_v4l.c | |
4 | * | |
5 | * Copyright 2001, STMicrolectronics, Inc. | |
6 | * Contact: steve.miller@st.com | |
7 | * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> | |
8 | * | |
9 | * Description: | |
10 | * This is a USB driver for CPia2 based video cameras. | |
11 | * The infrastructure of this driver is based on the cpia usb driver by | |
12 | * Jochen Scharrlach and Johannes Erdfeldt. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or | |
17 | * (at your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License | |
25 | * along with this program; if not, write to the Free Software | |
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
27 | * | |
28 | * Stripped of 2.4 stuff ready for main kernel submit by | |
d9b01449 | 29 | * Alan Cox <alan@lxorguk.ukuu.org.uk> |
ab33d507 AC |
30 | ****************************************************************************/ |
31 | ||
32 | #include <linux/version.h> | |
33 | ||
ab33d507 AC |
34 | |
35 | #include <linux/module.h> | |
36 | #include <linux/time.h> | |
37 | #include <linux/sched.h> | |
38 | #include <linux/slab.h> | |
39 | #include <linux/init.h> | |
873ecd8f | 40 | #include <linux/videodev2.h> |
cb63c2aa | 41 | #include <linux/stringify.h> |
35ea11ff | 42 | #include <media/v4l2-ioctl.h> |
ab33d507 AC |
43 | |
44 | #include "cpia2.h" | |
45 | #include "cpia2dev.h" | |
46 | ||
ab33d507 AC |
47 | static int video_nr = -1; |
48 | module_param(video_nr, int, 0); | |
49 | MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); | |
50 | ||
51 | static int buffer_size = 68*1024; | |
52 | module_param(buffer_size, int, 0); | |
53 | MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); | |
54 | ||
55 | static int num_buffers = 3; | |
56 | module_param(num_buffers, int, 0); | |
57 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" | |
cb63c2aa | 58 | __stringify(VIDEO_MAX_FRAME) ", default 3)"); |
ab33d507 AC |
59 | |
60 | static int alternate = DEFAULT_ALT; | |
61 | module_param(alternate, int, 0); | |
cb63c2aa TF |
62 | MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" |
63 | __stringify(USBIF_ISO_6) ", default " | |
64 | __stringify(DEFAULT_ALT) ")"); | |
ab33d507 AC |
65 | |
66 | static int flicker_freq = 60; | |
67 | module_param(flicker_freq, int, 0); | |
cb63c2aa TF |
68 | MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or" |
69 | __stringify(60) ", default " | |
70 | __stringify(60) ")"); | |
ab33d507 AC |
71 | |
72 | static int flicker_mode = NEVER_FLICKER; | |
73 | module_param(flicker_mode, int, 0); | |
74 | MODULE_PARM_DESC(flicker_mode, | |
cb63c2aa TF |
75 | "Flicker supression (" __stringify(NEVER_FLICKER) "or" |
76 | __stringify(ANTI_FLICKER_ON) ", default " | |
77 | __stringify(NEVER_FLICKER) ")"); | |
ab33d507 AC |
78 | |
79 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); | |
80 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); | |
81 | MODULE_SUPPORTED_DEVICE("video"); | |
82 | MODULE_LICENSE("GPL"); | |
83 | ||
84 | #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" | |
85 | ||
ab33d507 AC |
86 | struct control_menu_info { |
87 | int value; | |
88 | char name[32]; | |
89 | }; | |
90 | ||
91 | static struct control_menu_info framerate_controls[] = | |
92 | { | |
93 | { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, | |
94 | { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, | |
95 | { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, | |
96 | { CPIA2_VP_FRAMERATE_15, "15 fps" }, | |
97 | { CPIA2_VP_FRAMERATE_25, "25 fps" }, | |
98 | { CPIA2_VP_FRAMERATE_30, "30 fps" }, | |
99 | }; | |
0c71bf1c | 100 | #define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls)) |
ab33d507 AC |
101 | |
102 | static struct control_menu_info flicker_controls[] = | |
103 | { | |
104 | { NEVER_FLICKER, "Off" }, | |
105 | { FLICKER_50, "50 Hz" }, | |
106 | { FLICKER_60, "60 Hz" }, | |
107 | }; | |
0c71bf1c | 108 | #define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls)) |
ab33d507 AC |
109 | |
110 | static struct control_menu_info lights_controls[] = | |
111 | { | |
112 | { 0, "Off" }, | |
113 | { 64, "Top" }, | |
114 | { 128, "Bottom" }, | |
115 | { 192, "Both" }, | |
116 | }; | |
0c71bf1c | 117 | #define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls)) |
ab33d507 AC |
118 | #define GPIO_LIGHTS_MASK 192 |
119 | ||
120 | static struct v4l2_queryctrl controls[] = { | |
121 | { | |
122 | .id = V4L2_CID_BRIGHTNESS, | |
123 | .type = V4L2_CTRL_TYPE_INTEGER, | |
124 | .name = "Brightness", | |
125 | .minimum = 0, | |
126 | .maximum = 255, | |
127 | .step = 1, | |
128 | .default_value = DEFAULT_BRIGHTNESS, | |
129 | }, | |
130 | { | |
131 | .id = V4L2_CID_CONTRAST, | |
132 | .type = V4L2_CTRL_TYPE_INTEGER, | |
133 | .name = "Contrast", | |
134 | .minimum = 0, | |
135 | .maximum = 255, | |
136 | .step = 1, | |
137 | .default_value = DEFAULT_CONTRAST, | |
138 | }, | |
139 | { | |
140 | .id = V4L2_CID_SATURATION, | |
141 | .type = V4L2_CTRL_TYPE_INTEGER, | |
142 | .name = "Saturation", | |
143 | .minimum = 0, | |
144 | .maximum = 255, | |
145 | .step = 1, | |
146 | .default_value = DEFAULT_SATURATION, | |
147 | }, | |
148 | { | |
149 | .id = V4L2_CID_HFLIP, | |
150 | .type = V4L2_CTRL_TYPE_BOOLEAN, | |
151 | .name = "Mirror Horizontally", | |
152 | .minimum = 0, | |
153 | .maximum = 1, | |
154 | .step = 1, | |
155 | .default_value = 0, | |
156 | }, | |
157 | { | |
158 | .id = V4L2_CID_VFLIP, | |
159 | .type = V4L2_CTRL_TYPE_BOOLEAN, | |
160 | .name = "Flip Vertically", | |
161 | .minimum = 0, | |
162 | .maximum = 1, | |
163 | .step = 1, | |
164 | .default_value = 0, | |
165 | }, | |
166 | { | |
167 | .id = CPIA2_CID_TARGET_KB, | |
168 | .type = V4L2_CTRL_TYPE_INTEGER, | |
169 | .name = "Target KB", | |
170 | .minimum = 0, | |
171 | .maximum = 255, | |
172 | .step = 1, | |
173 | .default_value = DEFAULT_TARGET_KB, | |
174 | }, | |
175 | { | |
176 | .id = CPIA2_CID_GPIO, | |
177 | .type = V4L2_CTRL_TYPE_INTEGER, | |
178 | .name = "GPIO", | |
179 | .minimum = 0, | |
180 | .maximum = 255, | |
181 | .step = 1, | |
182 | .default_value = 0, | |
183 | }, | |
184 | { | |
185 | .id = CPIA2_CID_FLICKER_MODE, | |
186 | .type = V4L2_CTRL_TYPE_MENU, | |
187 | .name = "Flicker Reduction", | |
188 | .minimum = 0, | |
189 | .maximum = NUM_FLICKER_CONTROLS-1, | |
190 | .step = 1, | |
191 | .default_value = 0, | |
192 | }, | |
193 | { | |
194 | .id = CPIA2_CID_FRAMERATE, | |
195 | .type = V4L2_CTRL_TYPE_MENU, | |
196 | .name = "Framerate", | |
197 | .minimum = 0, | |
198 | .maximum = NUM_FRAMERATE_CONTROLS-1, | |
199 | .step = 1, | |
200 | .default_value = NUM_FRAMERATE_CONTROLS-1, | |
201 | }, | |
202 | { | |
203 | .id = CPIA2_CID_USB_ALT, | |
204 | .type = V4L2_CTRL_TYPE_INTEGER, | |
205 | .name = "USB Alternate", | |
206 | .minimum = USBIF_ISO_1, | |
207 | .maximum = USBIF_ISO_6, | |
208 | .step = 1, | |
209 | .default_value = DEFAULT_ALT, | |
210 | }, | |
211 | { | |
212 | .id = CPIA2_CID_LIGHTS, | |
213 | .type = V4L2_CTRL_TYPE_MENU, | |
214 | .name = "Lights", | |
215 | .minimum = 0, | |
216 | .maximum = NUM_LIGHTS_CONTROLS-1, | |
217 | .step = 1, | |
218 | .default_value = 0, | |
219 | }, | |
220 | { | |
221 | .id = CPIA2_CID_RESET_CAMERA, | |
222 | .type = V4L2_CTRL_TYPE_BUTTON, | |
223 | .name = "Reset Camera", | |
224 | .minimum = 0, | |
225 | .maximum = 0, | |
226 | .step = 0, | |
227 | .default_value = 0, | |
228 | }, | |
229 | }; | |
0c71bf1c | 230 | #define NUM_CONTROLS (ARRAY_SIZE(controls)) |
ab33d507 AC |
231 | |
232 | ||
233 | /****************************************************************************** | |
234 | * | |
235 | * cpia2_open | |
236 | * | |
237 | *****************************************************************************/ | |
bec43661 | 238 | static int cpia2_open(struct file *file) |
ab33d507 | 239 | { |
c170ecf4 | 240 | struct camera_data *cam = video_drvdata(file); |
d2db8fee | 241 | struct cpia2_fh *fh; |
ab33d507 AC |
242 | |
243 | if (!cam) { | |
244 | ERR("Internal error, camera_data not found!\n"); | |
245 | return -ENODEV; | |
246 | } | |
247 | ||
d2db8fee HV |
248 | if (!cam->present) |
249 | return -ENODEV; | |
ab33d507 | 250 | |
d2db8fee HV |
251 | if (cam->open_count == 0) { |
252 | if (cpia2_allocate_buffers(cam)) | |
253 | return -ENOMEM; | |
ab33d507 | 254 | |
d2db8fee HV |
255 | /* reset the camera */ |
256 | if (cpia2_reset_camera(cam) < 0) | |
257 | return -EIO; | |
ab33d507 | 258 | |
d2db8fee HV |
259 | cam->APP_len = 0; |
260 | cam->COM_len = 0; | |
ab33d507 AC |
261 | } |
262 | ||
d2db8fee HV |
263 | fh = kmalloc(sizeof(*fh), GFP_KERNEL); |
264 | if (!fh) | |
265 | return -ENOMEM; | |
266 | file->private_data = fh; | |
267 | fh->prio = V4L2_PRIORITY_UNSET; | |
268 | v4l2_prio_open(&cam->prio, &fh->prio); | |
269 | fh->mmapped = 0; | |
ab33d507 AC |
270 | |
271 | ++cam->open_count; | |
272 | ||
273 | cpia2_dbg_dump_registers(cam); | |
d2db8fee | 274 | return 0; |
ab33d507 AC |
275 | } |
276 | ||
277 | /****************************************************************************** | |
278 | * | |
279 | * cpia2_close | |
280 | * | |
281 | *****************************************************************************/ | |
bec43661 | 282 | static int cpia2_close(struct file *file) |
ab33d507 AC |
283 | { |
284 | struct video_device *dev = video_devdata(file); | |
285 | struct camera_data *cam = video_get_drvdata(dev); | |
286 | struct cpia2_fh *fh = file->private_data; | |
287 | ||
ab33d507 | 288 | if (cam->present && |
d2db8fee | 289 | (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) { |
ab33d507 AC |
290 | cpia2_usb_stream_stop(cam); |
291 | ||
d2db8fee | 292 | if (cam->open_count == 1) { |
ab33d507 AC |
293 | /* save camera state for later open */ |
294 | cpia2_save_camera_state(cam); | |
295 | ||
296 | cpia2_set_low_power(cam); | |
297 | cpia2_free_buffers(cam); | |
298 | } | |
299 | } | |
300 | ||
d2db8fee HV |
301 | if (fh->mmapped) |
302 | cam->mmapped = 0; | |
303 | v4l2_prio_close(&cam->prio, fh->prio); | |
304 | file->private_data = NULL; | |
305 | kfree(fh); | |
ab33d507 AC |
306 | |
307 | if (--cam->open_count == 0) { | |
308 | cpia2_free_buffers(cam); | |
309 | if (!cam->present) { | |
310 | video_unregister_device(dev); | |
311 | kfree(cam); | |
bafefc0c | 312 | return 0; |
ab33d507 AC |
313 | } |
314 | } | |
315 | ||
ab33d507 AC |
316 | return 0; |
317 | } | |
318 | ||
319 | /****************************************************************************** | |
320 | * | |
321 | * cpia2_v4l_read | |
322 | * | |
323 | *****************************************************************************/ | |
324 | static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, | |
325 | loff_t *off) | |
326 | { | |
c170ecf4 | 327 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
328 | int noblock = file->f_flags&O_NONBLOCK; |
329 | ||
330 | struct cpia2_fh *fh = file->private_data; | |
331 | ||
332 | if(!cam) | |
333 | return -EINVAL; | |
334 | ||
335 | /* Priority check */ | |
336 | if(fh->prio != V4L2_PRIORITY_RECORD) { | |
337 | return -EBUSY; | |
338 | } | |
339 | ||
340 | return cpia2_read(cam, buf, count, noblock); | |
341 | } | |
342 | ||
343 | ||
344 | /****************************************************************************** | |
345 | * | |
346 | * cpia2_v4l_poll | |
347 | * | |
348 | *****************************************************************************/ | |
349 | static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) | |
350 | { | |
c170ecf4 | 351 | struct camera_data *cam = video_drvdata(filp); |
ab33d507 AC |
352 | struct cpia2_fh *fh = filp->private_data; |
353 | ||
354 | if(!cam) | |
355 | return POLLERR; | |
356 | ||
357 | /* Priority check */ | |
358 | if(fh->prio != V4L2_PRIORITY_RECORD) { | |
359 | return POLLERR; | |
360 | } | |
361 | ||
362 | return cpia2_poll(cam, filp, wait); | |
363 | } | |
364 | ||
365 | ||
ab33d507 AC |
366 | static int sync(struct camera_data *cam, int frame_nr) |
367 | { | |
368 | struct framebuf *frame = &cam->buffers[frame_nr]; | |
369 | ||
370 | while (1) { | |
371 | if (frame->status == FRAME_READY) | |
372 | return 0; | |
373 | ||
374 | if (!cam->streaming) { | |
375 | frame->status = FRAME_READY; | |
376 | frame->length = 0; | |
377 | return 0; | |
378 | } | |
379 | ||
d2db8fee | 380 | mutex_unlock(&cam->v4l2_lock); |
ab33d507 AC |
381 | wait_event_interruptible(cam->wq_stream, |
382 | !cam->streaming || | |
383 | frame->status == FRAME_READY); | |
d2db8fee | 384 | mutex_lock(&cam->v4l2_lock); |
ab33d507 AC |
385 | if (signal_pending(current)) |
386 | return -ERESTARTSYS; | |
387 | if(!cam->present) | |
388 | return -ENOTTY; | |
389 | } | |
390 | } | |
391 | ||
ab33d507 AC |
392 | /****************************************************************************** |
393 | * | |
394 | * ioctl_set_gpio | |
395 | * | |
396 | *****************************************************************************/ | |
397 | ||
99cd47bc HV |
398 | static long cpia2_default(struct file *file, void *fh, bool valid_prio, |
399 | int cmd, void *arg) | |
ab33d507 | 400 | { |
cbfb3daa | 401 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
402 | __u32 gpio_val; |
403 | ||
cbfb3daa HV |
404 | if (cmd != CPIA2_CID_GPIO) |
405 | return -EINVAL; | |
406 | ||
ab33d507 AC |
407 | gpio_val = *(__u32*) arg; |
408 | ||
409 | if (gpio_val &~ 0xFFU) | |
410 | return -EINVAL; | |
411 | ||
412 | return cpia2_set_gpio(cam, (unsigned char)gpio_val); | |
413 | } | |
414 | ||
415 | /****************************************************************************** | |
416 | * | |
417 | * ioctl_querycap | |
418 | * | |
419 | * V4L2 device capabilities | |
420 | * | |
421 | *****************************************************************************/ | |
422 | ||
cbfb3daa | 423 | static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) |
ab33d507 | 424 | { |
cbfb3daa | 425 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 426 | |
ab33d507 AC |
427 | strcpy(vc->driver, "cpia2"); |
428 | ||
429 | if (cam->params.pnp_id.product == 0x151) | |
430 | strcpy(vc->card, "QX5 Microscope"); | |
431 | else | |
432 | strcpy(vc->card, "CPiA2 Camera"); | |
433 | switch (cam->params.pnp_id.device_type) { | |
434 | case DEVICE_STV_672: | |
435 | strcat(vc->card, " (672/"); | |
436 | break; | |
437 | case DEVICE_STV_676: | |
438 | strcat(vc->card, " (676/"); | |
439 | break; | |
440 | default: | |
ed82b9c2 | 441 | strcat(vc->card, " (XXX/"); |
ab33d507 AC |
442 | break; |
443 | } | |
444 | switch (cam->params.version.sensor_flags) { | |
445 | case CPIA2_VP_SENSOR_FLAGS_404: | |
446 | strcat(vc->card, "404)"); | |
447 | break; | |
448 | case CPIA2_VP_SENSOR_FLAGS_407: | |
449 | strcat(vc->card, "407)"); | |
450 | break; | |
451 | case CPIA2_VP_SENSOR_FLAGS_409: | |
452 | strcat(vc->card, "409)"); | |
453 | break; | |
454 | case CPIA2_VP_SENSOR_FLAGS_410: | |
455 | strcat(vc->card, "410)"); | |
456 | break; | |
457 | case CPIA2_VP_SENSOR_FLAGS_500: | |
458 | strcat(vc->card, "500)"); | |
459 | break; | |
460 | default: | |
ed82b9c2 | 461 | strcat(vc->card, "XXX)"); |
ab33d507 AC |
462 | break; |
463 | } | |
464 | ||
465 | if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) | |
466 | memset(vc->bus_info,0, sizeof(vc->bus_info)); | |
467 | ||
468 | vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, | |
469 | CPIA2_PATCH_VER); | |
470 | ||
471 | vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | | |
472 | V4L2_CAP_READWRITE | | |
473 | V4L2_CAP_STREAMING; | |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
478 | /****************************************************************************** | |
479 | * | |
480 | * ioctl_input | |
481 | * | |
482 | * V4L2 input get/set/enumerate | |
483 | * | |
484 | *****************************************************************************/ | |
485 | ||
cbfb3daa | 486 | static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) |
ab33d507 | 487 | { |
cbfb3daa HV |
488 | if (i->index) |
489 | return -EINVAL; | |
ab33d507 AC |
490 | strcpy(i->name, "Camera"); |
491 | i->type = V4L2_INPUT_TYPE_CAMERA; | |
cbfb3daa HV |
492 | return 0; |
493 | } | |
ab33d507 | 494 | |
cbfb3daa HV |
495 | static int cpia2_g_input(struct file *file, void *fh, unsigned int *i) |
496 | { | |
497 | *i = 0; | |
ab33d507 AC |
498 | return 0; |
499 | } | |
500 | ||
cbfb3daa HV |
501 | static int cpia2_s_input(struct file *file, void *fh, unsigned int i) |
502 | { | |
503 | return i ? -EINVAL : 0; | |
504 | } | |
505 | ||
ab33d507 AC |
506 | /****************************************************************************** |
507 | * | |
508 | * ioctl_enum_fmt | |
509 | * | |
510 | * V4L2 format enumerate | |
511 | * | |
512 | *****************************************************************************/ | |
513 | ||
cbfb3daa HV |
514 | static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, |
515 | struct v4l2_fmtdesc *f) | |
ab33d507 | 516 | { |
ab33d507 AC |
517 | int index = f->index; |
518 | ||
519 | if (index < 0 || index > 1) | |
520 | return -EINVAL; | |
521 | ||
522 | memset(f, 0, sizeof(*f)); | |
523 | f->index = index; | |
524 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
525 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | |
526 | switch(index) { | |
527 | case 0: | |
528 | strcpy(f->description, "MJPEG"); | |
529 | f->pixelformat = V4L2_PIX_FMT_MJPEG; | |
530 | break; | |
531 | case 1: | |
532 | strcpy(f->description, "JPEG"); | |
533 | f->pixelformat = V4L2_PIX_FMT_JPEG; | |
534 | break; | |
535 | default: | |
536 | return -EINVAL; | |
537 | } | |
538 | ||
539 | return 0; | |
540 | } | |
541 | ||
542 | /****************************************************************************** | |
543 | * | |
544 | * ioctl_try_fmt | |
545 | * | |
546 | * V4L2 format try | |
547 | * | |
548 | *****************************************************************************/ | |
549 | ||
cbfb3daa HV |
550 | static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, |
551 | struct v4l2_format *f) | |
ab33d507 | 552 | { |
cbfb3daa | 553 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
554 | |
555 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && | |
556 | f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | |
557 | return -EINVAL; | |
558 | ||
559 | f->fmt.pix.field = V4L2_FIELD_NONE; | |
560 | f->fmt.pix.bytesperline = 0; | |
561 | f->fmt.pix.sizeimage = cam->frame_size; | |
562 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | |
563 | f->fmt.pix.priv = 0; | |
564 | ||
565 | switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { | |
566 | case VIDEOSIZE_VGA: | |
567 | f->fmt.pix.width = 640; | |
568 | f->fmt.pix.height = 480; | |
569 | break; | |
570 | case VIDEOSIZE_CIF: | |
571 | f->fmt.pix.width = 352; | |
572 | f->fmt.pix.height = 288; | |
573 | break; | |
574 | case VIDEOSIZE_QVGA: | |
575 | f->fmt.pix.width = 320; | |
576 | f->fmt.pix.height = 240; | |
577 | break; | |
578 | case VIDEOSIZE_288_216: | |
579 | f->fmt.pix.width = 288; | |
580 | f->fmt.pix.height = 216; | |
581 | break; | |
582 | case VIDEOSIZE_256_192: | |
583 | f->fmt.pix.width = 256; | |
584 | f->fmt.pix.height = 192; | |
585 | break; | |
586 | case VIDEOSIZE_224_168: | |
587 | f->fmt.pix.width = 224; | |
588 | f->fmt.pix.height = 168; | |
589 | break; | |
590 | case VIDEOSIZE_192_144: | |
591 | f->fmt.pix.width = 192; | |
592 | f->fmt.pix.height = 144; | |
593 | break; | |
594 | case VIDEOSIZE_QCIF: | |
595 | default: | |
596 | f->fmt.pix.width = 176; | |
597 | f->fmt.pix.height = 144; | |
598 | break; | |
599 | } | |
600 | ||
601 | return 0; | |
602 | } | |
603 | ||
604 | /****************************************************************************** | |
605 | * | |
606 | * ioctl_set_fmt | |
607 | * | |
608 | * V4L2 format set | |
609 | * | |
610 | *****************************************************************************/ | |
611 | ||
cbfb3daa HV |
612 | static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, |
613 | struct v4l2_format *f) | |
ab33d507 | 614 | { |
cbfb3daa HV |
615 | struct camera_data *cam = video_drvdata(file); |
616 | struct cpia2_fh *fh = _fh; | |
ab33d507 AC |
617 | int err, frame; |
618 | ||
cbfb3daa HV |
619 | err = v4l2_prio_check(&cam->prio, fh->prio); |
620 | if (err) | |
621 | return err; | |
622 | err = cpia2_try_fmt_vid_cap(file, _fh, f); | |
ab33d507 AC |
623 | if(err != 0) |
624 | return err; | |
625 | ||
626 | /* Ensure that only this process can change the format. */ | |
627 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | |
628 | if(err != 0) { | |
629 | return err; | |
630 | } | |
631 | ||
632 | cam->pixelformat = f->fmt.pix.pixelformat; | |
633 | ||
634 | /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle | |
635 | * the missing Huffman table properly. */ | |
636 | cam->params.compression.inhibit_htables = 0; | |
637 | /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ | |
638 | ||
639 | /* we set the video window to something smaller or equal to what | |
640 | * is requested by the user??? | |
641 | */ | |
642 | DBG("Requested width = %d, height = %d\n", | |
643 | f->fmt.pix.width, f->fmt.pix.height); | |
873ecd8f HV |
644 | if (f->fmt.pix.width != cam->width || |
645 | f->fmt.pix.height != cam->height) { | |
646 | cam->width = f->fmt.pix.width; | |
647 | cam->height = f->fmt.pix.height; | |
ab33d507 AC |
648 | cam->params.roi.width = f->fmt.pix.width; |
649 | cam->params.roi.height = f->fmt.pix.height; | |
650 | cpia2_set_format(cam); | |
651 | } | |
652 | ||
653 | for (frame = 0; frame < cam->num_frames; ++frame) { | |
654 | if (cam->buffers[frame].status == FRAME_READING) | |
655 | if ((err = sync(cam, frame)) < 0) | |
656 | return err; | |
657 | ||
658 | cam->buffers[frame].status = FRAME_EMPTY; | |
659 | } | |
660 | ||
661 | return 0; | |
662 | } | |
663 | ||
664 | /****************************************************************************** | |
665 | * | |
666 | * ioctl_get_fmt | |
667 | * | |
668 | * V4L2 format get | |
669 | * | |
670 | *****************************************************************************/ | |
671 | ||
cbfb3daa HV |
672 | static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, |
673 | struct v4l2_format *f) | |
ab33d507 | 674 | { |
cbfb3daa | 675 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 676 | |
873ecd8f HV |
677 | f->fmt.pix.width = cam->width; |
678 | f->fmt.pix.height = cam->height; | |
ab33d507 AC |
679 | f->fmt.pix.pixelformat = cam->pixelformat; |
680 | f->fmt.pix.field = V4L2_FIELD_NONE; | |
681 | f->fmt.pix.bytesperline = 0; | |
682 | f->fmt.pix.sizeimage = cam->frame_size; | |
683 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | |
684 | f->fmt.pix.priv = 0; | |
685 | ||
686 | return 0; | |
687 | } | |
688 | ||
689 | /****************************************************************************** | |
690 | * | |
691 | * ioctl_cropcap | |
692 | * | |
693 | * V4L2 query cropping capabilities | |
694 | * NOTE: cropping is currently disabled | |
695 | * | |
696 | *****************************************************************************/ | |
697 | ||
cbfb3daa | 698 | static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c) |
ab33d507 | 699 | { |
cbfb3daa | 700 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
701 | |
702 | if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
703 | return -EINVAL; | |
704 | ||
705 | c->bounds.left = 0; | |
706 | c->bounds.top = 0; | |
873ecd8f HV |
707 | c->bounds.width = cam->width; |
708 | c->bounds.height = cam->height; | |
ab33d507 AC |
709 | c->defrect.left = 0; |
710 | c->defrect.top = 0; | |
873ecd8f HV |
711 | c->defrect.width = cam->width; |
712 | c->defrect.height = cam->height; | |
ab33d507 AC |
713 | c->pixelaspect.numerator = 1; |
714 | c->pixelaspect.denominator = 1; | |
715 | ||
716 | return 0; | |
717 | } | |
718 | ||
719 | /****************************************************************************** | |
720 | * | |
721 | * ioctl_queryctrl | |
722 | * | |
723 | * V4L2 query possible control variables | |
724 | * | |
725 | *****************************************************************************/ | |
726 | ||
cbfb3daa | 727 | static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) |
ab33d507 | 728 | { |
cbfb3daa | 729 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
730 | int i; |
731 | ||
732 | for(i=0; i<NUM_CONTROLS; ++i) { | |
733 | if(c->id == controls[i].id) { | |
734 | memcpy(c, controls+i, sizeof(*c)); | |
735 | break; | |
736 | } | |
737 | } | |
738 | ||
739 | if(i == NUM_CONTROLS) | |
740 | return -EINVAL; | |
741 | ||
742 | /* Some devices have additional limitations */ | |
743 | switch(c->id) { | |
744 | case V4L2_CID_BRIGHTNESS: | |
745 | /*** | |
746 | * Don't let the register be set to zero - bug in VP4 | |
747 | * flash of full brightness | |
748 | ***/ | |
749 | if (cam->params.pnp_id.device_type == DEVICE_STV_672) | |
750 | c->minimum = 1; | |
751 | break; | |
752 | case V4L2_CID_VFLIP: | |
753 | // VP5 Only | |
754 | if(cam->params.pnp_id.device_type == DEVICE_STV_672) | |
755 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | |
756 | break; | |
757 | case CPIA2_CID_FRAMERATE: | |
758 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && | |
759 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ | |
760 | // Maximum 15fps | |
ab33d507 AC |
761 | for(i=0; i<c->maximum; ++i) { |
762 | if(framerate_controls[i].value == | |
763 | CPIA2_VP_FRAMERATE_15) { | |
764 | c->maximum = i; | |
765 | c->default_value = i; | |
766 | } | |
767 | } | |
768 | } | |
769 | break; | |
770 | case CPIA2_CID_FLICKER_MODE: | |
771 | // Flicker control only valid for 672. | |
772 | if(cam->params.pnp_id.device_type != DEVICE_STV_672) | |
773 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | |
774 | break; | |
775 | case CPIA2_CID_LIGHTS: | |
776 | // Light control only valid for the QX5 Microscope. | |
777 | if(cam->params.pnp_id.product != 0x151) | |
778 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | |
779 | break; | |
780 | default: | |
781 | break; | |
782 | } | |
783 | ||
784 | return 0; | |
785 | } | |
786 | ||
787 | /****************************************************************************** | |
788 | * | |
789 | * ioctl_querymenu | |
790 | * | |
791 | * V4L2 query possible control variables | |
792 | * | |
793 | *****************************************************************************/ | |
794 | ||
cbfb3daa | 795 | static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m) |
ab33d507 | 796 | { |
cbfb3daa | 797 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
798 | |
799 | switch(m->id) { | |
800 | case CPIA2_CID_FLICKER_MODE: | |
223ffe5f | 801 | if (m->index >= NUM_FLICKER_CONTROLS) |
ab33d507 AC |
802 | return -EINVAL; |
803 | ||
804 | strcpy(m->name, flicker_controls[m->index].name); | |
805 | break; | |
806 | case CPIA2_CID_FRAMERATE: | |
807 | { | |
808 | int maximum = NUM_FRAMERATE_CONTROLS - 1; | |
809 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && | |
810 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ | |
811 | // Maximum 15fps | |
812 | int i; | |
813 | for(i=0; i<maximum; ++i) { | |
814 | if(framerate_controls[i].value == | |
815 | CPIA2_VP_FRAMERATE_15) | |
816 | maximum = i; | |
817 | } | |
818 | } | |
223ffe5f | 819 | if (m->index > maximum) |
ab33d507 AC |
820 | return -EINVAL; |
821 | ||
822 | strcpy(m->name, framerate_controls[m->index].name); | |
823 | break; | |
824 | } | |
825 | case CPIA2_CID_LIGHTS: | |
223ffe5f | 826 | if (m->index >= NUM_LIGHTS_CONTROLS) |
ab33d507 AC |
827 | return -EINVAL; |
828 | ||
829 | strcpy(m->name, lights_controls[m->index].name); | |
830 | break; | |
831 | default: | |
832 | return -EINVAL; | |
833 | } | |
834 | ||
835 | return 0; | |
836 | } | |
837 | ||
838 | /****************************************************************************** | |
839 | * | |
840 | * ioctl_g_ctrl | |
841 | * | |
842 | * V4L2 get the value of a control variable | |
843 | * | |
844 | *****************************************************************************/ | |
845 | ||
cbfb3daa | 846 | static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) |
ab33d507 | 847 | { |
cbfb3daa | 848 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
849 | |
850 | switch(c->id) { | |
851 | case V4L2_CID_BRIGHTNESS: | |
852 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, | |
853 | TRANSFER_READ, 0); | |
854 | c->value = cam->params.color_params.brightness; | |
855 | break; | |
856 | case V4L2_CID_CONTRAST: | |
857 | cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, | |
858 | TRANSFER_READ, 0); | |
859 | c->value = cam->params.color_params.contrast; | |
860 | break; | |
861 | case V4L2_CID_SATURATION: | |
862 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, | |
863 | TRANSFER_READ, 0); | |
864 | c->value = cam->params.color_params.saturation; | |
865 | break; | |
866 | case V4L2_CID_HFLIP: | |
867 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, | |
868 | TRANSFER_READ, 0); | |
869 | c->value = (cam->params.vp_params.user_effects & | |
870 | CPIA2_VP_USER_EFFECTS_MIRROR) != 0; | |
871 | break; | |
872 | case V4L2_CID_VFLIP: | |
873 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, | |
874 | TRANSFER_READ, 0); | |
875 | c->value = (cam->params.vp_params.user_effects & | |
876 | CPIA2_VP_USER_EFFECTS_FLIP) != 0; | |
877 | break; | |
878 | case CPIA2_CID_TARGET_KB: | |
879 | c->value = cam->params.vc_params.target_kb; | |
880 | break; | |
881 | case CPIA2_CID_GPIO: | |
882 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, | |
883 | TRANSFER_READ, 0); | |
884 | c->value = cam->params.vp_params.gpio_data; | |
885 | break; | |
886 | case CPIA2_CID_FLICKER_MODE: | |
887 | { | |
888 | int i, mode; | |
889 | cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, | |
890 | TRANSFER_READ, 0); | |
891 | if(cam->params.flicker_control.cam_register & | |
892 | CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { | |
893 | mode = NEVER_FLICKER; | |
894 | } else { | |
895 | if(cam->params.flicker_control.cam_register & | |
896 | CPIA2_VP_FLICKER_MODES_50HZ) { | |
657de3cd | 897 | mode = FLICKER_50; |
ab33d507 | 898 | } else { |
657de3cd | 899 | mode = FLICKER_60; |
ab33d507 AC |
900 | } |
901 | } | |
902 | for(i=0; i<NUM_FLICKER_CONTROLS; i++) { | |
903 | if(flicker_controls[i].value == mode) { | |
904 | c->value = i; | |
905 | break; | |
906 | } | |
907 | } | |
908 | if(i == NUM_FLICKER_CONTROLS) | |
909 | return -EINVAL; | |
910 | break; | |
911 | } | |
912 | case CPIA2_CID_FRAMERATE: | |
913 | { | |
914 | int maximum = NUM_FRAMERATE_CONTROLS - 1; | |
915 | int i; | |
916 | for(i=0; i<= maximum; i++) { | |
917 | if(cam->params.vp_params.frame_rate == | |
918 | framerate_controls[i].value) | |
919 | break; | |
920 | } | |
921 | if(i > maximum) | |
922 | return -EINVAL; | |
923 | c->value = i; | |
924 | break; | |
925 | } | |
926 | case CPIA2_CID_USB_ALT: | |
927 | c->value = cam->params.camera_state.stream_mode; | |
928 | break; | |
929 | case CPIA2_CID_LIGHTS: | |
930 | { | |
931 | int i; | |
932 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, | |
933 | TRANSFER_READ, 0); | |
934 | for(i=0; i<NUM_LIGHTS_CONTROLS; i++) { | |
935 | if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) == | |
936 | lights_controls[i].value) { | |
937 | break; | |
938 | } | |
939 | } | |
940 | if(i == NUM_LIGHTS_CONTROLS) | |
941 | return -EINVAL; | |
942 | c->value = i; | |
943 | break; | |
944 | } | |
945 | case CPIA2_CID_RESET_CAMERA: | |
946 | return -EINVAL; | |
947 | default: | |
948 | return -EINVAL; | |
949 | } | |
950 | ||
951 | DBG("Get control id:%d, value:%d\n", c->id, c->value); | |
952 | ||
953 | return 0; | |
954 | } | |
955 | ||
956 | /****************************************************************************** | |
957 | * | |
958 | * ioctl_s_ctrl | |
959 | * | |
960 | * V4L2 set the value of a control variable | |
961 | * | |
962 | *****************************************************************************/ | |
963 | ||
cbfb3daa | 964 | static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) |
ab33d507 | 965 | { |
cbfb3daa | 966 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
967 | int i; |
968 | int retval = 0; | |
969 | ||
970 | DBG("Set control id:%d, value:%d\n", c->id, c->value); | |
971 | ||
972 | /* Check that the value is in range */ | |
973 | for(i=0; i<NUM_CONTROLS; i++) { | |
974 | if(c->id == controls[i].id) { | |
975 | if(c->value < controls[i].minimum || | |
976 | c->value > controls[i].maximum) { | |
977 | return -EINVAL; | |
978 | } | |
979 | break; | |
980 | } | |
981 | } | |
982 | if(i == NUM_CONTROLS) | |
983 | return -EINVAL; | |
984 | ||
985 | switch(c->id) { | |
986 | case V4L2_CID_BRIGHTNESS: | |
987 | cpia2_set_brightness(cam, c->value); | |
988 | break; | |
989 | case V4L2_CID_CONTRAST: | |
990 | cpia2_set_contrast(cam, c->value); | |
991 | break; | |
992 | case V4L2_CID_SATURATION: | |
993 | cpia2_set_saturation(cam, c->value); | |
994 | break; | |
995 | case V4L2_CID_HFLIP: | |
996 | cpia2_set_property_mirror(cam, c->value); | |
997 | break; | |
998 | case V4L2_CID_VFLIP: | |
999 | cpia2_set_property_flip(cam, c->value); | |
1000 | break; | |
1001 | case CPIA2_CID_TARGET_KB: | |
1002 | retval = cpia2_set_target_kb(cam, c->value); | |
1003 | break; | |
1004 | case CPIA2_CID_GPIO: | |
1005 | retval = cpia2_set_gpio(cam, c->value); | |
1006 | break; | |
1007 | case CPIA2_CID_FLICKER_MODE: | |
1008 | retval = cpia2_set_flicker_mode(cam, | |
1009 | flicker_controls[c->value].value); | |
1010 | break; | |
1011 | case CPIA2_CID_FRAMERATE: | |
1012 | retval = cpia2_set_fps(cam, framerate_controls[c->value].value); | |
1013 | break; | |
1014 | case CPIA2_CID_USB_ALT: | |
1015 | retval = cpia2_usb_change_streaming_alternate(cam, c->value); | |
1016 | break; | |
1017 | case CPIA2_CID_LIGHTS: | |
1018 | retval = cpia2_set_gpio(cam, lights_controls[c->value].value); | |
1019 | break; | |
1020 | case CPIA2_CID_RESET_CAMERA: | |
1021 | cpia2_usb_stream_pause(cam); | |
1022 | cpia2_reset_camera(cam); | |
1023 | cpia2_usb_stream_resume(cam); | |
1024 | break; | |
1025 | default: | |
1026 | retval = -EINVAL; | |
1027 | } | |
1028 | ||
1029 | return retval; | |
1030 | } | |
1031 | ||
1032 | /****************************************************************************** | |
1033 | * | |
1034 | * ioctl_g_jpegcomp | |
1035 | * | |
1036 | * V4L2 get the JPEG compression parameters | |
1037 | * | |
1038 | *****************************************************************************/ | |
1039 | ||
cbfb3daa | 1040 | static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) |
ab33d507 | 1041 | { |
cbfb3daa | 1042 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
1043 | |
1044 | memset(parms, 0, sizeof(*parms)); | |
1045 | ||
1046 | parms->quality = 80; // TODO: Can this be made meaningful? | |
1047 | ||
1048 | parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; | |
1049 | if(!cam->params.compression.inhibit_htables) { | |
1050 | parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; | |
1051 | } | |
1052 | ||
1053 | parms->APPn = cam->APPn; | |
1054 | parms->APP_len = cam->APP_len; | |
1055 | if(cam->APP_len > 0) { | |
1056 | memcpy(parms->APP_data, cam->APP_data, cam->APP_len); | |
1057 | parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; | |
1058 | } | |
1059 | ||
1060 | parms->COM_len = cam->COM_len; | |
1061 | if(cam->COM_len > 0) { | |
1062 | memcpy(parms->COM_data, cam->COM_data, cam->COM_len); | |
1063 | parms->jpeg_markers |= JPEG_MARKER_COM; | |
1064 | } | |
1065 | ||
1066 | DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", | |
1067 | parms->APP_len, parms->COM_len); | |
1068 | ||
1069 | return 0; | |
1070 | } | |
1071 | ||
1072 | /****************************************************************************** | |
1073 | * | |
1074 | * ioctl_s_jpegcomp | |
1075 | * | |
1076 | * V4L2 set the JPEG compression parameters | |
1077 | * NOTE: quality and some jpeg_markers are ignored. | |
1078 | * | |
1079 | *****************************************************************************/ | |
1080 | ||
cbfb3daa | 1081 | static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) |
ab33d507 | 1082 | { |
cbfb3daa | 1083 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
1084 | |
1085 | DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", | |
1086 | parms->APP_len, parms->COM_len); | |
1087 | ||
1088 | cam->params.compression.inhibit_htables = | |
1089 | !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); | |
1090 | ||
1091 | if(parms->APP_len != 0) { | |
1092 | if(parms->APP_len > 0 && | |
1093 | parms->APP_len <= sizeof(cam->APP_data) && | |
1094 | parms->APPn >= 0 && parms->APPn <= 15) { | |
1095 | cam->APPn = parms->APPn; | |
1096 | cam->APP_len = parms->APP_len; | |
1097 | memcpy(cam->APP_data, parms->APP_data, parms->APP_len); | |
1098 | } else { | |
1099 | LOG("Bad APPn Params n=%d len=%d\n", | |
1100 | parms->APPn, parms->APP_len); | |
1101 | return -EINVAL; | |
1102 | } | |
1103 | } else { | |
1104 | cam->APP_len = 0; | |
1105 | } | |
1106 | ||
1107 | if(parms->COM_len != 0) { | |
1108 | if(parms->COM_len > 0 && | |
1109 | parms->COM_len <= sizeof(cam->COM_data)) { | |
1110 | cam->COM_len = parms->COM_len; | |
1111 | memcpy(cam->COM_data, parms->COM_data, parms->COM_len); | |
1112 | } else { | |
1113 | LOG("Bad COM_len=%d\n", parms->COM_len); | |
1114 | return -EINVAL; | |
1115 | } | |
1116 | } | |
1117 | ||
1118 | return 0; | |
1119 | } | |
1120 | ||
1121 | /****************************************************************************** | |
1122 | * | |
1123 | * ioctl_reqbufs | |
1124 | * | |
1125 | * V4L2 Initiate memory mapping. | |
1126 | * NOTE: The user's request is ignored. For now the buffers are fixed. | |
1127 | * | |
1128 | *****************************************************************************/ | |
1129 | ||
cbfb3daa | 1130 | static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) |
ab33d507 | 1131 | { |
cbfb3daa | 1132 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
1133 | |
1134 | if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
1135 | req->memory != V4L2_MEMORY_MMAP) | |
1136 | return -EINVAL; | |
1137 | ||
1138 | DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); | |
1139 | req->count = cam->num_frames; | |
1140 | memset(&req->reserved, 0, sizeof(req->reserved)); | |
1141 | ||
1142 | return 0; | |
1143 | } | |
1144 | ||
1145 | /****************************************************************************** | |
1146 | * | |
1147 | * ioctl_querybuf | |
1148 | * | |
1149 | * V4L2 Query memory buffer status. | |
1150 | * | |
1151 | *****************************************************************************/ | |
1152 | ||
cbfb3daa | 1153 | static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
ab33d507 | 1154 | { |
cbfb3daa | 1155 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
1156 | |
1157 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
1158 | buf->index > cam->num_frames) | |
1159 | return -EINVAL; | |
1160 | ||
1161 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | |
1162 | buf->length = cam->frame_size; | |
1163 | ||
1164 | buf->memory = V4L2_MEMORY_MMAP; | |
1165 | ||
1166 | if(cam->mmapped) | |
1167 | buf->flags = V4L2_BUF_FLAG_MAPPED; | |
1168 | else | |
1169 | buf->flags = 0; | |
1170 | ||
1171 | switch (cam->buffers[buf->index].status) { | |
1172 | case FRAME_EMPTY: | |
1173 | case FRAME_ERROR: | |
1174 | case FRAME_READING: | |
1175 | buf->bytesused = 0; | |
1176 | buf->flags = V4L2_BUF_FLAG_QUEUED; | |
1177 | break; | |
1178 | case FRAME_READY: | |
1179 | buf->bytesused = cam->buffers[buf->index].length; | |
1180 | buf->timestamp = cam->buffers[buf->index].timestamp; | |
1181 | buf->sequence = cam->buffers[buf->index].seq; | |
1182 | buf->flags = V4L2_BUF_FLAG_DONE; | |
1183 | break; | |
1184 | } | |
1185 | ||
1186 | DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", | |
1187 | buf->index, buf->m.offset, buf->flags, buf->sequence, | |
1188 | buf->bytesused); | |
1189 | ||
1190 | return 0; | |
1191 | } | |
1192 | ||
1193 | /****************************************************************************** | |
1194 | * | |
1195 | * ioctl_qbuf | |
1196 | * | |
1197 | * V4L2 User is freeing buffer | |
1198 | * | |
1199 | *****************************************************************************/ | |
1200 | ||
cbfb3daa | 1201 | static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
ab33d507 | 1202 | { |
cbfb3daa | 1203 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
1204 | |
1205 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
1206 | buf->memory != V4L2_MEMORY_MMAP || | |
1207 | buf->index > cam->num_frames) | |
1208 | return -EINVAL; | |
1209 | ||
1210 | DBG("QBUF #%d\n", buf->index); | |
1211 | ||
1212 | if(cam->buffers[buf->index].status == FRAME_READY) | |
1213 | cam->buffers[buf->index].status = FRAME_EMPTY; | |
1214 | ||
1215 | return 0; | |
1216 | } | |
1217 | ||
1218 | /****************************************************************************** | |
1219 | * | |
1220 | * find_earliest_filled_buffer | |
1221 | * | |
1222 | * Helper for ioctl_dqbuf. Find the next ready buffer. | |
1223 | * | |
1224 | *****************************************************************************/ | |
1225 | ||
1226 | static int find_earliest_filled_buffer(struct camera_data *cam) | |
1227 | { | |
1228 | int i; | |
1229 | int found = -1; | |
1230 | for (i=0; i<cam->num_frames; i++) { | |
1231 | if(cam->buffers[i].status == FRAME_READY) { | |
1232 | if(found < 0) { | |
1233 | found = i; | |
1234 | } else { | |
1235 | /* find which buffer is earlier */ | |
1236 | struct timeval *tv1, *tv2; | |
1237 | tv1 = &cam->buffers[i].timestamp; | |
1238 | tv2 = &cam->buffers[found].timestamp; | |
1239 | if(tv1->tv_sec < tv2->tv_sec || | |
1240 | (tv1->tv_sec == tv2->tv_sec && | |
1241 | tv1->tv_usec < tv2->tv_usec)) | |
1242 | found = i; | |
1243 | } | |
1244 | } | |
1245 | } | |
1246 | return found; | |
1247 | } | |
1248 | ||
1249 | /****************************************************************************** | |
1250 | * | |
1251 | * ioctl_dqbuf | |
1252 | * | |
1253 | * V4L2 User is asking for a filled buffer. | |
1254 | * | |
1255 | *****************************************************************************/ | |
1256 | ||
cbfb3daa | 1257 | static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
ab33d507 | 1258 | { |
cbfb3daa | 1259 | struct camera_data *cam = video_drvdata(file); |
ab33d507 AC |
1260 | int frame; |
1261 | ||
1262 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | |
1263 | buf->memory != V4L2_MEMORY_MMAP) | |
1264 | return -EINVAL; | |
1265 | ||
1266 | frame = find_earliest_filled_buffer(cam); | |
1267 | ||
1268 | if(frame < 0 && file->f_flags&O_NONBLOCK) | |
1269 | return -EAGAIN; | |
1270 | ||
1271 | if(frame < 0) { | |
1272 | /* Wait for a frame to become available */ | |
1273 | struct framebuf *cb=cam->curbuff; | |
d2db8fee | 1274 | mutex_unlock(&cam->v4l2_lock); |
ab33d507 AC |
1275 | wait_event_interruptible(cam->wq_stream, |
1276 | !cam->present || | |
1277 | (cb=cam->curbuff)->status == FRAME_READY); | |
d2db8fee | 1278 | mutex_lock(&cam->v4l2_lock); |
ab33d507 AC |
1279 | if (signal_pending(current)) |
1280 | return -ERESTARTSYS; | |
1281 | if(!cam->present) | |
1282 | return -ENOTTY; | |
1283 | frame = cb->num; | |
1284 | } | |
1285 | ||
1286 | ||
1287 | buf->index = frame; | |
1288 | buf->bytesused = cam->buffers[buf->index].length; | |
1289 | buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; | |
1290 | buf->field = V4L2_FIELD_NONE; | |
1291 | buf->timestamp = cam->buffers[buf->index].timestamp; | |
1292 | buf->sequence = cam->buffers[buf->index].seq; | |
1293 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | |
1294 | buf->length = cam->frame_size; | |
1295 | buf->input = 0; | |
1296 | buf->reserved = 0; | |
1297 | memset(&buf->timecode, 0, sizeof(buf->timecode)); | |
1298 | ||
1299 | DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, | |
1300 | cam->buffers[buf->index].status, buf->sequence, buf->bytesused); | |
1301 | ||
1302 | return 0; | |
1303 | } | |
1304 | ||
cbfb3daa | 1305 | static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p) |
ab33d507 | 1306 | { |
cbfb3daa | 1307 | struct cpia2_fh *fh = _fh; |
ab33d507 | 1308 | |
cbfb3daa HV |
1309 | *p = fh->prio; |
1310 | return 0; | |
1311 | } | |
ab33d507 | 1312 | |
cbfb3daa HV |
1313 | static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio) |
1314 | { | |
1315 | struct camera_data *cam = video_drvdata(file); | |
81dfea88 | 1316 | struct cpia2_fh *fh = _fh; |
ab33d507 | 1317 | |
cbfb3daa HV |
1318 | if (cam->streaming && prio != fh->prio && |
1319 | fh->prio == V4L2_PRIORITY_RECORD) | |
1320 | /* Can't drop record priority while streaming */ | |
1321 | return -EBUSY; | |
ab33d507 | 1322 | |
cbfb3daa HV |
1323 | if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio && |
1324 | v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) | |
1325 | /* Only one program can record at a time */ | |
1326 | return -EBUSY; | |
1327 | return v4l2_prio_change(&cam->prio, &fh->prio, prio); | |
1328 | } | |
ab33d507 | 1329 | |
cbfb3daa HV |
1330 | static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) |
1331 | { | |
1332 | struct camera_data *cam = video_drvdata(file); | |
ab33d507 | 1333 | |
cbfb3daa HV |
1334 | DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); |
1335 | if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
1336 | return -EINVAL; | |
ab33d507 | 1337 | |
cbfb3daa HV |
1338 | if (!cam->streaming) |
1339 | return cpia2_usb_stream_start(cam, | |
1340 | cam->params.camera_state.stream_mode); | |
1341 | return -EINVAL; | |
ab33d507 AC |
1342 | } |
1343 | ||
cbfb3daa | 1344 | static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) |
ab33d507 | 1345 | { |
cbfb3daa HV |
1346 | struct camera_data *cam = video_drvdata(file); |
1347 | ||
1348 | DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); | |
1349 | if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
1350 | return -EINVAL; | |
1351 | ||
1352 | if (cam->streaming) | |
1353 | return cpia2_usb_stream_stop(cam); | |
1354 | return -EINVAL; | |
ab33d507 AC |
1355 | } |
1356 | ||
1357 | /****************************************************************************** | |
1358 | * | |
1359 | * cpia2_mmap | |
1360 | * | |
1361 | *****************************************************************************/ | |
1362 | static int cpia2_mmap(struct file *file, struct vm_area_struct *area) | |
1363 | { | |
c170ecf4 | 1364 | struct camera_data *cam = video_drvdata(file); |
ab33d507 | 1365 | int retval; |
ab33d507 AC |
1366 | |
1367 | /* Priority check */ | |
1368 | struct cpia2_fh *fh = file->private_data; | |
1369 | if(fh->prio != V4L2_PRIORITY_RECORD) { | |
1370 | return -EBUSY; | |
1371 | } | |
1372 | ||
1373 | retval = cpia2_remap_buffer(cam, area); | |
1374 | ||
1375 | if(!retval) | |
1376 | fh->mmapped = 1; | |
1377 | return retval; | |
1378 | } | |
1379 | ||
1380 | /****************************************************************************** | |
1381 | * | |
1382 | * reset_camera_struct_v4l | |
1383 | * | |
1384 | * Sets all values to the defaults | |
1385 | *****************************************************************************/ | |
1386 | static void reset_camera_struct_v4l(struct camera_data *cam) | |
1387 | { | |
873ecd8f HV |
1388 | cam->width = cam->params.roi.width; |
1389 | cam->height = cam->params.roi.height; | |
ab33d507 AC |
1390 | |
1391 | cam->frame_size = buffer_size; | |
1392 | cam->num_frames = num_buffers; | |
1393 | ||
1394 | /* FlickerModes */ | |
1395 | cam->params.flicker_control.flicker_mode_req = flicker_mode; | |
1396 | cam->params.flicker_control.mains_frequency = flicker_freq; | |
1397 | ||
1398 | /* streamMode */ | |
1399 | cam->params.camera_state.stream_mode = alternate; | |
1400 | ||
1401 | cam->pixelformat = V4L2_PIX_FMT_JPEG; | |
1402 | v4l2_prio_init(&cam->prio); | |
ab33d507 AC |
1403 | } |
1404 | ||
cbfb3daa HV |
1405 | static const struct v4l2_ioctl_ops cpia2_ioctl_ops = { |
1406 | .vidioc_querycap = cpia2_querycap, | |
1407 | .vidioc_enum_input = cpia2_enum_input, | |
1408 | .vidioc_g_input = cpia2_g_input, | |
1409 | .vidioc_s_input = cpia2_s_input, | |
1410 | .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, | |
1411 | .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, | |
1412 | .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, | |
1413 | .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, | |
1414 | .vidioc_queryctrl = cpia2_queryctrl, | |
1415 | .vidioc_querymenu = cpia2_querymenu, | |
1416 | .vidioc_g_ctrl = cpia2_g_ctrl, | |
1417 | .vidioc_s_ctrl = cpia2_s_ctrl, | |
1418 | .vidioc_g_jpegcomp = cpia2_g_jpegcomp, | |
1419 | .vidioc_s_jpegcomp = cpia2_s_jpegcomp, | |
1420 | .vidioc_cropcap = cpia2_cropcap, | |
1421 | .vidioc_reqbufs = cpia2_reqbufs, | |
1422 | .vidioc_querybuf = cpia2_querybuf, | |
1423 | .vidioc_qbuf = cpia2_qbuf, | |
1424 | .vidioc_dqbuf = cpia2_dqbuf, | |
1425 | .vidioc_streamon = cpia2_streamon, | |
1426 | .vidioc_streamoff = cpia2_streamoff, | |
1427 | .vidioc_g_priority = cpia2_g_priority, | |
1428 | .vidioc_s_priority = cpia2_s_priority, | |
1429 | .vidioc_default = cpia2_default, | |
1430 | }; | |
1431 | ||
ab33d507 AC |
1432 | /*** |
1433 | * The v4l video device structure initialized for this device | |
1434 | ***/ | |
873ecd8f | 1435 | static const struct v4l2_file_operations cpia2_fops = { |
2ae15191 AC |
1436 | .owner = THIS_MODULE, |
1437 | .open = cpia2_open, | |
1438 | .release = cpia2_close, | |
1439 | .read = cpia2_v4l_read, | |
1440 | .poll = cpia2_v4l_poll, | |
cbfb3daa | 1441 | .unlocked_ioctl = video_ioctl2, |
2ae15191 | 1442 | .mmap = cpia2_mmap, |
ab33d507 AC |
1443 | }; |
1444 | ||
1445 | static struct video_device cpia2_template = { | |
1446 | /* I could not find any place for the old .initialize initializer?? */ | |
873ecd8f HV |
1447 | .name = "CPiA2 Camera", |
1448 | .fops = &cpia2_fops, | |
cbfb3daa | 1449 | .ioctl_ops = &cpia2_ioctl_ops, |
873ecd8f | 1450 | .release = video_device_release, |
ab33d507 AC |
1451 | }; |
1452 | ||
1453 | /****************************************************************************** | |
1454 | * | |
1455 | * cpia2_register_camera | |
1456 | * | |
1457 | *****************************************************************************/ | |
1458 | int cpia2_register_camera(struct camera_data *cam) | |
1459 | { | |
1460 | cam->vdev = video_device_alloc(); | |
1461 | if(!cam->vdev) | |
1462 | return -ENOMEM; | |
1463 | ||
1464 | memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); | |
1465 | video_set_drvdata(cam->vdev, cam); | |
d2db8fee | 1466 | cam->vdev->lock = &cam->v4l2_lock; |
ab33d507 AC |
1467 | |
1468 | reset_camera_struct_v4l(cam); | |
1469 | ||
1470 | /* register v4l device */ | |
dc60de33 | 1471 | if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { |
ab33d507 AC |
1472 | ERR("video_register_device failed\n"); |
1473 | video_device_release(cam->vdev); | |
1474 | return -ENODEV; | |
1475 | } | |
1476 | ||
1477 | return 0; | |
1478 | } | |
1479 | ||
1480 | /****************************************************************************** | |
1481 | * | |
1482 | * cpia2_unregister_camera | |
1483 | * | |
1484 | *****************************************************************************/ | |
1485 | void cpia2_unregister_camera(struct camera_data *cam) | |
1486 | { | |
1487 | if (!cam->open_count) { | |
1488 | video_unregister_device(cam->vdev); | |
1489 | } else { | |
38c7c036 LP |
1490 | LOG("%s removed while open, deferring " |
1491 | "video_unregister_device\n", | |
1492 | video_device_node_name(cam->vdev)); | |
ab33d507 AC |
1493 | } |
1494 | } | |
1495 | ||
1496 | /****************************************************************************** | |
1497 | * | |
1498 | * check_parameters | |
1499 | * | |
1500 | * Make sure that all user-supplied parameters are sensible | |
1501 | *****************************************************************************/ | |
1502 | static void __init check_parameters(void) | |
1503 | { | |
1504 | if(buffer_size < PAGE_SIZE) { | |
1505 | buffer_size = PAGE_SIZE; | |
1506 | LOG("buffer_size too small, setting to %d\n", buffer_size); | |
1507 | } else if(buffer_size > 1024*1024) { | |
1508 | /* arbitrary upper limiit */ | |
1509 | buffer_size = 1024*1024; | |
1510 | LOG("buffer_size ridiculously large, setting to %d\n", | |
1511 | buffer_size); | |
1512 | } else { | |
1513 | buffer_size += PAGE_SIZE-1; | |
1514 | buffer_size &= ~(PAGE_SIZE-1); | |
1515 | } | |
1516 | ||
1517 | if(num_buffers < 1) { | |
1518 | num_buffers = 1; | |
1519 | LOG("num_buffers too small, setting to %d\n", num_buffers); | |
1520 | } else if(num_buffers > VIDEO_MAX_FRAME) { | |
1521 | num_buffers = VIDEO_MAX_FRAME; | |
1522 | LOG("num_buffers too large, setting to %d\n", num_buffers); | |
1523 | } | |
1524 | ||
1525 | if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { | |
1526 | alternate = DEFAULT_ALT; | |
1527 | LOG("alternate specified is invalid, using %d\n", alternate); | |
1528 | } | |
1529 | ||
1530 | if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { | |
1531 | flicker_mode = NEVER_FLICKER; | |
1532 | LOG("Flicker mode specified is invalid, using %d\n", | |
1533 | flicker_mode); | |
1534 | } | |
1535 | ||
1536 | if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { | |
1537 | flicker_freq = FLICKER_60; | |
1538 | LOG("Flicker mode specified is invalid, using %d\n", | |
1539 | flicker_freq); | |
1540 | } | |
1541 | ||
1542 | if(video_nr < -1 || video_nr > 64) { | |
1543 | video_nr = -1; | |
1544 | LOG("invalid video_nr specified, must be -1 to 64\n"); | |
1545 | } | |
1546 | ||
1547 | DBG("Using %d buffers, each %d bytes, alternate=%d\n", | |
1548 | num_buffers, buffer_size, alternate); | |
1549 | } | |
1550 | ||
1551 | /************ Module Stuff ***************/ | |
1552 | ||
1553 | ||
1554 | /****************************************************************************** | |
1555 | * | |
1556 | * cpia2_init/module_init | |
1557 | * | |
1558 | *****************************************************************************/ | |
8cbe84f3 | 1559 | static int __init cpia2_init(void) |
ab33d507 AC |
1560 | { |
1561 | LOG("%s v%d.%d.%d\n", | |
1562 | ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); | |
1563 | check_parameters(); | |
1564 | cpia2_usb_init(); | |
1565 | return 0; | |
1566 | } | |
1567 | ||
1568 | ||
1569 | /****************************************************************************** | |
1570 | * | |
1571 | * cpia2_exit/module_exit | |
1572 | * | |
1573 | *****************************************************************************/ | |
8cbe84f3 | 1574 | static void __exit cpia2_exit(void) |
ab33d507 AC |
1575 | { |
1576 | cpia2_usb_cleanup(); | |
1577 | schedule_timeout(2 * HZ); | |
1578 | } | |
1579 | ||
ab33d507 AC |
1580 | module_init(cpia2_init); |
1581 | module_exit(cpia2_exit); | |
1582 |