Chamada do sistema P / Invoke ioctl
Estou desenvolvendo um aplicativo que precisa interagir com a abstração do Video4Linux. O aplicativo é desenvolvido em C #, usando o framework mono.
O problema que estou enfrentando é que eu não posso P / Invocar oioctl
chamada do sistema. Ou, mais precisamente, eu posso P / Invoke, mas ele falha muito.
A declaração externa é a seguinte:
<code>[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] private extern static int KernelIoCtrl(int fd, int request, IntPtr data); </code>
Por enquanto, tudo bem.
A rotina real que usa oKernelIoCtrl
é o seguinte:
<code>protected virtual int Control(IoSpecification request, object data) { GCHandle dataHandle; IntPtr dataPointer = IntPtr.Zero; try { // Pin I/O control data if (data != null) { dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); dataPointer = dataHandle.AddrOfPinnedObject(); } // Perform I/O control int result = KernelIoCtrl(mFileDescriptor, request.RequestCode, dataPointer); int errno = Marshal.GetLastWin32Error(); // Throw exception on errors if (errno != (int)ErrNumber.NoError) throw new System.ComponentModel.Win32Exception(errno); return (result); } finally { if (dataPointer != IntPtr.Zero) dataHandle.Free(); } } </code>
Todo o código acima parece bom. A classeIoSpecification
é usado para calcular o código de solicitação de E / S após a especificação do cabeçalho (basicamente segue a_IOC
macro declarado em/usr/include/linux/asm/ioctl.h
.
odata
parâmetro é uma estrutura, declarada da seguinte forma:
<code>[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct Capability { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string Driver; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string Device; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string BusInfo; public UInt32 Version; public CapabilityFlags Capabilities; [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] public UInt32[] Reserved; } </code>
que deve imitar a seguinte estrutura (declarada em/usr/include/linux/videodev2.h
):
<code>struct v4l2_capability { __u8 driver[16]; /* i.e. "bttv" */ __u8 card[32]; /* i.e. "Hauppauge WinTV" */ __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ __u32 version; /* should use KERNEL_VERSION() */ __u32 capabilities; /* Device capabilities */ __u32 reserved[4]; }; </code>
Antes de ocorrer a falha, havia um problema no cálculo do código de solicitação IOCTL eKernelIoCtrl
estava funcionando como esperado (retornandoerrno
igual aEINVAL). Quando eu corrigi o bug (e, na verdade, tenho o código de solicitação IOCTRL correto), a chamada foi iniciada para causar uma falha.
Em conclusão, parece que há um problema na organização da estrutura, mas não consigo ver o que está dando errado.
Temo que o problema seja a lista de argumentos variáveis, porque oioctl a rotina é declarada como segue (tirada do homem):
<code>int ioctl(int d, int request, ...); </code>
Mas eu vi muito código declarando a rotina acima comoint ioctl(int d, int request, void*);
e posso garantir que a solicitação IOCTRL específica leve apenas um argumento.