首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

ARM Linux 驅動開發實戰:字元設備驅動完整範例

     編輯:關於C語言

驅動程式架構

  • qudong.c:核心驅動代碼(open/read/write/release/file_operations)
  • Makefile:核心外建構腳本(x86 交叉編譯與 ARM 原生編譯)
  • test_app.c:用戶空間測試程式

核心驅動代碼 (qudong.c)


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

#define DEV_NAME "rwtest"
#define MAX_BUF_LEN 1024

static int major = 0;
static char *drv_buf;
static int buf_len = 0;

static ssize_t drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
    if (count > MAX_BUF_LEN) count = MAX_BUF_LEN;
    if (copy_from_user(drv_buf, buf, count)) return -EFAULT;
    buf_len = count;
    return count;
}

static ssize_t drv_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
    if (count > buf_len) count = buf_len;
    if (copy_to_user(buf, drv_buf, count)) return -EFAULT;
    return count;
}

static int drv_open(struct inode *inode, struct file *filp) {
    printk(KERN_INFO "%s: device opened\n", DEV_NAME);
    return 0;
}

static int drv_release(struct inode *inode, struct file *filp) {
    printk(KERN_INFO "%s: device closed\n", DEV_NAME);
    return 0;
}

static struct file_operations fops = {
    .owner   = THIS_MODULE,
    .write   = drv_write,
    .read    = drv_read,
    .open    = drv_open,
    .release = drv_release,
};

static int __init drv_init(void) {
    major = register_chrdev(0, DEV_NAME, &fops);
    if (major < 0) return major;
    drv_buf = kmalloc(MAX_BUF_LEN, GFP_KERNEL);
    if (!drv_buf) { unregister_chrdev(major, DEV_NAME); return -ENOMEM; }
    printk(KERN_INFO "%s: registered with major %d\n", DEV_NAME, major);
    return 0;
}

static void __exit drv_exit(void) {
    kfree(drv_buf);
    unregister_chrdev(major, DEV_NAME);
    printk(KERN_INFO "%s: unregistered\n", DEV_NAME);
}

module_init(drv_init);
module_exit(drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Developer");

Makefile (x86 宿主機交叉編譯 ARM)


KDIR := /usr/src/linux-headers-$(shell uname -r)
# ARM 交叉編譯時取消註解下兩行並註解上行
# KDIR := /path/to/arm-linux-kernel
# ARCH := arm
# CROSS_COMPILE := arm-linux-gnueabihf-

obj-m := qudong.o

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules $(ARCH) $(CROSS_COMPILE)

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers modules.order

用戶空間測試程式 (test_app.c)


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEV_PATH "/dev/rwtest"

int main() {
    int fd = open(DEV_PATH, O_RDWR);
    if (fd < 0) { perror("open"); return 1; }

    char wbuf[] = "Hello from user space!";
    char rbuf[128] = {0};

    if (write(fd, wbuf, strlen(wbuf)) < 0) perror("write");
    if (read(fd, rbuf, sizeof(rbuf)-1) < 0) perror("read");
    printf("Read back: %s\n", rbuf);

    close(fd);
    return 0;
}

部署與驗證步驟

  1. 編譯:make 產生 qudong.ko
  2. 載入:sudo insmod qudong.ko,查看 dmesg 確認 major number
  3. 建立裝置節點:sudo mknod /dev/rwtest c 0
  4. 編譯測試程式:gcc test_app.c -o test_app (ARM 交叉編譯加 arm-linux-gnueabihf-gcc)
  5. 執行測試:./test_app
  6. 卸載:sudo rmmod qudong

進階擴展方向

  • 支援 ioctl 命令控制裝置參數
  • 實作 poll/fasync 非同步通知
  • 使用 cdev + device_create 自動建立 /dev 節點 (驅動核心模型)
  • DMA 緩衝區零拷貝傳輸
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved