/drivers/media/video/stk-webcam.c
C | 1392 lines | 1141 code | 169 blank | 82 comment | 229 complexity | 669e62584534e4b00e422ec91bcdd769 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
- *
- * Copyright (C) 2006 Nicolas VIVIEN
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- *
- * Some parts are inspired from cafe_ccic.c
- * Copyright 2006-2007 Jonathan Corbet
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
- #include <linux/usb.h>
- #include <linux/mm.h>
- #include <linux/vmalloc.h>
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
- #include <media/v4l2-ioctl.h>
- #include "stk-webcam.h"
- static int hflip = 1;
- module_param(hflip, bool, 0444);
- MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
- static int vflip = 1;
- module_param(vflip, bool, 0444);
- MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
- static int debug;
- module_param(debug, int, 0444);
- MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");
- MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
- /* Some cameras have audio interfaces, we aren't interested in those */
- static struct usb_device_id stkwebcam_table[] = {
- { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
- { }
- };
- MODULE_DEVICE_TABLE(usb, stkwebcam_table);
- /*
- * Basic stuff
- */
- int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
- {
- struct usb_device *udev = dev->udev;
- int ret;
- ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x01,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- NULL,
- 0,
- 500);
- if (ret < 0)
- return ret;
- else
- return 0;
- }
- int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value)
- {
- struct usb_device *udev = dev->udev;
- int ret;
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0x00,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x00,
- index,
- (u8 *) value,
- sizeof(u8),
- 500);
- if (ret < 0)
- return ret;
- else
- return 0;
- }
- static int stk_start_stream(struct stk_camera *dev)
- {
- int value;
- int i, ret;
- int value_116, value_117;
- if (!is_present(dev))
- return -ENODEV;
- if (!is_memallocd(dev) || !is_initialised(dev)) {
- STK_ERROR("FIXME: Buffers are not allocated\n");
- return -EFAULT;
- }
- ret = usb_set_interface(dev->udev, 0, 5);
- if (ret < 0)
- STK_ERROR("usb_set_interface failed !\n");
- if (stk_sensor_wakeup(dev))
- STK_ERROR("error awaking the sensor\n");
- stk_camera_read_reg(dev, 0x0116, &value_116);
- stk_camera_read_reg(dev, 0x0117, &value_117);
- stk_camera_write_reg(dev, 0x0116, 0x0000);
- stk_camera_write_reg(dev, 0x0117, 0x0000);
- stk_camera_read_reg(dev, 0x0100, &value);
- stk_camera_write_reg(dev, 0x0100, value | 0x80);
- stk_camera_write_reg(dev, 0x0116, value_116);
- stk_camera_write_reg(dev, 0x0117, value_117);
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].urb) {
- ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
- atomic_inc(&dev->urbs_used);
- if (ret)
- return ret;
- }
- }
- set_streaming(dev);
- return 0;
- }
- static int stk_stop_stream(struct stk_camera *dev)
- {
- int value;
- int i;
- if (is_present(dev)) {
- stk_camera_read_reg(dev, 0x0100, &value);
- stk_camera_write_reg(dev, 0x0100, value & ~0x80);
- if (dev->isobufs != NULL) {
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].urb)
- usb_kill_urb(dev->isobufs[i].urb);
- }
- }
- unset_streaming(dev);
- if (usb_set_interface(dev->udev, 0, 0))
- STK_ERROR("usb_set_interface failed !\n");
- if (stk_sensor_sleep(dev))
- STK_ERROR("error suspending the sensor\n");
- }
- return 0;
- }
- /*
- * This seems to be the shortest init sequence we
- * must do in order to find the sensor
- * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
- * is also reset. Maybe powers down it?
- * Rest of values don't make a difference
- */
- static struct regval stk1125_initvals[] = {
- /*TODO: What means this sequence? */
- {0x0000, 0x24},
- {0x0100, 0x21},
- {0x0002, 0x68},
- {0x0003, 0x80},
- {0x0005, 0x00},
- {0x0007, 0x03},
- {0x000d, 0x00},
- {0x000f, 0x02},
- {0x0300, 0x12},
- {0x0350, 0x41},
- {0x0351, 0x00},
- {0x0352, 0x00},
- {0x0353, 0x00},
- {0x0018, 0x10},
- {0x0019, 0x00},
- {0x001b, 0x0e},
- {0x001c, 0x46},
- {0x0300, 0x80},
- {0x001a, 0x04},
- {0x0110, 0x00},
- {0x0111, 0x00},
- {0x0112, 0x00},
- {0x0113, 0x00},
- {0xffff, 0xff},
- };
- static int stk_initialise(struct stk_camera *dev)
- {
- struct regval *rv;
- int ret;
- if (!is_present(dev))
- return -ENODEV;
- if (is_initialised(dev))
- return 0;
- rv = stk1125_initvals;
- while (rv->reg != 0xffff) {
- ret = stk_camera_write_reg(dev, rv->reg, rv->val);
- if (ret)
- return ret;
- rv++;
- }
- if (stk_sensor_init(dev) == 0) {
- set_initialised(dev);
- return 0;
- } else
- return -1;
- }
- /* *********************************************** */
- /*
- * This function is called as an URB transfert is complete (Isochronous pipe).
- * So, the traitement is done in interrupt time, so it has be fast, not crash,
- * and not stall. Neat.
- */
- static void stk_isoc_handler(struct urb *urb)
- {
- int i;
- int ret;
- int framelen;
- unsigned long flags;
- unsigned char *fill = NULL;
- unsigned char *iso_buf = NULL;