#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <asm/io.h>
#include "ypublic.h"
MODULE_LICENSE("Dual BSD/GPL");
#define YMAJOR 100
#define YMINOR 1
#define YDEVICENAME "keydriver"
#define YBUFSIZE 10
#define UBRDIVn(baud) ()
//io
#define UARTBASE(n) (0x50000000+(0x00004000<<(n)))
#define UARTREGNUM 3
#define YUART0 UARTBASE(0)
#define YUART1 UARTBASE(1)
#define YUART2 UARTBASE(2)
#define YINFRARED_MODE SETB(6)
#define YNOPARITY 0
#define Y2STOPBIT SETB(2)
#define Y8BITS SETN(3,0)
typedef struct{
ulong ULCON;
ulong UCON;
ulong UFCON;
ulong UMCON;
ulong UTRSTAT;
ulong UERSTAT;
ulong UFSTAT;
ulong UMSTAT;
ulong UTXH;
ulong URXH;
ulong UBRDIV;
}YRUart;
typedef struct {
struct cdev dev;
uchar inbuf[YBUFSIZE];
uchar outbuf[YBUFSIZE];
}ycdev;
uint _pst;//记录按键的之前的状态
ycdev *_pdev;
static int _major=YMAJOR;
YRUart *_uart;
static struct timer_list _tm;
//io regs
#define GPBBASE 0x56000010
#define GPGBASE 0x56000060
ulong rgpbcon,rgpbdat,rgpbup;
ulong rgpgcon,rgpgdat,rgpgup;
void setIoConf(uint func,uint ionum,uint reg)
{
//set gpio function model
uint dat =ioread32(reg);
dat=setNB(func,dat,ionum*2,2);
iowrite32(dat,reg);
}
static void* initio(void)
{
if(request_mem_region(UARTBASE(0),sizeof(YRUart),"UART")==NULL)
return NULL;
_uart=(YRUart *)ioremap(UARTBASE(0),sizeof(YRUart));
return (void*)_uart;
}
void releaseio(void)
{
#if 1
if(_uart!=NULL){
iounmap((void*)UARTBASE(0));
release_mem_region(UARTBASE(0),sizeof(YRUart));
}
#endif
}
static irqreturn_t onIrq(int irq,void *dev_id)
{
//interrupt service function,disable current irq,and elimination of button's jitter
disable_irq_nosync((uint)dev_id);
_tm.expires=MS(20);
add_timer(&_tm);
return IRQ_HANDLED;
}
void initUart(void)
{
iowrite32(Y8BITS,&_uart->ULCON);
}
static void onTime(ulong arg)
{
#if 0
uint dat;
dat=ioread32(rgpbdat);
if(dat&SETB(10)){
iowrite32((~(SETB(7)|SETB(10)))&dat,rgpbdat);
}
else{
iowrite32(SETB(7)|SETB(10)|dat,rgpbdat);
}
_tm.expires=MS(2000);
add_timer(&_tm);
#else
setIoConf(Y2440_IO_IN,8,rgpgcon);
if((ioread32(rgpgdat)&SETB(8))==0){
//have a key down
//set another io output height
iowrite32(SETB(11)|ioread32(rgpgdat),rgpgdat);
//should be true
if(ioread32(rgpgdat)&SETB(8)){
printk(KERN_INFO "have key down\n");
_pst=1;
_tm.expires=MS(100);
add_timer(&_tm);
}
//have a expect
else printk(KERN_ERR "error 2\n");
//set another io output low
iowrite32(CLRB(11)&ioread32(rgpgdat),rgpgdat);
}
else{
//key up
if(_pst==1){
_pst=0;
printk(KERN_INFO "have key up\n");
}
else printk(KERN_INFO "error 3\n");
setIoConf(Y2440_IO_EINT,8,rgpgcon);
enable_irq(IRQ_EINT16);
}
#endif
}
int yopen(struct inode *pinode,struct file *pfile)
{
return 0;
}
int yrelease(struct inode *pinode,struct file *pfile)
{
return 0;
}
static struct file_operations _fops={
.open=yopen,
.release=yrelease,
};
int __init yinit(void)
{
dev_t devno=MKDEV(YMAJOR,YMINOR);
int rs;
uint tmp;
if(_major){
rs=register_chrdev_region(devno,1,YDEVICENAME);
}
else{
rs=alloc_chrdev_region(&devno,YMINOR,1,YDEVICENAME);
_major=MAJOR(devno);
}
if(rs<0)return rs;
_pdev=kmalloc(sizeof(ycdev),GFP_KERNEL);
if(!_pdev){
rs= -ENOMEM;
goto fail1;
}
cdev_init(&_pdev->dev,&_fops);
_pdev->dev.owner=THIS_MODULE;
rs=cdev_add(&_pdev->dev,MKDEV(_major,YMINOR),0);
if(rs){
rs=-EBUSY;
goto fail2;
}
#if 0
if(initio()==NULL)
printk(KERN_ERR"ioremap failed\n");
else printk(KERN_ERR"ioremap success\n");
#endif
//get GPIO register's base address
rgpbcon=(ulong)yioremap(GPBBASE,12,"gpbreg");
rgpgcon=(ulong)yioremap(GPGBASE,12,"gpgreg");
if(rgpbcon==0||rgpgcon==0)goto fail2;
else{
rgpbdat=rgpbcon+4;
rgpbup=rgpbcon+8;
//turn off two led
setIoConf(Y2440_IO_OUT,7,rgpbcon);
setIoConf(Y2440_IO_OUT,10,rgpbcon);
iowrite32(SETB(7)|SETB(10)|ioread32(rgpbup),rgpbup);
iowrite32(SETB(7)|SETB(10)|ioread32(rgpbdat),rgpbdat);
rgpgdat=rgpgcon+4;
rgpgup=rgpgcon+8;
//config number 8 io to interrupt model,11 io to output model
setIoConf(Y2440_IO_EINT,8,rgpgcon);
setIoConf(Y2440_IO_OUT,11,rgpgcon);
iowrite32(SETB(8)|SETB(11)|ioread32(rgpgup),rgpgup);
iowrite32(CLRB(11)&ioread32(rgpgdat),rgpgdat);
rs=request_irq(IRQ_EINT16,onIrq,IRQF_DISABLED,"IRQ16",(void *)(IRQ_EINT16));
if(rs)printk(KERN_INFO"irq failed");
}
//init io's pre-state and timer
_pst=0;
setup_timer(&_tm,onTime,IRQ_EINT16);
printk(KERN_INFO "driver ok\n");
return 0;
fail2:
printk(KERN_ERR "fail2\n");
kfree(_pdev);
fail1:
printk(KERN_ERR "fail1\n");
unregister_chrdev_region(devno,1);
return -EBUSY;
}
void __exit yexit(void)
{
del_timer(&_tm);
yiounmap(GPBBASE,12);
cdev_del(&_pdev->dev);
kfree(_pdev);
unregister_chrdev_region(MKDEV(_major,YMINOR),1);
}
MODULE_AUTHOR("MrY");
module_init(yinit);
module_exit(yexit);
|