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