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

📄 se401.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Endpoints (formerly known as AOX) se401 USB Camera Driver * * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) * * Still somewhat based on the Linux ov511 driver. *  * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on * their chipset available and supporting me while writing this driver. * 	- Jeroen Vreeken */static const char version[] = "0.23";#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/pagemap.h>#include <linux/usb.h>#include <asm/io.h>#include <asm/semaphore.h>#include <linux/wrapper.h>#include "se401.h"static int flickerless=0;static int video_nr = -1;static struct usb_device_id device_table [] = {	{ USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */	{ USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */	{ USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */	{ USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */	{ USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */	{ }};MODULE_DEVICE_TABLE(usb, device_table);MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");MODULE_DESCRIPTION("SE401 USB Camera Driver");MODULE_LICENSE("GPL");MODULE_PARM(flickerless, "i");MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");MODULE_PARM(video_nr, "i");EXPORT_NO_SYMBOLS;static struct usb_driver se401_driver;/********************************************************************** * * Memory management * **********************************************************************//* Here we want the physical address of the memory. * This is used when initializing the contents of the area. */static inline unsigned long kvirt_to_pa(unsigned long adr){	unsigned long kva, ret;	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));	kva |= adr & (PAGE_SIZE-1); /* restore the offset */	ret = __pa(kva);	return ret;}static void *rvmalloc(unsigned long size){	void *mem;	unsigned long adr;	size = PAGE_ALIGN(size);	mem = vmalloc_32(size);	if (!mem)		return NULL;	memset(mem, 0, size); /* Clear the ram out, no junk to the user */	adr = (unsigned long) mem;	while (size > 0) {		mem_map_reserve(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	return mem;}static void rvfree(void *mem, unsigned long size){	unsigned long adr;	if (!mem)		return;	adr = (unsigned long) mem;	while ((long) size > 0) {		mem_map_unreserve(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	vfree(mem);}/**************************************************************************** * * /proc interface * ***************************************************************************/#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)static struct proc_dir_entry *se401_proc_entry = NULL;extern struct proc_dir_entry *video_proc_entry;#define YES_NO(x) ((x) ? "yes" : "no")static int se401_read_proc(char *page, char **start, off_t off, int count,			   int *eof, void *data){	char *out = page;	int i, len;	struct usb_se401 *se401 = data;		/* Stay under PAGE_SIZE or else bla bla bla.... */	out+=sprintf(out, "driver_version  : %s\n", version);	out+=sprintf(out, "model           : %s\n", se401->camera_name);	out+=sprintf(out, "in use          : %s\n", YES_NO (se401->user));	out+=sprintf(out, "streaming       : %s\n", YES_NO (se401->streaming));	out+=sprintf(out, "button state    : %s\n", YES_NO (se401->button));	out+=sprintf(out, "button pressed  : %s\n", YES_NO (se401->buttonpressed));	out+=sprintf(out, "num_frames      : %d\n", SE401_NUMFRAMES);	out+=sprintf(out, "Sizes           :");	for (i=0; i<se401->sizes; i++) {		out+=sprintf(out, " %dx%d", se401->width[i],		    se401->height[i]);	}	out+=sprintf(out, "\n");		out+=sprintf(out, "Frames total    : %d\n", se401->readcount);	out+=sprintf(out, "Frames read     : %d\n", se401->framecount);	out+=sprintf(out, "Packets dropped : %d\n", se401->dropped);	out+=sprintf(out, "Decoding Errors : %d\n", se401->error);	len = out - page;	len -= off;	if (len < count) {		*eof = 1;			if (len <= 0) return 0;	} else		len = count;	*start = page + off;		return len;	}static int se401_write_proc(struct file *file, const char *buffer, 			    unsigned long count, void *data){	return -EINVAL;}static void create_proc_se401_cam (struct usb_se401 *se401){	char name[7];	struct proc_dir_entry *ent;	if (!se401_proc_entry || !se401)		return;	sprintf (name, "video%d", se401->vdev.minor);	ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,				se401_proc_entry);	if (!ent)		return;	ent->data = se401;	ent->read_proc = se401_read_proc;	ent->write_proc = se401_write_proc;	se401->proc_entry = ent;}static void destroy_proc_se401_cam (struct usb_se401 *se401){	/* One to much, just to be sure :) */	char name[9];	if (!se401 || !se401->proc_entry)		return;		sprintf(name, "video%d", se401->vdev.minor);	remove_proc_entry(name, se401_proc_entry);	se401->proc_entry = NULL;}static void proc_se401_create (void){	if (video_proc_entry == NULL) {		err("/proc/video/ doesn't exist");		return;	}	se401_proc_entry=create_proc_entry("se401", S_IFDIR, video_proc_entry);	if (se401_proc_entry)		se401_proc_entry->owner = THIS_MODULE;	else		err("Unable to initialize /proc/video/se401");}static void proc_se401_destroy(void){	if (se401_proc_entry == NULL)		return;	remove_proc_entry("se401", video_proc_entry);}#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS *//**************************************************************************** * * se401 register read/write functions * ***************************************************************************/static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,			 unsigned short value, unsigned char *cp, int size){	return usb_control_msg (                se401->dev,                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),                req,                (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,                value,                0,                cp,                size,                HZ        );}static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,			     unsigned short param){	/* specs say that the selector (address) should go in the value field	   and the param in index, but in the logs of the windows driver they do	   this the other way around...	 */	return usb_control_msg (		se401->dev,		usb_sndctrlpipe(se401->dev, 0),		SE401_REQ_SET_EXT_FEATURE,		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,		param,		selector,                NULL,                0,                HZ        );}static unsigned short se401_get_feature(struct usb_se401 *se401, 				        unsigned short selector){	/* For 'set' the selecetor should be in index, not sure if the spec is	   wrong here to....	 */	unsigned char cp[2];        usb_control_msg (                se401->dev,                usb_rcvctrlpipe(se401->dev, 0),                SE401_REQ_GET_EXT_FEATURE,                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,        	0,                selector,                cp,                2,                HZ        );	return cp[0]+cp[1]*256;}/**************************************************************************** * * Camera control * ***************************************************************************/static int se401_send_pict(struct usb_se401 *se401){	se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */	se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */	se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */	se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */	se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */	se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */	se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */	    		return 0;}static void se401_set_exposure(struct usb_se401 *se401, int brightness){	int integration=brightness<<5;		if (flickerless==50) {		integration=integration-integration%106667;	}	if (flickerless==60) {		integration=integration-integration%88889;	}	se401->brightness=integration>>5;	se401->expose_h=(integration>>16)&0xff;	se401->expose_m=(integration>>8)&0xff;	se401->expose_l=integration&0xff;}static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p){	p->brightness=se401->brightness;	if (se401->enhance) {		p->whiteness=32768;	} else {		p->whiteness=0;	}	p->colour=65535;	p->contrast=65535;	p->hue=se401->rgain<<10;	p->palette=se401->palette;	p->depth=3; /* rgb24 */	return 0;}static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p){	if (p->palette != VIDEO_PALETTE_RGB24)		return 1;	se401->palette=p->palette;	if (p->hue!=se401->hue) {		se401->rgain= p->hue>>10;		se401->bgain= 0x40-(p->hue>>10);		se401->hue=p->hue;	}	if (p->brightness!=se401->brightness) {		se401_set_exposure(se401, p->brightness);	}	if (p->whiteness>=32768) {		se401->enhance=1;	} else {		se401->enhance=0;	}	se401_send_pict(se401);	se401_send_pict(se401);	return 0;}/*	Hyundai have some really nice docs about this and other sensor related	stuff on their homepage: www.hei.co.kr*/static void se401_auto_resetlevel(struct usb_se401 *se401){	unsigned int ahrc, alrc;	int oldreset=se401->resetlevel;	/* For some reason this normally read-only register doesn't get reset	   to zero after reading them just once...	 */	se401_get_feature(se401, HV7131_REG_HIREFNOH); 	se401_get_feature(se401, HV7131_REG_HIREFNOL);	se401_get_feature(se401, HV7131_REG_LOREFNOH);	se401_get_feature(se401, HV7131_REG_LOREFNOL);	ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + 	    se401_get_feature(se401, HV7131_REG_HIREFNOL);	alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +	    se401_get_feature(se401, HV7131_REG_LOREFNOL);	/* Not an exact science, but it seems to work pretty well... */	if (alrc > 10) {		while (alrc>=10 && se401->resetlevel < 63) {			se401->resetlevel++;			alrc /=2;		}	} else if (ahrc > 20) {		while (ahrc>=20 && se401->resetlevel > 0) {			se401->resetlevel--;			ahrc /=2;		}	}	if (se401->resetlevel!=oldreset)		se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);	return;}/* irq handler for snapshot button */static void se401_button_irq(struct urb *urb){	struct usb_se401 *se401 = urb->context;		if (!se401->dev) {		info("ohoh: device vapourished");		return;	}		if (urb->actual_length >=2 && !urb->status) {		if (se401->button)			se401->buttonpressed=1;	}}static void se401_video_irq(struct urb *urb){	struct usb_se401 *se401 = urb->context;	int length = urb->actual_length;	/* ohoh... */	if (!se401->streaming)		return;	if (!se401->dev) {		info ("ohoh: device vapourished");		return;	}	/* 0 sized packets happen if we are to fast, but sometimes the camera	   keeps sending them forever...	 */	if (length && !urb->status) {		se401->nullpackets=0;		switch(se401->scratch[se401->scratch_next].state) {			case BUFFER_READY:			case BUFFER_BUSY: {				se401->dropped++;				break;			}			case BUFFER_UNUSED: {				memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);				se401->scratch[se401->scratch_next].state=BUFFER_READY;				se401->scratch[se401->scratch_next].offset=se401->bayeroffset;				se401->scratch[se401->scratch_next].length=length;				if (waitqueue_active(&se401->wq)) {					wake_up_interruptible(&se401->wq);				}				se401->scratch_overflow=0;				se401->scratch_next++;				if (se401->scratch_next>=SE401_NUMSCRATCH)					se401->scratch_next=0;;				break;			}		}		se401->bayeroffset+=length;		if (se401->bayeroffset>=se401->cheight*se401->cwidth) {			se401->bayeroffset=0;		}	} else {		se401->nullpackets++;		if (se401->nullpackets > SE401_MAX_NULLPACKETS) {			if (waitqueue_active(&se401->wq)) {				wake_up_interruptible(&se401->wq);			}				}	}	/* Resubmit urb for new data */	urb->status=0;	urb->dev=se401->dev;	if(usb_submit_urb(urb))		info("urb burned down");	return;}static void se401_send_size(struct usb_se401 *se401, int width, int height){	int i=0;	int mode=0x03; /* No compression */	int sendheight=height;	int sendwidth=width;	/* JangGu compression can only be used with the camera supported sizes,	   but bayer seems to work with any size that fits on the sensor.	   We check if we can use compression with the current size with either	   4 or 16 times subcapturing, if not we use uncompressed bayer data	   but this will result in cutouts of the maximum size....	 */	while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))		i++;	while (i<se401->sizes) {		if (se401->width[i]==width*2 && se401->height[i]==height*2) {			sendheight=se401->height[i];			sendwidth=se401->width[i];			mode=0x40;		}		if (se401->width[i]==width*4 && se401->height[i]==height*4) {			sendheight=se401->height[i];			sendwidth=se401->width[i];			mode=0x42;		}		i++;	}	se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);	se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);	se401_set_feature(se401, SE401_OPERATINGMODE, mode);	if (mode==0x03) {

⌨️ 快捷键说明

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