P / Wywołaj wywołanie systemowe ioctl
Rozwijam aplikację, która musi współdziałać z abstrakcją Video4Linux. Aplikacja jest rozwijana w języku C #, przy użyciu platformy mono.
Problem, z którym mam do czynienia, polega na tym, że nie mogę P / Invoke theioctl
wywołanie systemowe. Albo, dokładniej, mogę go P / Invoke, ale źle się rozbija.
Deklaracja extern jest następująca:
<code>[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] private extern static int KernelIoCtrl(int fd, int request, IntPtr data); </code>
Jak na razie dobrze.
Rzeczywista procedura używającaKernelIoCtrl
jest następujące:
<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>
Cały powyższy kod wydaje się dobry. KlasaIoSpecification
jest używany do obliczania kodu żądania We / Wy zgodnie ze specyfikacją nagłówka (zasadniczo następuje po_IOC
makro zadeklarowane na/usr/include/linux/asm/ioctl.h
.
Thedata
parametr jest strukturą zadeklarowaną jako następująca:
<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>
który powinien naśladować następującą strukturę (zadeklarowaną w/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>
Przed awarią wystąpił problem w obliczaniu kodu żądania IOCTL iKernelIoCtrl
działał zgodnie z oczekiwaniami (wracającerrno
równaEINVAL). Kiedy poprawiłem błąd (i rzeczywiście miałem poprawny kod żądania IOCTRL), połączenie zaczęło powodować awarię.
Podsumowując, wydaje się, że istnieje problem w zestawianiu struktury, ale nie widzę, co się dzieje źle.
Obawiam się, że problemem jest zmienna lista argumentów, ponieważioctl procedura jest deklarowana jako następująca (wzięta od człowieka):
<code>int ioctl(int d, int request, ...); </code>
Ale widziałem dużo kodu deklarującego powyższą procedurę jakoint ioctl(int d, int request, void*);
, i mogę zapewnić, że konkretne żądanie IOCTRL wymaga tylko jednego argumentu.