3 * @author Nicolas VIVIEN
6 * @brief V4L2 interface and functions
8 * @note Copyright (C) Nicolas VIVIEN
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/version.h>
31 #include <linux/errno.h>
32 #include <linux/slab.h>
33 #include <linux/kref.h>
34 #include <linux/vmalloc.h>
35 #include <linux/usb.h>
39 #include "sn9c20x-bridge.h"
41 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
42 #include <media/v4l2-ioctl.h>
45 static struct file_operations v4l_sn9c20x_fops
;
47 * @var sn9c20x_controls
48 * List of all V4Lv2 controls supported by the driver
50 static struct v4l2_queryctrl sn9c20x_controls
[] = {
52 .id
= V4L2_CID_BRIGHTNESS
,
53 .type
= V4L2_CTRL_TYPE_INTEGER
,
61 .type
= V4L2_CTRL_TYPE_INTEGER
,
69 .id = V4L2_CID_SATURATION,
70 .type = V4L2_CTRL_TYPE_INTEGER,
78 .id
= V4L2_CID_CONTRAST
,
79 .type
= V4L2_CTRL_TYPE_INTEGER
,
86 .id
= V4L2_CID_EXPOSURE
,
87 .type
= V4L2_CTRL_TYPE_INTEGER
,
95 .type
= V4L2_CTRL_TYPE_INTEGER
,
102 .id
= V4L2_CID_HFLIP
,
103 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
104 .name
= "Horizontal flip",
110 .id
= V4L2_CID_VFLIP
,
111 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
112 .name
= "Vertical flip",
118 .id
= V4L2_CID_SHARPNESS
,
119 .type
= V4L2_CTRL_TYPE_INTEGER
,
126 .id
= V4L2_CID_RED_BALANCE
,
127 .type
= V4L2_CTRL_TYPE_INTEGER
,
128 .name
= "Red Balance",
134 .id
= V4L2_CID_BLUE_BALANCE
,
135 .type
= V4L2_CTRL_TYPE_INTEGER
,
136 .name
= "Blue Balance",
142 .id
= V4L2_CID_EXPOSURE_AUTO
,
143 .type
= V4L2_CTRL_TYPE_INTEGER
,
144 .name
= "Automatic exposure control",
150 .id
= V4L2_CID_AUTOGAIN
,
151 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
152 .name
= "Automatic gain control",
158 .id
= V4L2_CID_AUTO_WHITE_BALANCE
,
159 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
160 .name
= "Automatic whitbalance control",
167 void v4l2_set_control_default(struct usb_sn9c20x
*dev
, __u32 ctrl
, __u16 value
)
170 for (i
= 0; i
< ARRAY_SIZE(sn9c20x_controls
); i
++) {
171 if (sn9c20x_controls
[i
].id
== ctrl
) {
172 sn9c20x_controls
[i
].default_value
= value
;
173 sn9c20x_set_camera_control(dev
,
181 void v4l_add_jpegheader(struct usb_sn9c20x
*dev
, __u8
*buffer
,
184 __u8 jpeg_header
[589] = {
185 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
186 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
187 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
188 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
189 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
190 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
191 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
192 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
193 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
194 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
195 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
196 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
197 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
198 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
199 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
201 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
202 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
203 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
204 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
205 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
206 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
207 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
208 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
209 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
210 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
211 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
212 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
213 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
214 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
215 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
216 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
217 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
218 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
219 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
220 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
221 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
222 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
223 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
224 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
225 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
226 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
227 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
228 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
229 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
230 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
231 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
232 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
233 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
234 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
235 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
236 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
237 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
238 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
239 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
240 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
241 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
242 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
243 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
245 __u8 qtable1
[128] = {
246 0x0d, 0x08, 0x08, 0x0d, 0x08, 0x08, 0x0d, 0x0d,
247 0x0d, 0x0d, 0x11, 0x0d, 0x0d, 0x11, 0x15, 0x21,
248 0x15, 0x15, 0x11, 0x11, 0x15, 0x2a, 0x1d, 0x1d,
249 0x19, 0x21, 0x32, 0x2a, 0x32, 0x32, 0x2e, 0x2a,
250 0x2e, 0x2e, 0x36, 0x3a, 0x4b, 0x43, 0x36, 0x3a,
251 0x47, 0x3a, 0x2e, 0x2e, 0x43, 0x5c, 0x43, 0x47,
252 0x4f, 0x54, 0x58, 0x58, 0x58, 0x32, 0x3f, 0x60,
253 0x64, 0x5c, 0x54, 0x64, 0x4b, 0x54, 0x58, 0x54,
254 0x0d, 0x11, 0x11, 0x15, 0x11, 0x15, 0x26, 0x15,
255 0x15, 0x26, 0x54, 0x36, 0x2e, 0x36, 0x54, 0x54,
256 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
257 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
258 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
259 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
260 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
261 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54
264 jpeg_header
[6] = 0x00;
265 jpeg_header
[71] = 0x01;
266 memcpy(jpeg_header
+ 7, qtable1
, 64);
267 memcpy(jpeg_header
+ 8 + 64, qtable1
+64, 64);
268 jpeg_header
[564] = dev
->vsettings
.format
.width
& 0xFF;
269 jpeg_header
[563] = (dev
->vsettings
.format
.width
>> 8) & 0xFF;
270 jpeg_header
[562] = dev
->vsettings
.format
.height
& 0xFF;
271 jpeg_header
[561] = (dev
->vsettings
.format
.height
>> 8) & 0xFF;
272 jpeg_header
[567] = 0x21;
274 memmove(buffer
+589, buffer
, buffer_size
);
275 memcpy(buffer
, jpeg_header
, 589);
278 * @brief Get V4L privileges
282 * @return 0 or negative error code
285 int v4l_get_privileges(struct file
*file
)
287 struct usb_sn9c20x
*dev
;
290 dev
= video_get_drvdata(video_devdata(file
));
292 if (dev
->owner
== file
)
295 mutex_lock(&open_lock
);
296 if (dev
->owner
!= NULL
) {
302 mutex_unlock(&open_lock
);
307 * @brief Check whether there are V4L privileges
314 int v4l_has_privileges(struct file
*file
)
316 struct usb_sn9c20x
*dev
;
319 dev
= video_get_drvdata(video_devdata(file
));
321 if (dev
->owner
== file
)
328 * @brief Drop V4L privileges
333 void v4l_drop_privileges(struct file
*file
)
335 struct usb_sn9c20x
*dev
;
337 dev
= video_get_drvdata(video_devdata(file
));
339 if (dev
->owner
== file
)
344 * @brief Enable video stream
346 * @param dev Pointer to device structure
347 * @param mode Mode for video stream
349 * @returns 0 or negative error value
352 int v4l2_enable_video(struct usb_sn9c20x
*dev
, int mode
)
356 if (mode
== SN9C20X_MODE_IDLE
) {
357 sn9c20x_enable_video(dev
, 0);
358 usb_sn9c20x_uninit_urbs(dev
);
359 sn9c20x_queue_enable(&dev
->queue
, 0);
364 if (dev
->mode
!= SN9C20X_MODE_IDLE
)
367 if (sn9c20x_queue_enable(&dev
->queue
, 1) < 0)
370 ret
= usb_sn9c20x_init_urbs(dev
);
375 sn9c20x_enable_video(dev
, 1);
378 if (dev
->vsettings
.format
.pixelformat
== V4L2_PIX_FMT_JPEG
)
379 dev
->queue
.flags
&= ~SN9C20X_QUEUE_DROP_INCOMPLETE
;
381 dev
->queue
.flags
|= SN9C20X_QUEUE_DROP_INCOMPLETE
;
387 * @param inode Pointer on an inode
388 * @param fp File pointer
390 * @returns 0 if all is OK
392 * @brief Open the video device
394 * This function permits to open a video device (/dev/videoX)
396 static int v4l_sn9c20x_open(struct inode
*inode
, struct file
*fp
)
400 struct usb_sn9c20x
*dev
;
401 struct video_device
*vdev
;
403 mutex_lock(&open_lock
);
405 vdev
= video_devdata(fp
);
406 dev
= video_get_drvdata(video_devdata(fp
));
408 fp
->private_data
= vdev
;
410 kref_get(&dev
->vopen
);
412 mutex_unlock(&open_lock
);
418 * @param inode Pointer on inode
419 * @param fp File pointer
421 * @returns 0 if all is OK
423 * @brief Release an opened file.
425 * This function permits to release an opened file with the 'open' method.
427 static int v4l_sn9c20x_release(struct inode
*inode
, struct file
*fp
)
429 struct usb_sn9c20x
*dev
;
430 struct video_device
*vdev
;
432 mutex_lock(&open_lock
);
434 vdev
= video_devdata(fp
);
435 dev
= video_get_drvdata(video_devdata(fp
));
437 if (v4l_has_privileges(fp
)) {
438 v4l2_enable_video(dev
, SN9C20X_MODE_IDLE
);
440 mutex_lock(&dev
->queue
.mutex
);
441 sn9c20x_free_buffers(&dev
->queue
);
442 mutex_unlock(&dev
->queue
.mutex
);
445 v4l_drop_privileges(fp
);
447 kref_put(&dev
->vopen
, usb_sn9c20x_delete
);
449 mutex_unlock(&open_lock
);
455 * @param fp File pointer
457 * @retval buf Buffer in user space
461 * @returns Count value
463 * @brief Read the video device
465 * This function is called by the application is reading the video device.
467 static ssize_t
v4l_sn9c20x_read(struct file
*fp
, char __user
*buf
,
468 size_t count
, loff_t
*f_pos
)
472 struct v4l2_buffer buffer
;
473 struct usb_sn9c20x
*dev
;
475 dev
= video_get_drvdata(video_devdata(fp
));
477 ret
= v4l_get_privileges(fp
);
481 if (dev
->mode
!= SN9C20X_MODE_IDLE
&&
482 dev
->mode
!= SN9C20X_MODE_READ
)
485 buffer
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
486 buffer
.memory
= V4L2_MEMORY_MMAP
;
487 if (dev
->mode
== SN9C20X_MODE_IDLE
) {
488 nbuffers
= sn9c20x_alloc_buffers(&dev
->queue
, 2,
489 dev
->vsettings
.format
.sizeimage
);
493 for (i
= 0; i
< nbuffers
; i
++) {
494 buffer
= dev
->queue
.buffer
[i
].buf
;
495 sn9c20x_queue_buffer(&dev
->queue
, &buffer
);
498 ret
= v4l2_enable_video(dev
, SN9C20X_MODE_READ
);
503 dev_sn9c20x_call_constantly(dev
);
505 if (dev
->queue
.read_buffer
== NULL
) {
506 ret
= sn9c20x_dequeue_buffer(&dev
->queue
, &buffer
,
507 fp
->f_flags
& O_NONBLOCK
);
511 if (dev
->vsettings
.format
.pixelformat
== V4L2_PIX_FMT_JPEG
) {
512 UDIA_DEBUG("Adding JPEG Header\n");
513 v4l_add_jpegheader(dev
, dev
->queue
.mem
+ buffer
.m
.offset
,
515 buffer
.bytesused
+= 589;
518 dev
->queue
.read_buffer
= &dev
->queue
.buffer
[buffer
.index
];
520 buffer
= dev
->queue
.read_buffer
->buf
;
523 count
= min((size_t)(buffer
.bytesused
- *f_pos
), count
);
524 if (copy_to_user(buf
, dev
->queue
.mem
+ buffer
.m
.offset
+ *f_pos
, count
))
528 if (*f_pos
>= buffer
.bytesused
) {
529 dev
->queue
.read_buffer
= NULL
;
530 sn9c20x_queue_buffer(&dev
->queue
, &buffer
);
538 * @param fp File pointer
541 * @returns 0 if all is OK
543 * @brief Polling function
545 static unsigned int v4l_sn9c20x_poll(struct file
*fp
, poll_table
*wait
)
547 struct usb_sn9c20x
*dev
;
548 struct video_device
*vdev
;
550 vdev
= video_devdata(fp
);
551 dev
= video_get_drvdata(video_devdata(fp
));
553 UDIA_STREAM("Poll\n");
555 if (vdev
== NULL
|| dev
== NULL
)
558 return sn9c20x_queue_poll(&dev
->queue
, fp
, wait
);
565 static void sn9c20x_vm_open(struct vm_area_struct
*vma
)
567 struct sn9c20x_buffer
*buffer
= vma
->vm_private_data
;
568 buffer
->vma_use_count
++;
576 static void sn9c20x_vm_close(struct vm_area_struct
*vma
)
578 struct sn9c20x_buffer
*buffer
= vma
->vm_private_data
;
579 buffer
->vma_use_count
--;
582 struct vm_operations_struct sn9c20x_vm_ops
= {
583 .open
= sn9c20x_vm_open
,
584 .close
= sn9c20x_vm_close
588 * @param fp File pointer
589 * @param vma VMA structure
591 * @returns 0 if all is OK
595 * This function permits to map a memory space.
597 static int v4l_sn9c20x_mmap(struct file
*fp
, struct vm_area_struct
*vma
)
600 unsigned long addr
, start
, size
;
604 struct usb_sn9c20x
*dev
;
605 struct video_device
*vdev
;
606 struct sn9c20x_buffer
*buffer
= NULL
;
608 vdev
= video_devdata(fp
);
609 dev
= video_get_drvdata(video_devdata(fp
));
611 UDIA_STREAM("mmap\n");
613 start
= vma
->vm_start
;
614 size
= vma
->vm_end
- vma
->vm_start
;
616 mutex_lock(&dev
->queue
.mutex
);
618 for (i
= 0; i
< dev
->queue
.count
; ++i
) {
619 buffer
= &dev
->queue
.buffer
[i
];
620 if ((buffer
->buf
.m
.offset
>> PAGE_SHIFT
) == vma
->vm_pgoff
)
624 if (i
== dev
->queue
.count
|| size
!= dev
->queue
.buf_size
) {
629 vma
->vm_flags
|= VM_IO
;
631 addr
= (unsigned long)dev
->queue
.mem
+ buffer
->buf
.m
.offset
;
633 page
= vmalloc_to_page((void *)addr
);
634 ret
= vm_insert_page(vma
, start
, page
);
643 vma
->vm_ops
= &sn9c20x_vm_ops
;
644 vma
->vm_private_data
= buffer
;
645 sn9c20x_vm_open(vma
);
647 mutex_unlock(&dev
->queue
.mutex
);
659 int sn9c20x_vidioc_querycap(struct file
*file
, void *priv
,
660 struct v4l2_capability
*cap
)
662 struct usb_sn9c20x
*dev
;
664 dev
= video_get_drvdata(priv
);
666 UDIA_DEBUG("VIDIOC_QUERYCAP\n");
668 strlcpy(cap
->driver
, "sn9c20x", sizeof(cap
->driver
));
669 cap
->capabilities
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
670 | V4L2_CAP_READWRITE
;
671 cap
->version
= (__u32
) DRIVER_VERSION_NUM
,
672 strlcpy(cap
->card
, dev
->vdev
->name
, sizeof(cap
->card
));
674 if (usb_make_path(dev
->udev
, cap
->bus_info
, sizeof(cap
->bus_info
)) < 0)
675 strlcpy(cap
->bus_info
, dev
->vdev
->name
, sizeof(cap
->bus_info
));
684 * @return 0 or negative error code
687 int sn9c20x_vidioc_enum_input(struct file
*file
, void *priv
,
688 struct v4l2_input
*input
)
690 UDIA_DEBUG("VIDIOC_ENUMINPUT %d\n", input
->index
);
695 strlcpy(input
->name
, "Webcam", sizeof(input
->name
));
696 input
->type
= V4L2_INPUT_TYPE_CAMERA
;
707 * @return 0 or negative error code
710 int sn9c20x_vidioc_g_input(struct file
*file
, void *priv
, unsigned int *index
)
712 UDIA_DEBUG("GET INPUT %d\n", *index
);
725 * @return 0 or negative error code
728 int sn9c20x_vidioc_s_input(struct file
*file
, void *priv
, unsigned int index
)
730 UDIA_DEBUG("SET INPUT %d\n", index
);
732 if (v4l_get_privileges(file
) < 0)
746 * @return 0 or negative error code
749 int sn9c20x_vidioc_queryctrl(struct file
*file
, void *priv
,
750 struct v4l2_queryctrl
*ctrl
)
753 UDIA_DEBUG("VIDIOC_QUERYCTRL id = %d\n", ctrl
->id
);
755 for (i
= 0; i
< ARRAY_SIZE(sn9c20x_controls
); i
++) {
756 if (sn9c20x_controls
[i
].id
== ctrl
->id
) {
757 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
758 memcpy(ctrl
, &sn9c20x_controls
[i
],
759 sizeof(struct v4l2_queryctrl
));
764 if (i
>= ARRAY_SIZE(sn9c20x_controls
))
775 * @return 0 or negative error code
778 int sn9c20x_vidioc_g_ctrl(struct file
*file
, void *priv
,
779 struct v4l2_control
*ctrl
)
781 struct usb_sn9c20x
*dev
;
783 dev
= video_get_drvdata(priv
);
785 UDIA_DEBUG("GET CTRL id=%d\n", ctrl
->id
);
788 case V4L2_CID_BRIGHTNESS
:
789 ctrl
->value
= dev
->vsettings
.brightness
;
792 case V4L2_CID_EXPOSURE
:
793 ctrl
->value
= dev
->vsettings
.exposure
;
797 ctrl
->value
= dev
->vsettings
.gain
;
801 ctrl
->value
= dev
->vsettings
.gamma
;
804 case V4L2_CID_SATURATION:
805 ctrl->value = dev->vsettings.colour;
808 case V4L2_CID_CONTRAST
:
809 ctrl
->value
= dev
->vsettings
.contrast
;
813 ctrl
->value
= dev
->vsettings
.hflip
;
817 ctrl
->value
= dev
->vsettings
.vflip
;
820 case V4L2_CID_SHARPNESS
:
821 ctrl
->value
= dev
->vsettings
.sharpness
;
824 case V4L2_CID_RED_BALANCE
:
825 ctrl
->value
= dev
->vsettings
.red_gain
;
828 case V4L2_CID_BLUE_BALANCE
:
829 ctrl
->value
= dev
->vsettings
.blue_gain
;
832 case V4L2_CID_EXPOSURE_AUTO
:
833 ctrl
->value
= dev
->vsettings
.auto_exposure
;
836 case V4L2_CID_AUTOGAIN
:
837 ctrl
->value
= dev
->vsettings
.auto_gain
;
840 case V4L2_CID_AUTO_WHITE_BALANCE
:
841 ctrl
->value
= dev
->vsettings
.auto_whitebalance
;
851 * @brief Apply v4l2 settings on camera
855 * @param ctrl V4L2 control structure
857 * @returns 0 or negative error value
860 int sn9c20x_vidioc_s_ctrl(struct file
*file
, void *priv
,
861 struct v4l2_control
*ctrl
)
863 struct usb_sn9c20x
*dev
;
865 dev
= video_get_drvdata(priv
);
867 UDIA_DEBUG("SET CTRL id=%d value=%d\n", ctrl
->id
, ctrl
->value
);
869 return sn9c20x_set_camera_control(dev
,
879 * @return 0 or negative error code
882 int sn9c20x_vidioc_enum_fmt_cap(struct file
*file
, void *priv
,
883 struct v4l2_fmtdesc
*fmt
)
885 struct usb_sn9c20x
*dev
;
887 dev
= video_get_drvdata(priv
);
889 UDIA_DEBUG("VIDIOC_ENUM_FMT %d\n", fmt
->index
);
891 if (fmt
->index
>= SN9C20X_N_FMTS
)
895 fmt
->pixelformat
= sn9c20x_fmts
[fmt
->index
].pix_fmt
;
897 if (fmt
->pixelformat
== V4L2_PIX_FMT_JPEG
&& jpeg
== 0)
900 memcpy(fmt
->description
, sn9c20x_fmts
[fmt
->index
].desc
, 32);
910 * @return 0 or negative error code
913 int sn9c20x_vidioc_try_fmt_cap(struct file
*file
, void *priv
,
914 struct v4l2_format
*fmt
)
917 struct usb_sn9c20x
*dev
;
919 dev
= video_get_drvdata(priv
);
920 UDIA_DEBUG("TRY FMT %d\n", fmt
->type
);
922 /* when this code is used prevents mplayer from setting outfmt
923 if(fmt->fmt.pix.field != V4L2_FIELD_NONE)
926 if (fmt
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_JPEG
&& jpeg
== 0)
929 for (index
= 0; index
< SN9C20X_N_FMTS
; index
++)
930 if (sn9c20x_fmts
[index
].pix_fmt
== fmt
->fmt
.pix
.pixelformat
)
933 if (index
>= SN9C20X_N_FMTS
)
936 sn9c20x_get_closest_resolution(dev
, &fmt
->fmt
.pix
.width
,
937 &fmt
->fmt
.pix
.height
);
939 fmt
->fmt
.pix
.bytesperline
= fmt
->fmt
.pix
.width
*
940 sn9c20x_fmts
[index
].depth
/ 8;
942 fmt
->fmt
.pix
.sizeimage
= fmt
->fmt
.pix
.height
*
943 fmt
->fmt
.pix
.bytesperline
;
945 fmt
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_SRGB
;
946 fmt
->fmt
.pix
.priv
= index
;
959 int sn9c20x_vidioc_g_fmt_cap(struct file
*file
, void *priv
,
960 struct v4l2_format
*fmt
)
962 struct usb_sn9c20x
*dev
;
964 dev
= video_get_drvdata(priv
);
966 UDIA_DEBUG("GET FMT %d\n", fmt
->type
);
968 memcpy(&(fmt
->fmt
.pix
), &(dev
->vsettings
.format
), sizeof(fmt
->fmt
.pix
));
979 * @return 0 or negative error code
982 int sn9c20x_vidioc_s_fmt_cap(struct file
*file
, void *priv
,
983 struct v4l2_format
*fmt
)
985 struct usb_sn9c20x
*dev
;
988 dev
= video_get_drvdata(priv
);
990 UDIA_DEBUG("SET FMT %d : %d\n", fmt
->type
, fmt
->fmt
.pix
.pixelformat
);
992 if (v4l_get_privileges(file
) < 0)
995 if (sn9c20x_queue_streaming(&dev
->queue
))
998 ret
= sn9c20x_vidioc_try_fmt_cap(file
, priv
, fmt
);
1002 sn9c20x_set_resolution(dev
, fmt
->fmt
.pix
.width
, fmt
->fmt
.pix
.height
);
1003 sn9c20x_set_format(dev
, fmt
->fmt
.pix
.pixelformat
);
1004 memcpy(&(dev
->vsettings
.format
), &(fmt
->fmt
.pix
), sizeof(fmt
->fmt
.pix
));
1014 * @return 0 or negative error code
1017 int sn9c20x_vidioc_reqbufs(struct file
*file
, void *priv
,
1018 struct v4l2_requestbuffers
*request
)
1021 struct usb_sn9c20x
*dev
;
1023 dev
= video_get_drvdata(priv
);
1025 if (v4l_get_privileges(file
) < 0) {
1030 if (request
->memory
!= V4L2_MEMORY_MMAP
||
1031 request
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
1036 if (sn9c20x_queue_streaming(&dev
->queue
)) {
1041 ret
= sn9c20x_alloc_buffers(&dev
->queue
, request
->count
,
1042 dev
->vsettings
.format
.sizeimage
);
1046 request
->count
= ret
;
1048 UDIA_DEBUG("Buffers Allocated %d\n", request
->count
);
1058 * @return 0 or negative error code
1061 int sn9c20x_vidioc_querybuf(struct file
*file
, void *priv
,
1062 struct v4l2_buffer
*buffer
)
1064 struct usb_sn9c20x
*dev
;
1066 dev
= video_get_drvdata(priv
);
1068 UDIA_DEBUG("QUERY BUFFERS %d %d\n", buffer
->index
, dev
->queue
.count
);
1070 if (buffer
->memory
!= V4L2_MEMORY_MMAP
||
1071 buffer
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1074 if (!v4l_has_privileges(file
))
1077 return sn9c20x_query_buffer(&dev
->queue
, buffer
);
1085 * @return 0 or negative error code
1088 int sn9c20x_vidioc_qbuf(struct file
*file
, void *priv
,
1089 struct v4l2_buffer
*buffer
)
1091 struct usb_sn9c20x
*dev
;
1093 dev
= video_get_drvdata(priv
);
1095 UDIA_DEBUG("VIDIOC_QBUF\n");
1097 if (!v4l_has_privileges(file
))
1100 return sn9c20x_queue_buffer(&dev
->queue
, buffer
);
1108 * @return 0 or negative error code
1111 int sn9c20x_vidioc_dqbuf(struct file
*file
, void *priv
,
1112 struct v4l2_buffer
*buffer
)
1114 struct usb_sn9c20x
*dev
;
1117 dev
= video_get_drvdata(priv
);
1119 UDIA_DEBUG("VIDIOC_DQBUF\n");
1121 if (!v4l_has_privileges(file
))
1124 ret
= sn9c20x_dequeue_buffer(&dev
->queue
, buffer
,
1125 file
->f_flags
& O_NONBLOCK
);
1129 if (dev
->vsettings
.format
.pixelformat
== V4L2_PIX_FMT_JPEG
) {
1130 UDIA_DEBUG("Adding JPEG Header\n");
1131 v4l_add_jpegheader(dev
, dev
->queue
.mem
+ buffer
->m
.offset
,
1133 buffer
->bytesused
+= 589;
1136 dev_sn9c20x_call_constantly(dev
);
1146 * @return 0 or negative error code
1149 int sn9c20x_vidioc_streamon(struct file
*file
, void *priv
,
1150 enum v4l2_buf_type type
)
1152 struct usb_sn9c20x
*dev
;
1154 dev
= video_get_drvdata(priv
);
1156 UDIA_DEBUG("VIDIOC_STREAMON\n");
1158 if (!v4l_has_privileges(file
))
1161 if (dev
->mode
!= SN9C20X_MODE_IDLE
)
1164 return v4l2_enable_video(dev
, SN9C20X_MODE_STREAM
);
1172 * @return 0 or negative error code
1175 int sn9c20x_vidioc_streamoff(struct file
*file
, void *priv
,
1176 enum v4l2_buf_type type
)
1178 struct usb_sn9c20x
*dev
;
1180 dev
= video_get_drvdata(priv
);
1182 UDIA_DEBUG("VIDIOC_STREAMOFF\n");
1184 if (!v4l_has_privileges(file
))
1187 return v4l2_enable_video(dev
, SN9C20X_MODE_IDLE
);
1195 * @return 0 or negative error code
1198 int sn9c20x_vidioc_g_param(struct file
*file
, void *priv
,
1199 struct v4l2_streamparm
*param
)
1201 struct usb_sn9c20x
*dev
;
1204 dev
= video_get_drvdata(priv
);
1206 if (param
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1209 param
->parm
.capture
.capability
= 0;
1210 param
->parm
.capture
.capturemode
= 0;
1211 param
->parm
.capture
.timeperframe
.numerator
= 1;
1212 param
->parm
.capture
.timeperframe
.denominator
= 30;
1213 param
->parm
.capture
.readbuffers
= 2;
1214 param
->parm
.capture
.extendedmode
= 0;
1224 * @return 0 or negative error code
1227 int sn9c20x_vidioc_s_param(struct file
*file
, void *priv
,
1228 struct v4l2_streamparm
*param
)
1230 struct usb_sn9c20x
*dev
;
1232 dev
= video_get_drvdata(priv
);
1234 if (v4l_get_privileges(file
))
1237 if (param
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1244 * @param inode Inode pointer
1245 * @param fp File pointer
1246 * @param cmd Command
1247 * @param arg Arguements of the command
1249 * @returns 0 if all is OK
1251 * @brief Manage IOCTL
1253 * This function permits to manage all the IOCTL from the application.
1255 static int v4l_sn9c20x_ioctl(struct inode
*inode
, struct file
*fp
,
1256 unsigned int cmd
, unsigned long arg
)
1259 struct usb_sn9c20x
*dev
;
1260 struct video_device
*vdev
;
1262 vdev
= video_devdata(fp
);
1263 dev
= video_get_drvdata(video_devdata(fp
));
1265 UDIA_DEBUG("v4l_sn9c20x_ioctl %02X\n", (unsigned char) cmd
);
1267 if (dev
== NULL
|| vdev
== NULL
)
1270 err
= video_ioctl2(inode
, fp
, cmd
, arg
);
1276 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1277 static const struct v4l2_ioctl_ops sn9c20x_v4l2_ioctl_ops
= {
1278 .vidioc_querycap
= sn9c20x_vidioc_querycap
,
1279 .vidioc_enum_fmt_vid_cap
= sn9c20x_vidioc_enum_fmt_cap
,
1280 .vidioc_try_fmt_vid_cap
= sn9c20x_vidioc_try_fmt_cap
,
1281 .vidioc_s_fmt_vid_cap
= sn9c20x_vidioc_s_fmt_cap
,
1282 .vidioc_g_fmt_vid_cap
= sn9c20x_vidioc_g_fmt_cap
,
1283 .vidioc_enum_input
= sn9c20x_vidioc_enum_input
,
1284 .vidioc_g_input
= sn9c20x_vidioc_g_input
,
1285 .vidioc_s_input
= sn9c20x_vidioc_s_input
,
1286 .vidioc_streamon
= sn9c20x_vidioc_streamon
,
1287 .vidioc_streamoff
= sn9c20x_vidioc_streamoff
,
1288 .vidioc_queryctrl
= sn9c20x_vidioc_queryctrl
,
1289 .vidioc_g_ctrl
= sn9c20x_vidioc_g_ctrl
,
1290 .vidioc_s_ctrl
= sn9c20x_vidioc_s_ctrl
,
1291 .vidioc_g_parm
= sn9c20x_vidioc_g_param
,
1292 .vidioc_s_parm
= sn9c20x_vidioc_s_param
,
1293 .vidioc_reqbufs
= sn9c20x_vidioc_reqbufs
,
1294 .vidioc_qbuf
= sn9c20x_vidioc_qbuf
,
1295 .vidioc_dqbuf
= sn9c20x_vidioc_dqbuf
,
1296 .vidioc_querybuf
= sn9c20x_vidioc_querybuf
,
1301 * @param dev Device structure
1303 * @returns 0 if all is OK
1305 * @brief Register the video device
1307 * This function permits to register the USB device to the video device.
1309 int v4l_sn9c20x_register_video_device(struct usb_sn9c20x
*dev
)
1313 strcpy(dev
->vdev
->name
, DRIVER_DESC
);
1315 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1316 dev
->vdev
->dev
= &dev
->interface
->dev
;
1317 dev
->vdev
->owner
= THIS_MODULE
;
1318 dev
->vdev
->type
= VID_TYPE_CAPTURE
;
1320 dev
->vdev
->parent
= &dev
->interface
->dev
;
1322 dev
->vdev
->current_norm
= 0;
1323 dev
->vdev
->tvnorms
= 0;
1324 dev
->vdev
->fops
= &v4l_sn9c20x_fops
;
1325 dev
->vdev
->release
= video_device_release
;
1326 dev
->vdev
->minor
= -1;
1328 if (log_level
& SN9C20X_DEBUG
)
1329 dev
->vdev
->debug
= V4L2_DEBUG_IOCTL_ARG
;
1331 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1332 dev
->vdev
->vidioc_querycap
= sn9c20x_vidioc_querycap
;
1333 dev
->vdev
->vidioc_enum_fmt_cap
= sn9c20x_vidioc_enum_fmt_cap
;
1334 dev
->vdev
->vidioc_try_fmt_cap
= sn9c20x_vidioc_try_fmt_cap
;
1335 dev
->vdev
->vidioc_s_fmt_cap
= sn9c20x_vidioc_s_fmt_cap
;
1336 dev
->vdev
->vidioc_g_fmt_cap
= sn9c20x_vidioc_g_fmt_cap
;
1337 dev
->vdev
->vidioc_enum_input
= sn9c20x_vidioc_enum_input
;
1338 dev
->vdev
->vidioc_g_input
= sn9c20x_vidioc_g_input
;
1339 dev
->vdev
->vidioc_s_input
= sn9c20x_vidioc_s_input
;
1340 dev
->vdev
->vidioc_streamon
= sn9c20x_vidioc_streamon
;
1341 dev
->vdev
->vidioc_streamoff
= sn9c20x_vidioc_streamoff
;
1342 dev
->vdev
->vidioc_queryctrl
= sn9c20x_vidioc_queryctrl
;
1343 dev
->vdev
->vidioc_g_ctrl
= sn9c20x_vidioc_g_ctrl
;
1344 dev
->vdev
->vidioc_s_ctrl
= sn9c20x_vidioc_s_ctrl
;
1345 dev
->vdev
->vidioc_g_parm
= sn9c20x_vidioc_g_param
;
1346 dev
->vdev
->vidioc_s_parm
= sn9c20x_vidioc_s_param
;
1347 dev
->vdev
->vidioc_reqbufs
= sn9c20x_vidioc_reqbufs
;
1348 dev
->vdev
->vidioc_qbuf
= sn9c20x_vidioc_qbuf
;
1349 dev
->vdev
->vidioc_dqbuf
= sn9c20x_vidioc_dqbuf
;
1350 dev
->vdev
->vidioc_querybuf
= sn9c20x_vidioc_querybuf
;
1352 dev
->vdev
->ioctl_ops
= &sn9c20x_v4l2_ioctl_ops
;
1355 video_set_drvdata(dev
->vdev
, dev
);
1357 sn9c20x_queue_init(&dev
->queue
);
1359 err
= video_register_device(dev
->vdev
, VFL_TYPE_GRABBER
, -1);
1362 UDIA_ERROR("Video register fail !\n");
1364 UDIA_INFO("SN9C20X USB 2.0 Webcam is now controlling "
1365 "video device /dev/video%d\n",
1373 * @param dev Device structure
1375 * @returns 0 if all is OK
1377 * @brief Unregister the video device
1379 * This function permits to unregister the video device.
1381 int v4l_sn9c20x_unregister_video_device(struct usb_sn9c20x
*dev
)
1383 UDIA_INFO("SN9C20X USB 2.0 Webcam releases control of video "
1384 "device /dev/video%d\n", dev
->vdev
->minor
);
1386 video_set_drvdata(dev
->vdev
, NULL
);
1387 video_unregister_device(dev
->vdev
);
1394 * @var v4l_sn9c20x_fops
1396 * This variable contains some callback
1398 static struct file_operations v4l_sn9c20x_fops
= {
1399 .owner
= THIS_MODULE
,
1400 .open
= v4l_sn9c20x_open
,
1401 .release
= v4l_sn9c20x_release
,
1402 .read
= v4l_sn9c20x_read
,
1403 .poll
= v4l_sn9c20x_poll
,
1404 .mmap
= v4l_sn9c20x_mmap
,
1405 .ioctl
= v4l_sn9c20x_ioctl
,
1406 #ifdef CONFIG_COMPAT
1407 .compat_ioctl
= v4l_compat_ioctl32
,