pac7311.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,121 行 · 第 1/2 页

C
1,121
字号
			v = 0xff;		reg_w(gspca_dev, 0xa2 + i, v);	}	reg_w(gspca_dev, 0xdc, 0x01);}/* This function is used by pac7311 only */static void setcontrast(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	reg_w(gspca_dev, 0xff, 0x04);	reg_w(gspca_dev, 0x10, sd->contrast >> 4);	/* load registers to sensor (Bit 0, auto clear) */	reg_w(gspca_dev, 0x11, 0x01);}/* This function is used by pac7302 only */static void setcolors(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	int i, v;	static const int a[9] =		{217, -212, 0, -101, 170, -67, -38, -315, 355};	static const int b[9] =		{19, 106, 0, 19, 106, 1, 19, 106, 1};	reg_w(gspca_dev, 0xff, 0x03);	/* page 3 */	reg_w(gspca_dev, 0x11, 0x01);	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */	for (i = 0; i < 9; i++) {		v = a[i] * sd->colors / COLOR_MAX + b[i];		reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);		reg_w(gspca_dev, 0x0f + 2 * i + 1, v);	}	reg_w(gspca_dev, 0xdc, 0x01);	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);}static void setgain(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	if (sd->sensor == SENSOR_PAC7302) {		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */		reg_w(gspca_dev, 0x10, sd->gain >> 3);	} else {		int gain = GAIN_MAX - sd->gain;		if (gain < 1)			gain = 1;		else if (gain > 245)			gain = 245;		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */		reg_w(gspca_dev, 0x0e, 0x00);		reg_w(gspca_dev, 0x0f, gain);	}	/* load registers to sensor (Bit 0, auto clear) */	reg_w(gspca_dev, 0x11, 0x01);}static void setexposure(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	__u8 reg;	/* register 2 of frame 3/4 contains the clock divider configuring the	   no fps according to the formula: 60 / reg. sd->exposure is the	   desired exposure time in ms. */	reg = 120 * sd->exposure / 1000;	if (reg < 2)		reg = 2;	else if (reg > 63)		reg = 63;	if (sd->sensor == SENSOR_PAC7302) {		/* On the pac7302 reg2 MUST be a multiple of 3, so round it to		   the nearest multiple of 3, except when between 6 and 12? */		if (reg < 6 || reg > 12)			reg = ((reg + 1) / 3) * 3;		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */		reg_w(gspca_dev, 0x02, reg);	} else {		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */		reg_w(gspca_dev, 0x02, reg);		/* Page 1 register 8 must always be 0x08 except when not in		   640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */		reg_w(gspca_dev, 0xff, 0x01);		if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&				reg <= 3)			reg_w(gspca_dev, 0x08, 0x09);		else			reg_w(gspca_dev, 0x08, 0x08);	}	/* load registers to sensor (Bit 0, auto clear) */	reg_w(gspca_dev, 0x11, 0x01);}static void sethvflip(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	__u8 data;	if (sd->sensor == SENSOR_PAC7302) {		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */		data = (sd->hflip ? 0x08 : 0x00)			| (sd->vflip ? 0x04 : 0x00);	} else {		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */		data = (sd->hflip ? 0x04 : 0x00)			| (sd->vflip ? 0x08 : 0x00);	}	reg_w(gspca_dev, 0x21, data);	/* load registers to sensor (Bit 0, auto clear) */	reg_w(gspca_dev, 0x11, 0x01);}/* this function is called at probe and resume time */static int sd_init(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	if (sd->sensor == SENSOR_PAC7302)		reg_w_seq(gspca_dev, init_7302, sizeof init_7302);	else		reg_w_seq(gspca_dev, init_7311, sizeof init_7311);	return 0;}static int sd_start(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	sd->sof_read = 0;	if (sd->sensor == SENSOR_PAC7302) {		reg_w_var(gspca_dev, start_7302);		setbrightcont(gspca_dev);		setcolors(gspca_dev);	} else {		reg_w_var(gspca_dev, start_7311);		setcontrast(gspca_dev);	}	setgain(gspca_dev);	setexposure(gspca_dev);	sethvflip(gspca_dev);	/* set correct resolution */	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {	case 2:					/* 160x120 pac7311 */		reg_w(gspca_dev, 0xff, 0x01);		reg_w(gspca_dev, 0x17, 0x20);		reg_w(gspca_dev, 0x87, 0x10);		break;	case 1:					/* 320x240 pac7311 */		reg_w(gspca_dev, 0xff, 0x01);		reg_w(gspca_dev, 0x17, 0x30);		reg_w(gspca_dev, 0x87, 0x11);		break;	case 0:					/* 640x480 */		if (sd->sensor == SENSOR_PAC7302)			break;		reg_w(gspca_dev, 0xff, 0x01);		reg_w(gspca_dev, 0x17, 0x00);		reg_w(gspca_dev, 0x87, 0x12);		break;	}	sd->sof_read = 0;	sd->autogain_ignore_frames = 0;	atomic_set(&sd->avg_lum, -1);	/* start stream */	reg_w(gspca_dev, 0xff, 0x01);	if (sd->sensor == SENSOR_PAC7302)		reg_w(gspca_dev, 0x78, 0x01);	else		reg_w(gspca_dev, 0x78, 0x05);	return 0;}static void sd_stopN(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	if (sd->sensor == SENSOR_PAC7302) {		reg_w(gspca_dev, 0xff, 0x01);		reg_w(gspca_dev, 0x78, 0x00);		reg_w(gspca_dev, 0x78, 0x00);		return;	}	reg_w(gspca_dev, 0xff, 0x04);	reg_w(gspca_dev, 0x27, 0x80);	reg_w(gspca_dev, 0x28, 0xca);	reg_w(gspca_dev, 0x29, 0x53);	reg_w(gspca_dev, 0x2a, 0x0e);	reg_w(gspca_dev, 0xff, 0x01);	reg_w(gspca_dev, 0x3e, 0x20);	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */}static void sd_stop0(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	if (sd->sensor == SENSOR_PAC7302) {		reg_w(gspca_dev, 0xff, 0x01);		reg_w(gspca_dev, 0x78, 0x40);	}}/* Include pac common sof detection functions */#include "pac_common.h"static void do_autogain(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	int avg_lum = atomic_read(&sd->avg_lum);	int desired_lum, deadzone;	if (avg_lum == -1)		return;	if (sd->sensor == SENSOR_PAC7302) {		desired_lum = 270 + sd->brightness * 4;		/* Hack hack, with the 7202 the first exposure step is		   pretty large, so if we're about to make the first		   exposure increase make the deadzone large to avoid		   oscilating */		if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&				sd->exposure > EXPOSURE_DEF &&				sd->exposure < 42)			deadzone = 90;		else			deadzone = 30;	} else {		desired_lum = 200;		deadzone = 20;	}	if (sd->autogain_ignore_frames > 0)		sd->autogain_ignore_frames--;	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,			deadzone, GAIN_KNEE, EXPOSURE_KNEE))		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;}static const unsigned char pac7311_jpeg_header1[] = {  0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08};static const unsigned char pac7311_jpeg_header2[] = {  0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,  0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00};/* this function is run at interrupt level */static void sd_pkt_scan(struct gspca_dev *gspca_dev,			struct gspca_frame *frame,	/* target */			__u8 *data,			/* isoc packet */			int len)			/* iso packet length */{	struct sd *sd = (struct sd *) gspca_dev;	unsigned char *sof;	sof = pac_find_sof(gspca_dev, data, len);	if (sof) {		unsigned char tmpbuf[4];		int n, lum_offset, footer_length;		if (sd->sensor == SENSOR_PAC7302) {		  /* 6 bytes after the FF D9 EOF marker a number of lumination		     bytes are send corresponding to different parts of the		     image, the 14th and 15th byte after the EOF seem to		     correspond to the center of the image */		  lum_offset = 61 + sizeof pac_sof_marker;		  footer_length = 74;		} else {		  lum_offset = 24 + sizeof pac_sof_marker;		  footer_length = 26;		}		/* Finish decoding current frame */		n = (sof - data) - (footer_length + sizeof pac_sof_marker);		if (n < 0) {			frame->data_end += n;			n = 0;		}		frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,					data, n);		if (gspca_dev->last_packet_type != DISCARD_PACKET &&				frame->data_end[-2] == 0xff &&				frame->data_end[-1] == 0xd9)			frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,						NULL, 0);		n = sof - data;		len -= n;		data = sof;		/* Get average lumination */		if (gspca_dev->last_packet_type == LAST_PACKET &&				n >= lum_offset)			atomic_set(&sd->avg_lum, data[-lum_offset] +						data[-lum_offset + 1]);		else			atomic_set(&sd->avg_lum, -1);		/* Start the new frame with the jpeg header */		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,			pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));		if (sd->sensor == SENSOR_PAC7302) {			/* The PAC7302 has the image rotated 90 degrees */			tmpbuf[0] = gspca_dev->width >> 8;			tmpbuf[1] = gspca_dev->width & 0xff;			tmpbuf[2] = gspca_dev->height >> 8;			tmpbuf[3] = gspca_dev->height & 0xff;		} else {			tmpbuf[0] = gspca_dev->height >> 8;			tmpbuf[1] = gspca_dev->height & 0xff;			tmpbuf[2] = gspca_dev->width >> 8;			tmpbuf[3] = gspca_dev->width & 0xff;		}		gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);		gspca_frame_add(gspca_dev, INTER_PACKET, frame,			pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));	}	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);}static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->brightness = val;	if (gspca_dev->streaming)		setbrightcont(gspca_dev);	return 0;}static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->brightness;	return 0;}static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->contrast = val;	if (gspca_dev->streaming) {		if (sd->sensor == SENSOR_PAC7302)			setbrightcont(gspca_dev);		else			setcontrast(gspca_dev);	}	return 0;}static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->contrast;	return 0;}static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->colors = val;	if (gspca_dev->streaming)		setcolors(gspca_dev);	return 0;}static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->colors;	return 0;}static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->gain = val;	if (gspca_dev->streaming)		setgain(gspca_dev);	return 0;}static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->gain;	return 0;}static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->exposure = val;	if (gspca_dev->streaming)		setexposure(gspca_dev);	return 0;}static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->exposure;	return 0;}static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->autogain = val;	/* when switching to autogain set defaults to make sure	   we are on a valid point of the autogain gain /	   exposure knee graph, and give this change time to	   take effect before doing autogain. */	if (sd->autogain) {		sd->exposure = EXPOSURE_DEF;		sd->gain = GAIN_DEF;		if (gspca_dev->streaming) {			sd->autogain_ignore_frames =				PAC_AUTOGAIN_IGNORE_FRAMES;			setexposure(gspca_dev);			setgain(gspca_dev);		}	}	return 0;}static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->autogain;	return 0;}static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->hflip = val;	if (gspca_dev->streaming)		sethvflip(gspca_dev);	return 0;}static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->hflip;	return 0;}static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val){	struct sd *sd = (struct sd *) gspca_dev;	sd->vflip = val;	if (gspca_dev->streaming)		sethvflip(gspca_dev);	return 0;}static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val){	struct sd *sd = (struct sd *) gspca_dev;	*val = sd->vflip;	return 0;}/* sub-driver description */static struct sd_desc sd_desc = {	.name = MODULE_NAME,	.ctrls = sd_ctrls,	.nctrls = ARRAY_SIZE(sd_ctrls),	.config = sd_config,	.init = sd_init,	.start = sd_start,	.stopN = sd_stopN,	.stop0 = sd_stop0,	.pkt_scan = sd_pkt_scan,	.dq_callback = do_autogain,};/* -- module initialisation -- */static __devinitdata struct usb_device_id device_table[] = {	{USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},	{USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},	{USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},	{USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},	{USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},	{USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},	{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},	{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},	{USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},	{USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},	{}};MODULE_DEVICE_TABLE(usb, device_table);/* -- device connect -- */static int sd_probe(struct usb_interface *intf,			const struct usb_device_id *id){	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),				THIS_MODULE);}static struct usb_driver sd_driver = {	.name = MODULE_NAME,	.id_table = device_table,	.probe = sd_probe,	.disconnect = gspca_disconnect,#ifdef CONFIG_PM	.suspend = gspca_suspend,	.resume = gspca_resume,#endif};/* -- module insert / remove -- */static int __init sd_mod_init(void){	if (usb_register(&sd_driver) < 0)		return -1;	PDEBUG(D_PROBE, "registered");	return 0;}static void __exit sd_mod_exit(void){	usb_deregister(&sd_driver);	PDEBUG(D_PROBE, "deregistered");}module_init(sd_mod_init);module_exit(sd_mod_exit);

⌨️ 快捷键说明

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