P / Invoke ioctl системный вызов

Я разрабатываю приложение, которое должно взаимодействовать с абстракцией Video4Linux. Приложение разработано на C # с использованием моно фреймворка.

Проблема, с которой я сталкиваюсь, заключается в том, что я не могу P / вызватьioctl системный вызов. Или, точнее, я могу P / Invoke его, но он плохо падает.

Внешняя декларация выглядит следующим образом:

<code>[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private extern static int KernelIoCtrl(int fd, int request, IntPtr data);
</code>

Все идет нормально.

Фактическая процедура, которая используетKernelIoCtrl является следующим:

<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>

Весь приведенный выше код выглядит хорошо. КлассIoSpecification используется для вычисления кода запроса ввода-вывода в соответствии со спецификацией заголовка (в основном_IOC макрос объявлен в/usr/include/linux/asm/ioctl.h.

data Параметр - это структура, объявленная следующим образом:

<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>

которая должна имитировать следующую структуру (объявлена в/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>

До сбоя возникла проблема при вычислении кода запроса IOCTL, иKernelIoCtrl работал как ожидалось (возвращаяerrno равноEINVAL). Когда я исправил ошибку (и действительно имел правильный код запроса IOCTRL), вызов начал вызывать сбой.

В заключение, кажется, что существует проблема в распределении структуры, но я не вижу, что происходит неправильно.

Я боюсь, что проблема в списке переменных аргументов, потому чтоioctl рутина объявляется следующим образом (взято из человека):

<code>int ioctl(int d, int request, ...);
</code>

Но я видел много кода, объявляющего вышеупомянутую процедуру какint ioctl(int d, int request, void*);и я могу гарантировать, что конкретный запрос IOCTRL принимает только один аргумент.

Ответы на вопрос(1)

Ваш ответ на вопрос