驱动--(平台设备机制)
总共需要有四个文件,Makefile led_test.c led_dev.c led_drv.c
Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR =/home/farsight-xf/linux_src/linux-2.6.35-farsight
PWD =$(shell pwd)
module:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
cp led_drv.ko led_dev.ko /opt/filesystem/allen
module_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules install
clean:
rm -rf *.so *.o *.ko *.mod.c *.order *.symvers
else
obj-m :=led_drv.o led_dev.o
endif
led_test.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include<sys/ioctl.h>
#include<unistd.h>
#include<signal.h>
int fd1;
int fd2;
char val1;
char val2;
int ret;
int flags;
void signal_handler(int signal)
{
ret = read(fd1, &val1, 1);
switch(val1)
{
case 1:
val2 = 1;
break;
case 2:
val2 = 2;
break;
case 3:
val2 = 3;
break;
case 4:
val2 = 4;
break;
default:
val2 = 5;
}
write(fd2 ,&val2,1);
}
int main(int argc, char **argv)
{
fd1 = open("/dev/s5pc100_buttons",O_RDWR);
fd2 = open("/dev/s5pc100_led", O_RDWR);
if(fd1 < 0)
{
printf("open /dev/buttons failed! \n");
return -1;
}
if(fd2 < 0)
{
printf("open /dev/s5pc100_led error! \n");
return -1;
}
/*--1--信号与信号处理函数绑定*/
signal(SIGIO,signal_handler);
/*--2--设置信号的拥有者*/
fcntl(fd1,F_SETOWN,getpid());
/*--3--设置异步通知*/
flags = fcntl(fd1,F_GETFL);
flags |= FASYNC;
fcntl(fd1, F_SETFL, flags);
while(1){
sleep(1);
printf("I love sleeping! \n");
}
close(fd1);
close(fd2);
return 0;
}
led_dev.c
#include<linux/fs.h>
#include<linux/cdev.h>
#include <linux/platform_device.h>
/*第三步*/
static struct resource s5pc100_led_resources[] = {
[0] = {
.start = 0xe03001c0,
.end = 0xe03001c7,
.flags = IORESOURCE_MEM,
},
[1] = {
.start =1 ,
.end = 1,
.flags = IORESOURCE_IRQ ,
},
};
static struct resource s5pc100_buttons_resources[] = {
[0] = {
.start = 0xE0300C00,
.end = 0xE0300C07,
.flags = IORESOURCE_MEM,
},
[1] = {
.start =1 ,
.end = 1,
.flags = IORESOURCE_IRQ ,
},
};
static int s5pc100_led_release(struct device *dev)
{
return 0;
}
static int s5pc100_buttons_release(struct device *dev)
{
return 0;
}
/*第二步*/
struct platform_device s5pc100_dev_led={
.name = "s5pc100_led",
.id = -1,
.num_resources = ARRAY_SIZE(s5pc100_led_resources),
.resource =s5pc100_led_resources ,
.dev = {
.release = s5pc100_led_release,
}
};
struct platform_device s5pc100_dev_buttons={
.name = "s5pc100_buttons",
.id = -1,
.num_resources = ARRAY_SIZE(s5pc100_buttons_resources),
.resource =s5pc100_buttons_resources ,
.dev = {
.release = s5pc100_buttons_release,
}
};
static int __init s5pc100_led_dev_init(void)
{
/*第一步*/
platform_device_register(&s5pc100_dev_led);
platform_device_register(&s5pc100_dev_buttons);
return 0;
}
static void __exit s5pc100_led_dev_exit(void)
{
platform_device_unregister(&s5pc100_dev_led);
platform_device_unregister(&s5pc100_dev_buttons);
}
module_init(s5pc100_led_dev_init);
module_exit(s5pc100_led_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("allen");
led_drv.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include<linux/cdev.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include<asm/irq.h>
#include<mach/irqs.h>
#include<linux/interrupt.h>
#include <linux/sched.h>
#include<linux/slab.h>
#include<linux/poll.h>
static volatile unsigned long *gpg3con = NULL;
static volatile unsigned long *gpg3dat = NULL;
static volatile unsigned long *gph0con =NULL;
static volatile unsigned long *gph0dat =NULL;
static unsigned int s5pc100_major = 0;
static unsigned int s5pc100_buttons_major = 0;
static struct class *s5pc100_led_class = NULL;
static struct class *s5pc100_buttons_class = NULL;
static struct cdev *cdev =NULL;
wait_queue_head_t buttons_wq;
struct fasync_struct *mybuttons_fasync;
struct buttons{
int irq;
char *name;
int bit;
int buttons_val;
int pin_val;
};
struct buttons buttons_array[6]={
{IRQ_EINT(1),"key1",1,0x01},
{IRQ_EINT(2),"key2",2,0x02},
{IRQ_EINT(3),"key3",3,0x03},
{IRQ_EINT(4),"key4",4,0x04},
{IRQ_EINT(6),"key5",6,0x05},
{IRQ_EINT(7),"key6",7,0x06},
};
char key;
/*定义一个 针对led 的结构体*/
struct s5pc100_led{
struct cedv *cdev;
unsigned int pin;
};
/*声明一个结构体指针*/
struct s5pc100_led *s5pc100_ledp;
/*中断第二步,处理程序*/
static irqreturn_t mybutton_handler(int irq,void * dev_id)
{
struct buttons *cur_pin = (struct buttons *)dev_id;
printk("buttons test ok! \n");
cur_pin->pin_val = (*gph0dat)&(0x1<<cur_pin->bit);
if(cur_pin->pin_val){
/*没有按下*/
key = cur_pin->buttons_val | 0x80;
}else{
key = cur_pin->buttons_val;
}
printk("key =%d\n",key);
/*---4---唤醒*/
wake_up_interruptible(&buttons_wq);
/*发送 信号给应用程序*/
kill_fasync(&mybuttons_fasync,SIGIO,POLLIN);
return IRQ_HANDLED;
}
int s5pc100_led_open (struct inode *inode, struct file *file)
{
//*gpg3con &= ~(0xf<<s5pc100_ledp->pin *4);
//*gpg3con |= (0x1<<s5pc100_ledp->pin *4);
*gpg3con &= ~0xffff;
*gpg3con |= 0x1111;
return 0;
}
static int s5pc100_buttons_open(struct inode *inode, struct file *file)
{
int i;
int ret;
printk("open ok!\n");
/*中断第一步*/
for(i = 0; i<6; i++)
ret = request_irq(buttons_array[i].irq,mybutton_handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,buttons_array[i].name,&buttons_array[i]);
return 0;
}
static int s5pc100_buttons_release (struct inode * inode,struct file * file)
{
int i;
for(i = 0; i<6; i++)
free_irq(buttons_array[i].irq,&buttons_array[i]);//中断释放
return 0;
}
static ssize_t s5pc100_buttons_read(struct file *file, char __user *buf, size_t count, loff_t *opps)
{
int ret;
if(key==0 && (file->f_flags & O_NONBLOCK))
return 0;
/*---3---没有按键按下的时候,则休眠*/
wait_event_interruptible(buttons_wq,key);
ret = copy_to_user(buf,&key,count);
key = 0;
return 1;
}
static int s5pc100_buttons_fasync (int fd, struct file *file, int on)
{
int tmp;
tmp = fasync_helper(fd,file,on,&mybuttons_fasync);
return tmp;
}
ssize_t s5pc100_led_write (struct file *file, const char __user *buf, size_t count, loff_t *opps)
{
char tmp;
int ret;
printk("entered write \n");
ret = copy_from_user(&tmp,buf,1);
switch(tmp)
{
case 1:
*gpg3dat |= (0x1<<(s5pc100_ledp->pin));
break;
case 2:
*gpg3dat |= (0x1<<(s5pc100_ledp->pin+1));
break;
case 3:
*gpg3dat |= (0x1<<(s5pc100_ledp->pin+2));
break;
case 4:
*gpg3dat |= (0x1<<(s5pc100_ledp->pin-1));
break;
default:
*gpg3dat = 0x0;
}
return 0;
}
struct file_operations s5pc100_led_fops = {
.owner = THIS_MODULE,
.open = s5pc100_led_open,
.write = s5pc100_led_write,
};
struct file_operations s5pc100_buttons_fops={
.owner = THIS_MODULE,
.open = s5pc100_buttons_open,
.release = s5pc100_buttons_release,
.read = s5pc100_buttons_read,
.fasync = s5pc100_buttons_fasync,
};
void s5pc100_setup_cdev(void)
{
dev_t devno = MKDEV(s5pc100_major, 0);
s5pc100_ledp->cdev = cdev_alloc();
cdev_init(s5pc100_ledp->cdev,&s5pc100_led_fops);
cdev_add(s5pc100_ledp->cdev,devno,1);
}
static void s5pc100_buttons_cdev(void)
{
dev_t devno = MKDEV(s5pc100_buttons_major, 0);
cdev = cdev_alloc();
cdev_init(cdev, &s5pc100_buttons_fops);
cdev->owner = THIS_MODULE;
cdev_add(cdev,devno,1);
}
int s5pc100_led_probe(struct platform_device *pdev)
{
dev_t devno;
struct resource *res;
printk("entered probe of led\n");
/*获取io 资源*/
res = platform_get_resource(pdev,IORESOURCE_MEM,0);
/*映射io 资源*/
gpg3con = ioremap(res->start, res->end - res->start +1);
gpg3dat = gpg3con + 1;
/*为led 结构体分配空间*/
s5pc100_ledp = kmalloc(sizeof(struct s5pc100_led),GFP_KERNEL);
/*获取irq 资源*/
res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
/*映射irq 资源*/
s5pc100_ledp->pin = res->start;
/*如果你有子系统的话,就调用子系统的接口函数,
*注册到子系统里面去如:frambuffer_register
*/
/*没有子系统的话就注册到内核当中去*/
/*这种情况就和先前的步骤一样了*/
alloc_chrdev_region(&devno,0,1,"s5pc100_led");
s5pc100_major = MAJOR(devno);
s5pc100_setup_cdev();
s5pc100_led_class = class_create(THIS_MODULE,"s5pc100_led_class");
device_create(s5pc100_led_class,NULL,devno,NULL,"s5pc100_led");
return 0;
}
int s5pc100_buttons_probe(struct platform_device *pdev)
{
dev_t devno;
struct resource *res;
printk("entered probe of buttons\n");
/*获取io 资源*/
res = platform_get_resource(pdev,IORESOURCE_MEM,0);
/*映射io 资源*/
gph0con = ioremap(res->start, res->end - res->start +1);
gph0dat = gph0con + 1;
/*如果你有子系统的话,就调用子系统的接口函数,
*注册到子系统里面去如:frambuffer_register
*/
/*没有子系统的话就注册到内核当中去*/
/*这种情况就和先前的步骤一样了*/
alloc_chrdev_region(&devno,0,1,"s5pc100_buttons");
s5pc100_buttons_major= MAJOR(devno);
s5pc100_buttons_cdev();
s5pc100_buttons_class = class_create(THIS_MODULE,"s5pc100_buttons_class");
device_create(s5pc100_buttons_class,NULL,devno,NULL,"s5pc100_buttons");
init_waitqueue_head(&buttons_wq);
return 0;
}
int s5pc100_led_remove(struct platform_device *pdev)
{
dev_t devno = MKDEV(s5pc100_major, 0);
unregister_chrdev_region(devno,1);
device_destroy(s5pc100_led_class,devno);
class_destroy(s5pc100_led_class);
iounmap(gpg3con);
return 0;
}
int s5pc100_buttons_remove(struct platform_device *pdev)
{
dev_t devno = MKDEV(s5pc100_buttons_major,0);
unregister_chrdev_region(devno,1);//设备号
device_destroy(s5pc100_buttons_class,devno);//设备节点
class_destroy(s5pc100_buttons_class);
cdev_del(cdev);//设备结构体
iounmap(gph0con);
return 0;
}
/*第二步*/
struct platform_driver s5pc100_led_drv = {
.probe = s5pc100_led_probe,
.remove = s5pc100_led_remove,
.driver = {
.name = "s5pc100_led",
.owner = THIS_MODULE,
},
};
struct platform_driver s5pc100_buttons_drv = {
.probe = s5pc100_buttons_probe,
.remove = s5pc100_buttons_remove,
.driver = {
.name = "s5pc100_buttons",
.owner = THIS_MODULE,
},
};
static int __init s5pc100_led_drv_init(void)
{
/*第一步*/
platform_driver_register(&s5pc100_led_drv);
platform_driver_register(&s5pc100_buttons_drv);
return 0;
}
static void __exit s5pc100_led_drv_exit(void)
{
platform_driver_unregister(&s5pc100_led_drv);
platform_driver_unregister(&s5pc100_buttons_drv);
}
module_init(s5pc100_led_drv_init);
module_exit(s5pc100_led_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("allen");