Restores USB audio functionality of SN9C202 webcams
[microdia.git] / microdia-v4l.c
blobb65e22d6eb5f0dc4ba183072e14533be948cdb40
1 /**
2 * @file microdia-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>
37 #include <media/v4l2-common.h>
40 #include "microdia.h"
41 #include "sn9c20x.h"
44 /* USER DEFINED V4L2-CONTROLS: */
45 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
46 #define V4L2_CID_AUTOEXPOSURE (V4L2_CID_PRIVATE_BASE + 0)
47 #else
48 #define V4L2_CID_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
49 #define V4L2_CID_AUTOEXPOSURE (V4L2_CID_PRIVATE_BASE + 1)
50 #endif
52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
53 #include <media/v4l2-ioctl.h>
54 #endif
56 static struct file_operations v4l_microdia_fops;
58 /**
59 * format list
62 #define NUM_V4L2_FORMATS 4
64 struct v4l2_pix_format microdia_fmts[] = {
66 .width = 640,
67 .height = 480,
68 .pixelformat = V4L2_PIX_FMT_YUV420,
69 .field = V4L2_FIELD_NONE,
70 .bytesperline = 960,
71 .sizeimage = 460800,
72 .colorspace = V4L2_COLORSPACE_SRGB,
73 .priv = 0
76 .width = 640,
77 .height = 480,
78 .pixelformat = V4L2_PIX_FMT_BGR24,
79 .field = V4L2_FIELD_NONE,
80 .bytesperline = 1920,
81 .sizeimage = 921600,
82 .colorspace = V4L2_COLORSPACE_SRGB,
83 .priv = 0
86 .width = 640,
87 .height = 480,
88 .pixelformat = V4L2_PIX_FMT_RGB24,
89 .field = V4L2_FIELD_NONE,
90 .bytesperline = 1920,
91 .sizeimage = 921600,
92 .colorspace = V4L2_COLORSPACE_SRGB,
93 .priv = 0
96 .width = 640,
97 .height = 480,
98 .pixelformat = V4L2_PIX_FMT_YUYV,
99 .field = V4L2_FIELD_NONE,
100 .bytesperline = 1280,
101 .sizeimage = 614400,
102 .colorspace = V4L2_COLORSPACE_SRGB,
103 .priv = 0
108 * @param dev
109 * @param fmt v4l2 fmt id
111 * @returns index of requested format
113 * @brief check if v4l2 forat is supported by device.
115 * This function permits to check if v4l2 format is supported.
117 int v4l2_format_supported(struct usb_microdia *dev, __u32 fmt)
119 int i;
120 for (i = 0; i < sizeof(dev->supported_fmts) * 8; i++) {
121 if (i > (ARRAY_SIZE(microdia_fmts) - 1))
122 break;
123 if (dev->supported_fmts & (1 << i) &&
124 microdia_fmts[i].pixelformat == fmt)
125 return i;
127 return -EINVAL;
131 * @param dev
132 * @param index format index
134 * @returns reference to format structure
136 * @brief enumerate supported formats
138 * This function will enumerate all supported formats.
140 struct v4l2_pix_format *v4l2_enum_supported_formats(struct usb_microdia *dev,
141 __u8 index)
143 int i, bit = 0;
144 for (i = 0; i < sizeof(dev->supported_fmts) * 8; i++) {
145 if (i > (ARRAY_SIZE(microdia_fmts) - 1))
146 break;
147 if (dev->supported_fmts & (1 << i)) {
148 if (bit == index)
149 return &microdia_fmts[i];
150 bit++;
153 return NULL;
157 * @var microdia_controls
158 * List of all V4Lv2 controls supported by the driver
160 static struct v4l2_queryctrl microdia_controls[] = {
162 .id = V4L2_CID_BRIGHTNESS,
163 .type = V4L2_CTRL_TYPE_INTEGER,
164 .name = "Brightness",
165 .minimum = 0,
166 .maximum = 0xff00,
167 .step = 1,
168 .default_value = 0x7f00,
171 .id = V4L2_CID_WHITENESS,
172 .type = V4L2_CTRL_TYPE_INTEGER,
173 .name = "Whiteness",
174 .minimum = 0,
175 .maximum = 0xff00,
176 .step = 1,
177 .default_value = 0x7f00,
181 .id = V4L2_CID_SATURATION,
182 .type = V4L2_CTRL_TYPE_INTEGER,
183 .name = "Saturation",
184 .minimum = 0,
185 .maximum = 0xff00,
186 .step = 1,
187 .default_value = 0x7f00,
191 .id = V4L2_CID_CONTRAST,
192 .type = V4L2_CTRL_TYPE_INTEGER,
193 .name = "Contrast",
194 .minimum = 0,
195 .maximum = 0xff00,
196 .step = 1,
197 .default_value = 0x0000,
200 .id = V4L2_CID_EXPOSURE,
201 .type = V4L2_CTRL_TYPE_INTEGER,
202 .name = "Exposure",
203 .minimum = 0,
204 .maximum = 0xff00,
205 .step = 1,
206 .default_value = 0x1000,
209 .id = V4L2_CID_HFLIP,
210 .type = V4L2_CTRL_TYPE_BOOLEAN,
211 .name = "Horizontal flip",
212 .minimum = 0,
213 .maximum = 1,
214 .step = 1,
215 .default_value = 0,
218 .id = V4L2_CID_VFLIP,
219 .type = V4L2_CTRL_TYPE_BOOLEAN,
220 .name = "Vertical flip",
221 .minimum = 0,
222 .maximum = 1,
223 .step = 1,
224 .default_value = 0,
227 .id = V4L2_CID_SHARPNESS,
228 .type = V4L2_CTRL_TYPE_INTEGER,
229 .name = "Sharpness",
230 .minimum = 0,
231 .maximum = 0x3f,
232 .step = 1,
233 .default_value = 0x1f,
236 .id = V4L2_CID_RED_BALANCE,
237 .type = V4L2_CTRL_TYPE_INTEGER,
238 .name = "Red Balance",
239 .minimum = 0,
240 .maximum = 0x7f,
241 .step = 1,
242 .default_value = 0x20,
245 .id = V4L2_CID_BLUE_BALANCE,
246 .type = V4L2_CTRL_TYPE_INTEGER,
247 .name = "Blue Balance",
248 .minimum = 0,
249 .maximum = 0x7f,
250 .step = 1,
251 .default_value = 0x20,
254 .id = V4L2_CID_AUTOEXPOSURE,
255 .type = V4L2_CTRL_TYPE_BOOLEAN,
256 .name = "Automatic exposure control",
257 .minimum = 0,
258 .maximum = 1,
259 .step = 1,
260 .default_value = 0,
263 .id = V4L2_CID_AUTO_WHITE_BALANCE,
264 .type = V4L2_CTRL_TYPE_BOOLEAN,
265 .name = "Automatic whitbalance control",
266 .minimum = 0,
267 .maximum = 1,
268 .step = 1,
269 .default_value = 0,
274 * @brief Get V4L privileges
276 * @param file
278 * @return 0 or negative error code
281 int v4l_get_privileges(struct file *file)
283 struct usb_microdia *dev;
284 int ret = 0;
286 dev = video_get_drvdata(video_devdata(file));
288 if (dev->owner == file)
289 return 0;
291 mutex_lock(&open_lock);
292 if (dev->owner != NULL) {
293 ret = -EBUSY;
294 goto done;
296 dev->owner = file;
297 done:
298 mutex_unlock(&open_lock);
299 return ret;
303 * @brief Check whether there are V4L privileges
305 * @param file
307 * @return 0 or 1
310 int v4l_has_privileges(struct file *file)
312 struct usb_microdia *dev;
313 int ret = 0;
315 dev = video_get_drvdata(video_devdata(file));
317 if (dev->owner == file)
318 ret = 1;
320 return ret;
324 * @brief Drop V4L privileges
326 * @param file
329 void v4l_drop_privileges(struct file *file)
331 struct usb_microdia *dev;
333 dev = video_get_drvdata(video_devdata(file));
335 if (dev->owner == file)
336 dev->owner = NULL;
340 * @brief Enable video stream
342 * @param dev Pointer to device structure
343 * @param mode Mode for video stream
345 * @returns 0 or negative error value
348 int v4l2_enable_video(struct usb_microdia *dev, int mode)
350 int ret;
352 if (mode == MICRODIA_MODE_IDLE) {
353 dev_microdia_stop_stream(dev);
354 usb_microdia_isoc_cleanup(dev);
355 dev_microdia_camera_off(dev);
356 microdia_queue_enable(&dev->queue, 0);
357 dev->mode = mode;
358 return 0;
361 if (dev->mode != MICRODIA_MODE_IDLE)
362 return -EBUSY;
364 if (microdia_queue_enable(&dev->queue, 1) < 0)
365 return -EBUSY;
367 dev_microdia_camera_on(dev);
368 ret = usb_microdia_isoc_init(dev);
370 if (ret)
371 return ret;
373 dev_microdia_start_stream(dev);
374 dev_microdia_camera_settings(dev);
375 dev->mode = mode;
377 return 0;
381 * @param inode Pointer on an inode
382 * @param fp File pointer
384 * @returns 0 if all is OK
386 * @brief Open the video device
388 * This function permits to open a video device (/dev/videoX)
390 static int v4l_microdia_open(struct inode *inode, struct file *fp)
392 int ret = 0;
394 struct usb_microdia *dev;
395 struct video_device *vdev;
397 mutex_lock(&open_lock);
399 vdev = video_devdata(fp);
400 dev = video_get_drvdata(video_devdata(fp));
402 fp->private_data = vdev;
404 kref_get(&dev->vopen);
406 mutex_unlock(&open_lock);
407 return ret;
412 * @param inode Pointer on inode
413 * @param fp File pointer
415 * @returns 0 if all is OK
417 * @brief Release an opened file.
419 * This function permits to release an opened file with the 'open' method.
421 static int v4l_microdia_release(struct inode *inode, struct file *fp)
423 struct usb_microdia *dev;
424 struct video_device *vdev;
426 mutex_lock(&open_lock);
428 vdev = video_devdata(fp);
429 dev = video_get_drvdata(video_devdata(fp));
431 if (v4l_has_privileges(fp)) {
432 v4l2_enable_video(dev, MICRODIA_MODE_IDLE);
434 mutex_lock(&dev->queue.mutex);
435 microdia_free_buffers(&dev->queue);
436 mutex_unlock(&dev->queue.mutex);
439 v4l_drop_privileges(fp);
441 kref_put(&dev->vopen, usb_microdia_delete);
443 mutex_unlock(&open_lock);
444 return 0;
449 * @param fp File pointer
451 * @retval buf Buffer in user space
452 * @retval count
453 * @retval f_pos
455 * @returns Count value
457 * @brief Read the video device
459 * This function is called by the application is reading the video device.
461 static ssize_t v4l_microdia_read(struct file *fp, char __user *buf,
462 size_t count, loff_t *f_pos)
464 int i, ret;
465 int nbuffers;
466 struct v4l2_buffer buffer;
467 struct usb_microdia *dev;
469 dev = video_get_drvdata(video_devdata(fp));
471 ret = v4l_get_privileges(fp);
472 if (ret < 0)
473 return ret;
475 if (dev->mode != MICRODIA_MODE_IDLE &&
476 dev->mode != MICRODIA_MODE_READ)
477 return -EBUSY;
479 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
480 buffer.memory = V4L2_MEMORY_MMAP;
481 if (dev->mode == MICRODIA_MODE_IDLE) {
482 nbuffers = microdia_alloc_buffers(&dev->queue, 2,
483 MICRODIA_FRAME_SIZE);
484 if (nbuffers < 0)
485 return nbuffers;
487 for (i = 0; i < nbuffers; i++) {
488 buffer = dev->queue.buffer[i].buf;
489 microdia_queue_buffer(&dev->queue, &buffer);
492 ret = v4l2_enable_video(dev, MICRODIA_MODE_READ);
493 if (ret < 0)
494 return ret;
497 if (dev->queue.read_buffer == NULL) {
498 ret = microdia_dequeue_buffer(&dev->queue, &buffer,
499 fp->f_flags & O_NONBLOCK);
500 if (ret < 0)
501 return ret;
503 microdia_decompress(dev, &buffer);
504 dev->queue.read_buffer = &dev->queue.buffer[buffer.index];
505 } else {
506 buffer = dev->queue.read_buffer->buf;
509 count = min((size_t)(buffer.bytesused - *f_pos), count);
510 if (copy_to_user(buf, dev->queue.mem + buffer.m.offset + *f_pos, count))
511 return -EFAULT;
513 *f_pos += count;
514 if (*f_pos >= buffer.bytesused) {
515 dev->queue.read_buffer = NULL;
516 microdia_queue_buffer(&dev->queue, &buffer);
517 *f_pos = 0;
519 return count;
524 * @param fp File pointer
525 * @param wait
527 * @returns 0 if all is OK
529 * @brief Polling function
531 static unsigned int v4l_microdia_poll(struct file *fp, poll_table *wait)
533 struct usb_microdia *dev;
534 struct video_device *vdev;
536 vdev = video_devdata(fp);
537 dev = video_get_drvdata(video_devdata(fp));
539 UDIA_STREAM("Poll\n");
541 if (vdev == NULL || dev == NULL)
542 return -EFAULT;
544 return microdia_queue_poll(&dev->queue, fp, wait);
548 * @param vma
551 static void microdia_vm_open(struct vm_area_struct *vma)
553 struct microdia_buffer *buffer = vma->vm_private_data;
554 buffer->vma_use_count++;
559 * @param vma
562 static void microdia_vm_close(struct vm_area_struct *vma)
564 struct microdia_buffer *buffer = vma->vm_private_data;
565 buffer->vma_use_count--;
568 struct vm_operations_struct microdia_vm_ops = {
569 .open = microdia_vm_open,
570 .close = microdia_vm_close
574 * @param fp File pointer
575 * @param vma VMA structure
577 * @returns 0 if all is OK
579 * @brief Memory map
581 * This function permits to map a memory space.
583 static int v4l_microdia_mmap(struct file *fp, struct vm_area_struct *vma)
585 struct page *page;
586 unsigned long addr, start, size;
587 unsigned int i;
588 int ret = 0;
590 struct usb_microdia *dev;
591 struct video_device *vdev;
592 struct microdia_buffer *buffer = NULL;
594 vdev = video_devdata(fp);
595 dev = video_get_drvdata(video_devdata(fp));
597 UDIA_STREAM("mmap\n");
599 start = vma->vm_start;
600 size = vma->vm_end - vma->vm_start;
602 mutex_lock(&dev->queue.mutex);
604 for (i = 0; i < dev->queue.count; ++i) {
605 buffer = &dev->queue.buffer[i];
606 if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
607 break;
610 if (i == dev->queue.count || size != dev->queue.buf_size) {
611 ret = -EINVAL;
612 goto done;
615 vma->vm_flags |= VM_IO;
617 addr = (unsigned long)dev->queue.mem + buffer->buf.m.offset;
618 while (size > 0) {
619 page = vmalloc_to_page((void *)addr);
620 ret = vm_insert_page(vma, start, page);
621 if (ret < 0)
622 goto done;
624 start += PAGE_SIZE;
625 addr += PAGE_SIZE;
626 size -= PAGE_SIZE;
629 vma->vm_ops = &microdia_vm_ops;
630 vma->vm_private_data = buffer;
631 microdia_vm_open(vma);
632 done:
633 mutex_unlock(&dev->queue.mutex);
634 return ret;
638 * @param file
639 * @param priv
640 * @param cap
642 * @return 0
645 int microdia_vidioc_querycap(struct file *file, void *priv,
646 struct v4l2_capability *cap)
648 struct usb_microdia *dev;
650 dev = video_get_drvdata(priv);
652 UDIA_DEBUG("VIDIOC_QUERYCAP\n");
654 strlcpy(cap->driver, "microdia", sizeof(cap->driver));
655 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
656 | V4L2_CAP_READWRITE;
657 cap->version = (__u32) DRIVER_VERSION_NUM,
658 strlcpy(cap->card, dev->vdev->name, sizeof(cap->card));
660 if (usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)) < 0)
661 strlcpy(cap->bus_info, dev->vdev->name, sizeof(cap->bus_info));
662 return 0;
666 * @param file
667 * @param priv
668 * @param input
670 * @return 0 or negative error code
673 int microdia_vidioc_enum_input(struct file *file, void *priv,
674 struct v4l2_input *input)
676 UDIA_DEBUG("VIDIOC_ENUMINPUT %d\n", input->index);
678 if (input->index)
679 return -EINVAL;
681 strlcpy(input->name, "Webcam", sizeof(input->name));
682 input->type = V4L2_INPUT_TYPE_CAMERA;
683 input->std = 0;
685 return 0;
689 * @param file
690 * @param priv
691 * @param index
693 * @return 0 or negative error code
696 int microdia_vidioc_g_input(struct file *file, void *priv, unsigned int *index)
698 UDIA_DEBUG("GET INPUT %d\n", *index);
700 if (index)
701 return -EINVAL;
703 return 0;
707 * @param file
708 * @param priv
709 * @param index
711 * @return 0 or negative error code
714 int microdia_vidioc_s_input(struct file *file, void *priv, unsigned int index)
716 UDIA_DEBUG("SET INPUT %d\n", index);
718 if (v4l_get_privileges(file) < 0)
719 return -EBUSY;
721 if (index != 0)
722 return -EINVAL;
724 return 0;
728 * @param file
729 * @param priv
730 * @param ctrl
732 * @return 0 or negative error code
735 int microdia_vidioc_queryctrl(struct file *file, void *priv,
736 struct v4l2_queryctrl *ctrl)
738 int i;
739 int nbr;
741 UDIA_DEBUG("VIDIOC_QUERYCTRL id = %d\n", ctrl->id);
743 nbr = sizeof(microdia_controls)/sizeof(struct v4l2_queryctrl);
745 for (i = 0; i < nbr; i++) {
746 if (microdia_controls[i].id == ctrl->id) {
747 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
748 memcpy(ctrl, &microdia_controls[i],
749 sizeof(struct v4l2_queryctrl));
750 break;
754 if (i >= nbr)
755 return -EINVAL;
757 return 0;
761 * @param file
762 * @param priv
763 * @param ctrl
765 * @return 0 or negative error code
768 int microdia_vidioc_g_ctrl(struct file *file, void *priv,
769 struct v4l2_control *ctrl)
771 struct usb_microdia *dev;
773 dev = video_get_drvdata(priv);
775 UDIA_DEBUG("GET CTRL id=%d\n", ctrl->id);
777 switch (ctrl->id) {
778 case V4L2_CID_BRIGHTNESS:
779 ctrl->value = dev->vsettings.brightness;
780 break;
782 case V4L2_CID_EXPOSURE:
783 ctrl->value = dev->vsettings.exposure;
784 break;
786 case V4L2_CID_WHITENESS:
787 ctrl->value = dev->vsettings.whiteness;
788 break;
790 case V4L2_CID_SATURATION:
791 ctrl->value = dev->vsettings.colour;
792 break;
794 case V4L2_CID_CONTRAST:
795 ctrl->value = dev->vsettings.contrast;
796 break;
798 case V4L2_CID_HFLIP:
799 ctrl->value = dev->vsettings.hflip;
800 break;
802 case V4L2_CID_VFLIP:
803 ctrl->value = dev->vsettings.vflip;
804 break;
806 case V4L2_CID_SHARPNESS:
807 ctrl->value = dev->vsettings.sharpness;
808 break;
810 case V4L2_CID_RED_BALANCE:
811 ctrl->value = dev->vsettings.rgb_gain[0];
812 break;
814 case V4L2_CID_BLUE_BALANCE:
815 ctrl->value = dev->vsettings.rgb_gain[3];
816 break;
818 case V4L2_CID_AUTOEXPOSURE:
819 ctrl->value = dev->vsettings.auto_exposure;
820 break;
822 case V4L2_CID_AUTO_WHITE_BALANCE:
823 ctrl->value = dev->vsettings.auto_whitebalance;
824 break;
826 default:
827 return -EINVAL;
829 return 0;
833 * @brief Apply v4l2 settings on camera
835 * @param file
836 * @param priv
837 * @param ctrl V4L2 control structure
839 * @returns 0 or negative error value
842 int microdia_vidioc_s_ctrl(struct file *file, void *priv,
843 struct v4l2_control *ctrl)
845 struct usb_microdia *dev;
847 dev = video_get_drvdata(priv);
849 UDIA_DEBUG("SET CTRL id=%d value=%d\n", ctrl->id, ctrl->value);
851 switch (ctrl->id) {
852 case V4L2_CID_BRIGHTNESS:
853 dev->vsettings.brightness = (0xff00 & ctrl->value);
854 dev_microdia_camera_set_brightness(dev);
855 break;
857 case V4L2_CID_EXPOSURE:
858 dev->vsettings.exposure = (0xff00 & ctrl->value);
859 dev_microdia_camera_set_exposure(dev);
860 break;
862 case V4L2_CID_WHITENESS:
863 dev->vsettings.whiteness = (0xff00 & ctrl->value);
864 dev_microdia_camera_set_gamma(dev);
865 break;
867 case V4L2_CID_SATURATION:
868 dev->vsettings.colour = (0xff00 & ctrl->value);
869 break;
871 case V4L2_CID_CONTRAST:
872 dev->vsettings.contrast = (0xff00 & ctrl->value);
873 dev_microdia_camera_set_contrast(dev);
874 break;
876 case V4L2_CID_HFLIP:
877 dev->vsettings.hflip = ctrl->value;
878 dev_microdia_camera_set_hvflip(dev);
879 break;
881 case V4L2_CID_VFLIP:
882 dev->vsettings.vflip = ctrl->value;
883 dev_microdia_camera_set_hvflip(dev);
884 break;
886 case V4L2_CID_SHARPNESS:
887 dev->vsettings.sharpness = ctrl->value;
888 dev_microdia_camera_set_sharpness(dev);
889 break;
891 case V4L2_CID_RED_BALANCE:
892 dev->vsettings.rgb_gain[0] = ctrl->value;
893 dev_microdia_camera_set_rgb_gain(dev);
894 break;
896 case V4L2_CID_BLUE_BALANCE:
897 dev->vsettings.rgb_gain[3] = ctrl->value;
898 dev_microdia_camera_set_rgb_gain(dev);
899 break;
901 case V4L2_CID_AUTOEXPOSURE:
902 dev->vsettings.auto_exposure = ctrl->value;
903 dev_microdia_camera_set_auto_exposure(dev);
904 break;
906 case V4L2_CID_AUTO_WHITE_BALANCE:
907 dev->vsettings.auto_whitebalance = ctrl->value;
908 dev_microdia_camera_set_auto_whitebalance(dev);
909 break;
911 default:
912 return -EINVAL;
915 return 0;
919 * @param file
920 * @param priv
921 * @param fmt
923 * @return 0 or negative error code
926 int microdia_vidioc_enum_fmt_cap(struct file *file, void *priv,
927 struct v4l2_fmtdesc *fmt)
929 struct usb_microdia *dev;
930 struct v4l2_pix_format *format;
932 dev = video_get_drvdata(priv);
934 UDIA_DEBUG("VIDIOC_ENUM_FMT %d\n", fmt->index);
936 format = v4l2_enum_supported_formats(dev, fmt->index);
937 if (format == NULL)
938 return -EINVAL;
940 fmt->flags = 0;
941 fmt->pixelformat = format->pixelformat;
942 fmt->description[0] = fmt->pixelformat & 0xFF;
943 fmt->description[1] = (fmt->pixelformat >> 8) & 0xFF;
944 fmt->description[2] = (fmt->pixelformat >> 16) & 0xFF;
945 fmt->description[3] = fmt->pixelformat >> 24;
946 fmt->description[4] = 0;
948 return 0;
952 * @param file
953 * @param priv
954 * @param fmt
956 * @return 0 or negative error code
959 int microdia_vidioc_try_fmt_cap(struct file *file, void *priv,
960 struct v4l2_format *fmt)
962 struct usb_microdia *dev;
964 dev = video_get_drvdata(priv);
965 UDIA_DEBUG("TRY FMT %d\n", fmt->type);
967 /* when this code is used prevents mplayer from setting outfmt
968 if(fmt->fmt.pix.field != V4L2_FIELD_NONE)
969 return -EINVAL;
972 if (v4l2_format_supported(dev, fmt->fmt.pix.pixelformat) < 0)
973 return -EINVAL;
975 sn9c20x_get_closest_resolution(&fmt->fmt.pix.width,
976 &fmt->fmt.pix.height);
978 switch (fmt->fmt.pix.pixelformat) {
979 case V4L2_PIX_FMT_YUV420:
980 fmt->fmt.pix.bytesperline = (fmt->fmt.pix.width * 3)/2;
981 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
982 fmt->fmt.pix.bytesperline;
983 break;
984 case V4L2_PIX_FMT_RGB24:
985 case V4L2_PIX_FMT_BGR24:
986 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3;
987 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
988 fmt->fmt.pix.bytesperline;
989 break;
990 case V4L2_PIX_FMT_YUYV:
991 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 2;
992 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
993 fmt->fmt.pix.bytesperline;
994 break;
995 default:
996 return -EINVAL;
999 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
1000 fmt->fmt.pix.priv = 0;
1002 return 0;
1006 * @param file
1007 * @param priv
1008 * @param fmt
1010 * @return 0
1013 int microdia_vidioc_g_fmt_cap(struct file *file, void *priv,
1014 struct v4l2_format *fmt)
1016 struct usb_microdia *dev;
1018 dev = video_get_drvdata(priv);
1020 UDIA_DEBUG("GET FMT %d\n", fmt->type);
1022 memcpy(&(fmt->fmt.pix), &(dev->vsettings.format), sizeof(fmt->fmt.pix));
1025 return 0;
1029 * @param file
1030 * @param priv
1031 * @param fmt
1033 * @return 0 or negative error code
1036 int microdia_vidioc_s_fmt_cap(struct file *file, void *priv,
1037 struct v4l2_format *fmt)
1039 struct usb_microdia *dev;
1040 int ret;
1042 dev = video_get_drvdata(priv);
1044 UDIA_DEBUG("SET FMT %d : %d\n", fmt->type, fmt->fmt.pix.pixelformat);
1046 if (v4l_get_privileges(file) < 0)
1047 return -EBUSY;
1049 if (dev->queue.streaming)
1050 return -EBUSY;
1052 ret = microdia_vidioc_try_fmt_cap(file, priv, fmt);
1053 if (ret)
1054 return -EINVAL;
1056 sn9c20x_set_resolution(dev, fmt->fmt.pix.width, fmt->fmt.pix.height);
1058 memcpy(&(dev->vsettings.format), &(fmt->fmt.pix), sizeof(fmt->fmt.pix));
1060 return 0;
1064 * @param file
1065 * @param priv
1066 * @param request
1068 * @return 0 or negative error code
1071 int microdia_vidioc_reqbufs(struct file *file, void *priv,
1072 struct v4l2_requestbuffers *request)
1074 int ret = 0;
1075 struct usb_microdia *dev;
1077 dev = video_get_drvdata(priv);
1079 if (v4l_get_privileges(file) < 0) {
1080 ret = -EBUSY;
1081 goto done;
1084 if (request->memory != V4L2_MEMORY_MMAP ||
1085 request->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1086 ret = -EINVAL;
1087 goto done;
1090 if (dev->queue.streaming) {
1091 ret = -EBUSY;
1092 goto done;
1095 ret = microdia_alloc_buffers(&dev->queue, request->count,
1096 MICRODIA_FRAME_SIZE);
1097 if (ret < 0)
1098 goto done;
1100 dev->queue.drop_incomplete = 1;
1102 request->count = ret;
1103 ret = 0;
1104 UDIA_INFO("Buffers Allocated %d\n", request->count);
1105 done:
1106 return ret;
1110 * @param file
1111 * @param priv
1112 * @param buffer
1114 * @return 0 or negative error code
1117 int microdia_vidioc_querybuf(struct file *file, void *priv,
1118 struct v4l2_buffer *buffer)
1120 struct usb_microdia *dev;
1122 dev = video_get_drvdata(priv);
1124 UDIA_DEBUG("QUERY BUFFERS %d %d\n", buffer->index, dev->queue.count);
1126 if (buffer->memory != V4L2_MEMORY_MMAP ||
1127 buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1128 return -EINVAL;
1130 if (!v4l_has_privileges(file))
1131 return -EBUSY;
1133 return microdia_query_buffer(&dev->queue, buffer);
1137 * @param file
1138 * @param priv
1139 * @param buffer
1141 * @return 0 or negative error code
1144 int microdia_vidioc_qbuf(struct file *file, void *priv,
1145 struct v4l2_buffer *buffer)
1147 struct usb_microdia *dev;
1149 dev = video_get_drvdata(priv);
1151 UDIA_DEBUG("VIDIOC_QBUF\n");
1153 if (!v4l_has_privileges(file))
1154 return -EBUSY;
1156 return microdia_queue_buffer(&dev->queue, buffer);
1160 * @param file
1161 * @param priv
1162 * @param buffer
1164 * @return 0 or negative error code
1167 int microdia_vidioc_dqbuf(struct file *file, void *priv,
1168 struct v4l2_buffer *buffer)
1170 struct usb_microdia *dev;
1171 int ret = 0;
1173 dev = video_get_drvdata(priv);
1175 UDIA_DEBUG("VIDIOC_DQBUF\n");
1177 if (!v4l_has_privileges(file))
1178 return -EBUSY;
1180 ret = microdia_dequeue_buffer(&dev->queue, buffer,
1181 file->f_flags & O_NONBLOCK);
1182 if (ret < 0)
1183 return ret;
1185 microdia_decompress(dev, buffer);
1187 return ret;
1191 * @param file
1192 * @param priv
1193 * @param type
1195 * @return 0 or negative error code
1198 int microdia_vidioc_streamon(struct file *file, void *priv,
1199 enum v4l2_buf_type type)
1201 struct usb_microdia *dev;
1203 dev = video_get_drvdata(priv);
1205 UDIA_DEBUG("VIDIOC_STREAMON\n");
1207 if (!v4l_has_privileges(file))
1208 return -EBUSY;
1210 if (dev->mode != MICRODIA_MODE_IDLE)
1211 return -EBUSY;
1213 return v4l2_enable_video(dev, MICRODIA_MODE_STREAM);
1217 * @param file
1218 * @param priv
1219 * @param type
1221 * @return 0 or negative error code
1224 int microdia_vidioc_streamoff(struct file *file, void *priv,
1225 enum v4l2_buf_type type)
1227 struct usb_microdia *dev;
1229 dev = video_get_drvdata(priv);
1231 UDIA_DEBUG("VIDIOC_STREAMOFF\n");
1233 if (!v4l_has_privileges(file))
1234 return -EBUSY;
1236 return v4l2_enable_video(dev, MICRODIA_MODE_IDLE);
1240 * @param file
1241 * @param priv
1242 * @param param
1244 * @return 0 or negative error code
1247 int microdia_vidioc_g_param(struct file *file, void *priv,
1248 struct v4l2_streamparm *param)
1250 struct usb_microdia *dev;
1253 dev = video_get_drvdata(priv);
1255 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1256 return -EINVAL;
1258 param->parm.capture.capability = 0;
1259 param->parm.capture.capturemode = 0;
1260 param->parm.capture.timeperframe.numerator = 1;
1261 param->parm.capture.timeperframe.denominator = 30;
1262 param->parm.capture.readbuffers = 2;
1263 param->parm.capture.extendedmode = 0;
1265 return 0;
1269 * @param file
1270 * @param priv
1271 * @param param
1273 * @return 0 or negative error code
1276 int microdia_vidioc_s_param(struct file *file, void *priv,
1277 struct v4l2_streamparm *param)
1279 struct usb_microdia *dev;
1281 dev = video_get_drvdata(priv);
1283 if (v4l_get_privileges(file))
1284 return -EBUSY;
1286 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1287 return -EINVAL;
1289 return 0;
1293 * @param inode Inode pointer
1294 * @param fp File pointer
1295 * @param cmd Command
1296 * @param arg Arguements of the command
1298 * @returns 0 if all is OK
1300 * @brief Manage IOCTL
1302 * This function permits to manage all the IOCTL from the application.
1304 static int v4l_microdia_ioctl(struct inode *inode, struct file *fp,
1305 unsigned int cmd, unsigned long arg)
1307 int err;
1308 struct usb_microdia *dev;
1309 struct video_device *vdev;
1311 vdev = video_devdata(fp);
1312 dev = video_get_drvdata(video_devdata(fp));
1314 UDIA_DEBUG("v4l_microdia_ioctl %02X\n", (unsigned char) cmd);
1316 if (dev == NULL || vdev == NULL)
1317 return -EFAULT;
1319 err = video_ioctl2(inode, fp, cmd, arg);
1321 return err;
1325 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1326 static const struct v4l2_ioctl_ops microdia_v4l2_ioctl_ops = {
1327 .vidioc_querycap = microdia_vidioc_querycap,
1328 .vidioc_enum_fmt_vid_cap = microdia_vidioc_enum_fmt_cap,
1329 .vidioc_try_fmt_vid_cap = microdia_vidioc_try_fmt_cap,
1330 .vidioc_s_fmt_vid_cap = microdia_vidioc_s_fmt_cap,
1331 .vidioc_g_fmt_vid_cap = microdia_vidioc_g_fmt_cap,
1332 .vidioc_enum_input = microdia_vidioc_enum_input,
1333 .vidioc_g_input = microdia_vidioc_g_input,
1334 .vidioc_s_input = microdia_vidioc_s_input,
1335 .vidioc_streamon = microdia_vidioc_streamon,
1336 .vidioc_streamoff = microdia_vidioc_streamoff,
1337 .vidioc_queryctrl = microdia_vidioc_queryctrl,
1338 .vidioc_g_ctrl = microdia_vidioc_g_ctrl,
1339 .vidioc_s_ctrl = microdia_vidioc_s_ctrl,
1340 .vidioc_g_parm = microdia_vidioc_g_param,
1341 .vidioc_s_parm = microdia_vidioc_s_param,
1342 .vidioc_reqbufs = microdia_vidioc_reqbufs,
1343 .vidioc_qbuf = microdia_vidioc_qbuf,
1344 .vidioc_dqbuf = microdia_vidioc_dqbuf,
1345 .vidioc_querybuf = microdia_vidioc_querybuf,
1347 #endif
1350 * @param dev Device structure
1352 * @returns 0 if all is OK
1354 * @brief Register the video device
1356 * This function permits to register the USB device to the video device.
1358 int v4l_microdia_register_video_device(struct usb_microdia *dev)
1360 int err;
1362 strcpy(dev->vdev->name, DRIVER_DESC);
1364 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1365 dev->vdev->dev = &dev->interface->dev;
1366 dev->vdev->owner = THIS_MODULE;
1367 dev->vdev->type = VID_TYPE_CAPTURE;
1368 #else
1369 dev->vdev->dev = dev->interface->dev;
1370 #endif
1371 dev->vdev->current_norm = 0;
1372 dev->vdev->tvnorms = 0;
1373 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1374 dev->vdev->hardware = VID_HARDWARE_MICRODIA;
1375 #endif
1376 dev->vdev->fops = &v4l_microdia_fops;
1377 dev->vdev->release = video_device_release;
1378 dev->vdev->minor = -1;
1380 if (log_level & MICRODIA_DEBUG)
1381 dev->vdev->debug = V4L2_DEBUG_IOCTL_ARG;
1383 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
1384 dev->vdev->vidioc_querycap = microdia_vidioc_querycap;
1385 dev->vdev->vidioc_enum_fmt_cap = microdia_vidioc_enum_fmt_cap;
1386 dev->vdev->vidioc_try_fmt_cap = microdia_vidioc_try_fmt_cap;
1387 dev->vdev->vidioc_s_fmt_cap = microdia_vidioc_s_fmt_cap;
1388 dev->vdev->vidioc_g_fmt_cap = microdia_vidioc_g_fmt_cap;
1389 dev->vdev->vidioc_enum_input = microdia_vidioc_enum_input;
1390 dev->vdev->vidioc_g_input = microdia_vidioc_g_input;
1391 dev->vdev->vidioc_s_input = microdia_vidioc_s_input;
1392 dev->vdev->vidioc_streamon = microdia_vidioc_streamon;
1393 dev->vdev->vidioc_streamoff = microdia_vidioc_streamoff;
1394 dev->vdev->vidioc_queryctrl = microdia_vidioc_queryctrl;
1395 dev->vdev->vidioc_g_ctrl = microdia_vidioc_g_ctrl;
1396 dev->vdev->vidioc_s_ctrl = microdia_vidioc_s_ctrl;
1397 dev->vdev->vidioc_g_parm = microdia_vidioc_g_param;
1398 dev->vdev->vidioc_s_parm = microdia_vidioc_s_param;
1399 dev->vdev->vidioc_reqbufs = microdia_vidioc_reqbufs;
1400 dev->vdev->vidioc_qbuf = microdia_vidioc_qbuf;
1401 dev->vdev->vidioc_dqbuf = microdia_vidioc_dqbuf;
1402 dev->vdev->vidioc_querybuf = microdia_vidioc_querybuf;
1403 #else
1404 dev->vdev->ioctl_ops = &microdia_v4l2_ioctl_ops;
1405 #endif
1407 video_set_drvdata(dev->vdev, dev);
1409 microdia_queue_init(&dev->queue);
1411 err = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
1413 if (err)
1414 UDIA_ERROR("Video register fail !\n");
1415 else
1416 UDIA_INFO("Microdia USB 2.0 Webcam is now controlling "
1417 "video device /dev/video%d\n",
1418 dev->vdev->minor);
1420 return err;
1425 * @param dev Device structure
1427 * @returns 0 if all is OK
1429 * @brief Unregister the video device
1431 * This function permits to unregister the video device.
1433 int v4l_microdia_unregister_video_device(struct usb_microdia *dev)
1435 UDIA_INFO("Microdia USB 2.0 Webcam releases control of video "
1436 "device /dev/video%d\n", dev->vdev->minor);
1438 video_set_drvdata(dev->vdev, NULL);
1439 video_unregister_device(dev->vdev);
1441 return 0;
1446 * @var v4l_microdia_fops
1448 * This variable contains some callback
1450 static struct file_operations v4l_microdia_fops = {
1451 .owner = THIS_MODULE,
1452 .open = v4l_microdia_open,
1453 .release = v4l_microdia_release,
1454 .read = v4l_microdia_read,
1455 .poll = v4l_microdia_poll,
1456 .mmap = v4l_microdia_mmap,
1457 .ioctl = v4l_microdia_ioctl,
1458 #ifdef CONFIG_COMPAT
1459 .compat_ioctl = v4l_compat_ioctl32,
1460 #endif
1461 .llseek = no_llseek