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.

questionAnswers(1)

yourAnswerToTheQuestion