zoukankan      html  css  js  c++  java
  • 【原创】Linux应用程序完整调用自己写的字符设备驱动过程

    Linux应用程序完整调用自己写的字符设备驱动过程
     
     
    一、先写驱动程序hello.c
    实现字符驱动的打开、关闭、读、写的函数框架,加载和卸载程序入口调用
     
    通过dmesg来查看内核printk的打印
    使用makefile来编写驱动,生成ko文件
     
    lsmod查看驱动
    insmod 加载驱动
    rmmod卸载驱动
    cat /proc/devices,查看主设备号使用情况,
    在dev目录下创建hello设备节点
    mknod /dev/hello c 200 0
     
    //驱动hello.c代码

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/uaccess.h>

    static struct file_operations chardev_fops;
    #define CAHRDEV_MAJOR 200
    #define CHARDEV_NAME "hello kernel!"
    char writebuf[100];
    char readbuf[100];

    static struct file_operations chardev_fops;


    static int chardev_open(struct inode *inode, struct file *file)
    {
    printk("chrdev_open! ");
    return 0;
    }

    static int chardev_close(struct inode *inode, struct file *filp)
    {
    printk("chrdev_release! ");
    return 0;
    }

    static ssize_t chardev_read(struct file *filp, __user char *buf,size_t
    count,loff_t *ppos)
    {
    int ret = 0;
    snprintf(readbuf,sizeof(readbuf),CHARDEV_NAME);
    ret = copy_to_user(buf,readbuf,count);
    if(ret == 0)
    {
    printk("chardev_read. ");
    }
    return 0;
    }

    static ssize_t chardev_write(struct file *filp, const char __user *buf,size_t
    count,loff_t *ppos)
    {
    int ret = 0;
    ret = copy_from_user(writebuf,buf,count);
    if(ret == 0)
    {
    printk("chrdev_write is : %s ",&writebuf);
    }

    return 0;
    }

    static int hello_init(void)
    {
    int retvalue = 0;
    /* 注册字符设备驱动 */
    //cat /proc/devices,查看主设备号使用情况,
    retvalue = register_chrdev(CAHRDEV_MAJOR, CHARDEV_NAME, &chardev_fops);
    if(retvalue < 0)
    {
    /* 字符设备注册失败,自行处理 */
    printk("hello_init fail. ");

    }
    else
    {
    printk("hello world enter modules!!! ");
    }

    return 0;
    }

    static void hello_exit(void)
    {
    /* 注销字符设备驱动 */
    unregister_chrdev(CAHRDEV_MAJOR, CHARDEV_NAME);
    printk("hello world exit modules! ");
    }

    static struct file_operations chardev_fops={
    .owner = THIS_MODULE,
    .open = chardev_open,
    .read = chardev_read,
    .write = chardev_write,
    .release= chardev_close,
    };


    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("panda");

     
    二、再写应用程序helloAPP.c
    应用层调用打开、读、写、关闭字符底层驱动函数
    查看创建的节点
    ls /dev/hello -l
    应用程序调用设备驱动节点
    ./helloAPP /dev/hello
     
    //应用代码helloAPP.c

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

    //argc:应用程序参数个数
    //argv[]:具体参数内容,是字符串形式
    int main(int argc,char *argv[])
    {
    int fd = 0;
    int ret = 0;
    char *filename;
    char readbuf[100];
    char writebuf[100] = "hello APP!!!";

    filename = argv[1];

    fd = open(filename,O_RDWR);
    if(fd <0)
    {
    printf("can't open %s fail! ",filename);
    return -1;
    }
    else{
    printf("open OK! ");
    }

    ret = read(fd,readbuf,50);
    if(ret <0)
    {
    printf("can't read %s fail! ",filename);
    }
    else{
    printf("read data is: %s ",readbuf);
    }

    ret = write(fd,writebuf,50);
    if(ret <0)
    {
    printf("can't write %s fail! ",filename);
    }
    else{
    printf("write OK! ");
    }

    ret = close(fd);
    if(ret <0)
    {
    printf("can't close %s fail! ",filename);
    }else
    {
    printf("close OK! ");
    }




    printf("hello world! ");

    return 0;

    }

     
    三、最终打印内容
    应用层调用打印:

     驱动层调用打印,输入dmesg打印printk内容

    注意:
    主设备号高12位,次设备号低20位,所以请注意Linux系统中主设备号范围为 0~4095,
     
    man 1 命令查询
    man 2 系统调用查询
    man 3 库查询
    man 2 open
     

  • 相关阅读:
    static关键字用法(转载)
    浮点数资源(转)
    关于指针
    使用animate()的时候,有时候会出现移进移出的闪动问题
    要求开启密码大写提示
    如果layer层在iframe下不居中滚动
    自动适应iframe右边的高度
    jquery实现输入框实时输入触发事件代码
    使得最右边的元素右边框为0
    交互过程中封装了一些常用的函数(不断添加中)
  • 原文地址:https://www.cnblogs.com/baiduboy/p/13997612.html
Copyright © 2011-2022 走看看