Add autowhitebalance for SOI968
[microdia.git] / sn9c20x-v4l2.c
blobfedf2c5010fde05b842254085d9115c8ad8c9ce2
1 /**
2 * @file sn9c20x-v4l2.c
3 * @author Nicolas VIVIEN
4 * @date 2008-02-01
6 * @brief V4L2 interface and functions
8 * @note Copyright (C) Nicolas VIVIEN
10 * @par Licences
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
15 * any later version.
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>
36 #include <linux/mm.h>
38 #include "sn9c20x.h"
39 #include "sn9c20x-bridge.h"
41 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
42 #include <media/v4l2-ioctl.h>
43 #endif
45 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
46 static struct file_operations v4l_sn9c20x_fops;
47 #else
48 static struct v4l2_file_operations v4l_sn9c20x_fops;
49 #endif
50 /**
51 * @var sn9c20x_controls
52 * List of all V4Lv2 controls supported by the driver
54 static struct v4l2_queryctrl sn9c20x_controls[] = {
56 .id = V4L2_CID_BRIGHTNESS,
57 .type = V4L2_CTRL_TYPE_INTEGER,
58 .name = "Brightness",
59 .minimum = 0,
60 .maximum = 0xff,
61 .step = 1,
64 .id = V4L2_CID_GAMMA,
65 .type = V4L2_CTRL_TYPE_INTEGER,
66 .name = "Gamma",
67 .minimum = 0,
68 .maximum = 0xff,
69 .step = 1,
73 .id = V4L2_CID_SATURATION,
74 .type = V4L2_CTRL_TYPE_INTEGER,
75 .name = "Saturation",
76 .minimum = 0,
77 .maximum = 0xff,
78 .step = 1,
82 .id = V4L2_CID_CONTRAST,
83 .type = V4L2_CTRL_TYPE_INTEGER,
84 .name = "Contrast",
85 .minimum = 0,
86 .maximum = 0xff,
87 .step = 1,
90 .id = V4L2_CID_EXPOSURE,
91 .type = V4L2_CTRL_TYPE_INTEGER,
92 .name = "Exposure",
93 .minimum = 0,
94 .maximum = 0xff,
95 .step = 1,
98 .id = V4L2_CID_GAIN,
99 .type = V4L2_CTRL_TYPE_INTEGER,
100 .name = "Gain",
101 .minimum = 0,
102 .maximum = 0xff,
103 .step = 1,
106 .id = V4L2_CID_HFLIP,
107 .type = V4L2_CTRL_TYPE_BOOLEAN,
108 .name = "Horizontal flip",
109 .minimum = 0,
110 .maximum = 1,
111 .step = 1,
114 .id = V4L2_CID_VFLIP,
115 .type = V4L2_CTRL_TYPE_BOOLEAN,
116 .name = "Vertical flip",
117 .minimum = 0,
118 .maximum = 1,
119 .step = 1,
122 .id = V4L2_CID_SHARPNESS,
123 .type = V4L2_CTRL_TYPE_INTEGER,
124 .name = "Sharpness",
125 .minimum = 0,
126 .maximum = 0x3f,
127 .step = 1,
130 .id = V4L2_CID_RED_BALANCE,
131 .type = V4L2_CTRL_TYPE_INTEGER,
132 .name = "Red Balance",
133 .minimum = 0,
134 .maximum = 0x7f,
135 .step = 1,
138 .id = V4L2_CID_BLUE_BALANCE,
139 .type = V4L2_CTRL_TYPE_INTEGER,
140 .name = "Blue Balance",
141 .minimum = 0,
142 .maximum = 0x7f,
143 .step = 1,
145 /* According to v4l2 specs auto exposure should be a 4 step value.
146 * This make little since for webcams however so a boolean is used
147 * instead.
150 .id = V4L2_CID_EXPOSURE_AUTO,
151 .type = V4L2_CTRL_TYPE_BOOLEAN,
152 .name = "Automatic exposure control",
153 .minimum = 0,
154 .maximum = 1,
155 .step = 1,
158 .id = V4L2_CID_AUTOGAIN,
159 .type = V4L2_CTRL_TYPE_BOOLEAN,
160 .name = "Automatic gain control",
161 .minimum = 0,
162 .maximum = 1,
163 .step = 1,
166 .id = V4L2_CID_AUTO_WHITE_BALANCE,
167 .type = V4L2_CTRL_TYPE_BOOLEAN,
168 .name = "Automatic whitbalance control",
169 .minimum = 0,
170 .maximum = 1,
171 .step = 1,
175 void v4l2_set_control_default(struct usb_sn9c20x *dev, __u32 ctrl, __u16 value)
177 int i;
178 for (i = 0; i < ARRAY_SIZE(sn9c20x_controls); i++) {
179 if (sn9c20x_controls[i].id == ctrl) {
180 sn9c20x_controls[i].default_value = value;
181 sn9c20x_set_camera_control(dev,
182 ctrl,
183 value);
184 break;
189 void v4l_add_jpegheader(struct usb_sn9c20x *dev, __u8 *buffer,
190 __u32 buffer_size)
192 static __u8 jpeg_header[589] = {
193 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
194 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
195 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
196 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
197 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
198 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
199 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
200 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
201 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
202 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
203 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
204 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
205 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
206 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
207 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
209 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
210 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
211 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
212 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
213 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
214 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
215 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
216 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
217 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
218 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
219 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
220 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
221 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
222 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
223 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
224 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
225 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
226 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
227 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
228 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
229 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
230 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
231 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
232 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
233 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
234 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
235 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
236 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
237 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
238 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
239 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
240 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
241 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
242 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
243 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
244 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
245 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
246 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
247 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
248 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
249 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
250 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
251 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
253 static __u8 qtable1[128] = {
254 0x0d, 0x08, 0x08, 0x0d, 0x08, 0x08, 0x0d, 0x0d,
255 0x0d, 0x0d, 0x11, 0x0d, 0x0d, 0x11, 0x15, 0x21,
256 0x15, 0x15, 0x11, 0x11, 0x15, 0x2a, 0x1d, 0x1d,
257 0x19, 0x21, 0x32, 0x2a, 0x32, 0x32, 0x2e, 0x2a,
258 0x2e, 0x2e, 0x36, 0x3a, 0x4b, 0x43, 0x36, 0x3a,
259 0x47, 0x3a, 0x2e, 0x2e, 0x43, 0x5c, 0x43, 0x47,
260 0x4f, 0x54, 0x58, 0x58, 0x58, 0x32, 0x3f, 0x60,
261 0x64, 0x5c, 0x54, 0x64, 0x4b, 0x54, 0x58, 0x54,
262 0x0d, 0x11, 0x11, 0x15, 0x11, 0x15, 0x26, 0x15,
263 0x15, 0x26, 0x54, 0x36, 0x2e, 0x36, 0x54, 0x54,
264 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
265 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
266 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
267 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
268 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
269 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54
272 jpeg_header[6] = 0x00;
273 jpeg_header[71] = 0x01;
274 memcpy(jpeg_header + 7, qtable1, 64);
275 memcpy(jpeg_header + 8 + 64, qtable1+64, 64);
276 jpeg_header[564] = dev->vsettings.format.width & 0xFF;
277 jpeg_header[563] = (dev->vsettings.format.width >> 8) & 0xFF;
278 jpeg_header[562] = dev->vsettings.format.height & 0xFF;
279 jpeg_header[561] = (dev->vsettings.format.height >> 8) & 0xFF;
280 jpeg_header[567] = 0x21;
282 memmove(buffer+589, buffer, buffer_size);
283 memcpy(buffer, jpeg_header, 589);
286 * @brief Get V4L privileges
288 * @param file
290 * @return 0 or negative error code
293 int v4l_get_privileges(struct file *file)
295 struct usb_sn9c20x *dev;
296 int ret = 0;
298 dev = video_get_drvdata(video_devdata(file));
300 if (dev->owner == file)
301 return 0;
303 mutex_lock(&open_lock);
304 if (dev->owner != NULL) {
305 ret = -EBUSY;
306 goto done;
308 dev->owner = file;
309 done:
310 mutex_unlock(&open_lock);
311 return ret;
315 * @brief Check whether there are V4L privileges
317 * @param file
319 * @return 0 or 1
322 int v4l_has_privileges(struct file *file)
324 struct usb_sn9c20x *dev;
325 int ret = 0;
327 dev = video_get_drvdata(video_devdata(file));
329 if (dev->owner == file)
330 ret = 1;
332 return ret;
336 * @brief Drop V4L privileges
338 * @param file
341 void v4l_drop_privileges(struct file *file)
343 struct usb_sn9c20x *dev;
345 dev = video_get_drvdata(video_devdata(file));
347 if (dev->owner == file)
348 dev->owner = NULL;
352 * @brief Enable video stream
354 * @param dev Pointer to device structure
355 * @param mode Mode for video stream
357 * @returns 0 or negative error value
360 int v4l2_enable_video(struct usb_sn9c20x *dev, int mode)
362 int ret;
364 if (mode == SN9C20X_MODE_IDLE) {
365 sn9c20x_enable_video(dev, 0);
366 usb_sn9c20x_uninit_urbs(dev);
367 sn9c20x_queue_enable(&dev->queue, 0);
368 dev->mode = mode;
369 return 0;
372 if (dev->mode != SN9C20X_MODE_IDLE)
373 return -EBUSY;
375 if (sn9c20x_queue_enable(&dev->queue, 1) < 0)
376 return -EBUSY;
378 ret = usb_sn9c20x_init_urbs(dev);
380 if (ret)
381 return ret;
383 sn9c20x_enable_video(dev, 1);
384 dev->mode = mode;
386 if (dev->vsettings.format.pixelformat == V4L2_PIX_FMT_JPEG)
387 dev->queue.flags &= ~SN9C20X_QUEUE_DROP_INCOMPLETE;
388 else
389 dev->queue.flags |= SN9C20X_QUEUE_DROP_INCOMPLETE;
391 return 0;
395 * @param inode Pointer on an inode
396 * @param fp File pointer
398 * @returns 0 if all is OK
400 * @brief Open the video device
402 * This function permits to open a video device (/dev/videoX)
404 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
405 static int v4l_sn9c20x_open(struct inode *inode, struct file *fp)
406 #else
407 static int v4l_sn9c20x_open(struct file *fp)
408 #endif
410 int ret = 0;
412 struct usb_sn9c20x *dev;
413 struct video_device *vdev;
415 mutex_lock(&open_lock);
417 vdev = video_devdata(fp);
418 dev = video_get_drvdata(video_devdata(fp));
420 fp->private_data = vdev;
422 kref_get(&dev->vopen);
424 mutex_unlock(&open_lock);
425 return ret;
430 * @param inode Pointer on inode
431 * @param fp File pointer
433 * @returns 0 if all is OK
435 * @brief Release an opened file.
437 * This function permits to release an opened file with the 'open' method.
439 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
440 static int v4l_sn9c20x_release(struct inode *inode, struct file *fp)
441 #else
442 static int v4l_sn9c20x_release(struct file *fp)
443 #endif
445 struct usb_sn9c20x *dev;
446 struct video_device *vdev;
448 mutex_lock(&open_lock);
450 vdev = video_devdata(fp);
451 dev = video_get_drvdata(video_devdata(fp));
453 if (v4l_has_privileges(fp)) {
454 v4l2_enable_video(dev, SN9C20X_MODE_IDLE);
456 mutex_lock(&dev->queue.mutex);
457 sn9c20x_free_buffers(&dev->queue);
458 mutex_unlock(&dev->queue.mutex);
461 v4l_drop_privileges(fp);
463 kref_put(&dev->vopen, usb_sn9c20x_delete);
465 mutex_unlock(&open_lock);
466 return 0;
471 * @param fp File pointer
473 * @retval buf Buffer in user space
474 * @retval count
475 * @retval f_pos
477 * @returns Count value
479 * @brief Read the video device
481 * This function is called by the application is reading the video device.
483 static ssize_t v4l_sn9c20x_read(struct file *fp, char __user *buf,
484 size_t count, loff_t *f_pos)
486 int i, ret;
487 int nbuffers;
488 struct v4l2_buffer buffer;
489 struct usb_sn9c20x *dev;
491 dev = video_get_drvdata(video_devdata(fp));
493 ret = v4l_get_privileges(fp);
494 if (ret < 0)
495 return ret;
497 if (dev->mode != SN9C20X_MODE_IDLE &&
498 dev->mode != SN9C20X_MODE_READ)
499 return -EBUSY;
501 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
502 buffer.memory = V4L2_MEMORY_MMAP;
503 if (dev->mode == SN9C20X_MODE_IDLE) {
504 nbuffers = sn9c20x_alloc_buffers(&dev->queue, 2,
505 dev->vsettings.format.sizeimage);
506 if (nbuffers < 0)
507 return nbuffers;
509 for (i = 0; i < nbuffers; i++) {
510 buffer = dev->queue.buffer[i].buf;
511 sn9c20x_queue_buffer(&dev->queue, &buffer);
514 ret = v4l2_enable_video(dev, SN9C20X_MODE_READ);
515 if (ret < 0)
516 return ret;
519 dev_sn9c20x_call_constantly(dev);
521 if (dev->queue.read_buffer == NULL) {
522 ret = sn9c20x_dequeue_buffer(&dev->queue, &buffer,
523 fp->f_flags & O_NONBLOCK);
524 if (ret < 0)
525 return ret;
527 if (dev->vsettings.format.pixelformat == V4L2_PIX_FMT_JPEG) {
528 UDIA_DEBUG("Adding JPEG Header\n");
529 v4l_add_jpegheader(dev, dev->queue.mem + buffer.m.offset,
530 buffer.bytesused);
531 buffer.bytesused += 589;
534 dev->queue.read_buffer = &dev->queue.buffer[buffer.index];
535 } else {
536 buffer = dev->queue.read_buffer->buf;
539 count = min((size_t)(buffer.bytesused - *f_pos), count);
540 if (copy_to_user(buf, dev->queue.mem + buffer.m.offset + *f_pos, count))
541 return -EFAULT;
543 *f_pos += count;
544 if (*f_pos >= buffer.bytesused) {
545 dev->queue.read_buffer = NULL;
546 sn9c20x_queue_buffer(&dev->queue, &buffer);
547 *f_pos = 0;
549 return count;
554 * @param fp File pointer
555 * @param wait
557 * @returns 0 if all is OK
559 * @brief Polling function
561 static unsigned int v4l_sn9c20x_poll(struct file *fp, poll_table *wait)
563 struct usb_sn9c20x *dev;
564 struct video_device *vdev;
566 vdev = video_devdata(fp);
567 dev = video_get_drvdata(video_devdata(fp));
569 UDIA_STREAM("Poll\n");
571 if (vdev == NULL || dev == NULL)
572 return -EFAULT;
574 return sn9c20x_queue_poll(&dev->queue, fp, wait);
578 * @param vma
581 static void sn9c20x_vm_open(struct vm_area_struct *vma)
583 struct sn9c20x_buffer *buffer = vma->vm_private_data;
584 buffer->vma_use_count++;
589 * @param vma
592 static void sn9c20x_vm_close(struct vm_area_struct *vma)
594 struct sn9c20x_buffer *buffer = vma->vm_private_data;
595 buffer->vma_use_count--;
598 struct vm_operations_struct sn9c20x_vm_ops = {
599 .open = sn9c20x_vm_open,
600 .close = sn9c20x_vm_close
604 * @param fp File pointer
605 * @param vma VMA structure
607 * @returns 0 if all is OK
609 * @brief Memory map
611 * This function permits to map a memory space.
613 static int v4l_sn9c20x_mmap(struct file *fp, struct vm_area_struct *vma)
615 struct page *page;
616 unsigned long addr, start, size;
617 unsigned int i;
618 int ret = 0;
620 struct usb_sn9c20x *dev;
621 struct video_device *vdev;
622 struct sn9c20x_buffer *buffer = NULL;
624 vdev = video_devdata(fp);
625 dev = video_get_drvdata(video_devdata(fp));
627 UDIA_STREAM("mmap\n");
629 start = vma->vm_start;
630 size = vma->vm_end - vma->vm_start;
632 mutex_lock(&dev->queue.mutex);
634 for (i = 0; i < dev->queue.count; ++i) {
635 buffer = &dev->queue.buffer[i];
636 if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
637 break;
640 if (i == dev->queue.count || size != dev->queue.buf_size) {
641 ret = -EINVAL;
642 goto done;
645 vma->vm_flags |= VM_IO;
647 addr = (unsigned long)dev->queue.mem + buffer->buf.m.offset;
648 while (size > 0) {
649 page = vmalloc_to_page((void *)addr);
650 ret = vm_insert_page(vma, start, page);
651 if (ret < 0)
652 goto done;
654 start += PAGE_SIZE;
655 addr += PAGE_SIZE;
656 size -= PAGE_SIZE;
659 vma->vm_ops = &sn9c20x_vm_ops;
660 vma->vm_private_data = buffer;
661 sn9c20x_vm_open(vma);
662 done:
663 mutex_unlock(&dev->queue.mutex);
664 return ret;
668 * @param file
669 * @param priv
670 * @param cap
672 * @return 0
675 int sn9c20x_vidioc_querycap(struct file *file, void *priv,
676 struct v4l2_capability *cap)
678 struct usb_sn9c20x *dev;
680 dev = video_get_drvdata(priv);
682 UDIA_DEBUG("VIDIOC_QUERYCAP\n");
684 strlcpy(cap->driver, "sn9c20x", sizeof(cap->driver));
685 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
686 | V4L2_CAP_READWRITE;
687 cap->version = (__u32) DRIVER_VERSION_NUM,
688 strlcpy(cap->card, dev->vdev->name, sizeof(cap->card));
690 if (usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)) < 0)
691 strlcpy(cap->bus_info, dev->vdev->name, sizeof(cap->bus_info));
692 return 0;
696 * @param file
697 * @param priv
698 * @param input
700 * @return 0 or negative error code
703 int sn9c20x_vidioc_enum_input(struct file *file, void *priv,
704 struct v4l2_input *input)
706 UDIA_DEBUG("VIDIOC_ENUMINPUT %d\n", input->index);
708 if (input->index)
709 return -EINVAL;
711 strlcpy(input->name, "Webcam", sizeof(input->name));
712 input->type = V4L2_INPUT_TYPE_CAMERA;
713 input->std = 0;
715 return 0;
719 * @param file
720 * @param priv
721 * @param index
723 * @return 0 or negative error code
726 int sn9c20x_vidioc_g_input(struct file *file, void *priv, unsigned int *index)
728 UDIA_DEBUG("GET INPUT %d\n", *index);
730 if (index)
731 return -EINVAL;
733 return 0;
737 * @param file
738 * @param priv
739 * @param index
741 * @return 0 or negative error code
744 int sn9c20x_vidioc_s_input(struct file *file, void *priv, unsigned int index)
746 UDIA_DEBUG("SET INPUT %d\n", index);
748 if (v4l_get_privileges(file) < 0)
749 return -EBUSY;
751 if (index != 0)
752 return -EINVAL;
754 return 0;
758 * @param file
759 * @param priv
760 * @param ctrl
762 * @return 0 or negative error code
765 int sn9c20x_vidioc_queryctrl(struct file *file, void *priv,
766 struct v4l2_queryctrl *ctrl)
768 int i;
769 int ret = 0;
770 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
771 int min;
772 __u32 idnew, idlast;
773 #endif
774 struct usb_sn9c20x *dev;
776 dev = video_get_drvdata(priv);
778 UDIA_DEBUG("VIDIOC_QUERYCTRL id = %d\n", ctrl->id);
780 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
781 if (ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
782 min = 0;
783 idnew = V4L2_CTRL_FLAG_NEXT_CTRL;
784 idlast = ctrl->id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
785 for (i = 0; i < ARRAY_SIZE(sn9c20x_controls); i++) {
786 if ((sn9c20x_controls[i].id < idnew) &&
787 (sn9c20x_controls[i].id > idlast)) {
788 idnew = sn9c20x_controls[i].id;
789 min = i;
792 if (idnew != V4L2_CTRL_FLAG_NEXT_CTRL) {
793 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
794 memcpy(ctrl, &sn9c20x_controls[min],
795 sizeof(struct v4l2_queryctrl));
796 goto done;
797 } else {
798 goto error;
800 } else
801 #endif
803 for (i = 0; i < ARRAY_SIZE(sn9c20x_controls); i++) {
804 if (sn9c20x_controls[i].id == ctrl->id) {
805 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
806 memcpy(ctrl, &sn9c20x_controls[i],
807 sizeof(struct v4l2_queryctrl));
808 goto done;
813 error:
814 ret = -EINVAL;
815 done:
816 if ((ctrl->id == V4L2_CID_GAIN && dev->vsettings.auto_gain) ||
817 (ctrl->id == V4L2_CID_EXPOSURE && dev->vsettings.auto_exposure) ||
818 ((ctrl->id == V4L2_CID_BLUE_BALANCE ||
819 ctrl->id == V4L2_CID_RED_BALANCE) &&
820 dev->vsettings.auto_whitebalance)) {
821 ctrl->flags |= V4L2_CTRL_FLAG_GRABBED;
823 return ret;
827 * @param file
828 * @param priv
829 * @param ctrl
831 * @return 0 or negative error code
834 int sn9c20x_vidioc_g_ctrl(struct file *file, void *priv,
835 struct v4l2_control *ctrl)
837 struct usb_sn9c20x *dev;
839 dev = video_get_drvdata(priv);
841 UDIA_DEBUG("GET CTRL id=%d\n", ctrl->id);
843 switch (ctrl->id) {
844 case V4L2_CID_BRIGHTNESS:
845 ctrl->value = dev->vsettings.brightness;
846 break;
848 case V4L2_CID_EXPOSURE:
849 ctrl->value = dev->vsettings.exposure;
850 break;
852 case V4L2_CID_GAIN:
853 ctrl->value = dev->vsettings.gain;
854 break;
856 case V4L2_CID_GAMMA:
857 ctrl->value = dev->vsettings.gamma;
858 break;
860 case V4L2_CID_SATURATION:
861 ctrl->value = dev->vsettings.colour;
862 break;
864 case V4L2_CID_CONTRAST:
865 ctrl->value = dev->vsettings.contrast;
866 break;
868 case V4L2_CID_HFLIP:
869 ctrl->value = dev->vsettings.hflip;
870 break;
872 case V4L2_CID_VFLIP:
873 ctrl->value = dev->vsettings.vflip;
874 break;
876 case V4L2_CID_SHARPNESS:
877 ctrl->value = dev->vsettings.sharpness;
878 break;
880 case V4L2_CID_RED_BALANCE:
881 ctrl->value = dev->vsettings.red_gain;
882 break;
884 case V4L2_CID_BLUE_BALANCE:
885 ctrl->value = dev->vsettings.blue_gain;
886 break;
888 case V4L2_CID_EXPOSURE_AUTO:
889 ctrl->value = dev->vsettings.auto_exposure;
890 break;
892 case V4L2_CID_AUTOGAIN:
893 ctrl->value = dev->vsettings.auto_gain;
894 break;
896 case V4L2_CID_AUTO_WHITE_BALANCE:
897 ctrl->value = dev->vsettings.auto_whitebalance;
898 break;
900 default:
901 return -EINVAL;
903 return 0;
907 * @brief Apply v4l2 settings on camera
909 * @param file
910 * @param priv
911 * @param ctrl V4L2 control structure
913 * @returns 0 or negative error value
916 int sn9c20x_vidioc_s_ctrl(struct file *file, void *priv,
917 struct v4l2_control *ctrl)
919 struct usb_sn9c20x *dev;
921 dev = video_get_drvdata(priv);
923 UDIA_DEBUG("SET CTRL id=%d value=%d\n", ctrl->id, ctrl->value);
925 if ((ctrl->id == V4L2_CID_GAIN && dev->vsettings.auto_gain) ||
926 (ctrl->id == V4L2_CID_EXPOSURE && dev->vsettings.auto_exposure) ||
927 ((ctrl->id == V4L2_CID_BLUE_BALANCE ||
928 ctrl->id == V4L2_CID_RED_BALANCE) &&
929 dev->vsettings.auto_whitebalance)) {
930 return -EBUSY;
933 return sn9c20x_set_camera_control(dev,
934 ctrl->id,
935 ctrl->value);
939 * @param file
940 * @param priv
941 * @param fmt
943 * @return 0 or negative error code
946 int sn9c20x_vidioc_enum_fmt_cap(struct file *file, void *priv,
947 struct v4l2_fmtdesc *fmt)
949 struct usb_sn9c20x *dev;
951 dev = video_get_drvdata(priv);
953 UDIA_DEBUG("VIDIOC_ENUM_FMT %d\n", fmt->index);
955 if (fmt->index >= SN9C20X_N_FMTS)
956 return -EINVAL;
958 fmt->flags = 0;
959 fmt->pixelformat = sn9c20x_fmts[fmt->index].pix_fmt;
961 if (fmt->pixelformat == V4L2_PIX_FMT_JPEG && dev->jpeg == 0)
962 return -EINVAL;
964 memcpy(fmt->description, sn9c20x_fmts[fmt->index].desc, 32);
966 return 0;
970 * @param file
971 * @param priv
972 * @param fmt
974 * @return 0 or negative error code
977 int sn9c20x_vidioc_try_fmt_cap(struct file *file, void *priv,
978 struct v4l2_format *fmt)
980 int index;
981 struct usb_sn9c20x *dev;
983 dev = video_get_drvdata(priv);
984 UDIA_DEBUG("TRY FMT %d\n", fmt->type);
986 /* when this code is used prevents mplayer from setting outfmt
987 if(fmt->fmt.pix.field != V4L2_FIELD_NONE)
988 return -EINVAL;
990 if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG && dev->jpeg == 0)
991 return -EINVAL;
993 for (index = 0; index < SN9C20X_N_FMTS; index++)
994 if (sn9c20x_fmts[index].pix_fmt == fmt->fmt.pix.pixelformat)
995 break;
997 if (index >= SN9C20X_N_FMTS)
998 return -EINVAL;
1000 sn9c20x_get_closest_resolution(dev, &fmt->fmt.pix.width,
1001 &fmt->fmt.pix.height);
1003 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width *
1004 sn9c20x_fmts[index].depth / 8;
1006 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
1007 fmt->fmt.pix.bytesperline;
1009 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
1010 fmt->fmt.pix.priv = index;
1012 return 0;
1016 * @param file
1017 * @param priv
1018 * @param fmt
1020 * @return 0
1023 int sn9c20x_vidioc_g_fmt_cap(struct file *file, void *priv,
1024 struct v4l2_format *fmt)
1026 struct usb_sn9c20x *dev;
1028 dev = video_get_drvdata(priv);
1030 UDIA_DEBUG("GET FMT %d\n", fmt->type);
1032 memcpy(&(fmt->fmt.pix), &(dev->vsettings.format), sizeof(fmt->fmt.pix));
1035 return 0;
1039 * @param file
1040 * @param priv
1041 * @param fmt
1043 * @return 0 or negative error code
1046 int sn9c20x_vidioc_s_fmt_cap(struct file *file, void *priv,
1047 struct v4l2_format *fmt)
1049 struct usb_sn9c20x *dev;
1050 int ret;
1052 dev = video_get_drvdata(priv);
1054 UDIA_DEBUG("SET FMT %d : %d\n", fmt->type, fmt->fmt.pix.pixelformat);
1056 if (v4l_get_privileges(file) < 0)
1057 return -EBUSY;
1059 if (sn9c20x_queue_streaming(&dev->queue))
1060 return -EBUSY;
1062 ret = sn9c20x_vidioc_try_fmt_cap(file, priv, fmt);
1063 if (ret)
1064 return -EINVAL;
1066 sn9c20x_set_resolution(dev, fmt->fmt.pix.width, fmt->fmt.pix.height);
1067 sn9c20x_set_format(dev, fmt->fmt.pix.pixelformat);
1068 memcpy(&(dev->vsettings.format), &(fmt->fmt.pix), sizeof(fmt->fmt.pix));
1070 return 0;
1074 * @param file
1075 * @param priv
1076 * @param request
1078 * @return 0 or negative error code
1081 int sn9c20x_vidioc_reqbufs(struct file *file, void *priv,
1082 struct v4l2_requestbuffers *request)
1084 int ret = 0;
1085 struct usb_sn9c20x *dev;
1087 dev = video_get_drvdata(priv);
1089 if (v4l_get_privileges(file) < 0) {
1090 ret = -EBUSY;
1091 goto done;
1094 if (request->memory != V4L2_MEMORY_MMAP ||
1095 request->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1096 ret = -EINVAL;
1097 goto done;
1100 if (sn9c20x_queue_streaming(&dev->queue)) {
1101 ret = -EBUSY;
1102 goto done;
1105 ret = sn9c20x_alloc_buffers(&dev->queue, request->count,
1106 dev->vsettings.format.sizeimage);
1107 if (ret < 0)
1108 goto done;
1110 request->count = ret;
1111 ret = 0;
1112 UDIA_DEBUG("Buffers Allocated %d\n", request->count);
1113 done:
1114 return ret;
1118 * @param file
1119 * @param priv
1120 * @param buffer
1122 * @return 0 or negative error code
1125 int sn9c20x_vidioc_querybuf(struct file *file, void *priv,
1126 struct v4l2_buffer *buffer)
1128 struct usb_sn9c20x *dev;
1130 dev = video_get_drvdata(priv);
1132 UDIA_DEBUG("QUERY BUFFERS %d %d\n", buffer->index, dev->queue.count);
1134 if (buffer->memory != V4L2_MEMORY_MMAP ||
1135 buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1136 return -EINVAL;
1138 if (!v4l_has_privileges(file))
1139 return -EBUSY;
1141 return sn9c20x_query_buffer(&dev->queue, buffer);
1145 * @param file
1146 * @param priv
1147 * @param buffer
1149 * @return 0 or negative error code
1152 int sn9c20x_vidioc_qbuf(struct file *file, void *priv,
1153 struct v4l2_buffer *buffer)
1155 struct usb_sn9c20x *dev;
1157 dev = video_get_drvdata(priv);
1159 UDIA_DEBUG("VIDIOC_QBUF\n");
1161 if (!v4l_has_privileges(file))
1162 return -EBUSY;
1164 return sn9c20x_queue_buffer(&dev->queue, buffer);
1168 * @param file
1169 * @param priv
1170 * @param buffer
1172 * @return 0 or negative error code
1175 int sn9c20x_vidioc_dqbuf(struct file *file, void *priv,
1176 struct v4l2_buffer *buffer)
1178 struct usb_sn9c20x *dev;
1179 int ret = 0;
1181 dev = video_get_drvdata(priv);
1183 UDIA_DEBUG("VIDIOC_DQBUF\n");
1185 if (!v4l_has_privileges(file))
1186 return -EBUSY;
1188 ret = sn9c20x_dequeue_buffer(&dev->queue, buffer,
1189 file->f_flags & O_NONBLOCK);
1190 if (ret < 0)
1191 return ret;
1193 if (dev->vsettings.format.pixelformat == V4L2_PIX_FMT_JPEG) {
1194 UDIA_DEBUG("Adding JPEG Header\n");
1195 v4l_add_jpegheader(dev, dev->queue.mem + buffer->m.offset,
1196 buffer->bytesused);
1197 buffer->bytesused += 589;
1200 dev_sn9c20x_call_constantly(dev);
1202 return ret;
1206 * @param file
1207 * @param priv
1208 * @param type
1210 * @return 0 or negative error code
1213 int sn9c20x_vidioc_streamon(struct file *file, void *priv,
1214 enum v4l2_buf_type type)
1216 struct usb_sn9c20x *dev;
1218 dev = video_get_drvdata(priv);
1220 UDIA_DEBUG("VIDIOC_STREAMON\n");
1222 if (!v4l_has_privileges(file))
1223 return -EBUSY;
1225 if (dev->mode != SN9C20X_MODE_IDLE)
1226 return -EBUSY;
1228 return v4l2_enable_video(dev, SN9C20X_MODE_STREAM);
1232 * @param file
1233 * @param priv
1234 * @param type
1236 * @return 0 or negative error code
1239 int sn9c20x_vidioc_streamoff(struct file *file, void *priv,
1240 enum v4l2_buf_type type)
1242 struct usb_sn9c20x *dev;
1244 dev = video_get_drvdata(priv);
1246 UDIA_DEBUG("VIDIOC_STREAMOFF\n");
1248 if (!v4l_has_privileges(file))
1249 return -EBUSY;
1251 return v4l2_enable_video(dev, SN9C20X_MODE_IDLE);
1255 * @param file
1256 * @param priv
1257 * @param param
1259 * @return 0 or negative error code
1262 int sn9c20x_vidioc_g_param(struct file *file, void *priv,
1263 struct v4l2_streamparm *param)
1265 struct usb_sn9c20x *dev;
1268 dev = video_get_drvdata(priv);
1270 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1271 return -EINVAL;
1273 param->parm.capture.capability = 0;
1274 param->parm.capture.capturemode = 0;
1275 param->parm.capture.timeperframe.numerator = 1;
1276 param->parm.capture.timeperframe.denominator = 30;
1277 param->parm.capture.readbuffers = 2;
1278 param->parm.capture.extendedmode = 0;
1280 return 0;
1284 * @param file
1285 * @param priv
1286 * @param param
1288 * @return 0 or negative error code
1291 int sn9c20x_vidioc_s_param(struct file *file, void *priv,
1292 struct v4l2_streamparm *param)
1294 struct usb_sn9c20x *dev;
1296 dev = video_get_drvdata(priv);
1298 if (v4l_get_privileges(file))
1299 return -EBUSY;
1301 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1302 return -EINVAL;
1304 return 0;
1308 * @param inode Inode pointer
1309 * @param fp File pointer
1310 * @param cmd Command
1311 * @param arg Arguements of the command
1313 * @returns 0 if all is OK
1315 * @brief Manage IOCTL
1317 * This function permits to manage all the IOCTL from the application.
1319 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1320 static int v4l_sn9c20x_ioctl(struct inode *inode, struct file *fp,
1321 unsigned int cmd, unsigned long arg)
1322 #else
1323 static long v4l_sn9c20x_ioctl(struct file *fp,
1324 unsigned int cmd, unsigned long arg)
1325 #endif
1327 int err;
1328 struct usb_sn9c20x *dev;
1329 struct video_device *vdev;
1331 vdev = video_devdata(fp);
1332 dev = video_get_drvdata(video_devdata(fp));
1334 UDIA_DEBUG("v4l_sn9c20x_ioctl %02X\n", (unsigned char) cmd);
1336 if (dev == NULL || vdev == NULL)
1337 return -EFAULT;
1339 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1340 err = video_ioctl2(inode, fp, cmd, arg);
1341 #else
1342 err = video_ioctl2(fp, cmd, arg);
1343 #endif
1345 return err;
1349 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1350 static const struct v4l2_ioctl_ops sn9c20x_v4l2_ioctl_ops = {
1351 .vidioc_querycap = sn9c20x_vidioc_querycap,
1352 .vidioc_enum_fmt_vid_cap = sn9c20x_vidioc_enum_fmt_cap,
1353 .vidioc_try_fmt_vid_cap = sn9c20x_vidioc_try_fmt_cap,
1354 .vidioc_s_fmt_vid_cap = sn9c20x_vidioc_s_fmt_cap,
1355 .vidioc_g_fmt_vid_cap = sn9c20x_vidioc_g_fmt_cap,
1356 .vidioc_enum_input = sn9c20x_vidioc_enum_input,
1357 .vidioc_g_input = sn9c20x_vidioc_g_input,
1358 .vidioc_s_input = sn9c20x_vidioc_s_input,
1359 .vidioc_streamon = sn9c20x_vidioc_streamon,
1360 .vidioc_streamoff = sn9c20x_vidioc_streamoff,
1361 .vidioc_queryctrl = sn9c20x_vidioc_queryctrl,
1362 .vidioc_g_ctrl = sn9c20x_vidioc_g_ctrl,
1363 .vidioc_s_ctrl = sn9c20x_vidioc_s_ctrl,
1364 .vidioc_g_parm = sn9c20x_vidioc_g_param,
1365 .vidioc_s_parm = sn9c20x_vidioc_s_param,
1366 .vidioc_reqbufs = sn9c20x_vidioc_reqbufs,
1367 .vidioc_qbuf = sn9c20x_vidioc_qbuf,
1368 .vidioc_dqbuf = sn9c20x_vidioc_dqbuf,
1369 .vidioc_querybuf = sn9c20x_vidioc_querybuf,
1371 #endif
1374 * @param dev Device structure
1376 * @returns 0 if all is OK
1378 * @brief Register the video device
1380 * This function permits to register the USB device to the video device.
1382 int v4l_sn9c20x_register_video_device(struct usb_sn9c20x *dev)
1384 int err;
1386 strcpy(dev->vdev->name, DRIVER_DESC);
1388 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1389 dev->vdev->dev = &dev->interface->dev;
1390 dev->vdev->owner = THIS_MODULE;
1391 dev->vdev->type = VID_TYPE_CAPTURE;
1392 #else
1393 dev->vdev->parent = &dev->interface->dev;
1394 #endif
1395 dev->vdev->current_norm = 0;
1396 dev->vdev->tvnorms = 0;
1397 dev->vdev->fops = &v4l_sn9c20x_fops;
1398 dev->vdev->release = video_device_release;
1399 dev->vdev->minor = -1;
1401 if (log_level & SN9C20X_DEBUG)
1402 dev->vdev->debug = V4L2_DEBUG_IOCTL_ARG;
1404 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1405 dev->vdev->vidioc_querycap = sn9c20x_vidioc_querycap;
1406 dev->vdev->vidioc_enum_fmt_cap = sn9c20x_vidioc_enum_fmt_cap;
1407 dev->vdev->vidioc_try_fmt_cap = sn9c20x_vidioc_try_fmt_cap;
1408 dev->vdev->vidioc_s_fmt_cap = sn9c20x_vidioc_s_fmt_cap;
1409 dev->vdev->vidioc_g_fmt_cap = sn9c20x_vidioc_g_fmt_cap;
1410 dev->vdev->vidioc_enum_input = sn9c20x_vidioc_enum_input;
1411 dev->vdev->vidioc_g_input = sn9c20x_vidioc_g_input;
1412 dev->vdev->vidioc_s_input = sn9c20x_vidioc_s_input;
1413 dev->vdev->vidioc_streamon = sn9c20x_vidioc_streamon;
1414 dev->vdev->vidioc_streamoff = sn9c20x_vidioc_streamoff;
1415 dev->vdev->vidioc_queryctrl = sn9c20x_vidioc_queryctrl;
1416 dev->vdev->vidioc_g_ctrl = sn9c20x_vidioc_g_ctrl;
1417 dev->vdev->vidioc_s_ctrl = sn9c20x_vidioc_s_ctrl;
1418 dev->vdev->vidioc_g_parm = sn9c20x_vidioc_g_param;
1419 dev->vdev->vidioc_s_parm = sn9c20x_vidioc_s_param;
1420 dev->vdev->vidioc_reqbufs = sn9c20x_vidioc_reqbufs;
1421 dev->vdev->vidioc_qbuf = sn9c20x_vidioc_qbuf;
1422 dev->vdev->vidioc_dqbuf = sn9c20x_vidioc_dqbuf;
1423 dev->vdev->vidioc_querybuf = sn9c20x_vidioc_querybuf;
1424 #else
1425 dev->vdev->ioctl_ops = &sn9c20x_v4l2_ioctl_ops;
1426 #endif
1428 video_set_drvdata(dev->vdev, dev);
1430 sn9c20x_queue_init(&dev->queue);
1432 err = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
1434 if (err)
1435 UDIA_ERROR("Video register fail !\n");
1436 else
1437 UDIA_INFO("Webcam device %04X:%04X is now controlling video "
1438 "device /dev/video%d\n",
1439 le16_to_cpu(dev->udev->descriptor.idVendor),
1440 le16_to_cpu(dev->udev->descriptor.idProduct),
1441 dev->vdev->minor);
1443 return err;
1448 * @param dev Device structure
1450 * @returns 0 if all is OK
1452 * @brief Unregister the video device
1454 * This function permits to unregister the video device.
1456 int v4l_sn9c20x_unregister_video_device(struct usb_sn9c20x *dev)
1458 UDIA_INFO("SN9C20X USB 2.0 Webcam releases control of video "
1459 "device /dev/video%d\n", dev->vdev->minor);
1461 video_set_drvdata(dev->vdev, NULL);
1462 video_unregister_device(dev->vdev);
1464 return 0;
1469 * @var v4l_sn9c20x_fops
1471 * This variable contains some callback
1474 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1475 static struct file_operations v4l_sn9c20x_fops = {
1476 #else
1477 static struct v4l2_file_operations v4l_sn9c20x_fops = {
1478 #endif
1479 .owner = THIS_MODULE,
1480 .open = v4l_sn9c20x_open,
1481 .release = v4l_sn9c20x_release,
1482 .read = v4l_sn9c20x_read,
1483 .poll = v4l_sn9c20x_poll,
1484 .mmap = v4l_sn9c20x_mmap,
1485 .ioctl = v4l_sn9c20x_ioctl,
1486 #ifdef CONFIG_COMPAT
1487 .compat_ioctl = v4l_compat_ioctl32,
1488 #endif
1489 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1490 .llseek = no_llseek
1491 #endif