Chinaunix首页 | 论坛 | 博客
  • 博客访问: 492207
  • 博文数量: 130
  • 博客积分: 2111
  • 博客等级: 大尉
  • 技术积分: 1373
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-28 09:55
个人简介

IT民工

文章分类

全部博文(130)

文章存档

2021年(1)

2019年(1)

2017年(3)

2014年(1)

2013年(3)

2012年(2)

2011年(3)

2010年(2)

2009年(114)

分类: LINUX

2009-08-28 12:53:58

linux 2.6下的第一个驱动(s3c2440)[按键驱动]
2007-09-02 12:01:04

/*======================================

定时器程序还有一点点问题,按键的时候不能屏蔽中断,

一个键按下去会不停的产生中断

=======================================*/

 

#ifndef MODULE
#define MODULE
#endif

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME   "key"
#define KEY_NUMBER     123

#define GPF_CON      0x56000050
#define GPF_DATA     0x56000054

#define GPB_CON      0x56000010
#define GPB_DATA     0x56000014

#define GPG_CON      0x56000060
#define GPG_DATA     0x56000064 

#define SRCPND       0x4a000000

#define no_key_enter      -1
#define s1  1
#define s2  2
#define s3  3
#define s4 4
#define s5 5
#define s6 6
#define s7 7
#define s8 8

 

#define GPF_0_H  (1<<0)
#define GPF_2_H  (1<<2)
#define GPG_3_H  (1<<3)
#define GPG_11_H (1<<11)
 
#define GPB_6_H   (1<<6)
#define GPB_7_H   (1<<7)

#define INTERRUPT_BASE 0x4a000000
#define EINT0         (1<<0)
#define EINT2   (1<<2) 
#define EINT8_23 (1<<5)         //   EINT11,EINT19

#define EINT11  (1<<11)
#define EINT19      (1<<19)

#define INTMOD  0x04
#define INTMASK_CON     0x560000a4

MODULE_LICENSE("GPL");

static unsigned int ver_GPB_6_7_addr;    //shu xian
static unsigned int hor_GPG_3_11_addr;   //heng xian
static unsigned int hor_GPF_0_2_addr;
static unsigned int ver_GPB_6_7_data;
static unsigned int hor_GPF_0_2_data;
static unsigned int hor_GPG_3_11_data;
 void *srcpnd;
static unsigned int interrupt_addr;
static unsigned char keyval;
int read=0;
static unsigned int GPB_6_7_LOW_PORT=0x73f;
static unsigned int EINTMASK_ADDR;
wait_queue_head_t buttons_wait;

static void set_interrupt_port();
static void cleanpend();

static void get_system_port_addr(void)
{
 ver_GPB_6_7_addr=(unsigned int)ioremap(GPB_CON,4);
 ver_GPB_6_7_data=(unsigned int)ioremap(GPB_DATA,4);

 hor_GPF_0_2_addr=(unsigned int)ioremap(GPF_CON,4);
 hor_GPF_0_2_data=(unsigned int)ioremap(GPF_DATA,4);

 hor_GPG_3_11_addr=(unsigned int)ioremap(GPG_CON,4);
 hor_GPG_3_11_data=(unsigned int)ioremap(GPG_DATA,4);  

 interrupt_addr=(unsigned int)ioremap(INTERRUPT_BASE,1024);     //0x4a000000
 EINTMASK_ADDR=(unsigned int )ioremap(INTMASK_CON,1024);
 srcpnd=EINTMASK_ADDR;// srcpnd=EINTMASK_ADDR;

}

static void enable_interrupt()
{
 unsigned int interrupt_statu; 
 interrupt_statu=readl(interrupt_addr);
 interrupt_statu=interrupt_statu&0x021;
 writel(interrupt_statu,interrupt_addr); 
 interrupt_statu=readl(interrupt_addr+INTMOD);      //INTMOD 0x4a000000+ 0x04
 interrupt_statu=interrupt_statu&(~(EINT0 | EINT2 | EINT8_23));  //set bit to 0 ,enable IRQ mode
 writel(interrupt_statu,interrupt_addr+INTMOD);    
// printk("<1> 01\r\n"); 
 interrupt_statu=readl(EINTMASK_ADDR);             //0x560000a4
 interrupt_statu=interrupt_statu&(~(EINT0 | EINT2 | EINT11 | EINT19));  //set bit to 0 ,enable interrupt,to 1,is masked
 writel(interrupt_statu,EINTMASK_ADDR);
//  printk("<1> 02\r\n"); 
// interrupt_statu=readl(EINTMASK_ADDR);
// interrupt_statu=interrupt_statu&(~(EINT11 | EINT19));
// writel(interrupt_statu,EINTMASK_ADDR);

 set_interrupt_port();
}
#if 0
static void unable_interrupt()
{
 unsigned int interrupt_statu; 
 unsigned int GPF_IN_DATA,GPG_IN_DATA;
 unsigned int hor_GPG_3_11_statu,hor_GPF_0_2_statu;
 interrupt_statu=readl(interrupt_addr);
 interrupt_statu=interrupt_statu&0x021;
 writel(interrupt_statu,interrupt_addr); 
 interrupt_statu=readl(interrupt_addr+INTMOD);      //INTMOD 0x4a000000+ 0x04
 interrupt_statu=interrupt_statu&(~(EINT0 | EINT2 | EINT8_23));  //set bit to 0 ,enable IRQ mode
 writel(interrupt_statu,interrupt_addr+INTMOD);    
// printk("<1> 01\r\n"); 
 interrupt_statu=readl(EINTMASK_ADDR);             //0x560000a4
 interrupt_statu=interrupt_statu&((EINT0 | EINT2 | EINT11 | EINT19));  //set bit to 0 ,enable interrupt,to 1,is masked
 writel(interrupt_statu,EINTMASK_ADDR);

 hor_GPF_0_2_statu=readl(hor_GPF_0_2_addr);
 GPF_IN_DATA=(hor_GPF_0_2_statu&0xffcc)|0x0011; //set interrput port,enable GPF0,GPF2,interrupt module
 printk("<1>GPF_IN_DATA=%x\r\n",GPF_IN_DATA);
 writel(GPF_IN_DATA,hor_GPF_0_2_addr);
//  printk("<1> 04\r\n"); 
 hor_GPG_3_11_statu=readl(hor_GPG_3_11_addr);
 GPG_IN_DATA=(hor_GPG_3_11_statu &0xff3fff3f)|0x00400040;   //set interrput port,enable GPG3,GPG11,interrupt module
 printk("<1>GPG_IN_DATA=%x\r\n",GPG_IN_DATA);
 writel(GPG_IN_DATA,hor_GPG_3_11_addr);
//  printk("<1> 02\r\n"); 
// interrupt_statu=readl(EINTMASK_ADDR);
// interrupt_statu=interrupt_statu&(~(EINT11 | EINT19));
// writel(interrupt_statu,EINTMASK_ADDR);

// set_interrupt_port();
}

#endif

static void set_interrupt_port()
{
 unsigned int ver_GPB_6_7_statu;
 unsigned int hor_GPF_0_2_statu;
 unsigned int hor_GPG_3_11_statu;
 unsigned int GPB_IN_DATA;
 unsigned int GPF_IN_DATA;
 unsigned int GPG_IN_DATA;
 ver_GPB_6_7_statu=readl(ver_GPB_6_7_addr);
        GPB_IN_DATA=(ver_GPB_6_7_statu&0x3f0fff)|0x005000; //set output port
 printk("<1>GPB_IN_DATA=%x\r\n",GPB_IN_DATA);
 writel(GPB_IN_DATA,ver_GPB_6_7_addr);
//  printk("<1> 03\r\n"); 
 hor_GPF_0_2_statu=readl(hor_GPF_0_2_addr);
 GPF_IN_DATA=(hor_GPF_0_2_statu&0xffcc)|0x00ee; //set interrput port,enable GPF0,GPF2,interrupt module
 printk("<1>GPF_IN_DATA=%x\r\n",GPF_IN_DATA);
 writel(GPF_IN_DATA,hor_GPF_0_2_addr);
//  printk("<1> 04\r\n"); 
 hor_GPG_3_11_statu=readl(hor_GPG_3_11_addr);
 GPG_IN_DATA=(hor_GPG_3_11_statu &0xff3fff3f)|0x00b000b0;   //set interrput port,enable GPG3,GPG11,interrupt module
 printk("<1>GPG_IN_DATA=%x\r\n",GPG_IN_DATA);
 writel(GPG_IN_DATA,hor_GPG_3_11_addr);
// printk("<1> 05\r\n"); 
}

 

static void set_output_module()
{
 unsigned int hor_GPF_0_2_statu;
 unsigned int GPF_IN_DATA;
 unsigned int hor_GPG_3_11_statu;
 unsigned int GPG_IN_DATA;
 hor_GPF_0_2_statu=readl(hor_GPF_0_2_addr);
 GPF_IN_DATA=(hor_GPF_0_2_statu&0xffcc)|0x0011; //set output mode
// GPF_IN_DATA=(hor_GPF_0_2_statu&0xffcc);  //set input mode 
// printk("<1>GPF_IN_DTAT=%x\r\n",GPF_IN_DATA);
 writel(GPF_IN_DATA,hor_GPF_0_2_addr);
// printk("<1> 06\r\n");
 hor_GPG_3_11_statu=readl(hor_GPG_3_11_addr);
 GPG_IN_DATA=(hor_GPG_3_11_statu & 0xff3fff3f)|0x0700070;   //set output mode
// GPG_IN_DATA=(hor_GPG_3_11_statu & 0xff3fff3f);     //set input mode
// printk("<1>GPG_IN_DATA=%x\r\n",GPG_IN_DATA);
 writel(GPG_IN_DATA,hor_GPG_3_11_addr);
// printk("<1> 07\r\n");
}

 

void mytimer_ok(unsigned long expires)
{
 cleanpend();

 printk("<1>mytimer_ok!\r\n");
//   printk("<1> 08");
}

static void irq_pend()
{
 unsigned int port_statu;
 port_statu=readl(srcpnd);
 port_statu=port_statu | (EINT0 | EINT2 | EINT8_23);
 writel(port_statu,srcpnd);

}

#define GPG_3_11_H  ((1<<3) | (1<<11))
#define GPF_0_2_H   ((1<<0) | (1<<2))
#define GPB_6_7_H   ((1<<6) | (1<<7))
struct timer_list mytimer;
static unsigned int get_key_value()
{
 
 unsigned int port_statu;
// unsigned int key_value=-1;
 unsigned int GPF;
 unsigned int GPG,GPB;
 unsigned int GPG_STATU,GPF_STATU;
 unsigned int GPG_STATU1,GPF_STATU1;
 unsigned int GPF_STATU2,GPF_STATU3;
 unsigned int GPG_STATU2,GPG_STATU3;
 unsigned int GPB_IN_DATA,GPB_STATU; 
 unsigned int time,value=-1;
 irq_pend(); 
 init_timer(&mytimer);
 mytimer.expires=500000;
 mytimer.function=mytimer_ok;
 add_timer(&mytimer);
 printk("<1>add_timer\r\n");

// unsigned int statu1,statu2,statu3;
// set_output_module();
#if 0
 port_statu=readl(ver_GPB_6_7_data);
 port_statu=(port_statu & (GPB_6_7_LOW_PORT));
 writel(port_statu,ver_GPB_6_7_data);
#endif
 port_statu=readl(ver_GPB_6_7_data);
// printk("<1>GPB_6_7_LOW=%x\r\n",port_statu&GPB_6_7_LOW_PORT);
 
 time=0;
 while(time<4)
 {
#if 1 
  if(time==0)
   value=0x0; 
  if(time==1)
   value=(1<<6);
  if(time==2)
   value=(1<<7);
  if(time==3)
   value=0x0; 
 
  port_statu=readl(ver_GPB_6_7_data);
  port_statu=((port_statu&GPB_6_7_LOW_PORT)|value);
  writel(port_statu,ver_GPB_6_7_data);
#endif
  GPF=readl(hor_GPF_0_2_data);
  GPG=readl(hor_GPG_3_11_data);
  GPB=readl(ver_GPB_6_7_data);

  GPG_STATU=GPG & GPG_3_11_H;
  GPF_STATU=GPF & GPF_0_2_H;
  GPB_STATU=GPB & GPB_6_7_H;
 
 // printk("<1>GPG_STATU=%x,GPF_STATU=%x,GPB_STATU=%x\r\n",GPG_STATU,GPF_STATU,GPB_STATU);
  if(time==0)
  {
   GPG_STATU1=GPG_STATU;
   GPF_STATU1=GPF_STATU; 
  }
  if(time==1)
  {
   GPG_STATU2=GPG_STATU;
   GPF_STATU2=GPF_STATU;
  }
  if(time==2)
  {
   GPG_STATU3=GPG_STATU;
   GPF_STATU3=GPF_STATU;
  }
  time++;  
 } 
 if((GPF_STATU1==0x04)&&(GPF_STATU3==0x04))
  value=1;
 if((GPF_STATU1==0x04)&&(GPF_STATU2==0x04))
  value=2;
 if((GPF_STATU1==0x01)&&(GPF_STATU3==0x01))
  value=3;
 if((GPF_STATU1==0x01)&&(GPF_STATU2==0x01)) 
  value=4;
 if((GPG_STATU1==0x800)&&(GPG_STATU3==0x800))
  value=5;
 if((GPG_STATU1==0x800)&&(GPG_STATU2==0x800))
  value=6;
 if((GPG_STATU1==0x08)&&(GPG_STATU3==0x08)) 
  value=7;
 if((GPG_STATU1==0x08)&&(GPG_STATU2==0x08))
  value=8;
 
 del_timer(&mytimer);
 // cleanpend();
 
 return value;
 
 

#if 0 
 if(GPG_STATU==0X800)
  return 56;
 if(GPG_STATU==0X08)
  return 78;
 if(GPF_STATU==0x04)
  return 12;
 if(GPF_STATU==0X01);
  return 34;

#endif

}

#if 0
static unsigned int scan_key()
{
 
unsigned int key_value=-1;
// unsigned int time=0;
 unsigned int port_statu;
 

//  key_value=get_key_value();
 printk("<1>key_value=%d\r\n",key_value);
 if(key_value!=no_key_enter)
 {
  printk("the enter key is s%d\r\n",key_value);
 }
 port_statu=readl(ver_GPB_6_7_data);
 port_statu=port_statu&GPB_6_7_LOW_PORT;
 writel(port_statu,ver_GPB_6_7_data);
 return key_value;

}
#endif

static void cleanpend()
{
 unsigned int port_statu;
 port_statu=readl(srcpnd);
 port_statu=port_statu&(~(EINT0 | EINT2 | EINT8_23));
 writel(port_statu,srcpnd);
//   printk("<1> 08");
}

irqreturn_t keys_irq(int irq,void *dev_id,struct pt_regs *reg)
{
 int flags;
 keyval=(unsigned char )irq;
 cleanpend();
 read=1;
 save_flags(flags);
 cli();
// printk("<1>press key!\r\n");
 printk("<1>key%d is enter!\r\n", get_key_value());
 restore_flags(flags);
 wake_up_interruptible(&buttons_wait); 
 return 0;
}

 

static int request_irqs(void)
{
 int ret=0;
 unsigned int port_statu;
 unsigned int GPB_IN_DATA;

// printk("<1>request_irqs\r\n");
// enable_interrupt();
// set_interrupt_port();
// set the GPB6,GPB7 in low
// printk("<1>here\r\n");
// if(scan_key()>0) 
// if(1)
// {
// enable_interrupt();

 set_output_module();   //set input mode ,changed!

 port_statu=readl(ver_GPB_6_7_addr);
        GPB_IN_DATA=((port_statu & 0x3f0fff) | 0x05000); //set GPB6,GPB7 in  output mode
 printk("<1>GPB_IN_DATA=%x\r\n",GPB_IN_DATA);
 writel(GPB_IN_DATA,ver_GPB_6_7_addr);
 


 port_statu=readl(ver_GPB_6_7_data);
 port_statu=port_statu&GPB_6_7_LOW_PORT;
 writel(port_statu,ver_GPB_6_7_data);

  enable_interrupt();

  ret+=request_irq(IRQ_EINT0,keys_irq,SA_INTERRUPT,DEVICE_NAME,keys_irq);
  ret+=request_irq(IRQ_EINT2,keys_irq,SA_INTERRUPT,DEVICE_NAME,keys_irq);
  ret+=request_irq(IRQ_EINT11,keys_irq,SA_INTERRUPT,DEVICE_NAME,keys_irq);
  ret+=request_irq(IRQ_EINT19,keys_irq,SA_INTERRUPT,DEVICE_NAME,keys_irq);
 // printk("<1>IRQ_EINT19_RET=%x\r\n",ret);

  set_irq_type(IRQ_EINT0,IRQT_BOTHEDGE);
  set_irq_type(IRQ_EINT2,IRQT_BOTHEDGE);
  set_irq_type(IRQ_EINT11,IRQT_BOTHEDGE);
  set_irq_type(IRQ_EINT19,IRQT_BOTHEDGE);
// }
 if(ret)
 {
  printk("<1>request irq failed! ret=%x\r\n",ret);
 }
// printk("<1>scan_key()=%d\r\n",scan_key());
 return 0;
}

static void free_irqs(void)
{
 free_irq(IRQ_EINT0,keys_irq);
 free_irq(IRQ_EINT2,keys_irq);
 free_irq(IRQ_EINT11,keys_irq);
 free_irq(IRQ_EINT19,keys_irq);
}

static int key_read(struct file *file,char *buf,size_t count,loff_t *ppos)
{
 read=0;
 printk("<1> read start!\r\n");
 copy_to_user(buf,(char *)&keyval,1);
 return 0;
}

static unsigned int key_select(struct file* file,struct poll_table_struct *wait){
 if(read)
  return 1;
 interruptible_sleep_on(&buttons_wait);
 return 0;
}

static int key_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
 switch(cmd)
 {
  default:
   return -EINVAL;
 }
}

static struct file_operations key_fops=
{
 .owner=THIS_MODULE,
 .ioctl=key_ioctl,
 .poll=key_select,
 .read=key_read,
};

static struct miscdevice key_dev=
{
 KEY_NUMBER,
 "key",
 &key_fops,
};

static int __init key_init(void)
{
 int ret;
 misc_register(&key_dev);
 get_system_port_addr();
 init_waitqueue_head(&buttons_wait);
 ret=request_irqs();
 printk("<1>key_init  ret=%x\r\n",ret);
 return 0;
}

static void __exit key_exit(void)
{
 free_irqs();
 misc_deregister(&key_dev);
 printk("<1> clean key module\r\n");
}

module_init(key_init);
module_exit(key_exit);

阅读(1316) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:qtopia pda2.2.0编译和运行一个例子

给主人留下些什么吧!~~