PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Kernel Driver » Пример драйвера для доступа к портам компьютера


Пример драйвера для доступа к портам компьютера

Сообщений 1 страница 13 из 13

1

Исходный код драйвера для прямого доступа к портам (LPT, COM и др.) компьютера. Для лучшего понимания устройства и работы драйвера, можете прочитать эту статью.

Код:
; Драйвер для прямого доступа к портам компьютера - pbdriverio.sys.
Declare DriverEntry(*DriverObject, *RegistryPath)

; Точка входа в программу.
!public PureBasicStart
!section '.code' code readable executable align 8
!PureBasicStart:
*A=@DriverEntry()
!jmp [p_A]

; Декларация функций для FASM.
!extrn PB_PeekL
!extrn PB_PokeL
!extrn PB_PeekB
!extrn PB_PokeB
;!extrn _DbgPrint
!extrn _IoCompleteRequest@8
!extrn _RtlInitUnicodeString@8
!extrn _IoCreateDevice@28
!extrn _IoDeleteDevice@4
!extrn _IoCreateSymbolicLink@8
!extrn _IoDeleteSymbolicLink@4

; Импорт функций ядра.
Import "ntoskrnl.lib"
  IoCompleteRequest(*IRP, PriorityBoost)
  RtlInitUnicodeString(*UString, *String)
  IoCreateDevice(*DriverObject, DeviceExtensionSize, *UDeviceName, DeviceType, DeviceCharacteristics, Exclusive, *DeviceObject)
  IoDeleteDevice(*DeviceObject)
  IoCreateSymbolicLink(*SymbolicLinkName, *DeviceName)
  IoDeleteSymbolicLink(*SymbolicLinkName)
EndImport

; ImportC "ntoskrnl.lib"
; 	DbgPrint(a.s)
; EndImport


#IOCTL_READ_PORT_UCHAR	 = $200 
#IOCTL_WRITE_PORT_UCHAR	 = $400

; Прямая запись в порт.
Procedure.b InPort(Port.u)
 Protected Result.b=0
 EnableASM
 MOV DX, Port
 IN  al,DX
 MOV Result, al
 DisableASM
ProcedureReturn Result
EndProcedure

; Прямое чтение из порта.
Procedure OutPort(Port.u, Byte.a)
 EnableASM
 MOV al, Byte
 MOV DX, Port
 OUT DX, al
 DisableASM
EndProcedure


Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION
  
  *Stack = *pIrp\Tail\Overlay\CurrentStackLocation
  
  inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
  outBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength
  
  CtrlBuff   = PeekL(*pIrp\SystemBuffer)
  address = CtrlBuff & $FFFF
  Byte.a    = (CtrlBuff>>16)&255
  
  Code = *Stack\Parameters\DeviceIoControl\IoControlCode
  
  Select Code
    Case #IOCTL_READ_PORT_UCHAR
      InByte.b=InPort(address)
      PokeB(*pIrp\SystemBuffer, InByte)
      *pIrp\IoStatus\Information = 1
      
    Case #IOCTL_WRITE_PORT_UCHAR
      OutPort(address, Byte)
      *pIrp\IoStatus\Information = 0
      
    Default
      ntStatus = #STATUS_UNSUCCESSFUL
      *pIrp\IoStatus\Information = 0
  EndSelect
  
  ntStatus = #STATUS_SUCCESS
  
  *pIrp\IoStatus\Status = ntStatus
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  
  ProcedureReturn ntStatus
EndProcedure

Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  *pIrp\IoStatus\Information = 0
  *pIrp\IoStatus\Status = #STATUS_SUCCESS
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  ProcedureReturn #STATUS_SUCCESS
EndProcedure

Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
  Protected uniDOSString.UNICODE_STRING
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  IoDeleteSymbolicLink (@uniDOSString)
  IoDeleteDevice(*DriverObject\DeviceObject)
EndProcedure


Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  Protected deviceObject.DEVICE_OBJECT
  Protected uniNameString.UNICODE_STRING
  Protected uniDOSString.UNICODE_STRING
  RtlInitUnicodeString(@uniNameString, ?Device)
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject)
  If status <> #STATUS_SUCCESS
    ProcedureReturn status
  EndIf
  
  status = IoCreateSymbolicLink(@uniDOSString, @uniNameString)
  If status <> #STATUS_SUCCESS
    IoDeleteDevice(@deviceObject) ; Мы должны сами убирать "хвосты" в режиме ядра!
    ProcedureReturn status
  EndIf
  
  *DriverObject\DriverUnload = @UnloadDriver()
	
  *DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
  *DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
	
  ProcedureReturn #STATUS_SUCCESS
EndProcedure



; 
DataSection
  
  Device:
  !du '\Device\pbdriverio', 0, 0
  
  DosDevices:
  !du '\DosDevices\pbdriverio', 0, 0

EndDataSection

Это аналог довольно известного драйвера, используемого в библиотеке inpout32.dll.
Компилируем его с помощью PureBasic.
Скачать драйвер, а так же аналог указанной библиотеки, названный PB_IO.dll (в месте с исходными текстами и примерами использования), можно здесь http://pure-basic.narod.ru/forum_files/ … ver_IO.zip
Примечательно что PB_IO.dll при той же функциональности, имеет в три раза меньший размер чем inpout32.dll (12 КБ PB_IO.dll и 32 КБ inpout32.dll). Теперь вы понимаете сколько "мусора" в inpout32.dll?

Скриншот одного из примеров его использования, измеряющий температуру процессора и системной платы (будет работать не на всех компьютерах).
http://pure-basic.narod.ru/forum_files/driver/img/DrPB_IO.PNG

Код примера.

Код:
CompilerIf Defined(PBIO_OK, #PB_Constant)=0
  Enumeration
    #PBIO_OK
    #PBIO_ErrCopyDriver
    #PBIO_ErrInstallDriver
    #PBIO_ErrAccess
  EndEnumeration
CompilerEndIf

If OpenLibrary(2, "..\PB_IO.dll")=0
  MessageRequester("", "Нет PB_IO.dll.", #MB_OK|#MB_ICONERROR)
  End
EndIf

Prototype Inp(PortAddress.u)
Prototype Out(PortAddress.u, Byte.a)
Prototype Status()
Prototype.f Version()

Global Inp.Inp =GetFunction(2, "Inp")
Global Out.Out =GetFunction(2, "Out")
Status.Status =  GetFunction(2, "Status")
Version.Version =GetFunction(2, "Version")


#ADR_REG = $295 ;Это адреса регистров системной платы, с помощью которых можно узнать температуру
#DATA_REG = $296

Procedure Termo() ; Эта процедура вызывается по таймеру каждую секунду
   Out(#ADR_REG, $2B) ; Получает текущую температуру процессора
   x=Inp(#DATA_REG)
   SetGadgetItemText(0,0,StrU(x, #PB_Byte)+" °C",1) ; отображаем её в таблице
   
   Out(#ADR_REG, $29) ; Получает текущую температуру системной платы
   x=Inp(#DATA_REG)
   SetGadgetItemText(0,1,StrU(x, #PB_Byte)+" °C",1)  ; отображаем её в таблице
EndProcedure 
 
Err = Status()
If Err<>#PBIO_OK
  MessageRequester("", "Ошибка драйвера "+Str(Err))
EndIf

OpenWindow(0,0,0,274,80,"TermoControl",#PB_Window_MinimizeGadget|#PB_Window_Invisible|#PB_Window_ScreenCentered) 

ListIconGadget(0,2,4,270,70,"Имя",120,#PB_ListIcon_GridLines) ; Таблица
SetGadgetFont(0,LoadFont(0,"MS Sans Serif",10) ) ; Шрифт используемый в таблице
AddGadgetColumn(0, 1, "Температура", 140) ; Добавление колонки в таблицу
AddGadgetItem(0, 0, "Процессор") ; Добавление строк в таблицу
AddGadgetItem(0, 1, "Мат. плата") 

Termo()
AddWindowTimer(0,2,1000) ; Таймер.

HideWindow(0,0) ; Отображение окна

Repeat ; Главный цикл программы 
  Event=WaitWindowEvent()
  If Event=#PB_Event_Timer
    Termo()
  EndIf
Until Event=#PB_Event_CloseWindow

0

2

Версия драйвера (pbdriverio_x64.sys), работающая на x64 системах. http://pure-basic.narod.ru/forum_files/ … IO_x64.rar

0

3

Универсальный драйвер, работающий как на x86 (32 бита), так и на x64 (64 бита) системах. http://pure-basic.narod.ru/forum_files/ … 86_x64.zip
Он предназначен для 32-битных приложений, которые будут запускаться как на x86, так и на x64 системах.

0

4

Для порта LPT, имеющего адрес 378(встроенный на материнке), проблем нет.
А что делать со слотовым LPT?
Там насколько я понимаю нет железного адреса.
Можно ли как-то использовать ваш драйвер?

0

5

Если имеется в виду ISA, PCI или др. подобная плата, которой назначается адрес, пусть даже не стандартный, работать должно. А с переходником USB - LPT, работать не будет.

0

6

У меня, например, PCI плата создает два порта с адресами:
http://s020.radikal.ru/i702/1212/04/e21d0d9c50d0t.jpg
Все, вроде бы, понятно, но для рядового пользователя вводить эти адреса будет проблематично - замучают вопросами. Можно ли автоматически определять эти адреса, а пользователю предоставлять только выбор "LPT1" / "LPT2" / "LPT3" / ... ?

0

7

Наверняка можно. Нужно поискать в интернете как это сделать.

0

8

Код драйвера предназначенный для компиляции в версии PureBasic 5.11.

Код:
Declare DriverEntry(*DriverObject, *RegistryPath)

XIncludeFile #PB_Compiler_Home+"DDK\ntddk.pbi"
XIncludeFile #PB_Compiler_Home+"DDK\ntstatus.pbi"

CompilerSelect #PB_Compiler_Processor
  CompilerCase #PB_Processor_x86 
    Import "ntoskrnl.lib"
  CompilerCase #PB_Processor_x64   
    ImportC "ntoskrnl.lib"
CompilerEndSelect

  IoCompleteRequest(*IRP, PriorityBoost)
  RtlInitUnicodeString(*UString, *String)
  IoCreateDevice(*DriverObject, DeviceExtensionSize, *UDeviceName, DeviceType, DeviceCharacteristics, Exclusive, *DeviceObject)
  IoDeleteDevice(*DeviceObject)
  IoCreateSymbolicLink(*SymbolicLinkName, *DeviceName)
  IoDeleteSymbolicLink(*SymbolicLinkName)
EndImport


#IOCTL_READ_PORT_UCHAR	 = $200 
#IOCTL_WRITE_PORT_UCHAR	 = $400


*A=@DriverEntry()
!jmp [p_A]


; Прямая запись в порт.
Procedure.b InPort(Port.u)
  Protected Result.b=0
  EnableASM
  MOV DX, Port
  IN  al,DX
  MOV Result, al
  DisableASM
  ProcedureReturn Result
EndProcedure

; Прямое чтение из порта.
Procedure OutPort(Port.u, Byte.a)
  EnableASM
  MOV al, Byte
  MOV DX, Port
  OUT DX, al
  DisableASM
EndProcedure


Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION
  
  *Stack = *pIrp\Tail\Overlay\CurrentStackLocation
  
  inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
  outBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength
  
  CtrlBuff   = PeekI(*pIrp\SystemBuffer)
  address = CtrlBuff & $FFFF
  Byte.a    = (CtrlBuff>>16)&255
  
  Code = *Stack\Parameters\DeviceIoControl\IoControlCode
  
  ntStatus = #STATUS_SUCCESS
  
  Select Code
    Case #IOCTL_READ_PORT_UCHAR
      InByte.b=InPort(address)
      PokeB(*pIrp\SystemBuffer, InByte)
      *pIrp\IoStatus\Information = 1
      
    Case #IOCTL_WRITE_PORT_UCHAR
      OutPort(address, Byte)
      *pIrp\IoStatus\Information = 0
      
    Default
      ntStatus = #STATUS_UNSUCCESSFUL
      *pIrp\IoStatus\Information = 0
  EndSelect
  
  
  *pIrp\IoStatus\Status = ntStatus
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  
  ProcedureReturn ntStatus
EndProcedure

Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  *pIrp\IoStatus\Information = 0
  *pIrp\IoStatus\Status = #STATUS_SUCCESS
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  ProcedureReturn #STATUS_SUCCESS
EndProcedure

Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
  Protected uniDOSString.UNICODE_STRING
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  IoDeleteSymbolicLink (@uniDOSString)
  IoDeleteDevice(*DriverObject\DeviceObject)
EndProcedure


Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  Protected deviceObject.DEVICE_OBJECT
  Protected uniNameString.UNICODE_STRING
  Protected uniDOSString.UNICODE_STRING
  RtlInitUnicodeString(@uniNameString, ?Device)
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject)
  If status <> #STATUS_SUCCESS
    ProcedureReturn status
  EndIf
  
  status = IoCreateSymbolicLink(@uniDOSString, @uniNameString)
  If status <> #STATUS_SUCCESS
    IoDeleteDevice(@deviceObject) ; Мы должны сами убирать "хвосты" в режиме ядра!
    ProcedureReturn status
  EndIf
  
  *DriverObject\DriverUnload = @UnloadDriver()
  
  *DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
  *DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
  
  ProcedureReturn #STATUS_SUCCESS
EndProcedure



; 
DataSection
  CompilerSelect #PB_Compiler_Processor
    CompilerCase #PB_Processor_x86 
      Device:
      !du '\Device\pbdriverio', 0, 0
      
      DosDevices:
      !du '\DosDevices\pbdriverio', 0, 0
    CompilerCase #PB_Processor_x64
      Device:
      !du '\Device\pbdriverio_x64', 0, 0
      
      DosDevices:
      !du '\DosDevices\pbdriverio_x64', 0, 0
  CompilerEndSelect
EndDataSection

Если сравнить его с вариантом для  PureBasic 4.61 из первого сообщения темы, то можно увидеть что в этом коде нет необходимости декларации функций для FASMа и отсутствует необходимости объявлять в коде точку входа в программу.

0

9

Пётр написал(а):

Код драйвера предназначенный для компиляции в версии PureBasic 5.11.

Если сравнить его с вариантом для  PureBasic 4.61 из первого сообщения темы, то можно увидеть что в этом коде нет необходимости декларации функций для FASMа и отсутствует необходимости объявлять в коде точку входа в программу.

Здравствуйте!. У Меня  PureBasic 5.11 х64. Пожалуйста подскажите в каком формате компилировать драйвер и как им потом пользоваться??? Ведь как я понял драйвер и библиотека PB_IO.dll - разные вещи? Если так, тогда, куда установить этот драйвер? Помогите разобраться. Что мне нужно сделать, что-б в своих программах х64 можно-было обращаться к портам.

И где взять файлы требуемые для компиляции:
XIncludeFile #PB_Compiler_Home+"DDK\ntddk.pbi"
XIncludeFile #PB_Compiler_Home+"DDK\ntstatus.pbi"

Отредактировано Filins (21.04.2014 16:35:50)

0

10

Filins написал(а):

Если так, тогда, куда установить этот драйвер?

Драйвер при компиляции зашит в PB_IO.dll. При загрузке DLL, драйвер будет автоматически устанавливается (если он отсутствует в системе).
Библиотеку inpout32.dll приходилось использовать? PB_IO.dll работает аналогично, разница только в названии функций.
Если нет необходимости модифицировать код драйвера, то перекомпилировать его не нужно. Тоже касается и DLL. Можно взять готовую DLL PB_IO.dll из архива и использовать в проекте.
Но если модификация драйвера необходима, то необходимо скачать среду программирования PureBasic 4.61.
32 и 64 битный драйвер компилируется соответственно в x86 и x64 версии.

Filins написал(а):

И где взять файлы требуемые для компиляции:
XIncludeFile #PB_Compiler_Home+"DDK\ntddk.pbi"XIncludeFile
#PB_Compiler_Home+"DDK\ntstatus.pbi"

В вышеуказанной среде программирования они есть.

0

11

Пётр написал(а):

Драйвер при компиляции зашит в PB_IO.dll. При загрузке DLL, драйвер будет автоматически устанавливается (если он отсутствует в системе).
Библиотеку inpout32.dll приходилось использовать? PB_IO.dll работает аналогично, разница только в названии функций.
Если нет необходимости модифицировать код драйвера, то перекомпилировать его не нужно. Тоже касается и DLL. Можно взять готовую DLL PB_IO.dll из архива и использовать в проекте.
Но если модификация драйвера необходима, то необходимо скачать среду программирования PureBasic 4.61.
32 и 64 битный драйвер компилируется соответственно в x86 и x64 версии.

В вышеуказанной среде программирования они есть.

Спасибо за объяснение. Надеюсь сейчас у меня всё получится. Может ещё кто подскажет, -  возможно-ли в реальном времени читать/записывать оцифрованный звук на порт звуковой карты, если да то как узнать адрес и остальные параметры порта (команды...). Вот, что-б понятней было зачем это мне, немного опишу поставленную задачу. Мне нужно снимать звук поступающий, например от микрофона, и в реальном времени записывать этот цифровой звук (подобие WAV), например в область ОЗУ (Записывать дискретные значения с порта Аналого-Цифрового-Преобразователя). А так-же нужна обратная задача - вывод с генерированной мной звуковой волны (имею ввиду цифровой волны, сформированной в ОЗУ) напрямую в порт, прямо на Цифро-Аналогового-Преобразователя, который имеется на любой звуковой карте. Никакие задержки не приветствуются, нужно реальное время (ну или хоть на слух реальное). Причем считывание / запись - параллельные патоки (в одно и тоже время, и это мне уже не трудно... байт считал, байт записал и.т.д.) Обобщаю: Нужен прямой доступ к портам звуковой карты и описание самих этих портов.

Отредактировано Filins (21.04.2014 17:15:45)

0

12

Это сделать не так просто по нескольким причинам.
Во первых, у каждой модели звуковой карты, свои особенности (номера портов, конфигурация и т. д.), не зря же под каждую звуковуху свой драйвер.
Во вторых, адреса портов не постоянны, а назначаются системой при настройке.
В третьих, винда многозадачная и ни о каком реальном времени и речи быть не может.

Нужно воспользоваться средствами винды для чтения данных из звуковой карты и записи в нее.

0

13

Хорошо. Придётся учится программировать Цифровой сигнальный процессор (DSP) - что-ж, это наверное то-же интересно!. Спасибо Пётр за информацию.

Отредактировано Filins (22.04.2014 09:35:08)

0


Вы здесь » PureBasic - форум » Kernel Driver » Пример драйвера для доступа к портам компьютера