【问题标题】:Why not get the offset to the read-write functions of my driver?为什么不获取驱动程序读写功能的偏移量?
【发布时间】:2013-06-27 10:54:08
【问题描述】:

我正在编写一个驱动程序,该驱动程序执行对已映射(在驱动程序打开中)的内存位置的读取和写入:

request_mem_region(0x62200000,0x0006C,secuencial);

contador = ioremap_nocache(0x62200000,0x0006C   );

其中:0x62200000,0x0006C是内存中已经实例化的ipcore的内存位置和大小。 “secuencial”是设备驱动程序的名称。

contador 是一个 void*(它是一个指向虚拟地址的指针)

根据我的设备驱动代码中的读写功能:

static ssize_t device_read(struct file *filp, char *buffer,size_t length, loff_t * offset)  

static ssize_t device_write(struct file *filp, char *buffer,size_t length, loff_t * offset) 

还有我的文件操作:

static struct file_operations fops = {
    .read    = device_read,
    .write   = device_write,
    .open    = device_open,
    .release = device_release
};

在我的 c 程序中,我使用库中的一个函数:

read (fd_secuencial,buffer_lectura,199, offset_read);

write( fd_secuencial,  msg,  10, offset_write);

变量在哪里:

loff_t offset_read=0x00000004;
loff_t offset_write=0x00000044;

而fd_secuencial是在open中获得的设备驱动的文件描述符:

fd_secuencial = open("/dev/secuencial", O_RDWR | O_NOCTTY | O_NONBLOCK);

buffer 和 msg 是读/写数据的缓冲区。

问题是偏移永远不会出现在我的驱动程序中的读/写函数中,

我打印: printk(KERN_ALERT "偏移量: %llu\n", *offset);

并且偏移量始终为 0....

我的代码有什么问题?有什么想法吗?

我通过

更改了从读取功能访问文件的位置
filp-> f_pos = integer_different_values​​. 

并且没有读数被带到映射的不同内存位置。 也就是说,“f_pos”发生了变化,但不会像访问内存块一样访问文件(这是持有的方法)。

如果我增加使用“contador”成就访问的内存位置,则可以正确读取。

我怀疑定义了函数 device_read / write 但函数的方法中没有实现 loff_t * pos 字段。 如果我调用从应用程序读取的函数,带有5个参数,编译器不会发出警告并且执行正常(但显然考虑到前3个参数)

因此,我不能从应用程序传递给函数 device_read / write driver,offset 作为第 4 个参数。

调用方法的正确方法如下:

loff_t offset = 16;
loff_t * off = &offset;

通过这种方式,您将偏移值传递给一个名为 off(它正在请求函数原型)的指针

非常感谢您的帮助!

【问题讨论】:

  • 这是字符设备吗?据我所知,他们不允许搜索,所以偏移参数有点多余。
  • 是的,它是一个字符设备驱动程序,我想在 ioread 和 iowrite 函数中使用 de offset:ioread32(contador + *offset); iowrite32(contador + *offset);
  • 这听起来像是一个 XY 问题。撇开字符设备不可搜索的问题不谈,为什么要在 IO 读/写函数中使用该偏移量?
  • 因为内存中有ipcore寄存器,是可读写的,例如每个寄存器有32bits大小,第一个寄存器写入接受某种类型的数据,结果在寄存器中得到偏移量= 0x044
  • 抱歉,我认为我的问题不太清楚。我的意思是,你为什么让用户空间程序直接写入寄存器空间?您的内核驱动程序不应该抽象设备细节并提供某种 API,而不是让用户空间程序直接写入寄存器吗?

标签: c linux kernel driver linux-device-driver


【解决方案1】:

您可以使用 LDD3 中所述的字符设备实现单独的搜索功能:http://tjworld.net/books/ldd3/#SeekingADevice

您可以使用 file_operations 结构的 llseek 字段来为原型分配一个 seek 函数:

loff_t (*llseek) (struct file *, loff_t, int);

然后用户应用程序或 API 将使用用户空间函数 lseek() 函数来执行它。

但是,如果您对寄存器执行的操作除了从设备读取数据或将数据写入设备之外,还具有副作用,您可能应该使用 ioctl() 接口并提供 API 包装器。见http://tjworld.net/books/ldd3/#TheIoctlMethod

【讨论】:

  • loff_t 它很长(根据 linux 设备驱动程序),例如: loff_t variable= 0x0000004;这是对的吗?
  • 我刚刚意识到我从 file_operations 结构中复制了 read() 而不是 llseek()。我已经相应地编辑了答案。
  • 实际上,loff_t 的大小取决于实现,但对于大多数系统来说,假设它是long long 可能是安全的。在内核 (lxr.linux.no/linux+v2.6.33/include/linux/types.h#L50) 中,loff_t 定义为 __kernel_loff_t,对于两个 x86 架构都定义为 long long,但对于 arm 定义为 long。这似乎与用户空间库中 off_t 的定义无关。至于您的问题,您提供的陈述在语法上是正确的。
  • 我在来自 mi 应用程序的 llseek 中有此警告:(.text+0xa8): 警告:llseek' function may be dangerous; use lseek64' 代替。我修改了 fop 但没有访问驱动程序中的 lseek 方法调用是: llseek(fd_secuencial, 0x0000000000000012, 0); fop 是: static struct file_operations fops = { .read = device_read, .llseek = device_llseek, .write = device_write, .open = device_open, .release = device_release };而 llseek 方法是: static loff_t device_llseek(struct file *, loff_t, int);非常感谢
  • lseek64() (man7.org/linux/man-pages/man3/lseek64.3.html) 的手册页说“上述所有功能都是根据 [_llseek 系统调用] 实现的”。我猜_llseek 系统调用是调用您的模块llseek() 文件操作的原因。您不必更改任何 fop 即可实现 lseek64()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
相关资源
最近更新 更多