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

📄 ov511.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * OmniVision OV511 Camera-to-USB Bridge Driver * Copyright 1999 Mark W. McClelland * * Based on the Linux CPiA driver. *  * Released under GPL v.2 license. * * Important keywords in comments: *    CAMERA SPECIFIC - Camera specific code; may not work with other cameras. *    DEBUG - Debugging code. *    FIXME - Something that is broken or needs improvement. * * Version History: *    Version 1.00 - Initial version *//* * 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. */#define __NO_VERSION__/* Handle mangled (versioned) external symbols */#include <linux/config.h>   /* retrieve the CONFIG_* macros */#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)#	define MODVERSIONS  /* force it on */#endif#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/kernel.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/smp_lock.h>#include <linux/videodev.h>#include <linux/vmalloc.h>#include <linux/wrapper.h>#include <linux/module.h>#include <linux/spinlock.h>#include <asm/io.h>#include "usb.h"#include "ov511.h"#define OV511_I2C_RETRIES 3/* Video Size 640 x 480 x 3 bytes for RGB */#define MAX_FRAME_SIZE (640 * 480 * 3)// FIXME - Force CIF to make some apps happy for the moment. Should find a //         better way to do this.#define DEFAULT_WIDTH 640#define DEFAULT_HEIGHT 480char kernel_version[] = UTS_RELEASE;/*******************************//* Memory management functions *//*******************************/#define MDEBUG(x)	do { } while(0)		/* Debug memory management */static struct usb_driver ov511_driver;/* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr){	unsigned long ret = 0UL;	pmd_t *pmd;	pte_t *ptep, pte;	if (!pgd_none(*pgd)) {		pmd = pmd_offset(pgd, adr);		if (!pmd_none(*pmd)) {			ptep = pte_offset(pmd, adr);			pte = *ptep;			if (pte_present(pte))				ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));		}	}	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));	return ret;}static inline unsigned long uvirt_to_bus(unsigned long adr){	unsigned long kva, ret;	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);	ret = virt_to_bus((void *)kva);	MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));	return ret;}static inline unsigned long kvirt_to_bus(unsigned long adr){	unsigned long va, kva, ret;	va = VMALLOC_VMADDR(adr);	kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = virt_to_bus((void *)kva);	MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));	return ret;}/* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */static inline unsigned long kvirt_to_pa(unsigned long adr){	unsigned long va, kva, ret;	va = VMALLOC_VMADDR(adr);	kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = __pa(kva);	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));	return ret;}static void *rvmalloc(unsigned long size){	void *mem;	unsigned long adr, page;	/* Round it off to PAGE_SIZE */	size += (PAGE_SIZE - 1);	size &= ~(PAGE_SIZE - 1);	mem = vmalloc(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) {		page = kvirt_to_pa(adr);		mem_map_reserve(MAP_NR(__va(page)));		adr += PAGE_SIZE;		if (size > PAGE_SIZE)			size -= PAGE_SIZE;		else			size = 0;	}	return mem;}static void rvfree(void *mem, unsigned long size){	unsigned long adr, page;	if (!mem)		return;	size += (PAGE_SIZE - 1);	size &= ~(PAGE_SIZE - 1);	adr=(unsigned long) mem;	while (size > 0) {		page = kvirt_to_pa(adr);		mem_map_unreserve(MAP_NR(__va(page)));		adr += PAGE_SIZE;		if (size > PAGE_SIZE)			size -= PAGE_SIZE;		else			size = 0;	}	vfree(mem);}int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value){	int rc;	rc = usb_control_msg(dev,		usb_sndctrlpipe(dev, 0),		2 /* REG_IO */,		USB_TYPE_CLASS | USB_RECIP_DEVICE,		0, (__u16)reg, &value, 1, HZ);				#if 0	PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);#endif				return rc;}/* returns: negative is error, pos or zero is data */int ov511_reg_read(struct usb_device *dev, unsigned char reg){	int rc;	unsigned char buffer[1];	rc = usb_control_msg(dev,		usb_rcvctrlpipe(dev, 0),		2 /* REG_IO */,		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,		0, (__u16)reg, buffer, 1, HZ);                               #if 0	PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);#endif		if(rc < 0)		return rc;	else		return buffer[0];	}int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value){	int rc, retries;#if 0	PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);#endif	/* Three byte write cycle */	for(retries = OV511_I2C_RETRIES;;) {		/* Select camera register */		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);		if (rc < 0) return rc;		/* Write "value" to I2C data port of OV511 */		rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);			if (rc < 0) return rc;		/* Initiate 3-byte write cycle */		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);		if (rc < 0) return rc;		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */		if (rc < 0) return rc;		if((rc&2) == 0) /* Ack? */			break;		/* I2C abort */			ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);		if (--retries < 0) return -1;	}	return 0;}/* returns: negative is error, pos or zero is data */int ov511_i2c_read(struct usb_device *dev, unsigned char reg){	int rc, value, retries;	/* Two byte write cycle */	for(retries = OV511_I2C_RETRIES;;) {		/* Select camera register */		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);		if (rc < 0) return rc;		/* Initiate 2-byte write cycle */		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);		if (rc < 0) return rc;		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */		if (rc < 0) return rc;		if((rc&2) == 0) /* Ack? */			break;		/* I2C abort */			ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);		if (--retries < 0) return -1;	}	/* Two byte read cycle */	for(retries = OV511_I2C_RETRIES;;) {		/* Initiate 2-byte read cycle */		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);		if (rc < 0) return rc;		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);		while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */		if (rc < 0) return rc;		if((rc&2) == 0) /* Ack? */			break;		/* I2C abort */			rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);		if (rc < 0) return rc;		if (--retries < 0) return -1;	}	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);#if 0	PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);#endif			/* This is needed to make ov511_i2c_write() work */	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);	if (rc < 0) return rc;		return (value);}#if 0static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn){	int i;	int rc;	for(i=reg1; i<=regn; i++) {	  rc = ov511_i2c_read(dev, i);#if 0	  PDEBUG("OV7610[0x%X] = 0x%X\n", i, rc);#endif	}}static void ov511_dump_i2c_regs( struct usb_device *dev){	PDEBUG("I2C REGS\n");	ov511_dump_i2c_range(dev, 0x00, 0x38);}static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn){	int i;	int rc;	for(i=reg1; i<=regn; i++) {	  rc = ov511_reg_read(dev, i);	  PDEBUG("OV511[0x%X] = 0x%X\n", i, rc);	}}static void ov511_dump_regs( struct usb_device *dev){	PDEBUG("CAMERA INTERFACE REGS\n");	ov511_dump_reg_range(dev, 0x10, 0x1f);	PDEBUG("DRAM INTERFACE REGS\n");	ov511_dump_reg_range(dev, 0x20, 0x23);	PDEBUG("ISO FIFO REGS\n");	ov511_dump_reg_range(dev, 0x30, 0x31);	PDEBUG("PIO REGS\n");	ov511_dump_reg_range(dev, 0x38, 0x39);	ov511_dump_reg_range(dev, 0x3e, 0x3e);	PDEBUG("I2C REGS\n");	ov511_dump_reg_range(dev, 0x40, 0x49);	PDEBUG("SYSTEM CONTROL REGS\n");	ov511_dump_reg_range(dev, 0x50, 0x53);	ov511_dump_reg_range(dev, 0x5e, 0x5f);	PDEBUG("OmniCE REGS\n");	ov511_dump_reg_range(dev, 0x70, 0x79);	ov511_dump_reg_range(dev, 0x80, 0x9f);	ov511_dump_reg_range(dev, 0xa0, 0xbf);}#endifint ov511_i2c_reset(struct usb_device *dev){	int rc;	PDEBUG("Reset 7610\n");	rc = ov511_i2c_write(dev, 0x12, 0x80);	if (rc < 0)		printk(KERN_ERR "ov511: i2c reset: command failed\n");	return rc;}int ov511_reset(struct usb_device *dev, unsigned char reset_type){	int rc;		PDEBUG("Reset: type=0x%X\n", reset_type);	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);	if (rc < 0)		printk(KERN_ERR "ov511: reset: command failed\n");	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);	if (rc < 0)		printk(KERN_ERR "ov511: reset: command failed\n");	return rc;}int ov511_set_packet_size(struct usb_ov511 *ov511, int size){	int alt, multiplier, err;		#if 0	PDEBUG("set packet size: %d\n", size);#endif		switch (size) {		case 992:			alt = 0;			multiplier = 31;			break;		case 993:			alt = 1;			multiplier = 31;			break;		case 768:			alt = 2;			multiplier = 24;			break;		case 769:			alt = 3;			multiplier = 24;			break;		case 512:			alt = 4;			multiplier = 16;			break;		case 513:			alt = 5;			multiplier = 16;			break;		case 257:			alt = 6;			multiplier = 8;			break;		case 0:			alt = 7;			multiplier = 1; // FIXME - is this correct?			break;		default:			printk(KERN_ERR "ov511_set_packet_size: invalid size (%d)\n",			       size);			return -EINVAL;	}	err = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,	                          multiplier);	if (err < 0) {		printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n",		       err);		return -ENOMEM;	}		if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {		printk(KERN_ERR "ov511: Set packet size: set interface error\n");		return -EBUSY;	}	// FIXME - Should we only reset the FIFO?	if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)		return -ENOMEM;	return 0;}static int ov511_mode_init_regs(struct usb_ov511 *ov511,				int width, int height, int mode){	int rc = 0;	struct usb_device *dev = ov511->dev;#if 0	PDEBUG("ov511_mode_init_regs(ov511, %d, %d, %d)\n",	       width, height, mode);#endif	ov511_set_packet_size(ov511, 0);	/* Set mode consistent registers */	ov511_i2c_write(dev, 0x0f, 0x03);	ov511_i2c_write(dev, 0x10, 0xff);	ov511_i2c_write(dev, 0x13, 0x01);	ov511_i2c_write(dev, 0x16, 0x06);	ov511_i2c_write(dev, 0x20, 0x1c);	ov511_i2c_write(dev, 0x24, 0x2e); /* 10 */	ov511_i2c_write(dev, 0x25, 0x7c); /* 8a */	ov511_i2c_write(dev, 0x26, 0x70);	ov511_i2c_write(dev, 0x28, 0x24); /* 24 */	ov511_i2c_write(dev, 0x2b, 0xac);	ov511_i2c_write(dev, 0x2c, 0xfe);	ov511_i2c_write(dev, 0x2d, 0x93);	ov511_i2c_write(dev, 0x34, 0x8b);	if (width == 640 && height == 480) {		ov511_reg_write(dev, 0x12, 0x4f);		ov511_reg_write(dev, 0x13, 0x3d);		ov511_reg_write(dev, 0x14, 0x00);		ov511_reg_write(dev, 0x15, 0x00);		ov511_reg_write(dev, 0x18, 0x03);		ov511_i2c_write(dev, 0x11, 0x01);		ov511_i2c_write(dev, 0x12, 0x24);		ov511_i2c_write(dev, 0x14, 0x04);		ov511_i2c_write(dev, 0x35, 0x9e);	} else if (width == 320 && height == 240) {		ov511_reg_write(dev, 0x12, 0x27);		ov511_reg_write(dev, 0x13, 0x1f);		ov511_reg_write(dev, 0x14, 0x00);		ov511_reg_write(dev, 0x15, 0x00);		ov511_reg_write(dev, 0x18, 0x03);		ov511_i2c_write(dev, 0x11, 0x00);		ov511_i2c_write(dev, 0x12, 0x04);		ov511_i2c_write(dev, 0x14, 0x24);		ov511_i2c_write(dev, 0x35, 0x1e);	} else {		PDEBUG("ov511: Unknown mode (%d, %d): %d\n",		       width, height, mode);		rc = -EINVAL;	}	ov511_set_packet_size(ov511, 993);	return rc;}	/*************************************************************Turn a YUV4:2:0 block into an RGB block*************************************************************/#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)static inline void ov511_move_420_block(int y00, int y01, int y10, int y11,					int u, int v, int w,					unsigned char * pOut){	int r    = 68911 * v;	int g    = -16915 * u + -35101 * v;	int b    = 87097 * u;	y00 *= 49152;	y01 *= 49152;	y10 *= 49152;	y11 *= 49152;	*(pOut+w*3) = LIMIT(r + y10);	*pOut++     = LIMIT(r + y00);	*(pOut+w*3) = LIMIT(g + y10);

⌨️ 快捷键说明

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