//驱动代码如下.主设备号设为232 ,适用GEC2410 十六键矩阵键盘
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define S3C2410_GPG11 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 11) // S3C2410_GPG11 undefined in regs-gpio.h
#define DEVICE_NAME "matrix_button"
#define BUTTON_MAJOR 232
unsigned int s3c2410_gpio_getpin(unsigned int pin)
{
unsigned long base = S3C2410_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
return __raw_readl(base + 0x04) & (1<< offs);
}
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
unsigned long base = S3C2410_GPIO_BASE(pin);
unsigned long mask;
unsigned long con;
unsigned long flags;
if(pin
mask =3<< (S3C2410_GPIO_OFFSET(pin)*2);
local_irq_save(flags);
con = __raw_readl(base + 0x00);
con &= ~mask;
con |= function;
__raw_writel(con, base + 0x00);
local_irq_restore(flags);
}
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
unsigned long base = S3C2410_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);
dat &= ~(1 << offs);
dat |= to << offs;
__raw_writel(dat, base + 0x04);
local_irq_restore(flags);
}
#define EXTINT_OFF (IRQ_EINT4 - 4)
// clear SRCPND&INTPND
void s3c_irq_ack(unsigned int irqno)
{
unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
return;
}
void s3c_irqext_ack(unsigned int irqno)
{
unsigned long req;
unsigned long bit;
bit = 1UL << (irqno - EXTINT_OFF);
__raw_writel(bit, S3C2410_EINTPEND);
req = __raw_readl(S3C2410_EINTPEND);
if (irqno <= IRQ_EINT7 )
{
if ((req & 0xf0) == 0)
s3c_irq_ack(IRQ_EINT4t7);
}
else
{
if ((req >> 8) == 0)
s3c_irq_ack(IRQ_EINT8t23);
}
return;
}
// set external interrupt mode, trigger type and gpio registers
int realarm_interrupt_init(unsigned int irq, unsigned int type)
{
unsigned long gpcon_reg;
unsigned long gpcon_offset;
unsigned long extint_reg;
unsigned long extint_offset;
unsigned long newvalue = 0;
unsigned long value;
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C2410_EXTINT0;
gpcon_offset = (irq - IRQ_EINT0) * 2;
extint_offset = (irq - IRQ_EINT0) * 4;
}
else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
{
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C2410_EXTINT0;
gpcon_offset = (irq - EXTINT_OFF) * 2;
extint_offset = (irq - EXTINT_OFF) * 4;
}
else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
{
gpcon_reg = S3C2410_GPGCON;
extint_reg = S3C2410_EXTINT1;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT8) * 4;
}
else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
{
gpcon_reg = S3C2410_GPGCON;
extint_reg = S3C2410_EXTINT2;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT16) * 4;
} else
{
return -1;
}
/* Set the GPIO to external interrupt mode */
value = __raw_readl(gpcon_reg);
value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
__raw_writel(value, gpcon_reg);
/* Set the external interrupt to pointed trigger type */
switch (type)
{
case IRQT_NOEDGE:
printk(KERN_WARNING "No edge setting!\n");
break;
case IRQT_RISING:
newvalue = S3C2410_EXTINT_RISEEDGE;
break;
case IRQT_FALLING:
newvalue = S3C2410_EXTINT_FALLEDGE;
break;
case IRQT_BOTHEDGE:
newvalue = S3C2410_EXTINT_BOTHEDGE;
break;
case IRQT_LOW:
newvalue = S3C2410_EXTINT_LOWLEV;
break;
case IRQT_HIGH:
newvalue = S3C2410_EXTINT_HILEV;
break;
default:
printk(KERN_ERR "No such irq type %d", type);
return -1;
}
value = __raw_readl(extint_reg);
value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
__raw_writel(value, extint_reg);
return 0;
}
static struct key_info {
int irq_no;
unsigned int gpio_port;
int function_inp;
int function_eintn;
}key_info_tab[4]={
{ IRQ_EINT0, S3C2410_GPF0,S3C2410_GPF0_INP,S3C2410_GPF0_EINT0},
{ IRQ_EINT2, S3C2410_GPF2,S3C2410_GPF2_INP,S3C2410_GPF2_EINT2},
{ IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG3_INP,S3C2410_GPG3_EINT11 },
{ IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG11_INP,S3C2410_GPG11_EINT19}};
struct matrix_button
{
int key_value;
int ready;
int open_count;
wait_queue_head_t buttons_wait;
struct cdev cdev;
struct semaphore sem;
};
static struct matrix_button* matrix_button_dev;
static struct output_pin
{
unsigned int gpio_pin;
int function_outp;
}output_pin_tab[4]={
{S3C2410_GPE11,S3C2410_GPE11_OUTP},
{S3C2410_GPG6,S3C2410_GPG6_OUTP},
{S3C2410_GPE13,S3C2410_GPE13_OUTP},
{S3C2410_GPG2,S3C2410_GPG2_OUTP}
};
static int key_scan(void)
{
int i,j,k,ret=0;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(i==j)s3c2410_gpio_setpin(output_pin_tab[j].gpio_pin,0);
else s3c2410_gpio_setpin(output_pin_tab[j].gpio_pin,1);
}
for(k=0;k<4;k++)
{
if(s3c2410_gpio_getpin(key_info_tab[k].gpio_port)==0)
{
ret=i*10+k+1;
return ret;
}
}
}
return ret;
}
static void port_init(void)
{
int i;
for(i=0;i<4;i++)
{
s3c2410_gpio_cfgpin(output_pin_tab[i].gpio_pin,output_pin_tab[i].function_outp);
s3c2410_gpio_setpin(output_pin_tab[i].gpio_pin,0);
s3c2410_gpio_cfgpin(key_info_tab[i].gpio_port,key_info_tab[i].function_eintn);
realarm_interrupt_init(key_info_tab[i].irq_no,IRQT_FALLING);
}
}
static irqreturn_t matrix_button_irq(int irq, void *dev_id, struct pt_regs *reg)
{
struct matrix_button *dev=dev_id;
struct key_info *k;
int i;
int found = 0;
int flags;
down(&dev->sem);
for (i = 0; i < sizeof(key_info_tab)/ sizeof(key_info_tab[0]); i++)
{
k = key_info_tab + i;
if (k->irq_no == irq)
{
found = 1;
break;
}
}
if (!found)
{
printk(KERN_NOTICE "bad irq %d in button\n", irq);
return IRQ_HANDLED;
}
save_flags(flags); // save CPSR
cli(); // Close interrupt
if(k->irq_no
else
s3c_irqext_ack(k->irq_no);
for(i=0;i
k=key_info_tab+i;
s3c2410_gpio_cfgpin(k->gpio_port,k->function_inp);
}
mdelay(100);
dev->key_value=key_scan();
if(dev->key_value==0)
{
up(&dev->sem);
port_init();
restore_flags(flags);
return IRQ_HANDLED;
}
dev->ready=1;
up(&dev->sem);
wake_up(&dev->buttons_wait);
port_init();
restore_flags(flags);
return IRQ_HANDLED;
}
static int request_irqs(struct matrix_button *dev)
{
struct key_info *k;
int i;
for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab[0]); i++)
{
k = key_info_tab + i;
if (request_irq(k->irq_no, &matrix_button_irq, SA_INTERRUPT, DEVICE_NAME, dev)) return -1;
}
return 0;
}
static void free_irqs(struct matrix_button *dev)
{
struct key_info *k;
int i;
for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab[0]); i++)
{
k = key_info_tab + i;
free_irq(k->irq_no,dev);
}
}
static int matrix_button_read(struct file * filp, char __user * buffer, size_t count, loff_t *f_pos)
{
struct matrix_button *dev=filp->private_data;
down(&dev->sem);
if(!dev->ready)
return -EAGAIN;
copy_to_user(buffer, &dev->key_value, sizeof(int));
dev->ready = 0;
up(&dev->sem);
return count;
}
static unsigned int matrix_button_poll( struct file *filp, struct poll_table_struct *wait)
{
struct matrix_button *dev=filp->private_data;
poll_wait(filp, &dev->buttons_wait, wait);
if (dev->ready)
return POLLIN;
else
return 0;
}
static int matrix_button_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
default:
return -EINVAL;
}
}
static int matrix_button_open(struct inode *inode,struct file *filp)
{
int ret;
struct matrix_button *dev;
dev=container_of(inode->i_cdev,struct matrix_button,cdev);
down(&dev->sem);
filp->private_data=dev;
if(dev->open_count==0)
{
ret = request_irqs(dev);
if (ret)
{
cdev_del(&matrix_button_dev->cdev);
unregister_chrdev_region(MKDEV(BUTTON_MAJOR,0),1);
kfree(matrix_button_dev);
printk(DEVICE_NAME " can't request irqs\n");
return ret;
}
}
dev->open_count++;
up(&dev->sem);
return 0;
}
static int matrix_button_release(struct inode *inode,struct file *filp)
{
struct matrix_button *dev=filp->private_data;
down(&dev->sem);
if((dev->open_count--)==1)
free_irqs(dev);
up(&dev->sem);
return 0;
}
static struct file_operations matrix_button_fops = {
owner: THIS_MODULE,
ioctl: matrix_button_ioctl,
poll: matrix_button_poll,
read: matrix_button_read,
open: matrix_button_open,
release:matrix_button_release
};
static int __init matrix_button_init(void)
{
int ret;
dev_t dev=MKDEV(BUTTON_MAJOR,0);
ret=register_chrdev_region(dev,1,"matrix_button");
if(ret<0)
return ret;
matrix_button_dev=kmalloc(sizeof(struct matrix_button),GFP_KERNEL);
memset(matrix_button_dev,0,sizeof(struct matrix_button));
matrix_button_dev->ready=0;
matrix_button_dev->key_value=0;
matrix_button_dev->open_count=0;
init_waitqueue_head(&matrix_button_dev->buttons_wait);
init_MUTEX(&matrix_button_dev->sem);
cdev_init(&matrix_button_dev->cdev,&matrix_button_fops);
matrix_button_dev->cdev.owner=THIS_MODULE;
matrix_button_dev->cdev.ops=&matrix_button_fops;
port_init();
ret=cdev_add(&matrix_button_dev->cdev,dev,1);
if(ret)
printk(KERN_NOTICE "Error %d",ret);
return 0;
}
static void __exit matrix_button_exit(void)
{
cdev_del(&matrix_button_dev->cdev);
unregister_chrdev_region(MKDEV(BUTTON_MAJOR,0),1);
kfree(matrix_button_dev);
free_irqs(matrix_button_dev);
}
module_init(matrix_button_init);
module_exit(matrix_button_exit);
MODULE_LICENSE("GPL");
//以下为测试代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int buttons_fd,i;
int key_value;
buttons_fd = open("/dev/matrix_button", 0);
if (buttons_fd < 0) {
perror("open device buttons");
exit(1);
}
for (;;)
{
fd_set rds;
int ret;
FD_ZERO(&rds);
FD_SET(buttons_fd, &rds);
ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL);
if (ret < 0)
{
perror("select");
exit(1);
}
if (ret == 0)
{
printf("Timeout.\n");
}
else if (FD_ISSET(buttons_fd, &rds))
{
int ret = read(buttons_fd, &key_value, sizeof key_value);
if (ret != sizeof key_value)
{
if (errno != EAGAIN)
perror("read buttons\n");
continue;
}
else
{
printf("buttons_value: %d\n", key_value);
}
}
}
close(buttons_fd);
return 0;
}
上一篇:S3C2410 LED驱动程序
下一篇:s3c2410的Bootloader(Vivi)简介
推荐阅读最新更新时间:2024-03-16 15:22
设计资源 培训 开发板 精华推荐
- 直播已结束|TI C2000 Piccolo 单芯片——实现双轴伺服电机和马达控制
- 【EEWORLD第三十届】2011年09月社区明星人物揭晓!
- 免费样片体验:EEworld邀你一起玩转TI 运放新秀-OPA388
- 免费测评|ESP32-S2-Kaluga-1新型多媒体开发板,灵活拆装,满足多种需求
- elexcon 2023 报名推广
- ADI有奖下载活动之15 ADI公司智能可穿戴医疗保健设备解决方案
- 预约有礼:以光代电,硅光芯片了解一下~ 走进工程师网络学堂直播,赢好礼
- 观看福禄克计量校准视频 参与调查问卷好礼送!
- ADI 生命体征监测技术:对人体实施状态监控,答题有好礼
- 再见2019,你好2020!写下你的年终总结和新年计划