2023年7月13日 星期四 Linux驱动作业

这篇具有很好参考价值的文章主要介绍了2023年7月13日 星期四 Linux驱动作业。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.使用platform驱动实现代码实现如下要求

a.应用程序通过阻塞的io模型来读取number变量的值
b.number是内核驱动中的一个变量
c.number的值随着按键按下而改变(按键中断)
例如number=0 按下按键number=1再次按下按键number=0d.在按下按键的时候需要同时将1ed1的状态取反
t
e.驱动中需要编写字符设备驱动f.驱动中需要自动创建设备节点
g.这个驱动需要的所有设备信息放在设备树的同一个节点中

应用程序


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
 
 int number;
int main(int argc, char const *argv[])
{
    int buf[128] = {0};
    int fd = open("/dev/myled0", O_RDWR);
    if (fd < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while (1)
    {
        read(fd,&number,sizeof(number));//读取数据
        printf("number:%d\n",number);
    }
 
    close(fd);
 
    return 0;
}

驱动程序


#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/io.h>

struct resource *res;
unsigned int irqno;
struct gpio_desc *gpiono;
struct cdev *cdev;
unsigned int major = 0;
unsigned int minor = 0; // 次设备号的起始值
dev_t devno;
struct class *cls;
struct device *dev;
// 定义等待队列头
wait_queue_head_t wq_head;
unsigned int condition = 0;
struct device_node *dnode;
int number = 0;
int i;
/*myplatform{
        compatible = "hqyj,myplatform";
        reg=<0X12345678 0X400>;
        interrupt-parent=<&gpiof>;
        interrupts=<9 0>;   //9表示引用中断父节点时的索引信息  0表示默认设置
           led1=<&gpioe 10 0>;

    };*/
// 中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{
    number = !number;
    gpiod_set_value(gpiono, !gpiod_get_value(gpiono));
    condition = 1;                   // 表示硬件数据就绪
    wake_up_interruptible(&wq_head); // 唤醒休眠的进程
    return IRQ_HANDLED;
}
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    if (sizeof(number) < size)
        size = sizeof(number);
    wait_event_interruptible(wq_head, condition); // 将进程切换为休眠

    ret = copy_to_user(ubuf, &number, size);
    if (ret)
    {
        printk("copy_tO_user filed\n");
        return -EIO;
    }
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    condition = 0; // 表示下一次硬件数据没有准备好
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 定义操作方法结构体变量并赋值
struct file_operations fops = {

    .open = mycdev_open,
    .read = mycdev_read,
    .release = mycdev_close,
};
// probe函数,匹配设备成功执行
int pdrv_probe(struct platform_device *pdev)
{
    int ret, i;
    // 初始化等待队列头
    init_waitqueue_head(&wq_head);
    // 1.分配字符设备驱动对象空间  cdev_alloc
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        printk("申请字符设备驱动对象空间失败\n");
        ret = -EFAULT;
        goto out1;
    }
    printk("字符设备驱动对象申请成功\n");
    // 2.字符设备驱动对象部分初始化  cdev_init
    cdev_init(cdev, &fops);
    // 3.申请设备号  register_chrdev_region/alloc_chrdev_region
    if (major > 0) // 静态申请设备号
    {
        ret = register_chrdev_region(MKDEV(major, minor), 3, "myled");
        if (ret)
        {
            printk("静态指定设备号失败\n");
            goto out2;
        }
    }
    else // 动态申请设备号
    {
        ret = alloc_chrdev_region(&devno, minor, 3, "myled");
        if (ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major = MAJOR(devno); // 根据设备号得到主设备号
        minor = MINOR(devno); // 根据设备号得到次设备号
    }
    printk("申请设备号成功\n");
    // 4.注册字符设备驱动对象  cdev_add()
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    // 5.向上提交目录
    cls = class_create(THIS_MODULE, "myled");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = -PTR_ERR(cls);
        goto out4;
    }
    printk("向上提交目录成功\n");
    // 6.向上提交设备节点
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if (IS_ERR(dev))
        {
            printk("向上提交节点信息失败\n");
            ret = -PTR_ERR(dev);
            goto out5;
        }
    }
    printk("向上提交设备节点信息成功\n");
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 获取设备信息
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == NULL)
    {
        printk("获取资源失败\n");
        return -ENXIO;
    }
    printk("获取资源信息成功 %x\n", res->start);
    irqno = platform_get_irq(pdev, 0);
    if (irqno < 0)
    {
        printk("获取中断资源失败\n");
        return irqno;
    }
    printk("中断类型资源为%d\n", irqno);
    // 注册中断
    ret = request_irq(irqno, myirq_handler, IRQF_TRIGGER_FALLING, "key", NULL);
    if (ret)
    {
        printk("注册驱动失败\n");
        return ret;
    }
    printk("key1中断注册成功\n");
    // 获取gpio信息
    // pdev->dev.of_node  设备树匹配之后会把设备树节点结构体首地址赋值给dev的of_node成员
    gpiono = gpiod_get_from_of_node(pdev->dev.of_node, "led1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono))
    {
        printk("解析GPIO信息失败\n");
        return -PTR_ERR(gpiono);
    }
    // 亮灯
    gpiod_set_value(gpiono, 1);
    return 0;

out5:
    for (--i; i >= 0; i--)
    {
        // 销毁上面提交的设备信息
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
out4:
    cdev_del(cdev);
out3:
    unregister_chrdev_region(MKDEV(major, minor), 3);
out2:
    kfree(cdev);
out1:
    return ret;
}
// remove 设备和驱动分离时执行
int pdrv_remove(struct platform_device *pdev)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 1.销毁设备信息  device_destroy
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    // 2.销毁目录  class_destroy
    class_destroy(cls);
    // 3.注销对象  cdev_del()
    cdev_del(cdev);
    // 4.释放设备号   unregister_chrdev_region()
    unregister_chrdev_region(MKDEV(major, minor), 3);
    // 5.释放对象空间  kfree()
    kfree(cdev);
    free_irq(irqno, 0);
    // 灭灯
    gpiod_set_value(gpiono, 0);
    // s释放gpio信息
    gpiod_put(gpiono);
    return 0;
}
// 构建设备树匹配的表
struct of_device_id oftable[] = {
    {
        .compatible = "hqyj,myplatform",
    },
    {
        .compatible = "hqyj,myplatform1",
    },
    {},
};

struct platform_driver pdrv = {
    .probe = pdrv_probe,
    .remove = pdrv_remove,
    .driver = {
        .name = "aaaaa",
        .of_match_table = oftable, // 设置设备树匹配
    },

};

// 一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

运行结果

2023年7月13日 星期四 Linux驱动作业,C语言,ARM,驱动,linux,运维,服务器文章来源地址https://www.toymoban.com/news/detail-559676.html

到了这里,关于2023年7月13日 星期四 Linux驱动作业的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2023年下学期《C语言》作业0x02-分支 XTU OJ 1068 1069 1070 1071 1072

    没有换行,不然会格式错误 取模和取余的叠加使用,可以实现取数字最后一位的要求  c语言使用布尔变量需要使用stdbool.h头文件,哪怕输入的是整数,我们定义为双精度变量存储数据其实也是可以的 

    2024年02月07日
    浏览(34)
  • 【AI视野·今日NLP 自然语言处理论文速览 第五十四期】Fri, 13 Oct 2023

    AI视野 ·今日CS.NLP 自然语言处理论文速览 Fri, 13 Oct 2023 Totally 75 papers 👉 上期速览 ✈更多精彩请移步主页 Tree-Planner: Efficient Close-loop Task Planning with Large Language Models Authors Mengkang Hu, Yao Mu, Xinmiao Yu, Mingyu Ding, Shiguang Wu, Wenqi Shao, Qiguang Chen, Bin Wang, Yu Qiao, Ping Luo 本文研究闭环任务规

    2024年02月07日
    浏览(43)
  • 【C语言编程基础】根据日期求星期(基姆拉尔森计算公式)

    任意给出一个年月日,求出是星期几。 输入:     年   月   日 输出:   0~6 星期日用 0 表示,星期一用 1 表示,星期二用 2 表示......星期六用 6 表示。 这里采用基姆拉尔森计算公式: w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7 在公式中d表示日期中的日数,m表示月份数,y表示年数

    2024年02月06日
    浏览(49)
  • Kali Linux 2023.2 修改系统语言

    一、需要解决的问题  kali 2023.2 安装完毕,操作系统默认语言为英文,为了尽快学习入门,将其操作系统默认语言更改为中文。修改完语言,对于系统使用的影响,将后续更新,如果没有影响,那就太赞了! 二、步骤 1、切换到root账号; 2、打开设置,命令:dpkg-reconfigure

    2024年02月13日
    浏览(54)
  • NNDL 作业13 优化算法3D可视化

    编程实现优化算法,并3D可视化 :   : NNDL实验 优化算法3D轨迹 鱼书例题3D版_优化算法3d展示-CSDN博客 从轨迹、速度等多个角度讲解各个算法优缺点 : :   先简述算法:  SGD(随机梯度下降):SGD是最基本的优化算法之一,它在每次更新模型参数时仅考虑单个样本的梯度。由于随

    2024年02月03日
    浏览(46)
  • 【探索 Kubernetes|作业管理篇 系列 13】StatefulSet 拓扑状态

    大家好,我是秋意零。 在上一篇中,我们讲解了 Deployment 这种无状态的控制器;而如果要部署有状态的应用,那么 Deployment 显然是达不到我们的需求的。 今天讲解的是 StatefulSet 有状态控制器。 最近搞了一个扣扣群,旨在技术交流、博客互助,希望各位大佬多多支持! 获取

    2024年02月11日
    浏览(46)
  • 【23-24 秋学期】NNDL 作业13 优化算法3D可视化

    分别画出  和  的3D图 代码如下: 分别画出  和  的3D轨迹图 (1) 结果如下:  (2) 结合3D动画,用自己的语言,从轨迹、速度等多个角度讲解各个算法优缺点 Animations that may help your intuitions about the learning process dynamics.  Left: Contours of a loss surface and time evolution of different

    2024年02月04日
    浏览(38)
  • C语言 switch语句详细讲解 简单计算器及PTA例题季节判断,今天星期几-1(switch语句实现), 数据按需处理

    (1) 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到  break  语句为止。 (2)不是每一个 case 都需要包含  break 。如果 case 语句不包含  break ,控制流将会  继续  后续的 case,直到遇到 break 为止。 (3) 上面所有 case 都无法判断结果时,可用 default 代替

    2024年02月05日
    浏览(60)
  • 农业无人机行业分析:单年内作业量突破13亿亩次

    面对我国18亿亩的耕地植保市场需求,未来我国植保无人机将依然保持快速发展态势,预计2022年我国植保无人机销量将增长至8万架。 植保无人机市场呈现爆发式增长,同时也吸引了不少企业进入,我们从2022年植保无人机企业网络热度榜中可以看出,虽然有多家企业对植保无

    2024年01月16日
    浏览(57)
  • 6.22 驱动开发作业

    字符设备驱动的内部实现有两种情况: 情况1.应用层调用open函数的内部实现: open函数的第一个参数是要打开的文件的路径,根据这个路径 虚拟文件系统层VFS 可以找到这个文件在文件系统中唯一的标识,也就是inode号,通过inode号作为索引可以找到储存在内核中的struct inode结

    2024年02月11日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包