Из пользовательского приложения не открывается объект устройства

Тема в разделе "WASM.NT.KERNEL", создана пользователем binom, 23 май 2007.

  1. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    Я пишу драйвер для карты памяти PcCard.
    Задача в следующем: драйвер должен загружаться, создавать объект устройства и подключаться в стек при подключении карточки и обеспечивать пользовательскому приложению работу с регистрами данной карточки.
    Я взял каркас драйвера из книги Солдатова. И переделал его следующим образом:
    В функции DriverEntry я зарегестрировал ссылку на свою функцию AddDevice() и обработчик IRP_MJ_PNP.
    Код отвечающий за создание объекта устройства и подключению его к стеку вынес в AddDevice().
    В обработчике IRP_MJ_PNP обрабатываю только IRP_MN_START_DEVICE, все остальные коды пропускаю для обработки дальше.
    В обработчике IRP_MN_START_DEVICE проецирую ресурсы карточки в системную память и выставляю режим работы карточки.
    Драйвер нормально загружается. В отладочных целях здесь же в IRP_MN_START_DEVICE произвожу обращение к регистрам карточки - команды отрабатывают нормально, это видно и в SoftICE и на логическом анализаторе, подключенном к шинам на карточке.

    Проблемы начались, когда я попытался открыть объект устройство из пользовательского приложения функцией
    Проблема 1:
    CreateFileW( L"\\\\.\\MyDrv", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
    В результате возвращается ошибка, чтото типа "Файл не найден", хотя в WinObj и имя объекта устройства и символьная ссылка на него присутствуют. При запуске примера из Солдатова все открывается нормально.


    Обратился к DDK. Нашел такую инфу, символические ссылки были в моде при программировании Legacy драйверов, а для WDM или хотябы худо-бедно PnP драйверов необходимо создавать безымянные объект устройства и регистрировать для него класс интерфейсов устройва.

    Проблема 2:
    Попробовал пойти этим путем. Все зарегистрировал в AddDevice() как написано в DDK. Теперь по образу и подобию примеров и DDK в юзерской проге пытаюсь вызвать SetupDiGetClassDevs. И опять облом: линковщик выдает ошибку
    что не может залинковать ее. причем пути к либам я прописал.

    Короче, хелп ми плиз.
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    а она точно правильно создана то?
     
  3. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    а в каком смысле правильно сделана? Ну как у Солдатова, и как в DDK описано. И в WinObj отображается.

    UNICODE_STRING symLinkName;
    #define SYM_LINK_NAME L"\\DosDevices\\MyDrv"
    RtlInitUnicodeString( &symLinkName, SYM_LINK_NAME );

    IoCreateSymbolicLink( &symLinkName, &devName );
    здесь devName - строка которая была передана в функцию IoCreateDevice().
     
  4. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    кстати еще вот какое наблюдение:
    когда в WinObj открываешь перечень объектов устройств и двараза кликаешь на моем объекте устройства, то выскакивает окно ошибки Unable to Open.
    Подскажите кто нибудь, может на в AddDevice() надо вызывать IoCreateDevice()?
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    WinObj посылает IRP запрос IRP_MJ_CREATE для открытия хендла объекта, если он не удовлетворяется (а это можно случайно сделать, забыв обработать этот IRP), то открытие объекта с треском пролетает и вываливается знакомое уже сообщение об ошибке. Не каждый девайс можно так открыть. Только те, чьи дрова обрабатывают IRP_MJ_CREATE
     
  6. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    я в DriverEntry пишу следующее:
    Код (Text):
    1.              DriverObject->DriverExtension->AddDevice            = MyAddDeviceFunc;
    2.     DriverObject->DriverUnload                          = UnloadRoutine;
    3.     DriverObject->MajorFunction[ IRP_MJ_CREATE ]        = Create_File_IRPprocessing;
    4.     DriverObject->MajorFunction[ IRP_MJ_CLOSE ]         = Close_HandleIRPprocessing;
    5.     DriverObject->MajorFunction[ IRP_MJ_READ ]          = ReadWrite_IRPhandler;
    6.     DriverObject->MajorFunction[ IRP_MJ_WRITE ]         = ReadWrite_IRPhandler;
    7.     DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ]= DeviceControlRoutine;
    8.     DriverObject->MajorFunction[ IRP_MJ_PNP ]           = PNP_IRPprocessing;
    9.  
    10.     DriverObject->MajorFunction[ IRP_MJ_POWER ]         = ReadWrite_IRPhandler;
    11.     DriverObject->MajorFunction[ IRP_MJ_CLEANUP ]         = ReadWrite_IRPhandler;
    12. здесь для многих запросов просто заглушка из Солдатова.
    13.  
    14.  А вот текст ообработчика IRP_MJ_CREATE:
    15. NTSTATUS Create_File_IRPprocessing(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
    16. {
    17.     PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
    18.  
    19.    
    20.     NTSTATUS status = STATUS_SUCCESS;
    21.  
    22.  
    23.     // Задаем печать отладочных сообщений – если сборка отладочная
    24.     #if DBG
    25.     DbgPrint("-MyFirstDriver- Create File is %ws\n", &(IrpStack->FileObject->FileName.Buffer));
    26.     #endif
    27.    
    28.     return CompleteIrp(Irp,STATUS_SUCCESS,0); // Успешное завершение
    29. }
    Все как в Солдатове, только создание объекта устройства и символьной ссылки на него в AddDevice(), и добавлен обработчик IRP_MJ_PNP
     
  7. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    не читал я Солдатова, и слава богу

    pIrp->IoStatus.Status= status;
    pIrp->IoStatus.Information = 0;
    return CompleteIrp(Irp, status, ...
     
  8. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    мб стоит еще записать в Irp->IoStatus.Information = 0, Irp->IoStatus.Status = status; ?

    Моя стандартная DriverCreateClose для IRP_MJ_CREATE/IRP_MJ_CLOSE:
    Код (Text):
    1. NTSTATUS DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    2. {
    3.     Irp->IoStatus.Information = 0;
    4.     Irp->IoStatus.Status = STATUS_SUCCESS;
    5.  
    6.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
    7.     return STATUS_SUCCESS;
    8. }
    Хотя хз, может это и не повлияет
     
  9. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    Дело в том, что в Солдатове
    NTSTATUS CompleteIrp( PIRP Irp, NTSTATUS status, ULONG info)
    {
    Irp->IoStatus.Status = status;
    Irp->IoStatus.Information = info;
    IoCompleteRequest(Irp,IO_NO_INCREMENT);
    return status;
    }

    Так что запрос завершается нормально. Я с помощью IRPTrace посмотрел при вызове CreateFile из высокоуровнего приложения никаких запросов в драйвер не происходит.
    У меня возникло предположение, что возможно в ключах реестра все дело. Я их накопировал из какого-то примера.
     
  10. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    Да вот я на что наткнулся, не знаю как я раньше не посмотрел туда.

    В диспетчере устройств для данного устройства нарисован желтый восклицательный знак и
    в поле Состояние устройства запись: запуск этого устройства невозможен(код 10)
    Хотя, как я уже говорил в WinObj присутствуют и символьная ссылка и имя объекта устройство. И обработчик IRP_MN_START_DEVICE отрабатывает без проблем.
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    А-а, ну тогда ок :)
    При открытии девайса должно посылаться IRP_MJ_CREATE... чето у тебя не то ;) Покажи код DriverEntry полностью.
    И ключи желательно тоже.
     
  12. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    Вот код некоторых функций:
    NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath )
    {
    NTSTATUS status = STATUS_SUCCESS;


    DriverObject->DriverExtension->AddDevice = MyAddDeviceFunc;
    DriverObject->DriverUnload = UnloadRoutine;
    DriverObject->MajorFunction[ IRP_MJ_CREATE ] = Create_File_IRPprocessing;
    DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = Close_HandleIRPprocessing;
    DriverObject->MajorFunction[ IRP_MJ_READ ] = ReadWrite_IRPhandler;
    DriverObject->MajorFunction[ IRP_MJ_WRITE ] = ReadWrite_IRPhandler;
    DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = DeviceControlRoutine;
    DriverObject->MajorFunction[ IRP_MJ_PNP ] = PNP_IRPprocessing;

    return status;
    }


    NTSTATUS MyAddDeviceFunc( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject )
    {
    PDEVICE_OBJECT fdo;
    UNICODE_STRING devName;

    NTSTATUS status = STATUS_SUCCESS;

    RtlInitUnicodeString( &devName, L"\\Device\\MyDevice1" );

    status = IoCreateDevice(DriverObject,
    sizeof(EXAMPLE_DEVICE_EXTENSION),
    &devName, // может быть и NULL
    FILE_DEVICE_UNKNOWN,
    0,//FILE_DEVICE_SECURE_OPEN,
    FALSE, // без эксклюзивного доступа
    &fdo);
    if(!NT_SUCCESS(status))
    return status;




    PEXAMPLE_DEVICE_EXTENSION dx = (PEXAMPLE_DEVICE_EXTENSION)fdo->DeviceExtension;
    dx->fdo = fdo; // Сохраняем обратный указатель


    //коннектим в стек
    dx->nextFDO = IoAttachDeviceToDeviceStack( fdo, PhysicalDeviceObject );

    // Объект спин-блокировки, который будем использовать для
    // разнесения во времени выполнения кода обработчика
    // IOCTL запросов. Инициализируем его:
    KeInitializeSpinLock(&MySpinLock);

    UNICODE_STRING symLinkName;
    #define SYM_LINK_NAME L"\\DosDevices\\MyDrv"
    RtlInitUnicodeString( &symLinkName, SYM_LINK_NAME );
    dx->ustrSymLinkName = symLinkName;

    // Создаем символьную ссылку

    status = IoCreateSymbolicLink( &symLinkName, &devName );


    if (!NT_SUCCESS(status))
    { // при неудаче – удалить Device Object и вернуть управление
    IoDeleteDevice( fdo );
    return status;
    }

    return status;

    }
    NTSTATUS PNP_IRPprocessing( IN PDEVICE_OBJECT fdo, IN PIRP Irp )
    {
    NTSTATUS status = STATUS_SUCCESS;
    PIO_STACK_LOCATION pIRPCell = IoGetCurrentIrpStackLocation( Irp );

    PCM_RESOURCE_LIST resList;

    PEXAMPLE_DEVICE_EXTENSION dx = (PEXAMPLE_DEVICE_EXTENSION)fdo->DeviceExtension;
    UCHAR i;
    PIO_STACK_LOCATION pNewIRPCell;

    PPCMCIA_INTERFACE_STANDARD pInterfacePCMCIA;
    USHORT res;


    switch( pIRPCell->MinorFunction )
    {
    case IRP_MN_START_DEVICE :
    {

    //----------------------------отправляем этот запрос нижнему драйверу,------------------
    IoCopyCurrentIrpStackLocationToNext( Irp );
    KeInitializeEvent( &myEvent, NotificationEvent, 0);

    //здесь не приведен код функции MyCompletion, я опишу словами: в нем событие
    //устанавливается в сигнальное состояние и
    //возвращается статус STATUS_MORE_PROCESSING_REQUIRED, для того чтобы мы смогли
    //завершить обработку этого пакета, прежде,чем вернуть управление диспечеру PnP

    IoSetCompletionRoutine( Irp, MyCompletion, &myEvent, TRUE, TRUE, TRUE );
    status = IoCallDriver( dx->nextFDO, Irp);

    if( !NT_SUCCESS( status ) )
    {
    return status;
    }
    status = KeWaitForSingleObject( &myEvent, Executive, KernelMode, TRUE, 0);
    //--------------------------------------------------------------------------------------
    pIRPCell = IoGetCurrentIrpStackLocation( Irp );

    if( pIRPCell == NULL)
    {
    return STATUS_INSUFFICIENT_RESOURCES;
    }

    //берем список ресурсов который прислал PnP менеджер
    resList = pIRPCell->Parameters.StartDevice.AllocatedResources;
    if( resList == 0 )
    {
    CompleteIrp( Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
    }
    for( i = 0; i < resList->List->PartialResourceList.Count; i ++)
    {//делаем их разделяемыми

    resList->List->PartialResourceList.PartialDescriptors[ i ].ShareDisposition = 3;
    }
    //выделяем память под структуру для адресов
    pMem = (PMYMEMORY)ExAllocatePoolWithTag( NonPagedPool, sizeof( MYMEMORY ),
    0x206D6456);
    if( pMem == 0 )
    {
    CompleteIrp( Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
    }
    pMem->Start = resList->List->PartialResourceList.PartialDescriptors[ 0 ].u.Memory.Start;
    pMem->Length = resList->List->PartialResourceList.PartialDescriptors[ 0 ].u.Memory.Length;


    //проецируем физические адреса, которые выделены карточке PnP менеджером на
    //системное адресное пространство
    pMem->pSystemMem = MmMapIoSpace( pMem->Start, pMem->Length, MmNonCached);

    if( pMem->pSystemMem == NULL )
    {
    ExFreePool( pMem );
    return STATUS_INSUFFICIENT_RESOURCES;
    }

    //карточка работает в 16 разрядном режиме адресации, поэтому необходимо
    //гарантированно ее перевести в это состояние
    //-посылаем запрос нижележащему драйверу IRP_MN_QUERY_INTERFACE
    pNewIRP = IoAllocateIrp( dx->nextFDO->StackSize, 0);

    if( pNewIRP == NULL )
    {
    ExFreePool( pMem );
    return STATUS_INSUFFICIENT_RESOURCES;
    }

    //пакет IRP выделили так, что для текущего драйвера ячейки стека нету.
    //переходим к ячейке стека, предназначенной для следующего в стеке драйвера
    pNewIRPCell = IoGetNextIrpStackLocation( pNewIRP );


    pInterfacePCMCIA = (PPCMCIA_INTERFACE_STANDARD)ExAllocatePoolWithTag( NonPagedPool,
    sizeof( PCMCIA_INTERFACE_STANDARD ),
    0x206D6450);
    pNewIRP->IoStatus.Status = STATUS_NOT_SUPPORTED;

    pNewIRPCell->MajorFunction = IRP_MJ_PNP;
    pNewIRPCell->MinorFunction = IRP_MN_QUERY_INTERFACE;
    pNewIRPCell->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCMCIA_INTERFACE_STANDART;
    pNewIRPCell->Parameters.QueryInterface.Interface = (PINTERFACE)pInterfacePCMCIA;
    pNewIRPCell->Parameters.QueryInterface.Size = sizeof( PCMCIA_INTERFACE_STANDARD );
    pNewIRPCell->Parameters.QueryInterface.InterfaceSpecificData = 0;
    pNewIRPCell->Parameters.QueryInterface.Version = 1;


    KeInitializeEvent( &myEvent2, NotificationEvent, 0);
    //в этой функции завершиния аналогично устанавливаем событие в сигнальное состояние
    //и возвращаем статус STATUS_MORE_PROCESSING_REQUIRED
    IoSetCompletionRoutine( pNewIRP, MyCompletion2, &myEvent2, TRUE, TRUE, TRUE );

    status = IoCallDriver( dx->nextFDO, pNewIRP );

    if( !NT_SUCCESS( status ) )
    {
    ExFreePool( pMem );
    return status;
    }

    status = KeWaitForSingleObject( &myEvent2, Executive, KernelMode, TRUE, 0);

    if( !NT_SUCCESS( status ) )
    {
    ExFreePool( pMem );
    return status;
    }

    //устанавливаем непосредственно 16 разрядную адресацию
    (pInterfacePCMCIA->ModifyMemoryWindow)( pInterfacePCMCIA->Context, // IN PVOID Context
    (ULONGLONG)(pMem->Start).QuadPart, //IN PHYSICAL_MEMORY HostBase,
    (ULONGLONG)0, //IN PHYSICAL_MEMORY CardBase,
    TRUE, //IN BOOLEAN Enable,
    0x1000, //IN ULONG WindowSize,
    2, //IN UCHAR AccessSpeed, PCMCIA_MEMORY_16BIT_ACCESS,//IN UCHAR BusWidth,
    FALSE );//IN BOOLEAN AttributeMemory


    return STATUS_SUCCESS;

    }

    //!!!!!!!!!!!ВСЕ ОСТАЛЬНЫЕ КОДЫ, В ЭТОМ ДИСПЕТЧЕРЕ ПОРОПУСКАЮТСЯ НИЖНЕМУ ДРАЙВЕРУ В СТЕКЕ!!!!!!!!!!!!!!!!!!!!!!!!!
     
  13. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Возможно проблема не только в этом (очень бегло просмотрел только функцию AddDevice), но в AddDevice обязательно нужно сбросить флаг DO_DEVICE_INITIALIZING. Иначе система будет считать, что давайс всё ещё не готов к работе.
    Код (Text):
    1. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
    Настоятельно не рекомендую брать за основу исходики из вышеозначенной книги. В DDK их полно. Там тоже есть ошибки, но их значительно меньше.
     
  14. binom

    binom New Member

    Публикаций:
    0
    Регистрация:
    26 дек 2006
    Сообщения:
    12
    Я вам крайне признателен. Действительно, убрав этот флаг, все стало работать нормально. Задав поиск в DDK по строке DO_DEVICE_INITIALIZING я нашел топик AddDevice Routines in Function or Filter Drivers в котором это сказано.
    Вы наверное правы не стоит обращаться к этой книге. По моему мнению она дает только некоторый ликбез по теме драйверов, но она на порядок лучше книги Валерии Комисаровой(у мнея сложилось такое мнение).
     
  15. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Возможно, но после издания перевода "Programming the Microsoft Driver Model, Second Edition" лучше все эти книжки ф топку.

    http://www.piter.com/book.phtml?978591180057

    Перевод не читал, а подлинник ОЧЕНЬ рекомендую.