Path: blob/master/drivers/media/video/gspca/vicam.c
17602 views
/*1* gspca ViCam subdriver2*3* Copyright (C) 2011 Hans de Goede <[email protected]>4*5* Based on the usbvideo vicam driver, which is:6*7* Copyright (c) 2002 Joe Burks ([email protected]),8* Christopher L Cheney ([email protected]),9* Pavel Machek ([email protected]),10* John Tyner ([email protected]),11* Monroe Williams ([email protected])12*13* This program is free software; you can redistribute it and/or modify14* it under the terms of the GNU General Public License as published by15* the Free Software Foundation; either version 2 of the License, or16* any later version.17*18* This program is distributed in the hope that it will be useful,19* but WITHOUT ANY WARRANTY; without even the implied warranty of20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the21* GNU General Public License for more details.22*23* You should have received a copy of the GNU General Public License24* along with this program; if not, write to the Free Software25* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA26*/2728#define MODULE_NAME "vicam"29#define HEADER_SIZE 643031#include <linux/workqueue.h>32#include <linux/slab.h>33#include <linux/firmware.h>34#include <linux/ihex.h>35#include "gspca.h"3637MODULE_AUTHOR("Hans de Goede <[email protected]>");38MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver");39MODULE_LICENSE("GPL");4041enum e_ctrl {42GAIN,43EXPOSURE,44NCTRL /* number of controls */45};4647struct sd {48struct gspca_dev gspca_dev; /* !! must be the first item */49struct work_struct work_struct;50struct workqueue_struct *work_thread;51struct gspca_ctrl ctrls[NCTRL];52};5354/* The vicam sensor has a resolution of 512 x 244, with I believe square55pixels, but this is forced to a 4:3 ratio by optics. So it has56non square pixels :( */57static struct v4l2_pix_format vicam_mode[] = {58{ 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,59.bytesperline = 256,60.sizeimage = 256 * 122,61.colorspace = V4L2_COLORSPACE_SRGB,},62/* 2 modes with somewhat more square pixels */63{ 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,64.bytesperline = 256,65.sizeimage = 256 * 200,66.colorspace = V4L2_COLORSPACE_SRGB,},67{ 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,68.bytesperline = 256,69.sizeimage = 256 * 240,70.colorspace = V4L2_COLORSPACE_SRGB,},71#if 0 /* This mode has extremely non square pixels, testing use only */72{ 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,73.bytesperline = 512,74.sizeimage = 512 * 122,75.colorspace = V4L2_COLORSPACE_SRGB,},76#endif77{ 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,78.bytesperline = 512,79.sizeimage = 512 * 244,80.colorspace = V4L2_COLORSPACE_SRGB,},81};8283static const struct ctrl sd_ctrls[] = {84[GAIN] = {85{86.id = V4L2_CID_GAIN,87.type = V4L2_CTRL_TYPE_INTEGER,88.name = "Gain",89.minimum = 0,90.maximum = 255,91.step = 1,92.default_value = 200,93},94},95[EXPOSURE] = {96{97.id = V4L2_CID_EXPOSURE,98.type = V4L2_CTRL_TYPE_INTEGER,99.name = "Exposure",100.minimum = 0,101.maximum = 2047,102.step = 1,103.default_value = 256,104},105},106};107108static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request,109u16 value, u16 index, u8 *data, u16 len)110{111int ret;112113ret = usb_control_msg(gspca_dev->dev,114usb_sndctrlpipe(gspca_dev->dev, 0),115request,116USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,117value, index, data, len, 1000);118if (ret < 0)119err("control msg req %02X error %d", request, ret);120121return ret;122}123124static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state)125{126int ret;127128ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0);129if (ret < 0)130return ret;131132if (state)133ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0);134135return ret;136}137138/*139* request and read a block of data - see warning on vicam_command.140*/141static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)142{143struct sd *sd = (struct sd *)gspca_dev;144int ret, unscaled_height, act_len = 0;145u8 *req_data = gspca_dev->usb_buf;146147memset(req_data, 0, 16);148req_data[0] = sd->ctrls[GAIN].val;149if (gspca_dev->width == 256)150req_data[1] |= 0x01; /* low nibble x-scale */151if (gspca_dev->height <= 122) {152req_data[1] |= 0x10; /* high nibble y-scale */153unscaled_height = gspca_dev->height * 2;154} else155unscaled_height = gspca_dev->height;156req_data[2] = 0x90; /* unknown, does not seem to do anything */157if (unscaled_height <= 200)158req_data[3] = 0x06; /* vend? */159else if (unscaled_height <= 242) /* Yes 242 not 240 */160req_data[3] = 0x07; /* vend? */161else /* Up to 244 lines with req_data[3] == 0x08 */162req_data[3] = 0x08; /* vend? */163164if (sd->ctrls[EXPOSURE].val < 256) {165/* Frame rate maxed out, use partial frame expo time */166req_data[4] = 255 - sd->ctrls[EXPOSURE].val;167req_data[5] = 0x00;168req_data[6] = 0x00;169req_data[7] = 0x01;170} else {171/* Modify frame rate */172req_data[4] = 0x00;173req_data[5] = 0x00;174req_data[6] = sd->ctrls[EXPOSURE].val & 0xFF;175req_data[7] = sd->ctrls[EXPOSURE].val >> 8;176}177req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */178/* bytes 9-15 do not seem to affect exposure or image quality */179180mutex_lock(&gspca_dev->usb_lock);181ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16);182mutex_unlock(&gspca_dev->usb_lock);183if (ret < 0)184return ret;185186ret = usb_bulk_msg(gspca_dev->dev,187usb_rcvbulkpipe(gspca_dev->dev, 0x81),188data, size, &act_len, 10000);189/* successful, it returns 0, otherwise negative */190if (ret < 0 || act_len != size) {191err("bulk read fail (%d) len %d/%d",192ret, act_len, size);193return -EIO;194}195return 0;196}197198/* This function is called as a workqueue function and runs whenever the camera199* is streaming data. Because it is a workqueue function it is allowed to sleep200* so we can use synchronous USB calls. To avoid possible collisions with other201* threads attempting to use the camera's USB interface we take the gspca202* usb_lock when performing USB operations. In practice the only thing we need203* to protect against is the usb_set_interface call that gspca makes during204* stream_off as the camera doesn't provide any controls that the user could try205* to change.206*/207static void vicam_dostream(struct work_struct *work)208{209struct sd *sd = container_of(work, struct sd, work_struct);210struct gspca_dev *gspca_dev = &sd->gspca_dev;211int ret, frame_sz;212u8 *buffer;213214frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage +215HEADER_SIZE;216buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA);217if (!buffer) {218err("Couldn't allocate USB buffer");219goto exit;220}221222while (gspca_dev->present && gspca_dev->streaming) {223ret = vicam_read_frame(gspca_dev, buffer, frame_sz);224if (ret < 0)225break;226227/* Note the frame header contents seem to be completely228constant, they do not change with either image, or229settings. So we simply discard it. The frames have230a very similar 64 byte footer, which we don't even231bother reading from the cam */232gspca_frame_add(gspca_dev, FIRST_PACKET,233buffer + HEADER_SIZE,234frame_sz - HEADER_SIZE);235gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);236}237exit:238kfree(buffer);239}240241/* This function is called at probe time just before sd_init */242static int sd_config(struct gspca_dev *gspca_dev,243const struct usb_device_id *id)244{245struct cam *cam = &gspca_dev->cam;246struct sd *sd = (struct sd *)gspca_dev;247248/* We don't use the buffer gspca allocates so make it small. */249cam->bulk = 1;250cam->bulk_size = 64;251cam->cam_mode = vicam_mode;252cam->nmodes = ARRAY_SIZE(vicam_mode);253cam->ctrls = sd->ctrls;254255INIT_WORK(&sd->work_struct, vicam_dostream);256257return 0;258}259260/* this function is called at probe and resume time */261static int sd_init(struct gspca_dev *gspca_dev)262{263int ret;264const struct ihex_binrec *rec;265const struct firmware *uninitialized_var(fw);266u8 *firmware_buf;267268ret = request_ihex_firmware(&fw, "vicam/firmware.fw",269&gspca_dev->dev->dev);270if (ret) {271err("Failed to load \"vicam/firmware.fw\": %d\n", ret);272return ret;273}274275firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);276if (!firmware_buf) {277ret = -ENOMEM;278goto exit;279}280for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {281memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len));282ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf,283be16_to_cpu(rec->len));284if (ret < 0)285break;286}287288kfree(firmware_buf);289exit:290release_firmware(fw);291return ret;292}293294/* Set up for getting frames. */295static int sd_start(struct gspca_dev *gspca_dev)296{297struct sd *sd = (struct sd *)gspca_dev;298int ret;299300ret = vicam_set_camera_power(gspca_dev, 1);301if (ret < 0)302return ret;303304/* Start the workqueue function to do the streaming */305sd->work_thread = create_singlethread_workqueue(MODULE_NAME);306queue_work(sd->work_thread, &sd->work_struct);307308return 0;309}310311/* called on streamoff with alt==0 and on disconnect */312/* the usb_lock is held at entry - restore on exit */313static void sd_stop0(struct gspca_dev *gspca_dev)314{315struct sd *dev = (struct sd *)gspca_dev;316317/* wait for the work queue to terminate */318mutex_unlock(&gspca_dev->usb_lock);319/* This waits for vicam_dostream to finish */320destroy_workqueue(dev->work_thread);321dev->work_thread = NULL;322mutex_lock(&gspca_dev->usb_lock);323324vicam_set_camera_power(gspca_dev, 0);325}326327/* Table of supported USB devices */328static const struct usb_device_id device_table[] = {329{USB_DEVICE(0x04c1, 0x009d)},330{USB_DEVICE(0x0602, 0x1001)},331{}332};333334MODULE_DEVICE_TABLE(usb, device_table);335336/* sub-driver description */337static const struct sd_desc sd_desc = {338.name = MODULE_NAME,339.ctrls = sd_ctrls,340.nctrls = ARRAY_SIZE(sd_ctrls),341.config = sd_config,342.init = sd_init,343.start = sd_start,344.stop0 = sd_stop0,345};346347/* -- device connect -- */348static int sd_probe(struct usb_interface *intf,349const struct usb_device_id *id)350{351return gspca_dev_probe(intf, id,352&sd_desc,353sizeof(struct sd),354THIS_MODULE);355}356357static struct usb_driver sd_driver = {358.name = MODULE_NAME,359.id_table = device_table,360.probe = sd_probe,361.disconnect = gspca_disconnect,362#ifdef CONFIG_PM363.suspend = gspca_suspend,364.resume = gspca_resume,365#endif366};367368/* -- module insert / remove -- */369static int __init sd_mod_init(void)370{371return usb_register(&sd_driver);372}373374static void __exit sd_mod_exit(void)375{376usb_deregister(&sd_driver);377}378379module_init(sd_mod_init);380module_exit(sd_mod_exit);381382383