Linux 驱动开发:字符设备、块设备与网络设备驱动详解

文章目录

概要

[一. 字符设备驱动](#一. 字符设备驱动)

[1.1 概念](#1.1 概念)

[1.2 主要函数](#1.2 主要函数)

[1.3 开发流程](#1.3 开发流程)

[二. 块设备驱动](#二. 块设备驱动)

[2.1 概念](#2.1 概念)

[2.2 主要函数](#2.2 主要函数)

[2.3 开发流程](#2.3 开发流程)

[三. 网络设备驱动](#三. 网络设备驱动)

[3.1 概念](#3.1 概念)

[3.2 主要函数](#3.2 主要函数)

[3.3 开发流程](#3.3 开发流程)

概要

在 Linux 系统中,设备驱动是连接硬件与操作系统的桥梁。Linux 内核支持多种类型的设备驱动,主要包括字符设备驱动、块设备驱动和网络设备驱动。本文将详细介绍这三种设备驱动的概念、特点以及开发流程。

一. 字符设备驱动

1.1 概念

字符设备是指以字节流形式进行数据读写的设备,例如键盘、鼠标、串口等。字符设备驱动的主要特点是数据按顺序访问,不支持随机访问。

1.2 主要函数

  • open():打开设备。
  • release():关闭设备。
  • read():从设备读取数据。
  • write():向设备写入数据。
  • ioctl():设备控制操作。

1.3 开发流程

  1. 定义设备结构体,包含设备号、设备名称等信息。

  2. 实现 file_operations 结构体中的操作函数。

  3. 使用 register_chrdev() 注册字符设备。

  4. 创建设备文件节点,使用 mknod 命令。

  5. 测试驱动,通过用户空间程序访问设备。

如下即为字符设备驱动开发主要函数的定义:

复制代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "my_char_device"
static int major_number;

static int device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device opened\n");
    return 0;
}

static int device_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device closed\n");
    return 0;
}

static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) {
    printk(KERN_INFO "Device read\n");
    return 0;
}

static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) {
    printk(KERN_INFO "Device write\n");
    return length;
}

static struct file_operations fops = {
    .open = device_open,
    .release = device_release,
    .read = device_read,
    .write = device_write,
};

static int __init my_char_device_init(void) {
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register char device\n");
        return major_number;
    }
    printk(KERN_INFO "Char device registered with major number %d\n", major_number);
    return 0;
}

static void __exit my_char_device_exit(void) {
    unregister_chrdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "Char device unregistered\n");
}

module_init(my_char_device_init);
module_exit(my_char_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chelsea");
MODULE_DESCRIPTION("IMX6ULL");

二. 块设备驱动

2.1 概念

块设备是指以数据块为单位进行读写的设备,例如硬盘、SSD 等。块设备驱动支持随机访问,通常用于存储设备。

2.2 主要函数

  • open():打开设备。
  • release():关闭设备。
  • read():从设备读取数据块。
  • write():向设备写入数据块。
  • ioctl():设备控制操作。

2.3 开发流程

  1. 定义设备结构体,包含设备号、设备名称等信息。

  2. 实现 block_device_operations 结构体中的操作函数。

  3. 使用 register_blkdev() 注册块设备。

  4. 创建设备文件节点,使用 mknod 命令。

  5. 测试驱动,通过用户空间程序访问设备。

如下即为块设备驱动开发主要函数的定义:

复制代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>

#define DEVICE_NAME "my_block_device"
static int major_number;
static struct gendisk *my_disk;

static int device_open(struct block_device *bdev, fmode_t mode) {
    printk(KERN_INFO "Block device opened\n");
    return 0;
}

static void device_release(struct gendisk *disk, fmode_t mode) {
    printk(KERN_INFO "Block device closed\n");
}

static struct block_device_operations fops = {
    .open = device_open,
    .release = device_release,
};

static int __init my_block_device_init(void) {
    major_number = register_blkdev(0, DEVICE_NAME);
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register block device\n");
        return major_number;
    }
    my_disk = alloc_disk(1);
    if (!my_disk) {
        unregister_blkdev(major_number, DEVICE_NAME);
        return -ENOMEM;
    }
    my_disk->major = major_number;
    my_disk->first_minor = 0;
    my_disk->fops = &fops;
    sprintf(my_disk->disk_name, "my_block_device");
    set_capacity(my_disk, 1024); // 1MB
    add_disk(my_disk);
    printk(KERN_INFO "Block device registered with major number %d\n", major_number);
    return 0;
}

static void __exit my_block_device_exit(void) {
    del_gendisk(my_disk);
    put_disk(my_disk);
    unregister_blkdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "Block device unregistered\n");
}

module_init(my_block_device_init);
module_exit(my_block_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chelsea");
MODULE_DESCRIPTION("IMX6ULL");

三. 网络设备驱动

3.1 概念

网络设备是指用于网络通信的设备,例如网卡、无线网卡等。网络设备驱动负责处理网络数据包的发送和接收。

3.2 主要函数

  • open():打开设备。
  • stop():关闭设备。
  • hard_start_xmit():发送数据包。
  • rx_handler():接收数据包。

3.3 开发流程

  1. 定义设备结构体,包含设备名称、MAC 地址等信息。

  2. 实现 net_device_ops 结构体中的操作函数。

  3. 使用 register_netdev() 注册网络设备。

  4. 配置网络设备,设置 IP 地址、子网掩码等。

  5. 测试驱动,通过用户空间程序访问设备。

如下即为网络设备驱动开发主要函数的定义:

复制代码
#include <linux/module.h>
#include <linux/netdevice.h>

#define DEVICE_NAME "my_net_device"
static struct net_device *my_net_device;

static int device_open(struct net_device *dev) {
    printk(KERN_INFO "Network device opened\n");
    netif_start_queue(dev);
    return 0;
}

static int device_stop(struct net_device *dev) {
    printk(KERN_INFO "Network device closed\n");
    netif_stop_queue(dev);
    return 0;
}

static netdev_tx_t device_start_xmit(struct sk_buff *skb, struct net_device *dev) {
    printk(KERN_INFO "Packet transmitted\n");
    dev_kfree_skb(skb);
    return NETDEV_TX_OK;
}

static struct net_device_ops netdev_ops = {
    .ndo_open = device_open,
    .ndo_stop = device_stop,
    .ndo_start_xmit = device_start_xmit,
};

static void device_setup(struct net_device *dev) {
    ether_setup(dev);
    dev->netdev_ops = &netdev_ops;
}

static int __init my_net_device_init(void) {
    my_net_device = alloc_netdev(0, DEVICE_NAME, NET_NAME_UNKNOWN, device_setup);
    if (!my_net_device) {
        return -ENOMEM;
    }
    if (register_netdev(my_net_device)) {
        free_netdev(my_net_device);
        return -1;
    }
    printk(KERN_INFO "Network device registered\n");
    return 0;
}

static void __exit my_net_device_exit(void) {
    unregister_netdev(my_net_device);
    free_netdev(my_net_device);
    printk(KERN_INFO "Network device unregistered\n");
}

module_init(my_net_device_init);
module_exit(my_net_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chelsea);
MODULE_DESCRIPTION("IMX6ULL");
相关推荐
猪脚踏浪14 小时前
linux 拷贝文件或目录到指定的位置
linux
大树881 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠1 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质1 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush41 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5201 天前
Linux 11 动态监控指令top
linux
Inhand陈工1 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
大鱼>1 天前
大语言模型+物联网:LLM理解物理世界
物联网·struts·语言模型·多模态·aiot
果丁智能1 天前
物联网智能锁赋能集中式住宿:身份核验与远程权限管控的全链路技术实践
大数据·人工智能·物联网·智能家居
酣大智1 天前
ARP代理--工作原理
运维·网络·arp·arp代理