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结果:
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值