zoukankan      html  css  js  c++  java
  • liunx驱动----点亮LED

    自动挂接根文件系统(直接从NFS启动)

    1. 修改uboot命令行

    把 bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200

    改为:
    set bootarges noinitrd root=/dev/nfs nfsroot=192.168.0.104:/home/book/work/nfs_root/first_fs ip=192.168.0.10:192.168.0.104:192.168.0.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0,115200
     
    在uboot中设置如下:
    setenv bootargs noinitrd root=/dev/nfs console=ttySAC0 nfsroot=192.168.0.104:/home/book/work/nfs_root/first_fs ip=192.168.0.3:192.168.0.104:192.168.0.1:255.255.255.0::eth0:off init=/linuxrc
    设置NFS启动参数 :
    1. 设置服务器IP,目录
    2. 设置自己的IP
     
    运行第一个驱动程序
    insmod first_drv.ko 挂载first_drv.ko
    cat /proc/devices 查看当前挂载了的驱动
     
    增加一个测试程序
     
     
    include <sys/types.h>
    include <sys/stat.h>
    include <fcntl.h>
    include <stdio.h>
     
     
    int main(int argc, char **argv)
    {
    int fd;
    int val = 1;
    fd = open("/dev/xxx", O_RDWR);//打开
    if (fd < 0)
    {
    printf("can't open!
    ");
    }
    write(fd,&val,4);//
    return 0;
    }
     
    编译测试程序
    arm-linux-gcc -o first_dev_test first_dev_test.c
    提示不能打开当前测试文件是因为不存在/dev/xxx这个文件
    所以需要创建这个设备节点
    创建设备节点使用mknod 命令
    mknod /dev/xxx c 111 0
    命令 设备节点 设备类型(字符型) 主设备号(111) 次设备号
     
     
    挂载设备 命令:insmod xxx(设备名称
    卸载设备命令:rmmod xxx(设备名称)
    查看设备命令:lsmod
    cat /proc/devices 查看当前挂载了的驱动
     
     
    自动分配主设备号
    在注册 register_chrdev函数中设备号位置填写0 系统将在自动分配设备号
    1驱动程序里面可以自动分配主设备号 也可以手动指定设备号
    1. 应用程序去打开一个open("/dev/xxx", O_RDWR); 使用 mknod /dev/xxx c 主设备号 次设备号 手动创建
    2. 使用自动创建 使用udev机制 就是busybox 中的mdev机制自动创建 (根据系统信息创设备节点)

    定义一个类和一个设备

    static struct class *firstdrv_class;
    static struct class_device *firstdrv_class_dev;
    在初始化设备时添加
    1. 使用class_create创建一个firstdrv_class类
    firstdrv_class = class_create(THIS_MODULE,"firstdrv");//创建一个 first_class 这样的一个类
    1. 使用class_device_create创建一个设备 设备节点是 xyz

    firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); //mdev 自动创建一个 /dev/xyz */

     

    int frist_drv_init(void)
    
    {
    
    major= register_chrdev(0,"frist_drv",&first_drv_fops);//注册函数(注册驱动程序) (major 主设备号 )告诉内核
    
    //主设备号 驱动名称 file_operations结构
    
     
    
    /*生成系统信息*/
    
    firstdrv_class = class_create(THIS_MODULE,"firstdrv");//创建一个 first_class 这样的一个类
    
    firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); //mdev 自动创建一个 /dev/xyz */
    
    return 0;
    
    }
    在出口函数中添加如下
    1. 使用class_device_unregister 函数来卸载 class_device_create创建的设备

    class_device_unregister(firstdrv_class_dev);

    1. 使用class_destroy 释放 掉firstdrv_class这个类

    class_destroy(firstdrv_class);

    void frist_drv_exit(void)
    {
    unregister_chrdev(major,"frist_drv");//卸载函数 卸载驱动
    class_device_unregister(firstdrv_class_dev);
    class_destroy(firstdrv_class);
    }
    实现点亮LED灯功能
     
    硬件操作
    映射虚拟地址 :使用 ioremap(off,sz) 函数 映射
    /*将设备的物理地址映射为虚拟地址*/
    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); //0x56000050 (物理 地址) 16(长度)
    gpfdat = gpfcon+1; //0x56000050+4 = 0x56000054 (物理地址) 16(长度)
    取消虚拟地址映射:iounmap(_addr);
    iounmap(gpfcon);
    iounmap(gpfcon+1);
    内核和用户之间参数传递 :
    copy_from_user的功能是从用户空间传递数据到内核空间
    对应的 copy_to_user 从内核空间传递数据到 用户空间
    copy_from_user(&val,buf,count);
     
    1. 配置 GPFCON open
    static int first_drv_open(struct inode *inode, struct file *file)
    
    {
    
    //printk("first_drv_open
    ");
    
    /*配置GPFCON 4 5 6为输出*/
    
    *gpfcon &=~((0x3<<(4*2))|(0x3<<(5*2))|(0x3<<(6*2)));//清除GPFCON 4 5 6对应位
    
    *gpfcon |= ((0x1<<(4*2))|(0x1<<(5*2))|(0x1<<(6*2)));//设置 GPFCON 4 5 6 为输出
    
    return 0;
    
    }
     
    1. 设置 GPFDAT write
    static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
    int val;
    //printk("first_drv_write
    ");
    copy_from_user(&val,buf,count);//将buf中的数据拷贝到 val中 val的值等于 *buf的前0-count的数据 copy_from_user的功能是从用户空间传递数据到内核空间
    // 对应的 copy_to_user 从内核空间传递数据到 用户空间
    if(val == 0)
    {
    *gpfdat |= ((1<<4)|(1<<5)|(1<<6));// 熄灭灯
    }
    else
    {
    *gpfdat &= ~((1<<4)|(1<<5)|(1<<6));//打开led
    }
    return 0;
    }
    使用次设备号:
    主设备号 是建立与内核的链接,次设备号 是用来给驱动使用的 

     

  • 相关阅读:
    ACM FPGA 2019 -- Reconfigurable Convolutional Kernels for Neural Networks on FPGAs 论文解读
    VLSI基础-- 第六章 时序逻辑电路
    ISSCC-2020:GANPU 论文解读
    fabric知识梳理图解
    在浏览器端获取文件的MD5值
    mysql实现随机获取几条数据的方法
    数据仓库之Data Vault模型总结
    大数据分析基础——维度模型
    ArrayList类源码解析——ArrayList动态数组的实现细节(基于JDK8)
    Java的四个标记接口:Serializable、Cloneable、RandomAccess和Remote接口
  • 原文地址:https://www.cnblogs.com/hjxzjp/p/10428662.html
Copyright © 2011-2022 走看看