MikePol
Постоялец
Offline
|
|
« : 22-05-2008 06:59 » |
|
На примере Oney собрал драйвера для PCI устройства. Устройство работает только с портами ввода/вывода. Драйвер работает в 2000/XP, в 98-м пишет "ошибка код 10", но все равно работает. Скачал Windows Driver Kits для того, чтобы собрать под висту. Драйвер отлично собирается - никаких ошибок. Но при установке, после указания системе .sys файла появляется окно установки и оно зависает. В конце концов система выдает ошибку (истекло время ожидания). Для отладки под 2000/ХР я использовал DebugView ( в коде использую KdPrint). Под вистой эта утилита не работает (не может сделать Kernel Capture). Посмотреть в каком месте зависает не могу В чем может быть проблема ? Как под вистой можно смотреть отладочные сообщения драйвера ? И вообще какие отладчики существуют под Висту ?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #1 : 22-05-2008 10:34 » |
|
по поводу отладки - глянь пару постов назад, флаг в реестре надо взвести. где то я кидал ссылку. кстати, посмотри, у меня под вистой была ерунда, что в inf-е админские права на доступ по R/W стояли, а апликуха в висте по умолчанию от пользователя запускается, даже если ты админ. PS http://blogs.msdn.com/doronh/archive/2006/11/14/where-did-my-debug-output-go-in-vista.aspx"If you are using DbgPrint for your debug output in Vista you may have noticed that you cannot see anything in the debugger. That is because DbgPrint now defaults to the DEFAULT debug component (you can read about the change here) and the default settings for this component is to hide all output. To remedy this you can do either of the following Change the value of Kd_DEFAULT_MASK to 0xFFFFFFFF ('ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF') at runtime or right after boot Open up the registry and go to this path, HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter and add the following value "DEFAULT" : REG_DWORD : 0xFFFFFFFF and then reboot This will allow you to see your debug output, but you might see a lot of other components' output as well. One way to mitigate this is to use DbgPrintEx instead and pick the component ID which most closely matches your driver's functionality. Note that DbgPrintEx is only available on Windows XP and later so if you need to support Windows 2000 you might want want to stick with DbgPrint since choosing which function to use at runtime can be difficult (since passing var args can be difficult unless you have variadic parameter support for macros (which the latest WDK has))."
|
|
« Последнее редактирование: 22-05-2008 10:36 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #2 : 28-05-2008 06:05 » |
|
А Вы не могли бы объяснить где надо менять "Kd_DEFAULT_MASK to 0xFFFFFFFF " ? У меня раздела реестра "Debug Print Filter " не существует. Его надо создать , а потом добавить в него параметр "Default" со значением 0xFFFFFFFF ?
|
|
|
Записан
|
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #3 : 28-05-2008 06:38 » |
|
Все, разобрался, спасибо !
|
|
|
Записан
|
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #4 : 29-05-2008 07:23 » |
|
Проблема с DbgView решилась. Но запустить драйвер под вистой мне так и не удалось. Нормально отрабатывает DriverEntry, AddDivice, StartDevice (IRP_MN_START_DEVICE). Но установщик ОС пытается установить несколько минут ( полоска бегает) но потом выдает сообщение : "Возврат из операции произошел из-за превышения времени ожидания". DbgView показывает, что после этого приходят еще несколько пакетов (PNP), которые я отбрасываю. IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(pdx->LowerDeviceObject, Irp);
В диспетчере устройств, устройство отображается, как будто все драйвера нормально установились, однако , если зайти на вкладку ресуры - окно зависает. Устройство должно использовать диапазон портов ввода вывода (8 байт) Ниже код трех функций DriverEntry, AddDivice, StartDevice (IRP_MN_START_DEVICE). В чем может быть проблема ? extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { // DriverEntry KdPrint((DRIVERNAME " - Entering DriverEntry: DriverObject %8.8lX\n", DriverObject)); // Insist that OS support at least the WDM level of the DDK we use
if (!IoIsWdmVersionAvailable(1, 0)) { KdPrint((DRIVERNAME " - Expected version of WDM (%d.%2.2d) not available\n", 1, 0)); return STATUS_UNSUCCESSFUL; }
// See if we're running under Win98 or NT:
KdPrint(("\n NOW TEST RIGISTRY \n N")); win98 = FALSE;
#if DBG if (win98) KdPrint((DRIVERNAME " - Running under Windows 98\n")); else KdPrint((DRIVERNAME " - Running under NT\n")); #endif
DriverObject->DriverUnload = DriverUnload; DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; //DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite; // DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCleanup; // DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; //DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DispatchControl; cardnumber = 0;
KdPrint(("Mike : Entry Completed \n ")); //char tempstr = masind[cardnumber] ;
//KdPrint((tempstr));
return STATUS_SUCCESS; } // DriverEntry NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo) { // AddDevice PAGED_CODE(); KdPrint((DRIVERNAME " - Entering AddDevice: DriverObject %8.8lX, pdo %8.8lX\n", DriverObject, pdo)); NTSTATUS status=STATUS_SUCCESS;
// Create a function device object to represent the hardware we're managing.
PDEVICE_OBJECT fdo;
/*ULONG dxsize = (sizeof(DEVICE_EXTENSION) + 7) & ~7; ULONG xsize = dxsize ; */ /*UNICODE_STRING numberstr; RtlInitUnicodeString(&numberstr, L"XX");
RtlIntegerToUnicodeString(cardnumber, 0, &numberstr); */ UNICODE_STRING devname;
switch (cardnumber) { case 0: RtlInitUnicodeString(&devname, L"\\DosDevices\\lir940pci0");break; case 1: RtlInitUnicodeString(&devname, L"\\DosDevices\\lir940pci1");break; case 2: RtlInitUnicodeString(&devname, L"\\DosDevices\\lir940pci2");break; case 3: RtlInitUnicodeString(&devname, L"\\DosDevices\\lir940pci3"); } /*if (cardnumber) RtlInitUnicodeString(&devname, L"\\DosDevices\\lir940pci1"); else RtlInitUnicodeString(&devname, L"\\DosDevices\\lir940pci0"); */
//RtlAppendUnicodeStringToString(&devname , &numberstr);
cardnumber++;
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &devname, FILE_DEVICE_UNKNOWN, /*для 98*FILE_DEVICE_SECURE_OPEN*/ 0x00000100, FALSE, &fdo); if (!NT_SUCCESS(status)) { // can't create device object KdPrint((DRIVERNAME " - IoCreateDevice failed - %X\n", status)); return status; } // can't create device object PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// From this point forward, any error will have side effects that need to // be cleaned up.
do { // finish initialization pdx->DeviceObject = fdo; pdx->Pdo = pdo;
fdo->Flags |= DO_BUFFERED_IO;
pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo); if (!pdx->LowerDeviceObject) { // can't attach KdPrint((DRIVERNAME " - IoAttachDeviceToDeviceStack failed\n")); status = 0xC00002B6L; // для 98 STATUS_DEVICE_REMOVED; break; } // can't attach
// Clear the "initializing" flag so that we can get IRPs
fdo->Flags &= ~DO_DEVICE_INITIALIZING; } // finish initialization while (FALSE);
if (!NT_SUCCESS(status)) { // need to cleanup
KdPrint(("Mike ^ Error on Init ")); if (pdx->devname.Buffer) RtlFreeUnicodeString(&pdx->devname); if (pdx->LowerDeviceObject) IoDetachDevice(pdx->LowerDeviceObject); IoDeleteDevice(fdo); } // need to cleanup // if (NT_SUCCESS(status)) KdPrint(("MIke : AddDevice is OK "));
KdPrint((DRIVERNAME " - ADD DEVICE before status %X\n", status)); return status; } // AddDevice NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated) { // StartDevice NTSTATUS status=STATUS_SUCCESS; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// Identify the I/O resources we're supposed to use. KdPrint(("Mike : Entry Start Device "));
PHYSICAL_ADDRESS portbase; BOOLEAN gotport = FALSE; if (!translated) { KdPrint(("Resourse not translated !!! ")); return STATUS_DEVICE_CONFIGURATION_ERROR; // no resources assigned?? } KdPrint(("TRNSLATED OK !!! "));
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = translated->PartialDescriptors; ULONG nres = translated->Count; KdPrint((" N resourse %d \n", nres));
PHYSICAL_ADDRESS membase;
bool isport = TRUE;
for (ULONG i = 0; i < nres; ++i, ++resource) { // for each resource switch (resource->Type) { // switch on resource type
case CmResourceTypePort: portbase = resource->u.Port.Start; pdx->nports = resource->u.Port.Length; KdPrint((DRIVERNAME " - I/O resource PORT %d\n", portbase)); pdx->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0; gotport = TRUE;
break; case CmResourceTypeMemory: { membase = resource->u.Memory.Start;
pdx->mem_length = resource->u.Memory.Length; KdPrint((DRIVERNAME " - I/O resource MEMORY start = %X length =%d \n", pdx->mem_start,pdx->mem_length ));
gotport = TRUE;
isport = FALSE; break; } default: KdPrint((DRIVERNAME " - Unexpected I/O resource type %d\n", resource->Type)); break; } // switch on resource type } // for each resource
if (!(TRUE && gotport )) { KdPrint((DRIVERNAME " - Didn't get expected I/O resources\n")); return STATUS_DEVICE_CONFIGURATION_ERROR; }
pdx->portbase = (PUCHAR) portbase.QuadPart; pdx->portaddr = portbase.LowPart; KdPrint((DRIVERNAME " Mike - PortADDR %0x My ", pdx->portaddr )); KdPrint((DRIVERNAME " Mike - PortBASE %0x My ", pdx->portbase ));
// ResetDevice(pdx); // reset the device
KdPrint((DRIVERNAME "STATUS = %X\n",status));
if (!NT_SUCCESS(status)) { KdPrint((DRIVERNAME " - IoConnectInterrupt failed - %X\n", status)); if (pdx->portbase && pdx->mappedport) MmUnmapIoSpace(pdx->portbase, pdx->nports); pdx->portbase = NULL; return status; }
pdx->ismem_plata = !isport;
KdPrint((DRIVERNAME "Isport = %d\n",isport));
if (!isport) { pdx->mem_start = (PUCHAR) MmMapIoSpace(membase, pdx->mem_length, MmNonCached); if (!pdx->mem_start) return STATUS_NO_MEMORY; }
KdPrint((DRIVERNAME "The End Of StartDevice\n"));
// Initialize the device
// KeSynchronizeExecution(pdx->InterruptObject, (PKSYNCHRONIZE_ROUTINE) SetupDevice, pdx);
return status; } // StartDevice
|
|
« Последнее редактирование: 29-05-2008 07:41 от MikePol »
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #5 : 29-05-2008 09:17 » |
|
строка: for (ULONG i = 0; i < nres; ++i, ++resource) - не с того индекса. или с того? ++i и ++resource как-то непривычно выглядели))) обычно я i++ ...
if (!(TRUE && gotport )) - вообще не понял про мапирование портов.. надо так: if (devExt->Port.MappedPort) { //RISC архитектура (порты отображаются в оперативную память) devExt->PortBaseAddr = (DWORD) MmMapIoSpace (devExt->Port.Start, devExt->Port.Length, //==4*4 MmNonCached); }
и что то с последовательностью напутано... // ResetDevice(pdx); // reset the device после чего MmMapIoSpace...
да, еще. что в отладочных сообщениях то в итоге? до куда все дошло то?
|
|
« Последнее редактирование: 29-05-2008 09:30 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #6 : 29-05-2008 09:49 » |
|
строка: for (ULONG i = 0; i < nres; ++i, ++resource) - не с того индекса. или с того? ++i и ++resource как-то непривычно выглядели))) обычно я i++ ...
Там только один ресурс - 8 байт порта ввода вывода. Но, почему то цикл выполняется 2 раза, то есть nres = 2. Я сейчас всместо nres единицу поставил в условии цикла .
Мапирование портов я не делаю. isport = 1 ВСЕГДА для этого устройства.
ResetDevice закоментирован, я просто не стал вырезать. Вообще это "переработка" pci42 Oney. Была задача сделать быстро работоспособный драйвер. Поэтому редактировал пример, пока хоть как-то не заработало. Там много лишнего осталось, но убирать не стал - боялся что перестанет работать.
В отладочных сообщениях доходит до KdPrint((DRIVERNAME "The End Of StartDevice\n")); Потом ничего не происходит несколько минут, потом система выдает сообщение о превышении времени ожидания и после этого приходит 15 пакетов в висте и 4 в XP, которые я "скипаю" . Проблема в том, что в XP все отлично работает, а в висте - сообщение о превышении времени ожидания.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #7 : 29-05-2008 10:15 » |
|
pdx->portbase = (PUCHAR) portbase.QuadPart; это вы к чему? что за указатель?
про мапирование - пардон ошибся... я думал это код для мапироавния портов IO для RISC. хотя вообще говоря мало ли...)
перед обработкой и звхватом ресурсов я делаю status = SendIrpSynchronously(Irp, devExt->LowerDevice); и только после него проверяю ресурсы.
про nres = 2 - проверьте что за тип второго ресурса там возвращается.
PS SendIrpSynchronously - это мой СallDevice(lover) и ожидание завершения нижележащим драйвером. вроде как вначале надо делать.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #8 : 29-05-2008 10:21 » |
|
да, IRP_MN_START_DEVICE:
This IRP must be handled first by the parent bus driver for a device and then by each higher driver in the device stack.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #9 : 29-05-2008 12:06 » |
|
pdx->portbase = (PUCHAR) portbase.QuadPart; это вы к чему? что за указатель?
Он не используется нигде , я удалил его вообще.
про nres = 2 - проверьте что за тип второго ресурса там возвращается.
Тип ресурса - CmResourceTypeDevicePrivate
Если сначала вызывать IoCallDriver, то драйвер перезагружает XP, а в висте ничего не меняется. Опять через несколько минут ошибка времени ожидания .
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #10 : 29-05-2008 14:32 » |
|
CmResourceTypeDevicePrivate - его не надо обрабатывать. Если сначала вызывать IoCallDriver, то драйвер перезагружает XP, а в висте ничего не меняется. Опять через несколько минут ошибка времени ожидания .
- значит что то еще не правильно. перезагружать не должно. посмотрите поиском по DDK\src\kernel\ любой пример - ВЕЗДЕ первым делом IRP_MN_START_DEVICE пересылается ниже и ТОЛЬКО ПОТОМ обрабатывается. это ТРЕБОВАНИЕ DDK. покажите весь код обработки IRP_MN_START_DEVICE.
|
|
« Последнее редактирование: 29-05-2008 14:35 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #11 : 30-05-2008 03:45 » |
|
Странно, если бы это неправильно работало, то в и в XP и 98-м не работало. А тут только в Висте зависает. Вообще я пример Oney переделывал, вряд ли я изменил порядок вызова IoCallDriver. #pragma PAGEDCODE /// for Vista
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) { // DispatchPnp PAGED_CODE(); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG fcn = stack->MinorFunction;
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("In PnP Dispatch IRP - %X",Irp)); switch (fcn) { case IRP_MN_START_DEVICE: { // IoCallDriver(pdx->LowerDeviceObject, Irp); /// XP перезагружается PCM_PARTIAL_RESOURCE_LIST raw, translated; raw = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList; translated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
status = StartDevice(fdo,raw,translated); return CompleteRequest(Irp, status, Irp->Size); break; } case IRP_MN_REMOVE_DEVICE: { KdPrint((" MIke : IRP_MN_STOP_DEVICE")); StopDevice(fdo,FALSE); RemoveDevice(fdo); return STATUS_SUCCESS; break; } default: { KdPrint(("IRP PNP BY DEFAULT ")); IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(pdx->LowerDeviceObject, Irp); } } }
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #12 : 30-05-2008 10:38 » |
|
жесть... не ожидал такого от Ony... то есть вы вообще нижележащий драйвер(драйвер шины) не вызываете? ? это не правильно. вообще не правильно. что не появляется BSOD - вам повезло) значит так. когда к вам приходят IRP, вы должны не только обработать их сами, но и передать их дальше по стеку. (если в кратце) в какой последовательности их обрабатывать - указано в DDK. не передают IRP нижележащим драйверам только в двух случаях: либо драйвер шины(у него нет нижележащего), либо если вы завершаете его со статусом отличным от SUCCESS. да и то не всегда. заначится так. перед проверкой ресурсов, неплохо бы пропустить IRP дальше. причем дождаться полной его обработки драйвером шины. для этого необходимо вызвать такую функцию: NTSTATUS SendIrpSynchronously( IN PIRP Irp, IN PDEVICE_OBJECT LowerDevice) { DWORD status; KEVENT event; KdPrint( (": SendIrpSynchronously\n")); KeInitializeEvent( &event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine( Irp, Sh01CompletionRoutine, &event, TRUE,TRUE,TRUE);
status = IoCallDriver(LowerDevice, Irp);
if (STATUS_PENDING == status) { KeWaitForSingleObject( &event, Executive, // Waiting for reason of a driver KernelMode, // Must be kernelmode if event memory is in stack FALSE, // No allert NULL); // No timeout status = Irp->IoStatus.Status; }; KdPrint( ("SendIrpSynchronously-exit\n")); return status; } NTSTATUS Sh01CompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PKEVENT event; KdPrint( (": CompletionRoutine\n"));
event = (PKEVENT) Context; if (Irp->PendingReturned) { //по примеру XP - это не надо IoMarkIrpPending(Irp); //по DDK2000 - 'это просто необходимо;) KeSetEvent(event, 0, FALSE);//по примеру XP оно здесь } // // We could switch on the major and minor functions of the IRP to perform // different functions, but we know that Context is an event that needs // to be set. // //KeSetEvent(event, 0, FALSE);//так было в 2000 // // Allows the caller to reuse the IRP // KdPrint( (": CompletionRoutine-exit\n")); return STATUS_MORE_PROCESSING_REQUIRED; }
в PNP делать так: NTSTATUS status; PIO_STACK_LOCATION IOStack; PDEVICE_EXTENSION_MY devExt;
IOStack = IoGetCurrentIrpStackLocation(Irp); devExt = (PDEVICE_EXTENSION_MY)DeviceObject->DeviceExtension; switch (IOStack->MinorFunction) { case IRP_MN_START_DEVICE: //------------------------------------- status = SendIrpSynchronously(Irp, devExt->LowerDevice); //->начало обработки IRP...............
if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { ............... ВАША ОБРАБОТКА } else { //в противном случае не стартовало... KdPrint( (": Call Lower Driver - faled?\n")); status = STATUS_UNSUCCESSFUL; }; break; case IRP_MN_REMOVE_DEVICE: //запрос на удаление драйвера возвращает ТОЛЬКО! STATUS_SUCCESS
................... ТУТ удаляем все ресурсы!!!!!!!!!!!!!!!!!!
Irp->IoStatus.Status = STATUS_SUCCESS; //обязательно! остальные значения недопустимы!!!*** status = SkipCurrIrpStack_CallLowerDriver(devExt->LowerDevice,Irp);
IoDetachDevice( devExt->LowerDevice); IoDeleteDevice( DeviceObject ); //удаляем само устройство (!!! в том числе удаляется devExt!!!)
status = STATUS_SUCCESS; //обязательно! остальные значения недопустимы!!! return status;//<<<<<<<<<<<<<------------------ default: //данные запросы не определены, но я думаю, //что в целях на всякий сучай необходимо предусмотреть их обработку********* //впринципе такое возможно для более высокой версии WDM... может быть XP? // Pass down all the unhandled Irps. // status = SkipCurrIrpStack_CallLowerDriver(devExt->LowerDevice,Irp); IoReleaseRemoveLock(&devExt->RemoveLock, Irp); return status; };
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);//вернул по примеру XP return status; };
//пропуск IRP вниз по стеку и вызов нижележащего объекта устройства // *********************************************************************** DWORD __forceinline SkipCurrIrpStack_CallLowerDriver(PDEVICE_OBJECT LowerDevice, PIRP Irp) { IoSkipCurrentIrpStackLocation (Irp); return IoCallDriver(LowerDevice, Irp); }; PS вообще это не все что надо обрабатывать.... это какой то неправильный пример был. совсем не правильный... во вложении - пример драйвера PCI устройства с поддержкой портов IO (одно окно) и прерыванием. поддержаны READ|WRITE и IOCTL впрочем там много чего напихано, а нужно лишь обработка PNP. пример сделан на DriverStudio 3.2 примерно такой я брал за основу когда писал свои драйвера. PPS на самом деле у меня еще больше запросов обрабатывается. и QweryRemove - все запросы и QweryStop и т.д.
|
|
« Последнее редактирование: 30-05-2008 11:00 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #13 : 30-05-2008 10:56 » |
|
да, а откуда пример брали? глянуть бы... у ony был пример Generic с книжкой - там все правильно. короче вы меня не пугайте))) у Oney - все правильно в примере PCI42! там вызов ForwardAndWait функции в самом начале START_DEVICE. раз уж лень изучать подробно - берите пример из DS который я вам кинул. думаю он должен заработать.
|
|
« Последнее редактирование: 30-05-2008 11:09 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #14 : 02-06-2008 12:21 » |
|
Ochkarik, большое спасибо за ваши советы. На самом деле, мне хочется изучить это подробно. Сейчас я добавил функцию ForwardAndWait в DispatchPNP case IRP_MN_START_DEVICE: {
Irp->IoStatus.Status = STATUS_SUCCESS; // status = ForwardAndWait((PDEVICE_EXTENSION)fdo->DeviceExtension, Irp); // KdPrint((DRIVERNAME "STATUS = %d\n",status));
if (!NT_SUCCESS(status)) return CompleteRequest(Irp, status, Irp->IoStatus.Information);
PCM_PARTIAL_RESOURCE_LIST raw, translated; raw = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList; translated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
status = StartDevice(fdo,raw,translated); return CompleteRequest(Irp, status, Irp->IoStatus.Information); break;
Тестирую в ХР, система требует перезагрузки , то есть status, возвращаемый ForwardAndWait - не STATUS_SUCCESS. После перезагрузки драйвер нормально запускается. Правда, если его остановить, а потом запустить опять - требует перезагрузку. В чем может быть причина "неправильного" статуса ? ForwardAndWait NTSTATUS OnRequestComplete(PDEVICE_OBJECT junk, PIRP Irp, PKEVENT pev) { // OnRequestComplete KeSetEvent(pev, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } // OnRequestComplete
NTSTATUS ForwardAndWait(PDEVICE_EXTENSION pdx, PIRP Irp) { // ForwardAndWait PAGED_CODE(); KEVENT event; KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID) &event, TRUE, TRUE, TRUE);
IoCallDriver(pdx->LowerDeviceObject, Irp); KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); return Irp->IoStatus.Status; } // ForwardAndWait
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #15 : 02-06-2008 13:16 » |
|
ForwardAndWait - не при чем.
причина в том, что вы его не выгружаете целиком. или в том, что забыли при остановке и выгрузке все заянтые ресурсы освободить. скорее всего - первое.
при выгрузке вам помимо всего прочего придут IRP_MN_QUERY_STOP_DEVICE потом IRP_MN_STOP_DEVICE (или IRP_MN_CANCEL_STOP_DEVICE). по ним вы должны остановить и освободить ресурсы. - помоему это для перераспределения ресурсов. PS (сорри эт я облажался - при выгрузке они помоему не приходят. но такие IRP тоже есть)
перед выгрузкой помоему эти: так же бывают IRP_MN_QUERY_REMOVE_DEVICE потом IRP_MN_REMOVE_DEVICE (или IRP_MN_CANCEL_REMOVE_DEVICE) они посылаются перед удалением драйвера для освобождения ресурсов.
есть еще IRP_MN_SURPRISE_REMOVAL - это обычно для шин с горячей заменой(USB/ExpressCard/PCMCIA и т.д.). по IRP_MN_REMOVE_DEVICE, кстати - еще и IoDetachDevice( devExt->LowerDevice); IoDeleteDevice( DeviceObject ); //удаляем само устройство (!!! в том числе удаляется devExt!!!) сделать надо.
ForwardAndWait должна быть не только в START_DEVICE, но и остальных. но там надо смотреть по месту... обычно в случае начала процесса (обработки чего либо, старта и т.д.) сначала IRP шлется ниже по стеку(ForwardAndWait), потом обрабатывается самим драйвером. идея в том, что любой челен стека может "провалить" IRP. в случае "удаления" устройства(или отмены) - обычно наоборот(return IoCallDriver()), чтобы освободить все занятые ресурсы до того как начнет зачищать свои ресурсы нижележащий.
в общем посмотри еше раз пример Ony повнимательнее либо мой пример DevicePCI.zip. в DDK опять же пишут - что и в какой последовательности делать.
|
|
« Последнее редактирование: 02-06-2008 13:18 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #16 : 04-06-2008 06:12 » |
|
Все сделал , как в примере pci42 у Они (по крайней мере мне так кажется). В итоге в XP драйвер отлично запускается, останавливается, перезапускается. А в Висте зависает, причем не выводит некоторые отладочные сообщения. Я обрабатываю только 2 Irp c IRP_MN_PNP: 1. IRP_MN_START_DEVICE 2. IRP_MN_REMOVE_DEVICE Ну и в остальных случаях - спускаю по стеку вниз. вот DispatchPnp: NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) { // DispatchPnp PAGED_CODE(); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG fcn = stack->MinorFunction;
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("In PnP Dispatch IRP - %X\n",Irp)); switch (fcn) { case IRP_MN_START_DEVICE: {
KdPrint((DRIVERNAME "Enter in IRP_MN_START_DEVICE\n")); Irp->IoStatus.Status = STATUS_SUCCESS; // status = ForwardAndWait((PDEVICE_EXTENSION)fdo->DeviceExtension, Irp); //
KdPrint((DRIVERNAME "STATUS = %d\n",status));
if (!NT_SUCCESS(status)) return CompleteRequest(Irp, status, Irp->IoStatus.Information);
PCM_PARTIAL_RESOURCE_LIST raw, translated; raw = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList; translated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
status = StartDevice(fdo,raw,translated); return CompleteRequest(Irp, status, Irp->IoStatus.Information); break; } case IRP_MN_REMOVE_DEVICE: { KdPrint((" MIke : IRP_MN_STOP_DEVICE")); StopDevice(fdo,FALSE); RemoveDevice(fdo); IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(pdx->LowerDeviceObject, Irp); break; } default: { KdPrint(("IRP PNP BY DEFAULT ")); IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(pdx->LowerDeviceObject, Irp); } } }
Вот ForwardAndWait: NTSTATUS ForwardAndWait(PDEVICE_EXTENSION pdx, PIRP Irp) { // ForwardAndWait
KdPrint(("Before PAGED_CODE();\n")); PAGED_CODE(); KdPrint(("BeforeKeInitializeEvent\n")); KEVENT event; KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
KdPrint(("Before IoSetCompletionRoutine\n")); IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID) &event, TRUE, TRUE, TRUE);
KdPrint(("Before IoCallDriver\n")); IoCallDriver(pdx->LowerDeviceObject, Irp); KdPrint(("Before KeWaitForSingleObject\n")); KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
KdPrint(("Forward and Wait Complete STATUS = %d\n", Irp->IoStatus.Status));
return Irp->IoStatus.Status; } // ForwardAndWait
В ХР все отладочные сообщения выводятся. В Висте - в DispatchPnp выводится только KdPrint(("In PnP Dispatch IRP - %X\n",Irp)); Дальше выводятся сообщения из StartDevice. То есть в Висте ни KdPrint((DRIVERNAME "Enter in IRP_MN_START_DEVICE\n"));, ни одного сообщения из ForwardAndWait не выводятся, однако отображаются сообщения из StartDevice. Читаю Они, пока не нашел ничего в чем может быть проблема. Собираю с помощью Windows Vista and Windows Server Longhorn x86 Checked Build Environment. В XP этот драйвер работает, а в самой Висте не хочет
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #17 : 04-06-2008 07:43 » |
|
поводу отладочных сообщений: в XP был баг (в висте наверняка остался): при отладке, когда подряд следует много длинных отладочных сообщений, переполнялся системный буфер этих сообщений. в следствии чего, некоторые сообщения пропадали. уменьшите длинну сообщений. и уберите не нужные.
CompleteRequest(Irp, status, Irp->IoStatus.Information); - вот это, что за ерунда? вместо IoCompleteRequest(Irp, IO_NO_INCREMENT);?
далее, по IRP_MN_REMOVE_DEVICE, - что за RemoveDevice()? return IoCallDriver(pdx->LowerDeviceObject, Irp); - ересь!
я же привел пример кода. там указано то надо сделать и в какой последовательности.
в DDK глава есть: найдите описание IRP_MN_REMOVE_DEVICE, там ссылка "Handling an IRP_MN_REMOVE_DEVICE Request" а в ней, по ссылке "Removing a Device in a Function Driver ".
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
MikePol
Постоялец
Offline
|
|
« Ответ #18 : 04-06-2008 10:14 » |
|
CompleteRequest это практически то же самое, что и IoCompleteRequest #pragma LOCKEDCODE NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN UINT_PTR info) { // CompleteRequest Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } // CompleteRequest
RemoveDevice #pragma PAGEDCODE
VOID RemoveDevice(IN PDEVICE_OBJECT fdo) { // RemoveDevice PAGED_CODE(); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; NTSTATUS status; RtlFreeUnicodeString(&pdx->devname);
if (pdx->LowerDeviceObject) IoDetachDevice(pdx->LowerDeviceObject);
IoDeleteDevice(fdo); } // RemoveDevice
Там вроде тоже самое выполняется, что и в Вашем примере. Изменил порядок в IRP_MN_REMOVE: case IRP_MN_REMOVE_DEVICE: { KdPrint((" MIke : IRP_MN_STOP_DEVICE")); // StopDevice(fdo,FALSE);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp); IoCallDriver(pdx->LowerDeviceObject, Irp);
RemoveDevice(fdo); return STATUS_SUCCESS; break; }
Результат тот же. Виста подвисает и выдает сообщение о том , что истекло время ожидания. ХР работает отлично. По поводу сообщений: сообщения не выводятся из "середины". То есть до определенного сообщения выводятся все и после все. А только те, которые в case IRP_MN_START_DEVICE: не выводятся.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #19 : 04-06-2008 13:01 » |
|
вместо IoSkipCurrentIrpStackLocation(Irp); IoCallDriver(pdx->LowerDeviceObject, Irp); надо: ForwardAndWait() впрочем не думаю что поможет... буду думать.
да.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
|