字符设备驱动程序的面向对象编程:
逻辑思路:
① 每个具体的设备驱动使用自定义的结构体将所有相关的变量组织起来成为结构体的成员
② 结构体对象和一些设备cdev等结构体使用动态分配内存的方式(
kzalloc和kfree #include <linux/slab.h>),在驱动注册挂载的时候和卸载的时候
③ 利用前面所说的字符设备文件描述结构体inode和file,在具体的操作函数中索引到结构体对象(
Linux内核提供了一个宏container_of可以根据某个结构体成员变量定位到结构体对象的基地址);
④ 以上步骤就可以实现全局的驱动工程通过自定义的驱动结构体对象来交互数据和操作设备了。
实例代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
/*=================================================================================================
*???????????工程是一个NXP的GPIO1_IO03的led设备驱动,使用面向对象的方式来编程
==================================================================================================*/
#define LED_MINOR ????0????????
//设备的次设备号
#define LED_NAME ????"led"????
//设备驱动的名字
#define COUNT ????????1? ? ? ?
//驱动设备要创建的设备数
#define LEDOFF????????0? ? ? ?
//关灯
#define LEDON? ? ? ? ?1? ? ? ?
//开灯
/* 需要操作的相关物理寄存器与地址 */
#define CCM_CCGR1_BASE????????????(0x020c406cu)
#define SW_MUX_GPIO1_IO03_BASE????(0x020e0068u)
#define SW_PAD_GPIO1_IO03_BASE????(0x020e02f4u)
#define GPIO1_DR_BASE????????????(0x0209c000u)
#define GPIO1_GDIR_BASE????????????(0x0209c004u)
/* 统一LED设备驱动结构体,动态分配 */
typedef struct{
????dev_t led_devid;???????????????????????
//led驱动设备号
????struct cdev led_cdev;??????????????????
//led字符驱动设备的注册结构体
????struct file_operations led_fops;? ? ? ?
//led字符设备的操作实现结构体
????struct class *led_class;???????????????
//led字符驱动设备热拔插class
????struct device *led_device;?????????????
//led字符驱动设备热拔插device
????
/* led gpio寄存器的虚拟地址????*/
????void __iomem *VIRTUAL_CCM_CCGR1;
????void __iomem *VIRTUAL_SW_MUX_GPIO1_IO03;
????void __iomem *VIRTUAL_SW_PAD_GPIO1_IO03;
????void __iomem *VIRTUAL_GPIO1_DR;
????void __iomem *VIRTUAL_GPIO1_GDIR;
}LED_DRIVER_T;
static LED_DRIVER_T *led_driver_t = NULL;
/*======================================================================
*?????????????????字符设备功能操作函数接口的实现
=======================================================================*/
static int led_open(struct inode *inode,struct file *filp)
{
????struct cdev *led_cdev = inode->i_cdev;
????LED_DRIVER_T *led_driver_t = container_of(led_cdev,LED_DRIVER_T,led_cdev);
????if(NULL == led_driver_t)
????{
????????printk("The led device open failed!\r\n");
????????return -1;
????}
????
????printk("The led device is open:%d:%d\r\n",MAJOR(led_driver_t->led_devid),MINOR(led_driver_t->led_devid));
????return 0;
}
static int led_close(struct inode *inode,struct file *filp)
{
????struct cdev *led_cdev = inode->i_cdev;
????LED_DRIVER_T *led_driver_t = container_of(led_cdev,LED_DRIVER_T,led_cdev);
????if(NULL == led_driver_t)
????{
????????printk("The led device close error!\r\n");
????????return -1;
????}
????
????return 0;
}
static ssize_t led_read(struct file *filp,char __user *buf,size_t cnt,loff_t *loff)
{
????ssize_t retvalue = 0;
????u32 val = 0u;
????u8 databuf[1];
????
//struct cdev *led_cdev = filp->f_path.dentry->d_inode->i_cdev;
????struct cdev *led_cdev = filp->f_inode->i_cdev;
????LED_DRIVER_T *led_driver_t = container_of(led_cdev,LED_DRIVER_T,led_cdev);
????if(NULL == led_driver_t)
????{
????????printk("read led device error!\r\n");
????????return -1;
????}
????
????
/* 读取led设备对应的输出值寄存器 */
????val = readl(led_driver_t->VIRTUAL_GPIO1_DR);
????if(val&(0x1u<<3u))
????????databuf[0] = LEDOFF;
????else
????????databuf[0] = LEDON;
????retvalue = copy_to_user(buf,databuf,1);
????
????return retvalue;
}
static ssize_t led_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *loff)
{
????ssize_t retvalue = 0;
????u32 val = 0u;
????u8 databuf[1];
????
//struct cdev *led_cdev = filp->f_path.dentry->d_inode->i_cdev;
????struct cdev *led_cdev = filp->f_inode->i_cdev;
????LED_DRIVER_T *led_driver_t = container_of(led_cdev,LED_DRIVER_T,led_cdev);
????if(NULL == led_driver_t)
????{
????????printk("write led device error!\r\n");
????????return -1;
????}
????
????retvalue = copy_from_user(databuf,buf,1);
????if(0>retvalue)
????{
????????printk("write led device data is fail!\r\n");
????????return retvalue;
????}
????val = readl(led_driver_t->VIRTUAL_GPIO1_DR);
????if(LEDON == databuf[0])
????????val &= ~(0x1u<<3u);
????else if(LEDOFF == databuf[0])
????????val |= (0x1u<<3u);
????writel(val,led_driver_t->VIRTUAL_GPIO1_DR);
????
????return retvalue;
}
/*======================================================================
*???????????????????驱动设备的注册与注销
=======================================================================*/
static int __init led_init(void)
{
????int retvalue = 0;
????u32 val = 0u;
????
???
?/* 1 动态申请一个LED设备驱动对象LED_DRIVER_T */
????
led_driver_t = kzalloc(sizeof(LED_DRIVER_T),GFP_KERNEL);
????if(NULL == led_driver_t)
????{
????????printk("The led driver malloc struct failed!\r\n");
????????retvalue = -1;
????????goto err;
????}
????memset(led_driver_t,0u,sizeof(LED_DRIVER_T));
????
/* 2 LED相关的寄存器申请虚拟地址 */
????led_driver_t->VIRTUAL_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);
????led_driver_t->VIRTUAL_SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE,4);
????led_driver_t->VIRTUAL_SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE,4);
????led_driver_t->VIRTUAL_GPIO1_DR = ioremap(GPIO1_DR_BASE,4);
????led_driver_t->VIRTUAL_GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE,4);
????
/* 初始化LED相关寄存器 */
????
/* 使能GPIO1的时钟电源 */
????val = readl(led_driver_t->VIRTUAL_CCM_CCGR1);
????val &= ~(0x3u<<26u);
????val |= (0x3u<<26u);
????writel(val,led_driver_t->VIRTUAL_CCM_CCGR1);
????
/* 设置GPIO1_IO03的复用功能,复用为普通IO */
????writel(5u,led_driver_t->VIRTUAL_SW_MUX_GPIO1_IO03);
????
/* 配置GPIO1_IO03的电气属性 */
????writel(0x10b0u,led_driver_t->VIRTUAL_SW_PAD_GPIO1_IO03);
????
/* 配置GPIO1_IO03为数字量输出功能 */
????val = readl(led_driver_t->VIRTUAL_GPIO1_GDIR);
????val &= ~(0x1u<<3u);
????val |= (0x1u<<3u);
????writel(val,led_driver_t->VIRTUAL_GPIO1_GDIR);
????
/* 默认熄灭LED */
????val = readl(led_driver_t->VIRTUAL_GPIO1_DR);
????val |= (0x1u<<3u);
????writel(val,led_driver_t->VIRTUAL_GPIO1_DR);
????
/* 3 动态向Linux申请空闲的设备号 */
????retvalue = alloc_chrdev_region(&(led_driver_t->led_devid),LED_MINOR,COUNT,LED_NAME);
????if(0>retvalue)
????{
????????printk("The led driver alloc devid failed!\r\n");
????????goto err0;
????}
????
/* 4 配置led字符驱动设备的操作函数功能 */
????(led_driver_t->led_fops).open = led_open;
????(led_driver_t->led_fops).release = led_close;
????(led_driver_t->led_fops).read = led_read;
????(led_driver_t->led_fops).write = led_write;
????
/* 5 初始化cdev字符驱动描述结构体 */
????cdev_init(&(led_driver_t->led_cdev),&(led_driver_t->led_fops));
????led_driver_t->led_cdev.owner = THIS_MODULE;
????retvalue = cdev_add(&(led_driver_t->led_cdev),led_driver_t->led_devid,COUNT);
????if(0>retvalue)
????{
????????printk("The led driver cdev insmod failed!\r\n");
????????goto err1;
????}
????
/* 6 使用mdev工具制造虚拟设备热拔插事件 */
????led_driver_t->led_class = class_create(THIS_MODULE,LED_NAME);
????if(NULL == (led_driver_t->led_class))
????{
????????printk("The led driver alloc class failed!\r\n");
????????goto err2;
????}
????led_driver_t->led_device = device_create(led_driver_t->led_class,NULL,led_driver_t->led_devid,NULL,LED_NAME);
????if(NULL == (led_driver_t->led_device))
????{
????????printk("The led driver alloc device failed!\r\n");
????????goto err3;
????}
????
????printk("The led driver install OK! Device path is /dev/%s\r\n",LED_NAME);
????
????return retvalue;
????
err3:
????class_destroy(led_driver_t->led_class);
err2:
????cdev_del(&(led_driver_t->led_cdev));
err1:
????unregister_chrdev_region(led_driver_t->led_devid,COUNT);
err0:
????iounmap(led_driver_t->VIRTUAL_CCM_CCGR1);
????iounmap(led_driver_t->VIRTUAL_SW_MUX_GPIO1_IO03);
????iounmap(led_driver_t->VIRTUAL_SW_PAD_GPIO1_IO03);
????iounmap(led_driver_t->VIRTUAL_GPIO1_DR);
????iounmap(led_driver_t->VIRTUAL_GPIO1_GDIR);
????
kfree(led_driver_t);
err:
????return retvalue;
}
static void __exit led_exit(void)
{
????u32 val = 0u;
????if(NULL != led_driver_t)
????{
????????device_destroy((led_driver_t->led_class),led_driver_t->led_devid);
????????class_destroy(led_driver_t->led_class);
????????
????????cdev_del(&(led_driver_t->led_cdev));
????????unregister_chrdev_region(led_driver_t->led_devid,COUNT);
????????
????????
/* 默认熄灭LED */
????????val = readl(led_driver_t->VIRTUAL_GPIO1_DR);
????????val |= (0x1u<<3u);
????????writel(val,led_driver_t->VIRTUAL_GPIO1_DR);
????????iounmap(led_driver_t->VIRTUAL_CCM_CCGR1);
????????iounmap(led_driver_t->VIRTUAL_SW_MUX_GPIO1_IO03);
????????iounmap(led_driver_t->VIRTUAL_SW_PAD_GPIO1_IO03);
????????iounmap(led_driver_t->VIRTUAL_GPIO1_DR);
????????iounmap(led_driver_t->VIRTUAL_GPIO1_GDIR);
????????
????????
kfree(led_driver_t);
????????led_driver_t = NULL;
????}
????
????return;
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("WangXiaokun");
宏container_of的原型:
#define container_of(ptr, type, member) \
????(type *)((char *)(ptr) - (char *) &((type *)0)->member)
#endif
|