V4l2 controls now have a max range of 255.
[microdia.git] / sn9c20x-v4l2.c
blob735807e9f4c8061df4f3b1b9a141f07764c7871e
1 /**
2 * @file sn9c20x-v4l.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,
58 .default_value = 0x7f,
61 .id = V4L2_CID_GAMMA,
62 .type = V4L2_CTRL_TYPE_INTEGER,
63 .name = "Gamma",
64 .minimum = 0,
65 .maximum = 0xff,
66 .step = 1,
67 .default_value = 0x7f,
71 .id = V4L2_CID_SATURATION,
72 .type = V4L2_CTRL_TYPE_INTEGER,
73 .name = "Saturation",
74 .minimum = 0,
75 .maximum = 0xff,
76 .step = 1,
77 .default_value = 0x7f,
81 .id = V4L2_CID_CONTRAST,
82 .type = V4L2_CTRL_TYPE_INTEGER,
83 .name = "Contrast",
84 .minimum = 0,
85 .maximum = 0xff,
86 .step = 1,
87 .default_value = 0x00,
90 .id = V4L2_CID_EXPOSURE,
91 .type = V4L2_CTRL_TYPE_INTEGER,
92 .name = "Exposure",
93 .minimum = 0,
94 .maximum = 0xff,
95 .step = 1,
96 .default_value = 0x10,
99 .id = V4L2_CID_GAIN,
100 .type = V4L2_CTRL_TYPE_INTEGER,
101 .name = "Gain",
102 .minimum = 0,
103 .maximum = 0xff,
104 .step = 1,
105 .default_value = 0x10,
108 .id = V4L2_CID_HFLIP,
109 .type = V4L2_CTRL_TYPE_BOOLEAN,
110 .name = "Horizontal flip",
111 .minimum = 0,
112 .maximum = 1,
113 .step = 1,
114 .default_value = 0,
117 .id = V4L2_CID_VFLIP,
118 .type = V4L2_CTRL_TYPE_BOOLEAN,
119 .name = "Vertical flip",
120 .minimum = 0,
121 .maximum = 1,
122 .step = 1,
123 .default_value = 0,
126 .id = V4L2_CID_SHARPNESS,
127 .type = V4L2_CTRL_TYPE_INTEGER,
128 .name = "Sharpness",
129 .minimum = 0,
130 .maximum = 0x3f,
131 .step = 1,
132 .default_value = 0x1f,
135 .id = V4L2_CID_RED_BALANCE,
136 .type = V4L2_CTRL_TYPE_INTEGER,
137 .name = "Red Balance",
138 .minimum = 0,
139 .maximum = 0x7f,
140 .step = 1,
141 .default_value = 0x1f,
144 .id = V4L2_CID_BLUE_BALANCE,
145 .type = V4L2_CTRL_TYPE_INTEGER,
146 .name = "Blue Balance",
147 .minimum = 0,
148 .maximum = 0x7f,
149 .step = 1,
150 .default_value = 0x1f,
153 .id = V4L2_CID_EXPOSURE_AUTO,
154 .type = V4L2_CTRL_TYPE_INTEGER,
155 .name = "Automatic exposure control",
156 .minimum = 0,
157 .maximum = 3,
158 .step = 1,
159 .default_value = 0,
162 .id = V4L2_CID_AUTOGAIN,
163 .type = V4L2_CTRL_TYPE_BOOLEAN,
164 .name = "Automatic gain control",
165 .minimum = 0,
166 .maximum = 1,
167 .step = 1,
168 .default_value = 0,
171 .id = V4L2_CID_AUTO_WHITE_BALANCE,
172 .type = V4L2_CTRL_TYPE_BOOLEAN,
173 .name = "Automatic whitbalance control",
174 .minimum = 0,
175 .maximum = 1,
176 .step = 1,
177 .default_value = 0,
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 dev_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 dev_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;
510 dev->queue.read_buffer = &dev->queue.buffer[buffer.index];
511 } else {
512 buffer = dev->queue.read_buffer->buf;
515 count = min((size_t)(buffer.bytesused - *f_pos), count);
516 if (copy_to_user(buf, dev->queue.mem + buffer.m.offset + *f_pos, count))
517 return -EFAULT;
519 *f_pos += count;
520 if (*f_pos >= buffer.bytesused) {
521 dev->queue.read_buffer = NULL;
522 sn9c20x_queue_buffer(&dev->queue, &buffer);
523 *f_pos = 0;
525 return count;
530 * @param fp File pointer
531 * @param wait
533 * @returns 0 if all is OK
535 * @brief Polling function
537 static unsigned int v4l_sn9c20x_poll(struct file *fp, poll_table *wait)
539 struct usb_sn9c20x *dev;
540 struct video_device *vdev;
542 vdev = video_devdata(fp);
543 dev = video_get_drvdata(video_devdata(fp));
545 UDIA_STREAM("Poll\n");
547 if (vdev == NULL || dev == NULL)
548 return -EFAULT;
550 return sn9c20x_queue_poll(&dev->queue, fp, wait);
554 * @param vma
557 static void sn9c20x_vm_open(struct vm_area_struct *vma)
559 struct sn9c20x_buffer *buffer = vma->vm_private_data;
560 buffer->vma_use_count++;
565 * @param vma
568 static void sn9c20x_vm_close(struct vm_area_struct *vma)
570 struct sn9c20x_buffer *buffer = vma->vm_private_data;
571 buffer->vma_use_count--;
574 struct vm_operations_struct sn9c20x_vm_ops = {
575 .open = sn9c20x_vm_open,
576 .close = sn9c20x_vm_close
580 * @param fp File pointer
581 * @param vma VMA structure
583 * @returns 0 if all is OK
585 * @brief Memory map
587 * This function permits to map a memory space.
589 static int v4l_sn9c20x_mmap(struct file *fp, struct vm_area_struct *vma)
591 struct page *page;
592 unsigned long addr, start, size;
593 unsigned int i;
594 int ret = 0;
596 struct usb_sn9c20x *dev;
597 struct video_device *vdev;
598 struct sn9c20x_buffer *buffer = NULL;
600 vdev = video_devdata(fp);
601 dev = video_get_drvdata(video_devdata(fp));
603 UDIA_STREAM("mmap\n");
605 start = vma->vm_start;
606 size = vma->vm_end - vma->vm_start;
608 mutex_lock(&dev->queue.mutex);
610 for (i = 0; i < dev->queue.count; ++i) {
611 buffer = &dev->queue.buffer[i];
612 if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
613 break;
616 if (i == dev->queue.count || size != dev->queue.buf_size) {
617 ret = -EINVAL;
618 goto done;
621 vma->vm_flags |= VM_IO;
623 addr = (unsigned long)dev->queue.mem + buffer->buf.m.offset;
624 while (size > 0) {
625 page = vmalloc_to_page((void *)addr);
626 ret = vm_insert_page(vma, start, page);
627 if (ret < 0)
628 goto done;
630 start += PAGE_SIZE;
631 addr += PAGE_SIZE;
632 size -= PAGE_SIZE;
635 vma->vm_ops = &sn9c20x_vm_ops;
636 vma->vm_private_data = buffer;
637 sn9c20x_vm_open(vma);
638 done:
639 mutex_unlock(&dev->queue.mutex);
640 return ret;
644 * @param file
645 * @param priv
646 * @param cap
648 * @return 0
651 int sn9c20x_vidioc_querycap(struct file *file, void *priv,
652 struct v4l2_capability *cap)
654 struct usb_sn9c20x *dev;
656 dev = video_get_drvdata(priv);
658 UDIA_DEBUG("VIDIOC_QUERYCAP\n");
660 strlcpy(cap->driver, "sn9c20x", sizeof(cap->driver));
661 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
662 | V4L2_CAP_READWRITE;
663 cap->version = (__u32) DRIVER_VERSION_NUM,
664 strlcpy(cap->card, dev->vdev->name, sizeof(cap->card));
666 if (usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)) < 0)
667 strlcpy(cap->bus_info, dev->vdev->name, sizeof(cap->bus_info));
668 return 0;
672 * @param file
673 * @param priv
674 * @param input
676 * @return 0 or negative error code
679 int sn9c20x_vidioc_enum_input(struct file *file, void *priv,
680 struct v4l2_input *input)
682 UDIA_DEBUG("VIDIOC_ENUMINPUT %d\n", input->index);
684 if (input->index)
685 return -EINVAL;
687 strlcpy(input->name, "Webcam", sizeof(input->name));
688 input->type = V4L2_INPUT_TYPE_CAMERA;
689 input->std = 0;
691 return 0;
695 * @param file
696 * @param priv
697 * @param index
699 * @return 0 or negative error code
702 int sn9c20x_vidioc_g_input(struct file *file, void *priv, unsigned int *index)
704 UDIA_DEBUG("GET INPUT %d\n", *index);
706 if (index)
707 return -EINVAL;
709 return 0;
713 * @param file
714 * @param priv
715 * @param index
717 * @return 0 or negative error code
720 int sn9c20x_vidioc_s_input(struct file *file, void *priv, unsigned int index)
722 UDIA_DEBUG("SET INPUT %d\n", index);
724 if (v4l_get_privileges(file) < 0)
725 return -EBUSY;
727 if (index != 0)
728 return -EINVAL;
730 return 0;
734 * @param file
735 * @param priv
736 * @param ctrl
738 * @return 0 or negative error code
741 int sn9c20x_vidioc_queryctrl(struct file *file, void *priv,
742 struct v4l2_queryctrl *ctrl)
744 int i;
745 int nbr;
747 UDIA_DEBUG("VIDIOC_QUERYCTRL id = %d\n", ctrl->id);
749 nbr = sizeof(sn9c20x_controls)/sizeof(struct v4l2_queryctrl);
751 for (i = 0; i < nbr; i++) {
752 if (sn9c20x_controls[i].id == ctrl->id) {
753 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
754 memcpy(ctrl, &sn9c20x_controls[i],
755 sizeof(struct v4l2_queryctrl));
756 break;
760 if (i >= nbr)
761 return -EINVAL;
763 return 0;
767 * @param file
768 * @param priv
769 * @param ctrl
771 * @return 0 or negative error code
774 int sn9c20x_vidioc_g_ctrl(struct file *file, void *priv,
775 struct v4l2_control *ctrl)
777 struct usb_sn9c20x *dev;
779 dev = video_get_drvdata(priv);
781 UDIA_DEBUG("GET CTRL id=%d\n", ctrl->id);
783 switch (ctrl->id) {
784 case V4L2_CID_BRIGHTNESS:
785 ctrl->value = dev->vsettings.brightness;
786 break;
788 case V4L2_CID_EXPOSURE:
789 ctrl->value = dev->vsettings.exposure;
790 break;
792 case V4L2_CID_GAIN:
793 ctrl->value = dev->vsettings.gain;
794 break;
796 case V4L2_CID_GAMMA:
797 ctrl->value = dev->vsettings.gamma;
798 break;
800 case V4L2_CID_SATURATION:
801 ctrl->value = dev->vsettings.colour;
802 break;
804 case V4L2_CID_CONTRAST:
805 ctrl->value = dev->vsettings.contrast;
806 break;
808 case V4L2_CID_HFLIP:
809 ctrl->value = dev->vsettings.hflip;
810 break;
812 case V4L2_CID_VFLIP:
813 ctrl->value = dev->vsettings.vflip;
814 break;
816 case V4L2_CID_SHARPNESS:
817 ctrl->value = dev->vsettings.sharpness;
818 break;
820 case V4L2_CID_RED_BALANCE:
821 ctrl->value = dev->vsettings.red_gain;
822 break;
824 case V4L2_CID_BLUE_BALANCE:
825 ctrl->value = dev->vsettings.blue_gain;
826 break;
828 case V4L2_CID_EXPOSURE_AUTO:
829 ctrl->value = dev->vsettings.auto_exposure;
830 break;
832 case V4L2_CID_AUTOGAIN:
833 ctrl->value = dev->vsettings.auto_gain;
834 break;
836 case V4L2_CID_AUTO_WHITE_BALANCE:
837 ctrl->value = dev->vsettings.auto_whitebalance;
838 break;
840 default:
841 return -EINVAL;
843 return 0;
847 * @brief Apply v4l2 settings on camera
849 * @param file
850 * @param priv
851 * @param ctrl V4L2 control structure
853 * @returns 0 or negative error value
856 int sn9c20x_vidioc_s_ctrl(struct file *file, void *priv,
857 struct v4l2_control *ctrl)
859 struct usb_sn9c20x *dev;
861 dev = video_get_drvdata(priv);
863 UDIA_DEBUG("SET CTRL id=%d value=%d\n", ctrl->id, ctrl->value);
865 return sn9c20x_set_camera_control(dev,
866 ctrl->id,
867 ctrl->value);
871 * @param file
872 * @param priv
873 * @param fmt
875 * @return 0 or negative error code
878 int sn9c20x_vidioc_enum_fmt_cap(struct file *file, void *priv,
879 struct v4l2_fmtdesc *fmt)
881 struct usb_sn9c20x *dev;
883 dev = video_get_drvdata(priv);
885 UDIA_DEBUG("VIDIOC_ENUM_FMT %d\n", fmt->index);
887 if (fmt->index >= dev->camera.nfmts)
888 return -EINVAL;
890 fmt->flags = 0;
891 fmt->pixelformat = dev->camera.fmts[fmt->index].pix_fmt;
893 if (fmt->pixelformat == V4L2_PIX_FMT_JPEG && jpeg == 0)
894 return -EINVAL;
896 memcpy(fmt->description, dev->camera.fmts[fmt->index].desc, 32);
898 return 0;
902 * @param file
903 * @param priv
904 * @param fmt
906 * @return 0 or negative error code
909 int sn9c20x_vidioc_try_fmt_cap(struct file *file, void *priv,
910 struct v4l2_format *fmt)
912 int index;
913 struct usb_sn9c20x *dev;
915 dev = video_get_drvdata(priv);
916 UDIA_DEBUG("TRY FMT %d\n", fmt->type);
918 /* when this code is used prevents mplayer from setting outfmt
919 if(fmt->fmt.pix.field != V4L2_FIELD_NONE)
920 return -EINVAL;
922 if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG && jpeg == 0)
923 return -EINVAL;
925 for (index = 0; index < dev->camera.nfmts; index++)
926 if (dev->camera.fmts[index].pix_fmt == fmt->fmt.pix.pixelformat)
927 break;
929 if (index >= dev->camera.nfmts)
930 return -EINVAL;
932 if (dev->camera.fmts[index].set_format == NULL)
933 return -EINVAL;
935 sn9c20x_get_closest_resolution(dev, &fmt->fmt.pix.width,
936 &fmt->fmt.pix.height);
938 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width *
939 dev->camera.fmts[index].depth / 8;
941 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
942 fmt->fmt.pix.bytesperline;
944 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
945 fmt->fmt.pix.priv = index;
947 return 0;
951 * @param file
952 * @param priv
953 * @param fmt
955 * @return 0
958 int sn9c20x_vidioc_g_fmt_cap(struct file *file, void *priv,
959 struct v4l2_format *fmt)
961 struct usb_sn9c20x *dev;
963 dev = video_get_drvdata(priv);
965 UDIA_DEBUG("GET FMT %d\n", fmt->type);
967 memcpy(&(fmt->fmt.pix), &(dev->vsettings.format), sizeof(fmt->fmt.pix));
970 return 0;
974 * @param file
975 * @param priv
976 * @param fmt
978 * @return 0 or negative error code
981 int sn9c20x_vidioc_s_fmt_cap(struct file *file, void *priv,
982 struct v4l2_format *fmt)
984 struct usb_sn9c20x *dev;
985 int ret;
987 dev = video_get_drvdata(priv);
989 UDIA_DEBUG("SET FMT %d : %d\n", fmt->type, fmt->fmt.pix.pixelformat);
991 if (v4l_get_privileges(file) < 0)
992 return -EBUSY;
994 if (sn9c20x_queue_streaming(&dev->queue))
995 return -EBUSY;
997 ret = sn9c20x_vidioc_try_fmt_cap(file, priv, fmt);
998 if (ret)
999 return -EINVAL;
1001 sn9c20x_set_resolution(dev, fmt->fmt.pix.width, fmt->fmt.pix.height);
1002 dev->camera.fmts[fmt->fmt.pix.priv].set_format(dev);
1003 memcpy(&(dev->vsettings.format), &(fmt->fmt.pix), sizeof(fmt->fmt.pix));
1005 return 0;
1009 * @param file
1010 * @param priv
1011 * @param request
1013 * @return 0 or negative error code
1016 int sn9c20x_vidioc_reqbufs(struct file *file, void *priv,
1017 struct v4l2_requestbuffers *request)
1019 int ret = 0;
1020 struct usb_sn9c20x *dev;
1022 dev = video_get_drvdata(priv);
1024 if (v4l_get_privileges(file) < 0) {
1025 ret = -EBUSY;
1026 goto done;
1029 if (request->memory != V4L2_MEMORY_MMAP ||
1030 request->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1031 ret = -EINVAL;
1032 goto done;
1035 if (sn9c20x_queue_streaming(&dev->queue)) {
1036 ret = -EBUSY;
1037 goto done;
1040 ret = sn9c20x_alloc_buffers(&dev->queue, request->count,
1041 dev->vsettings.format.sizeimage);
1042 if (ret < 0)
1043 goto done;
1045 request->count = ret;
1046 ret = 0;
1047 UDIA_DEBUG("Buffers Allocated %d\n", request->count);
1048 done:
1049 return ret;
1053 * @param file
1054 * @param priv
1055 * @param buffer
1057 * @return 0 or negative error code
1060 int sn9c20x_vidioc_querybuf(struct file *file, void *priv,
1061 struct v4l2_buffer *buffer)
1063 struct usb_sn9c20x *dev;
1065 dev = video_get_drvdata(priv);
1067 UDIA_DEBUG("QUERY BUFFERS %d %d\n", buffer->index, dev->queue.count);
1069 if (buffer->memory != V4L2_MEMORY_MMAP ||
1070 buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1071 return -EINVAL;
1073 if (!v4l_has_privileges(file))
1074 return -EBUSY;
1076 return sn9c20x_query_buffer(&dev->queue, buffer);
1080 * @param file
1081 * @param priv
1082 * @param buffer
1084 * @return 0 or negative error code
1087 int sn9c20x_vidioc_qbuf(struct file *file, void *priv,
1088 struct v4l2_buffer *buffer)
1090 struct usb_sn9c20x *dev;
1092 dev = video_get_drvdata(priv);
1094 UDIA_DEBUG("VIDIOC_QBUF\n");
1096 if (!v4l_has_privileges(file))
1097 return -EBUSY;
1099 return sn9c20x_queue_buffer(&dev->queue, buffer);
1103 * @param file
1104 * @param priv
1105 * @param buffer
1107 * @return 0 or negative error code
1110 int sn9c20x_vidioc_dqbuf(struct file *file, void *priv,
1111 struct v4l2_buffer *buffer)
1113 struct usb_sn9c20x *dev;
1114 int ret = 0;
1116 dev = video_get_drvdata(priv);
1118 UDIA_DEBUG("VIDIOC_DQBUF\n");
1120 if (!v4l_has_privileges(file))
1121 return -EBUSY;
1123 ret = sn9c20x_dequeue_buffer(&dev->queue, buffer,
1124 file->f_flags & O_NONBLOCK);
1125 if (ret < 0)
1126 return ret;
1128 if (dev->vsettings.format.pixelformat == V4L2_PIX_FMT_JPEG) {
1129 UDIA_DEBUG("Adding JPEG Header\n");
1130 v4l_add_jpegheader(dev, dev->queue.mem + buffer->m.offset,
1131 buffer->bytesused);
1132 buffer->bytesused += 589;
1135 dev_sn9c20x_call_constantly(dev);
1137 return ret;
1141 * @param file
1142 * @param priv
1143 * @param type
1145 * @return 0 or negative error code
1148 int sn9c20x_vidioc_streamon(struct file *file, void *priv,
1149 enum v4l2_buf_type type)
1151 struct usb_sn9c20x *dev;
1153 dev = video_get_drvdata(priv);
1155 UDIA_DEBUG("VIDIOC_STREAMON\n");
1157 if (!v4l_has_privileges(file))
1158 return -EBUSY;
1160 if (dev->mode != SN9C20X_MODE_IDLE)
1161 return -EBUSY;
1163 return v4l2_enable_video(dev, SN9C20X_MODE_STREAM);
1167 * @param file
1168 * @param priv
1169 * @param type
1171 * @return 0 or negative error code
1174 int sn9c20x_vidioc_streamoff(struct file *file, void *priv,
1175 enum v4l2_buf_type type)
1177 struct usb_sn9c20x *dev;
1179 dev = video_get_drvdata(priv);
1181 UDIA_DEBUG("VIDIOC_STREAMOFF\n");
1183 if (!v4l_has_privileges(file))
1184 return -EBUSY;
1186 return v4l2_enable_video(dev, SN9C20X_MODE_IDLE);
1190 * @param file
1191 * @param priv
1192 * @param param
1194 * @return 0 or negative error code
1197 int sn9c20x_vidioc_g_param(struct file *file, void *priv,
1198 struct v4l2_streamparm *param)
1200 struct usb_sn9c20x *dev;
1203 dev = video_get_drvdata(priv);
1205 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1206 return -EINVAL;
1208 param->parm.capture.capability = 0;
1209 param->parm.capture.capturemode = 0;
1210 param->parm.capture.timeperframe.numerator = 1;
1211 param->parm.capture.timeperframe.denominator = 30;
1212 param->parm.capture.readbuffers = 2;
1213 param->parm.capture.extendedmode = 0;
1215 return 0;
1219 * @param file
1220 * @param priv
1221 * @param param
1223 * @return 0 or negative error code
1226 int sn9c20x_vidioc_s_param(struct file *file, void *priv,
1227 struct v4l2_streamparm *param)
1229 struct usb_sn9c20x *dev;
1231 dev = video_get_drvdata(priv);
1233 if (v4l_get_privileges(file))
1234 return -EBUSY;
1236 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1237 return -EINVAL;
1239 return 0;
1243 * @param inode Inode pointer
1244 * @param fp File pointer
1245 * @param cmd Command
1246 * @param arg Arguements of the command
1248 * @returns 0 if all is OK
1250 * @brief Manage IOCTL
1252 * This function permits to manage all the IOCTL from the application.
1254 static int v4l_sn9c20x_ioctl(struct inode *inode, struct file *fp,
1255 unsigned int cmd, unsigned long arg)
1257 int err;
1258 struct usb_sn9c20x *dev;
1259 struct video_device *vdev;
1261 vdev = video_devdata(fp);
1262 dev = video_get_drvdata(video_devdata(fp));
1264 UDIA_DEBUG("v4l_sn9c20x_ioctl %02X\n", (unsigned char) cmd);
1266 if (dev == NULL || vdev == NULL)
1267 return -EFAULT;
1269 err = video_ioctl2(inode, fp, cmd, arg);
1271 return err;
1275 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1276 static const struct v4l2_ioctl_ops sn9c20x_v4l2_ioctl_ops = {
1277 .vidioc_querycap = sn9c20x_vidioc_querycap,
1278 .vidioc_enum_fmt_vid_cap = sn9c20x_vidioc_enum_fmt_cap,
1279 .vidioc_try_fmt_vid_cap = sn9c20x_vidioc_try_fmt_cap,
1280 .vidioc_s_fmt_vid_cap = sn9c20x_vidioc_s_fmt_cap,
1281 .vidioc_g_fmt_vid_cap = sn9c20x_vidioc_g_fmt_cap,
1282 .vidioc_enum_input = sn9c20x_vidioc_enum_input,
1283 .vidioc_g_input = sn9c20x_vidioc_g_input,
1284 .vidioc_s_input = sn9c20x_vidioc_s_input,
1285 .vidioc_streamon = sn9c20x_vidioc_streamon,
1286 .vidioc_streamoff = sn9c20x_vidioc_streamoff,
1287 .vidioc_queryctrl = sn9c20x_vidioc_queryctrl,
1288 .vidioc_g_ctrl = sn9c20x_vidioc_g_ctrl,
1289 .vidioc_s_ctrl = sn9c20x_vidioc_s_ctrl,
1290 .vidioc_g_parm = sn9c20x_vidioc_g_param,
1291 .vidioc_s_parm = sn9c20x_vidioc_s_param,
1292 .vidioc_reqbufs = sn9c20x_vidioc_reqbufs,
1293 .vidioc_qbuf = sn9c20x_vidioc_qbuf,
1294 .vidioc_dqbuf = sn9c20x_vidioc_dqbuf,
1295 .vidioc_querybuf = sn9c20x_vidioc_querybuf,
1297 #endif
1300 * @param dev Device structure
1302 * @returns 0 if all is OK
1304 * @brief Register the video device
1306 * This function permits to register the USB device to the video device.
1308 int v4l_sn9c20x_register_video_device(struct usb_sn9c20x *dev)
1310 int err;
1312 strcpy(dev->vdev->name, DRIVER_DESC);
1314 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1315 dev->vdev->dev = &dev->interface->dev;
1316 dev->vdev->owner = THIS_MODULE;
1317 dev->vdev->type = VID_TYPE_CAPTURE;
1318 #else
1319 dev->vdev->parent = &dev->interface->dev;
1320 #endif
1321 dev->vdev->current_norm = 0;
1322 dev->vdev->tvnorms = 0;
1323 dev->vdev->fops = &v4l_sn9c20x_fops;
1324 dev->vdev->release = video_device_release;
1325 dev->vdev->minor = -1;
1327 if (log_level & SN9C20X_DEBUG)
1328 dev->vdev->debug = V4L2_DEBUG_IOCTL_ARG;
1330 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1331 dev->vdev->vidioc_querycap = sn9c20x_vidioc_querycap;
1332 dev->vdev->vidioc_enum_fmt_cap = sn9c20x_vidioc_enum_fmt_cap;
1333 dev->vdev->vidioc_try_fmt_cap = sn9c20x_vidioc_try_fmt_cap;
1334 dev->vdev->vidioc_s_fmt_cap = sn9c20x_vidioc_s_fmt_cap;
1335 dev->vdev->vidioc_g_fmt_cap = sn9c20x_vidioc_g_fmt_cap;
1336 dev->vdev->vidioc_enum_input = sn9c20x_vidioc_enum_input;
1337 dev->vdev->vidioc_g_input = sn9c20x_vidioc_g_input;
1338 dev->vdev->vidioc_s_input = sn9c20x_vidioc_s_input;
1339 dev->vdev->vidioc_streamon = sn9c20x_vidioc_streamon;
1340 dev->vdev->vidioc_streamoff = sn9c20x_vidioc_streamoff;
1341 dev->vdev->vidioc_queryctrl = sn9c20x_vidioc_queryctrl;
1342 dev->vdev->vidioc_g_ctrl = sn9c20x_vidioc_g_ctrl;
1343 dev->vdev->vidioc_s_ctrl = sn9c20x_vidioc_s_ctrl;
1344 dev->vdev->vidioc_g_parm = sn9c20x_vidioc_g_param;
1345 dev->vdev->vidioc_s_parm = sn9c20x_vidioc_s_param;
1346 dev->vdev->vidioc_reqbufs = sn9c20x_vidioc_reqbufs;
1347 dev->vdev->vidioc_qbuf = sn9c20x_vidioc_qbuf;
1348 dev->vdev->vidioc_dqbuf = sn9c20x_vidioc_dqbuf;
1349 dev->vdev->vidioc_querybuf = sn9c20x_vidioc_querybuf;
1350 #else
1351 dev->vdev->ioctl_ops = &sn9c20x_v4l2_ioctl_ops;
1352 #endif
1354 video_set_drvdata(dev->vdev, dev);
1356 sn9c20x_queue_init(&dev->queue);
1358 err = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
1360 if (err)
1361 UDIA_ERROR("Video register fail !\n");
1362 else
1363 UDIA_INFO("SN9C20X USB 2.0 Webcam is now controlling "
1364 "video device /dev/video%d\n",
1365 dev->vdev->minor);
1367 return err;
1372 * @param dev Device structure
1374 * @returns 0 if all is OK
1376 * @brief Unregister the video device
1378 * This function permits to unregister the video device.
1380 int v4l_sn9c20x_unregister_video_device(struct usb_sn9c20x *dev)
1382 UDIA_INFO("SN9C20X USB 2.0 Webcam releases control of video "
1383 "device /dev/video%d\n", dev->vdev->minor);
1385 video_set_drvdata(dev->vdev, NULL);
1386 video_unregister_device(dev->vdev);
1388 return 0;
1393 * @var v4l_sn9c20x_fops
1395 * This variable contains some callback
1397 static struct file_operations v4l_sn9c20x_fops = {
1398 .owner = THIS_MODULE,
1399 .open = v4l_sn9c20x_open,
1400 .release = v4l_sn9c20x_release,
1401 .read = v4l_sn9c20x_read,
1402 .poll = v4l_sn9c20x_poll,
1403 .mmap = v4l_sn9c20x_mmap,
1404 .ioctl = v4l_sn9c20x_ioctl,
1405 #ifdef CONFIG_COMPAT
1406 .compat_ioctl = v4l_compat_ioctl32,
1407 #endif
1408 .llseek = no_llseek