diff options
Diffstat (limited to 'drivers/media/video/cpia2/cpia2_v4l.c')
-rw-r--r-- | drivers/media/video/cpia2/cpia2_v4l.c | 2104 |
1 files changed, 2104 insertions, 0 deletions
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c new file mode 100644 index 000000000000..3480a2ca7cdc --- /dev/null +++ b/drivers/media/video/cpia2/cpia2_v4l.c | |||
@@ -0,0 +1,2104 @@ | |||
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 | ||
29 | * Alan Cox <alan@redhat.com> | ||
30 | ****************************************************************************/ | ||
31 | |||
32 | #include <linux/version.h> | ||
33 | |||
34 | #include <linux/config.h> | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/time.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/moduleparam.h> | ||
42 | |||
43 | #include "cpia2.h" | ||
44 | #include "cpia2dev.h" | ||
45 | |||
46 | |||
47 | //#define _CPIA2_DEBUG_ | ||
48 | |||
49 | #define MAKE_STRING_1(x) #x | ||
50 | #define MAKE_STRING(x) MAKE_STRING_1(x) | ||
51 | |||
52 | static int video_nr = -1; | ||
53 | module_param(video_nr, int, 0); | ||
54 | MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); | ||
55 | |||
56 | static int buffer_size = 68*1024; | ||
57 | module_param(buffer_size, int, 0); | ||
58 | MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); | ||
59 | |||
60 | static int num_buffers = 3; | ||
61 | module_param(num_buffers, int, 0); | ||
62 | MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" | ||
63 | MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)"); | ||
64 | |||
65 | static int alternate = DEFAULT_ALT; | ||
66 | module_param(alternate, int, 0); | ||
67 | MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" | ||
68 | MAKE_STRING(USBIF_ISO_6) ", default " | ||
69 | MAKE_STRING(DEFAULT_ALT) ")"); | ||
70 | |||
71 | static int flicker_freq = 60; | ||
72 | module_param(flicker_freq, int, 0); | ||
73 | MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" | ||
74 | MAKE_STRING(60) ", default " | ||
75 | MAKE_STRING(60) ")"); | ||
76 | |||
77 | static int flicker_mode = NEVER_FLICKER; | ||
78 | module_param(flicker_mode, int, 0); | ||
79 | MODULE_PARM_DESC(flicker_mode, | ||
80 | "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" | ||
81 | MAKE_STRING(ANTI_FLICKER_ON) ", default " | ||
82 | MAKE_STRING(NEVER_FLICKER) ")"); | ||
83 | |||
84 | MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); | ||
85 | MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); | ||
86 | MODULE_SUPPORTED_DEVICE("video"); | ||
87 | MODULE_LICENSE("GPL"); | ||
88 | |||
89 | #define ABOUT "V4L-Driver for Vision CPiA2 based cameras" | ||
90 | |||
91 | #ifndef VID_HARDWARE_CPIA2 | ||
92 | #error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h" | ||
93 | #endif | ||
94 | |||
95 | struct control_menu_info { | ||
96 | int value; | ||
97 | char name[32]; | ||
98 | }; | ||
99 | |||
100 | static struct control_menu_info framerate_controls[] = | ||
101 | { | ||
102 | { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, | ||
103 | { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, | ||
104 | { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, | ||
105 | { CPIA2_VP_FRAMERATE_15, "15 fps" }, | ||
106 | { CPIA2_VP_FRAMERATE_25, "25 fps" }, | ||
107 | { CPIA2_VP_FRAMERATE_30, "30 fps" }, | ||
108 | }; | ||
109 | #define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0])) | ||
110 | |||
111 | static struct control_menu_info flicker_controls[] = | ||
112 | { | ||
113 | { NEVER_FLICKER, "Off" }, | ||
114 | { FLICKER_50, "50 Hz" }, | ||
115 | { FLICKER_60, "60 Hz" }, | ||
116 | }; | ||
117 | #define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0])) | ||
118 | |||
119 | static struct control_menu_info lights_controls[] = | ||
120 | { | ||
121 | { 0, "Off" }, | ||
122 | { 64, "Top" }, | ||
123 | { 128, "Bottom" }, | ||
124 | { 192, "Both" }, | ||
125 | }; | ||
126 | #define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0])) | ||
127 | #define GPIO_LIGHTS_MASK 192 | ||
128 | |||
129 | static struct v4l2_queryctrl controls[] = { | ||
130 | { | ||
131 | .id = V4L2_CID_BRIGHTNESS, | ||
132 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
133 | .name = "Brightness", | ||
134 | .minimum = 0, | ||
135 | .maximum = 255, | ||
136 | .step = 1, | ||
137 | .default_value = DEFAULT_BRIGHTNESS, | ||
138 | }, | ||
139 | { | ||
140 | .id = V4L2_CID_CONTRAST, | ||
141 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
142 | .name = "Contrast", | ||
143 | .minimum = 0, | ||
144 | .maximum = 255, | ||
145 | .step = 1, | ||
146 | .default_value = DEFAULT_CONTRAST, | ||
147 | }, | ||
148 | { | ||
149 | .id = V4L2_CID_SATURATION, | ||
150 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
151 | .name = "Saturation", | ||
152 | .minimum = 0, | ||
153 | .maximum = 255, | ||
154 | .step = 1, | ||
155 | .default_value = DEFAULT_SATURATION, | ||
156 | }, | ||
157 | { | ||
158 | .id = V4L2_CID_HFLIP, | ||
159 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
160 | .name = "Mirror Horizontally", | ||
161 | .minimum = 0, | ||
162 | .maximum = 1, | ||
163 | .step = 1, | ||
164 | .default_value = 0, | ||
165 | }, | ||
166 | { | ||
167 | .id = V4L2_CID_VFLIP, | ||
168 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
169 | .name = "Flip Vertically", | ||
170 | .minimum = 0, | ||
171 | .maximum = 1, | ||
172 | .step = 1, | ||
173 | .default_value = 0, | ||
174 | }, | ||
175 | { | ||
176 | .id = CPIA2_CID_TARGET_KB, | ||
177 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
178 | .name = "Target KB", | ||
179 | .minimum = 0, | ||
180 | .maximum = 255, | ||
181 | .step = 1, | ||
182 | .default_value = DEFAULT_TARGET_KB, | ||
183 | }, | ||
184 | { | ||
185 | .id = CPIA2_CID_GPIO, | ||
186 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
187 | .name = "GPIO", | ||
188 | .minimum = 0, | ||
189 | .maximum = 255, | ||
190 | .step = 1, | ||
191 | .default_value = 0, | ||
192 | }, | ||
193 | { | ||
194 | .id = CPIA2_CID_FLICKER_MODE, | ||
195 | .type = V4L2_CTRL_TYPE_MENU, | ||
196 | .name = "Flicker Reduction", | ||
197 | .minimum = 0, | ||
198 | .maximum = NUM_FLICKER_CONTROLS-1, | ||
199 | .step = 1, | ||
200 | .default_value = 0, | ||
201 | }, | ||
202 | { | ||
203 | .id = CPIA2_CID_FRAMERATE, | ||
204 | .type = V4L2_CTRL_TYPE_MENU, | ||
205 | .name = "Framerate", | ||
206 | .minimum = 0, | ||
207 | .maximum = NUM_FRAMERATE_CONTROLS-1, | ||
208 | .step = 1, | ||
209 | .default_value = NUM_FRAMERATE_CONTROLS-1, | ||
210 | }, | ||
211 | { | ||
212 | .id = CPIA2_CID_USB_ALT, | ||
213 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
214 | .name = "USB Alternate", | ||
215 | .minimum = USBIF_ISO_1, | ||
216 | .maximum = USBIF_ISO_6, | ||
217 | .step = 1, | ||
218 | .default_value = DEFAULT_ALT, | ||
219 | }, | ||
220 | { | ||
221 | .id = CPIA2_CID_LIGHTS, | ||
222 | .type = V4L2_CTRL_TYPE_MENU, | ||
223 | .name = "Lights", | ||
224 | .minimum = 0, | ||
225 | .maximum = NUM_LIGHTS_CONTROLS-1, | ||
226 | .step = 1, | ||
227 | .default_value = 0, | ||
228 | }, | ||
229 | { | ||
230 | .id = CPIA2_CID_RESET_CAMERA, | ||
231 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
232 | .name = "Reset Camera", | ||
233 | .minimum = 0, | ||
234 | .maximum = 0, | ||
235 | .step = 0, | ||
236 | .default_value = 0, | ||
237 | }, | ||
238 | }; | ||
239 | #define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0])) | ||
240 | |||
241 | |||
242 | /****************************************************************************** | ||
243 | * | ||
244 | * cpia2_open | ||
245 | * | ||
246 | *****************************************************************************/ | ||
247 | static int cpia2_open(struct inode *inode, struct file *file) | ||
248 | { | ||
249 | struct video_device *dev = video_devdata(file); | ||
250 | struct camera_data *cam = video_get_drvdata(dev); | ||
251 | int retval = 0; | ||
252 | |||
253 | if (!cam) { | ||
254 | ERR("Internal error, camera_data not found!\n"); | ||
255 | return -ENODEV; | ||
256 | } | ||
257 | |||
258 | if(down_interruptible(&cam->busy_lock)) | ||
259 | return -ERESTARTSYS; | ||
260 | |||
261 | if(!cam->present) { | ||
262 | retval = -ENODEV; | ||
263 | goto err_return; | ||
264 | } | ||
265 | |||
266 | if (cam->open_count > 0) { | ||
267 | goto skip_init; | ||
268 | } | ||
269 | |||
270 | if (cpia2_allocate_buffers(cam)) { | ||
271 | retval = -ENOMEM; | ||
272 | goto err_return; | ||
273 | } | ||
274 | |||
275 | /* reset the camera */ | ||
276 | if (cpia2_reset_camera(cam) < 0) { | ||
277 | retval = -EIO; | ||
278 | goto err_return; | ||
279 | } | ||
280 | |||
281 | cam->APP_len = 0; | ||
282 | cam->COM_len = 0; | ||
283 | |||
284 | skip_init: | ||
285 | { | ||
286 | struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL); | ||
287 | if(!fh) { | ||
288 | retval = -ENOMEM; | ||
289 | goto err_return; | ||
290 | } | ||
291 | file->private_data = fh; | ||
292 | fh->prio = V4L2_PRIORITY_UNSET; | ||
293 | v4l2_prio_open(&cam->prio, &fh->prio); | ||
294 | fh->mmapped = 0; | ||
295 | } | ||
296 | |||
297 | ++cam->open_count; | ||
298 | |||
299 | cpia2_dbg_dump_registers(cam); | ||
300 | |||
301 | err_return: | ||
302 | up(&cam->busy_lock); | ||
303 | return retval; | ||
304 | } | ||
305 | |||
306 | /****************************************************************************** | ||
307 | * | ||
308 | * cpia2_close | ||
309 | * | ||
310 | *****************************************************************************/ | ||
311 | static int cpia2_close(struct inode *inode, struct file *file) | ||
312 | { | ||
313 | struct video_device *dev = video_devdata(file); | ||
314 | struct camera_data *cam = video_get_drvdata(dev); | ||
315 | struct cpia2_fh *fh = file->private_data; | ||
316 | |||
317 | down(&cam->busy_lock); | ||
318 | |||
319 | if (cam->present && | ||
320 | (cam->open_count == 1 | ||
321 | || fh->prio == V4L2_PRIORITY_RECORD | ||
322 | )) { | ||
323 | cpia2_usb_stream_stop(cam); | ||
324 | |||
325 | if(cam->open_count == 1) { | ||
326 | /* save camera state for later open */ | ||
327 | cpia2_save_camera_state(cam); | ||
328 | |||
329 | cpia2_set_low_power(cam); | ||
330 | cpia2_free_buffers(cam); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | { | ||
335 | if(fh->mmapped) | ||
336 | cam->mmapped = 0; | ||
337 | v4l2_prio_close(&cam->prio,&fh->prio); | ||
338 | file->private_data = NULL; | ||
339 | kfree(fh); | ||
340 | } | ||
341 | |||
342 | if (--cam->open_count == 0) { | ||
343 | cpia2_free_buffers(cam); | ||
344 | if (!cam->present) { | ||
345 | video_unregister_device(dev); | ||
346 | kfree(cam); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | up(&cam->busy_lock); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /****************************************************************************** | ||
356 | * | ||
357 | * cpia2_v4l_read | ||
358 | * | ||
359 | *****************************************************************************/ | ||
360 | static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, | ||
361 | loff_t *off) | ||
362 | { | ||
363 | struct video_device *dev = video_devdata(file); | ||
364 | struct camera_data *cam = video_get_drvdata(dev); | ||
365 | int noblock = file->f_flags&O_NONBLOCK; | ||
366 | |||
367 | struct cpia2_fh *fh = file->private_data; | ||
368 | |||
369 | if(!cam) | ||
370 | return -EINVAL; | ||
371 | |||
372 | /* Priority check */ | ||
373 | if(fh->prio != V4L2_PRIORITY_RECORD) { | ||
374 | return -EBUSY; | ||
375 | } | ||
376 | |||
377 | return cpia2_read(cam, buf, count, noblock); | ||
378 | } | ||
379 | |||
380 | |||
381 | /****************************************************************************** | ||
382 | * | ||
383 | * cpia2_v4l_poll | ||
384 | * | ||
385 | *****************************************************************************/ | ||
386 | static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) | ||
387 | { | ||
388 | struct video_device *dev = video_devdata(filp); | ||
389 | struct camera_data *cam = video_get_drvdata(dev); | ||
390 | |||
391 | struct cpia2_fh *fh = filp->private_data; | ||
392 | |||
393 | if(!cam) | ||
394 | return POLLERR; | ||
395 | |||
396 | /* Priority check */ | ||
397 | if(fh->prio != V4L2_PRIORITY_RECORD) { | ||
398 | return POLLERR; | ||
399 | } | ||
400 | |||
401 | return cpia2_poll(cam, filp, wait); | ||
402 | } | ||
403 | |||
404 | |||
405 | /****************************************************************************** | ||
406 | * | ||
407 | * ioctl_cap_query | ||
408 | * | ||
409 | *****************************************************************************/ | ||
410 | static int ioctl_cap_query(void *arg, struct camera_data *cam) | ||
411 | { | ||
412 | struct video_capability *vc; | ||
413 | int retval = 0; | ||
414 | vc = arg; | ||
415 | |||
416 | if (cam->params.pnp_id.product == 0x151) | ||
417 | strcpy(vc->name, "QX5 Microscope"); | ||
418 | else | ||
419 | strcpy(vc->name, "CPiA2 Camera"); | ||
420 | |||
421 | vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER; | ||
422 | vc->channels = 1; | ||
423 | vc->audios = 0; | ||
424 | vc->minwidth = 176; /* VIDEOSIZE_QCIF */ | ||
425 | vc->minheight = 144; | ||
426 | switch (cam->params.version.sensor_flags) { | ||
427 | case CPIA2_VP_SENSOR_FLAGS_500: | ||
428 | vc->maxwidth = STV_IMAGE_VGA_COLS; | ||
429 | vc->maxheight = STV_IMAGE_VGA_ROWS; | ||
430 | break; | ||
431 | case CPIA2_VP_SENSOR_FLAGS_410: | ||
432 | vc->maxwidth = STV_IMAGE_CIF_COLS; | ||
433 | vc->maxheight = STV_IMAGE_CIF_ROWS; | ||
434 | break; | ||
435 | default: | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | return retval; | ||
440 | } | ||
441 | |||
442 | /****************************************************************************** | ||
443 | * | ||
444 | * ioctl_get_channel | ||
445 | * | ||
446 | *****************************************************************************/ | ||
447 | static int ioctl_get_channel(void *arg) | ||
448 | { | ||
449 | int retval = 0; | ||
450 | struct video_channel *v; | ||
451 | v = arg; | ||
452 | |||
453 | if (v->channel != 0) | ||
454 | return -EINVAL; | ||
455 | |||
456 | v->channel = 0; | ||
457 | strcpy(v->name, "Camera"); | ||
458 | v->tuners = 0; | ||
459 | v->flags = 0; | ||
460 | v->type = VIDEO_TYPE_CAMERA; | ||
461 | v->norm = 0; | ||
462 | |||
463 | return retval; | ||
464 | } | ||
465 | |||
466 | /****************************************************************************** | ||
467 | * | ||
468 | * ioctl_set_channel | ||
469 | * | ||
470 | *****************************************************************************/ | ||
471 | static int ioctl_set_channel(void *arg) | ||
472 | { | ||
473 | struct video_channel *v; | ||
474 | int retval = 0; | ||
475 | v = arg; | ||
476 | |||
477 | if (retval == 0 && v->channel != 0) | ||
478 | retval = -EINVAL; | ||
479 | |||
480 | return retval; | ||
481 | } | ||
482 | |||
483 | /****************************************************************************** | ||
484 | * | ||
485 | * ioctl_set_image_prop | ||
486 | * | ||
487 | *****************************************************************************/ | ||
488 | static int ioctl_set_image_prop(void *arg, struct camera_data *cam) | ||
489 | { | ||
490 | struct video_picture *vp; | ||
491 | int retval = 0; | ||
492 | vp = arg; | ||
493 | |||
494 | /* brightness, color, contrast need no check 0-65535 */ | ||
495 | memcpy(&cam->vp, vp, sizeof(*vp)); | ||
496 | |||
497 | /* update cam->params.colorParams */ | ||
498 | cam->params.color_params.brightness = vp->brightness / 256; | ||
499 | cam->params.color_params.saturation = vp->colour / 256; | ||
500 | cam->params.color_params.contrast = vp->contrast / 256; | ||
501 | |||
502 | DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n", | ||
503 | cam->params.color_params.brightness, | ||
504 | cam->params.color_params.saturation, | ||
505 | cam->params.color_params.contrast); | ||
506 | |||
507 | cpia2_set_color_params(cam); | ||
508 | |||
509 | return retval; | ||
510 | } | ||
511 | |||
512 | static int sync(struct camera_data *cam, int frame_nr) | ||
513 | { | ||
514 | struct framebuf *frame = &cam->buffers[frame_nr]; | ||
515 | |||
516 | while (1) { | ||
517 | if (frame->status == FRAME_READY) | ||
518 | return 0; | ||
519 | |||
520 | if (!cam->streaming) { | ||
521 | frame->status = FRAME_READY; | ||
522 | frame->length = 0; | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | up(&cam->busy_lock); | ||
527 | wait_event_interruptible(cam->wq_stream, | ||
528 | !cam->streaming || | ||
529 | frame->status == FRAME_READY); | ||
530 | down(&cam->busy_lock); | ||
531 | if (signal_pending(current)) | ||
532 | return -ERESTARTSYS; | ||
533 | if(!cam->present) | ||
534 | return -ENOTTY; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | /****************************************************************************** | ||
539 | * | ||
540 | * ioctl_set_window_size | ||
541 | * | ||
542 | *****************************************************************************/ | ||
543 | static int ioctl_set_window_size(void *arg, struct camera_data *cam, | ||
544 | struct cpia2_fh *fh) | ||
545 | { | ||
546 | /* copy_from_user, check validity, copy to internal structure */ | ||
547 | struct video_window *vw; | ||
548 | int frame, err; | ||
549 | vw = arg; | ||
550 | |||
551 | if (vw->clipcount != 0) /* clipping not supported */ | ||
552 | return -EINVAL; | ||
553 | |||
554 | if (vw->clips != NULL) /* clipping not supported */ | ||
555 | return -EINVAL; | ||
556 | |||
557 | /* Ensure that only this process can change the format. */ | ||
558 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | ||
559 | if(err != 0) | ||
560 | return err; | ||
561 | |||
562 | cam->pixelformat = V4L2_PIX_FMT_JPEG; | ||
563 | |||
564 | /* Be sure to supply the Huffman tables, this isn't MJPEG */ | ||
565 | cam->params.compression.inhibit_htables = 0; | ||
566 | |||
567 | /* we set the video window to something smaller or equal to what | ||
568 | * is requested by the user??? | ||
569 | */ | ||
570 | DBG("Requested width = %d, height = %d\n", vw->width, vw->height); | ||
571 | if (vw->width != cam->vw.width || vw->height != cam->vw.height) { | ||
572 | cam->vw.width = vw->width; | ||
573 | cam->vw.height = vw->height; | ||
574 | cam->params.roi.width = vw->width; | ||
575 | cam->params.roi.height = vw->height; | ||
576 | cpia2_set_format(cam); | ||
577 | } | ||
578 | |||
579 | for (frame = 0; frame < cam->num_frames; ++frame) { | ||
580 | if (cam->buffers[frame].status == FRAME_READING) | ||
581 | if ((err = sync(cam, frame)) < 0) | ||
582 | return err; | ||
583 | |||
584 | cam->buffers[frame].status = FRAME_EMPTY; | ||
585 | } | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | /****************************************************************************** | ||
591 | * | ||
592 | * ioctl_get_mbuf | ||
593 | * | ||
594 | *****************************************************************************/ | ||
595 | static int ioctl_get_mbuf(void *arg, struct camera_data *cam) | ||
596 | { | ||
597 | struct video_mbuf *vm; | ||
598 | int i; | ||
599 | vm = arg; | ||
600 | |||
601 | memset(vm, 0, sizeof(*vm)); | ||
602 | vm->size = cam->frame_size*cam->num_frames; | ||
603 | vm->frames = cam->num_frames; | ||
604 | for (i = 0; i < cam->num_frames; i++) | ||
605 | vm->offsets[i] = cam->frame_size * i; | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | /****************************************************************************** | ||
611 | * | ||
612 | * ioctl_mcapture | ||
613 | * | ||
614 | *****************************************************************************/ | ||
615 | static int ioctl_mcapture(void *arg, struct camera_data *cam, | ||
616 | struct cpia2_fh *fh) | ||
617 | { | ||
618 | struct video_mmap *vm; | ||
619 | int video_size, err; | ||
620 | vm = arg; | ||
621 | |||
622 | if (vm->frame < 0 || vm->frame >= cam->num_frames) | ||
623 | return -EINVAL; | ||
624 | |||
625 | /* set video size */ | ||
626 | video_size = cpia2_match_video_size(vm->width, vm->height); | ||
627 | if (cam->video_size < 0) { | ||
628 | return -EINVAL; | ||
629 | } | ||
630 | |||
631 | /* Ensure that only this process can change the format. */ | ||
632 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | ||
633 | if(err != 0) | ||
634 | return err; | ||
635 | |||
636 | if (video_size != cam->video_size) { | ||
637 | cam->video_size = video_size; | ||
638 | cam->params.roi.width = vm->width; | ||
639 | cam->params.roi.height = vm->height; | ||
640 | cpia2_set_format(cam); | ||
641 | } | ||
642 | |||
643 | if (cam->buffers[vm->frame].status == FRAME_READING) | ||
644 | if ((err=sync(cam, vm->frame)) < 0) | ||
645 | return err; | ||
646 | |||
647 | cam->buffers[vm->frame].status = FRAME_EMPTY; | ||
648 | |||
649 | return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode); | ||
650 | } | ||
651 | |||
652 | /****************************************************************************** | ||
653 | * | ||
654 | * ioctl_sync | ||
655 | * | ||
656 | *****************************************************************************/ | ||
657 | static int ioctl_sync(void *arg, struct camera_data *cam) | ||
658 | { | ||
659 | int frame; | ||
660 | |||
661 | frame = *(int*)arg; | ||
662 | |||
663 | if (frame < 0 || frame >= cam->num_frames) | ||
664 | return -EINVAL; | ||
665 | |||
666 | return sync(cam, frame); | ||
667 | } | ||
668 | |||
669 | |||
670 | /****************************************************************************** | ||
671 | * | ||
672 | * ioctl_set_gpio | ||
673 | * | ||
674 | *****************************************************************************/ | ||
675 | |||
676 | static int ioctl_set_gpio(void *arg, struct camera_data *cam) | ||
677 | { | ||
678 | __u32 gpio_val; | ||
679 | |||
680 | gpio_val = *(__u32*) arg; | ||
681 | |||
682 | if (gpio_val &~ 0xFFU) | ||
683 | return -EINVAL; | ||
684 | |||
685 | return cpia2_set_gpio(cam, (unsigned char)gpio_val); | ||
686 | } | ||
687 | |||
688 | /****************************************************************************** | ||
689 | * | ||
690 | * ioctl_querycap | ||
691 | * | ||
692 | * V4L2 device capabilities | ||
693 | * | ||
694 | *****************************************************************************/ | ||
695 | |||
696 | static int ioctl_querycap(void *arg, struct camera_data *cam) | ||
697 | { | ||
698 | struct v4l2_capability *vc = arg; | ||
699 | |||
700 | memset(vc, 0, sizeof(*vc)); | ||
701 | strcpy(vc->driver, "cpia2"); | ||
702 | |||
703 | if (cam->params.pnp_id.product == 0x151) | ||
704 | strcpy(vc->card, "QX5 Microscope"); | ||
705 | else | ||
706 | strcpy(vc->card, "CPiA2 Camera"); | ||
707 | switch (cam->params.pnp_id.device_type) { | ||
708 | case DEVICE_STV_672: | ||
709 | strcat(vc->card, " (672/"); | ||
710 | break; | ||
711 | case DEVICE_STV_676: | ||
712 | strcat(vc->card, " (676/"); | ||
713 | break; | ||
714 | default: | ||
715 | strcat(vc->card, " (???/"); | ||
716 | break; | ||
717 | } | ||
718 | switch (cam->params.version.sensor_flags) { | ||
719 | case CPIA2_VP_SENSOR_FLAGS_404: | ||
720 | strcat(vc->card, "404)"); | ||
721 | break; | ||
722 | case CPIA2_VP_SENSOR_FLAGS_407: | ||
723 | strcat(vc->card, "407)"); | ||
724 | break; | ||
725 | case CPIA2_VP_SENSOR_FLAGS_409: | ||
726 | strcat(vc->card, "409)"); | ||
727 | break; | ||
728 | case CPIA2_VP_SENSOR_FLAGS_410: | ||
729 | strcat(vc->card, "410)"); | ||
730 | break; | ||
731 | case CPIA2_VP_SENSOR_FLAGS_500: | ||
732 | strcat(vc->card, "500)"); | ||
733 | break; | ||
734 | default: | ||
735 | strcat(vc->card, "???)"); | ||
736 | break; | ||
737 | } | ||
738 | |||
739 | if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) | ||
740 | memset(vc->bus_info,0, sizeof(vc->bus_info)); | ||
741 | |||
742 | vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, | ||
743 | CPIA2_PATCH_VER); | ||
744 | |||
745 | vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
746 | V4L2_CAP_READWRITE | | ||
747 | V4L2_CAP_STREAMING; | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | /****************************************************************************** | ||
753 | * | ||
754 | * ioctl_input | ||
755 | * | ||
756 | * V4L2 input get/set/enumerate | ||
757 | * | ||
758 | *****************************************************************************/ | ||
759 | |||
760 | static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam) | ||
761 | { | ||
762 | struct v4l2_input *i = arg; | ||
763 | |||
764 | if(ioclt_nr != VIDIOC_G_INPUT) { | ||
765 | if (i->index != 0) | ||
766 | return -EINVAL; | ||
767 | } | ||
768 | |||
769 | memset(i, 0, sizeof(*i)); | ||
770 | strcpy(i->name, "Camera"); | ||
771 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | /****************************************************************************** | ||
777 | * | ||
778 | * ioctl_enum_fmt | ||
779 | * | ||
780 | * V4L2 format enumerate | ||
781 | * | ||
782 | *****************************************************************************/ | ||
783 | |||
784 | static int ioctl_enum_fmt(void *arg,struct camera_data *cam) | ||
785 | { | ||
786 | struct v4l2_fmtdesc *f = arg; | ||
787 | int index = f->index; | ||
788 | |||
789 | if (index < 0 || index > 1) | ||
790 | return -EINVAL; | ||
791 | |||
792 | memset(f, 0, sizeof(*f)); | ||
793 | f->index = index; | ||
794 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
795 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
796 | switch(index) { | ||
797 | case 0: | ||
798 | strcpy(f->description, "MJPEG"); | ||
799 | f->pixelformat = V4L2_PIX_FMT_MJPEG; | ||
800 | break; | ||
801 | case 1: | ||
802 | strcpy(f->description, "JPEG"); | ||
803 | f->pixelformat = V4L2_PIX_FMT_JPEG; | ||
804 | break; | ||
805 | default: | ||
806 | return -EINVAL; | ||
807 | } | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | /****************************************************************************** | ||
813 | * | ||
814 | * ioctl_try_fmt | ||
815 | * | ||
816 | * V4L2 format try | ||
817 | * | ||
818 | *****************************************************************************/ | ||
819 | |||
820 | static int ioctl_try_fmt(void *arg,struct camera_data *cam) | ||
821 | { | ||
822 | struct v4l2_format *f = arg; | ||
823 | |||
824 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
825 | return -EINVAL; | ||
826 | |||
827 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && | ||
828 | f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | ||
829 | return -EINVAL; | ||
830 | |||
831 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
832 | f->fmt.pix.bytesperline = 0; | ||
833 | f->fmt.pix.sizeimage = cam->frame_size; | ||
834 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | ||
835 | f->fmt.pix.priv = 0; | ||
836 | |||
837 | switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { | ||
838 | case VIDEOSIZE_VGA: | ||
839 | f->fmt.pix.width = 640; | ||
840 | f->fmt.pix.height = 480; | ||
841 | break; | ||
842 | case VIDEOSIZE_CIF: | ||
843 | f->fmt.pix.width = 352; | ||
844 | f->fmt.pix.height = 288; | ||
845 | break; | ||
846 | case VIDEOSIZE_QVGA: | ||
847 | f->fmt.pix.width = 320; | ||
848 | f->fmt.pix.height = 240; | ||
849 | break; | ||
850 | case VIDEOSIZE_288_216: | ||
851 | f->fmt.pix.width = 288; | ||
852 | f->fmt.pix.height = 216; | ||
853 | break; | ||
854 | case VIDEOSIZE_256_192: | ||
855 | f->fmt.pix.width = 256; | ||
856 | f->fmt.pix.height = 192; | ||
857 | break; | ||
858 | case VIDEOSIZE_224_168: | ||
859 | f->fmt.pix.width = 224; | ||
860 | f->fmt.pix.height = 168; | ||
861 | break; | ||
862 | case VIDEOSIZE_192_144: | ||
863 | f->fmt.pix.width = 192; | ||
864 | f->fmt.pix.height = 144; | ||
865 | break; | ||
866 | case VIDEOSIZE_QCIF: | ||
867 | default: | ||
868 | f->fmt.pix.width = 176; | ||
869 | f->fmt.pix.height = 144; | ||
870 | break; | ||
871 | } | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | /****************************************************************************** | ||
877 | * | ||
878 | * ioctl_set_fmt | ||
879 | * | ||
880 | * V4L2 format set | ||
881 | * | ||
882 | *****************************************************************************/ | ||
883 | |||
884 | static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh) | ||
885 | { | ||
886 | struct v4l2_format *f = arg; | ||
887 | int err, frame; | ||
888 | |||
889 | err = ioctl_try_fmt(arg, cam); | ||
890 | if(err != 0) | ||
891 | return err; | ||
892 | |||
893 | /* Ensure that only this process can change the format. */ | ||
894 | err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); | ||
895 | if(err != 0) { | ||
896 | return err; | ||
897 | } | ||
898 | |||
899 | cam->pixelformat = f->fmt.pix.pixelformat; | ||
900 | |||
901 | /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle | ||
902 | * the missing Huffman table properly. */ | ||
903 | cam->params.compression.inhibit_htables = 0; | ||
904 | /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ | ||
905 | |||
906 | /* we set the video window to something smaller or equal to what | ||
907 | * is requested by the user??? | ||
908 | */ | ||
909 | DBG("Requested width = %d, height = %d\n", | ||
910 | f->fmt.pix.width, f->fmt.pix.height); | ||
911 | if (f->fmt.pix.width != cam->vw.width || | ||
912 | f->fmt.pix.height != cam->vw.height) { | ||
913 | cam->vw.width = f->fmt.pix.width; | ||
914 | cam->vw.height = f->fmt.pix.height; | ||
915 | cam->params.roi.width = f->fmt.pix.width; | ||
916 | cam->params.roi.height = f->fmt.pix.height; | ||
917 | cpia2_set_format(cam); | ||
918 | } | ||
919 | |||
920 | for (frame = 0; frame < cam->num_frames; ++frame) { | ||
921 | if (cam->buffers[frame].status == FRAME_READING) | ||
922 | if ((err = sync(cam, frame)) < 0) | ||
923 | return err; | ||
924 | |||
925 | cam->buffers[frame].status = FRAME_EMPTY; | ||
926 | } | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /****************************************************************************** | ||
932 | * | ||
933 | * ioctl_get_fmt | ||
934 | * | ||
935 | * V4L2 format get | ||
936 | * | ||
937 | *****************************************************************************/ | ||
938 | |||
939 | static int ioctl_get_fmt(void *arg,struct camera_data *cam) | ||
940 | { | ||
941 | struct v4l2_format *f = arg; | ||
942 | |||
943 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
944 | return -EINVAL; | ||
945 | |||
946 | f->fmt.pix.width = cam->vw.width; | ||
947 | f->fmt.pix.height = cam->vw.height; | ||
948 | f->fmt.pix.pixelformat = cam->pixelformat; | ||
949 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
950 | f->fmt.pix.bytesperline = 0; | ||
951 | f->fmt.pix.sizeimage = cam->frame_size; | ||
952 | f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; | ||
953 | f->fmt.pix.priv = 0; | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | /****************************************************************************** | ||
959 | * | ||
960 | * ioctl_cropcap | ||
961 | * | ||
962 | * V4L2 query cropping capabilities | ||
963 | * NOTE: cropping is currently disabled | ||
964 | * | ||
965 | *****************************************************************************/ | ||
966 | |||
967 | static int ioctl_cropcap(void *arg,struct camera_data *cam) | ||
968 | { | ||
969 | struct v4l2_cropcap *c = arg; | ||
970 | |||
971 | if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
972 | return -EINVAL; | ||
973 | |||
974 | c->bounds.left = 0; | ||
975 | c->bounds.top = 0; | ||
976 | c->bounds.width = cam->vw.width; | ||
977 | c->bounds.height = cam->vw.height; | ||
978 | c->defrect.left = 0; | ||
979 | c->defrect.top = 0; | ||
980 | c->defrect.width = cam->vw.width; | ||
981 | c->defrect.height = cam->vw.height; | ||
982 | c->pixelaspect.numerator = 1; | ||
983 | c->pixelaspect.denominator = 1; | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | /****************************************************************************** | ||
989 | * | ||
990 | * ioctl_queryctrl | ||
991 | * | ||
992 | * V4L2 query possible control variables | ||
993 | * | ||
994 | *****************************************************************************/ | ||
995 | |||
996 | static int ioctl_queryctrl(void *arg,struct camera_data *cam) | ||
997 | { | ||
998 | struct v4l2_queryctrl *c = arg; | ||
999 | int i; | ||
1000 | |||
1001 | for(i=0; i<NUM_CONTROLS; ++i) { | ||
1002 | if(c->id == controls[i].id) { | ||
1003 | memcpy(c, controls+i, sizeof(*c)); | ||
1004 | break; | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | if(i == NUM_CONTROLS) | ||
1009 | return -EINVAL; | ||
1010 | |||
1011 | /* Some devices have additional limitations */ | ||
1012 | switch(c->id) { | ||
1013 | case V4L2_CID_BRIGHTNESS: | ||
1014 | /*** | ||
1015 | * Don't let the register be set to zero - bug in VP4 | ||
1016 | * flash of full brightness | ||
1017 | ***/ | ||
1018 | if (cam->params.pnp_id.device_type == DEVICE_STV_672) | ||
1019 | c->minimum = 1; | ||
1020 | break; | ||
1021 | case V4L2_CID_VFLIP: | ||
1022 | // VP5 Only | ||
1023 | if(cam->params.pnp_id.device_type == DEVICE_STV_672) | ||
1024 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
1025 | break; | ||
1026 | case CPIA2_CID_FRAMERATE: | ||
1027 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && | ||
1028 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ | ||
1029 | // Maximum 15fps | ||
1030 | int i; | ||
1031 | for(i=0; i<c->maximum; ++i) { | ||
1032 | if(framerate_controls[i].value == | ||
1033 | CPIA2_VP_FRAMERATE_15) { | ||
1034 | c->maximum = i; | ||
1035 | c->default_value = i; | ||
1036 | } | ||
1037 | } | ||
1038 | } | ||
1039 | break; | ||
1040 | case CPIA2_CID_FLICKER_MODE: | ||
1041 | // Flicker control only valid for 672. | ||
1042 | if(cam->params.pnp_id.device_type != DEVICE_STV_672) | ||
1043 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
1044 | break; | ||
1045 | case CPIA2_CID_LIGHTS: | ||
1046 | // Light control only valid for the QX5 Microscope. | ||
1047 | if(cam->params.pnp_id.product != 0x151) | ||
1048 | c->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
1049 | break; | ||
1050 | default: | ||
1051 | break; | ||
1052 | } | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | /****************************************************************************** | ||
1058 | * | ||
1059 | * ioctl_querymenu | ||
1060 | * | ||
1061 | * V4L2 query possible control variables | ||
1062 | * | ||
1063 | *****************************************************************************/ | ||
1064 | |||
1065 | static int ioctl_querymenu(void *arg,struct camera_data *cam) | ||
1066 | { | ||
1067 | struct v4l2_querymenu *m = arg; | ||
1068 | |||
1069 | memset(m->name, 0, sizeof(m->name)); | ||
1070 | m->reserved = 0; | ||
1071 | |||
1072 | switch(m->id) { | ||
1073 | case CPIA2_CID_FLICKER_MODE: | ||
1074 | if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS) | ||
1075 | return -EINVAL; | ||
1076 | |||
1077 | strcpy(m->name, flicker_controls[m->index].name); | ||
1078 | break; | ||
1079 | case CPIA2_CID_FRAMERATE: | ||
1080 | { | ||
1081 | int maximum = NUM_FRAMERATE_CONTROLS - 1; | ||
1082 | if(cam->params.pnp_id.device_type == DEVICE_STV_672 && | ||
1083 | cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ | ||
1084 | // Maximum 15fps | ||
1085 | int i; | ||
1086 | for(i=0; i<maximum; ++i) { | ||
1087 | if(framerate_controls[i].value == | ||
1088 | CPIA2_VP_FRAMERATE_15) | ||
1089 | maximum = i; | ||
1090 | } | ||
1091 | } | ||
1092 | if(m->index < 0 || m->index > maximum) | ||
1093 | return -EINVAL; | ||
1094 | |||
1095 | strcpy(m->name, framerate_controls[m->index].name); | ||
1096 | break; | ||
1097 | } | ||
1098 | case CPIA2_CID_LIGHTS: | ||
1099 | if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS) | ||
1100 | return -EINVAL; | ||
1101 | |||
1102 | strcpy(m->name, lights_controls[m->index].name); | ||
1103 | break; | ||
1104 | default: | ||
1105 | return -EINVAL; | ||
1106 | } | ||
1107 | |||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | /****************************************************************************** | ||
1112 | * | ||
1113 | * ioctl_g_ctrl | ||
1114 | * | ||
1115 | * V4L2 get the value of a control variable | ||
1116 | * | ||
1117 | *****************************************************************************/ | ||
1118 | |||
1119 | static int ioctl_g_ctrl(void *arg,struct camera_data *cam) | ||
1120 | { | ||
1121 | struct v4l2_control *c = arg; | ||
1122 | |||
1123 | switch(c->id) { | ||
1124 | case V4L2_CID_BRIGHTNESS: | ||
1125 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, | ||
1126 | TRANSFER_READ, 0); | ||
1127 | c->value = cam->params.color_params.brightness; | ||
1128 | break; | ||
1129 | case V4L2_CID_CONTRAST: | ||
1130 | cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, | ||
1131 | TRANSFER_READ, 0); | ||
1132 | c->value = cam->params.color_params.contrast; | ||
1133 | break; | ||
1134 | case V4L2_CID_SATURATION: | ||
1135 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, | ||
1136 | TRANSFER_READ, 0); | ||
1137 | c->value = cam->params.color_params.saturation; | ||
1138 | break; | ||
1139 | case V4L2_CID_HFLIP: | ||
1140 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, | ||
1141 | TRANSFER_READ, 0); | ||
1142 | c->value = (cam->params.vp_params.user_effects & | ||
1143 | CPIA2_VP_USER_EFFECTS_MIRROR) != 0; | ||
1144 | break; | ||
1145 | case V4L2_CID_VFLIP: | ||
1146 | cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, | ||
1147 | TRANSFER_READ, 0); | ||
1148 | c->value = (cam->params.vp_params.user_effects & | ||
1149 | CPIA2_VP_USER_EFFECTS_FLIP) != 0; | ||
1150 | break; | ||
1151 | case CPIA2_CID_TARGET_KB: | ||
1152 | c->value = cam->params.vc_params.target_kb; | ||
1153 | break; | ||
1154 | case CPIA2_CID_GPIO: | ||
1155 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, | ||
1156 | TRANSFER_READ, 0); | ||
1157 | c->value = cam->params.vp_params.gpio_data; | ||
1158 | break; | ||
1159 | case CPIA2_CID_FLICKER_MODE: | ||
1160 | { | ||
1161 | int i, mode; | ||
1162 | cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, | ||
1163 | TRANSFER_READ, 0); | ||
1164 | if(cam->params.flicker_control.cam_register & | ||
1165 | CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { | ||
1166 | mode = NEVER_FLICKER; | ||
1167 | } else { | ||
1168 | if(cam->params.flicker_control.cam_register & | ||
1169 | CPIA2_VP_FLICKER_MODES_50HZ) { | ||
1170 | mode = FLICKER_50; | ||
1171 | } else { | ||
1172 | mode = FLICKER_60; | ||
1173 | } | ||
1174 | } | ||
1175 | for(i=0; i<NUM_FLICKER_CONTROLS; i++) { | ||
1176 | if(flicker_controls[i].value == mode) { | ||
1177 | c->value = i; | ||
1178 | break; | ||
1179 | } | ||
1180 | } | ||
1181 | if(i == NUM_FLICKER_CONTROLS) | ||
1182 | return -EINVAL; | ||
1183 | break; | ||
1184 | } | ||
1185 | case CPIA2_CID_FRAMERATE: | ||
1186 | { | ||
1187 | int maximum = NUM_FRAMERATE_CONTROLS - 1; | ||
1188 | int i; | ||
1189 | for(i=0; i<= maximum; i++) { | ||
1190 | if(cam->params.vp_params.frame_rate == | ||
1191 | framerate_controls[i].value) | ||
1192 | break; | ||
1193 | } | ||
1194 | if(i > maximum) | ||
1195 | return -EINVAL; | ||
1196 | c->value = i; | ||
1197 | break; | ||
1198 | } | ||
1199 | case CPIA2_CID_USB_ALT: | ||
1200 | c->value = cam->params.camera_state.stream_mode; | ||
1201 | break; | ||
1202 | case CPIA2_CID_LIGHTS: | ||
1203 | { | ||
1204 | int i; | ||
1205 | cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, | ||
1206 | TRANSFER_READ, 0); | ||
1207 | for(i=0; i<NUM_LIGHTS_CONTROLS; i++) { | ||
1208 | if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) == | ||
1209 | lights_controls[i].value) { | ||
1210 | break; | ||
1211 | } | ||
1212 | } | ||
1213 | if(i == NUM_LIGHTS_CONTROLS) | ||
1214 | return -EINVAL; | ||
1215 | c->value = i; | ||
1216 | break; | ||
1217 | } | ||
1218 | case CPIA2_CID_RESET_CAMERA: | ||
1219 | return -EINVAL; | ||
1220 | default: | ||
1221 | return -EINVAL; | ||
1222 | } | ||
1223 | |||
1224 | DBG("Get control id:%d, value:%d\n", c->id, c->value); | ||
1225 | |||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | /****************************************************************************** | ||
1230 | * | ||
1231 | * ioctl_s_ctrl | ||
1232 | * | ||
1233 | * V4L2 set the value of a control variable | ||
1234 | * | ||
1235 | *****************************************************************************/ | ||
1236 | |||
1237 | static int ioctl_s_ctrl(void *arg,struct camera_data *cam) | ||
1238 | { | ||
1239 | struct v4l2_control *c = arg; | ||
1240 | int i; | ||
1241 | int retval = 0; | ||
1242 | |||
1243 | DBG("Set control id:%d, value:%d\n", c->id, c->value); | ||
1244 | |||
1245 | /* Check that the value is in range */ | ||
1246 | for(i=0; i<NUM_CONTROLS; i++) { | ||
1247 | if(c->id == controls[i].id) { | ||
1248 | if(c->value < controls[i].minimum || | ||
1249 | c->value > controls[i].maximum) { | ||
1250 | return -EINVAL; | ||
1251 | } | ||
1252 | break; | ||
1253 | } | ||
1254 | } | ||
1255 | if(i == NUM_CONTROLS) | ||
1256 | return -EINVAL; | ||
1257 | |||
1258 | switch(c->id) { | ||
1259 | case V4L2_CID_BRIGHTNESS: | ||
1260 | cpia2_set_brightness(cam, c->value); | ||
1261 | break; | ||
1262 | case V4L2_CID_CONTRAST: | ||
1263 | cpia2_set_contrast(cam, c->value); | ||
1264 | break; | ||
1265 | case V4L2_CID_SATURATION: | ||
1266 | cpia2_set_saturation(cam, c->value); | ||
1267 | break; | ||
1268 | case V4L2_CID_HFLIP: | ||
1269 | cpia2_set_property_mirror(cam, c->value); | ||
1270 | break; | ||
1271 | case V4L2_CID_VFLIP: | ||
1272 | cpia2_set_property_flip(cam, c->value); | ||
1273 | break; | ||
1274 | case CPIA2_CID_TARGET_KB: | ||
1275 | retval = cpia2_set_target_kb(cam, c->value); | ||
1276 | break; | ||
1277 | case CPIA2_CID_GPIO: | ||
1278 | retval = cpia2_set_gpio(cam, c->value); | ||
1279 | break; | ||
1280 | case CPIA2_CID_FLICKER_MODE: | ||
1281 | retval = cpia2_set_flicker_mode(cam, | ||
1282 | flicker_controls[c->value].value); | ||
1283 | break; | ||
1284 | case CPIA2_CID_FRAMERATE: | ||
1285 | retval = cpia2_set_fps(cam, framerate_controls[c->value].value); | ||
1286 | break; | ||
1287 | case CPIA2_CID_USB_ALT: | ||
1288 | retval = cpia2_usb_change_streaming_alternate(cam, c->value); | ||
1289 | break; | ||
1290 | case CPIA2_CID_LIGHTS: | ||
1291 | retval = cpia2_set_gpio(cam, lights_controls[c->value].value); | ||
1292 | break; | ||
1293 | case CPIA2_CID_RESET_CAMERA: | ||
1294 | cpia2_usb_stream_pause(cam); | ||
1295 | cpia2_reset_camera(cam); | ||
1296 | cpia2_usb_stream_resume(cam); | ||
1297 | break; | ||
1298 | default: | ||
1299 | retval = -EINVAL; | ||
1300 | } | ||
1301 | |||
1302 | return retval; | ||
1303 | } | ||
1304 | |||
1305 | /****************************************************************************** | ||
1306 | * | ||
1307 | * ioctl_g_jpegcomp | ||
1308 | * | ||
1309 | * V4L2 get the JPEG compression parameters | ||
1310 | * | ||
1311 | *****************************************************************************/ | ||
1312 | |||
1313 | static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam) | ||
1314 | { | ||
1315 | struct v4l2_jpegcompression *parms = arg; | ||
1316 | |||
1317 | memset(parms, 0, sizeof(*parms)); | ||
1318 | |||
1319 | parms->quality = 80; // TODO: Can this be made meaningful? | ||
1320 | |||
1321 | parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; | ||
1322 | if(!cam->params.compression.inhibit_htables) { | ||
1323 | parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; | ||
1324 | } | ||
1325 | |||
1326 | parms->APPn = cam->APPn; | ||
1327 | parms->APP_len = cam->APP_len; | ||
1328 | if(cam->APP_len > 0) { | ||
1329 | memcpy(parms->APP_data, cam->APP_data, cam->APP_len); | ||
1330 | parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; | ||
1331 | } | ||
1332 | |||
1333 | parms->COM_len = cam->COM_len; | ||
1334 | if(cam->COM_len > 0) { | ||
1335 | memcpy(parms->COM_data, cam->COM_data, cam->COM_len); | ||
1336 | parms->jpeg_markers |= JPEG_MARKER_COM; | ||
1337 | } | ||
1338 | |||
1339 | DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", | ||
1340 | parms->APP_len, parms->COM_len); | ||
1341 | |||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | /****************************************************************************** | ||
1346 | * | ||
1347 | * ioctl_s_jpegcomp | ||
1348 | * | ||
1349 | * V4L2 set the JPEG compression parameters | ||
1350 | * NOTE: quality and some jpeg_markers are ignored. | ||
1351 | * | ||
1352 | *****************************************************************************/ | ||
1353 | |||
1354 | static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam) | ||
1355 | { | ||
1356 | struct v4l2_jpegcompression *parms = arg; | ||
1357 | |||
1358 | DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", | ||
1359 | parms->APP_len, parms->COM_len); | ||
1360 | |||
1361 | cam->params.compression.inhibit_htables = | ||
1362 | !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); | ||
1363 | |||
1364 | if(parms->APP_len != 0) { | ||
1365 | if(parms->APP_len > 0 && | ||
1366 | parms->APP_len <= sizeof(cam->APP_data) && | ||
1367 | parms->APPn >= 0 && parms->APPn <= 15) { | ||
1368 | cam->APPn = parms->APPn; | ||
1369 | cam->APP_len = parms->APP_len; | ||
1370 | memcpy(cam->APP_data, parms->APP_data, parms->APP_len); | ||
1371 | } else { | ||
1372 | LOG("Bad APPn Params n=%d len=%d\n", | ||
1373 | parms->APPn, parms->APP_len); | ||
1374 | return -EINVAL; | ||
1375 | } | ||
1376 | } else { | ||
1377 | cam->APP_len = 0; | ||
1378 | } | ||
1379 | |||
1380 | if(parms->COM_len != 0) { | ||
1381 | if(parms->COM_len > 0 && | ||
1382 | parms->COM_len <= sizeof(cam->COM_data)) { | ||
1383 | cam->COM_len = parms->COM_len; | ||
1384 | memcpy(cam->COM_data, parms->COM_data, parms->COM_len); | ||
1385 | } else { | ||
1386 | LOG("Bad COM_len=%d\n", parms->COM_len); | ||
1387 | return -EINVAL; | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | /****************************************************************************** | ||
1395 | * | ||
1396 | * ioctl_reqbufs | ||
1397 | * | ||
1398 | * V4L2 Initiate memory mapping. | ||
1399 | * NOTE: The user's request is ignored. For now the buffers are fixed. | ||
1400 | * | ||
1401 | *****************************************************************************/ | ||
1402 | |||
1403 | static int ioctl_reqbufs(void *arg,struct camera_data *cam) | ||
1404 | { | ||
1405 | struct v4l2_requestbuffers *req = arg; | ||
1406 | |||
1407 | if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1408 | req->memory != V4L2_MEMORY_MMAP) | ||
1409 | return -EINVAL; | ||
1410 | |||
1411 | DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); | ||
1412 | req->count = cam->num_frames; | ||
1413 | memset(&req->reserved, 0, sizeof(req->reserved)); | ||
1414 | |||
1415 | return 0; | ||
1416 | } | ||
1417 | |||
1418 | /****************************************************************************** | ||
1419 | * | ||
1420 | * ioctl_querybuf | ||
1421 | * | ||
1422 | * V4L2 Query memory buffer status. | ||
1423 | * | ||
1424 | *****************************************************************************/ | ||
1425 | |||
1426 | static int ioctl_querybuf(void *arg,struct camera_data *cam) | ||
1427 | { | ||
1428 | struct v4l2_buffer *buf = arg; | ||
1429 | |||
1430 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1431 | buf->index > cam->num_frames) | ||
1432 | return -EINVAL; | ||
1433 | |||
1434 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | ||
1435 | buf->length = cam->frame_size; | ||
1436 | |||
1437 | buf->memory = V4L2_MEMORY_MMAP; | ||
1438 | |||
1439 | if(cam->mmapped) | ||
1440 | buf->flags = V4L2_BUF_FLAG_MAPPED; | ||
1441 | else | ||
1442 | buf->flags = 0; | ||
1443 | |||
1444 | switch (cam->buffers[buf->index].status) { | ||
1445 | case FRAME_EMPTY: | ||
1446 | case FRAME_ERROR: | ||
1447 | case FRAME_READING: | ||
1448 | buf->bytesused = 0; | ||
1449 | buf->flags = V4L2_BUF_FLAG_QUEUED; | ||
1450 | break; | ||
1451 | case FRAME_READY: | ||
1452 | buf->bytesused = cam->buffers[buf->index].length; | ||
1453 | buf->timestamp = cam->buffers[buf->index].timestamp; | ||
1454 | buf->sequence = cam->buffers[buf->index].seq; | ||
1455 | buf->flags = V4L2_BUF_FLAG_DONE; | ||
1456 | break; | ||
1457 | } | ||
1458 | |||
1459 | DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", | ||
1460 | buf->index, buf->m.offset, buf->flags, buf->sequence, | ||
1461 | buf->bytesused); | ||
1462 | |||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | /****************************************************************************** | ||
1467 | * | ||
1468 | * ioctl_qbuf | ||
1469 | * | ||
1470 | * V4L2 User is freeing buffer | ||
1471 | * | ||
1472 | *****************************************************************************/ | ||
1473 | |||
1474 | static int ioctl_qbuf(void *arg,struct camera_data *cam) | ||
1475 | { | ||
1476 | struct v4l2_buffer *buf = arg; | ||
1477 | |||
1478 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1479 | buf->memory != V4L2_MEMORY_MMAP || | ||
1480 | buf->index > cam->num_frames) | ||
1481 | return -EINVAL; | ||
1482 | |||
1483 | DBG("QBUF #%d\n", buf->index); | ||
1484 | |||
1485 | if(cam->buffers[buf->index].status == FRAME_READY) | ||
1486 | cam->buffers[buf->index].status = FRAME_EMPTY; | ||
1487 | |||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | /****************************************************************************** | ||
1492 | * | ||
1493 | * find_earliest_filled_buffer | ||
1494 | * | ||
1495 | * Helper for ioctl_dqbuf. Find the next ready buffer. | ||
1496 | * | ||
1497 | *****************************************************************************/ | ||
1498 | |||
1499 | static int find_earliest_filled_buffer(struct camera_data *cam) | ||
1500 | { | ||
1501 | int i; | ||
1502 | int found = -1; | ||
1503 | for (i=0; i<cam->num_frames; i++) { | ||
1504 | if(cam->buffers[i].status == FRAME_READY) { | ||
1505 | if(found < 0) { | ||
1506 | found = i; | ||
1507 | } else { | ||
1508 | /* find which buffer is earlier */ | ||
1509 | struct timeval *tv1, *tv2; | ||
1510 | tv1 = &cam->buffers[i].timestamp; | ||
1511 | tv2 = &cam->buffers[found].timestamp; | ||
1512 | if(tv1->tv_sec < tv2->tv_sec || | ||
1513 | (tv1->tv_sec == tv2->tv_sec && | ||
1514 | tv1->tv_usec < tv2->tv_usec)) | ||
1515 | found = i; | ||
1516 | } | ||
1517 | } | ||
1518 | } | ||
1519 | return found; | ||
1520 | } | ||
1521 | |||
1522 | /****************************************************************************** | ||
1523 | * | ||
1524 | * ioctl_dqbuf | ||
1525 | * | ||
1526 | * V4L2 User is asking for a filled buffer. | ||
1527 | * | ||
1528 | *****************************************************************************/ | ||
1529 | |||
1530 | static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) | ||
1531 | { | ||
1532 | struct v4l2_buffer *buf = arg; | ||
1533 | int frame; | ||
1534 | |||
1535 | if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1536 | buf->memory != V4L2_MEMORY_MMAP) | ||
1537 | return -EINVAL; | ||
1538 | |||
1539 | frame = find_earliest_filled_buffer(cam); | ||
1540 | |||
1541 | if(frame < 0 && file->f_flags&O_NONBLOCK) | ||
1542 | return -EAGAIN; | ||
1543 | |||
1544 | if(frame < 0) { | ||
1545 | /* Wait for a frame to become available */ | ||
1546 | struct framebuf *cb=cam->curbuff; | ||
1547 | up(&cam->busy_lock); | ||
1548 | wait_event_interruptible(cam->wq_stream, | ||
1549 | !cam->present || | ||
1550 | (cb=cam->curbuff)->status == FRAME_READY); | ||
1551 | down(&cam->busy_lock); | ||
1552 | if (signal_pending(current)) | ||
1553 | return -ERESTARTSYS; | ||
1554 | if(!cam->present) | ||
1555 | return -ENOTTY; | ||
1556 | frame = cb->num; | ||
1557 | } | ||
1558 | |||
1559 | |||
1560 | buf->index = frame; | ||
1561 | buf->bytesused = cam->buffers[buf->index].length; | ||
1562 | buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; | ||
1563 | buf->field = V4L2_FIELD_NONE; | ||
1564 | buf->timestamp = cam->buffers[buf->index].timestamp; | ||
1565 | buf->sequence = cam->buffers[buf->index].seq; | ||
1566 | buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; | ||
1567 | buf->length = cam->frame_size; | ||
1568 | buf->input = 0; | ||
1569 | buf->reserved = 0; | ||
1570 | memset(&buf->timecode, 0, sizeof(buf->timecode)); | ||
1571 | |||
1572 | DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, | ||
1573 | cam->buffers[buf->index].status, buf->sequence, buf->bytesused); | ||
1574 | |||
1575 | return 0; | ||
1576 | } | ||
1577 | |||
1578 | /****************************************************************************** | ||
1579 | * | ||
1580 | * cpia2_ioctl | ||
1581 | * | ||
1582 | *****************************************************************************/ | ||
1583 | static int cpia2_do_ioctl(struct inode *inode, struct file *file, | ||
1584 | unsigned int ioctl_nr, void *arg) | ||
1585 | { | ||
1586 | struct video_device *dev = video_devdata(file); | ||
1587 | struct camera_data *cam = video_get_drvdata(dev); | ||
1588 | int retval = 0; | ||
1589 | |||
1590 | if (!cam) | ||
1591 | return -ENOTTY; | ||
1592 | |||
1593 | /* make this _really_ smp-safe */ | ||
1594 | if (down_interruptible(&cam->busy_lock)) | ||
1595 | return -ERESTARTSYS; | ||
1596 | |||
1597 | if (!cam->present) { | ||
1598 | up(&cam->busy_lock); | ||
1599 | return -ENODEV; | ||
1600 | } | ||
1601 | |||
1602 | /* Priority check */ | ||
1603 | switch (ioctl_nr) { | ||
1604 | case VIDIOCSWIN: | ||
1605 | case VIDIOCMCAPTURE: | ||
1606 | case VIDIOC_S_FMT: | ||
1607 | { | ||
1608 | struct cpia2_fh *fh = file->private_data; | ||
1609 | retval = v4l2_prio_check(&cam->prio, &fh->prio); | ||
1610 | if(retval) { | ||
1611 | up(&cam->busy_lock); | ||
1612 | return retval; | ||
1613 | } | ||
1614 | break; | ||
1615 | } | ||
1616 | case VIDIOCGMBUF: | ||
1617 | case VIDIOCSYNC: | ||
1618 | { | ||
1619 | struct cpia2_fh *fh = file->private_data; | ||
1620 | if(fh->prio != V4L2_PRIORITY_RECORD) { | ||
1621 | up(&cam->busy_lock); | ||
1622 | return -EBUSY; | ||
1623 | } | ||
1624 | break; | ||
1625 | } | ||
1626 | default: | ||
1627 | break; | ||
1628 | } | ||
1629 | |||
1630 | switch (ioctl_nr) { | ||
1631 | case VIDIOCGCAP: /* query capabilites */ | ||
1632 | retval = ioctl_cap_query(arg, cam); | ||
1633 | break; | ||
1634 | |||
1635 | case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */ | ||
1636 | retval = ioctl_get_channel(arg); | ||
1637 | break; | ||
1638 | case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */ | ||
1639 | retval = ioctl_set_channel(arg); | ||
1640 | break; | ||
1641 | case VIDIOCGPICT: /* image properties */ | ||
1642 | memcpy(arg, &cam->vp, sizeof(struct video_picture)); | ||
1643 | break; | ||
1644 | case VIDIOCSPICT: | ||
1645 | retval = ioctl_set_image_prop(arg, cam); | ||
1646 | break; | ||
1647 | case VIDIOCGWIN: /* get/set capture window */ | ||
1648 | memcpy(arg, &cam->vw, sizeof(struct video_window)); | ||
1649 | break; | ||
1650 | case VIDIOCSWIN: | ||
1651 | retval = ioctl_set_window_size(arg, cam, file->private_data); | ||
1652 | break; | ||
1653 | case VIDIOCGMBUF: /* mmap interface */ | ||
1654 | retval = ioctl_get_mbuf(arg, cam); | ||
1655 | break; | ||
1656 | case VIDIOCMCAPTURE: | ||
1657 | retval = ioctl_mcapture(arg, cam, file->private_data); | ||
1658 | break; | ||
1659 | case VIDIOCSYNC: | ||
1660 | retval = ioctl_sync(arg, cam); | ||
1661 | break; | ||
1662 | /* pointless to implement overlay with this camera */ | ||
1663 | case VIDIOCCAPTURE: | ||
1664 | case VIDIOCGFBUF: | ||
1665 | case VIDIOCSFBUF: | ||
1666 | case VIDIOCKEY: | ||
1667 | retval = -EINVAL; | ||
1668 | break; | ||
1669 | |||
1670 | /* tuner interface - we have none */ | ||
1671 | case VIDIOCGTUNER: | ||
1672 | case VIDIOCSTUNER: | ||
1673 | case VIDIOCGFREQ: | ||
1674 | case VIDIOCSFREQ: | ||
1675 | retval = -EINVAL; | ||
1676 | break; | ||
1677 | |||
1678 | /* audio interface - we have none */ | ||
1679 | case VIDIOCGAUDIO: | ||
1680 | case VIDIOCSAUDIO: | ||
1681 | retval = -EINVAL; | ||
1682 | break; | ||
1683 | |||
1684 | /* CPIA2 extension to Video4Linux API */ | ||
1685 | case CPIA2_IOC_SET_GPIO: | ||
1686 | retval = ioctl_set_gpio(arg, cam); | ||
1687 | break; | ||
1688 | case VIDIOC_QUERYCAP: | ||
1689 | retval = ioctl_querycap(arg,cam); | ||
1690 | break; | ||
1691 | |||
1692 | case VIDIOC_ENUMINPUT: | ||
1693 | case VIDIOC_G_INPUT: | ||
1694 | case VIDIOC_S_INPUT: | ||
1695 | retval = ioctl_input(ioctl_nr, arg,cam); | ||
1696 | break; | ||
1697 | |||
1698 | case VIDIOC_ENUM_FMT: | ||
1699 | retval = ioctl_enum_fmt(arg,cam); | ||
1700 | break; | ||
1701 | case VIDIOC_TRY_FMT: | ||
1702 | retval = ioctl_try_fmt(arg,cam); | ||
1703 | break; | ||
1704 | case VIDIOC_G_FMT: | ||
1705 | retval = ioctl_get_fmt(arg,cam); | ||
1706 | break; | ||
1707 | case VIDIOC_S_FMT: | ||
1708 | retval = ioctl_set_fmt(arg,cam,file->private_data); | ||
1709 | break; | ||
1710 | |||
1711 | case VIDIOC_CROPCAP: | ||
1712 | retval = ioctl_cropcap(arg,cam); | ||
1713 | break; | ||
1714 | case VIDIOC_G_CROP: | ||
1715 | case VIDIOC_S_CROP: | ||
1716 | // TODO: I think cropping can be implemented - SJB | ||
1717 | retval = -EINVAL; | ||
1718 | break; | ||
1719 | |||
1720 | case VIDIOC_QUERYCTRL: | ||
1721 | retval = ioctl_queryctrl(arg,cam); | ||
1722 | break; | ||
1723 | case VIDIOC_QUERYMENU: | ||
1724 | retval = ioctl_querymenu(arg,cam); | ||
1725 | break; | ||
1726 | case VIDIOC_G_CTRL: | ||
1727 | retval = ioctl_g_ctrl(arg,cam); | ||
1728 | break; | ||
1729 | case VIDIOC_S_CTRL: | ||
1730 | retval = ioctl_s_ctrl(arg,cam); | ||
1731 | break; | ||
1732 | |||
1733 | case VIDIOC_G_JPEGCOMP: | ||
1734 | retval = ioctl_g_jpegcomp(arg,cam); | ||
1735 | break; | ||
1736 | case VIDIOC_S_JPEGCOMP: | ||
1737 | retval = ioctl_s_jpegcomp(arg,cam); | ||
1738 | break; | ||
1739 | |||
1740 | case VIDIOC_G_PRIORITY: | ||
1741 | { | ||
1742 | struct cpia2_fh *fh = file->private_data; | ||
1743 | *(enum v4l2_priority*)arg = fh->prio; | ||
1744 | break; | ||
1745 | } | ||
1746 | case VIDIOC_S_PRIORITY: | ||
1747 | { | ||
1748 | struct cpia2_fh *fh = file->private_data; | ||
1749 | enum v4l2_priority prio; | ||
1750 | prio = *(enum v4l2_priority*)arg; | ||
1751 | if(cam->streaming && | ||
1752 | prio != fh->prio && | ||
1753 | fh->prio == V4L2_PRIORITY_RECORD) { | ||
1754 | /* Can't drop record priority while streaming */ | ||
1755 | retval = -EBUSY; | ||
1756 | } else if(prio == V4L2_PRIORITY_RECORD && | ||
1757 | prio != fh->prio && | ||
1758 | v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) { | ||
1759 | /* Only one program can record at a time */ | ||
1760 | retval = -EBUSY; | ||
1761 | } else { | ||
1762 | retval = v4l2_prio_change(&cam->prio, &fh->prio, prio); | ||
1763 | } | ||
1764 | break; | ||
1765 | } | ||
1766 | |||
1767 | case VIDIOC_REQBUFS: | ||
1768 | retval = ioctl_reqbufs(arg,cam); | ||
1769 | break; | ||
1770 | case VIDIOC_QUERYBUF: | ||
1771 | retval = ioctl_querybuf(arg,cam); | ||
1772 | break; | ||
1773 | case VIDIOC_QBUF: | ||
1774 | retval = ioctl_qbuf(arg,cam); | ||
1775 | break; | ||
1776 | case VIDIOC_DQBUF: | ||
1777 | retval = ioctl_dqbuf(arg,cam,file); | ||
1778 | break; | ||
1779 | case VIDIOC_STREAMON: | ||
1780 | { | ||
1781 | int type; | ||
1782 | DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); | ||
1783 | type = *(int*)arg; | ||
1784 | if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1785 | retval = -EINVAL; | ||
1786 | |||
1787 | if(!cam->streaming) { | ||
1788 | retval = cpia2_usb_stream_start(cam, | ||
1789 | cam->params.camera_state.stream_mode); | ||
1790 | } else { | ||
1791 | retval = -EINVAL; | ||
1792 | } | ||
1793 | |||
1794 | break; | ||
1795 | } | ||
1796 | case VIDIOC_STREAMOFF: | ||
1797 | { | ||
1798 | int type; | ||
1799 | DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); | ||
1800 | type = *(int*)arg; | ||
1801 | if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1802 | retval = -EINVAL; | ||
1803 | |||
1804 | if(cam->streaming) { | ||
1805 | retval = cpia2_usb_stream_stop(cam); | ||
1806 | } else { | ||
1807 | retval = -EINVAL; | ||
1808 | } | ||
1809 | |||
1810 | break; | ||
1811 | } | ||
1812 | |||
1813 | case VIDIOC_ENUMOUTPUT: | ||
1814 | case VIDIOC_G_OUTPUT: | ||
1815 | case VIDIOC_S_OUTPUT: | ||
1816 | case VIDIOC_G_MODULATOR: | ||
1817 | case VIDIOC_S_MODULATOR: | ||
1818 | |||
1819 | case VIDIOC_ENUMAUDIO: | ||
1820 | case VIDIOC_G_AUDIO: | ||
1821 | case VIDIOC_S_AUDIO: | ||
1822 | |||
1823 | case VIDIOC_ENUMAUDOUT: | ||
1824 | case VIDIOC_G_AUDOUT: | ||
1825 | case VIDIOC_S_AUDOUT: | ||
1826 | |||
1827 | case VIDIOC_ENUMSTD: | ||
1828 | case VIDIOC_QUERYSTD: | ||
1829 | case VIDIOC_G_STD: | ||
1830 | case VIDIOC_S_STD: | ||
1831 | |||
1832 | case VIDIOC_G_TUNER: | ||
1833 | case VIDIOC_S_TUNER: | ||
1834 | case VIDIOC_G_FREQUENCY: | ||
1835 | case VIDIOC_S_FREQUENCY: | ||
1836 | |||
1837 | case VIDIOC_OVERLAY: | ||
1838 | case VIDIOC_G_FBUF: | ||
1839 | case VIDIOC_S_FBUF: | ||
1840 | |||
1841 | case VIDIOC_G_PARM: | ||
1842 | case VIDIOC_S_PARM: | ||
1843 | retval = -EINVAL; | ||
1844 | break; | ||
1845 | default: | ||
1846 | retval = -ENOIOCTLCMD; | ||
1847 | break; | ||
1848 | } | ||
1849 | |||
1850 | up(&cam->busy_lock); | ||
1851 | return retval; | ||
1852 | } | ||
1853 | |||
1854 | static int cpia2_ioctl(struct inode *inode, struct file *file, | ||
1855 | unsigned int ioctl_nr, unsigned long iarg) | ||
1856 | { | ||
1857 | return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl); | ||
1858 | } | ||
1859 | |||
1860 | /****************************************************************************** | ||
1861 | * | ||
1862 | * cpia2_mmap | ||
1863 | * | ||
1864 | *****************************************************************************/ | ||
1865 | static int cpia2_mmap(struct file *file, struct vm_area_struct *area) | ||
1866 | { | ||
1867 | int retval; | ||
1868 | struct video_device *dev = video_devdata(file); | ||
1869 | struct camera_data *cam = video_get_drvdata(dev); | ||
1870 | |||
1871 | /* Priority check */ | ||
1872 | struct cpia2_fh *fh = file->private_data; | ||
1873 | if(fh->prio != V4L2_PRIORITY_RECORD) { | ||
1874 | return -EBUSY; | ||
1875 | } | ||
1876 | |||
1877 | retval = cpia2_remap_buffer(cam, area); | ||
1878 | |||
1879 | if(!retval) | ||
1880 | fh->mmapped = 1; | ||
1881 | return retval; | ||
1882 | } | ||
1883 | |||
1884 | /****************************************************************************** | ||
1885 | * | ||
1886 | * reset_camera_struct_v4l | ||
1887 | * | ||
1888 | * Sets all values to the defaults | ||
1889 | *****************************************************************************/ | ||
1890 | static void reset_camera_struct_v4l(struct camera_data *cam) | ||
1891 | { | ||
1892 | /*** | ||
1893 | * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP | ||
1894 | * Ioctl. Here, just do the window and picture stucts. | ||
1895 | ***/ | ||
1896 | cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */ | ||
1897 | cam->vp.brightness = (u16) cam->params.color_params.brightness * 256; | ||
1898 | cam->vp.colour = (u16) cam->params.color_params.saturation * 256; | ||
1899 | cam->vp.contrast = (u16) cam->params.color_params.contrast * 256; | ||
1900 | |||
1901 | cam->vw.x = 0; | ||
1902 | cam->vw.y = 0; | ||
1903 | cam->vw.width = cam->params.roi.width; | ||
1904 | cam->vw.height = cam->params.roi.height; | ||
1905 | cam->vw.flags = 0; | ||
1906 | cam->vw.clipcount = 0; | ||
1907 | |||
1908 | cam->frame_size = buffer_size; | ||
1909 | cam->num_frames = num_buffers; | ||
1910 | |||
1911 | /* FlickerModes */ | ||
1912 | cam->params.flicker_control.flicker_mode_req = flicker_mode; | ||
1913 | cam->params.flicker_control.mains_frequency = flicker_freq; | ||
1914 | |||
1915 | /* streamMode */ | ||
1916 | cam->params.camera_state.stream_mode = alternate; | ||
1917 | |||
1918 | cam->pixelformat = V4L2_PIX_FMT_JPEG; | ||
1919 | v4l2_prio_init(&cam->prio); | ||
1920 | return; | ||
1921 | } | ||
1922 | |||
1923 | /*** | ||
1924 | * The v4l video device structure initialized for this device | ||
1925 | ***/ | ||
1926 | static struct file_operations fops_template = { | ||
1927 | .owner= THIS_MODULE, | ||
1928 | .open= cpia2_open, | ||
1929 | .release= cpia2_close, | ||
1930 | .read= cpia2_v4l_read, | ||
1931 | .poll= cpia2_v4l_poll, | ||
1932 | .ioctl= cpia2_ioctl, | ||
1933 | .llseek= no_llseek, | ||
1934 | .mmap= cpia2_mmap, | ||
1935 | }; | ||
1936 | |||
1937 | static struct video_device cpia2_template = { | ||
1938 | /* I could not find any place for the old .initialize initializer?? */ | ||
1939 | .owner= THIS_MODULE, | ||
1940 | .name= "CPiA2 Camera", | ||
1941 | .type= VID_TYPE_CAPTURE, | ||
1942 | .type2 = V4L2_CAP_VIDEO_CAPTURE | | ||
1943 | V4L2_CAP_STREAMING, | ||
1944 | .hardware= VID_HARDWARE_CPIA2, | ||
1945 | .minor= -1, | ||
1946 | .fops= &fops_template, | ||
1947 | .release= video_device_release, | ||
1948 | }; | ||
1949 | |||
1950 | /****************************************************************************** | ||
1951 | * | ||
1952 | * cpia2_register_camera | ||
1953 | * | ||
1954 | *****************************************************************************/ | ||
1955 | int cpia2_register_camera(struct camera_data *cam) | ||
1956 | { | ||
1957 | cam->vdev = video_device_alloc(); | ||
1958 | if(!cam->vdev) | ||
1959 | return -ENOMEM; | ||
1960 | |||
1961 | memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); | ||
1962 | video_set_drvdata(cam->vdev, cam); | ||
1963 | |||
1964 | reset_camera_struct_v4l(cam); | ||
1965 | |||
1966 | /* register v4l device */ | ||
1967 | if (video_register_device | ||
1968 | (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
1969 | ERR("video_register_device failed\n"); | ||
1970 | video_device_release(cam->vdev); | ||
1971 | return -ENODEV; | ||
1972 | } | ||
1973 | |||
1974 | return 0; | ||
1975 | } | ||
1976 | |||
1977 | /****************************************************************************** | ||
1978 | * | ||
1979 | * cpia2_unregister_camera | ||
1980 | * | ||
1981 | *****************************************************************************/ | ||
1982 | void cpia2_unregister_camera(struct camera_data *cam) | ||
1983 | { | ||
1984 | if (!cam->open_count) { | ||
1985 | video_unregister_device(cam->vdev); | ||
1986 | } else { | ||
1987 | LOG("/dev/video%d removed while open, " | ||
1988 | "deferring video_unregister_device\n", | ||
1989 | cam->vdev->minor); | ||
1990 | } | ||
1991 | } | ||
1992 | |||
1993 | /****************************************************************************** | ||
1994 | * | ||
1995 | * check_parameters | ||
1996 | * | ||
1997 | * Make sure that all user-supplied parameters are sensible | ||
1998 | *****************************************************************************/ | ||
1999 | static void __init check_parameters(void) | ||
2000 | { | ||
2001 | if(buffer_size < PAGE_SIZE) { | ||
2002 | buffer_size = PAGE_SIZE; | ||
2003 | LOG("buffer_size too small, setting to %d\n", buffer_size); | ||
2004 | } else if(buffer_size > 1024*1024) { | ||
2005 | /* arbitrary upper limiit */ | ||
2006 | buffer_size = 1024*1024; | ||
2007 | LOG("buffer_size ridiculously large, setting to %d\n", | ||
2008 | buffer_size); | ||
2009 | } else { | ||
2010 | buffer_size += PAGE_SIZE-1; | ||
2011 | buffer_size &= ~(PAGE_SIZE-1); | ||
2012 | } | ||
2013 | |||
2014 | if(num_buffers < 1) { | ||
2015 | num_buffers = 1; | ||
2016 | LOG("num_buffers too small, setting to %d\n", num_buffers); | ||
2017 | } else if(num_buffers > VIDEO_MAX_FRAME) { | ||
2018 | num_buffers = VIDEO_MAX_FRAME; | ||
2019 | LOG("num_buffers too large, setting to %d\n", num_buffers); | ||
2020 | } | ||
2021 | |||
2022 | if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { | ||
2023 | alternate = DEFAULT_ALT; | ||
2024 | LOG("alternate specified is invalid, using %d\n", alternate); | ||
2025 | } | ||
2026 | |||
2027 | if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { | ||
2028 | flicker_mode = NEVER_FLICKER; | ||
2029 | LOG("Flicker mode specified is invalid, using %d\n", | ||
2030 | flicker_mode); | ||
2031 | } | ||
2032 | |||
2033 | if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { | ||
2034 | flicker_freq = FLICKER_60; | ||
2035 | LOG("Flicker mode specified is invalid, using %d\n", | ||
2036 | flicker_freq); | ||
2037 | } | ||
2038 | |||
2039 | if(video_nr < -1 || video_nr > 64) { | ||
2040 | video_nr = -1; | ||
2041 | LOG("invalid video_nr specified, must be -1 to 64\n"); | ||
2042 | } | ||
2043 | |||
2044 | DBG("Using %d buffers, each %d bytes, alternate=%d\n", | ||
2045 | num_buffers, buffer_size, alternate); | ||
2046 | } | ||
2047 | |||
2048 | /************ Module Stuff ***************/ | ||
2049 | |||
2050 | |||
2051 | /****************************************************************************** | ||
2052 | * | ||
2053 | * cpia2_init/module_init | ||
2054 | * | ||
2055 | *****************************************************************************/ | ||
2056 | int __init cpia2_init(void) | ||
2057 | { | ||
2058 | LOG("%s v%d.%d.%d\n", | ||
2059 | ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); | ||
2060 | check_parameters(); | ||
2061 | cpia2_usb_init(); | ||
2062 | return 0; | ||
2063 | } | ||
2064 | |||
2065 | |||
2066 | /****************************************************************************** | ||
2067 | * | ||
2068 | * cpia2_exit/module_exit | ||
2069 | * | ||
2070 | *****************************************************************************/ | ||
2071 | void __exit cpia2_exit(void) | ||
2072 | { | ||
2073 | cpia2_usb_cleanup(); | ||
2074 | schedule_timeout(2 * HZ); | ||
2075 | } | ||
2076 | |||
2077 | |||
2078 | int __init cpia2_setup(char *str) | ||
2079 | { | ||
2080 | while(str) { | ||
2081 | if(!strncmp(str, "buffer_size:", 12)) { | ||
2082 | buffer_size = simple_strtoul(str + 13, &str, 10); | ||
2083 | } else if(!strncmp(str, "num_buffers:", 12)) { | ||
2084 | num_buffers = simple_strtoul(str + 13, &str, 10); | ||
2085 | } else if(!strncmp(str, "alternate:", 10)) { | ||
2086 | alternate = simple_strtoul(str + 11, &str, 10); | ||
2087 | } else if(!strncmp(str, "video_nr:", 9)) { | ||
2088 | video_nr = simple_strtoul(str + 10, &str, 10); | ||
2089 | } else if(!strncmp(str, "flicker_freq:",13)) { | ||
2090 | flicker_freq = simple_strtoul(str + 14, &str, 10); | ||
2091 | } else if(!strncmp(str, "flicker_mode:",13)) { | ||
2092 | flicker_mode = simple_strtoul(str + 14, &str, 10); | ||
2093 | } else { | ||
2094 | ++str; | ||
2095 | } | ||
2096 | } | ||
2097 | return 1; | ||
2098 | } | ||
2099 | |||
2100 | __setup("cpia2=", cpia2_setup); | ||
2101 | |||
2102 | module_init(cpia2_init); | ||
2103 | module_exit(cpia2_exit); | ||
2104 | |||