Complete renaming to sn920x and declare driver "v2009.01"
[microdia.git] / sn9c20x-v4l2.c
blobc71e3a6afdf5f7f31fe224eeaae0399e813fcc1c
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 static struct file_operations v4l_sn9c20x_fops;
46 /**
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,
54 .name = "Brightness",
55 .minimum = 0,
56 .maximum = 0xff,
57 .step = 1,
60 .id = V4L2_CID_GAMMA,
61 .type = V4L2_CTRL_TYPE_INTEGER,
62 .name = "Gamma",
63 .minimum = 0,
64 .maximum = 0xff,
65 .step = 1,
69 .id = V4L2_CID_SATURATION,
70 .type = V4L2_CTRL_TYPE_INTEGER,
71 .name = "Saturation",
72 .minimum = 0,
73 .maximum = 0xff,
74 .step = 1,
78 .id = V4L2_CID_CONTRAST,
79 .type = V4L2_CTRL_TYPE_INTEGER,
80 .name = "Contrast",
81 .minimum = 0,
82 .maximum = 0xff,
83 .step = 1,
86 .id = V4L2_CID_EXPOSURE,
87 .type = V4L2_CTRL_TYPE_INTEGER,
88 .name = "Exposure",
89 .minimum = 0,
90 .maximum = 0xff,
91 .step = 1,
94 .id = V4L2_CID_GAIN,
95 .type = V4L2_CTRL_TYPE_INTEGER,
96 .name = "Gain",
97 .minimum = 0,
98 .maximum = 0xff,
99 .step = 1,
102 .id = V4L2_CID_HFLIP,
103 .type = V4L2_CTRL_TYPE_BOOLEAN,
104 .name = "Horizontal flip",
105 .minimum = 0,
106 .maximum = 1,
107 .step = 1,
110 .id = V4L2_CID_VFLIP,
111 .type = V4L2_CTRL_TYPE_BOOLEAN,
112 .name = "Vertical flip",
113 .minimum = 0,
114 .maximum = 1,
115 .step = 1,
118 .id = V4L2_CID_SHARPNESS,
119 .type = V4L2_CTRL_TYPE_INTEGER,
120 .name = "Sharpness",
121 .minimum = 0,
122 .maximum = 0x3f,
123 .step = 1,
126 .id = V4L2_CID_RED_BALANCE,
127 .type = V4L2_CTRL_TYPE_INTEGER,
128 .name = "Red Balance",
129 .minimum = 0,
130 .maximum = 0x7f,
131 .step = 1,
134 .id = V4L2_CID_BLUE_BALANCE,
135 .type = V4L2_CTRL_TYPE_INTEGER,
136 .name = "Blue Balance",
137 .minimum = 0,
138 .maximum = 0x7f,
139 .step = 1,
142 .id = V4L2_CID_EXPOSURE_AUTO,
143 .type = V4L2_CTRL_TYPE_INTEGER,
144 .name = "Automatic exposure control",
145 .minimum = 0,
146 .maximum = 3,
147 .step = 1,
150 .id = V4L2_CID_AUTOGAIN,
151 .type = V4L2_CTRL_TYPE_BOOLEAN,
152 .name = "Automatic gain control",
153 .minimum = 0,
154 .maximum = 1,
155 .step = 1,
158 .id = V4L2_CID_AUTO_WHITE_BALANCE,
159 .type = V4L2_CTRL_TYPE_BOOLEAN,
160 .name = "Automatic whitbalance control",
161 .minimum = 0,
162 .maximum = 1,
163 .step = 1,
167 void v4l2_set_control_default(struct usb_sn9c20x *dev, __u32 ctrl, __u16 value)
169 int i;
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,
174 ctrl,
175 value);
176 break;
181 void v4l_add_jpegheader(struct usb_sn9c20x *dev, __u8 *buffer,
182 __u32 buffer_size)
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
280 * @param file
282 * @return 0 or negative error code
285 int v4l_get_privileges(struct file *file)
287 struct usb_sn9c20x *dev;
288 int ret = 0;
290 dev = video_get_drvdata(video_devdata(file));
292 if (dev->owner == file)
293 return 0;
295 mutex_lock(&open_lock);
296 if (dev->owner != NULL) {
297 ret = -EBUSY;
298 goto done;
300 dev->owner = file;
301 done:
302 mutex_unlock(&open_lock);
303 return ret;
307 * @brief Check whether there are V4L privileges
309 * @param file
311 * @return 0 or 1
314 int v4l_has_privileges(struct file *file)
316 struct usb_sn9c20x *dev;
317 int ret = 0;
319 dev = video_get_drvdata(video_devdata(file));
321 if (dev->owner == file)
322 ret = 1;
324 return ret;
328 * @brief Drop V4L privileges
330 * @param file
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)
340 dev->owner = NULL;
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)
354 int ret;
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);
360 dev->mode = mode;
361 return 0;
364 if (dev->mode != SN9C20X_MODE_IDLE)
365 return -EBUSY;
367 if (sn9c20x_queue_enable(&dev->queue, 1) < 0)
368 return -EBUSY;
370 ret = usb_sn9c20x_init_urbs(dev);
372 if (ret)
373 return ret;
375 sn9c20x_enable_video(dev, 1);
376 dev->mode = mode;
378 if (dev->vsettings.format.pixelformat == V4L2_PIX_FMT_JPEG)
379 dev->queue.flags &= ~SN9C20X_QUEUE_DROP_INCOMPLETE;
380 else
381 dev->queue.flags |= SN9C20X_QUEUE_DROP_INCOMPLETE;
383 return 0;
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)
398 int ret = 0;
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);
413 return ret;
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);
450 return 0;
455 * @param fp File pointer
457 * @retval buf Buffer in user space
458 * @retval count
459 * @retval f_pos
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)
470 int i, ret;
471 int nbuffers;
472 struct v4l2_buffer buffer;
473 struct usb_sn9c20x *dev;
475 dev = video_get_drvdata(video_devdata(fp));
477 ret = v4l_get_privileges(fp);
478 if (ret < 0)
479 return ret;
481 if (dev->mode != SN9C20X_MODE_IDLE &&
482 dev->mode != SN9C20X_MODE_READ)
483 return -EBUSY;
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);
490 if (nbuffers < 0)
491 return nbuffers;
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);
499 if (ret < 0)
500 return ret;
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);
508 if (ret < 0)
509 return ret;
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,
514 buffer.bytesused);
515 buffer.bytesused += 589;
518 dev->queue.read_buffer = &dev->queue.buffer[buffer.index];
519 } else {
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))
525 return -EFAULT;
527 *f_pos += count;
528 if (*f_pos >= buffer.bytesused) {
529 dev->queue.read_buffer = NULL;
530 sn9c20x_queue_buffer(&dev->queue, &buffer);
531 *f_pos = 0;
533 return count;
538 * @param fp File pointer
539 * @param wait
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)
556 return -EFAULT;
558 return sn9c20x_queue_poll(&dev->queue, fp, wait);
562 * @param vma
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++;
573 * @param vma
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
593 * @brief Memory map
595 * This function permits to map a memory space.
597 static int v4l_sn9c20x_mmap(struct file *fp, struct vm_area_struct *vma)
599 struct page *page;
600 unsigned long addr, start, size;
601 unsigned int i;
602 int ret = 0;
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)
621 break;
624 if (i == dev->queue.count || size != dev->queue.buf_size) {
625 ret = -EINVAL;
626 goto done;
629 vma->vm_flags |= VM_IO;
631 addr = (unsigned long)dev->queue.mem + buffer->buf.m.offset;
632 while (size > 0) {
633 page = vmalloc_to_page((void *)addr);
634 ret = vm_insert_page(vma, start, page);
635 if (ret < 0)
636 goto done;
638 start += PAGE_SIZE;
639 addr += PAGE_SIZE;
640 size -= PAGE_SIZE;
643 vma->vm_ops = &sn9c20x_vm_ops;
644 vma->vm_private_data = buffer;
645 sn9c20x_vm_open(vma);
646 done:
647 mutex_unlock(&dev->queue.mutex);
648 return ret;
652 * @param file
653 * @param priv
654 * @param cap
656 * @return 0
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));
676 return 0;
680 * @param file
681 * @param priv
682 * @param input
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);
692 if (input->index)
693 return -EINVAL;
695 strlcpy(input->name, "Webcam", sizeof(input->name));
696 input->type = V4L2_INPUT_TYPE_CAMERA;
697 input->std = 0;
699 return 0;
703 * @param file
704 * @param priv
705 * @param index
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);
714 if (index)
715 return -EINVAL;
717 return 0;
721 * @param file
722 * @param priv
723 * @param 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)
733 return -EBUSY;
735 if (index != 0)
736 return -EINVAL;
738 return 0;
742 * @param file
743 * @param priv
744 * @param ctrl
746 * @return 0 or negative error code
749 int sn9c20x_vidioc_queryctrl(struct file *file, void *priv,
750 struct v4l2_queryctrl *ctrl)
752 int i;
753 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
754 int min;
755 __u32 idnew, idlast;
756 #endif
758 UDIA_DEBUG("VIDIOC_QUERYCTRL id = %d\n", ctrl->id);
760 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
761 if (ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
762 min = 0;
763 idnew = V4L2_CTRL_FLAG_NEXT_CTRL;
764 idlast = ctrl->id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
765 for (i = 0; i < ARRAY_SIZE(sn9c20x_controls); i++) {
766 if ((sn9c20x_controls[i].id < idnew) &&
767 (sn9c20x_controls[i].id > idlast)) {
768 idnew = sn9c20x_controls[i].id;
769 min = i;
772 if (idnew != V4L2_CTRL_FLAG_NEXT_CTRL) {
773 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
774 memcpy(ctrl, &sn9c20x_controls[min],
775 sizeof(struct v4l2_queryctrl));
776 return 0;
777 } else
778 return -EINVAL;
779 } else
780 #endif
782 for (i = 0; i < ARRAY_SIZE(sn9c20x_controls); i++) {
783 if (sn9c20x_controls[i].id == ctrl->id) {
784 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
785 memcpy(ctrl, &sn9c20x_controls[i],
786 sizeof(struct v4l2_queryctrl));
787 break;
792 if (i >= ARRAY_SIZE(sn9c20x_controls))
793 return -EINVAL;
795 return 0;
799 * @param file
800 * @param priv
801 * @param ctrl
803 * @return 0 or negative error code
806 int sn9c20x_vidioc_g_ctrl(struct file *file, void *priv,
807 struct v4l2_control *ctrl)
809 struct usb_sn9c20x *dev;
811 dev = video_get_drvdata(priv);
813 UDIA_DEBUG("GET CTRL id=%d\n", ctrl->id);
815 switch (ctrl->id) {
816 case V4L2_CID_BRIGHTNESS:
817 ctrl->value = dev->vsettings.brightness;
818 break;
820 case V4L2_CID_EXPOSURE:
821 ctrl->value = dev->vsettings.exposure;
822 break;
824 case V4L2_CID_GAIN:
825 ctrl->value = dev->vsettings.gain;
826 break;
828 case V4L2_CID_GAMMA:
829 ctrl->value = dev->vsettings.gamma;
830 break;
832 case V4L2_CID_SATURATION:
833 ctrl->value = dev->vsettings.colour;
834 break;
836 case V4L2_CID_CONTRAST:
837 ctrl->value = dev->vsettings.contrast;
838 break;
840 case V4L2_CID_HFLIP:
841 ctrl->value = dev->vsettings.hflip;
842 break;
844 case V4L2_CID_VFLIP:
845 ctrl->value = dev->vsettings.vflip;
846 break;
848 case V4L2_CID_SHARPNESS:
849 ctrl->value = dev->vsettings.sharpness;
850 break;
852 case V4L2_CID_RED_BALANCE:
853 ctrl->value = dev->vsettings.red_gain;
854 break;
856 case V4L2_CID_BLUE_BALANCE:
857 ctrl->value = dev->vsettings.blue_gain;
858 break;
860 case V4L2_CID_EXPOSURE_AUTO:
861 ctrl->value = dev->vsettings.auto_exposure;
862 break;
864 case V4L2_CID_AUTOGAIN:
865 ctrl->value = dev->vsettings.auto_gain;
866 break;
868 case V4L2_CID_AUTO_WHITE_BALANCE:
869 ctrl->value = dev->vsettings.auto_whitebalance;
870 break;
872 default:
873 return -EINVAL;
875 return 0;
879 * @brief Apply v4l2 settings on camera
881 * @param file
882 * @param priv
883 * @param ctrl V4L2 control structure
885 * @returns 0 or negative error value
888 int sn9c20x_vidioc_s_ctrl(struct file *file, void *priv,
889 struct v4l2_control *ctrl)
891 struct usb_sn9c20x *dev;
893 dev = video_get_drvdata(priv);
895 UDIA_DEBUG("SET CTRL id=%d value=%d\n", ctrl->id, ctrl->value);
897 return sn9c20x_set_camera_control(dev,
898 ctrl->id,
899 ctrl->value);
903 * @param file
904 * @param priv
905 * @param fmt
907 * @return 0 or negative error code
910 int sn9c20x_vidioc_enum_fmt_cap(struct file *file, void *priv,
911 struct v4l2_fmtdesc *fmt)
913 struct usb_sn9c20x *dev;
915 dev = video_get_drvdata(priv);
917 UDIA_DEBUG("VIDIOC_ENUM_FMT %d\n", fmt->index);
919 if (fmt->index >= SN9C20X_N_FMTS)
920 return -EINVAL;
922 fmt->flags = 0;
923 fmt->pixelformat = sn9c20x_fmts[fmt->index].pix_fmt;
925 if (fmt->pixelformat == V4L2_PIX_FMT_JPEG && jpeg == 0)
926 return -EINVAL;
928 memcpy(fmt->description, sn9c20x_fmts[fmt->index].desc, 32);
930 return 0;
934 * @param file
935 * @param priv
936 * @param fmt
938 * @return 0 or negative error code
941 int sn9c20x_vidioc_try_fmt_cap(struct file *file, void *priv,
942 struct v4l2_format *fmt)
944 int index;
945 struct usb_sn9c20x *dev;
947 dev = video_get_drvdata(priv);
948 UDIA_DEBUG("TRY FMT %d\n", fmt->type);
950 /* when this code is used prevents mplayer from setting outfmt
951 if(fmt->fmt.pix.field != V4L2_FIELD_NONE)
952 return -EINVAL;
954 if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG && jpeg == 0)
955 return -EINVAL;
957 for (index = 0; index < SN9C20X_N_FMTS; index++)
958 if (sn9c20x_fmts[index].pix_fmt == fmt->fmt.pix.pixelformat)
959 break;
961 if (index >= SN9C20X_N_FMTS)
962 return -EINVAL;
964 sn9c20x_get_closest_resolution(dev, &fmt->fmt.pix.width,
965 &fmt->fmt.pix.height);
967 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width *
968 sn9c20x_fmts[index].depth / 8;
970 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
971 fmt->fmt.pix.bytesperline;
973 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
974 fmt->fmt.pix.priv = index;
976 return 0;
980 * @param file
981 * @param priv
982 * @param fmt
984 * @return 0
987 int sn9c20x_vidioc_g_fmt_cap(struct file *file, void *priv,
988 struct v4l2_format *fmt)
990 struct usb_sn9c20x *dev;
992 dev = video_get_drvdata(priv);
994 UDIA_DEBUG("GET FMT %d\n", fmt->type);
996 memcpy(&(fmt->fmt.pix), &(dev->vsettings.format), sizeof(fmt->fmt.pix));
999 return 0;
1003 * @param file
1004 * @param priv
1005 * @param fmt
1007 * @return 0 or negative error code
1010 int sn9c20x_vidioc_s_fmt_cap(struct file *file, void *priv,
1011 struct v4l2_format *fmt)
1013 struct usb_sn9c20x *dev;
1014 int ret;
1016 dev = video_get_drvdata(priv);
1018 UDIA_DEBUG("SET FMT %d : %d\n", fmt->type, fmt->fmt.pix.pixelformat);
1020 if (v4l_get_privileges(file) < 0)
1021 return -EBUSY;
1023 if (sn9c20x_queue_streaming(&dev->queue))
1024 return -EBUSY;
1026 ret = sn9c20x_vidioc_try_fmt_cap(file, priv, fmt);
1027 if (ret)
1028 return -EINVAL;
1030 sn9c20x_set_resolution(dev, fmt->fmt.pix.width, fmt->fmt.pix.height);
1031 sn9c20x_set_format(dev, fmt->fmt.pix.pixelformat);
1032 memcpy(&(dev->vsettings.format), &(fmt->fmt.pix), sizeof(fmt->fmt.pix));
1034 return 0;
1038 * @param file
1039 * @param priv
1040 * @param request
1042 * @return 0 or negative error code
1045 int sn9c20x_vidioc_reqbufs(struct file *file, void *priv,
1046 struct v4l2_requestbuffers *request)
1048 int ret = 0;
1049 struct usb_sn9c20x *dev;
1051 dev = video_get_drvdata(priv);
1053 if (v4l_get_privileges(file) < 0) {
1054 ret = -EBUSY;
1055 goto done;
1058 if (request->memory != V4L2_MEMORY_MMAP ||
1059 request->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1060 ret = -EINVAL;
1061 goto done;
1064 if (sn9c20x_queue_streaming(&dev->queue)) {
1065 ret = -EBUSY;
1066 goto done;
1069 ret = sn9c20x_alloc_buffers(&dev->queue, request->count,
1070 dev->vsettings.format.sizeimage);
1071 if (ret < 0)
1072 goto done;
1074 request->count = ret;
1075 ret = 0;
1076 UDIA_DEBUG("Buffers Allocated %d\n", request->count);
1077 done:
1078 return ret;
1082 * @param file
1083 * @param priv
1084 * @param buffer
1086 * @return 0 or negative error code
1089 int sn9c20x_vidioc_querybuf(struct file *file, void *priv,
1090 struct v4l2_buffer *buffer)
1092 struct usb_sn9c20x *dev;
1094 dev = video_get_drvdata(priv);
1096 UDIA_DEBUG("QUERY BUFFERS %d %d\n", buffer->index, dev->queue.count);
1098 if (buffer->memory != V4L2_MEMORY_MMAP ||
1099 buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1100 return -EINVAL;
1102 if (!v4l_has_privileges(file))
1103 return -EBUSY;
1105 return sn9c20x_query_buffer(&dev->queue, buffer);
1109 * @param file
1110 * @param priv
1111 * @param buffer
1113 * @return 0 or negative error code
1116 int sn9c20x_vidioc_qbuf(struct file *file, void *priv,
1117 struct v4l2_buffer *buffer)
1119 struct usb_sn9c20x *dev;
1121 dev = video_get_drvdata(priv);
1123 UDIA_DEBUG("VIDIOC_QBUF\n");
1125 if (!v4l_has_privileges(file))
1126 return -EBUSY;
1128 return sn9c20x_queue_buffer(&dev->queue, buffer);
1132 * @param file
1133 * @param priv
1134 * @param buffer
1136 * @return 0 or negative error code
1139 int sn9c20x_vidioc_dqbuf(struct file *file, void *priv,
1140 struct v4l2_buffer *buffer)
1142 struct usb_sn9c20x *dev;
1143 int ret = 0;
1145 dev = video_get_drvdata(priv);
1147 UDIA_DEBUG("VIDIOC_DQBUF\n");
1149 if (!v4l_has_privileges(file))
1150 return -EBUSY;
1152 ret = sn9c20x_dequeue_buffer(&dev->queue, buffer,
1153 file->f_flags & O_NONBLOCK);
1154 if (ret < 0)
1155 return ret;
1157 if (dev->vsettings.format.pixelformat == V4L2_PIX_FMT_JPEG) {
1158 UDIA_DEBUG("Adding JPEG Header\n");
1159 v4l_add_jpegheader(dev, dev->queue.mem + buffer->m.offset,
1160 buffer->bytesused);
1161 buffer->bytesused += 589;
1164 dev_sn9c20x_call_constantly(dev);
1166 return ret;
1170 * @param file
1171 * @param priv
1172 * @param type
1174 * @return 0 or negative error code
1177 int sn9c20x_vidioc_streamon(struct file *file, void *priv,
1178 enum v4l2_buf_type type)
1180 struct usb_sn9c20x *dev;
1182 dev = video_get_drvdata(priv);
1184 UDIA_DEBUG("VIDIOC_STREAMON\n");
1186 if (!v4l_has_privileges(file))
1187 return -EBUSY;
1189 if (dev->mode != SN9C20X_MODE_IDLE)
1190 return -EBUSY;
1192 return v4l2_enable_video(dev, SN9C20X_MODE_STREAM);
1196 * @param file
1197 * @param priv
1198 * @param type
1200 * @return 0 or negative error code
1203 int sn9c20x_vidioc_streamoff(struct file *file, void *priv,
1204 enum v4l2_buf_type type)
1206 struct usb_sn9c20x *dev;
1208 dev = video_get_drvdata(priv);
1210 UDIA_DEBUG("VIDIOC_STREAMOFF\n");
1212 if (!v4l_has_privileges(file))
1213 return -EBUSY;
1215 return v4l2_enable_video(dev, SN9C20X_MODE_IDLE);
1219 * @param file
1220 * @param priv
1221 * @param param
1223 * @return 0 or negative error code
1226 int sn9c20x_vidioc_g_param(struct file *file, void *priv,
1227 struct v4l2_streamparm *param)
1229 struct usb_sn9c20x *dev;
1232 dev = video_get_drvdata(priv);
1234 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1235 return -EINVAL;
1237 param->parm.capture.capability = 0;
1238 param->parm.capture.capturemode = 0;
1239 param->parm.capture.timeperframe.numerator = 1;
1240 param->parm.capture.timeperframe.denominator = 30;
1241 param->parm.capture.readbuffers = 2;
1242 param->parm.capture.extendedmode = 0;
1244 return 0;
1248 * @param file
1249 * @param priv
1250 * @param param
1252 * @return 0 or negative error code
1255 int sn9c20x_vidioc_s_param(struct file *file, void *priv,
1256 struct v4l2_streamparm *param)
1258 struct usb_sn9c20x *dev;
1260 dev = video_get_drvdata(priv);
1262 if (v4l_get_privileges(file))
1263 return -EBUSY;
1265 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1266 return -EINVAL;
1268 return 0;
1272 * @param inode Inode pointer
1273 * @param fp File pointer
1274 * @param cmd Command
1275 * @param arg Arguements of the command
1277 * @returns 0 if all is OK
1279 * @brief Manage IOCTL
1281 * This function permits to manage all the IOCTL from the application.
1283 static int v4l_sn9c20x_ioctl(struct inode *inode, struct file *fp,
1284 unsigned int cmd, unsigned long arg)
1286 int err;
1287 struct usb_sn9c20x *dev;
1288 struct video_device *vdev;
1290 vdev = video_devdata(fp);
1291 dev = video_get_drvdata(video_devdata(fp));
1293 UDIA_DEBUG("v4l_sn9c20x_ioctl %02X\n", (unsigned char) cmd);
1295 if (dev == NULL || vdev == NULL)
1296 return -EFAULT;
1298 err = video_ioctl2(inode, fp, cmd, arg);
1300 return err;
1304 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1305 static const struct v4l2_ioctl_ops sn9c20x_v4l2_ioctl_ops = {
1306 .vidioc_querycap = sn9c20x_vidioc_querycap,
1307 .vidioc_enum_fmt_vid_cap = sn9c20x_vidioc_enum_fmt_cap,
1308 .vidioc_try_fmt_vid_cap = sn9c20x_vidioc_try_fmt_cap,
1309 .vidioc_s_fmt_vid_cap = sn9c20x_vidioc_s_fmt_cap,
1310 .vidioc_g_fmt_vid_cap = sn9c20x_vidioc_g_fmt_cap,
1311 .vidioc_enum_input = sn9c20x_vidioc_enum_input,
1312 .vidioc_g_input = sn9c20x_vidioc_g_input,
1313 .vidioc_s_input = sn9c20x_vidioc_s_input,
1314 .vidioc_streamon = sn9c20x_vidioc_streamon,
1315 .vidioc_streamoff = sn9c20x_vidioc_streamoff,
1316 .vidioc_queryctrl = sn9c20x_vidioc_queryctrl,
1317 .vidioc_g_ctrl = sn9c20x_vidioc_g_ctrl,
1318 .vidioc_s_ctrl = sn9c20x_vidioc_s_ctrl,
1319 .vidioc_g_parm = sn9c20x_vidioc_g_param,
1320 .vidioc_s_parm = sn9c20x_vidioc_s_param,
1321 .vidioc_reqbufs = sn9c20x_vidioc_reqbufs,
1322 .vidioc_qbuf = sn9c20x_vidioc_qbuf,
1323 .vidioc_dqbuf = sn9c20x_vidioc_dqbuf,
1324 .vidioc_querybuf = sn9c20x_vidioc_querybuf,
1326 #endif
1329 * @param dev Device structure
1331 * @returns 0 if all is OK
1333 * @brief Register the video device
1335 * This function permits to register the USB device to the video device.
1337 int v4l_sn9c20x_register_video_device(struct usb_sn9c20x *dev)
1339 int err;
1341 strcpy(dev->vdev->name, DRIVER_DESC);
1343 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1344 dev->vdev->dev = &dev->interface->dev;
1345 dev->vdev->owner = THIS_MODULE;
1346 dev->vdev->type = VID_TYPE_CAPTURE;
1347 #else
1348 dev->vdev->parent = &dev->interface->dev;
1349 #endif
1350 dev->vdev->current_norm = 0;
1351 dev->vdev->tvnorms = 0;
1352 dev->vdev->fops = &v4l_sn9c20x_fops;
1353 dev->vdev->release = video_device_release;
1354 dev->vdev->minor = -1;
1356 if (log_level & SN9C20X_DEBUG)
1357 dev->vdev->debug = V4L2_DEBUG_IOCTL_ARG;
1359 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1360 dev->vdev->vidioc_querycap = sn9c20x_vidioc_querycap;
1361 dev->vdev->vidioc_enum_fmt_cap = sn9c20x_vidioc_enum_fmt_cap;
1362 dev->vdev->vidioc_try_fmt_cap = sn9c20x_vidioc_try_fmt_cap;
1363 dev->vdev->vidioc_s_fmt_cap = sn9c20x_vidioc_s_fmt_cap;
1364 dev->vdev->vidioc_g_fmt_cap = sn9c20x_vidioc_g_fmt_cap;
1365 dev->vdev->vidioc_enum_input = sn9c20x_vidioc_enum_input;
1366 dev->vdev->vidioc_g_input = sn9c20x_vidioc_g_input;
1367 dev->vdev->vidioc_s_input = sn9c20x_vidioc_s_input;
1368 dev->vdev->vidioc_streamon = sn9c20x_vidioc_streamon;
1369 dev->vdev->vidioc_streamoff = sn9c20x_vidioc_streamoff;
1370 dev->vdev->vidioc_queryctrl = sn9c20x_vidioc_queryctrl;
1371 dev->vdev->vidioc_g_ctrl = sn9c20x_vidioc_g_ctrl;
1372 dev->vdev->vidioc_s_ctrl = sn9c20x_vidioc_s_ctrl;
1373 dev->vdev->vidioc_g_parm = sn9c20x_vidioc_g_param;
1374 dev->vdev->vidioc_s_parm = sn9c20x_vidioc_s_param;
1375 dev->vdev->vidioc_reqbufs = sn9c20x_vidioc_reqbufs;
1376 dev->vdev->vidioc_qbuf = sn9c20x_vidioc_qbuf;
1377 dev->vdev->vidioc_dqbuf = sn9c20x_vidioc_dqbuf;
1378 dev->vdev->vidioc_querybuf = sn9c20x_vidioc_querybuf;
1379 #else
1380 dev->vdev->ioctl_ops = &sn9c20x_v4l2_ioctl_ops;
1381 #endif
1383 video_set_drvdata(dev->vdev, dev);
1385 sn9c20x_queue_init(&dev->queue);
1387 err = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
1389 if (err)
1390 UDIA_ERROR("Video register fail !\n");
1391 else
1392 UDIA_INFO("SN9C20X USB 2.0 Webcam is now controlling "
1393 "video device /dev/video%d\n",
1394 dev->vdev->minor);
1396 return err;
1401 * @param dev Device structure
1403 * @returns 0 if all is OK
1405 * @brief Unregister the video device
1407 * This function permits to unregister the video device.
1409 int v4l_sn9c20x_unregister_video_device(struct usb_sn9c20x *dev)
1411 UDIA_INFO("SN9C20X USB 2.0 Webcam releases control of video "
1412 "device /dev/video%d\n", dev->vdev->minor);
1414 video_set_drvdata(dev->vdev, NULL);
1415 video_unregister_device(dev->vdev);
1417 return 0;
1422 * @var v4l_sn9c20x_fops
1424 * This variable contains some callback
1426 static struct file_operations v4l_sn9c20x_fops = {
1427 .owner = THIS_MODULE,
1428 .open = v4l_sn9c20x_open,
1429 .release = v4l_sn9c20x_release,
1430 .read = v4l_sn9c20x_read,
1431 .poll = v4l_sn9c20x_poll,
1432 .mmap = v4l_sn9c20x_mmap,
1433 .ioctl = v4l_sn9c20x_ioctl,
1434 #ifdef CONFIG_COMPAT
1435 .compat_ioctl = v4l_compat_ioctl32,
1436 #endif
1437 .llseek = no_llseek