Linux驱动开发13个实用案例

Linux驱动开发13个实用案例

以下为你提供20个Linux驱动开发的实用案例,涵盖字符设备驱动、块设备驱动、网络设备驱动等不同类型,包含应用场景、技巧、代码示例和操作步骤。先赞再看后评论,腰缠万贯财进门。

1. 简单字符设备驱动应用场景用于实现基本的设备文件读写操作,例如模拟一个简单的传感器设备。

技巧使用cdev结构体来注册字符设备,实现file\_operations结构体中的读写函数。

代码示例代码语言:c复制#include

#include

#include

#include

#define DEVICE\_NAME "simple\_char\_dev"

#define BUFFER\_SIZE 100

static char buffer[BUFFER\_SIZE];

static int major;

static ssize\_t simple\_read(struct file \*filp, char \_\_user \*buf, size\_t count, loff\_t \*f\_pos) {

if (\*f\_pos >= BUFFER\_SIZE)

return 0;

if (\*f\_pos + count > BUFFER\_SIZE)

count = BUFFER\_SIZE - \*f\_pos;

if (copy\_to\_user(buf, buffer + \*f\_pos, count))

return -EFAULT;

\*f\_pos += count;

return count;

}

static ssize\_t simple\_write(struct file \*filp, const char \_\_user \*buf, size\_t count, loff\_t \*f\_pos) {

if (\*f\_pos >= BUFFER\_SIZE)

return -ENOSPC;

if (\*f\_pos + count > BUFFER\_SIZE)

count = BUFFER\_SIZE - \*f\_pos;

if (copy\_from\_user(buffer + \*f\_pos, buf, count))

return -EFAULT;

\*f\_pos += count;

return count;

}

static struct file\_operations fops = {

.read = simple\_read,

.write = simple\_write,

};

static int \_\_init simple\_char\_init(void) {

major = register\_chrdev(0, DEVICE\_NAME, &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.\n", major);

return 0;

}

static void \_\_exit simple\_char\_exit(void) {

unregister\_chrdev(major, DEVICE\_NAME);

printk(KERN\_INFO "Simple char device module unloaded.\n");

}

module\_init(simple\_char\_init);

module\_exit(simple\_char\_exit);

MODULE\_LICENSE("GPL");操作步骤编写上述代码保存为simple\_char.c。编写Makefile:代码语言:makefile复制obj-m += simple\_char.o

all:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean编译驱动:make加载驱动:sudo insmod simple\_char.ko创建设备文件:sudo mknod /dev/simple\_char c $(major) 0测试驱动:代码语言:bash复制echo "Hello, World!" > /dev/simple\_char

cat /dev/simple\_char卸载驱动:sudo rmmod simple\_char2. 带互斥锁的字符设备驱动应用场景当多个进程可能同时访问设备时,需要使用互斥锁来保证数据的一致性。

技巧使用mutex结构体来实现互斥访问。

代码示例代码语言:c复制#include

#include

#include

#include

#include

#define DEVICE\_NAME "mutex\_char\_dev"

#define BUFFER\_SIZE 100

static char buffer[BUFFER\_SIZE];

static int major;

static DEFINE\_MUTEX(mutex);

static ssize\_t mutex\_read(struct file \*filp, char \_\_user \*buf, size\_t count, loff\_t \*f\_pos) {

ssize\_t ret;

if (!mutex\_trylock(&mutex))

return -EBUSY;

if (\*f\_pos >= BUFFER\_SIZE)

ret = 0;

else {

if (\*f\_pos + count > BUFFER\_SIZE)

count = BUFFER\_SIZE - \*f\_pos;

if (copy\_to\_user(buf, buffer + \*f\_pos, count))

ret = -EFAULT;

else {

\*f\_pos += count;

ret = count;

}

}

mutex\_unlock(&mutex);

return ret;

}

static ssize\_t mutex\_write(struct file \*filp, const char \_\_user \*buf, size\_t count, loff\_t \*f\_pos) {

ssize\_t ret;

if (!mutex\_trylock(&mutex))

return -EBUSY;

if (\*f\_pos >= BUFFER\_SIZE)

ret = -ENOSPC;

else {

if (\*f\_pos + count > BUFFER\_SIZE)

count = BUFFER\_SIZE - \*f\_pos;

if (copy\_from\_user(buffer + \*f\_pos, buf, count))

ret = -EFAULT;

else {

\*f\_pos += count;

ret = count;

}

}

mutex\_unlock(&mutex);

return ret;

}

static struct file\_operations fops = {

.read = mutex\_read,

.write = mutex\_write,

};

static int \_\_init mutex\_char\_init(void) {

major = register\_chrdev(0, DEVICE\_NAME, &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.\n", major);

return 0;

}

static void \_\_exit mutex\_char\_exit(void) {

unregister\_chrdev(major, DEVICE\_NAME);

printk(KERN\_INFO "Mutex char device module unloaded.\n");

}

module\_init(mutex\_char\_init);

module\_exit(mutex\_char\_exit);

MODULE\_LICENSE("GPL");操作步骤与简单字符设备驱动类似,只是编译和加载的是mutex\_char.ko。

3. 定时器驱动应用场景周期性地执行某个任务,例如定时采集传感器数据。

技巧使用timer\_list结构体和mod\_timer函数来实现定时器。

代码示例代码语言:c复制#include

#include

#include

#define TIMEOUT 5000 // 5 seconds

static struct timer\_list my\_timer;

static void timer\_callback(unsigned long data) {

printk(KERN\_INFO "Timer callback fired!\n");

mod\_timer(&my\_timer, jiffies + msecs\_to\_jiffies(TIMEOUT));

}

static int \_\_init timer\_init(void) {

setup\_timer(&my\_timer, timer\_callback, 0);

mod\_timer(&my\_timer, jiffies + msecs\_to\_jiffies(TIMEOUT));

printk(KERN\_INFO "Timer initialized.\n");

return 0;

}

static void \_\_exit timer\_exit(void) {

del\_timer(&my\_timer);

printk(KERN\_INFO "Timer removed.\n");

}

module\_init(timer\_init);

module\_exit(timer\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为timer.c,编写Makefile并编译。加载驱动:sudo insmod timer.ko观察内核日志:dmesg卸载驱动:sudo rmmod timer4. 中断驱动应用场景处理硬件中断,例如按键按下等事件。

技巧使用request\_irq函数来注册中断处理函数。

代码示例代码语言:c复制#include

#include

#include

#define IRQ\_NUMBER 1

static irqreturn\_t irq\_handler(int irq, void \*dev\_id) {

printk(KERN\_INFO "Interrupt received!\n");

return IRQ\_HANDLED;

}

static int \_\_init irq\_init(void) {

int ret;

ret = request\_irq(IRQ\_NUMBER, irq\_handler, IRQF\_SHARED, "my\_irq", (void \*)(irq\_handler));

if (ret) {

printk(KERN\_ALERT "Failed to register IRQ %d\n", IRQ\_NUMBER);

return ret;

}

printk(KERN\_INFO "IRQ registered successfully.\n");

return 0;

}

static void \_\_exit irq\_exit(void) {

free\_irq(IRQ\_NUMBER, (void \*)(irq\_handler));

printk(KERN\_INFO "IRQ freed.\n");

}

module\_init(irq\_init);

module\_exit(irq\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为irq.c,编写Makefile并编译。加载驱动:sudo insmod irq.ko触发中断(根据实际硬件情况),观察内核日志:dmesg卸载驱动:sudo rmmod irq5. 内核线程驱动应用场景在后台执行一些长时间运行的任务,例如数据处理。

技巧使用kthread\_create和wake\_up\_process函数来创建和启动内核线程。

代码示例代码语言:c复制#include

#include

#include

static struct task\_struct \*my\_thread;

static int thread\_function(void \*data) {

while (!kthread\_should\_stop()) {

printk(KERN\_INFO "Kernel thread is running...\n");

msleep(1000);

}

return 0;

}

static int \_\_init kthread\_init(void) {

my\_thread = kthread\_create(thread\_function, NULL, "my\_thread");

if (IS\_ERR(my\_thread)) {

printk(KERN\_ALERT "Failed to create kernel thread.\n");

return PTR\_ERR(my\_thread);

}

wake\_up\_process(my\_thread);

printk(KERN\_INFO "Kernel thread created and started.\n");

return 0;

}

static void \_\_exit kthread\_exit(void) {

kthread\_stop(my\_thread);

printk(KERN\_INFO "Kernel thread stopped.\n");

}

module\_init(kthread\_init);

module\_exit(kthread\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为kthread.c,编写Makefile并编译。加载驱动:sudo insmod kthread.ko观察内核日志:dmesg卸载驱动:sudo rmmod kthread6. 简单块设备驱动应用场景模拟一个简单的块设备,例如虚拟磁盘。

技巧使用gendisk结构体和block\_device\_operations结构体来实现块设备驱动。

代码示例代码语言:c复制#include

#include

#include

#define KERNEL\_SECTOR\_SIZE 512

#define DISK\_SIZE (1024 \* 1024) // 1MB

static struct gendisk \*my\_disk;

static struct request\_queue \*my\_queue;

static unsigned char \*disk\_data;

static void my\_request(struct request\_queue \*q) {

struct request \*rq;

while ((rq = blk\_fetch\_request(q)) != NULL) {

if (blk\_rq\_is\_passthrough(rq)) {

printk(KERN\_ERR "Skip non-fs request\n");

\_\_blk\_end\_request\_all(rq, -EIO);

continue;

}

sector\_t start\_sector = blk\_rq\_pos(rq);

unsigned int sectors = blk\_rq\_sectors(rq);

void \*buffer = bio\_data(rq->bio);

if (rq\_data\_dir(rq) == READ) {

memcpy(buffer, disk\_data + start\_sector \* KERNEL\_SECTOR\_SIZE, sectors \* KERNEL\_SECTOR\_SIZE);

} else {

memcpy(disk\_data + start\_sector \* KERNEL\_SECTOR\_SIZE, buffer, sectors \* KERNEL\_SECTOR\_SIZE);

}

\_\_blk\_end\_request\_all(rq, 0);

}

}

static struct block\_device\_operations my\_fops = {

.owner = THIS\_MODULE,

};

static int \_\_init block\_init(void) {

disk\_data = vmalloc(DISK\_SIZE);

if (!disk\_data) {

printk(KERN\_ALERT "Failed to allocate disk data.\n");

return -ENOMEM;

}

my\_queue = blk\_init\_queue(my\_request, NULL);

if (!my\_queue) {

printk(KERN\_ALERT "Failed to initialize request queue.\n");

vfree(disk\_data);

return -ENOMEM;

}

my\_disk = alloc\_disk(1);

if (!my\_disk) {

printk(KERN\_ALERT "Failed to allocate gendisk.\n");

blk\_cleanup\_queue(my\_queue);

vfree(disk\_data);

return -ENOMEM;

}

my\_disk->major = register\_blkdev(0, "my\_block\_dev");

my\_disk->first\_minor = 0;

my\_disk->fops = &my\_fops;

my\_disk->queue = my\_queue;

sprintf(my\_disk->disk\_name, "my\_block\_dev");

set\_capacity(my\_disk, DISK\_SIZE / KERNEL\_SECTOR\_SIZE);

add\_disk(my\_disk);

printk(KERN\_INFO "Block device initialized.\n");

return 0;

}

static void \_\_exit block\_exit(void) {

del\_gendisk(my\_disk);

put\_disk(my\_disk);

unregister\_blkdev(my\_disk->major, "my\_block\_dev");

blk\_cleanup\_queue(my\_queue);

vfree(disk\_data);

printk(KERN\_INFO "Block device removed.\n");

}

module\_init(block\_init);

module\_exit(block\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为block.c,编写Makefile并编译。加载驱动:sudo insmod block.ko查看块设备:lsblk格式化和挂载块设备:代码语言:bash复制sudo mkfs.ext4 /dev/my\_block\_dev

sudo mkdir /mnt/my\_block

sudo mount /dev/my\_block\_dev /mnt/my\_block卸载驱动前先卸载块设备:代码语言:bash复制sudo umount /mnt/my\_block

sudo rmmod block7. 基于 PWM 的呼吸灯驱动应用场景用于控制 LED 实现呼吸灯效果,常见于智能家居、嵌入式设备的状态指示等场景。

技巧利用 PWM(脉冲宽度调制)技术,通过调整占空比来改变 LED 的亮度。在 Linux 内核中,通常使用硬件的 PWM 控制器,并通过相关的内核接口进行配置和操作。

代码示例代码语言:c复制#include

#include

#include

#define PWM\_CHIP\_ID 0

#define PWM\_PERIOD\_NS 1000000 // 1ms period

#define PWM\_MIN\_DUTY\_NS 0

#define PWM\_MAX\_DUTY\_NS 1000000

static struct pwm\_device \*pwm\_dev;

static int \_\_init pwm\_led\_init(void) {

pwm\_dev = pwm\_request(PWM\_CHIP\_ID, "pwm\_led");

if (IS\_ERR(pwm\_dev)) {

printk(KERN\_ALERT "Failed to request PWM device.\n");

return PTR\_ERR(pwm\_dev);

}

pwm\_config(pwm\_dev, PWM\_MIN\_DUTY\_NS, PWM\_PERIOD\_NS);

pwm\_enable(pwm\_dev);

printk(KERN\_INFO "PWM LED initialized.\n");

return 0;

}

static void \_\_exit pwm\_led\_exit(void) {

pwm\_disable(pwm\_dev);

pwm\_free(pwm\_dev);

printk(KERN\_INFO "PWM LED removed.\n");

}

module\_init(pwm\_led\_init);

module\_exit(pwm\_led\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 pwm\_led.c,编写 Makefile 并编译。加载驱动:sudo insmod pwm\_led.ko可以通过 /sys/class/pwm/pwmchipX/pwmY/duty\_cycle 文件来动态调整占空比,例如:代码语言:bash复制echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty\_cycle卸载驱动:sudo rmmod pwm\_led8. I2C 设备驱动(读取传感器数据)应用场景用于与 I2C 接口的传感器进行通信,如温度传感器、加速度计等。

技巧使用 Linux 内核的 I2C 子系统,通过 i2c\_client 和 i2c\_driver 结构体来实现与 I2C 设备的交互。

代码示例代码语言:c复制#include

#include

#include

#define I2C\_DEVICE\_ADDR 0x50

static int my\_i2c\_probe(struct i2c\_client \*client, const struct i2c\_device\_id \*id) {

u8 data;

int ret;

ret = i2c\_smbus\_read\_byte(client);

if (ret < 0) {

printk(KERN\_ALERT "Failed to read from I2C device.\n");

return ret;

}

data = (u8)ret;

printk(KERN\_INFO "Read data from I2C device: 0x%02x\n", data);

return 0;

}

static int my\_i2c\_remove(struct i2c\_client \*client) {

printk(KERN\_INFO "I2C device removed.\n");

return 0;

}

static const struct i2c\_device\_id my\_i2c\_id[] = {

{ "my\_i2c\_device", 0 },

{ }

};

MODULE\_DEVICE\_TABLE(i2c, my\_i2c\_id);

static struct i2c\_driver my\_i2c\_driver = {

.driver = {

.name = "my\_i2c\_driver",

.owner = THIS\_MODULE,

},

.probe = my\_i2c\_probe,

.remove = my\_i2c\_remove,

.id\_table = my\_i2c\_id,

};

static int \_\_init i2c\_driver\_init(void) {

return i2c\_add\_driver(&my\_i2c\_driver);

}

static void \_\_exit i2c\_driver\_exit(void) {

i2c\_del\_driver(&my\_i2c\_driver);

}

module\_init(i2c\_driver\_init);

module\_exit(i2c\_driver\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 i2c\_driver.c,编写 Makefile 并编译。加载驱动:sudo insmod i2c\_driver.ko确保 I2C 设备已正确连接,观察内核日志查看读取的数据:dmesg卸载驱动:sudo rmmod i2c\_driver9. SPI 设备驱动(读写数据)应用场景用于与 SPI 接口的设备进行通信,如 SPI 闪存、SPI 显示屏等。

技巧使用 Linux 内核的 SPI 子系统,通过 spi\_device 和 spi\_driver 结构体来实现与 SPI 设备的交互。

代码示例代码语言:c复制#include

#include

#include

#define SPI\_DEVICE\_MODE SPI\_MODE\_0

#define SPI\_DEVICE\_BITS\_PER\_WORD 8

#define SPI\_DEVICE\_MAX\_SPEED\_HZ 1000000

static int my\_spi\_probe(struct spi\_device \*spi) {

u8 tx\_buf[1] = { 0xAA };

u8 rx\_buf[1];

struct spi\_transfer xfer = {

.tx\_buf = tx\_buf,

.rx\_buf = rx\_buf,

.len = 1,

};

struct spi\_message msg;

spi\_message\_init(&msg);

spi\_message\_add\_tail(&xfer, &msg);

if (spi\_sync(spi, &msg)) {

printk(KERN\_ALERT "SPI transfer failed.\n");

return -EIO;

}

printk(KERN\_INFO "Received data from SPI device: 0x%02x\n", rx\_buf[0]);

return 0;

}

static int my\_spi\_remove(struct spi\_device \*spi) {

printk(KERN\_INFO "SPI device removed.\n");

return 0;

}

static const struct spi\_device\_id my\_spi\_id[] = {

{ "my\_spi\_device", 0 },

{ }

};

MODULE\_DEVICE\_TABLE(spi, my\_spi\_id);

static struct spi\_driver my\_spi\_driver = {

.driver = {

.name = "my\_spi\_driver",

.owner = THIS\_MODULE,

},

.probe = my\_spi\_probe,

.remove = my\_spi\_remove,

.id\_table = my\_spi\_id,

};

static int \_\_init spi\_driver\_init(void) {

return spi\_register\_driver(&my\_spi\_driver);

}

static void \_\_exit spi\_driver\_exit(void) {

spi\_unregister\_driver(&my\_spi\_driver);

}

module\_init(spi\_driver\_init);

module\_exit(spi\_driver\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 spi\_driver.c,编写 Makefile 并编译。加载驱动:sudo insmod spi\_driver.ko确保 SPI 设备已正确连接,观察内核日志查看读取的数据:dmesg卸载驱动:sudo rmmod spi\_driver10. USB 设备驱动(简单识别)应用场景用于识别连接到系统的 USB 设备,如 USB 鼠标、USB 键盘等。

技巧使用 Linux 内核的 USB 子系统,通过 usb\_driver 结构体来实现 USB 设备的识别和处理。

代码示例代码语言:c复制#include

#include

#include

#define USB\_VENDOR\_ID 0x1234

#define USB\_PRODUCT\_ID 0x5678

static int my\_usb\_probe(struct usb\_interface \*intf, const struct usb\_device\_id \*id) {

printk(KERN\_INFO "USB device connected: Vendor ID 0x%04x, Product ID 0x%04x\n",

id->idVendor, id->idProduct);

return 0;

}

static void my\_usb\_disconnect(struct usb\_interface \*intf) {

printk(KERN\_INFO "USB device disconnected.\n");

}

static struct usb\_device\_id my\_usb\_id\_table[] = {

{ USB\_DEVICE(USB\_VENDOR\_ID, USB\_PRODUCT\_ID) },

{ }

};

MODULE\_DEVICE\_TABLE(usb, my\_usb\_id\_table);

static struct usb\_driver my\_usb\_driver = {

.name = "my\_usb\_driver",

.probe = my\_usb\_probe,

.disconnect = my\_usb\_disconnect,

.id\_table = my\_usb\_id\_table,

};

static int \_\_init usb\_driver\_init(void) {

return usb\_register(&my\_usb\_driver);

}

static void \_\_exit usb\_driver\_exit(void) {

usb\_deregister(&my\_usb\_driver);

}

module\_init(usb\_driver\_init);

module\_exit(usb\_driver\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 usb\_driver.c,编写 Makefile 并编译。加载驱动:sudo insmod usb\_driver.ko连接符合指定 Vendor ID 和 Product ID 的 USB 设备,观察内核日志:dmesg卸载驱动:sudo rmmod usb\_driver11. 输入设备驱动(模拟键盘)应用场景用于模拟键盘输入,可用于自动化测试、远程控制等场景。

技巧使用 Linux 内核的输入子系统,通过 input\_dev 结构体来创建和注册输入设备。

代码示例代码语言:c复制#include

#include

#include

static struct input\_dev \*my\_input\_dev;

static int \_\_init input\_driver\_init(void) {

int err;

my\_input\_dev = input\_allocate\_device();

if (!my\_input\_dev) {

printk(KERN\_ALERT "Failed to allocate input device.\n");

return -ENOMEM;

}

my\_input\_dev->name = "my\_keyboard";

set\_bit(EV\_KEY, my\_input\_dev->evbit);

set\_bit(KEY\_A, my\_input\_dev->keybit);

err = input\_register\_device(my\_input\_dev);

if (err) {

printk(KERN\_ALERT "Failed to register input device.\n");

input\_free\_device(my\_input\_dev);

return err;

}

input\_report\_key(my\_input\_dev, KEY\_A, 1);

input\_sync(my\_input\_dev);

input\_report\_key(my\_input\_dev, KEY\_A, 0);

input\_sync(my\_input\_dev);

printk(KERN\_INFO "Input device initialized and sent 'A' key event.\n");

return 0;

}

static void \_\_exit input\_driver\_exit(void) {

input\_unregister\_device(my\_input\_dev);

printk(KERN\_INFO "Input device removed.\n");

}

module\_init(input\_driver\_init);

module\_exit(input\_driver\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 input\_driver.c,编写 Makefile 并编译。加载驱动:sudo insmod input\_driver.ko观察系统中是否有模拟的键盘输入(如在文本编辑器中可能会出现字符 'A')卸载驱动:sudo rmmod input\_driver12. 帧缓冲设备驱动(简单显示)应用场景用于在屏幕上进行简单的图形显示,如嵌入式设备的小屏幕显示。

技巧使用 Linux 内核的帧缓冲子系统,通过 fb\_info 结构体来实现帧缓冲设备驱动。

代码示例代码语言:c复制#include

#include

#include

static struct fb\_info \*my\_fb\_info;

static int my\_fb\_set\_par(struct fb\_info \*info) {

return 0;

}

static int my\_fb\_blank(int blank, struct fb\_info \*info) {

return 0;

}

static struct fb\_ops my\_fb\_ops = {

.owner = THIS\_MODULE,

.fb\_set\_par = my\_fb\_set\_par,

.fb\_blank = my\_fb\_blank,

};

static int \_\_init fb\_driver\_init(void) {

my\_fb\_info = framebuffer\_alloc(0, NULL);

if (!my\_fb\_info) {

printk(KERN\_ALERT "Failed to allocate framebuffer info.\n");

return -ENOMEM;

}

my\_fb\_info->fbops = &my\_fb\_ops;

my\_fb\_info->var.xres = 640;

my\_fb\_info->var.yres = 480;

my\_fb\_info->var.bits\_per\_pixel = 16;

my\_fb\_info->fix.smem\_len = my\_fb\_info->var.xres \* my\_fb\_info->var.yres \*

(my\_fb\_info->var.bits\_per\_pixel / 8);

if (register\_framebuffer(my\_fb\_info)) {

printk(KERN\_ALERT "Failed to register framebuffer.\n");

framebuffer\_release(my\_fb\_info);

return -EFAULT;

}

printk(KERN\_INFO "Framebuffer device initialized.\n");

return 0;

}

static void \_\_exit fb\_driver\_exit(void) {

unregister\_framebuffer(my\_fb\_info);

framebuffer\_release(my\_fb\_info);

printk(KERN\_INFO "Framebuffer device removed.\n");

}

module\_init(fb\_driver\_init);

module\_exit(fb\_driver\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 fb\_driver.c,编写 Makefile 并编译。加载驱动:sudo insmod fb\_driver.ko可以使用 fbset 命令查看帧缓冲设备信息:代码语言:bash复制sudo fbset -i /dev/fbX # X 为帧缓冲设备编号卸载驱动:sudo rmmod fb\_driver13. 看门狗设备驱动(简单实现)应用场景用于系统的硬件监控和故障恢复,当系统出现异常时,看门狗可以复位系统。

技巧使用 Linux 内核的看门狗子系统,通过 watchdog\_device 结构体来实现看门狗设备驱动。

代码示例代码语言:c复制#include

#include

#include

static int my\_wdt\_start(struct watchdog\_device \*wdd) {

printk(KERN\_INFO "Watchdog started.\n");

return 0;

}

static int my\_wdt\_stop(struct watchdog\_device \*wdd) {

printk(KERN\_INFO "Watchdog stopped.\n");

return 0;

}

static int my\_wdt\_ping(struct watchdog\_device \*wdd) {

printk(KERN\_INFO "Watchdog pinged.\n");

return 0;

}

static struct watchdog\_info my\_wdt\_info = {

.options = WDIOF\_KEEPALIVEPING,

.firmware\_version = 1,

.identity = "My Watchdog",

};

static struct watchdog\_ops my\_wdt\_ops = {

.owner = THIS\_MODULE,

.start = my\_wdt\_start,

.stop = my\_wdt\_stop,

.ping = my\_wdt\_ping,

};

static struct watchdog\_device my\_wdt\_dev = {

.info = &my\_wdt\_info,

.ops = &my\_wdt\_ops,

};

static int \_\_init wdt\_driver\_init(void) {

return watchdog\_register\_device(&my\_wdt\_dev);

}

static void \_\_exit wdt\_driver\_exit(void) {

watchdog\_unregister\_device(&my\_wdt\_dev);

}

module\_init(wdt\_driver\_init);

module\_exit(wdt\_driver\_exit);

MODULE\_LICENSE("GPL");操作步骤编写代码保存为 wdt\_driver.c,编写 Makefile 并编译。加载驱动:sudo insmod wdt\_driver.ko可以使用 watchdog 命令来操作看门狗设备:代码语言:bash复制sudo echo 1 > /dev/watchdog # 启动看门狗

sudo echo V > /dev/watchdog # 停止看门狗卸载驱动:sudo rmmod wdt\_driver最后以上是13个 Linux 驱动开发中常用的小案例,收藏起来,用得着的时候不会抓瞎,就像 V 哥经常会收集一些小案例在自己的知识库里,需要用的时候很方便可以检索到,你说用 AI?对 AI 很强大,但我自己调试好的小案例用起来也很方便,就像自己创建的一个智能体一样,你觉得呢。关注威哥爱编程,全栈开发就你行。

相关数据