Я пишу драйвер для карты памяти 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. И опять облом: линковщик выдает ошибку что не может залинковать ее. причем пути к либам я прописал. Короче, хелп ми плиз.
а в каком смысле правильно сделана? Ну как у Солдатова, и как в DDK описано. И в WinObj отображается. UNICODE_STRING symLinkName; #define SYM_LINK_NAME L"\\DosDevices\\MyDrv" RtlInitUnicodeString( &symLinkName, SYM_LINK_NAME ); IoCreateSymbolicLink( &symLinkName, &devName ); здесь devName - строка которая была передана в функцию IoCreateDevice().
кстати еще вот какое наблюдение: когда в WinObj открываешь перечень объектов устройств и двараза кликаешь на моем объекте устройства, то выскакивает окно ошибки Unable to Open. Подскажите кто нибудь, может на в AddDevice() надо вызывать IoCreateDevice()?
WinObj посылает IRP запрос IRP_MJ_CREATE для открытия хендла объекта, если он не удовлетворяется (а это можно случайно сделать, забыв обработать этот IRP), то открытие объекта с треском пролетает и вываливается знакомое уже сообщение об ошибке. Не каждый девайс можно так открыть. Только те, чьи дрова обрабатывают IRP_MJ_CREATE
я в DriverEntry пишу следующее: Код (Text): 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; DriverObject->MajorFunction[ IRP_MJ_POWER ] = ReadWrite_IRPhandler; DriverObject->MajorFunction[ IRP_MJ_CLEANUP ] = ReadWrite_IRPhandler; здесь для многих запросов просто заглушка из Солдатова. А вот текст ообработчика IRP_MJ_CREATE: NTSTATUS Create_File_IRPprocessing(IN PDEVICE_OBJECT fdo,IN PIRP Irp) { PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; // Задаем печать отладочных сообщений – если сборка отладочная #if DBG DbgPrint("-MyFirstDriver- Create File is %ws\n", &(IrpStack->FileObject->FileName.Buffer)); #endif return CompleteIrp(Irp,STATUS_SUCCESS,0); // Успешное завершение } Все как в Солдатове, только создание объекта устройства и символьной ссылки на него в AddDevice(), и добавлен обработчик IRP_MJ_PNP
не читал я Солдатова, и слава богу pIrp->IoStatus.Status= status; pIrp->IoStatus.Information = 0; return CompleteIrp(Irp, status, ...
мб стоит еще записать в Irp->IoStatus.Information = 0, Irp->IoStatus.Status = status; ? Моя стандартная DriverCreateClose для IRP_MJ_CREATE/IRP_MJ_CLOSE: Код (Text): NTSTATUS DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } Хотя хз, может это и не повлияет
Дело в том, что в Солдатове 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) Хотя, как я уже говорил в WinObj присутствуют и символьная ссылка и имя объекта устройство. И обработчик IRP_MN_START_DEVICE отрабатывает без проблем.
А-а, ну тогда ок При открытии девайса должно посылаться IRP_MJ_CREATE... чето у тебя не то Покажи код DriverEntry полностью. И ключи желательно тоже.
Вот код некоторых функций: 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; } //!!!!!!!!!!!ВСЕ ОСТАЛЬНЫЕ КОДЫ, В ЭТОМ ДИСПЕТЧЕРЕ ПОРОПУСКАЮТСЯ НИЖНЕМУ ДРАЙВЕРУ В СТЕКЕ!!!!!!!!!!!!!!!!!!!!!!!!!
Возможно проблема не только в этом (очень бегло просмотрел только функцию AddDevice), но в AddDevice обязательно нужно сбросить флаг DO_DEVICE_INITIALIZING. Иначе система будет считать, что давайс всё ещё не готов к работе. Код (Text): fdo->Flags &= ~DO_DEVICE_INITIALIZING; Настоятельно не рекомендую брать за основу исходики из вышеозначенной книги. В DDK их полно. Там тоже есть ошибки, но их значительно меньше.
Я вам крайне признателен. Действительно, убрав этот флаг, все стало работать нормально. Задав поиск в DDK по строке DO_DEVICE_INITIALIZING я нашел топик AddDevice Routines in Function or Filter Drivers в котором это сказано. Вы наверное правы не стоит обращаться к этой книге. По моему мнению она дает только некоторый ликбез по теме драйверов, но она на порядок лучше книги Валерии Комисаровой(у мнея сложилось такое мнение).
Возможно, но после издания перевода "Programming the Microsoft Driver Model, Second Edition" лучше все эти книжки ф топку. http://www.piter.com/book.phtml?978591180057 Перевод не читал, а подлинник ОЧЕНЬ рекомендую.