📄 pc140_button.c
字号:
/**********************************************************************
**********************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/arch/regs-gpio.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/regs-mem.h>
#define DEVICE_NAME "io_button"
#define MAX_BUTTON_BUF 16
#define BUF_HEAD (buttondev.buf[buttondev.head])
#define BUF_TAIL (buttondev.buf[buttondev.tail])
#define INCBUF(x,mod) ((++(x)) & ((mod)-1))
#define CPLD_IO_CFG_BASE (0xE1400000)
#define CPLD_IO_DATA_BASE (0xE1000000)
#define ROW (0)
#define COL (0x200000)
#define REPEAT_DELAY HZ/10
static int flag = 0;
static unsigned int oldkey=0xffff;
static int pc140_button_major = 0;
typedef struct {
unsigned char buf[MAX_BUTTON_BUF];
unsigned int head,tail;
wait_queue_head_t wq;
} BUTTON_DEV;
static BUTTON_DEV buttondev;
struct timer_list button_timer;
static int buttonstatus[64]={0x7f7f,0x7fbf,0x7fdf,0x7fef,0x7ff7,0x7ffb,0x7ffd,0x7ffe,
0xbf7f,0xbfbf,0xbfdf,0xbfef,0xbff7,0xbffb,0xbffd,0xbffe,
0xdf7f,0xdfbf,0xdfdf,0xdfef,0xdff7,0xdffb,0xdffd,0xdffe,
0xef7f,0xefbf,0xefdf,0xefef,0xeff7,0xeffb,0xeffd,0xeffe,
0xf77f,0xf7bf,0xf7df,0xf7ef,0xf7f7,0xf7fb,0xf7fd,0xf7fe,
0xfb7f,0xfbbf,0xfbdf,0xfbef,0xfbf7,0xfbfb,0xfbfd,0xfbfe,
0xfd7f,0xfdbf,0xfddf,0xfdef,0xfdf7,0xfdfb,0xfdfd,0xfdfe,
0xfe7f,0xfebf,0xfedf,0xfeef,0xfef7,0xfefb,0xfefd,0xfefe,
}; //row:15--8 col:7--0
static void setdata(unsigned int pin,unsigned char status)
{
outb(0x00,(CPLD_IO_CFG_BASE + pin));
outb(status,(CPLD_IO_DATA_BASE + pin));
}
static unsigned char getdata(unsigned int pin)
{
unsigned char status;
outb(0xff,(CPLD_IO_CFG_BASE + pin));
status=inb((CPLD_IO_DATA_BASE + pin));
return status;
}
static void storekey(unsigned int key)
{
int i;
for(i=0;i<64;i++)
{
if(key==buttonstatus[i]){
BUF_HEAD=i;
buttondev.head=INCBUF(buttondev.head,MAX_BUTTON_BUF);
flag = 1;
wake_up_interruptible(&(buttondev.wq));
break;
}
}
}
static unsigned char buttonRead(void)
{
unsigned char button_ret;
button_ret=BUF_TAIL;
buttondev.tail=INCBUF(buttondev.tail,MAX_BUTTON_BUF);
return button_ret;
}
static void pc140_but_timer_callback(unsigned long data)
{
unsigned char colstatus,rowstatus;
unsigned int newkey;
setdata(ROW,0xff);
setdata(COL,0x00);
rowstatus = getdata(ROW);
setdata(ROW,0x00);
setdata(COL,0xff);
colstatus = getdata(COL);
newkey = colstatus|(rowstatus<<8);
printk("key:%d",newkey);
if(((oldkey^newkey)&newkey)!=0){
storekey(newkey);
}
oldkey=newkey;
mod_timer(&button_timer, jiffies + REPEAT_DELAY);
}
static ssize_t pc140_button_read(struct file *filp, char *buff, size_t count,loff_t *offset)
{
static unsigned char button_ret;
retry:
if(buttondev.head!=buttondev.tail)
{
button_ret=buttonRead();
copy_to_user(buff,(char *)&button_ret,sizeof(unsigned char));
return sizeof(unsigned char);
}
else
{
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(buttondev.wq,flag);
flag=0;
if(signal_pending(current))
{
printk("rturn -ERESTARTSYS\n");
return -ERESTARTSYS;
}
goto retry;
}
return sizeof(unsigned char);
}
static irqreturn_t pc140_button_open(struct inode * inode, struct file * filp)
{
buttondev.head=buttondev.tail=0;
init_timer(&button_timer);
button_timer.function = pc140_but_timer_callback;
button_timer.data = 0;
mod_timer(&button_timer, jiffies + REPEAT_DELAY);
return 0;
}
static int pc140_button_close(struct inode * inode, struct file * filp)
{
return 0;
}
static struct file_operations pc140_button_fops = {
.owner = THIS_MODULE,
.open = pc140_button_open,
.release=pc140_button_close,
.read = pc140_button_read,
};
static int __init pc140_button_init(void)
{
int ret;
unsigned int bswcon = inl((unsigned int)S3C2410_BWSCON);
//printk("S3C2410_BWSCON = 0x%08x\n",bswcon);
bswcon = (bswcon & 0xFFFCFFFF) | 0x00000000;
outl(bswcon,(unsigned int)S3C2410_BWSCON);
bswcon = inl((unsigned int)S3C2410_BWSCON);
//printk("S3C2410_BWSCON = 0x%08x\n",bswcon);
outb(0xF0, (0xE0000000 + 0x01E00000 + 1));
ret = register_chrdev(0,DEVICE_NAME,&pc140_button_fops);
if(ret < 0)
{
printk("button: can't get major number\n");
return ret;
}
pc140_button_major = ret;
#ifdef CONFIG_DEVFS_FS
ret = devfs_mk_cdev(MKDEV(pc140_button_major,0), S_IFCHR | S_IRUGO | S_IWUSR,DEVICE_NAME);
if(ret)
{
unregister_chrdev(pc140_button_major,DEVICE_NAME);
printk("pc140_button: can't make char device fo devfs\n");
return ret;
}
#endif
init_waitqueue_head(&(buttondev.wq));
printk(DEVICE_NAME"initialized\n");
setdata(ROW,0);
setdata(COL,0);
return 0;
}
static void __exit pc140_button_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_remove(DEVICE_NAME);
#endif
unregister_chrdev(pc140_button_major,DEVICE_NAME);
printk("button driver removed\n");
setdata(ROW,0xff);
setdata(COL,0xff);
}
module_init(pc140_button_init);
module_exit(pc140_button_exit);
MODULE_ALIAS(DEVICE_NAME);
MODULE_DESCRIPTION("pc140 button Driver");
MODULE_AUTHOR("feng");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -