/*
* Mars MR97310A library
*
* The original mr97310a driver, which supported the Aiptek Pencam VGA+, is
* Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
*
* Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
* and for the routines for detecting and classifying these various cameras,
* is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
*
* Support for the control settings for the CIF cameras is
* Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and
* Thomas Kaiser <thomas@kaiser-linux.li>
*
* Support for the control settings for the VGA cameras is
* Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
*
* Several previously unsupported cameras are owned and have been tested by
* Hans de Goede <hdegoede@redhat.com> and
* Thomas Kaiser <thomas@kaiser-linux.li> and
* Theodore Kilgore <kilgota@auburn.edu> and
* Edmond Rodriguez <erodrig_97@yahoo.com> and
* Aurelien Jacobs <aurel@gnuage.org>
*
* The MR97311A support in gspca/mars.c has been helpful in understanding some
* of the registers in these cameras.
*
* 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
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define MODULE_NAME "mr97310a"
#include "gspca.h"
#define CAM_TYPE_CIF 0
#define CAM_TYPE_VGA 1
#define MR97310A_BRIGHTNESS_DEFAULT 0
#define MR97310A_EXPOSURE_MIN 0
#define MR97310A_EXPOSURE_MAX 4095
#define MR97310A_EXPOSURE_DEFAULT 1000
#define MR97310A_GAIN_MIN 0
#define MR97310A_GAIN_MAX 31
#define MR97310A_GAIN_DEFAULT 25
#define MR97310A_CONTRAST_MIN 0
#define MR97310A_CONTRAST_MAX 31
#define MR97310A_CONTRAST_DEFAULT 23
#define MR97310A_CS_GAIN_MIN 0
#define MR97310A_CS_GAIN_MAX 0x7ff
#define MR97310A_CS_GAIN_DEFAULT 0x110
#define MR97310A_CID_CLOCKDIV (V4L2_CTRL_CLASS_USER + 0x1000)
#define MR97310A_MIN_CLOCKDIV_MIN 3
#define MR97310A_MIN_CLOCKDIV_MAX 8
#define MR97310A_MIN_CLOCKDIV_DEFAULT 3
MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
"Theodore Kilgore <kilgota@auburn.edu>");
MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
MODULE_LICENSE("GPL");
/* global parameters */
static int force_sensor_type = -1;
module_param(force_sensor_type, int, 0644);
MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
struct { /* exposure/min_clockdiv control cluster */
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *min_clockdiv;
};
u8 sof_read;
u8 cam_type; /* 0 is CIF and 1 is VGA */
u8 sensor_type; /* We use 0 and 1 here, too. */
u8 do_lcd_stop;
u8 adj_colors;
};
struct sensor_w_data {
u8 reg;
u8 flags;
u8 data[16];
int len;
};
static void sd_stopN(struct gspca_dev *gspca_dev);
static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 4},
{176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 3},
{320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 2},
{352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
.bytesperline = 352,
.sizeimage = 352 * 288,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
{640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
};
/* the bytes to write are in gspca_dev->usb_buf */
static int mr_write(struct gspca_dev *gspca_dev, int len)
{
int rc;
rc = usb_bulk_msg(gspca_dev->dev,
usb_sndbulkpipe(gspca_dev->dev, 4),
gspca_dev->usb_buf, len, NULL, 500);
if (rc < 0)
pr_err("reg write [%02x] error %d\n",
gspca_dev->usb_buf[0], rc);
return rc;
}
/* the bytes are read into gspca_dev->usb_buf */
static int mr_read(struct gspca_dev *gspca_dev, int len)
{
int rc;
rc = usb_bulk_msg(gspca_dev->dev,
usb_rcvbulkpipe(gspca_dev->dev, 3),
gspca_dev->usb_buf, len, NULL, 500);
if (rc < 0)
pr_err("reg read [%02x] error %d\n",
gspca_dev->usb_buf