/*
* 2009-04-12
* kernel version: 2.6.28.8
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("sch");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("s3c2410 buttons driver");
#define DEV_COUNT 1
#define DEV_NAME "s3c2410_buttons"
#define MAX_BUF_LEN 16
#define SIZE MAX_BUF_LEN
#define INCBUF(x) (++(x)%(MAX_BUF_LEN))
#define DECBUF(x) (--(x)%(MAX_BUF_LEN))
struct key_info {
unsigned int irq_no;
unsigned int gpio_port;
int key_no;
};
struct s3c2410_buttons
{
unsigned int flag;
unsigned char buf[MAX_BUF_LEN];
unsigned int head, tail;
wait_queue_head_t wq;
struct cdev buttons_cdev;
};
static int minor_num = 0;
static int major_num = 0;
static struct key_info key_info_tab[4] = {
{ IRQ_EINT0, S3C2410_GPF0, KEY_3 },
{ IRQ_EINT2, S3C2410_GPF2, KEY_2 },
{ IRQ_EINT11, S3C2410_GPG3, KEY_1 },
{ IRQ_EINT19, S3C2410_GPG11, KEY_ESC },
};
static struct s3c2410_buttons buttons_device;
static struct class *buttons_class;
static irqreturn_t buttons_irq_isr(int irq, void *dev_id); //中断服务程序
//static void do_task_irq(unsigned long dummy); //任务队列的执行函数
//DECLARE_TASKLET(task_irq, do_task_irq, 0); //中断服务下半部分的任务队列
int buttons_open(struct inode *inode, struct file *filp)
{
try_module_get(THIS_MODULE); //表示此驱动被使用,记数器增加
return 0;
}
int buttons_release(struct inode *inode,struct file *filp)
{
module_put(THIS_MODULE); //表示此驱动使用完毕,记数器减一
return 0;
}
ssize_t buttons_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
{
int err;
char tmp;
retry:
if (buttons_device.head != buttons_device.tail) {
tmp = buttons_device.buf[buttons_device.tail];
err = copy_to_user(buf, &tmp, 1);
//printk(KERN_DEBUG "buttons_device.buf=0x%x\n", buttons_device.buf[buttons_device.tail]);
if (err != 0) {
printk(KERN_ERR "buttons_read copy_to_user error!!\n");
return 0;
}
buttons_device.tail = INCBUF(buttons_device.tail);
return 1;
}
else {
if (filp->f_flags & O_NONBLOCK) {
return -EAGAIN;
}
wait_event_interruptible(buttons_device.wq, buttons_device.flag);
buttons_device.flag = 0;
if (signal_pending(current)) {
return -ERESTARTSYS;
}
goto retry;
}
return 1;
}
ssize_t buttons_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
int err;
memset(buttons_device.buf, 0, sizeof(char)*SIZE);
err = copy_from_user(buttons_device.buf, buf, count);
if (err != 0) {
printk(KERN_DEBUG "buttons_write copy_from_user error !\n");
return 0;
}
return count;
}
int buttons_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
return 1;
}
static irqreturn_t buttons_irq_isr(int irq, void *dev_id)
{
int i;
//tasklet_schedule(&task_irq); //任务调度中断下半部分服务程序
for (i=0; i<4; i++) {
if (key_info_tab[i].irq_no == irq) {
buttons_device.buf[buttons_device.head] = key_info_tab[i].key_no;
buttons_device.head = INCBUF(buttons_device.head);
buttons_device.flag = 1;
wake_up_interruptible(&(buttons_device.wq));
break;
}
}
return IRQ_HANDLED; //返回中断已经获得
}
/*
static void do_task_irq(unsigned long dummy)
{
buttons_device.buf[buttons_device.head] = 'T';
printk(KERN_DEBUG "buttons_device.head=%d\n", buttons_device.head);
printk(KERN_DEBUG "buttons_device.buf=0x%x\n", buttons_device.buf[buttons_device.head]);
buttons_device.head = INCBUF(buttons_device.head);
buttons_device.flag = 1;
wake_up_interruptible(&(buttons_device.wq));
}
*/
struct file_operations buttons_fops =
{
.owner = THIS_MODULE,
.read = buttons_read,
.write = buttons_write,
.open = buttons_open,
.release = buttons_release,
.ioctl = buttons_ioctl,
};
static int __init buttons_init(void)
{
dev_t dev_num = 0;
int res;
int err;
int i;
//分配设备号
if (major_num) { //手动分配设备号
dev_num = MKDEV(major_num, minor_num);
res = register_chrdev_region(dev_num, DEV_COUNT, DEV_NAME);
}
else { //动态分配设备号
res = alloc_chrdev_region(&dev_num, minor_num, DEV_COUNT, DEV_NAME);
major_num = MAJOR(dev_num);
}
if (res < 0) {
printk(KERN_ERR "alloc_chrdev_region error !\n");
return -1;
}
//申请中断
for (i=0; i<4; i++) {
set_irq_type(key_info_tab[i].irq_no, IRQT_FALLING); //下降沿触发
res = request_irq(key_info_tab[i].irq_no, &buttons_irq_isr, IRQF_SAMPLE_RANDOM, DEV_NAME, NULL);
if (res < 0) {
printk(KERN_ERR "request_irq error_num= %d !\n", res);
return -1;
}
}
//设备初始化
memset(&buttons_device, 0, sizeof(struct device));
memset(buttons_device.buf, 0, sizeof(unsigned char)*SIZE);
buttons_device.flag = 0;
init_waitqueue_head(&(buttons_device.wq)); //初始化队列
//注册设备
cdev_init(&(buttons_device.buttons_cdev), &buttons_fops);//cdev 结构嵌入一个自己的结构体需初始化
buttons_device.buttons_cdev.owner = THIS_MODULE;
buttons_device.buttons_cdev.ops = &buttons_fops;
err = cdev_add(&(buttons_device.buttons_cdev), dev_num, 1);
if (err != 0) {
printk(KERN_ERR "IRQ cdev_add error!!\n");
}
/* Populate sysfs entries */
buttons_class = class_create(THIS_MODULE, "irq_class");
/* Send uevents to udev, so it'll create /dev node */
device_create(buttons_class, NULL, dev_num, NULL, DEV_NAME);
printk(KERN_INFO "registered the %s success\n", DEV_NAME);
return 0;
}
static void __exit buttons_exit(void)
{
int i;
dev_t dev_num;
dev_num = MKDEV(major_num, minor_num);
cdev_del(&(buttons_device.buttons_cdev));
device_destroy(buttons_class, dev_num);
class_destroy(buttons_class);
for (i=0; i<4; i++)
free_irq(key_info_tab[i].irq_no, NULL);
unregister_chrdev_region(dev_num, 1);
printk(KERN_INFO "unregistered the %s\n", DEV_NAME);
return;
}
module_init(buttons_init);
module_exit(buttons_exit);
/* arm-linux-gcc test1.c -o test1 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int buttons_fd;
char key_value;
buttons_fd = open("/dev/s3c2410_buttons", 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;
}
阅读(1137) | 评论(0) | 转发(0) |