Есть 2 LPT-ключа. В Windows XP информацию о них можно получить с помощью программы chkey32w.exe, входящей в состав ИБ 8.5.
Created attachment 929 [details] Информация о первом ключе
Created attachment 930 [details] Информация о втором ключе
Драйвер ключа sentinel.sys падает во время выполнения DriverEntry из-за вызова нереализованной функции IoQueryDeviceDescription (http://msdn.microsoft.com/en-us/library/aa490868.aspx).
Если модифицировать IoGetDeviceObjectPointer, чтобы возвращалось STATUS_SUCCESS, и IoBuildDeviceIoControlRequest, чтобы она ничего не делала и просто возвращала ненулевой указатель, то при загрузке драйвера получаем: fixme:ntoskrnl:IoGetDeviceObjectPointer stub: L"\\Device\\ParallelPort0" 80 0x842db4fc 0x842db4f8 fixme:ntoskrnl:ObfDereferenceObject stub: 0x842db8e4 trace:ntoskrnl:ExAllocatePoolWithTag 244 pool 1 -> 0x81011c20 trace:ntoskrnl:KeInitializeEvent 0x842db48c 0 0 trace:ntoskrnl:IoBuildDeviceIoControlRequest 160030, (nil), (nil), 0, 0x842db4b4, 32, 1, 0x842db48c, 0x842db484 trace:ntoskrnl:__regs_IofCallDriver (nil) 0x12121212 wine: Unhandled page fault on write access to 0x12121235 at address 0x84a886fc (thread 001b), starting debugger... 160030 - это IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO (http://msdn.microsoft.com/en-us/library/ms799485.aspx).
Модифицировал функцию IoGetDeviceObjectPointer так, чтобы она создавала новое устройство и возвращала указатель на него, если первый параметр \Device\ParallelPort0. Добавил несколько стабов. Исправил ObfDereferenceObject.
Добавил ещё несколько стабов. Драйвер не падает. DriverEntry (функция драйвера, вызываемая при его инициализации) возвращает ошибку STATUS_NO_SUCH_DEVICE.
Внесены изменения в функции IoBuildDeviceIoControlRequest, IofCompleteRequest, IofCallDriver и process_ioctl. Написан дополнительный тест для IoBuildDeviceIoControlRequest. Написан тест для IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO.
Добавлена функция wine_complete_request, аналог IofCompleteRequest с конвенцией вызова cdecl. Вызовы IofCompleteRequest в wineusbhub заменены на вызовы wine_complete_request. Изменены обработчики IOCTL в mountmgr так, чтобы перед возвратом из них происходил вызов wine_complete_request.
Написан тест для функции IoQueryDeviceDescription.
Добавил стаб для KeStallExecutionProcessor. Написал тест для IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO. Написал тестовую программу (под Linux), открывающую порт с помощью ieee1284_open. На atlant с LPT-ключом порты открываются, если пользователь root, иначе в логе strace ошибки при выполнении ioperm(0x378, 0x3, 0x1) и при открытии /dev/port. ieee1284_get_deviceid завершается под пользователем из группы lp с ошибкой -7 (Error initialising port), под root при первом вызове -8 (Error interfacing system), при последующих -10 (Invalid port). Вывод тестовой программы из libieee1284-0.2.10: # ./test Found 3 ports: 0x278: 0x378: 0x3bc: 0x278: inaccessible 0x378: inaccessible 0x3bc: inaccessible
./test выполнялась под root
Описанные выше проблемы с библиотекой libieee1284 исчезают при использовании версии 0.2.11.
Реализовал чтение/запись для регистров data, dsr (только чтение) и dcr (с некоторой оговоркой, см. NOTE в ieee1284.h) параллельного порта с помощью libieee1284. DriverEntry завершается успешно.
Переделал функцию IoGetDeviceObjectPointer так, что она теперь работает для всех устройств, а не только для \Device\ParallelPort0. Перенёс создание устройства \Device\ParallelPort0 в новый модуль parport.sys.
Добавил в configure.ac проверки на наличие libieee1284. Теперь parport.sys создаёт различное количество устройств \Device\ParallelPort* в зависимости от того, сколько присутствует параллельных портов на машине, на которой запускается wine.
Сделал хак, позволяющий вызывать обработчик IRP_MJ_READ драйвера. Обработчик падает.
Падение обработчика было вызвано вызовом функций, указатели на которые должны были возвращаться в ответ на IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO. Теперь возвращаются указатели на стабы. Реализовал KeStallExecutionProcessor с помощью nanosleep. Сейчас драйвер не падает, но chkey32w.exe ключ не видит. Обработчик IRP_MJ_READ всегда возвращает STATUS_SUCCESS.
Часть битов в регистрах dsr и dcr на PC инвертированы по отношению к тем же битам на других платформах. Функции из libieee1284 реализованы так, что принимают и возвращает значения регистров "как на других платформах". А нам нужны регистры "как на PC", поэтому надо инвертировать часть битов перед записью и после чтения. После внесения исправлений chkey32w.exe ключ видит. Отправил в рассылку патчи: ntoskrnl.exe: Add stub for IoQueryDeviceDescription. hal: Add stub for HalTranslateBusAddress. ntoskrnl.exe: Add stub for KeInitializeSemaphore. hal: Add stubs for {READ,WRITE}_PORT_UCHAR. ntoskrnl.exe: Add semi-stub implementation of Io{Allocate,Write}ErrorLogEntry. include: Add ddk/parallel.h. hal: Add stub for KeStallExecutionProcessor. ntoskrnl.exe: Partially implement IoGetDeviceObjectPointer. Add parport.sys. Re-generate some files. parport.sys: Add fixmes. parport.sys: Add parallel port callback routines. ntoskrnl.exe: Add stub for KeReleaseSemaphore. hal: Implement KeStallExecutionProcessor. ntoskrnl.exe: Add stub for MmMapLockedPagesSpecifyCache. parport.sys: Add DriverUnload routine. ntoskrnl.exe: Implement MmMapLockedPagesSpecifyCache. Add implementation of IRP_MJ_READ handling. hal: Partially implement HalTranslateBusAddress. parport.sys: Implement PPARALLEL_{TRY_ALLOCATE,FREE}_ROUTINE callbacks. Implement {READ,WRITE}_PORT_UCHAR for parallel port registers.
Патч: commit 8ea3cd2639fe268f6eab688648420bcee75ea21b Author: Alexander Morozov <amorozov@etersoft.ru> Date: Wed Jan 28 21:10:12 2009 +0300 ntoskrnl.exe: Add stub for MmMapLockedPagesSpecifyCache. Заменил наш код: typedef enum _MEMORY_CACHING_TYPE { MmNonCached = FALSE, MmCached = TRUE, MmWriteCombined = MmFrameBufferCached, MmHardwareCoherentCached, MmCachingTypeDoNotUse1, MmCachingTypeDoNotUse2, MmMaximumCacheType } MEMORY_CACHING_TYPE; на версию из pure: typedef enum _MEMORY_CACHING_TYPE { MmNonCached = 0, MmCached = 1, MmWriteCombined = 2, MmHardwareCoherentCached = 3, MmNonCachedUnordered = 4, MmUSWCCached = 5, MmMaximumCacheType = 6 } MEMORY_CACHING_TYPE; Небольшая разница есть, возможно возникнут проблемы