• Linux驱动基础


    lsmod显示模块:

    lsmod 以美观的方式列出/proc/modules的内容。

    输出为:

        Module(模块名)    Size(模块大小)   Used by(被...使用)

        在/proc/modules中相应的是:

        (模块名,模块大小,被...使用,模块地址

    insmod:加载模块

    rmmod:卸载模块

    查看模块信息:

    /proc/modules文件中列出了内核加载的所有模块的信息:

    第一列:模块名称

    第二列:模块使用的内存大小,单位是bytes

    第三列:模块被load的次数

    第四列:是否有其他模块依赖此模块,如果有,列出对应模块的名称

    第五列:模块当前的状态,live(已经加载),loading(加载中),unloading(卸载中)

    第六列:模块在内核内存中的偏移值

    代码:

    #include <linux/kernel.h>
    #include  
    #include  
    //#include
    //#include
    #include ioctl.h>  // 这个头文件可能定义了 unlocked_ioctl 的类型


    #define MY_IOCTL_CMD 0x99
    #define MY_IOCTL_TYPE 0x99

    static int Major; // 主设备号  
    static char msg[256]; // 存储消息的缓冲区  
    static char *msg_Ptr; // 当前写入的位置  

    void test(void)
    {
        return ;
    }
    EXPORT_SYMBOL(test);

    static int hello_open(struct inode *inode, struct file *file)  
    {
        test();    
        return 0;  
    }  
      
    static int hello_read(struct file *filp, char *buffer, size_t length, loff_t * offset)  
    {  
        int bytes_read = 0;  
        if (*msg_Ptr == 0) return 0; // 如果没有数据可读,返回0  
        while (length && *msg_Ptr) {  
            put_user(*(msg_Ptr++), buffer++); // 将数据复制到用户空间  
            length--;  
            bytes_read++;  
        }  
        return bytes_read;  
    }  
      
    static int hello_write(struct file *filp, const char *buff, size_t len, loff_t * off)  
    {  
        int total_written = 0;  
        while (len) {  
            char c;  
            get_user(c, buff); // 从用户空间读取数据  
            *(msg_Ptr++) = c; // 将数据写入到消息缓冲区中  
            len--;  
            total_written++;  
            buff++;  
        }  
        return total_written;  
    }  

    static long hello_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
    {
          printk("hsm ioctl");
          if (_IOC_TYPE(cmd) != 0x99)
            return -ENOTTY;
          else
              printk("ok.......");
        
          return 0;
    }

    static int hello_release(struct inode *inode, struct file *file)  
    {  
        msg_Ptr = msg; // 重置消息指针到开始位置,以便下一次写入可以从开始位置开始  
        return 0;  
    }  

    static struct file_operations hello_fops = {   
      //  .read = hello_read,    
      //  .write = hello_write,    
      //  .open = hello_open,    
      //  .release = hello_release,    
        .unlocked_ioctl = hello_ioctl, 
    }; 

    static int hello_init(void) {  
        Major = register_chrdev(0, "my_dev", &hello_fops);  
        if (Major < 0) {  
            printk(KERN_ALERT "Registering char device failed with %d\n", Major);  
            return Major;  
        }  
        printk(KERN_INFO "I was assigned major number %d. To talk to the driver, create a dev file with 'mknod /dev/my_dev c %d 0'.\n", Major, Major);  
        return 0;  
    }  
      
    static void hello_exit(void) {  
        unregister_chrdev(Major, "my_dev");  
        printk(KERN_INFO "Unregistered and removed /dev/my_dev.\n");  
    }  
      
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
     


    Makefile:

    obj-m := driver.o

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    #KERNELDIR ?= /root/linux-4.19.90-all-arch-master
    PWD       := $(shell pwd)

    default:
        $(MAKE) -C ${KERNELDIR} M=$(PWD)  modules
    clean:
        rm *.o *.ko *.symvers *.order *.mod.c .*.cmd .tmp_versions/ -rf

    insmod后创建驱动文件,mknod /dev/my_dev c 237 0

    应用:

    #include
    #include
    #include
    #include

    #define MY_DEVICE_TYPE 0x99
    #define MY_IOCTL_CMD  _IOWR (MY_DEVICE_TYPE, 0x99, unsigned long)

    int main()
    {
        int fd = open("/dev/my_dev", O_RDWR); // 替换为你的设备名  
        if (fd < 0) {  
            perror("open");  
            return -1;  
        }  
        if (ioctl(fd, MY_IOCTL_CMD, "hello") < 0) {  
            perror("ioctl");
            close(fd);  
            return -1;  
        }  
        printf("succ!\n");
        close(fd); // 别忘了关闭文件描述符!
        return -1;
    }
     

            Makefile:

    OBJ=app

    $(OBJ): app.c
        gcc app.c -o app

    .PHONY:clean

    clean:
        rm -rf app
     

    测试:

            

    调用成功。

    dmesg:

    使用dmesg显示内核打印日志:

    这样简单的驱动驱动程序就实现了。。。。

  • 相关阅读:
    Linux进阶---第五篇
    数据结构(C语言)——单链表
    【C++】undered_set与undered_map
    山洪灾害预警方案(山洪预警解决方案的组成)
    大二Web课程设计——家乡主题网页设计(web前端网页制作课作业) 四川旅游网页设计制作
    [Docker]三.Docker 部署nginx,以及映射端口,挂载数据卷
    Visual Studio Code下C/C++开发环境的配置及使用
    Elasticsearch安装
    Java基础进阶集合-Comparable接口,Comparator比较器案例
    【nowcoder】牛牛举办编程比赛、删除公共字符
  • 原文地址:https://blog.csdn.net/qq_30531921/article/details/140465153