📄 fps200.c
字号:
/** * Title: fps200.c * Type: C (*.c) * Description: a driver of fps200 in linux 2.4.x * Copyright: Copyright (c) 2003 * Company: djws * author djws * version 1.0 */#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include <linux/slab.h> /* kmalloc() */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t *///#include <linux/proc_fs.h>#include <linux/init.h>//#include <linux/fcntl.h> /* O_ACCMODE *///#include <asm/system.h> /* cli(), *_flags */#include <linux/delay.h> /* udelay() */#include <asm/io.h> /* ioremap(), iounmap() *///#include <asm/hardware.h>#include <linux/ioport.h>//#include <asm/sizes.h>//#include <linux/tqueue.h>//#include <linux/interrupt.h>#include <asm/irq.h>#include <linux/string.h>//#include <linux/sched.h>//#include <linux/mm.h>//#include <asm/pgtable.h>//#include <asm/page.h>//#include <asm/setup.h>//#include <asm/mach-types.h>//#include <asm/mach/arch.h>//#include <asm/mach/map.h>#include <asm/uaccess.h>#include <asm/arch/irqs.h>#include "fps200.h" /* local definitions */#define FPS200_VR 0xfd000000#define FPS_INDEX (*(volatile unsigned char *)FPS200_VR)#define FPS_DATA (*(volatile unsigned char *)(FPS200_VR+1))/* * I don't use static symbols here, because we export no symbols */#define FPS200_MAJOR 240#define FPS200_NR_DEVS 0#define FPS200_IRQ IRQ_EINT2 // the irq is 6#define FPS200_DATASIZE 76800int fps200_major = FPS200_MAJOR;int fps200_nr_devs = FPS200_NR_DEVS; /* number of bare fps200 devices (no use here) */MODULE_PARM(fps200_major,"i");MODULE_PARM(fps200_nr_devs,"i");MODULE_AUTHOR("Dai Jin");MODULE_LICENSE("GPL");struct file_operations fps200_fops = { open: fps200_open,// read: fps200_read,// write: fps200_write, ioctl: fps200_ioctl, release: fps200_release};struct file_operations *fps200_fop_array[]={ &fps200_fops, /* type 0 */ /* add more later */};#define FPS200_MAX_TYPE 0FPS200_Dev *fps200_device;void fps200_interrupt(int irq, void *dev_id, struct pt_regs *regs) { disable_irq(irq); //udelay(1000); //fps_get_image(); fps200_device->flag = 1;}void fps_get_image(void) { int i = 0; int j = 0; FPS_INDEX = FPS_CTRLA; FPS_DATA = FPS_CTRLA_GETIMG; for(i=0; i<300; i++) { FPS_INDEX = FPS_CTRLB; while(!(FPS_CTRLB_RDY&FPS_DATA)){udelay(1);}; for(j=0; j<256; j++) { FPS_INDEX = FPS_CTRLB; while(!(FPS_CTRLB_RDY&FPS_DATA)){udelay(1);}; FPS_INDEX = FPS_CTRLA; *((unsigned char *)(fps200_device->data+i*256+j))=FPS_DATA; } }}int fps200_open(struct inode *inode, struct file *filp) { MOD_INC_USE_COUNT; return(0);}int fps200_release(struct inode *inode, struct file *filp) { MOD_DEC_USE_COUNT; return(0);}int fps200_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0; int ret = 0; unsigned char tmp; if(_IOC_TYPE(cmd) != FPS200_IOC_MAGIC) return -ENOTTY; if(_IOC_NR(cmd) > FPS200_IOC_MAXNR) return -ENOTTY; if (_IOC_DIR(cmd) & _IOC_READ) err = verify_area(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = verify_area(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return err; switch(cmd) { case FPS200_IOCSDTR: ret = __get_user(tmp, (unsigned char *)arg); if(tmp > 0x7f) tmp = 0x7f; FPS_INDEX = FPS_DTR; FPS_DATA = tmp; break; case FPS200_IOCSDCR: ret = __get_user(tmp, (unsigned char *)arg); if(tmp > 0x1f) tmp = 0x1f; FPS_INDEX = FPS_DCR; FPS_DATA = tmp; break; case FPS200_IOCSPGC: ret = __get_user(tmp, (unsigned char *)arg); if(tmp > 0x0f) tmp = 0x0f; FPS_INDEX = FPS_PGC; FPS_DATA = tmp; break; case FPS200_IOCGDTR: FPS_INDEX = FPS_DTR; tmp = FPS_DATA; ret = __put_user(tmp, (unsigned char *)arg); break; case FPS200_IOCGDCR: FPS_INDEX = FPS_DCR; tmp = FPS_DATA; ret = __put_user(tmp, (unsigned char *)arg); break; case FPS200_IOCGPGC: FPS_INDEX = FPS_PGC; tmp = FPS_DATA; ret = __put_user(tmp, (unsigned char *)arg); break; case FPS200_IOCEINT: enable_irq(FPS200_IRQ); break; case FPS200_IOCDINT: disable_irq(FPS200_IRQ); break; case FPS200_IOCFCAP: fps_get_image(); case FPS200_IOCGDATA: copy_to_user((void *)arg, fps200_device->data, FPS200_DATASIZE); ret = 0; fps200_device->flag = 0; break; case FPS200_IOCCLR: memset(fps200_device->data, 0, FPS200_DATASIZE); fps200_device->flag = 0; break; case FPS200_IOCCINT: if(((clps_readw(INTSR1))&0x40) == 0) { udelay(100); if(((clps_readw(INTSR1))&0x40) == 0) ret = __put_user(0x01, (unsigned char *)arg); else ret = __put_user(0x0, (unsigned char *)arg); } else ret = __put_user(0x0, (unsigned char *)arg); break; case FPS200_IOCCRDY: ret = __put_user(fps200_device->flag, (unsigned char *)arg); break; default: return -ENOTTY; } return ret;}static int __init fps200_init_module(void) { int result; char tmp; if((result = check_region (FPS200_VR,2))) { printk ("<1> can't get I/O port address \n"); return (result); } if (!request_region (FPS200_VR,2,"fps200")) return -EBUSY; SET_MODULE_OWNER(&fps200_fops);/* * Register your major, and accept a dynamic number. This is the * first thing to do, in order to avoid releasing other module's * fops in scull_cleanup_module()*/ result = register_chrdev(fps200_major, "fps200", &fps200_fops); if(result < 0) { printk("<1>fps200: can't get major %d\n",fps200_major); return result; } if(fps200_major == 0) fps200_major = result; /* dynamic *//* read chip id first, if not equal 0x20xx, print error */ FPS_INDEX = FPS_CIDH; tmp = FPS_DATA; if(tmp != 0x20) { printk("<1>wrong chip ID, insmod fail.\n"); return -EIO; } /* row auto inc. inner 12MHz vibrator. no low-power state */ FPS_INDEX = FPS_CTRLB; FPS_DATA = (FPS_CTRLB_AFDEN|FPS_CTRLB_AUTOINCEN|FPS_CTRLB_ENABLE); /* wait for 30us */ udelay(35); // make delay longer than 30us /* Interupt */ FPS_INDEX = FPS_ICR; FPS_DATA = (FPS_ICR_IE0|FPS_ICR_IT0_LEVEL); FPS_INDEX = FPS_THR; FPS_DATA = ( FPS_THR_THV | FPS_THR_THC ); /* DTR, DCR, PGC */ FPS_INDEX = FPS_DTR; FPS_DATA = 0x23; FPS_INDEX = FPS_DCR; FPS_DATA = 0x1; FPS_INDEX = FPS_PGC; FPS_DATA = 0; /* other initial */ FPS_INDEX = FPS_RAL; // raw address FPS_DATA = 0; FPS_INDEX = FPS_RAH; FPS_DATA = 0; FPS_INDEX = FPS_REL; FPS_DATA = 0; FPS_INDEX = FPS_REH; FPS_DATA = 0; FPS_INDEX = FPS_CAL; // column address FPS_DATA = 0; FPS_INDEX = FPS_CEL; FPS_DATA = 0; FPS_INDEX = FPS_CTRLC; FPS_DATA = 0; FPS_INDEX = FPS_CTRLA; FPS_DATA = 0; // clear FPS_CTRLA_AINSEL /* set irq */ result = request_irq(FPS200_IRQ, fps200_interrupt, SA_INTERRUPT, "fps200", NULL); if(result) { printk("<1>can't get assigned irq.\n"); return -EIO; } fps200_device = kmalloc(sizeof(FPS200_Dev), GFP_KERNEL); if(!fps200_device) { FPS_INDEX = FPS_CTRLB; FPS_DATA = 0; return -ENOMEM; } memset(fps200_device, 0, sizeof(FPS200_Dev)); fps200_device->data = kmalloc(FPS200_DATASIZE, GFP_KERNEL); if(!fps200_device) { FPS_INDEX = FPS_CTRLB; FPS_DATA = 0; kfree(fps200_device); return -ENOMEM; } memset(fps200_device->data, 0, FPS200_DATASIZE); return(0);}static void __exit fps200_cleanup_module(void) { kfree(fps200_device->data); kfree(fps200_device); FPS_INDEX = FPS_CTRLB; FPS_DATA = 0; release_region (FPS200_VR,2); free_irq(FPS200_IRQ, NULL); unregister_chrdev(fps200_major, "fps200");}module_init(fps200_init_module);module_exit(fps200_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -