Linux驱动代码学习

字符设备实践:

chartest.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/fs.h>            //文件操作集合
#include <linux/uaccess.h>        //copy_to_user的头文件
#include <linux/cdev.h>            //cdev结构体以及cdev_init等
#include <linux/kdev_t.h>        //MKDEV所需的头文件
#include <linux/device.h>        //class_create,device_create
#include <linux/io.h>            //寄存器

dev_t char_dev;                    

struct cdev    muqing_cdev;        //cdev结构体用来表示字符设备
struct class  *muqing_class;    //class类
struct device *muqing_device;    //device设备结构体
#define NUMCHAR  1

#define GPIO3_DR 0x209C000        //LED2  Io物理地址
/*********************** echo none > /sys/class/leds/sys-led/trigger”改变LED2的触发方式 ***************************/

unsigned int* gpio3_3;            //虚拟地址

#define SIZEBEY  4                //寄存器字节

/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = "Hello Word";
    printk("Hello chartext_read\n");
     
    if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
        printk("hd_fops_release error\n");
        return 0;
    }
    return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = {0};
    printk("Hello chartext_write\n");
    
    if( copy_from_user(kbuf,ubuf,size) != 0 ){
        printk("chartext_write error\n");
        return 0;
    }
    if( kbuf[0] == '1' ){
        *gpio3_3 |= (1 << 3);
    }else if( kbuf[0] == '0' ){
        *gpio3_3 &= ~(1 << 3);
    }
    printk("chartext_write urse is %s\n",kbuf);
    return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
    printk("Hello chartext_open\n");
    
    return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
    printk("Hello chartext_release\n");
    
    return 0;
}


struct file_operations chartext_fops={    //文件操作集合
    .owner   = THIS_MODULE,
    .read    = chartext_read,
    .write   = chartext_write,
    .open    = chartext_open,
    .release = chartext_release,
};

static int chartext_init(void){
    int ret;
    
    /*静态注册设备号
    char_dev = MKDEV(100, 30);
    ret = register_chrdev_region(char_dev,NUMCHAR,"muqingdev");
    if( ret != 0 ){
        printk("chartext_init: register_chrdev_region error!!\n");
        return ret;
    }*/
    
    /*动态注册设备号*/
    ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
    if( ret != 0 ){
        printk("alloc_chrdev_region: register_chrdev_region error!!\n");
        return ret;
    }
    printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
    printk("MAJOR %d\n\n",MAJOR(char_dev));
    printk("MINOR %d\n\n",MINOR(char_dev));

    
    /*内存映射*/
    gpio3_3 = ioremap(GPIO3_DR, SIZEBEY);
    if( gpio3_3 == NULL ){
        printk("ioremap error3!!\n");
        return 0;
    }
    printk("ioremap ok3!!\n");
    
    /*初始化cdev*/
    muqing_cdev.owner = THIS_MODULE;
    cdev_init(&muqing_cdev,&chartext_fops);
    /*向内核注册设备*/
    cdev_add(&muqing_cdev,char_dev,NUMCHAR);
    /*创建类 ,在、sys/class下*/
    muqing_class  = class_create(THIS_MODULE, "lcdclass");
    /*自动创建设备节点, /dev下*/
    muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
    printk("chartext_init\n");
    return 0;
}

static void chartext_exit(void){//杂项设备驱动
    iounmap(gpio3_3);
    unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
    cdev_del(&muqing_cdev);                        //删除设备
    device_destroy(muqing_class,char_dev);        //注销设备
    class_destroy(muqing_class);                //删除类
    printk("Bye!!!\n");
}

module_init(chartext_init);    //驱动模块入口函数
module_exit(chartext_exit);    //驱动模块出口函数
MODULE_LICENSE("GPL");        //内核模块声明


app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int fd;
    int i;
    char buf[64] = {0};
    /*char writebuf[64]  = "1";
    char writebuf1[64] = "0";*/
    fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
    if( fd < 0 ){
        perror("open error\n");
        return fd;
    }
    read(fd,buf,sizeof(buf));
    printf("read buf id %s\n",buf);

    write(fd,argv[1],1); 
    close(fd);
    return 0;

}

timer定时器实践:

timerlist.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/timer.h>        //定时器
#include <linux/fs.h>           //文件操作集合
#include <linux/uaccess.h>      //copy_to_user的头文件
#include <linux/kdev_t.h>       //MKDEV所需要的头文件
#include <linux/cdev.h>         //cdev结构体以及cdev-init
#include <linux/device.h>       //class_create,device_create
#include <linux/io.h>            //寄存器

dev_t char_dev;        


struct cdev    muqing_cdev;        //cdev结构体用来表示字符设备
struct class  *muqing_class;    //class类
struct device *muqing_device;    //device设备结构体
#define NUMCHAR  2

struct timer_list Mytimer;
unsigned long i = 1;

#define GPIO5_DR 0x20AC000        //蜂鸣器Io物
unsigned int* gpio5_1;            //虚拟地址
#define SIZEBEY  4                //寄存器字节

#define GPIO3_DR 0x209C000        //LED2  Io物理地址
/*********************** echo none > /sys/class/leds/sys-led/trigger”改变LED2的触发方式 ***************************/
unsigned int* gpio3_3;            //虚拟地址

static void Hello_World(unsigned long arg){
    if( i % 2 == 1 ){
        *gpio5_1 |= (1 << 1);
    }else if( i % 2 == 0 ){
        *gpio5_1 &= ~(1 << 1);
    }

    if( i % 2 == 1 ){
        *gpio3_3 |= (1 << 3);
    }else if( i % 2 == 0 ){
        *gpio3_3 &= ~(1 << 3);
    }
    
    i++;
    arg = jiffies + 1*HZ;
    printk("Hello World!!!\n");
    printk("receive timer data: %ld\n",arg);
    mod_timer(&Mytimer,arg);
}

static int timer_init(void){
    init_timer(&Mytimer);
    Mytimer.expires   = jiffies + 1*HZ; //超时时间
    Mytimer.data      = jiffies + 1*HZ; 
    Mytimer.function  = Hello_World;
    add_timer(&Mytimer); //将定时器注册到内核,开启定时器
    return 0;
}


/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = "Hello Word";
    printk("Hello chartext_read\n");
     
    if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
        printk("hd_fops_release error\n");
        return 0;
    }
    return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = {0};
    printk("Hello chartext_write\n");
    
    if( copy_from_user(kbuf,ubuf,size) != 0 ){
        printk("chartext_write error\n");
        return 0;
    }
    if( kbuf[0] == '1' ){
        timer_init();
    }else if( kbuf[0] == '0' ){
    del_timer_sync(&Mytimer);
    *gpio5_1 &= ~(1 << 1);
    *gpio3_3 |= (1 << 3);
    }
    printk("chartext_write urse is %s\n",kbuf);
    return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
    printk("Hello chartext_open\n");
    
    return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
    printk("Hello chartext_release\n");
    
    return 0;
}


struct file_operations chartext_fops={    //文件操作集合
    .owner   = THIS_MODULE,
    .read    = chartext_read,
    .write   = chartext_write,
    .open    = chartext_open,
    .release = chartext_release,
};

static int mytimer_init(void){
    int ret;
    /*动态注册设备号*/
    ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
    if( ret != 0 ){
        printk("alloc_chrdev_region: register_chrdev_region error!!\n");
        return ret;
    }
    printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
    printk("MAJOR %d\n\n",MAJOR(char_dev));
    printk("MINOR %d\n\n",MINOR(char_dev));


    /*内存映射*/
    gpio5_1 = ioremap(GPIO5_DR, SIZEBEY);
    if( gpio5_1 == NULL ){
        printk("ioremap error3!!\n");
        return 0;
    }

    gpio3_3 = ioremap(GPIO3_DR, SIZEBEY);
    if( gpio3_3 == NULL ){
        printk("ioremap error3!!\n");
        return 0;
    }
    printk("ioremap ok3!!\n");
    
    /*初始化cdev*/
    muqing_cdev.owner = THIS_MODULE;
    cdev_init(&muqing_cdev,&chartext_fops);
    /*向内核注册设备*/
    cdev_add(&muqing_cdev,char_dev,NUMCHAR);
    /*创建类 ,在、sys/class下*/
    muqing_class  = class_create(THIS_MODULE, "lcdclass");
    /*自动创建设备节点, /dev下*/
    muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
    printk("chartext_init\n");

    
    return 0;
}

static void mytimer_exit(void){
    unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
    cdev_del(&muqing_cdev);                        //删除设备
    device_destroy(muqing_class,char_dev);        //注销设备
    class_destroy(muqing_class);                //删除类
    del_timer_sync(&Mytimer);   //卸载定时器
    *gpio5_1 &= ~(1 << 1);
    *gpio3_3 |= (1 << 3);
    iounmap(gpio5_1);
    iounmap(gpio3_3);
    printk("timer bye!\n");
}

module_init(mytimer_init);
module_exit(mytimer_exit);
MODULE_LICENSE("GPL");

app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int fd;
    int i;
    char buf[64] = {0};
    /*char writebuf[64]  = "1";
    char writebuf1[64] = "0";*/
    fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
    if( fd < 0 ){
        perror("open error\n");
        return fd;
    }
    read(fd,buf,sizeof(buf));
    printf("read buf id %s\n",buf);

    write(fd,argv[1],1); 
    close(fd);
    return 0;

}
 

platform平台总线实践:

paltform_driver.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/fs.h>           //文件操作集合
#include <linux/uaccess.h>      //copy_to_user的头文件
#include <linux/kdev_t.h>       //MKDEV所需要的头文件
#include <linux/cdev.h>         //cdev结构体以及cdev-init
#include <linux/device.h>       //class_create,device_create
#include <linux/io.h>            //寄存器

static int chardev_register(void);

dev_t char_dev;        
struct resource * acadada;

struct cdev    muqing_cdev;        //cdev结构体用来表示字符设备
struct class  *muqing_class;    //class类
struct device *muqing_device;    //device设备结构体
#define NUMCHAR  2

#define GPIO5_DR 0x20AC000        //蜂鸣器Io物
unsigned int* gpio5_1;            //虚拟地址
#define SIZEBEY  4                //寄存器字节


int ZCY_platform_probe(struct platform_device *pdev){
    
    acadada = platform_get_resource(pdev,IORESOURCE_MEM,0);  //从platform_device.c获取硬件资源
    printk("start is :%c\n",acadada->start);
    printk("ZCY_platform_probe is ok!\n");
    chardev_register();
    return 0;
}
int ZCY_platform_remove(struct platform_device *pdev){


    printk("ZCY_platform_remove is ok!\n");
    return 0;
}


const struct platform_device_id ZCY_id_table={
    .name = "ZCY_platform",
};


struct platform_driver ZCY_platform_driver={                  
    .probe  = ZCY_platform_probe,    
    .remove = ZCY_platform_remove,  
    .driver={
        .name = "ZCY_platform",
        .owner = THIS_MODULE,
    },
    .id_table = &ZCY_id_table,
};

/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = "Hello Word";
    printk("Hello chartext_read\n");
     
    if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
        printk("hd_fops_release error\n");
        return 0;
    }
    return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = {0};
    printk("Hello chartext_write\n");
    
    if( copy_from_user(kbuf,ubuf,size) != 0 ){
        printk("chartext_write error\n");
        return 0;
    }
    if( kbuf[0] == '1' ){
        *gpio5_1 |= (1 << 1);
    }else if( kbuf[0] == '0' ){
        *gpio5_1 &= ~(1 << 1);
    }
    printk("chartext_write urse is %s\n",kbuf);
    return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
    printk("Hello chartext_open\n");
    
    return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
    printk("Hello chartext_release\n");
    
    return 0;
}


struct file_operations chartext_fops={    //文件操作集合
    .owner   = THIS_MODULE,
    .read    = chartext_read,
    .write   = chartext_write,
    .open    = chartext_open,
    .release = chartext_release,
};

static int chardev_register(void){
    int ret;
    /*动态注册设备号*/
    ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
    if( ret != 0 ){
        printk("alloc_chrdev_region: register_chrdev_region error!!\n");
        return ret;
    }
    printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
    printk("MAJOR %d\n\n",MAJOR(char_dev));
    printk("MINOR %d\n\n",MINOR(char_dev));
    
    /*内存映射*/
    gpio5_1 = ioremap(GPIO5_DR, SIZEBEY);
    if( gpio5_1 == NULL ){
        printk("ioremap error3!!\n");
        return 0;
    }
    printk("ioremap ok3!!\n");
    
    /*初始化cdev*/
    muqing_cdev.owner = THIS_MODULE;
    cdev_init(&muqing_cdev,&chartext_fops);
    /*向内核注册设备*/
    cdev_add(&muqing_cdev,char_dev,NUMCHAR);
    /*创建类 ,在、sys/class下*/
    muqing_class  = class_create(THIS_MODULE, "lcdclass");
    /*自动创建设备节点, /dev下*/
    muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
    printk("chartext_init\n");
    return 0;

}


static int platform_driver_init(void){
    int ret;
    ret = platform_driver_register(&ZCY_platform_driver);
    if(ret < 0){
        printk("platform_driver_register error!\n");
        return 0;
    }
    printk("platform_driver_init is ok!\n");
    return 0;
}

static void platform_driver_exit(void){
    platform_driver_unregister(&ZCY_platform_driver);
    unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
    cdev_del(&muqing_cdev);                        //删除设备
    device_destroy(muqing_class,char_dev);        //注销设备
    class_destroy(muqing_class);                //删除类
    *gpio5_1 &= ~(1 << 1);
    printk("bye bye!!!\n");
}


module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");

platform_device.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/platform_device.h>
#include <linux/ioport.h>

struct resource ZCY_resource[]={  //描述资源结构体
[0] = {    .start = 0x20AC000,      //设备起始地址
        .end   = 0x20AC003,      //设备结束地址
        .name = "GPIO5_DR",      //资源名
        .flags = IORESOURCE_MEM, //标志(物理地址)
      }
};

void platform_device_release(struct device *dev){

}

struct platform_device ZCY_platform={   //描述设备结构体
    .name = "ZCY_platform",               //platform 设备名,用来和驱动相匹配
    .id = 1,                            //号码,防止设备名相同
    .dev={
        .release = platform_device_release,
    },    
    .num_resources = ARRAY_SIZE(ZCY_resource),    //资源结构体数量
    .resource = ZCY_resource,                   //资源结构体名
};


static int platform_driver_init(void){
    int ret;
    ret = platform_device_register(&ZCY_platform);  //注册platform设备
    if(ret < 0){   
        printk("platform_device_register error!\n");
        return 0;
    }
    printk("platform_driver_init is ok!\n");
    return 0;
}

static void platform_driver_exit(void){
    platform_device_unregister(&ZCY_platform);    //注销
    printk("bye bye!!!\n");
}


module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");

app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int fd;
    int i;
    char buf[64] = {0};
    /*char writebuf[64]  = "1";
    char writebuf1[64] = "0";*/
    fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
    if( fd < 0 ){
        perror("open error\n");
        return fd;
    }
    read(fd,buf,sizeof(buf));
    printf("read buf id %s\n",buf);

    write(fd,argv[1],1); 
    close(fd);
    return 0;

}

设备树实践:

device_tree.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/fs.h>           //文件操作集合
#include <linux/uaccess.h>      //copy_to_user的头文件
#include <linux/kdev_t.h>       //MKDEV所需要的头文件
#include <linux/cdev.h>         //cdev结构体以及cdev-init
#include <linux/device.h>       //class_create,device_create
#include <linux/io.h>            //寄存器
#include <linux/of.h>
#include <linux/of_address.h>

//struct device_node    //设备节点结构体
//struct property       //设备属性结构体

static int chardev_register(void);

dev_t char_dev;        
struct resource * acadada;

struct cdev    muqing_cdev;        //cdev结构体用来表示字符设备
struct class  *muqing_class;    //class类
struct device *muqing_device;    //device设备结构体
#define NUMCHAR  2

#define GPIO5_DR 0x20AC000        //蜂鸣器Io物
unsigned int* gpio5_1;            //虚拟地址
#define SIZEBEY  4                //寄存器字节

struct device_node *ZCY_device_nota;
struct property *ZCY_property;

u32 out_values[2] = {0};
unsigned int *addrZCY;


int ZCY_device_tree_probe(struct platform_device *pdev){
    ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
    if(ZCY_device_nota == NULL){
        printk("of_find_node_by_path error!\n");
        return 0;
-    }
    printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);

/********************************查找属性  的OF函数***************************************************/
    ZCY_property = of_find_property(ZCY_device_nota, "compatible", 0);  // 查找指定属性的OF函数
    if(ZCY_property == NULL){
        printk("of_find_property error!\n");
        return 0;
    }
    printk("of_find_property name is: %s\n",(char *)ZCY_property->value);

    of_property_read_u32_array(ZCY_device_nota, "reg", out_values, 2);  //读取32位reg属性值

    printk("of_property_read_u32_array value is: 0x%x\n",out_values[0]);

    addrZCY = of_iomap(ZCY_device_nota, 0);
    if(addrZCY == NULL){
        printk("of_iomap is error!\n");
        return 0;
    }
    printk("of_iomap is ok!\n");
    chardev_register();
    
    return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){


    printk("ZCY_device_tree_remove is ok!\n");
    return 0;
}

const struct of_device_id    ZCY_of_match_table[] = {
    {
    .compatible = "tree_test"
    },

};


const struct platform_device_id ZCY_id_table={
    .name = "ZCY_platform",
};


struct platform_driver ZCY_platform_driver={
    .probe  = ZCY_device_tree_probe,
    .remove = ZCY_device_tree_remove,
    .driver={
        .name = "ZCY_platform",
        .owner = THIS_MODULE,
        .of_match_table = ZCY_of_match_table,
    },
    .id_table = &ZCY_id_table,
};

/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = "Hello Word";
    printk("Hello chartext_read\n");
     
    if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
        printk("hd_fops_release error\n");
        return 0;
    }
    return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = {0};
    printk("Hello chartext_write\n");
    
    if( copy_from_user(kbuf,ubuf,size) != 0 ){
        printk("chartext_write error\n");
        return 0;
    }
    if( kbuf[0] == '1' ){
        *gpio5_1 |= (1 << 1);
    }else if( kbuf[0] == '0' ){
        *gpio5_1 &= ~(1 << 1);
    }
    printk("chartext_write urse is %s\n",kbuf);
    return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
    printk("Hello chartext_open\n");
    
    return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
    printk("Hello chartext_release\n");
    
    return 0;
}


struct file_operations chartext_fops={    //文件操作集合
    .owner   = THIS_MODULE,
    .read    = chartext_read,
    .write   = chartext_write,
    .open    = chartext_open,
    .release = chartext_release,
};

static int chardev_register(void){
    int ret;
    /*动态注册设备号*/
    ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
    if( ret != 0 ){
        printk("alloc_chrdev_region: register_chrdev_region error!!\n");
        return ret;
    }
    printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
    printk("MAJOR %d\n\n",MAJOR(char_dev));
    printk("MINOR %d\n\n",MINOR(char_dev));
    
    /*内存映射*/
    gpio5_1 = ioremap(GPIO5_DR, SIZEBEY);
    if( gpio5_1 == NULL ){
        printk("ioremap error3!!\n");
        return 0;
    }
    printk("ioremap ok3!!\n");
    
    /*初始化cdev*/
    muqing_cdev.owner = THIS_MODULE;
    cdev_init(&muqing_cdev,&chartext_fops);
    /*向内核注册设备*/
    cdev_add(&muqing_cdev,char_dev,NUMCHAR);
    /*创建类 ,在、sys/class下*/
    muqing_class  = class_create(THIS_MODULE, "lcdclass");
    /*自动创建设备节点, /dev下*/
    muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
    printk("chartext_init\n");
    return 0;

}


static int device_tree_init(void){
    int ret;
    ret = platform_driver_register(&ZCY_platform_driver);
    if(ret < 0){
        printk("platform_driver_register error!\n");
        return 0;
    }
    printk("platform_driver_init is ok!\n");
    return 0;
}

static void device_tree_exit(void){
    platform_driver_unregister(&ZCY_platform_driver);
    unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
    cdev_del(&muqing_cdev);                        //删除设备
    device_destroy(muqing_class,char_dev);        //注销设备
    class_destroy(muqing_class);                //删除类
    *gpio5_1 &= ~(1 << 1);
    printk("bye bye!!!\n");
}


module_init(device_tree_init);
module_exit(device_tree_exit);
MODULE_LICENSE("GPL");

app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int fd;
    int i;
    char buf[64] = {0};
    /*char writebuf[64]  = "1";
    char writebuf1[64] = "0";*/
    fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
    if( fd < 0 ){
        perror("open error\n");
        return fd;
    }
    read(fd,buf,sizeof(buf));
    printf("read buf id %s\n",buf);

    write(fd,argv[1],1); 
    close(fd);
    return 0;

}

?????????

devicetree_GPIO.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/fs.h>           //文件操作集合
#include <linux/uaccess.h>      //copy_to_user的头文件
#include <linux/kdev_t.h>       //MKDEV所需要的头文件
#include <linux/cdev.h>         //cdev结构体以及cdev-init
#include <linux/device.h>       //class_create,device_create
#include <linux/io.h>            //寄存器
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>

//struct device_node    //设备节点结构体
//struct property       //设备属性结构体

static int chardev_register(void);

int ret;  //用来判断返回值


dev_t char_dev;        

struct cdev    muqing_cdev;        //cdev结构体用来表示字符设备
struct class  *muqing_class;    //class类
struct device *muqing_device;    //device设备结构体
#define NUMCHAR  1

struct device_node *ZCY_device_nota;
struct property *ZCY_property;

u32 out_values[2] = {0};


int GPIO5_1;  //申请的GPIO标号
char *GPIO_beep;//给申请出的GPIO的名字


int ZCY_device_tree_probe(struct platform_device *pdev){
    ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
    if(ZCY_device_nota == NULL){
        printk("of_find_node_by_path error!\n");
        return 0;
    }
    printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);

/********************************查找属性  的OF函数***************************************************/
    ZCY_property = of_find_property(ZCY_device_nota, "compatible", 0);  // 查找指定属性的OF函数
    if(ZCY_property == NULL){
        printk("of_find_property error!\n");
        return 0;
    }
    printk("of_find_property name is: %s\n",(char *)ZCY_property->value);

    of_property_read_u32_array(ZCY_device_nota, "reg", out_values, 2);  //读取32位reg属性值

    printk("of_property_read_u32_array value is: 0x%x\n",out_values[0]);

    GPIO5_1 = of_get_named_gpio(ZCY_device_nota, "gpios", 0);//从设备树中获取GPIO标号
    if(GPIO5_1 < 0){
        printk("of_get_named_gpio is error!\n");
        return 0;
    }
    printk("of_get_named_gpio is OK!\n");

    ret = gpio_request(GPIO5_1, GPIO_beep);   //申请GPIO管脚
    if(ret != 0){
        printk("gpio_request is error!\n");
    }
    printk("gpio_request is OK!\n");

    ret = gpio_direction_output(GPIO5_1, 0);  //将申请的GPIO管脚设置为输出,默认输出位0
    if(ret < 0){
        printk("gpio_direction_output is reeor!\n");
        return 0;
    }
    printk("gpio_direction_output is OK!\n");

    //__gpio_set_value(unsigned gpio, int value);   //设置GPIO管脚的值

    gpio_free(GPIO5_1);     //释放标号为GPIO5_1的GPIO管脚

    chardev_register();
    
    return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){

    printk("ZCY_device_tree_remove is ok!\n");
    return 0;
}

const struct of_device_id    ZCY_of_match_table[] = {
    {
    .compatible = "tree_test"
    },

};


const struct platform_device_id ZCY_id_table={
    .name = "ZCY_platform",
};


struct platform_driver ZCY_platform_driver={
    .probe  = ZCY_device_tree_probe,
    .remove = ZCY_device_tree_remove,
    .driver={
        .name = "ZCY_platform",
        .owner = THIS_MODULE,
        .of_match_table = ZCY_of_match_table,
    },
    .id_table = &ZCY_id_table,
};

/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = "Hello Word";
    printk("Hello chartext_read\n");
     
    if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
        printk("hd_fops_release error\n");
        return 0;
    }
    return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = {0};
    printk("Hello chartext_write\n");
    
    if( copy_from_user(kbuf,ubuf,size) != 0 ){
        printk("chartext_write error\n");
        return 0;
    }

    if( kbuf[0] == '1' ){
        gpio_set_value(GPIO5_1, 1);   //设置GPIO管脚的值
    }else if( kbuf[0] == '0' ){
        gpio_set_value(GPIO5_1, 0);   //设置GPIO管脚的值
    }
    printk("chartext_write urse is %s\n",kbuf);
    
    return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
    printk("Hello chartext_open\n");
    
    return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
    printk("Hello chartext_release\n");
    
    return 0;
}


struct file_operations chartext_fops={    //文件操作集合
    .owner   = THIS_MODULE,
    .read    = chartext_read,
    .write   = chartext_write,
    .open    = chartext_open,
    .release = chartext_release,
};

static int chardev_register(void){
    
    /*动态注册设备号*/
    ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
    if( ret != 0 ){
        printk("alloc_chrdev_region: register_chrdev_region error!!\n");
        return ret;
    }
    printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
    printk("MAJOR %d\n\n",MAJOR(char_dev));
    printk("MINOR %d\n\n",MINOR(char_dev));
    
    /*初始化cdev*/
    muqing_cdev.owner = THIS_MODULE;
    cdev_init(&muqing_cdev,&chartext_fops);
    printk("01\n");
    /*向内核注册设备*/
    cdev_add(&muqing_cdev,char_dev,NUMCHAR);
    printk("02\n");
    /*创建类 ,在、sys/class下*/
    muqing_class  = class_create(THIS_MODULE, "lcdclass");
    printk("03\n");
    /*自动创建设备节点, /dev下*/
    muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
    printk("chartext_init\n");
    return 0;

}


static int device_tree_init(void){
    int ret;
    ret = platform_driver_register(&ZCY_platform_driver);
    if(ret < 0){
        printk("platform_driver_register error!\n");
        return 0;
    }
    printk("platform_driver_init is ok!\n");
    return 0;
}

static void device_tree_exit(void){
    platform_driver_unregister(&ZCY_platform_driver);
    unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
    cdev_del(&muqing_cdev);                        //删除设备
    device_destroy(muqing_class,char_dev);        //注销设备
    class_destroy(muqing_class);                //删除类
    gpio_set_value(GPIO5_1, 0);
    printk("bye bye!!!\n");
}


module_init(device_tree_init);
module_exit(device_tree_exit);
MODULE_LICENSE("GPL");

app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int fd;
    fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
    if( fd < 0 ){
        perror("open error\n");
        return fd;
    }

    write(fd,argv[1],1); 
    close(fd);
    return 0;

}

test:

device_tree_led_test.c:

#include <linux/module.h>        //模块的相关头文件
#include <linux/init.h>            //初始化的相关头文件
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/fs.h>           //文件操作集合
#include <linux/uaccess.h>      //copy_to_user的头文件
#include <linux/kdev_t.h>       //MKDEV所需要的头文件
#include <linux/cdev.h>         //cdev结构体以及cdev-init
#include <linux/device.h>       //class_create,device_create
#include <linux/io.h>            //寄存器
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>

//struct device_node    //设备节点结构体
//struct property       //设备属性结构体

static int chardev_register(void);

int ret;  //用来判断返回值


dev_t char_dev;        

struct cdev    muqing_cdev;        //cdev结构体用来表示字符设备
struct class  *muqing_class;    //class类
struct device *muqing_device;    //device设备结构体
#define NUMCHAR  1

struct device_node *ZCY_device_nota;
struct property *ZCY_property;

u32 out_values[2] = {0};


int GPIO1_20;  //申请的GPIO标号
char *GPIO_led1;//给申请出的GPIO的名字


int ZCY_device_tree_probe(struct platform_device *pdev){
    ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
    if(ZCY_device_nota == NULL){
        printk("of_find_node_by_path error!\n");
        return 0;
    }
    printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);


    GPIO1_20 = of_get_named_gpio(ZCY_device_nota, "gpio1", 0);//从设备树中获取GPIO标号
    if(GPIO1_20 < 0){
        printk("of_get_named_gpio is error!\n");
        return 0;
    }
    printk("of_get_named_gpio is OK!\n");

    ret = gpio_request(GPIO1_20, "pinctrl_led");   //申请GPIO管脚
    if(ret != 0){
        printk("gpio_request is error!\n");
    }
    printk("gpio_request is OK!\n");

    ret = gpio_direction_output(GPIO1_20, 0);  //将申请的GPIO管脚设置为输出,默认输出位0
    if(ret < 0){
        printk("gpio_direction_output is reeor!\n");
        return 0;
    }
    printk("gpio_direction_output is OK!\n");

    //__gpio_set_value(unsigned gpio, int value);   //设置GPIO管脚的值

    gpio_free(GPIO1_20);     //释放标号为GPIO5_1的GPIO管脚

    chardev_register();
    
    return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){

    printk("ZCY_device_tree_remove is ok!\n");
    return 0;
}

const struct of_device_id    ZCY_of_match_table[] = {
    {
    .compatible = "tree_test"
    },

};


const struct platform_device_id ZCY_id_table={
    .name = "ZCY_platform",
};


struct platform_driver ZCY_platform_driver={
    .probe  = ZCY_device_tree_probe,
    .remove = ZCY_device_tree_remove,
    .driver={
        .name = "ZCY_platform",
        .owner = THIS_MODULE,
        .of_match_table = ZCY_of_match_table,
    },
    .id_table = &ZCY_id_table,
};

/*读取*/
ssize_t chartext_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = "Hello Word";
    printk("Hello chartext_read\n");
     
    if( copy_to_user(ubuf,kbuf,strlen(kbuf)) != 0 ){
        printk("hd_fops_release error\n");
        return 0;
    }
    return 0;
}
/*写*/
ssize_t chartext_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t){
    char kbuf[64] = {0};
    printk("Hello chartext_write\n");
    
    if( copy_from_user(kbuf,ubuf,size) != 0 ){
        printk("chartext_write error\n");
        return 0;
    }

    if( kbuf[0] == '1' ){
        gpio_set_value(GPIO1_20, 1);   //设置GPIO管脚的值
    }else if( kbuf[0] == '0' ){
        gpio_set_value(GPIO1_20, 0);   //设置GPIO管脚的值
    }
    printk("chartext_write urse is %s\n",kbuf);
    
    return 0;
}
/*打开*/
int chartext_open (struct inode *inode, struct file *file){
    printk("Hello chartext_open\n");
    
    return 0;
}
/*关闭*/
int chartext_release (struct inode *inode, struct file *file){
    printk("Hello chartext_release\n");
    
    return 0;
}


struct file_operations chartext_fops={    //文件操作集合
    .owner   = THIS_MODULE,
    .read    = chartext_read,
    .write   = chartext_write,
    .open    = chartext_open,
    .release = chartext_release,
};

static int chardev_register(void){
    
    /*动态注册设备号*/
    ret = alloc_chrdev_region(&char_dev,0,NUMCHAR,"alloclcddevice");
    if( ret != 0 ){
        printk("alloc_chrdev_region: register_chrdev_region error!!\n");
        return ret;
    }
    printk("alloc_chrdev_region: register_chrdev_region ok!!\n");
    printk("MAJOR %d\n\n",MAJOR(char_dev));
    printk("MINOR %d\n\n",MINOR(char_dev));
    
    /*初始化cdev*/
    muqing_cdev.owner = THIS_MODULE;
    cdev_init(&muqing_cdev,&chartext_fops);
    printk("01\n");
    /*向内核注册设备*/
    cdev_add(&muqing_cdev,char_dev,NUMCHAR);
    printk("02\n");
    /*创建类 ,在、sys/class下*/
    muqing_class  = class_create(THIS_MODULE, "lcdclass");
    printk("03\n");
    /*自动创建设备节点, /dev下*/
    muqing_device = device_create(muqing_class,NULL,char_dev,NULL,"lcddevice");
    printk("chartext_init\n");
    return 0;

}


static int device_tree_init(void){
    int ret;
    ret = platform_driver_register(&ZCY_platform_driver);
    if(ret < 0){
        printk("platform_driver_register error!\n");
        return 0;
    }
    printk("platform_driver_init is ok!\n");
    return 0;
}

static void device_tree_exit(void){
    platform_driver_unregister(&ZCY_platform_driver);
    unregister_chrdev_region(char_dev,NUMCHAR); //注销设备号
    cdev_del(&muqing_cdev);                        //删除设备
    device_destroy(muqing_class,char_dev);        //注销设备
    class_destroy(muqing_class);                //删除类
    gpio_set_value(GPIO1_20, 0);
    printk("bye bye!!!\n");
}


module_init(device_tree_init);
module_exit(device_tree_exit);
MODULE_LICENSE("GPL");

app.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int fd;
    fd = open("/dev/lcddevice",O_RDWR);//打开设备节点
    if( fd < 0 ){
        perror("open error\n");
        return fd;
    }

    write(fd,argv[1],1); 
    close(fd);
    return 0;

}

中断:

ZCY_interrupt.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>

//struct device_node    //设备节点结构体
//struct property       //设备属性结构体


int ret;  //用来判断返回值

struct device_node *ZCY_device_nota;//设备树节点
struct property *ZCY_property;         //设备树属性

int GPIO5_1;  //申请的GPIO标号
char *GPIO_beep;//给申请出的GPIO起一个名字

struct tasklet_struct ZCY_beep_tasklet;  //定义tasklet结构体

int irq_num;//中断号
/*
struct timer_list Mytimer; //定时器相关结构体

static int timer_init(void){   //定时器初始化
    init_timer(&Mytimer);
    Mytimer.expires   = jiffies + 1*HZ; //超时时间(定时器到时时间)
    Mytimer.data      = jiffies + 1*HZ; //要传入function函数的参数
    Mytimer.function  = Hello_World;    //function要执行的函数(定时器到时要执行的函数)
    add_timer(&Mytimer); //将定时器注册到内核,开启定时器
    return 0;
}

static void Hello_World(unsigned long arg){
    if( i % 2 == 1 ){
        *gpio5_1 |= (1 << 1);
    }else if( i % 2 == 0 ){
        *gpio5_1 &= ~(1 << 1);
    }
    
    i++;
    arg = jiffies + 1*HZ;
    printk("Hello World!!!\n");
    printk("receive timer data: %ld\n",arg);
    mod_timer(&Mytimer,arg);
}*/


irqreturn_t ZCY_beep_func(int irq,void *dev){   //中断函数
    printk("start\n");
    gpio_set_value(GPIO5_1,0);
    tasklet_schedule(&ZCY_beep_tasklet);
    printk("end\n");
    return IRQ_HANDLED;
}

void tasklet_func(unsigned long data){   //中断下文函数
    int i = data;
    printk("i is %d \n", i);
    while (i--)
    printk("ZCY_beep_func is %d \n", i);
}

int ZCY_device_tree_probe(struct platform_device *pdev){
    //匹配成功后进入probe函数
    ZCY_device_nota = of_find_node_by_path("/test"); //获得设备树文件节点资源函数
    if(ZCY_device_nota == NULL){
        printk("of_find_node_by_path error!\n");
        return 0;
    }
    printk("of_find_node_by_path name is: %s\n",ZCY_device_nota->name);

    GPIO5_1 = of_get_named_gpio(ZCY_device_nota, "gpios", 0);//从设备树中获取GPIO标号
    if(GPIO5_1 < 0){
        printk("of_get_named_gpio is error!\n");
        return 0;
    }
    printk("of_get_named_gpio is OK!\n");

    ret = gpio_request(GPIO5_1, GPIO_beep);   //申请GPIO管脚
    if(ret != 0){
        printk("gpio_request is error!\n");
    }
    printk("gpio_request is OK!\n");
    
    /*
    gpio_direction_input(GPIO5_1);

    gpio_set_value(GPIO5_1,0);*/
    
    ret = gpio_direction_output(GPIO5_1, 0);  //将申请的GPIO管脚设置为输出,默认输出位0
    if(ret < 0){
        printk("gpio_direction_output is reeor!\n");
        return 0;
    }
    printk("gpio_direction_output is OK!\n");


    /***********************************中断*********************************/
    
    irq_num = gpio_to_irq(GPIO5_1);    //通过GPIO标号获得中断号
    if(irq_num == 0){
        printk("gpio_to_irq is error!!!\n");
        return 0;
        }
    /*
    irq_num = irq_of_parse_and_map(ZCY_device_nota,0);//从设备树属性中提取中断号
    if(irq_num < 0){
        printk("gpio_to_irq is error!!!\n");
        return 0;
        }*/
    printk("irq_num is :%d\n",irq_num);

    ret = request_irq(irq_num,ZCY_beep_func,IRQF_TRIGGER_HIGH,"ZCY_interrupt",NULL);    //申请中断函数
    if(ret < 0){
        printk("request_irq is error!!!\n");
        return 0;
    }
    printk("request_irq is OK!\n");

    enable_irq(irq_num);  //中断使能函数

    tasklet_init(&ZCY_beep_tasklet,tasklet_func,100);   //初始化tasklet
    
    //__gpio_set_value(unsigned gpio, int value);   //设置GPIO管脚的值
    printk("GPIO5_1 is :%d\n",gpio_get_value(GPIO5_1));

    gpio_set_value(GPIO5_1,1);
    
    printk("GPIO5_1 is :%d\n",gpio_get_value(GPIO5_1));
    gpio_set_value(GPIO5_1,0);
    

    
    
    return 0;
}
int ZCY_device_tree_remove(struct platform_device *pdev){

    printk("ZCY_device_tree_remove is ok!\n");
    return 0;
}

const struct of_device_id    ZCY_of_match_table[] = {  //设备树属性
    {
    .compatible = "tree_test"
    },

};

const struct platform_device_id ZCY_id_table={
    .name = "ZCY_platform",
};


struct platform_driver ZCY_platform_driver={
    .probe  = ZCY_device_tree_probe,
    .remove = ZCY_device_tree_remove,
    .driver={
        .name = "ZCY_platform",
        .owner = THIS_MODULE,
        .of_match_table = ZCY_of_match_table,   //要进行匹配的设备树属性
    },
    .id_table = &ZCY_id_table,
};

static int device_tree_init(void){    //驱动入口函数
    int ret;
    ret = platform_driver_register(&ZCY_platform_driver);
    if(ret < 0){
        printk("platform_driver_register error!\n");
        return 0;
    }
    printk("platform_driver_init is ok!\n");
    return 0;
}

static void device_tree_exit(void){   //驱动出口函数
    free_irq(irq_num,NULL);
    tasklet_kill(&ZCY_beep_tasklet);
    gpio_set_value(GPIO5_1, 0);

    gpio_free(GPIO5_1);     //释放标号为GPIO5_1的GPIO管脚
    platform_driver_unregister(&ZCY_platform_driver);
    printk("bye bye!!!\n");
}

module_init(device_tree_init);//驱动入口函数
module_exit(device_tree_exit);//驱动出口函数
MODULE_LICENSE("GPL");

知识点

编程语言:精通 C 语言,熟悉 C++。
硬件接口:熟练掌握 IIC、SPI、串口、单总线等各种通信协议,使硬件外设与单片机可进行正常数据交互。
软件工具:Keil uVision5, VMware Workstation Pro,Source Insight,Xshell,secureCRT,串口调试助
手等软件工具均熟练掌握。
熟练移植 uboot,裁剪 kernel,制作文件系统,了解 Device tree;
熟练使用 buildroot/buybox 制作根文件系统,kernel 编译与裁剪;
模块的动态编译以及静态编译到内核,Makefile 简单语法;
熟练掌握字符设备,platform 平台总线,设备树,定时器 timer,中断 interrupt\软中断之上下文 tasklet,pinctrl
子系统,ioctrl,gpio 子系统驱动编写;
掌握常用外设驱动开发,LED,GPIO,按键,键盘,beep,wifi 驱动移植,RGB_lcd 屏幕,tp 触摸电容屏驱动;
熟练掌握 LCD(framebuffe)框架,并能进行修改调试;
熟练掌握 input 子系统框架,iic 总线驱动框架,spi 驱动框架
内核 logo 更改,u 盘/TF 卡的自动挂载,开机程序自启动;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值