linux驱动开发,读取字符的函数

1.linux驱动开发,读取字符的函数

在Linux驱动开发中,处理字符设备的读写操作是常见的任务。字符设备是一种按字符流处理数据的设备,如串口终端、键盘等。为了读取字符数据,你需要实现字符设备驱动中的相应函数。以下是一个简单的字符设备驱动示例,重点介绍如何读取字符。

1. 引入头文件

首先,引入必要的头文件:

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <linux/uaccess.h> // for copy_to_user  
#include <linux/slab.h>    // for kmalloc and kfree

2. 定义设备结构体

定义一个结构体来保存设备信息:

#define DEVICE_NAME "chardev"  
#define BUF_LEN 80  
  
static int major; // major number for the device  
static char msg[BUF_LEN]; // buffer to store the message  
static char *msg_Ptr;  
static int msg_Len;  
static int msg_Read_Pos;  
static int msg_Written;

3. 文件操作结构体

定义文件操作结构体,并实现其中的读函数:

static ssize_t chardev_read(struct file *filp, char __user *buffer, size_t len, loff_t *offset) {  
    int bytes_read = 0;  
  
    // Check if we have reached the end of the message  
    if (*msg_Ptr == 0) {  
        return 0; // End of file  
    }  
  
    // Adjust the length to make sure we don't read beyond the available message  
    if (*msg_Ptr + len > msg_Len) {  
        len = msg_Len - *msg_Ptr;  
    }  
  
    // Copy data to user space  
    if (copy_to_user(buffer, msg_Ptr, len)) {  
        return -EFAULT;  
    }  
  
    // Update the file offset  
    *msg_Ptr += len;  
    bytes_read = len;  
  
    return bytes_read;  
}  
  
static const struct file_operations fops = {  
    .owner = THIS_MODULE,  
    .read = chardev_read,  
    // You can add other file operations like write, open, release here  
};

4. 初始化与退出函数

实现驱动的初始化和退出函数:

static int __init chardev_init(void) {  
    // Allocate space for the message  
    msg_Ptr = msg;  
    msg_Len = 0;  
    msg_Read_Pos = 0;  
    msg_Written = 0;  
  
    // Register the character device  
    major = register_chrdev(0, DEVICE_NAME, &fops);  
    if (major < 0) {  
        printk(KERN_ALERT "Failed to register the character device\n");  
        return major;  
    }  
  
    printk(KERN_INFO "Registered character device with major number %d\n", major);  
    return 0;  
}  
  
static void __exit chardev_exit(void) {  
    // Unregister the character device  
    unregister_chrdev(major, DEVICE_NAME);  
    printk(KERN_INFO "Unregistered character device with major number %d\n", major);  
}

5. 模块加载与卸载

最后,定义模块加载与卸载宏:

module_init(chardev_init);  
module_exit(chardev_exit);  
  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("Your Name");  
MODULE_DESCRIPTION("A simple character device driver");  
MODULE_VERSION("1.0");

6. 编译与测试

  1. 编写好上述代码并保存为 chardev.c

  2. 创建 Makefile,内容如下:

    obj-m += chardev.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
  3. 在终端中运行 make 编译驱动。

  4. 使用 sudo insmod chardev.ko 加载驱动。

  5. 使用 sudo rmmod chardev 卸载驱动。

7. 创建测试程序

你可以编写一个简单的用户态测试程序来读取设备的数据,如下所示:

#include <stdio.h>  
#include <fcntl.h>  
#include <unistd.h>  
  
#define DEVICE "/dev/chardev"  
  
int main() {  
    int fd = open(DEVICE, O_RDONLY);  
    if (fd < 0) {  
        perror("Failed to open device");  
        return -1;  
    }  
  
    char buffer[80];  
    ssize_t bytesRead;  
  
    bytesRead = read(fd, buffer, sizeof(buffer) - 1);  
    if (bytesRead < 0) {  
        perror("Failed to read from device");  
        close(fd);  
        return -1;  
    }  
  
    buffer[bytesRead] = '\0';  
    printf("Read from device: %s\n", buffer);  
  
    close(fd);  
    return 0;  
}

编译并运行这个测试程序,你应该能够读取字符设备中的数据。

以上就是Linux字符设备驱动开发中读取字符的基本示例。根据具体需求,你可以扩展和完善这个驱动,比如添加写函数、处理并发访问等。

2.“bytesRead = read(fd, buffer, sizeof(buffer) - 1);” 这里“-1”的作用

在C语言编程中,当使用read函数从文件或设备读取数据时,read函数的原型通常如下:

ssize_t read(int fd, void *buf, size_t count);

其中,fd是文件描述符,buf是指向存储读取数据的缓冲区的指针,count是希望读取的最大字节数。

在表达式read(fd, buffer, sizeof(buffer) - 1)中,sizeof(buffer)返回缓冲区buffer的总大小(以字节为单位)。由于buffer通常是一个字符数组,并且我们希望在其末尾保留一个空字符(\0)以便将其作为C字符串处理,因此我们在调用read时将count设置为sizeof(buffer) - 1

这样做是为了确保在读取数据时不会覆盖缓冲区的最后一个字节,该字节用于存储空字符。这样,即使read函数读取了sizeof(buffer) - 1个字节的数据,缓冲区仍然可以以一个空字符结尾,从而保持其作为C字符串的有效性。

在读取操作之后,代码通常会将读取的字节数对应的字符位置设置为空字符:

buffer[bytesRead] = '\0'; // Null-terminate the string

这样做是为了确保字符串是以空字符结尾的,这对于后续的字符串处理函数(如printfstrlen等)来说是必要的。

总结来说,sizeof(buffer) - 1read函数调用中的作用是确保不会读取超过缓冲区容量减去一个字节的数据,以便在缓冲区中保留一个空字符的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值