brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · d98343f Raw
348 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * gspca ViCam subdriver4 *5 * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>6 *7 * Based on the usbvideo vicam driver, which is:8 *9 * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),10 *                    Chris Cheney (chris.cheney@gmail.com),11 *                    Pavel Machek (pavel@ucw.cz),12 *                    John Tyner (jtyner@cs.ucr.edu),13 *                    Monroe Williams (monroe@pobox.com)14 */15 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt17 18#define MODULE_NAME "vicam"19#define HEADER_SIZE 6420 21#include <linux/workqueue.h>22#include <linux/slab.h>23#include <linux/firmware.h>24#include <linux/ihex.h>25#include "gspca.h"26 27#define VICAM_FIRMWARE "vicam/firmware.fw"28 29MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");30MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver");31MODULE_LICENSE("GPL");32MODULE_FIRMWARE(VICAM_FIRMWARE);33 34struct sd {35	struct gspca_dev gspca_dev;	/* !! must be the first item */36	struct work_struct work_struct;37};38 39/* The vicam sensor has a resolution of 512 x 244, with I believe square40   pixels, but this is forced to a 4:3 ratio by optics. So it has41   non square pixels :( */42static struct v4l2_pix_format vicam_mode[] = {43	{ 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,44		.bytesperline = 256,45		.sizeimage = 256 * 122,46		.colorspace = V4L2_COLORSPACE_SRGB,},47	/* 2 modes with somewhat more square pixels */48	{ 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,49		.bytesperline = 256,50		.sizeimage = 256 * 200,51		.colorspace = V4L2_COLORSPACE_SRGB,},52	{ 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,53		.bytesperline = 256,54		.sizeimage = 256 * 240,55		.colorspace = V4L2_COLORSPACE_SRGB,},56#if 0   /* This mode has extremely non square pixels, testing use only */57	{ 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,58		.bytesperline = 512,59		.sizeimage = 512 * 122,60		.colorspace = V4L2_COLORSPACE_SRGB,},61#endif62	{ 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,63		.bytesperline = 512,64		.sizeimage = 512 * 244,65		.colorspace = V4L2_COLORSPACE_SRGB,},66};67 68static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request,69	u16 value, u16 index, u8 *data, u16 len)70{71	int ret;72 73	ret = usb_control_msg(gspca_dev->dev,74			      usb_sndctrlpipe(gspca_dev->dev, 0),75			      request,76			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,77			      value, index, data, len, 1000);78	if (ret < 0)79		pr_err("control msg req %02X error %d\n", request, ret);80 81	return ret;82}83 84static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state)85{86	int ret;87 88	ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0);89	if (ret < 0)90		return ret;91 92	if (state)93		ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0);94 95	return ret;96}97 98/*99 *  request and read a block of data100 */101static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)102{103	int ret, unscaled_height, act_len = 0;104	u8 *req_data = gspca_dev->usb_buf;105	s32 expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure);106	s32 gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);107 108	memset(req_data, 0, 16);109	req_data[0] = gain;110	if (gspca_dev->pixfmt.width == 256)111		req_data[1] |= 0x01; /* low nibble x-scale */112	if (gspca_dev->pixfmt.height <= 122) {113		req_data[1] |= 0x10; /* high nibble y-scale */114		unscaled_height = gspca_dev->pixfmt.height * 2;115	} else116		unscaled_height = gspca_dev->pixfmt.height;117	req_data[2] = 0x90; /* unknown, does not seem to do anything */118	if (unscaled_height <= 200)119		req_data[3] = 0x06; /* vend? */120	else if (unscaled_height <= 242) /* Yes 242 not 240 */121		req_data[3] = 0x07; /* vend? */122	else /* Up to 244 lines with req_data[3] == 0x08 */123		req_data[3] = 0x08; /* vend? */124 125	if (expo < 256) {126		/* Frame rate maxed out, use partial frame expo time */127		req_data[4] = 255 - expo;128		req_data[5] = 0x00;129		req_data[6] = 0x00;130		req_data[7] = 0x01;131	} else {132		/* Modify frame rate */133		req_data[4] = 0x00;134		req_data[5] = 0x00;135		req_data[6] = expo & 0xFF;136		req_data[7] = expo >> 8;137	}138	req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */139	/* bytes 9-15 do not seem to affect exposure or image quality */140 141	mutex_lock(&gspca_dev->usb_lock);142	ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16);143	mutex_unlock(&gspca_dev->usb_lock);144	if (ret < 0)145		return ret;146 147	ret = usb_bulk_msg(gspca_dev->dev,148			   usb_rcvbulkpipe(gspca_dev->dev, 0x81),149			   data, size, &act_len, 10000);150	/* successful, it returns 0, otherwise  negative */151	if (ret < 0 || act_len != size) {152		pr_err("bulk read fail (%d) len %d/%d\n",153		       ret, act_len, size);154		return -EIO;155	}156	return 0;157}158 159/*160 * This function is called as a workqueue function and runs whenever the camera161 * is streaming data. Because it is a workqueue function it is allowed to sleep162 * so we can use synchronous USB calls. To avoid possible collisions with other163 * threads attempting to use gspca_dev->usb_buf we take the usb_lock when164 * performing USB operations using it. In practice we don't really need this165 * as the cameras controls are only written from the workqueue.166 */167static void vicam_dostream(struct work_struct *work)168{169	struct sd *sd = container_of(work, struct sd, work_struct);170	struct gspca_dev *gspca_dev = &sd->gspca_dev;171	int ret, frame_sz;172	u8 *buffer;173 174	frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage +175		   HEADER_SIZE;176	buffer = kmalloc(frame_sz, GFP_KERNEL);177	if (!buffer) {178		pr_err("Couldn't allocate USB buffer\n");179		goto exit;180	}181 182	while (gspca_dev->present && gspca_dev->streaming) {183#ifdef CONFIG_PM184		if (gspca_dev->frozen)185			break;186#endif187		ret = vicam_read_frame(gspca_dev, buffer, frame_sz);188		if (ret < 0)189			break;190 191		/* Note the frame header contents seem to be completely192		   constant, they do not change with either image, or193		   settings. So we simply discard it. The frames have194		   a very similar 64 byte footer, which we don't even195		   bother reading from the cam */196		gspca_frame_add(gspca_dev, FIRST_PACKET,197				buffer + HEADER_SIZE,198				frame_sz - HEADER_SIZE);199		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);200	}201exit:202	kfree(buffer);203}204 205/* This function is called at probe time just before sd_init */206static int sd_config(struct gspca_dev *gspca_dev,207		const struct usb_device_id *id)208{209	struct cam *cam = &gspca_dev->cam;210	struct sd *sd = (struct sd *)gspca_dev;211 212	/* We don't use the buffer gspca allocates so make it small. */213	cam->bulk = 1;214	cam->bulk_size = 64;215	cam->cam_mode = vicam_mode;216	cam->nmodes = ARRAY_SIZE(vicam_mode);217 218	INIT_WORK(&sd->work_struct, vicam_dostream);219 220	return 0;221}222 223/* this function is called at probe and resume time */224static int sd_init(struct gspca_dev *gspca_dev)225{226	int ret;227	const struct ihex_binrec *rec;228	const struct firmware *fw;229	u8 *firmware_buf;230 231	ret = request_ihex_firmware(&fw, VICAM_FIRMWARE,232				    &gspca_dev->dev->dev);233	if (ret) {234		pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret);235		return ret;236	}237 238	firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);239	if (!firmware_buf) {240		ret = -ENOMEM;241		goto exit;242	}243	for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {244		memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len));245		ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf,246					be16_to_cpu(rec->len));247		if (ret < 0)248			break;249	}250 251	kfree(firmware_buf);252exit:253	release_firmware(fw);254	return ret;255}256 257/* Set up for getting frames. */258static int sd_start(struct gspca_dev *gspca_dev)259{260	struct sd *sd = (struct sd *)gspca_dev;261	int ret;262 263	ret = vicam_set_camera_power(gspca_dev, 1);264	if (ret < 0)265		return ret;266 267	schedule_work(&sd->work_struct);268 269	return 0;270}271 272/* called on streamoff with alt==0 and on disconnect */273/* the usb_lock is held at entry - restore on exit */274static void sd_stop0(struct gspca_dev *gspca_dev)275{276	struct sd *dev = (struct sd *)gspca_dev;277 278	/* wait for the work queue to terminate */279	mutex_unlock(&gspca_dev->usb_lock);280	/* This waits for vicam_dostream to finish */281	flush_work(&dev->work_struct);282	mutex_lock(&gspca_dev->usb_lock);283 284	if (gspca_dev->present)285		vicam_set_camera_power(gspca_dev, 0);286}287 288static int sd_init_controls(struct gspca_dev *gspca_dev)289{290	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;291 292	gspca_dev->vdev.ctrl_handler = hdl;293	v4l2_ctrl_handler_init(hdl, 2);294	gspca_dev->exposure = v4l2_ctrl_new_std(hdl, NULL,295			V4L2_CID_EXPOSURE, 0, 2047, 1, 256);296	gspca_dev->gain = v4l2_ctrl_new_std(hdl, NULL,297			V4L2_CID_GAIN, 0, 255, 1, 200);298 299	if (hdl->error) {300		pr_err("Could not initialize controls\n");301		return hdl->error;302	}303	return 0;304}305 306/* Table of supported USB devices */307static const struct usb_device_id device_table[] = {308	{USB_DEVICE(0x04c1, 0x009d)},309	{USB_DEVICE(0x0602, 0x1001)},310	{}311};312 313MODULE_DEVICE_TABLE(usb, device_table);314 315/* sub-driver description */316static const struct sd_desc sd_desc = {317	.name   = MODULE_NAME,318	.config = sd_config,319	.init   = sd_init,320	.init_controls = sd_init_controls,321	.start  = sd_start,322	.stop0  = sd_stop0,323};324 325/* -- device connect -- */326static int sd_probe(struct usb_interface *intf,327		const struct usb_device_id *id)328{329	return gspca_dev_probe(intf, id,330			&sd_desc,331			sizeof(struct sd),332			THIS_MODULE);333}334 335static struct usb_driver sd_driver = {336	.name       = MODULE_NAME,337	.id_table   = device_table,338	.probe      = sd_probe,339	.disconnect = gspca_disconnect,340#ifdef CONFIG_PM341	.suspend = gspca_suspend,342	.resume  = gspca_resume,343	.reset_resume = gspca_resume,344#endif345};346 347module_usb_driver(sd_driver);348