⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quickcam_messenger.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Driver for Logitech Quickcam Messenger usb video camera * Copyright (C) Jaya Kumar * * This work was sponsored by CIS(M) Sdn Bhd. * History: * 05/08/2006 - Jaya Kumar * I wrote this based on the konicawc by Simon Evans. * - * Full credit for reverse engineering and creating an initial * working linux driver for the VV6422 goes to the qce-ga project by * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell, * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as * others. * --- * 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 * (at your option) 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/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/input.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)#include <linux/usb/input.h>#else#include <linux/usb_input.h>#endif#include "usbvideo.h"#include "quickcam_messenger.h"#include "compat.h"/* * Version Information */#ifdef CONFIG_USB_DEBUGstatic int debug;#define DEBUG(n, format, arg...) \	if (n <= debug) {	 \		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \	}#else#define DEBUG(n, arg...)static const int debug;#endif#define DRIVER_VERSION "v0.01"#define DRIVER_DESC "Logitech Quickcam Messenger USB"#define USB_LOGITECH_VENDOR_ID	0x046D#define USB_QCM_PRODUCT_ID	0x08F0#define MAX_CAMERAS	1#define MAX_COLOUR	32768#define MAX_HUE		32768#define MAX_BRIGHTNESS	32768#define MAX_CONTRAST	32768#define MAX_WHITENESS	32768static int size = SIZE_320X240;static int colour = MAX_COLOUR;static int hue = MAX_HUE;static int brightness =	MAX_BRIGHTNESS;static int contrast =	MAX_CONTRAST;static int whiteness =	MAX_WHITENESS;static struct usbvideo *cams;static struct usb_device_id qcm_table [] = {	{ USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },	{ }};MODULE_DEVICE_TABLE(usb, qcm_table);#ifdef CONFIG_INPUTstatic void qcm_register_input(struct qcm *cam, struct usb_device *dev){	struct input_dev *input_dev;	int error;	usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));	strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));	cam->input = input_dev = input_allocate_device();	if (!input_dev) {		dev_warn(&dev->dev, "insufficient mem for cam input device\n");		return;	}	input_dev->name = "QCM button";	input_dev->phys = cam->input_physname;	usb_to_input_id(dev, &input_dev->id);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)	input_dev->dev.parent = &dev->dev;#else	input_dev->cdev.dev = &dev->dev;#endif	input_dev->evbit[0] = BIT_MASK(EV_KEY);	input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);	error = input_register_device(cam->input);	if (error) {		dev_warn(&dev->dev,			 "Failed to register camera's input device, err: %d\n",			 error);		input_free_device(cam->input);		cam->input = NULL;	}}static void qcm_unregister_input(struct qcm *cam){	if (cam->input) {		input_unregister_device(cam->input);		cam->input = NULL;	}}static void qcm_report_buttonstat(struct qcm *cam){	if (cam->input) {		input_report_key(cam->input, BTN_0, cam->button_sts);		input_sync(cam->input);	}}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)#elsestatic void qcm_int_irq(struct urb *urb)#endif{	int ret;	struct uvd *uvd = urb->context;	struct qcm *cam;	if (!CAMERA_IS_OPERATIONAL(uvd))		return;	if (!uvd->streaming)		return;	uvd->stats.urb_count++;	if (urb->status < 0)		uvd->stats.iso_err_count++;	else {		if (urb->actual_length > 0 ) {			cam = (struct qcm *) uvd->user_data;			if (cam->button_sts_buf == 0x88)				cam->button_sts = 0x0;			else if (cam->button_sts_buf == 0x80)				cam->button_sts = 0x1;			qcm_report_buttonstat(cam);		}	}	ret = usb_submit_urb(urb, GFP_ATOMIC);	if (ret < 0)		err("usb_submit_urb error (%d)", ret);}static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd){	int errflag;	usb_fill_int_urb(cam->button_urb, uvd->dev,			usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),			&cam->button_sts_buf,			1,			qcm_int_irq,			uvd, 16);	errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);	if (errflag)		err ("usb_submit_int ret %d", errflag);	return errflag;}static void qcm_stop_int_data(struct qcm *cam){	usb_kill_urb(cam->button_urb);}static int qcm_alloc_int_urb(struct qcm *cam){	cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!cam->button_urb)		return -ENOMEM;	return 0;}static void qcm_free_int(struct qcm *cam){	usb_free_urb(cam->button_urb);}#endif /* CONFIG_INPUT */static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val){	int ret;	/* we'll wait up to 3 slices but no more */	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),		0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,		reg, 0, &val, 1, 3*HZ);	return ret;}static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val){	int ret;	/* we'll wait up to 3 slices but no more */	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),		0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,		reg, 0, &val, 2, 3*HZ);	return ret;}static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,							__le16 *val){	int ret;	/* we'll wait up to 3 slices but no more */	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),		0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,		reg, 0, val, 2, 3*HZ);	return ret;}static int qcm_camera_on(struct uvd *uvd){	int ret;	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));	return 0;}static int qcm_camera_off(struct uvd *uvd){	int ret;	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));	return 0;}static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b){	unsigned int segment, valsat;	signed int   h = (signed int) hue;	unsigned int s = (sat - 32768) * 2;	/* rescale */	unsigned int v = val;	unsigned int p;	/*	the registers controlling gain are 8 bit of which	we affect only the last 4 bits with our gain.	we know that if saturation is 0, (unsaturated) then	we're grayscale (center axis of the colour cone) so	we set rgb=value. we use a formula obtained from	wikipedia to map the cone to the RGB plane. it's	as follows for the human value case of h=0..360,	s=0..1, v=0..1	h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)	q = v(1 - f*s) , t = v(1 - (1-f)s)	h_i==0 => r=v , g=t, b=p	h_i==1 => r=q , g=v, b=p	h_i==2 => r=p , g=v, b=t	h_i==3 => r=p , g=q, b=v	h_i==4 => r=t , g=p, b=v	h_i==5 => r=v , g=p, b=q	the bottom side (the point) and the stuff just up	of that is black so we simplify those two cases.	*/	if (sat < 32768) {		/* anything less than this is unsaturated */		*r = val;		*g = val;		*b = val;		return;	}	if (val <= (0xFFFF/8)) {		/* anything less than this is black */		*r = 0;		*g = 0;		*b = 0;		return;	}	/* the rest of this code is copying tukkat's	implementation of the hsv2rgb conversion as taken	from qc-usb-messenger code. the 10923 is 0xFFFF/6	to divide the cone into 6 sectors.  */	segment = (h + 10923) & 0xFFFF;	segment = segment*3 >> 16;		/* 0..2: 0=R, 1=G, 2=B */	hue -= segment * 21845;			/* -10923..10923 */	h = hue;	h *= 3;	valsat = v*s >> 16;			/* 0..65534 */	p = v - valsat;	if (h >= 0) {		unsigned int t = v - (valsat * (32769 - h) >> 15);		switch (segment) {		case 0:	/* R-> */			*r = v;			*g = t;			*b = p;			break;		case 1:	/* G-> */			*r = p;			*g = v;			*b = t;			break;		case 2:	/* B-> */			*r = t;			*g = p;			*b = v;			break;		}	} else {		unsigned int q = v - (valsat * (32769 + h) >> 15);		switch (segment) {		case 0:	/* ->R */			*r = v;			*g = p;			*b = q;			break;		case 1:	/* ->G */			*r = q;			*g = v;			*b = p;			break;		case 2:	/* ->B */			*r = p;			*g = q;			*b = v;			break;		}	}}static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,	u16 saturation, u16 value){	int ret;	u16 r=0,g=0,b=0;	/* this code is based on qc-usb-messenger */	qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);	r >>= 12;	g >>= 12;	b >>= 12;	/* min val is 8 */	r = max((u16) 8, r);	g = max((u16) 8, g);	b = max((u16) 8, b);	r |= 0x30;	g |= 0x30;	b |= 0x30;	/* set the r,g,b gain registers */	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));	/* doing as qc-usb did */	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));	return 0;}static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure){	int ret;	int formedval;	/* calculation was from qc-usb-messenger driver */	formedval = ( exposure >> 12 );	/* max value for formedval is 14 */	formedval = min(formedval, 14);	CHECK_RET(ret, qcm_stv_setb(uvd->dev,			0x143A, 0xF0 | formedval));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));	return 0;}static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,					int hue, int colour){	int ret;	/* brightness is exposure, contrast is gain, colour is saturation */	CHECK_RET(ret,		qcm_sensor_set_exposure(uvd, brightness));	CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));	return 0;}static int qcm_sensor_setsize(struct uvd *uvd, u8 size){	int ret;	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));	return 0;}static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness){	int ret;	/* some rescaling as done by the qc-usb-messenger code */	if (whiteness > 0xC000)		whiteness = 0xC000 + (whiteness & 0x3FFF)*8;	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,				(whiteness >> 8) & 0xFF));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,				(whiteness >> 16) & 0x03));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));	return 0;}static int qcm_sensor_init(struct uvd *uvd){	struct qcm *cam = (struct qcm *) uvd->user_data;	int ret;	int i;	for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {		CHECK_RET(ret, qcm_stv_setb(uvd->dev,					regval_table[i].reg,					regval_table[i].val));	}	CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,				cpu_to_le16(ISOC_PACKET_SIZE)));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));	CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));	CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,			uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));	CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));	return 0;}static int qcm_set_camera_size(struct uvd *uvd){	int ret;	struct qcm *cam = (struct qcm *) uvd->user_data;	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));	cam->width = camera_sizes[cam->size].width;	cam->height = camera_sizes[cam->size].height;	uvd->videosize = VIDEOSIZE(cam->width, cam->height);	return 0;}static int qcm_setup_on_open(struct uvd *uvd){	int ret;	CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,				uvd->vpic.colour, uvd->vpic.contrast));	CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));	CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));	CHECK_RET(ret, qcm_set_camera_size(uvd));	CHECK_RET(ret, qcm_camera_on(uvd));	return 0;}static void qcm_adjust_picture(struct uvd *uvd){	int ret;	struct qcm *cam = (struct qcm *) uvd->user_data;	ret = qcm_camera_off(uvd);	if (ret) {		err("can't turn camera off. abandoning pic adjustment");		return;	}	/* if there's been a change in contrast, hue, or	colour then we need to recalculate hsv in order	to update gains */	if ((cam->contrast != uvd->vpic.contrast) ||		(cam->hue != uvd->vpic.hue) ||		(cam->colour != uvd->vpic.colour)) {		cam->contrast = uvd->vpic.contrast;		cam->hue = uvd->vpic.hue;		cam->colour = uvd->vpic.colour;		ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,						cam->contrast);		if (ret) {			err("can't set gains. abandoning pic adjustment");			return;		}	}	if (cam->brightness != uvd->vpic.brightness) {		cam->brightness = uvd->vpic.brightness;		ret = qcm_sensor_set_exposure(uvd, cam->brightness);		if (ret) {			err("can't set exposure. abandoning pic adjustment");			return;		}	}	if (cam->whiteness != uvd->vpic.whiteness) {		cam->whiteness = uvd->vpic.whiteness;		qcm_sensor_set_shutter(uvd, cam->whiteness);		if (ret) {			err("can't set shutter. abandoning pic adjustment");			return;		}	}	ret = qcm_camera_on(uvd);	if (ret) {		err("can't reenable camera. pic adjustment failed");		return;	}}static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen){	int datalen;	int totaldata;	struct framehdr {		__be16 id;		__be16 len;	};	struct framehdr *fhdr;	totaldata = 0;	while (framelen) {		fhdr = (struct framehdr *) cdata;		datalen = be16_to_cpu(fhdr->len);		framelen -= 4;		cdata += 4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -