Проблемы синхронизации в драйвере USB устройства

Тема в разделе "WASM.NT.KERNEL", создана пользователем er1ss, 23 июл 2008.

  1. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Добрый день всем!

    Есть следующая задача:

    Существует некое устройство USB2.0 которое работает в режиме HiSpeed и посылает данные в реальном времени. Устройство имеет две конечные Interrupt и Bulk.

    Конечная точка Bulk используется для передачи данных.
    Конечная точка Interrupt используется для синхронизации.

    Через конечную точку Bulk посылается массив данных фиксированной длины (1.5 МБ) - фрейм. Данные внутри фрейма передается непрерывно без интервалов по 512 байт в пакете. Между фреймами есть небольшой интервал времени когда данные не посылаются.

    Для того чтобы засинхронизировать передачу массива данных через конечную точку прерываний передаются пакеты в которых указан маркер начала фрейма и номер текущего фрейма.
    Фреймы поступают с частотой 30 Гц (период 33 мс) интервал между фреймами ~5 мс.

    Для того чтобы зацепить начало фрейма опрашивается конечная точка прерываний и как только получен маркер начала фрейма запускается функция чтения массива данных.

    В коде это выглядит приблизительно так:

    NTSTATUS
    USBC_StartBulkStream(
    IN PDEVICE_OBJECT DeviceObject
    )
    {
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PBULK_STREAM_OBJECT streamObject;
    LARGE_INTEGER dueTime;
    BOOLEAN inQueue;
    ULONG i;
    KIRQL irql;

    PUSBC_DEVICE_EXTENSION pDx = DeviceObject->DeviceExtension;

    irql = KeGetCurrentIrql();
    USBC_DbgMessage( ("USBC_StartBulkStream(): function called at IRQL = %d\n", irql) );

    if (irql > DISPATCH_LEVEL)
    USBCAM_DbgMessage( ("USBC_StartBulkStream(): function called at Rised IRQL = %d\n", irql) );

    if (irql == PASSIVE_LEVEL)
    {
    USBC_DbgMessage( ("USBC_StartBulkStream(): Rising thread priority to LOW_REALTIME_PRIORITY\n") );
    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY + 2);
    }

    if (NULL != pDx->StreamConfigured)
    {
    USBC_DbgMessage( ("USBC_StartBulkStream(): Stream not cofigured\n") );

    ntStatus = STATUS_INVALID_DEVICE_STATE;
    goto StartBulkStream_exit;
    }

    if (NULL != pDx->StreamObject )
    {
    USBC_DbgMessage( ("USBC_StartBulkStream(): StreamObject alredy allocated\n") );

    ntStatus = STATUS_INVALID_DEVICE_STATE;
    goto StartBulkStream_exit;
    }

    if (NULL == pDx->DataPipeHandle)
    {
    USBC_DbgMessage( ("USBC_StartBulkStream(): Invalid PipeHandle\n") );

    ntStatus = STATUS_INVALID_DEVICE_STATE;
    goto StartBulkStream_exit;
    }

    // allocate BulkStreamObject
    streamObject = ExAllocatePool( NonPagedPool, sizeof(BULK_STREAM_OBJECT) );

    // reset frame count
    pDx->CurrentFrame = 0;

    if (streamObject)
    {
    RtlZeroMemory( streamObject, sizeof(BULK_STREAM_OBJECT) );

    streamObject->DeviceObject = DeviceObject;

    streamObject->PipeHandle = pDx->DataPipeHandle;
    streamObject->Address = pDx->DataPipeAddress;
    //
    streamObject->TransferSize = pDx->RawFrameLength;

    // event to be set when PendingIrps == 0; signals stream can be stopped
    KeInitializeEvent(&streamObject->NoPendingIrpEvent, NotificationEvent, FALSE);

    //
    streamObject->BulkStreamStarted = TRUE;

    // waiting for sync
    ntStatus = USBC_StreamSyncWait(DeviceObject);

    // This initializes the pair of IRP/URBS that we will keep endlessly recycling
    // until the stream is stoppped; at least one of these pairs will always be in
    // use and one will be available so continuous throughput is maintained.
    for (i=0; i < BULKUSB_MAX_IRP; i++)
    {
    ntStatus = USBC_StartTransfer(DeviceObject, streamObject, i);

    if (!NT_SUCCESS(ntStatus))
    {
    USBC_DbgMessage( ("USBC_StartBulkStream(): USBC_StartTransfer Error, Status = 0x%x\n", ntStatus) );
    break;
    }
    }

    if (streamObject->PendingIrps)
    {
    pDx->StreamObject = streamObject;

    } else {

    ExFreePool(streamObject);
    pDx->StreamObject = NULL;
    }
    } else { //streamObject

    ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    }

    StartBulkStream_exit:

    if (irql == PASSIVE_LEVEL)
    {
    USBC_DbgMessage( ("USBC_StartBulkStream(): Lowering thread priority to BASE_PRIORITY\n") );
    KeSetBasePriorityThread (KeGetCurrentThread(), 0);
    }
    return ntStatus;
    }

    Здесь внутри функции USBC_StreamSyncWait(DeviceObject) происходит ожидание маркера синхронизации и как только он получен функция возвращает управление основному коду. Прблема заключается в том что между моментом получения маркера синхронизации и возвратом в основной код может происходить и соствено происходит переключение потоков и соответственно потеря времени (квант на поток 16 мс) и фрейм уже читается не с начала а с каким то неизвестым смещением причем вычислить его по данным не представляется возможным.

    Может у кого-то есть соображения как победить проблему или кто-то уже сталкивался с подобной ситуацией.

    Спасибо!!!!!