Fix "brief" file summary for some source files
[microdia.git] / microdia-v4l.c
blobfc46ee2fcf04432d9ef0194fe94349f1a1bba297
1 /**
2 * @file microdia-v4l.c
3 * @author Nicolas VIVIEN
4 * @date 2008-02-01
5 * @version v0.0.0
7 * @brief V4L2 interface and functions
9 * @note Copyright (C) Nicolas VIVIEN
11 * @par Licences
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/version.h>
32 #include <linux/errno.h>
33 #include <linux/slab.h>
34 #include <linux/kref.h>
35 #include <linux/vmalloc.h>
36 #include <linux/usb.h>
37 #include <media/v4l2-common.h>
39 #include "microdia.h"
40 #include "sn9c20x.h"
43 /* USER DEFINED V4L2-CONTROLS: */
44 #define V4L2_CID_SHARPNESS (V4L2_CID_PRIVATE_BASE + 0)
45 #define V4L2_CID_AUTOEXPOSURE (V4L2_CID_PRIVATE_BASE + 1)
48 static struct file_operations v4l_microdia_fops;
50 /**
51 * format list
54 #define NUM_V4L2_FORMATS 4
56 struct v4l2_pix_format microdia_fmts[] = {
58 .width = 640,
59 .height = 480,
60 .pixelformat = V4L2_PIX_FMT_YUV420,
61 .field = V4L2_FIELD_NONE,
62 .bytesperline = 960,
63 .sizeimage = 460800,
64 .colorspace = V4L2_COLORSPACE_SRGB,
65 .priv = 0
68 .width = 640,
69 .height = 480,
70 .pixelformat = V4L2_PIX_FMT_BGR24,
71 .field = V4L2_FIELD_NONE,
72 .bytesperline = 1920,
73 .sizeimage = 921600,
74 .colorspace = V4L2_COLORSPACE_SRGB,
75 .priv = 0
78 .width = 640,
79 .height = 480,
80 .pixelformat = V4L2_PIX_FMT_RGB24,
81 .field = V4L2_FIELD_NONE,
82 .bytesperline = 1920,
83 .sizeimage = 921600,
84 .colorspace = V4L2_COLORSPACE_SRGB,
85 .priv = 0
88 .width = 640,
89 .height = 480,
90 .pixelformat = V4L2_PIX_FMT_YUYV,
91 .field = V4L2_FIELD_NONE,
92 .bytesperline = 1280,
93 .sizeimage = 614400,
94 .colorspace = V4L2_COLORSPACE_SRGB,
95 .priv = 0
99 /**
100 * @param dev
101 * @param fmt v4l2 fmt id
103 * @returns index of requested format
105 * @brief check if v4l2 forat is supported by device.
107 * This function permits to check if v4l2 format is supported.
109 int v4l2_format_supported(struct usb_microdia *dev, __u32 fmt)
111 int i;
112 for (i = 0; i < sizeof(dev->supported_fmts) * 8; i++) {
113 if (i > (ARRAY_SIZE(microdia_fmts) - 1))
114 break;
115 if (dev->supported_fmts & (1 << i) &&
116 microdia_fmts[i].pixelformat == fmt)
117 return i;
119 return -EINVAL;
123 * @param dev
124 * @param index format index
126 * @returns reference to format structure
128 * @brief enumerate supported formats
130 * This function will enumerate all supported formats.
132 struct v4l2_pix_format *v4l2_enum_supported_formats(struct usb_microdia *dev,
133 __u8 index)
135 int i, bit = 0;
136 for (i = 0; i < sizeof(dev->supported_fmts) * 8; i++) {
137 if (i > (ARRAY_SIZE(microdia_fmts) - 1))
138 break;
139 if (dev->supported_fmts & (1 << i)) {
140 if (bit == index)
141 return &microdia_fmts[i];
142 bit++;
145 return NULL;
149 * @var microdia_controls
150 * List of all V4Lv2 controls supported by the driver
152 static struct v4l2_queryctrl microdia_controls[] = {
154 .id = V4L2_CID_BRIGHTNESS,
155 .type = V4L2_CTRL_TYPE_INTEGER,
156 .name = "Brightness",
157 .minimum = 0,
158 .maximum = 0xff00,
159 .step = 1,
160 .default_value = 0x7f00,
163 .id = V4L2_CID_WHITENESS,
164 .type = V4L2_CTRL_TYPE_INTEGER,
165 .name = "Whiteness",
166 .minimum = 0,
167 .maximum = 0xff00,
168 .step = 1,
169 .default_value = 0x7f00,
173 .id = V4L2_CID_SATURATION,
174 .type = V4L2_CTRL_TYPE_INTEGER,
175 .name = "Saturation",
176 .minimum = 0,
177 .maximum = 0xff00,
178 .step = 1,
179 .default_value = 0x7f00,
183 .id = V4L2_CID_CONTRAST,
184 .type = V4L2_CTRL_TYPE_INTEGER,
185 .name = "Contrast",
186 .minimum = 0,
187 .maximum = 0xff00,
188 .step = 1,
189 .default_value = 0x0000,
192 .id = V4L2_CID_EXPOSURE,
193 .type = V4L2_CTRL_TYPE_INTEGER,
194 .name = "Exposure",
195 .minimum = 0,
196 .maximum = 0xff00,
197 .step = 1,
198 .default_value = 0x1000,
201 .id = V4L2_CID_HFLIP,
202 .type = V4L2_CTRL_TYPE_BOOLEAN,
203 .name = "Horizontal flip",
204 .minimum = 0,
205 .maximum = 1,
206 .step = 1,
207 .default_value = 0,
210 .id = V4L2_CID_VFLIP,
211 .type = V4L2_CTRL_TYPE_BOOLEAN,
212 .name = "Vertical flip",
213 .minimum = 0,
214 .maximum = 1,
215 .step = 1,
216 .default_value = 0,
219 .id = V4L2_CID_SHARPNESS,
220 .type = V4L2_CTRL_TYPE_INTEGER,
221 .name = "Sharpness",
222 .minimum = 0,
223 .maximum = 0x3f,
224 .step = 1,
225 .default_value = 0x1f,
228 .id = V4L2_CID_RED_BALANCE,
229 .type = V4L2_CTRL_TYPE_INTEGER,
230 .name = "Red Balance",
231 .minimum = 0,
232 .maximum = 0x7f,
233 .step = 1,
234 .default_value = 0x20,
237 .id = V4L2_CID_BLUE_BALANCE,
238 .type = V4L2_CTRL_TYPE_INTEGER,
239 .name = "Blue Balance",
240 .minimum = 0,
241 .maximum = 0x7f,
242 .step = 1,
243 .default_value = 0x20,
246 .id = V4L2_CID_AUTOEXPOSURE,
247 .type = V4L2_CTRL_TYPE_BOOLEAN,
248 .name = "Automatic exposure control",
249 .minimum = 0,
250 .maximum = 1,
251 .step = 1,
252 .default_value = 0,
255 .id = V4L2_CID_AUTO_WHITE_BALANCE,
256 .type = V4L2_CTRL_TYPE_BOOLEAN,
257 .name = "Automatic whitbalance control",
258 .minimum = 0,
259 .maximum = 1,
260 .step = 1,
261 .default_value = 0,
266 * The following three functions are used to get, test and drop v4l privleges.
268 int v4l_get_privileges(struct file *file)
270 struct usb_microdia *dev;
271 int ret = 0;
273 dev = video_get_drvdata(video_devdata(file));
275 if (dev->owner == file)
276 return 0;
278 mutex_lock(&open_lock);
279 if (dev->owner != NULL) {
280 ret = -EBUSY;
281 goto done;
283 dev->owner = file;
284 done:
285 mutex_unlock(&open_lock);
286 return ret;
289 int v4l_has_privileges(struct file *file)
291 struct usb_microdia *dev;
292 int ret = 0;
294 dev = video_get_drvdata(video_devdata(file));
296 if (dev->owner == file)
297 ret = 1;
299 return ret;
302 void v4l_drop_privileges(struct file *file)
304 struct usb_microdia *dev;
306 dev = video_get_drvdata(video_devdata(file));
308 if (dev->owner == file)
309 dev->owner = NULL;
313 * @brief Enable video stream
315 * @param dev Pointer to device structure
316 * @param mode Mode for video stream
318 * @returns 0 or negative error value
321 int v4l2_enable_video(struct usb_microdia *dev, int mode)
323 int ret;
325 if (mode == MICRODIA_MODE_IDLE) {
326 dev_microdia_stop_stream(dev);
327 usb_microdia_isoc_cleanup(dev);
328 dev_microdia_camera_off(dev);
329 microdia_queue_enable(&dev->queue, 0);
330 dev->mode = mode;
331 return 0;
334 if (dev->mode != MICRODIA_MODE_IDLE)
335 return -EBUSY;
337 if (microdia_queue_enable(&dev->queue, 1) < 0)
338 return -EBUSY;
340 dev_microdia_camera_on(dev);
341 ret = usb_microdia_isoc_init(dev);
343 if (ret)
344 return ret;
346 dev_microdia_start_stream(dev);
347 dev_microdia_camera_settings(dev);
348 dev->mode = mode;
350 return 0;
354 * @param inode Pointer on an inode
355 * @param fp File pointer
357 * @returns 0 if all is OK
359 * @brief Open the video device
361 * This function permits to open a video device (/dev/videoX)
363 static int v4l_microdia_open(struct inode *inode, struct file *fp)
365 int ret = 0;
367 struct usb_microdia *dev;
368 struct video_device *vdev;
370 mutex_lock(&open_lock);
372 vdev = video_devdata(fp);
373 dev = video_get_drvdata(video_devdata(fp));
375 fp->private_data = vdev;
377 kref_get(&dev->vopen);
379 mutex_unlock(&open_lock);
380 return ret;
385 * @param inode Pointer on inode
386 * @param fp File pointer
388 * @returns 0 if all is OK
390 * @brief Release an opened file.
392 * This function permits to release an opened file with the 'open' method.
394 static int v4l_microdia_release(struct inode *inode, struct file *fp)
396 struct usb_microdia *dev;
397 struct video_device *vdev;
399 mutex_lock(&open_lock);
401 vdev = video_devdata(fp);
402 dev = video_get_drvdata(video_devdata(fp));
404 if (v4l_has_privileges(fp)) {
405 v4l2_enable_video(dev, MICRODIA_MODE_IDLE);
407 mutex_lock(&dev->queue.mutex);
408 microdia_free_buffers(&dev->queue);
409 mutex_unlock(&dev->queue.mutex);
412 v4l_drop_privileges(fp);
414 kref_put(&dev->vopen, usb_microdia_delete);
416 mutex_unlock(&open_lock);
417 return 0;
422 * @param fp File pointer
424 * @retval buf Buffer in user space
425 * @retval count
426 * @retval f_pos
428 * @returns Count value
430 * @brief Read the video device
432 * This function is called by the application is reading the video device.
434 static ssize_t v4l_microdia_read(struct file *fp, char __user *buf,
435 size_t count, loff_t *f_pos)
437 int i, ret;
438 int nbuffers;
439 struct v4l2_buffer buffer;
440 struct usb_microdia *dev;
442 dev = video_get_drvdata(video_devdata(fp));
444 ret = v4l_get_privileges(fp);
445 if (ret < 0)
446 return ret;
448 if (dev->mode != MICRODIA_MODE_IDLE &&
449 dev->mode != MICRODIA_MODE_READ)
450 return -EBUSY;
452 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
453 buffer.memory = V4L2_MEMORY_MMAP;
454 if (dev->mode == MICRODIA_MODE_IDLE) {
455 nbuffers = microdia_alloc_buffers(&dev->queue, 2,
456 MICRODIA_FRAME_SIZE);
457 if (nbuffers < 0)
458 return nbuffers;
460 for (i = 0; i < nbuffers; i++) {
461 buffer = dev->queue.buffer[i].buf;
462 microdia_queue_buffer(&dev->queue, &buffer);
465 ret = v4l2_enable_video(dev, MICRODIA_MODE_READ);
466 if (ret < 0)
467 return ret;
470 if (dev->queue.read_buffer == NULL) {
471 ret = microdia_dequeue_buffer(&dev->queue, &buffer,
472 fp->f_flags & O_NONBLOCK);
473 if (ret < 0)
474 return ret;
476 microdia_decompress(dev, &buffer);
477 dev->queue.read_buffer = &dev->queue.buffer[buffer.index];
478 } else {
479 buffer = dev->queue.read_buffer->buf;
482 count = min((size_t)(buffer.bytesused - *f_pos), count);
483 if (copy_to_user(buf, dev->queue.mem + buffer.m.offset + *f_pos, count))
484 return -EFAULT;
486 *f_pos += count;
487 if (*f_pos >= buffer.bytesused) {
488 dev->queue.read_buffer = NULL;
489 microdia_queue_buffer(&dev->queue, &buffer);
490 *f_pos = 0;
492 return count;
497 * @param fp File pointer
498 * @param wait
500 * @returns 0 if all is OK
502 * @brief Polling function
504 static unsigned int v4l_microdia_poll(struct file *fp, poll_table *wait)
506 struct usb_microdia *dev;
507 struct video_device *vdev;
509 vdev = video_devdata(fp);
510 dev = video_get_drvdata(video_devdata(fp));
512 UDIA_STREAM("Poll\n");
514 if (vdev == NULL || dev == NULL)
515 return -EFAULT;
517 return microdia_queue_poll(&dev->queue, fp, wait);
520 static void microdia_vm_open(struct vm_area_struct *vma)
522 struct microdia_buffer *buffer = vma->vm_private_data;
523 buffer->vma_use_count++;
527 static void microdia_vm_close(struct vm_area_struct *vma)
529 struct microdia_buffer *buffer = vma->vm_private_data;
530 buffer->vma_use_count--;
533 struct vm_operations_struct microdia_vm_ops = {
534 .open = microdia_vm_open,
535 .close = microdia_vm_close
539 * @param fp File pointer
540 * @param vma VMA structure
542 * @returns 0 if all is OK
544 * @brief Memory map
546 * This function permits to map a memory space.
548 static int v4l_microdia_mmap(struct file *fp, struct vm_area_struct *vma)
550 struct page *page;
551 unsigned long addr, start, size;
552 unsigned int i;
553 int ret = 0;
555 struct usb_microdia *dev;
556 struct video_device *vdev;
557 struct microdia_buffer *buffer = NULL;
559 vdev = video_devdata(fp);
560 dev = video_get_drvdata(video_devdata(fp));
562 UDIA_STREAM("mmap\n");
564 start = vma->vm_start;
565 size = vma->vm_end - vma->vm_start;
567 mutex_lock(&dev->queue.mutex);
569 for (i = 0; i < dev->queue.count; ++i) {
570 buffer = &dev->queue.buffer[i];
571 if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
572 break;
575 if (i == dev->queue.count || size != dev->queue.buf_size) {
576 ret = -EINVAL;
577 goto done;
580 vma->vm_flags |= VM_IO;
582 addr = (unsigned long)dev->queue.mem + buffer->buf.m.offset;
583 while (size > 0) {
584 page = vmalloc_to_page((void *)addr);
585 ret = vm_insert_page(vma, start, page);
586 if (ret < 0)
587 goto done;
589 start += PAGE_SIZE;
590 addr += PAGE_SIZE;
591 size -= PAGE_SIZE;
594 vma->vm_ops = &microdia_vm_ops;
595 vma->vm_private_data = buffer;
596 microdia_vm_open(vma);
597 done:
598 mutex_unlock(&dev->queue.mutex);
599 return ret;
602 int microdia_vidioc_querycap(struct file *file, void *priv,
603 struct v4l2_capability *cap)
605 struct usb_microdia *dev;
607 dev = video_get_drvdata(priv);
609 UDIA_DEBUG("VIDIOC_QUERYCAP\n");
611 strlcpy(cap->driver, "microdia", sizeof(cap->driver));
612 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
613 | V4L2_CAP_READWRITE;
614 cap->version = (__u32) DRIVER_VERSION_NUM,
615 strlcpy(cap->card, dev->vdev->name, sizeof(cap->card));
617 if (usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)) < 0)
618 strlcpy(cap->bus_info, dev->vdev->name, sizeof(cap->bus_info));
619 return 0;
622 int microdia_vidioc_enum_input(struct file *file, void *priv,
623 struct v4l2_input *input)
625 UDIA_DEBUG("VIDIOC_ENUMINPUT %d\n", input->index);
627 if (input->index)
628 return -EINVAL;
630 strlcpy(input->name, "Webcam", sizeof(input->name));
631 input->type = V4L2_INPUT_TYPE_CAMERA;
632 input->std = 0;
634 return 0;
637 int microdia_vidioc_g_input(struct file *file, void *priv, unsigned int *index)
639 UDIA_DEBUG("GET INPUT %d\n", *index);
641 if (index)
642 return -EINVAL;
644 return 0;
647 int microdia_vidioc_s_input(struct file *file, void *priv, unsigned int index)
649 UDIA_DEBUG("SET INPUT %d\n", index);
651 if (v4l_get_privileges(file) < 0)
652 return -EBUSY;
654 if (index != 0)
655 return -EINVAL;
657 return 0;
660 int microdia_vidioc_queryctrl(struct file *file, void *priv,
661 struct v4l2_queryctrl *ctrl)
663 int i;
664 int nbr;
666 UDIA_DEBUG("VIDIOC_QUERYCTRL id = %d\n", ctrl->id);
668 nbr = sizeof(microdia_controls)/sizeof(struct v4l2_queryctrl);
670 for (i = 0; i < nbr; i++) {
671 if (microdia_controls[i].id == ctrl->id) {
672 UDIA_DEBUG("VIDIOC_QUERYCTRL found\n");
673 memcpy(ctrl, &microdia_controls[i],
674 sizeof(struct v4l2_queryctrl));
675 break;
679 if (i >= nbr)
680 return -EINVAL;
682 return 0;
685 int microdia_vidioc_g_ctrl(struct file *file, void *priv,
686 struct v4l2_control *ctrl)
688 struct usb_microdia *dev;
690 dev = video_get_drvdata(priv);
692 UDIA_DEBUG("GET CTRL id=%d\n", ctrl->id);
694 switch (ctrl->id) {
695 case V4L2_CID_BRIGHTNESS:
696 ctrl->value = dev->vsettings.brightness;
697 break;
699 case V4L2_CID_EXPOSURE:
700 ctrl->value = dev->vsettings.exposure;
701 break;
703 case V4L2_CID_WHITENESS:
704 ctrl->value = dev->vsettings.whiteness;
705 break;
707 case V4L2_CID_SATURATION:
708 ctrl->value = dev->vsettings.colour;
709 break;
711 case V4L2_CID_CONTRAST:
712 ctrl->value = dev->vsettings.contrast;
713 break;
715 case V4L2_CID_HFLIP:
716 ctrl->value = dev->vsettings.hflip;
717 break;
719 case V4L2_CID_VFLIP:
720 ctrl->value = dev->vsettings.vflip;
721 break;
723 case V4L2_CID_SHARPNESS:
724 ctrl->value = dev->vsettings.sharpness;
725 break;
727 case V4L2_CID_RED_BALANCE:
728 ctrl->value = dev->vsettings.rgb_gain[0];
729 break;
731 case V4L2_CID_BLUE_BALANCE:
732 ctrl->value = dev->vsettings.rgb_gain[3];
733 break;
735 case V4L2_CID_AUTOEXPOSURE:
736 ctrl->value = dev->vsettings.auto_exposure;
737 break;
739 case V4L2_CID_AUTO_WHITE_BALANCE:
740 ctrl->value = dev->vsettings.auto_whitebalance;
741 break;
743 default:
744 return -EINVAL;
746 return 0;
750 * @brief Apply v4l2 settings on camera
752 * @param file
753 * @param priv
754 * @param ctrl V4L2 control structure
756 * @returns 0 or negative error value
759 int microdia_vidioc_s_ctrl(struct file *file, void *priv,
760 struct v4l2_control *ctrl)
762 struct usb_microdia *dev;
764 dev = video_get_drvdata(priv);
766 UDIA_DEBUG("SET CTRL id=%d value=%d\n", ctrl->id, ctrl->value);
768 switch (ctrl->id) {
769 case V4L2_CID_BRIGHTNESS:
770 dev->vsettings.brightness = (0xff00 & ctrl->value);
771 dev_microdia_camera_set_brightness(dev);
772 break;
774 case V4L2_CID_EXPOSURE:
775 dev->vsettings.exposure = (0xff00 & ctrl->value);
776 dev_microdia_camera_set_exposure(dev);
777 break;
779 case V4L2_CID_WHITENESS:
780 dev->vsettings.whiteness = (0xff00 & ctrl->value);
781 dev_microdia_camera_set_gamma(dev);
782 break;
784 case V4L2_CID_SATURATION:
785 dev->vsettings.colour = (0xff00 & ctrl->value);
786 break;
788 case V4L2_CID_CONTRAST:
789 dev->vsettings.contrast = (0xff00 & ctrl->value);
790 dev_microdia_camera_set_contrast(dev);
791 break;
793 case V4L2_CID_HFLIP:
794 dev->vsettings.hflip = ctrl->value;
795 dev_microdia_camera_set_hvflip(dev);
796 break;
798 case V4L2_CID_VFLIP:
799 dev->vsettings.vflip = ctrl->value;
800 dev_microdia_camera_set_hvflip(dev);
801 break;
803 case V4L2_CID_SHARPNESS:
804 dev->vsettings.sharpness = ctrl->value;
805 dev_microdia_camera_set_sharpness(dev);
806 break;
808 case V4L2_CID_RED_BALANCE:
809 dev->vsettings.rgb_gain[0] = ctrl->value;
810 dev_microdia_camera_set_rgb_gain(dev);
811 break;
813 case V4L2_CID_BLUE_BALANCE:
814 dev->vsettings.rgb_gain[3] = ctrl->value;
815 dev_microdia_camera_set_rgb_gain(dev);
816 break;
818 case V4L2_CID_AUTOEXPOSURE:
819 dev->vsettings.auto_exposure = ctrl->value;
820 dev_microdia_camera_set_auto_exposure(dev);
821 break;
823 case V4L2_CID_AUTO_WHITE_BALANCE:
824 dev->vsettings.auto_whitebalance = ctrl->value;
825 dev_microdia_camera_set_auto_whitebalance(dev);
826 break;
828 default:
829 return -EINVAL;
832 return 0;
835 int microdia_vidioc_enum_fmt_cap(struct file *file, void *priv,
836 struct v4l2_fmtdesc *fmt)
838 struct usb_microdia *dev;
839 struct v4l2_pix_format *format;
841 dev = video_get_drvdata(priv);
843 UDIA_DEBUG("VIDIOC_ENUM_FMT %d\n", fmt->index);
845 format = v4l2_enum_supported_formats(dev, fmt->index);
846 if (format == NULL)
847 return -EINVAL;
849 fmt->flags = 0;
850 fmt->pixelformat = format->pixelformat;
851 fmt->description[0] = fmt->pixelformat & 0xFF;
852 fmt->description[1] = (fmt->pixelformat >> 8) & 0xFF;
853 fmt->description[2] = (fmt->pixelformat >> 16) & 0xFF;
854 fmt->description[3] = fmt->pixelformat >> 24;
855 fmt->description[4] = 0;
857 return 0;
860 int microdia_vidioc_try_fmt_cap(struct file *file, void *priv,
861 struct v4l2_format *fmt)
863 struct usb_microdia *dev;
865 dev = video_get_drvdata(priv);
866 UDIA_DEBUG("TRY FMT %d\n", fmt->type);
868 /* when this code is used prevents mplayer from setting outfmt
869 if(fmt->fmt.pix.field != V4L2_FIELD_NONE)
870 return -EINVAL;
873 if (v4l2_format_supported(dev, fmt->fmt.pix.pixelformat) < 0)
874 return -EINVAL;
876 sn9c20x_get_closest_resolution(&fmt->fmt.pix.width,
877 &fmt->fmt.pix.height);
879 switch (fmt->fmt.pix.pixelformat) {
880 case V4L2_PIX_FMT_YUV420:
881 fmt->fmt.pix.bytesperline = (fmt->fmt.pix.width * 3)/2;
882 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
883 fmt->fmt.pix.bytesperline;
884 break;
885 case V4L2_PIX_FMT_RGB24:
886 case V4L2_PIX_FMT_BGR24:
887 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3;
888 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
889 fmt->fmt.pix.bytesperline;
890 break;
891 case V4L2_PIX_FMT_YUYV:
892 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 2;
893 fmt->fmt.pix.sizeimage = fmt->fmt.pix.height *
894 fmt->fmt.pix.bytesperline;
895 break;
896 default:
897 return -EINVAL;
900 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
901 fmt->fmt.pix.priv = 0;
903 return 0;
906 int microdia_vidioc_g_fmt_cap(struct file *file, void *priv,
907 struct v4l2_format *fmt)
909 struct usb_microdia *dev;
911 dev = video_get_drvdata(priv);
913 UDIA_DEBUG("GET FMT %d\n", fmt->type);
915 memcpy(&(fmt->fmt.pix), &(dev->vsettings.format), sizeof(fmt->fmt.pix));
918 return 0;
921 int microdia_vidioc_s_fmt_cap(struct file *file, void *priv,
922 struct v4l2_format *fmt)
924 struct usb_microdia *dev;
925 int ret;
927 dev = video_get_drvdata(priv);
929 UDIA_DEBUG("SET FMT %d : %d\n", fmt->type, fmt->fmt.pix.pixelformat);
931 if (v4l_get_privileges(file) < 0)
932 return -EBUSY;
934 if (dev->queue.streaming)
935 return -EBUSY;
937 ret = microdia_vidioc_try_fmt_cap(file, priv, fmt);
938 if (ret)
939 return -EINVAL;
941 sn9c20x_set_resolution(dev, fmt->fmt.pix.width, fmt->fmt.pix.height);
943 memcpy(&(dev->vsettings.format), &(fmt->fmt.pix), sizeof(fmt->fmt.pix));
945 return 0;
948 int microdia_vidioc_reqbufs(struct file *file, void *priv,
949 struct v4l2_requestbuffers *request)
951 int ret = 0;
952 struct usb_microdia *dev;
954 dev = video_get_drvdata(priv);
956 if (v4l_get_privileges(file) < 0) {
957 ret = -EBUSY;
958 goto done;
961 if (request->memory != V4L2_MEMORY_MMAP ||
962 request->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
963 ret = -EINVAL;
964 goto done;
967 if (dev->queue.streaming) {
968 ret = -EBUSY;
969 goto done;
972 ret = microdia_alloc_buffers(&dev->queue, request->count,
973 MICRODIA_FRAME_SIZE);
974 if (ret < 0)
975 goto done;
977 dev->queue.drop_incomplete = 1;
979 request->count = ret;
980 ret = 0;
981 UDIA_INFO("Buffers Allocated %d\n", request->count);
982 done:
983 return ret;
986 int microdia_vidioc_querybuf(struct file *file, void *priv,
987 struct v4l2_buffer *buffer)
989 struct usb_microdia *dev;
991 dev = video_get_drvdata(priv);
993 UDIA_DEBUG("QUERY BUFFERS %d %d\n", buffer->index, dev->queue.count);
995 if (buffer->memory != V4L2_MEMORY_MMAP ||
996 buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
997 return -EINVAL;
999 if (!v4l_has_privileges(file))
1000 return -EBUSY;
1002 return microdia_query_buffer(&dev->queue, buffer);
1005 int microdia_vidioc_qbuf(struct file *file, void *priv,
1006 struct v4l2_buffer *buffer)
1008 struct usb_microdia *dev;
1010 dev = video_get_drvdata(priv);
1012 UDIA_DEBUG("VIDIOC_QBUF\n");
1014 if (!v4l_has_privileges(file))
1015 return -EBUSY;
1017 return microdia_queue_buffer(&dev->queue, buffer);
1020 int microdia_vidioc_dqbuf(struct file *file, void *priv,
1021 struct v4l2_buffer *buffer)
1023 struct usb_microdia *dev;
1024 int ret = 0;
1026 dev = video_get_drvdata(priv);
1028 UDIA_DEBUG("VIDIOC_DQBUF\n");
1030 if (!v4l_has_privileges(file))
1031 return -EBUSY;
1033 ret = microdia_dequeue_buffer(&dev->queue, buffer,
1034 file->f_flags & O_NONBLOCK);
1035 if (ret < 0)
1036 return ret;
1038 microdia_decompress(dev, buffer);
1040 return ret;
1043 int microdia_vidioc_streamon(struct file *file, void *priv,
1044 enum v4l2_buf_type type)
1046 struct usb_microdia *dev;
1048 dev = video_get_drvdata(priv);
1050 UDIA_DEBUG("VIDIOC_STREAMON\n");
1052 if (!v4l_has_privileges(file))
1053 return -EBUSY;
1055 if (dev->mode != MICRODIA_MODE_IDLE)
1056 return -EBUSY;
1058 return v4l2_enable_video(dev, MICRODIA_MODE_STREAM);
1061 int microdia_vidioc_streamoff(struct file *file, void *priv,
1062 enum v4l2_buf_type type)
1064 struct usb_microdia *dev;
1066 dev = video_get_drvdata(priv);
1068 UDIA_DEBUG("VIDIOC_STREAMOFF\n");
1070 if (!v4l_has_privileges(file))
1071 return -EBUSY;
1073 return v4l2_enable_video(dev, MICRODIA_MODE_IDLE);
1076 int microdia_vidioc_g_param(struct file *file, void *priv,
1077 struct v4l2_streamparm *param)
1079 struct usb_microdia *dev;
1082 dev = video_get_drvdata(priv);
1084 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1085 return -EINVAL;
1087 param->parm.capture.capability = 0;
1088 param->parm.capture.capturemode = 0;
1089 param->parm.capture.timeperframe.numerator = 1;
1090 param->parm.capture.timeperframe.denominator = 30;
1091 param->parm.capture.readbuffers = 2;
1092 param->parm.capture.extendedmode = 0;
1094 return 0;
1097 int microdia_vidioc_s_param(struct file *file, void *priv,
1098 struct v4l2_streamparm *param)
1100 struct usb_microdia *dev;
1102 dev = video_get_drvdata(priv);
1104 if (v4l_get_privileges(file))
1105 return -EBUSY;
1107 if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1108 return -EINVAL;
1110 return 0;
1114 * @param inode Inode pointer
1115 * @param fp File pointer
1116 * @param cmd Command
1117 * @param arg Arguements of the command
1119 * @returns 0 if all is OK
1121 * @brief Manage IOCTL
1123 * This function permits to manage all the IOCTL from the application.
1125 static int v4l_microdia_ioctl(struct inode *inode, struct file *fp,
1126 unsigned int cmd, unsigned long arg)
1128 int err;
1129 struct usb_microdia *dev;
1130 struct video_device *vdev;
1132 vdev = video_devdata(fp);
1133 dev = video_get_drvdata(video_devdata(fp));
1135 UDIA_DEBUG("v4l_microdia_ioctl %02X\n", (unsigned char) cmd);
1137 if (dev == NULL || vdev == NULL)
1138 return -EFAULT;
1140 err = video_ioctl2(inode, fp, cmd, arg);
1142 return err;
1147 * @param dev Device structure
1149 * @returns 0 if all is OK
1151 * @brief Register the video device
1153 * This function permits to register the USB device to the video device.
1155 int v4l_microdia_register_video_device(struct usb_microdia *dev)
1157 int err;
1159 strcpy(dev->vdev->name, DRIVER_DESC);
1161 dev->vdev->dev = &dev->interface->dev;
1162 dev->vdev->owner = THIS_MODULE;
1163 dev->vdev->type = VID_TYPE_CAPTURE;
1164 dev->vdev->current_norm = 0;
1165 dev->vdev->tvnorms = 0;
1166 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1167 dev->vdev->hardware = VID_HARDWARE_MICRODIA;
1168 #endif
1169 dev->vdev->fops = &v4l_microdia_fops;
1170 dev->vdev->release = video_device_release;
1171 dev->vdev->minor = -1;
1173 if (log_level & MICRODIA_DEBUG)
1174 dev->vdev->debug = V4L2_DEBUG_IOCTL_ARG;
1176 dev->vdev->vidioc_querycap = microdia_vidioc_querycap;
1177 dev->vdev->vidioc_enum_fmt_cap = microdia_vidioc_enum_fmt_cap;
1178 dev->vdev->vidioc_try_fmt_cap = microdia_vidioc_try_fmt_cap;
1179 dev->vdev->vidioc_s_fmt_cap = microdia_vidioc_s_fmt_cap;
1180 dev->vdev->vidioc_g_fmt_cap = microdia_vidioc_g_fmt_cap;
1181 dev->vdev->vidioc_enum_input = microdia_vidioc_enum_input;
1182 dev->vdev->vidioc_g_input = microdia_vidioc_g_input;
1183 dev->vdev->vidioc_s_input = microdia_vidioc_s_input;
1184 dev->vdev->vidioc_streamon = microdia_vidioc_streamon;
1185 dev->vdev->vidioc_streamoff = microdia_vidioc_streamoff;
1186 dev->vdev->vidioc_queryctrl = microdia_vidioc_queryctrl;
1187 dev->vdev->vidioc_g_ctrl = microdia_vidioc_g_ctrl;
1188 dev->vdev->vidioc_s_ctrl = microdia_vidioc_s_ctrl;
1189 dev->vdev->vidioc_g_parm = microdia_vidioc_g_param;
1190 dev->vdev->vidioc_s_parm = microdia_vidioc_s_param;
1191 dev->vdev->vidioc_reqbufs = microdia_vidioc_reqbufs;
1192 dev->vdev->vidioc_qbuf = microdia_vidioc_qbuf;
1193 dev->vdev->vidioc_dqbuf = microdia_vidioc_dqbuf;
1194 dev->vdev->vidioc_querybuf = microdia_vidioc_querybuf;
1196 video_set_drvdata(dev->vdev, dev);
1198 microdia_queue_init(&dev->queue);
1200 err = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
1202 if (err)
1203 UDIA_ERROR("Video register fail !\n");
1204 else
1205 UDIA_INFO("Microdia USB2.0 Camera is now controlling "
1206 "video device /dev/video%d\n",
1207 dev->vdev->minor);
1209 return err;
1214 * @param dev Device structure
1216 * @returns 0 if all is OK
1218 * @brief Unregister the video device
1220 * This function permits to unregister the video device.
1222 int v4l_microdia_unregister_video_device(struct usb_microdia *dev)
1224 UDIA_INFO("Microdia USB2.0 Camera release resources video "
1225 "device /dev/video%d\n", dev->vdev->minor);
1227 video_set_drvdata(dev->vdev, NULL);
1228 video_unregister_device(dev->vdev);
1230 return 0;
1235 * @var v4l_microdia_fops
1237 * This variable contains some callback
1239 static struct file_operations v4l_microdia_fops = {
1240 .owner = THIS_MODULE,
1241 .open = v4l_microdia_open,
1242 .release = v4l_microdia_release,
1243 .read = v4l_microdia_read,
1244 .poll = v4l_microdia_poll,
1245 .mmap = v4l_microdia_mmap,
1246 .ioctl = v4l_microdia_ioctl,
1247 #ifdef CONFIG_COMPAT
1248 .compat_ioctl = v4l_compat_ioctl32,
1249 #endif
1250 .llseek = no_llseek