P / Invocar llamada al sistema ioctl
Estoy desarrollando una aplicación que necesita interactuar con la abstracción de Video4Linux. La aplicación se desarrolla en C #, usando el framework mono.
El problema al que me enfrento es que no puedo P / Invocar elioctl
llamada al sistema. O, más precisamente, puedo P / Invocarlo, pero se bloquea gravemente.
La declaración externa es la siguiente:
<code>[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] private extern static int KernelIoCtrl(int fd, int request, IntPtr data); </code>
Hasta ahora tan bueno.
La rutina real que utiliza elKernelIoCtrl
es el siguiente:
<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 el código anterior parece bueno. La claseIoSpecification
se utiliza para calcular el código de solicitud de E / S siguiendo la especificación del encabezado (básicamente, sigue la_IOC
macro declarada en/usr/include/linux/asm/ioctl.h
.
losdata
El parámetro es una estructura, declarada de la siguiente manera:
<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 debe imitar la siguiente estructura (declarada en/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 tener la falla, hubo un problema en el cálculo del código de solicitud de IOCTL y laKernelIoCtrl
estaba trabajando como se esperaba (devolviendo unerrno
igual aEINVAL). Cuando corregí el error (y de hecho con el código de solicitud IOCTRL correcto), la llamada comenzó a causar un bloqueo.
En conclusión, parece que hay un problema en el ordenamiento de la estructura, pero no puedo ver qué está mal.
Me temo que el problema es la lista de argumentos variables, porque laioctl La rutina se declara como sigue (tomada del hombre):
<code>int ioctl(int d, int request, ...); </code>
Pero vi mucho código declarando la rutina anterior comoint ioctl(int d, int request, void*);
, y puedo asegurarme de que la solicitud IOCTRL específica tome solo un argumento.