最近参考网上资料,为自己的S3C44B0X开发板1X4按键写了驱动程序key1x4.c,以及简单的测试程序key_test.c:
/*********************************************************************/
/*key_test.c*/
#include
#include
#include
#include
#include
#include
int main()
{
int fd,count;
char buf[3];
printf("key1x4 test ....\n");
/*open key device */
fd=open("/dev/key1x4",O_RDWR);
printf("fd = %x\n", fd);
if(fd == -1)
{
printf("Could not open LED driver!\n");
return -1;
}
else printf("key opened\n");
while(1)
{
printf("key control led state :\n");
read(fd, buf, 3);
printf("------------------------------------\n");
printf ("LED1=%c ; LED2=%c ; LED1=%c\n",buf[0],buf[1],buf[2]);
printf("------------------------------------\n");
}
/*close led device */
close(fd);
printf("right end!!!!\n");
return 0;
}
运行该测试程序后,程序在超级中断里面打印
key1x4 test ....
fd =3
key opened
key control led state :
后,整个系统都死在那了,只能重启系统。
下面是驱动程序:
/*************************************************************************/
/*key1x4.c*/
/*
*******************************
key & led driver for my S3C44b0X board
*******************************
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define key_MAJOR 63
#define key_DEVNAME "key1x4"
#define BIT_EINT4567 (0x1<<21)
#define key_irq S3C44B0X_INTERRUPT_EINT4567
static u32 gnPCONC_backup;
static int state;
static int INT4567=0;
static char key_buf[3];
static int flag=0;
DECLARE_WAIT_QUEUE_HEAD(key_wait);
static struct timer_list key_timer;
struct led_local {
char *device;
} key[4]={{"key1"}, {"key2"}, {"key3"}, {"key4"}};
void led_manager(int arg, int nr)
{
if (arg == 0)
{
outb(inb(S3C44B0X_PDATC) | (1 << nr ), S3C44B0X_PDATC);
key_buf[nr]=1;
}
else if (arg == 1)
{
outb(inb(S3C44B0X_PDATC) & ~(1 << nr ), S3C44B0X_PDATC);
key_buf[nr]=0;
}
else
printk (KERN_INFO "Wrong arg\n");
}
static int key_open(struct inode *inode ,struct file *file)
{
printk (KERN_INFO "Hey! device opened\n");
return 0;
}
static int key_read(struct file *file ,char * buf,size_t count, loff_t * offset )
{
while (1)
{
//interruptible_sleep_on( &key_wait);
wait_event_interruptible(key_wait,flag);
count=3;
if(copy_to_user(buf,key_buf,count))
{
printk("error reading, copy_to_user\n");
return -EFAULT;
}
flag=0;
}
return count;
}
static int key_release(struct inode * inode ,struct file *file)
{
int i;
for(i=0;i<4;i++)
{
free_irq(key_irq, key.device);
}
printk (KERN_INFO "Hmmm! device closed\n");
return 0;
}
static struct file_operations key_ops={
open: key_open,
read: key_read,
release: key_release,
};
static void key_task(unsigned long irq)/*中断下半部*/
{
INT4567=inb(S3C44B0X_EXTINPND);
if (!INT4567)
return;
if (irq == key_irq)
{
switch (INT4567 )
{
case 1:
led_manager(++state%2, 1);
break;
case 2:
led_manager(++state%2, 2);
break;
default:
led_manager(++state%2, 3);
break;
}
}
else
printk (KERN_WARNING"%d irq wrong!", key_irq);
INT4567=0;
outb(0x0f,S3C44B0X_EXTINPND);
flag=1;
wake_up_interruptible(&key_wait);
enable_irq(irq);
return ;
}
static void key_interrupt(int irq, void *dev_id, struct pt_regs *regs)/*中断上半部*/
{
disable_irq(irq);
/*-------------------------*/
/* setup kernel timer */
/*-------------------------*/
init_timer(&key_timer);
key_timer.function = key_task;
key_timer.data = irq;
key_timer.expires = 10;
add_timer(&key_timer);
/*--------------------------*/
/* return from interrupt */
/*--------------------------*/
return;
}
/* device init*/
int key_init(void)
{
int result,i;
u32 temp;
u16 pdatc;
request_region(S3C44B0X_PCONC, 12, "key_DEVNAME");
result = register_chrdev(key_MAJOR,key_DEVNAME,&key_ops);
if (result<0)
{
printk (KERN_WARNING "led: can't get major number %d\n", key_MAJOR);
return result;
}
gnPCONC_backup = inl(S3C44B0X_PCONC);
printk("PCONC = %x\n",gnPCONC_backup);
temp = gnPCONC_backup & 0xFFFFFF03;
temp |= 0x57;
pdatc=(inl(S3C44B0X_PDATC) & 0x7);
outl(temp, S3C44B0X_PCONC);
outw(0x0,S3C44B0X_PUPC);
outw(pdatc, S3C44B0X_PDATC);
printk (KERN_INFO "key_ioctl driver done\n");
for(i=0;i<4;i++)
{
result=request_irq(key_irq, key_interrupt,SA_SHIRQ, key.device,key.device);
if (result)
{
printk(KERN_INFO "led: can't get assigned irq\n");
}
else
{ printk(KERN_INFO "led: get assigned irq \n");
}
}
// 将多功能端口G设置为中断功能
printk(KERN_INFO "S3C44B0X_PCONG=0x%x\n", inw(S3C44B0X_PCONG));
outw(0xff00, S3C44B0X_PCONG);
temp=inb(S3C44B0X_PUPG);
temp|=0xf0;
outb(temp,S3C44B0X_PUPG);
printk(KERN_INFO "S3C44B0X_PCONG=0x%x\n", inw(S3C44B0X_PCONG));
//设置外部中断控制寄存器EXINT ,外部中断请求寄存EXTINTPND
outl(0x22222222,S3C44B0X_EXTINT); //EXINT
outb(0x0f,S3C44B0X_EXTINPND); //EXTINTPND
//设置中断控制器INTCON
outb(0x5,S3C44B0X_INTCON); //INTCON
// outl(~(BIT_GLOBAL|BIT_EINT4567),S3C44B0X_INTMSK);//INTMSK开中断
init_waitqueue_head(&key_wait);
return 0;
}
int key_exit(void)
{
int result;
release_region(S3C44B0X_PCONC, 12);
if((result = unregister_chrdev(key_MAJOR,key_DEVNAME))<0)
{
printk("key_dev. unable to release major %d for read \n",key_MAJOR);
return result;
}
printk (KERN_INFO "key_ioctl cleaned up\n");
return 0;
}