Linux内核开发——自定义字符设备

Posted -飞鹤-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核开发——自定义字符设备相关的知识,希望对你有一定的参考价值。

1. 前言

Linux内核的驱动入门比较简单,只需要注册module_init和module_exit两个函数即可以完成最简单的驱动编译。然后就可以编译,接着将驱动文件载入系统就自动执行。

2. 普通驱动

2.1. 驱动代码

新建hello.c文件,内容如下:

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

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Mike");

static int __init hello_init(void)

        printk("Hello Mike!\\n")  ;
        return 0;


static void __exit hello_exit(void)

        printk("Exit Mike!\\n");


module_init(hello_init);
module_exit(hello_exit);

2.2. 编译

内核编译方法:

$(MAKE) -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules

参照内核编译方法编写一个Makefile:

# obj-m表示后面的内容编译为ko文件,如果有多个文件按空格分隔开添加
obj-m:=hello.o

PWD:=$(shell pwd)
KDIR=/lib/modules/$(shell uname -r)/build

# 下面利用makefile的隐式规则编译hello.o的同名hello.c文件,生链接生成ko文件
all :
        make -C $(KDIR) M=$(PWD) modules
clean :
        make -C $(KDIR) M=$(PWD) clean

2.3. 编译载入

sudo make
sudo insmod helloKo.ko
sudo rmmod helloKo

通过dmesg可以看到驱动的载入及退出。

3. 字符设备

3.1. 字符设备驱动

字符设备主要通过register_chrdev来注册,并实现file_operations中的几个基本的接口即可。

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

#define    MAJOR_NUM    250
#define    DEVICE_NAME  "hello"

int DriverOpen(struct inode *pslINode, struct file *pslFileStruct)

    printk( "hello open.\\n" );
    return(0);



ssize_t DriverWrite( struct file *pslFileStruct, const char __user *pBuffer, size_t nCount, loff_t *pOffset )

    printk( "hello write.\\n" );
    return(0);



long DriverIOControl( struct file *pslFileStruct, unsigned int uiCmd, unsigned long ulArg )

    printk(" hello ioctl.\\n" );
    return(0);



struct file_operations hello_flops = 
    .owner      = THIS_MODULE,
    .open       = DriverOpen,
    .write      = DriverWrite,
    .unlocked_ioctl = DriverIOControl
;

static int __init hello_init( void )

    int ret;

    ret = register_chrdev( MAJOR_NUM, DEVICE_NAME, &hello_flops );
    if ( ret < 0 )
    
        printk(" can't register major number.\\n" );
        return(ret);
    
    printk( " initialized.\\n" );
    return(0);



static void __exit hello_exit( void )

    printk("exit .\\n" );
    unregister_chrdev(MAJOR_NUM, DEVICE_NAME);


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

3.2. 编译安装

sudo make
sudo insmod helloKo.ko

使用lsmod命令查看安装的模块。

3.3. 生成设备文件

如果想访问某设备,则必须有对应的设备文件。驱动虽然已经载入到系统中,但是并没有对应的设备文件,这样应用程序就无法访问该驱动。Linux内核提供了mknod工具用来为驱动创建相应的设备文件。
mknod语法:

mknod DEVNAME b | c MAJOR MINOR

DEVNAME 为设备名,b|c则代码块设备或字符设备,后面则为主次版本号。
为驱动创建设备文件:

mknod /dev/hello c 250 0

执行上面的命令之后,就可以在dev目录看到hello文件,我们就可以正式访问这个字符设备了。

3.4. 测试

3.4.1. 代码

测试代码是用户态代码,主要是调用open打开驱动,并调用ioctl向驱动发起请求。编译main.cpp代码,如下:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stropts.h>
#include <string.h>
using namespace std;

int main( void )

    int fd;
    if ( (fd = open( "/dev/hello", O_RDWR ) ) < 0 )
    
        cerr << strerror( errno ) << endl;
        return(-1);
    

    ioctl(fd, 1, 0);
    close(fd);

    return(0);

3.4.2. 编译运行

g++ main.cpp -o main
sudo ./main

查看dmesg结果:

以上是关于Linux内核开发——自定义字符设备的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中用“”替换我的自定义字符?

自定义字符类

IO流自定义字符数组的拷贝。

需要一些关于自定义字符表的帮助和提示

java:打印菱形图案(传参打印的自定义字符和行数)

R语言str_flatten函数通过自定义字符连接(concatenate)字符串向量中的字符串