当前位置: 首页 > news >正文

建设项目环保竣工验收备案网站/seo免费教程

建设项目环保竣工验收备案网站,seo免费教程,网站制作先学什么,php网站日历选择日期怎么做最近学习字符设备驱动,其大致的框架与流程都基本搞懂了,为了方便以后代码重用,写了一个较为完善的模板, 以后如果需要写如:led、key、beep等的字符设备驱动,就不需要从O开始,可以直接用来修改调…

 

最近学习字符设备驱动,其大致的框架与流程都基本搞懂了,为了方便以后代码重用,写了一个较为完善的模板,
以后如果需要写如:led、key、beep等的字符设备驱动,就不需要从O开始,可以直接用来修改调试,
代码中有比较清晰的注释,以及错误处理与回收机制,并且经过了初步测试,是通过的

该模板的作用:编译生成.ko文件后,通过insmod *.ko加载模块,会自动在/dev目录下生成相应的设备文件,模板中设备文件名称为firdev,
同样,卸载模块时会自动将其删除,这主要是device与class这两个结构体的功劳,代码中都有注释...

// 驱动模板
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>

#define CHRDEV_CNT                1
#define CHRDEV_NAME                "firdev"

/* 自定义字符设备结构体 */
struct chr_dev {
        dev_t devnum;                        //设备号
        struct cdev *pcdev;                //cdev
        struct class *class;                //类
        struct device *device;                //设备
};
struct         chr_dev firdev;
char         kernel_buf[512];
/*
  * @brief  文件打开函数
  * @param  inode : 传递给驱动的inode
                        file  : 要打开的设备文件       
  * @retval 0 成功, 其他 失败
  */
static int chrdev_open(struct inode *inode, struct file *file)
{
        filp->private_data = &firdev;                 //设置私有数据
        printk(KERN_INFO "chrdev_open\n");
        return 0;
}
/*
  * @brief  文件关闭函数
  * @param  inode : 传递给驱动的inode
                        file  : 要关闭的设备文件       
  * @retval 0 成功, 其他 失败
  */
static int chrdev_release(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "chrdev_release\n");
        return 0;
}
/*
  * @brief  读函数, 将内核中的数据拷贝到应用层
  * @param  file: 要打开的设备文件
                        buf : 返回给用户空间的数据缓冲区
                        cnt : 要读取的数据长度
                        offt: 相对于文件首地址的偏移       
  * @retval 读取的字节数, 负值表示读取失败
  */
ssize_t chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{
        int ret = -1;
        printk(KERN_INFO "chrdev_read\n");
        //一定要用如下拷贝函数, 不信你试试别的
        ret = copy_to_user(ubuf, kernel_buf, count);
        if (ret) {
                printk(KERN_ERR "copy_to_user fail\n");
                return -EINVAL;
        }
        printk(KERN_INFO "copy_to_user success...:%s\n", kernel_buf);
       
        return 0;
}
/*
  * @brief  写函数, 将应用层传递过来的数据复制到内核中
  * @param  filp: 打开的文件描述符
                        buf : 要写给设备写入的数据
                        cnt : 要写入的数据长度
                        offt: 相对于文件首地址的偏移       
  * @retval 写入的字节数, 负值表示写入失败
  */
static ssize_t chrdev_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
{
        int ret = -1;
       
        printk(KERN_INFO "chrdev_write\n");
        //一定要用如下拷贝函数, 不信你试试别的
        ret = copy_from_user(kernel_buf, ubuf, count);
       
        if (ret) {
                printk(KERN_ERR "copy_from_user fail\n");
                return -EINVAL;
        }
        printk(KERN_INFO "copy_from_user success...:%s\n", kernel_buf);
       
        return 0;
}

//文件操作结构体, 外部操作此模块的接口, 需要我们填充
//.owner:指向拥有这个结构的模块的指针,用来在它的操作还在被使用时阻止模块被卸载
static struct file_operations chrdev_fops = {
        .owner                 = THIS_MODULE,
        //应用层间接调用的就是如下接口
        .open                = chrdev_open,                //打开设备时调用
        .release        = chrdev_release,        //关闭设备时调用
        .write                 = chrdev_write,                //写设备操作
        .read                = chrdev_read,                //读设备操作
};

static int __init chrdev_init(void)
{
        int ret;
        // 1.分配设备号
        ret = alloc_chrdev_region(&firdev.devnum, 0, CHRDEV_CNT, CHRDEV_NAME);
        if(ret < 0) {
                printk(KERN_ERR "alloc_chrdev_region fail\n");
                goto tag1; //如果执行到这里, 可以直接返回
        }
        printk(KERN_INFO "major = %d, minor = %d.\n", MAJOR(firdev.devnum), MINOR(firdev.devnum));
       
        // 2.初始化cdev, 并添加到系统
        // cdev绑定file_operations与dev_t, 添加进系统从而产生了联系
        firdev.pcdev = cdev_alloc();       
        //firdev.pcdev->owner = THIS_MODULE;
        //firdev.pcdev->ops = &chrdev_fops;                //将cdev和file_operations进行绑定
        cdev_init(firdev.pcdev, &chrdev_fops);//这条语句可代替上面两条语句
        ret = cdev_add(firdev.pcdev, firdev.devnum, CHRDEV_CNT);//将cdev结构体加入到系统中去
        if (ret) {
                printk(KERN_ERR "Unable to cdev_add\n");
                goto tag2;//如果执行到这里, 说明前面设备号分配成功了, 需要释放掉
        }
        printk(KERN_INFO "cdev_add success\n");
       
        // 3.创建类
        // 注册字符设备驱动完成后, 添加设备类的操作, 让内核帮我们发信息
        // 给udev,让udev自动创建和删除设备文件
        firdev.class = class_create(THIS_MODULE, CHRDEV_NAME);
        if (IS_ERR(firdev.class)) {
                goto tag3;//如果执行到这里, 说明设备号与cdev都分配成功了, 需要释放掉
        }
       
        // 4.创建设备
        // 最后1个参数字符串,就是我们将来要在/dev目录下创建的设备文件的名字
        // 所以我们这里要的文件名是/dev/firdev
        firdev.device = device_create(firdev.class, NULL, firdev.devnum, NULL, CHRDEV_NAME);
        if (IS_ERR(firdev.device)) {
                goto tag3;
        }
        return 0;
       
tag3:
        cdev_del(firdev.pcdev);
tag2:
        unregister_chrdev_region(firdev.devnum, CHRDEV_CNT);
tag1:       
        return -EINVAL;
}

//模块卸载函数, 注销要跟创建时倒着来
static void __exit chrdev_exit(void)
{
        // 销毁设备,即把创建的设备文件删掉
        device_destroy(firdev.class, firdev.devnum);
        // 销毁类,释放资源
        class_destroy(firdev.class);
       
        // 注销字符设备驱动结构
        cdev_del(firdev.pcdev);
        // 然后注销申请到的设备号
        unregister_chrdev_region(firdev.devnum, CHRDEV_CNT);
}

//模块加载与卸载时会调用如下接口
module_init(chrdev_init);
module_exit(chrdev_exit);

//下面这些都是跟模块相关, 需要加上才能编译
MODULE_LICENSE("GPL");                                // 模块许可证
MODULE_AUTHOR("author");                        // 模块作者
MODULE_DESCRIPTION("description");        // 模块信息
MODULE_ALIAS("alias");                                // 模块别名


//  测试代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define FILE "/dev/firdev"

int main(void)
{
        int fd = -1;
        int i = 0;
        char buf[64];
        fd = open(FILE, O_RDWR);
        if (fd < 0) {
                printf("open %s fail:%d\n",  FILE, fd);
                return -1;
        }
        printf("open %s ok\n", FILE);
       
        while(1) {
                memset(buf, 0, sizeof(buf));
                printf("input>>");
                scanf("%s", buf);
               
                if(strstr(buf, "write")) {
                        char *p = strstr(buf, ":");
                        write(fd, p+1, strlen(p));
                        printf("len:%d\n", strlen(p));
                }
                else if(!strcmp(buf, "read")) {
                        memset(buf, 0, sizeof(buf));
                        read(fd, buf, sizeof(buf));
                        printf("read str:%s\n", buf);
                }
                else if(!strcmp(buf, "clear"))
                        write(fd, 0, 1);
                else if(!strcmp(buf, "quit"))
                        break;
        }
}


//  测试结果
将驱动模板编译生成.ko文件,我的是first_drv.ko,拷贝至开发板
然后执行:insmod first_drv.ko
root@ALIENTEK-IMX6U:/mnt/ttt# insmod first_drv.ko
major = 249, minor = 0.
cdev_add success

说明模块加载成功,cat /proc/devices可看到firdev驱动,并且ls /dev可看到firdev目录,这就是自动生成的设备文件
然后测试代码测试,如下:

http://www.jmfq.cn/news/5000599.html

相关文章:

  • 搜索引擎搜不到网站/长沙哪家网络公司做网站好
  • vs做的网站排版错位/百度查重免费
  • 日本图形设计网站/网站建站教程
  • 深圳营销型网站公司电话/媒体网站
  • 网站建设的数据所有权/广告招商
  • 泗洪做网站/东莞seo优化方案
  • 电子商务网站模板/百度seo关键词优化方案
  • wordpress页面diy/谷歌seo优化推广
  • 广告营销策略有哪些/网站内容优化怎么去优化呢
  • 金华网站建设平台/外贸营销网站制作
  • 网站公安备案一般什么可以做/seo外包是什么
  • wordpress 扩展字段/关键词优化搜索排名
  • 外贸网站建设制作/市场营销网络
  • 英文网站建设企业/天津seo数据监控
  • 中国移动官方网站登录入口/企业网站优化
  • 河源市连平县建设局网站/seo的优点和缺点
  • 易居做网站/软文推广页面
  • 百度提交链接/学seo哪个培训好
  • 法院被执行人查询系统/seo产品是什么意思
  • 自己做公司网站难吗/营销网站建设都是专业技术人员
  • 做网站基本流程/seo发贴软件
  • c2c就是利用专业网站提供的电子商务平台完成交易/360搜索首页网址是多少
  • 塘厦网站仿做/手机优化大师为什么扣钱
  • 长春做网站外包/建立网站费用大概需要多少钱
  • 网站建设教学视频/网络推广整合平台
  • 做网站税费/seo外包公司报价
  • 手表网站大全/成人职业技术培训学校
  • 苏州网站建设公司电话/跨境电商平台注册开店流程
  • 东莞建设网站费用/电商详情页模板免费下载
  • 西宁的网站设计/seo优化首页