Linux驱动开发13个实用案例

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

1. 简单字符设备驱动

应用场景

用于实现基本的设备文件读写操作,例如模拟一个简单的传感器设备。

技巧

使用cdev结构体来注册字符设备,实现file_operations结构体中的读写函数。

代码示例

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

#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");

操作步骤

  1. 编写上述代码保存为simple_char.c
  2. 编写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
  1. 编译驱动:make
  2. 加载驱动:sudo insmod simple_char.ko
  3. 创建设备文件:sudo mknod /dev/simple_char c $(major) 0
  4. 测试驱动:
bash 复制代码
echo "Hello, World!" > /dev/simple_char
cat /dev/simple_char
  1. 卸载驱动:sudo rmmod simple_char

2. 带互斥锁的字符设备驱动

应用场景

当多个进程可能同时访问设备时,需要使用互斥锁来保证数据的一致性。

技巧

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

代码示例

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

#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 <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>

#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");

操作步骤

  1. 编写代码保存为timer.c,编写Makefile并编译。
  2. 加载驱动:sudo insmod timer.ko
  3. 观察内核日志:dmesg
  4. 卸载驱动:sudo rmmod timer

4. 中断驱动

应用场景

处理硬件中断,例如按键按下等事件。

技巧

使用request_irq函数来注册中断处理函数。

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>

#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");

操作步骤

  1. 编写代码保存为irq.c,编写Makefile并编译。
  2. 加载驱动:sudo insmod irq.ko
  3. 触发中断(根据实际硬件情况),观察内核日志:dmesg
  4. 卸载驱动:sudo rmmod irq

5. 内核线程驱动

应用场景

在后台执行一些长时间运行的任务,例如数据处理。

技巧

使用kthread_createwake_up_process函数来创建和启动内核线程。

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>

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");

操作步骤

  1. 编写代码保存为kthread.c,编写Makefile并编译。
  2. 加载驱动:sudo insmod kthread.ko
  3. 观察内核日志:dmesg
  4. 卸载驱动:sudo rmmod kthread

6. 简单块设备驱动

应用场景

模拟一个简单的块设备,例如虚拟磁盘。

技巧

使用gendisk结构体和block_device_operations结构体来实现块设备驱动。

代码示例

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

#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");

操作步骤

  1. 编写代码保存为block.c,编写Makefile并编译。
  2. 加载驱动:sudo insmod block.ko
  3. 查看块设备:lsblk
  4. 格式化和挂载块设备:
bash 复制代码
sudo mkfs.ext4 /dev/my_block_dev
sudo mkdir /mnt/my_block
sudo mount /dev/my_block_dev /mnt/my_block
  1. 卸载驱动前先卸载块设备:
bash 复制代码
sudo umount /mnt/my_block
sudo rmmod block

7. 基于 PWM 的呼吸灯驱动

应用场景

用于控制 LED 实现呼吸灯效果,常见于智能家居、嵌入式设备的状态指示等场景。

技巧

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

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pwm.h>

#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");

操作步骤

  1. 编写代码保存为 pwm_led.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod pwm_led.ko
  3. 可以通过 /sys/class/pwm/pwmchipX/pwmY/duty_cycle 文件来动态调整占空比,例如:
bash 复制代码
echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
  1. 卸载驱动:sudo rmmod pwm_led

8. I2C 设备驱动(读取传感器数据)

应用场景

用于与 I2C 接口的传感器进行通信,如温度传感器、加速度计等。

技巧

使用 Linux 内核的 I2C 子系统,通过 i2c_clienti2c_driver 结构体来实现与 I2C 设备的交互。

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

#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");

操作步骤

  1. 编写代码保存为 i2c_driver.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod i2c_driver.ko
  3. 确保 I2C 设备已正确连接,观察内核日志查看读取的数据:dmesg
  4. 卸载驱动:sudo rmmod i2c_driver

9. SPI 设备驱动(读写数据)

应用场景

用于与 SPI 接口的设备进行通信,如 SPI 闪存、SPI 显示屏等。

技巧

使用 Linux 内核的 SPI 子系统,通过 spi_devicespi_driver 结构体来实现与 SPI 设备的交互。

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>

#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");

操作步骤

  1. 编写代码保存为 spi_driver.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod spi_driver.ko
  3. 确保 SPI 设备已正确连接,观察内核日志查看读取的数据:dmesg
  4. 卸载驱动:sudo rmmod spi_driver

10. USB 设备驱动(简单识别)

应用场景

用于识别连接到系统的 USB 设备,如 USB 鼠标、USB 键盘等。

技巧

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

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>

#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");

操作步骤

  1. 编写代码保存为 usb_driver.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod usb_driver.ko
  3. 连接符合指定 Vendor ID 和 Product ID 的 USB 设备,观察内核日志:dmesg
  4. 卸载驱动:sudo rmmod usb_driver

11. 输入设备驱动(模拟键盘)

应用场景

用于模拟键盘输入,可用于自动化测试、远程控制等场景。

技巧

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

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>

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");

操作步骤

  1. 编写代码保存为 input_driver.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod input_driver.ko
  3. 观察系统中是否有模拟的键盘输入(如在文本编辑器中可能会出现字符 'A')
  4. 卸载驱动:sudo rmmod input_driver

12. 帧缓冲设备驱动(简单显示)

应用场景

用于在屏幕上进行简单的图形显示,如嵌入式设备的小屏幕显示。

技巧

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

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fb.h>

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");

操作步骤

  1. 编写代码保存为 fb_driver.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod fb_driver.ko
  3. 可以使用 fbset 命令查看帧缓冲设备信息:
bash 复制代码
sudo fbset -i /dev/fbX  # X 为帧缓冲设备编号
  1. 卸载驱动:sudo rmmod fb_driver

13. 看门狗设备驱动(简单实现)

应用场景

用于系统的硬件监控和故障恢复,当系统出现异常时,看门狗可以复位系统。

技巧

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

代码示例

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/watchdog.h>

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");

操作步骤

  1. 编写代码保存为 wdt_driver.c,编写 Makefile 并编译。
  2. 加载驱动:sudo insmod wdt_driver.ko
  3. 可以使用 watchdog 命令来操作看门狗设备:
bash 复制代码
sudo echo 1 > /dev/watchdog  # 启动看门狗
sudo echo V > /dev/watchdog  # 停止看门狗
  1. 卸载驱动:sudo rmmod wdt_driver

最后

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

相关推荐
lllsure28 分钟前
Linux 实用指令
linux·物联网
努力的小T1 小时前
使用 Docker 部署 Apache Spark 集群教程
linux·运维·服务器·docker·容器·spark·云计算
Nerd Nirvana1 小时前
OpenSSL crt & key (生成一套用于TLS双向认证的证书密钥)
linux·ssl·shell·认证·加密·tls·oepnssl
letisgo52 小时前
记录一次部署PC端网址全过程
linux·阿里云·服务器运维
枫叶落雨2222 小时前
08-Elasticsearch
运维·jenkins
怪怪王2 小时前
【GPU驱动】OpenGLES图形管线渲染机制
驱动开发·gpu·opengl
猫猫的小茶馆2 小时前
【网络编程】UDP协议
linux·服务器·网络·网络协议·ubuntu·udp
尚墨11112 小时前
linux 安装启动zookeeper全过程及遇到的坑
linux·zookeeper
鱼嘻2 小时前
Linux自学day23-进程和线程
linux·服务器·c语言·进程和线程
AuGuSt_813 小时前
在windows下安装windows+Ubuntu16.04双系统(下)
linux·ubuntu·双系统