目标:编写一个按键驱动程序,如果有按键按下就打印一些信息。
环境:TQ2440 Ubuntu12.04,linux-2.6.25
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/miscdevice.h>
- #include <linux/delay.h>
- #include <linux/mm.h>
- #include <linux/types.h>
- #include <linux/cdev.h>
- #include <asm/irq.h>
- #include <asm/arch/regs-gpio.h>
- #include <asm/arch/map.h>
- #include <asm/arch/regs-irq.h>
- #include <asm/io.h>
- #include <asm/hardware.h>
- #include <asm/uaccess.h>
- #include <asm/system.h>
- volatile unsigned long *gpfcon;
- volatile unsigned long *gpfdat;
- static struct class *btn_cls; //为了自动创建设备节点
- static struct class_device *btn_cls_dev; //为了自动创建设备节点
- static struct cdev cdev;
- static int major = 0;
- static int btn_open(struct inode *inode, struct file *file)
- {
- *gpfcon &= ~((0x3 <<(2*0)) | (0x3 << (2*1)) | (0x3 <<(2*2))//设置按键的引脚为输入引
- | (0x3 << (2*4))); //角
-
- return 0;
- }
- ssize_t btn_read(struct file *file, char __user * buf,
- size_t len, loff_t * ppos)
- {
- unsigned long rev;
- unsigned char key_val[4];
- if (len != sizeof(key_val))
- return -EINVAL;
-
- rev = *gpfdat; //读取寄存器的值
- key_val[0] = (rev & (1<<0)) ? 0 : 1;//获取K4的状态,是否按下
- key_val[1] = (rev & (1<<1)) ? 0 : 1;//获取K1的状态,是否按下
- key_val[2] = (rev & (1<<2)) ? 0 : 1;//获取K3的状态,是否按下
- key_val[3] = (rev & (1<<4)) ? 0 : 1;//获取K2的状态,是否按下
-
- copy_to_user(buf, key_val, sizeof(key_val));
-
- return 0;
- }
- static int btn_release(struct inode *inode, struct file *file)
- {
- printk("button release\n");
- return 0;
- }
- const struct file_operations btn_op =
- {
- .owner = THIS_MODULE,
- .open = btn_open,
- .read = btn_read,
- .release = btn_release,
- };
- static int btn_val_init()
- {
- dev_t devid;
- int rc;
- if (major)
- {
- devid = MKDEV(major, 0);
- rc = register_chrdev_region(devid, 1, "button");
- }
- else
- {
- rc = alloc_chrdev_region(&devid, 0, 1, "button");
- major = MAJOR(devid);
- }
-
- if (rc < 0)
- {
- printk(KERN_ERR, "can't get major");
- return -ENODEV;
- }
-
- cdev_init(&cdev, &btn_op);
- cdev_add(&cdev, devid, 1);
- btn_cls = class_create(THIS_MODULE, "button");
- btn_cls_dev = class_device_create(btn_cls, NULL, MKDEV(major, 0), NULL, "button0");//这个button0才是自动创建的设备节点的名字,可以和其他的名字不一样,见上面
- gpfcon = (volatile unsigned long)ioremap(0x56000050, 16);//GPFCON寄存器的地址映射
- gpfdat = gpfcon 1;
-
- return 0;
- }
- static void btn_val_exit()
- {
- class_device_destroy(btn_cls, MKDEV(major, 0));
- class_destroy(btn_cls);
- cdev_del(&cdev);
- unregister_chrdev_region(MKDEV(major, 0), 1);
- }
- module_init(btn_val_init);
- module_exit(btn_val_exit);
- MODULE_AUTHOR("xiaoming");
- MODULE_DESCRIPTION("read the value of button");
- MODULE_LICENSE("GPL");
运行结果:
测试小例子:
- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- int main()
- {
- int fd;
- unsigned char key_val[4];
- fd = open("/dev/button0", O_RDWR);//这个名字是 class_device_create 时的名字
- if (fd < 0)
- {
- printf("open /dev/button0 failed\n");
- return -1;
- }
- while (1)
- {
- read(fd, key_val, sizeof(key_val));
- if (key_val[0] || key_val[1] || key_val[2] || key_val[3])
- {
- printf("key[0] = %d, key[1] = %d, key[2] = %d, key[3] = %d\n",
- key_val[0], key_val[1], key_val[2], key_val[3]);
- }
- }
-
- return 0;
- }
运行结果:
当按下按键时就会打印一些信息
图1 TQ2440底板原理图
图2 TQ2440核心板原理图
图3.s3c2440.pdf
图4.s3c2440.pdf
阅读(999) | 评论(0) | 转发(0) |