这张图就是全部了。
device是与硬件相关的代码,driver是比较稳定的驱动代码。
当修改硬件部分的时候,只修改dev里面的东西。
=============================================================================================================================
下面用一个点亮LED的例子来说明这个分离的的例子:
这个驱动程序分为左右两边,即:dev 与 drv
在led_dev.中 分配,设置,注册一个platform_device
在led_drv中分配,设置,注册一个platform_driver
定义这个平台设备的资源:
static struct resource led_resource[] = {
[0] = {
.start = 0x56000010,//GPFCON的物理地址
.end = 0x56000010 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 6,// F6引脚
.end = 6,
.flags = IORESOURCE_IRQ,
},
};
定义一个平台设备:
struct platform_device device_led = {
.name = "myled",
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev={
.release = led_release,
},
};
在入口函数中 注册 这个 “平台设备”
static int led_dev_init(void)
{
platform_device_register(&device_led);
return 0;
}
static void led_dev_exit(void)
{
platform_device_unregister(&device_led);
}
定义一个平台driver
static struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
}
};
如果平台设备和平台driver匹配的上,就会调用这个led_driver这个函数。
实现这个probe函数:
static int led_probe(struct platform_device *pdev)
{
return 0;
}
注册字符设备:
major = register_chrdev(0,"myled",&led_fops);
static struct file_operations led_fops=
{
.owner = THIS_MODULE,//这个宏在推向编译模块时自动创建 __this_module变量
.open = led_open,
.write = led_write,
};
static int led_open(struct inode *inode,struct file *file)
{
//配置为输出引脚
*gpio_con &=~(0x3<<(pin*2));
*gpio_con |=(0x1<<(pin*2));
return 0;
}
static ssize_t led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){ int val; copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据 if(val == 1) { printk("val ==1"); *gpio_dat &=~(1<<pin); } else { printk("val ==0"); *gpio_dat|=(1<<pin); } return 0;}
struct resource *res;
/*根据platform_device的资源进行ioremap*/
res = platform_get_resource(pdev,IORESOURCE_MEM,0);
gpio_con = ioremap(res->start,res->end - res->start + 1);
gpio_dat = gpio_con + 1;
res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
pin = res->start;
platform_get_resource(pdev,IORESOURCE_IRQ,0);
是获得pdev的第1个IORESOURCE_IRQ类型的资源。
另外还需要在probe函数中创建设备节点:
led_cls = class_create(THIS_MODULE,"myled");
if(IS_ERR(led_cls))
return PTR_ERR(led_cls);
led_class_dev = device_create(led_cls,NULL,MKDEV(major,0),NULL,"wq_led");
if(unlikely(IS_ERR(led_class_dev)))
return PTR_ERR(led_class_dev);
这样基本就完成了。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
/*分配/设置/注册一个platform_device*/
/*这个平台设备的资源*/
static struct resource led_resource[] = {
[0] = {
.start = 0x56000010,
.end = 0x56000010 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 6,
.end = 6,
.flags = IORESOURCE_IRQ,
},
};
static void led_release(struct device *dev)
{
}
struct platform_device device_led = {
.name = "myled",
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev={
.release = led_release,
},
};
static int led_dev_init(void)
{
platform_device_register(&device_led);
return 0;
}
static void led_dev_exit(void)
{
platform_device_unregister(&device_led);
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
/*分配/设置/注册一个platform_driver*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static int major;
static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;
static struct class *led_cls;//设备类
static struct class_devices *led_class_dev;//设备
static int pin;
static int led_open(struct inode *inode,struct file *file)
{
//配置为输出引脚
*gpio_con &=~(0x3<<(pin*2));
*gpio_con |=(0x1<<(pin*2));
return 0;
}
static ssize_t led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
int val;
copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据
if(val == 1)
{
printk("val ==1");
*gpio_dat &=~(1<<pin);
}
else
{
printk("val ==0");
*gpio_dat|=(1<<pin);
}
return 0;
}
static struct file_operations led_fops=
{
.owner = THIS_MODULE,//这个宏在推向编译模块时自动创建 __this_module变量
.open = led_open,
.write = led_write,
};
static int led_probe(struct platform_device *pdev)
{
struct resource *res;
/*根据platform_device的资源进行ioremap*/
res = platform_get_resource(pdev,IORESOURCE_MEM,0);
gpio_con = ioremap(res->start,res->end - res->start + 1);
gpio_dat = gpio_con + 1;
res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
pin = res->start;
/*注册字符设备驱动*/
printk("led_probe found led \n");
major = register_chrdev(0,"myled",&led_fops);
led_cls = class_create(THIS_MODULE,"myled");
if(IS_ERR(led_cls))
return PTR_ERR(led_cls);
led_class_dev = device_create(led_cls,NULL,MKDEV(major,0),NULL,"wq_led");
if(unlikely(IS_ERR(led_class_dev)))
return PTR_ERR(led_class_dev);
return 0;
}
static int led_remove(struct platform_device *pdev)
{
/*卸载字符设备驱动*/
device_unregister(led_class_dev);
class_destroy(led_cls);
unregister_chrdev(major,"myled");
iounmap(gpio_con);
/*根据platform_device的资源进行iounmap*/
return 0;
}
static struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
}
};
static int led_drv_init(void)
{
platform_driver_register(&led_drv);
return 0;
}
static void led_drv_exit(void)
{
platform_driver_unregister(&led_drv);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/*wq_led on 打开
*wq_led off 关闭
*/
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/wq_led",O_RDWR);
if(fd < 0)
{
printf("can't open \n");
}
if(argc != 2)
{
printf("Usage :\n");
printf("%s <on|off>\n",argv[0]);
return 0;
}
if(strcmp(argv[1],"on") == 0)
{
val =1;
}
else
{
val =0;
}
write(fd,&val,4);
return 0;
}
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。