赞
踩
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <linux/slab.h> // 包含这个头文件来使用 kmalloc 和 kfree #include <linux/proc_fs.h> #include <linux/seq_file.h> #define DEVICE_NAME "mychar" #define CLASS_NAME "mychar_class" #define BUFFER_SIZE 1024 static int major; static struct cdev *my_cdev; static char *buffer; static int buffer_size = BUFFER_SIZE; static int mychar_open(struct inode *inode, struct file *file) { printk(KERN_INFO "mychar_open\n"); return 0; } static ssize_t mychar_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; unsigned int copy; if (p >= buffer_size) return 0; if (count > buffer_size - p) count = buffer_size - p; if (copy_to_user(buf, buffer + p, count)) return -EFAULT; *ppos += count; return count; } static ssize_t mychar_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; unsigned int copy; if (p >= buffer_size) return 0; if (count > buffer_size - p) count = buffer_size - p; if (copy_from_user(buffer + p, buf, count)) return -EFAULT; *ppos += count; return count; } static loff_t mychar_llseek(struct file *file, loff_t offset, int whence) { loff_t newpos = file->f_pos; switch (whence) { case SEEK_SET: newpos = offset; break; case SEEK_CUR: newpos += offset; break; case SEEK_END: newpos = buffer_size + offset; break; default: return -EINVAL; } if (newpos < 0 || newpos > buffer_size) return -EINVAL; file->f_pos = newpos; return newpos; } static struct file_operations mychar_fops = { .owner = THIS_MODULE, .open = mychar_open, .read = mychar_read, .write = mychar_write, // .llseek = mychar_llseek, }; // 假设你有一个字符设备的私有数据结构 struct mychar_dev { // ... 设备特定的数据 ... char buffer[4096]; // 示例缓冲区 size_t buffer_pos; // 示例缓冲区中的当前位置 }; static struct mychar_dev mychar_device; // /proc 文件的读取处理函数 static ssize_t mychar_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { size_t len; if (*ppos >= sizeof(mychar_device.buffer) || count == 0) return 0; len = min(count, sizeof(mychar_device.buffer) - (size_t)*ppos); if (copy_to_user(buf, mychar_device.buffer + *ppos, len)) return -EFAULT; *ppos += len; return len; } // /proc 文件的写入处理函数 static ssize_t mychar_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { size_t len; if (*ppos >= sizeof(mychar_device.buffer) || count == 0) return 0; len = min(count, sizeof(mychar_device.buffer) - (size_t)*ppos); if (copy_from_user(mychar_device.buffer + *ppos, buf, len)) return -EFAULT; // 更新设备缓冲区的位置(如果需要的话) // 这里我们简单地增加偏移量,但你可以根据需要进行更复杂的处理 *ppos += len; // 注意:在实际的设备驱动中,你可能需要同步缓冲区到硬件或执行其他操作 return len; } // /proc 文件的 file_operations 结构体 static const struct file_operations mychar_proc_fops = { .owner = THIS_MODULE, .read = mychar_proc_read, .write = mychar_proc_write, // 注意:没有 open 和 release,因为 /proc 文件系统的处理是自动的 // 也没有 llseek,因为 /proc 文件通常不支持随机访问 }; static struct class *mychar_class; static struct proc_dir_entry *mychar_proc_entry; static int __init mychar_init(void) { int err; dev_t devno = MKDEV(major, 0); if (major) { my_cdev = cdev_alloc(); my_cdev->owner = THIS_MODULE; my_cdev->ops = &mychar_fops; my_cdev->dev = devno; err = cdev_add(my_cdev, MKDEV(major, 0), 1); if (err) { printk(KERN_NOTICE "Error %d adding mychar", err); return err; } } else { err = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME); if (err < 0) { printk(KERN_NOTICE "Error %d registering character device", err); return err; } major = MAJOR(devno); my_cdev = cdev_alloc(); my_cdev->owner = THIS_MODULE; my_cdev->ops = &mychar_fops; my_cdev->dev = devno; err = cdev_add(my_cdev, MKDEV(major, 0), 1); if (err) { unregister_chrdev_region(MKDEV(major, 0), 1); printk(KERN_NOTICE "Error %d adding mychar", err); return err; } } buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); if (!buffer) { cdev_del(my_cdev); unregister_chrdev_region(MKDEV(major, 0), 1); printk(KERN_NOTICE "Failed to allocate device buffer\n"); return -ENOMEM; } // 创建设备类 mychar_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(mychar_class)) { printk(KERN_WARNING "Failed to register device class\n"); cdev_del(my_cdev); unregister_chrdev_region(MKDEV(major, 0), 1); kfree(buffer); return PTR_ERR(mychar_class); } // 创建设备 device_create(mychar_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); // 创建 /proc 文件 mychar_proc_entry = proc_create("mychar", 0666, NULL, &mychar_proc_fops); if (!mychar_proc_entry) { pr_err("Failed to create /proc/mychar\n"); return -ENOMEM; // 或者其他适当的错误码 } printk(KERN_INFO "mychar device registered with major number %d\n", major); return 0; } static void __exit mychar_exit(void) { device_destroy(mychar_class, MKDEV(major, 0)); class_destroy(mychar_class); cdev_del(my_cdev); unregister_chrdev_region(MKDEV(major, 0), 1); kfree(buffer); if (mychar_proc_entry) { remove_proc_entry("mychar", NULL); } printk(KERN_INFO "mychar device unregistered\n"); } module_init(mychar_init); module_exit(mychar_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple character device driver");
KERN_DIR = /home/book/demo/linux-5.4
obj-m += mychar.o
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #define BUFFER_SIZE 2048 // 定义缓冲区大小 int main(int argc, char *argv[]) { int fd; ssize_t ret; off_t pos; char buffer[BUFFER_SIZE]; // 假设 fd 已经被正确打开 fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open failed"); return EXIT_FAILURE; } // 首次读取(可能不需要,但根据原始代码保留) ret = read(fd, buffer, 0); // 这里传递 0 字节,实际上不会读取任何内容 if (ret != 0) { perror("Unexpected read return"); close(fd); return EXIT_FAILURE; } printf("***********read ret=%d\n", ret); // 重置文件位置 pos = lseek(fd, 0, SEEK_SET); if (pos < 0) { perror("lseek failed"); close(fd); return EXIT_FAILURE; } printf("***********lseek pos=%d\n", (int)pos); // 清理缓冲区(虽然在这个场景下可能不是必需的) memset(buffer, 0, BUFFER_SIZE); // 读取文件内容到缓冲区 ret = read(fd, buffer, BUFFER_SIZE); if (ret < 0) { perror("read failed"); close(fd); return EXIT_FAILURE; } printf("***********read ret=%d\n", ret); // 检查是否读取了足够的数据来检查换行符 if (ret < (ssize_t)(BUFFER_SIZE >> 1)) { char *bptr = buffer; // 查找换行符 while (*bptr && *bptr != '\n') { bptr++; } if (*bptr == '\n') { const off_t offset = 2 + (bptr - buffer); printf("***********offset=%d\n", (int)offset); // 跳转到换行符后的位置 pos = lseek(fd, offset, SEEK_SET); if (pos == (off_t)-1) { perror("lseek failed"); close(fd); return EXIT_FAILURE; } printf("***********lseek pos=%d\n", (int)pos); // 从新位置读取(如果需要) // 注意:这里可能需要额外的逻辑来决定是否再次读取 // 这里仅作为示例,不实际读取 ret = read(fd, buffer, BUFFER_SIZE); printf("***********read ret=%d\n", ret); // (void)ret; } } off_t dec; pos = lseek(fd, 0, SEEK_END); printf("***********lseek pos=%d\n", (int)pos); if (pos < 0) return EXIT_FAILURE; dec = pos / 13; printf("***********dec=%d\n", (int)dec); if (dec < 1) dec = 1; while (pos > 0) { off_t seek_pos; seek_pos = lseek(fd, pos, SEEK_SET); printf("***********lseek seek_pos=%d\n", (int)seek_pos); if (seek_pos < 0) break; ret = read(fd, buffer, 5); printf("***********read ret=%d\n", ret); (void)ret; if (dec > pos) dec = pos; pos -= dec; } // 关闭文件描述符 close(fd); return EXIT_SUCCESS; }
#include <stdio.h> #include <dirent.h> int main(int argc,char* argv[],char* envp[]) { struct dirent **namelist; printf("argc=%d, argv[0]=%s, argv[1]=%s\n", argc, argv[0], argv[1]); int numEntries = scandir(argv[1], &namelist, NULL, alphasort); if (numEntries < 0) { perror("scandir"); } else { for (int i = 0; i < numEntries; i++) { printf("File %d: %s\n", i, namelist[i]->d_name); } } // 释放动态分配的内存 for (int i = 0; i < numEntries; i++) { free(namelist[i]); } free(namelist); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。