CUSE IOCTL 回复包含指向字符数组的结构体
CUSE IOCTL Reply with Struct Containing a Pointer to a Character Array
在 ctypes
和 FUSE
的 CUSE
部分的帮助下,我正在 python 中的用户 space 中实现设备驱动程序。这不是我的第一个 CUSE
驱动程序,过去我已经能够对 return 结构执行以下操作。
class tvStruct(Structure):
_fields_ = [("tv_sec",c_long),
("tv_usec",c_long)]
可以将 timeval 结构传递回使用具有适当编号的 IOCTL 调用的应用程序。以下是CUSE
驱动的IOCTL文件操作。
def ioctl(self, req, cmd, arg_p, file_info, uflags, in_buff_p, in_bufsz, out_bufsz):
ioctl = DECODE_IOC(cmd)
if ioctl == IOC_READ_TIMEVAL:
if not in_buff_p:
PyCuse.fuse_reply_ioctl_retry(req,
pointer(PyCuse.iovec(cast(arg_p,c_void_p),
sizeof(tvStruct))),1,
pointer(PyCuse.iovec(cast(arg_p,c_void_p),
sizeof(tvStruct))),1)
else:
tvPtr = cast(in_buff_p,POINTER(tvStruct))
PyCuse.fuse_reply_ioctl(req, 0, tvPtr, sizeof(tvStruct))
else:
print("%s Unrecognized IOCTL #...\n",self.devname)
PyCuse.fuse_reply_err(req,1)
我正在开发的当前驱动程序需要return一个包含指向字符数组的指针的结构。
# C++ Struct
typedef struct {
__u16 addr;
__u16 length;
__u8* pBuf;
} EEPromData;
# Python Class
class EEPromDataStruct(Structure):
_fields_ = [("addr",c_ushort),
("length",c_ushort),
("pBuf",POINTER(c_char))] # I have tried several other ctypes types
# for `pBuf`, but to no avail yet
我知道我无法将指针从 Python 分配给 pBuf
,因为它们不是同一个内存上下文。我还了解到,使用 copy_to_user
从内核 space 中这有点容易。我受要求是 python 应用程序的约束,因为它附加到 python GUI。我感谢所有帮助。
更新 1
我知道这可以通过fuse_reply_ioctl_retry
方法解决。此方法允许我从应用程序复制数据或向应用程序复制数据。现在的问题是,在第二次调用 fuse_reply_ioctl_retry
时,FUSE
return 向应用程序发送错误代码。我将继续尝试解决此问题,但在此期间如果有任何帮助,我将不胜感激。谢谢。
我想通了。诀窍是为要访问其内容的结构中的每个指针调用 fuse_reply_ioctl_retry
,无论是修改它们还是只是从中读取。事实证明,使用 python
和 ctypes
以及 FUSE/CUSE
非常麻烦,如果其他人正在这样做,我强烈建议为此应用程序切换到直接 C,因为 ctypes
可能已经够棘手了,但在 CUSE/FUSE
系统之上,它非常可怕。我会的,但我必须 python 因为这是另一个应用程序的附加组件。小吐槽结束。
这是解决方案的精简版。
# ctypes Structure for driver
class EEPromDataStruct(Structure):
_fields_ = [("addr",c_ushort),
("length",c_ushort),
("pBuf",c_ulong)] #u8*
# Note that this is a long instead of some pointer.
# This is so I can easily know the application address
# the pointer holds.
...
# The IOCTL file operation for this driver
def ioctl(self, req, cmd, arg_p, file_info, uflags, in_buff_p,
in_bufsz, out_bufsz):
ioctl = DECODE_IOC(cmd)
if ioctl == IOC_READ_EEPROM:
if not in_buff_p:
PyCuse.fuse_reply_ioctl_retry(req,pointer(PyCuse.iovec(
cast(arg_p,c_void_p),sizeof(
EEPromDataStruct))),1,None,0)
else:
if out_bufsz == 0:
eepromDataPtr = cast(in_buff_p,POINTER(EEPromDataStruct))
addr = eepromDataPtr.contents.addr
length = eepromDataPtr.contents.length
pBuf = eepromDataPtr.contents.pBuf
# Load from pBuf
out_iovecs = pointer(PyCuse.iovec(cast(pBuf,c_void_p),length))
in_iovecs = pointer(PyCuse.iovec(cast(pBuf,c_void_p),length))
PyCuse.fuse_reply_ioctl_retry(req,in_iovecs,1,out_iovecs,1)
else:
eepromBuff.value = "Some String Here"
PyCuse.fuse_reply_ioctl(req, 0, eepromBuff, out_bufsz)
else:
print("%s Unrecognized IOCTL #...\n",self.devname)
PyCuse.fuse_reply_err(req,1)
if not in_buff_p
将检查应用程序内存是否已加载到驱动程序中,如果没有,它将调用 fuse_reply_ioctl_retry
进行加载。请注意,现在的一个主要区别是为这次重试指定的输出数据向量是 None
。这很重要,因为我随后会检查输出大小。如果它是 0,那么我知道它是我的主要 EEPromDataStruct
并且我继续这条路。我准备了一些数据向量并重试。最后,我获取指针并为其内容分配一些字符串。
这是一个漫长的过程。但它有效。希望对有需要的人有所帮助。
在 ctypes
和 FUSE
的 CUSE
部分的帮助下,我正在 python 中的用户 space 中实现设备驱动程序。这不是我的第一个 CUSE
驱动程序,过去我已经能够对 return 结构执行以下操作。
class tvStruct(Structure):
_fields_ = [("tv_sec",c_long),
("tv_usec",c_long)]
可以将 timeval 结构传递回使用具有适当编号的 IOCTL 调用的应用程序。以下是CUSE
驱动的IOCTL文件操作。
def ioctl(self, req, cmd, arg_p, file_info, uflags, in_buff_p, in_bufsz, out_bufsz):
ioctl = DECODE_IOC(cmd)
if ioctl == IOC_READ_TIMEVAL:
if not in_buff_p:
PyCuse.fuse_reply_ioctl_retry(req,
pointer(PyCuse.iovec(cast(arg_p,c_void_p),
sizeof(tvStruct))),1,
pointer(PyCuse.iovec(cast(arg_p,c_void_p),
sizeof(tvStruct))),1)
else:
tvPtr = cast(in_buff_p,POINTER(tvStruct))
PyCuse.fuse_reply_ioctl(req, 0, tvPtr, sizeof(tvStruct))
else:
print("%s Unrecognized IOCTL #...\n",self.devname)
PyCuse.fuse_reply_err(req,1)
我正在开发的当前驱动程序需要return一个包含指向字符数组的指针的结构。
# C++ Struct
typedef struct {
__u16 addr;
__u16 length;
__u8* pBuf;
} EEPromData;
# Python Class
class EEPromDataStruct(Structure):
_fields_ = [("addr",c_ushort),
("length",c_ushort),
("pBuf",POINTER(c_char))] # I have tried several other ctypes types
# for `pBuf`, but to no avail yet
我知道我无法将指针从 Python 分配给 pBuf
,因为它们不是同一个内存上下文。我还了解到,使用 copy_to_user
从内核 space 中这有点容易。我受要求是 python 应用程序的约束,因为它附加到 python GUI。我感谢所有帮助。
更新 1
我知道这可以通过fuse_reply_ioctl_retry
方法解决。此方法允许我从应用程序复制数据或向应用程序复制数据。现在的问题是,在第二次调用 fuse_reply_ioctl_retry
时,FUSE
return 向应用程序发送错误代码。我将继续尝试解决此问题,但在此期间如果有任何帮助,我将不胜感激。谢谢。
我想通了。诀窍是为要访问其内容的结构中的每个指针调用 fuse_reply_ioctl_retry
,无论是修改它们还是只是从中读取。事实证明,使用 python
和 ctypes
以及 FUSE/CUSE
非常麻烦,如果其他人正在这样做,我强烈建议为此应用程序切换到直接 C,因为 ctypes
可能已经够棘手了,但在 CUSE/FUSE
系统之上,它非常可怕。我会的,但我必须 python 因为这是另一个应用程序的附加组件。小吐槽结束。
这是解决方案的精简版。
# ctypes Structure for driver
class EEPromDataStruct(Structure):
_fields_ = [("addr",c_ushort),
("length",c_ushort),
("pBuf",c_ulong)] #u8*
# Note that this is a long instead of some pointer.
# This is so I can easily know the application address
# the pointer holds.
...
# The IOCTL file operation for this driver
def ioctl(self, req, cmd, arg_p, file_info, uflags, in_buff_p,
in_bufsz, out_bufsz):
ioctl = DECODE_IOC(cmd)
if ioctl == IOC_READ_EEPROM:
if not in_buff_p:
PyCuse.fuse_reply_ioctl_retry(req,pointer(PyCuse.iovec(
cast(arg_p,c_void_p),sizeof(
EEPromDataStruct))),1,None,0)
else:
if out_bufsz == 0:
eepromDataPtr = cast(in_buff_p,POINTER(EEPromDataStruct))
addr = eepromDataPtr.contents.addr
length = eepromDataPtr.contents.length
pBuf = eepromDataPtr.contents.pBuf
# Load from pBuf
out_iovecs = pointer(PyCuse.iovec(cast(pBuf,c_void_p),length))
in_iovecs = pointer(PyCuse.iovec(cast(pBuf,c_void_p),length))
PyCuse.fuse_reply_ioctl_retry(req,in_iovecs,1,out_iovecs,1)
else:
eepromBuff.value = "Some String Here"
PyCuse.fuse_reply_ioctl(req, 0, eepromBuff, out_bufsz)
else:
print("%s Unrecognized IOCTL #...\n",self.devname)
PyCuse.fuse_reply_err(req,1)
if not in_buff_p
将检查应用程序内存是否已加载到驱动程序中,如果没有,它将调用 fuse_reply_ioctl_retry
进行加载。请注意,现在的一个主要区别是为这次重试指定的输出数据向量是 None
。这很重要,因为我随后会检查输出大小。如果它是 0,那么我知道它是我的主要 EEPromDataStruct
并且我继续这条路。我准备了一些数据向量并重试。最后,我获取指针并为其内容分配一些字符串。
这是一个漫长的过程。但它有效。希望对有需要的人有所帮助。