#include<linux/init.h>
#include<linux/module.h>#include<linux/fs.h> //file_operations#include<linux/device.h> //class_create device_create#include<linux/cdev.h> //Struct cdev#include<linux/slab.h> //kmalloc#include<asm/io.h> //ioremap,writel,readl#include<asm/uaccess.h> //copy_from_user#include<mach/irqs.h>#include<linux/interrupt.h>#include<linux/irqreturn.h>#define S5PC100_PA_BUTTON 0xE0300C00
#define S5PC100_GPH0CON 0x0
#define S5PC100_GPH0DAT 0x4/*1.构建对象:抽象出一个buttons设备来*/
struct buttons_device{ unsigned int buttons_major; struct cdev *buttons_cdev; struct device *buttons_device; struct class *buttons_class; void __iomem *buttons_base; dev_t devno; unsigned int key_val;};static struct buttons_device *fs_buttons_dev;
static irqreturn_t buttons_irq(int irq,void *dev_id)
{ unsigned long val; struct buttons_device *cur_key =(struct buttons_device *)dev_id; /*处理中断*/ /*判断是按下还是松开,需要通过读取管脚的状态,保存键值*/ val = readl(cur_key->buttons_base + S5PC100_GPH0DAT) & (0xff<<0);if(val == 0){
cur_key->key_val = 0; }else if((val & (0x1<<1)) == 0){ cur_key->key_val = 1; }else if((val & (0x1<<2)) == 0){ cur_key->key_val = 2; }else if((val & (0x1<<3)) == 0){ cur_key->key_val = 3; }else if((val & (0x1<<4)) == 0){ cur_key->key_val = 4; }else if((val & (0x1<<6)) == 0){ cur_key->key_val = 5; }else if((val & (0x1<<7)) == 0){ cur_key->key_val = 6; }else{ cur_key->key_val = 100; } return IRQ_HANDLED;}static int buttons_open(struct inode *inode, struct file *file)
{ printk(KERN_INFO "buttons open!\n"); return 0;}static ssize_t buttons_read(struct file *file, char __user *buf, size_t size, loff_t *opps)
{ int ret;/*将键值返回给用户空间*/
ret = copy_to_user(buf, &fs_buttons_dev->key_val, size); fs_buttons_dev->key_val =0; return ret?-EINVAL:size;}struct file_operations buttons_fops ={
.owner =THIS_MODULE, .open =buttons_open, .read =buttons_read,};static int __init buttons_init(void)
{ int ret; /*1.为本地的buttons设备分配空间 *param1:大小 *param2:标志GFP_KERNEL:如果分配不成功,则会导致休眠 */ fs_buttons_dev=kmalloc(sizeof(struct buttons_device), GFP_KERNEL); if(fs_buttons_dev==NULL){ printk(KERN_ERR "no memory for malloc!\n"); return -ENOMEM; }/*2.申请设备号*/
ret=alloc_chrdev_region(&fs_buttons_dev->devno,0,1,"buttons_module"); if(ret<0){ printk(KERN_ERR "register major faibuttons!\n"); ret =-EINVAL; goto output0; }/*3.创建字符设备struct cdev*/
fs_buttons_dev->buttons_cdev =cdev_alloc(); if(fs_buttons_dev->buttons_cdev==NULL){ printk(KERN_ERR "alloc memory faibuttons\n"); ret =-ENOMEM; goto output1; } cdev_init(fs_buttons_dev->buttons_cdev, &buttons_fops); cdev_add(fs_buttons_dev->buttons_cdev,fs_buttons_dev->devno,1);/*4.创建设备文件*/
fs_buttons_dev->buttons_class=class_create(THIS_MODULE, "buttons_class"); if(IS_ERR(fs_buttons_dev->buttons_class)){ printk(KERN_ERR "create class faibuttons!\n"); ret =PTR_ERR(fs_buttons_dev->buttons_class); goto output2; } fs_buttons_dev->buttons_device=device_create(fs_buttons_dev->buttons_class,NULL,fs_buttons_dev->devno,NULL,"buttons"); if(IS_ERR(fs_buttons_dev->buttons_device)){ printk(KERN_ERR "create device faibuttons!\n"); ret =PTR_ERR(fs_buttons_dev->buttons_device); goto output3; }/*5.注册6个中断*/
/*EINT1*/ ret = request_irq(IRQ_EINT(1), buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"K1",fs_buttons_dev); if(ret){ printk(KERN_ERR "request irq failed!\n"); ret = -EFAULT; goto output4; } /*EINT2*/ ret = request_irq(IRQ_EINT(2), buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"K2",fs_buttons_dev); if(ret){ printk(KERN_ERR "request irq failed!\n"); ret = -EFAULT; goto output5; } /*EINT3*/ ret = request_irq(IRQ_EINT(3), buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"K3",fs_buttons_dev); if(ret){ printk(KERN_ERR "request irq failed!\n"); ret = -EFAULT; goto output6; } /*EINT4*/ ret = request_irq(IRQ_EINT(4), buttons_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"K4",fs_buttons_dev); if(ret){ printk(KERN_ERR "request irq failed!\n"); ret = -EFAULT; goto output7; } /*EINT6*/ ret = request_irq(IRQ_EINT(6), buttons_irq, IRQF_TRIGGER_FALLING,"K6",fs_buttons_dev); if(ret){ printk(KERN_ERR "request irq failed!\n"); ret = -EFAULT; goto output8; } /*EINT7*/ ret = request_irq(IRQ_EINT(7), buttons_irq, IRQF_TRIGGER_FALLING,"K7",fs_buttons_dev); if(ret){ printk(KERN_ERR "request irq failed!\n"); ret = -EFAULT; goto output9; }/*6.将物理地址映射为虚拟地址*/
fs_buttons_dev->buttons_base=ioremap(S5PC100_PA_BUTTON,8); if(!fs_buttons_dev->buttons_base){ printk(KERN_ERR "unable to ioremap!\n"); ret =-ENOMEM; goto output10; } return 0;output10: free_irq(IRQ_EINT(7),fs_buttons_dev);output9: free_irq(IRQ_EINT(6),fs_buttons_dev);output8: free_irq(IRQ_EINT(4),fs_buttons_dev);output7: free_irq(IRQ_EINT(3),fs_buttons_dev);output6: free_irq(IRQ_EINT(2),fs_buttons_dev);output5: free_irq(IRQ_EINT(1),fs_buttons_dev);output4: device_destroy(fs_buttons_dev->buttons_class, fs_buttons_dev->devno);output3: class_destroy(fs_buttons_dev->buttons_class);output2: cdev_del(fs_buttons_dev->buttons_cdev);output1: unregister_chrdev_region(fs_buttons_dev->devno,1);output0: kfree(fs_buttons_dev); return ret;}static void __exit buttons_exit(void)
{ unregister_chrdev_region(fs_buttons_dev->devno,1); cdev_del(fs_buttons_dev->buttons_cdev); device_destroy(fs_buttons_dev->buttons_class,fs_buttons_dev->devno); class_destroy(fs_buttons_dev->buttons_class); free_irq(IRQ_EINT(1),fs_buttons_dev); free_irq(IRQ_EINT(2),fs_buttons_dev); free_irq(IRQ_EINT(3),fs_buttons_dev); free_irq(IRQ_EINT(4),fs_buttons_dev); free_irq(IRQ_EINT(6),fs_buttons_dev); free_irq(IRQ_EINT(7),fs_buttons_dev); iounmap(fs_buttons_dev->buttons_base); kfree(fs_buttons_dev);}module_init(buttons_init);
module_exit(buttons_exit);MODULE_LICENSE("GPL");
led_dvr:
#include<linux/init.h>
#include<linux/module.h>#include<linux/fs.h> //file_operations#include<linux/device.h> //class_create device_create#include<linux/cdev.h> //Struct cdev#include<linux/slab.h> //kmalloc#include<asm/io.h> //ioremap#include<asm/uaccess.h> //copy_from_user#define LED_PA_ADDR 0xE03001C0/*1.构建对象:抽象出一个led设备来*/
struct led_device{ unsigned int led_major; struct cdev *led_cdev; struct device *led_device; struct class *led_class; dev_t devno;};static struct led_device *fs_led_dev;
static volatile unsigned long *gpg3con =NULL;
static volatile unsigned long *gpg3dat =NULL;static int led_open(struct inode *inode, struct file *file)
{ printk(KERN_INFO "led open!\n"); /*初始化硬件:将GPG3CON[0]配置为输出*/ *gpg3con &= ~(0xffff<<0); *gpg3con |= ((0x1<<0)|(0x1<<4)|(0x1<<8)|(0x1<<12));return 0;
}static int led_close(struct inode *inode, struct file *file)
{ printk(KERN_INFO "led close!\n"); /*初始化硬件:将GPG3CON[0]配置为输出*/ *gpg3con &= ~(0xffff<<0); return 0;}
//write(fd,&buf,4)
//sys_write//根据fd找到对应的file结构体//执行file->f_op->write =led_writestatic ssize_t led_write(struct file *file, const char __user *buf, size_t size, loff_t *opps){ int ret = 0; //int i = 1;//,j = 0,u = 0,k = 0; int val; /*获取用户空间的数据 *如果拷贝成功,则返回0 *失败返回剩下的没有拷贝成功的字节数>0 */ ret = copy_from_user(&val,buf,size); if(ret != 0) { printk("copy_from_user error!\n"); return -EINVAL; } switch(val) { case 1: *gpg3dat |= (0x1<<0); break; case 2: *gpg3dat |= (0x1<<1); break; case 3: *gpg3dat |= (0x1<<2); break; case 4: *gpg3dat |= (0x1<<3); break; /*case 5: break;*/ case 6: *gpg3dat |= ((0x1<<0)|(0x1<<1)|(0x1<<2)|(0x1<<3)); break; default: *gpg3dat &= ~(0xf<<0); break; } return ret?-EFAULT:size;}struct file_operations led_fops ={
.owner =THIS_MODULE, .open =led_open, .write =led_write, .release = led_close,};static int __init led_init(void)
{ int ret; /*1.为本地的led设备分配空间 *param1:大小 *param2:标志GFP_KERNEL:如果分配不成功,则会导致休眠 */ fs_led_dev=kmalloc(sizeof(struct led_device), GFP_KERNEL); if(fs_led_dev==NULL){ printk(KERN_ERR "no memory for malloc!\n"); return -ENOMEM; }/*2.申请设备号*/
ret=alloc_chrdev_region(&fs_led_dev->devno,0,1,"led_module"); if(ret<0){ printk(KERN_ERR "register major failed!\n"); ret =-EINVAL; goto output0; }/*3.创建字符设备struct cdev*/
fs_led_dev->led_cdev =cdev_alloc(); if(fs_led_dev->led_cdev==NULL){ printk(KERN_ERR "alloc memory failed\n"); ret =-ENOMEM; goto output1; } cdev_init(fs_led_dev->led_cdev, &led_fops); cdev_add(fs_led_dev->led_cdev,fs_led_dev->devno,1);/*4.创建设备文件*/
fs_led_dev->led_class=class_create(THIS_MODULE, "led_class"); if(IS_ERR(fs_led_dev->led_class)){ printk(KERN_ERR "create class failed!\n"); ret =PTR_ERR(fs_led_dev->led_class); goto output2; } fs_led_dev->led_device=device_create(fs_led_dev->led_class,NULL,fs_led_dev->devno,NULL,"led"); if(IS_ERR(fs_led_dev->led_device)){ printk(KERN_ERR "create device failed!\n"); ret =PTR_ERR(fs_led_dev->led_device); goto output3; }/*5.将物理地址映射为虚拟地址*/
gpg3con =ioremap(LED_PA_ADDR,8); gpg3dat =gpg3con+1; return 0;output3: class_destroy(fs_led_dev->led_class);output2: cdev_del(fs_led_dev->led_cdev);output1: unregister_chrdev_region(fs_led_dev->devno,1);output0: kfree(fs_led_dev); return ret;}static void __exit led_exit(void)
{ unregister_chrdev_region(fs_led_dev->devno,1); cdev_del(fs_led_dev->led_cdev); device_destroy(fs_led_dev->led_class,fs_led_dev->devno); class_destroy(fs_led_dev->led_class); iounmap(gpg3con); kfree(fs_led_dev);}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
test:
#include <stdio.h>
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <pthread.h>void delay()
{ int i,j; for(i=100000; i>0; i--) for(j=80; j>0; j--);}void *write_leds_func(void *arg)
{ int fd_1; int k = 1, h = 100; fd_1 = *(int *)arg; while(1) { if(write(fd_1, &k, 4) != 4) { } delay(); if(write(fd_1, &h, 4) != 4) { perror("write error!\n"); exit(1); } delay(); }}void display(int fd_1)
{ int i = 0; int j; int n = 100; while(i < 10) { for(j=1; j<=4; j++) { if(write(fd_1, &j, 4) != 4) { perror("write failed!\n"); exit(1); } } i++; delay(); delay(); if(write(fd_1, &n, 4) != 4) { perror("write failed!\n"); exit(1); } delay(); }}int main(int argc,char **argv)
{ int fd; int i,j; int n = 100; int fd_1; int key = 0; pthread_t th_id; /*1.打开设备/打开驱动/打开设备文件*/ fd = open("/dev/buttons", O_RDWR); if(fd < 0){ perror("open failed"); exit(1);}
fd_1 = open("/dev/led", O_RDWR);
if(fd_1 < 0){ perror("open failed"); exit(1); }display(fd_1);
pthread_create(&th_id, NULL, write_leds_func, &fd_1); while(1) { key = 0; if(read(fd, &key, 4) != 4) { perror("read failed"); exit(1); }if(key == 5)
{ i = 0; while(i < 3) { for(j=2; j<=4; j++) { if(write(fd_1, &j, 4) != 4) { perror("write failed!\n"); exit(1); } delay(); delay(); if(write(fd_1, &n, 4) != 4) { perror("write failed!\n"); exit(1); } delay(); delay(); } i++; } } if(key!=0) { if(write(fd_1, &key, 4) != 4) { perror("write failed"); exit(1); } } }close(fd);
close(fd_1); return 0;}
makefile:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?=/home/farsight/Linux_source/linux-2.6.35.5 PWD :=$(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules arm-unknown-linux-gnueabi-gcc -o buttons_leds_test buttons_leds_test.c -lpthread cp buttons_drv.ko leds_drv.ko buttons_leds_test /opt/rootfs/s5pc100_drvmodules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean: rm -rf hello_test *.o *~core *.ko *.mod.c .tmp_versions Module.symvers modules.orderelse obj-m :=buttons_drv.o leds_drv.oendif