97524

Драйвера, которые работают через COM порт

Реферат

Информатика, кибернетика и программирование

В общем случае для использования каждого устройства подключённого к компьютеру необходим специальный драйвер. Обычно с операционными системами поставляются драйверы для ключевых компонентов аппаратного обеспечения без которых система не сможет работать.

Русский

2015-10-19

602 KB

0 чел.

Реферат на тему:

» Драйвера, которые работают через COM порт»


1) Понятие драйверов

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

Драйвер представляет собой специализированный программный модуль, управляющий внешним устройством. Драйверы обеспечивают единый интерфейс к различным устройствам, тем самым изолируя пользовательские программы и ядро ОС от особенностей аппаратуры.

Нужно отметить, что большинство "настоящих" ОС запрещают пользовательским программам непосредственный доступ к аппаратуре. Это делается для повышения надежности и обеспечения безопасности в многопользовательских системах. В таких системах драйверы являются для прикладных программ единственным способом доступа к внешнему миру.

Еще одна важная функция драйвера - это разделение доступа к устройству в средах с вытесняющей многозадачностью. Допускать одновременный неконтролируемый доступ к устройству для нескольких параллельно исполняющихся процессов просто нельзя, потому что для большинства внешних устройств даже простейшие операции ввода/вывода не являются атомарными.

Например, в большинстве аппаратных реализаций последовательного порта RS232 передача байта состоит из четырех шагов: записи значения в регистр данных, записи команды "передавать" в регистр команды, ожидания прерывания по концу передачи и проверки успешности передачи путем считывания статусного регистра устройства. Нарушение последовательности шагов может приводить к непредсказуемым последствиям - например, перезапись регистра данных после подачи команды может приводить к передаче искаженных данных и т.д.

Нельзя также забывать о неприятностях более высокого уровня - например, смешивании вывода разных процессов на печати или устройстве внешней памяти. Поэтому оказывается необходимо связать с каждым внешним устройством какой-то разграничитель доступа во времени. В современных ОС эта функция возлагается именно на драйвер. Обычно один из модулей драйвера представляет собой процесс-монитор (fork-процесс в VAX/VMS, стратегическую функцию в Unix, OS/2 и Windows NT), выполняющий асинхронно поступающие запросы на доступ к устройству.

Чаще всего драйверы являются частью ядра системы, исполняются в высшем кольце защиты и имеют доступ на запись к сегментам данных пользовательских программ, а часто и к данным самого ядра. Таким образом, большинство современных ОС предоставляет драйверам практически неконтролируемый доступ к данным пользовательских задач и ядра. Это означает, что ошибка в драйвере может привести к разрушению пользовательских программ и самой ОС.

При определении интерфейса драйвера разработчики ОС должны найти правильный баланс между противоречивыми требованиями:

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

.

2) Правила написання драйверів

Прежде чем перейти непосредственно к теме, хотелось бы сказать несколько слов о роли драйверов в операционной системе. Вспомним первые персоналки и MS DOS, бывшую в то время практически единственным выбором для настольного ПК. Несмотря на всю ее простоту, драйвера, конечно, присутствовали и в ней. Практически все дело ограничивалось накопителями – дисководами, CD-ROM приводами, винчестерами, да элементарнейшими драйверами клавиатуры и дисплея. Для каждой программы, требующей большего, чем перечисленный набор, требовалось создавать собственный драйвер. Представьте себе, что вам требуется воспроизвести звук на имеющейся в компьютере звуковой карте. Если вы знаете ее модель и у вас есть хорошая документация, вы, потратив немало времени, напишете программу, которая сделает все желаемое. А если необходимо поддерживать две модели? Три? Двадцать? И это при учете того, что новая звуковая карта появляется не реже раза в полтора-два месяца? Естественный выход – возложить написание кода, специфичного для аппаратуры, на ее создателя. Да и фирма-производитель, наняв высококвалифицированных специалистов, справится с задачей намного эффективнее и быстрее. Во всех современных операционных системах так и поступают. Существуют требования, например, к драйверу звуковой карты, и пользователь устанавливает тот  вариант, который соответствует его «железу». А программа-проигрыватель через вызовы системных функций указывает, что именно она хотела бы воспроизвести, не заботясь об особенностях аппаратуры.

Система ввода-вывода в Windows NT.

Теперь перейдем собственно в Windows NT. Прежде всего следует заметить, что фирма Microsoft выпускает пакет DDK (Driver Development Kit), предназначенный именно для создания системных драйверов. Он содержит необходимые для разработки программы и библиотеки, а также документацию и примеры. В дальнейшем я буду неоднократно на него ссылаться.

В Windows NT драйвера бывают следующих типов:

  •  Kernel mode drivers. Основной тип драйвера. Если вы не знаете, какой тип драйвера вам нужен – вам сюда.
  •  Graphics drivers. Драйвера видеокарт. Как правило, создаются одновременно с самой видеокартой. Очень сложны в написании, так как должны учитывать множество противоречивых требований и поддерживать множество стандартов. Скорее всего, вам не потребуется создавать ничего подобного.
  •  Multimedia drivers. Драйверы для :
    •  Аудиоустройств – считывание, воспроизведение и компрессия аудиоданных.
    •  устройств работы с видео – захват и компрессия видеоданных.
    •  позиционных устройств – джойстики, световые перья, планшеты и пр.
  •  Network drivers – работа с сетью и сетевыми протоколами на всех уровнях.
  •  Virtual DOS Drivers – драйверы для виртуальных машин MS-DOS. Постепенно переходят в раздел рудиментарных.

Я остановлюсь на Kernel mode drivers, как на представляющих наибольший интерес для программиста. Прежде всего необходимо представить окружение драйвера, среду, в которой он работает (рис.1).

Рисунок 1. Главные компоненты операционной системы Windows NT.

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

Существует три типа драйверов ядра, каждый тип имеет четко определенные структуру и функциональность.

  •  Device drivers, такие как драйвер клавиатуры или дисковый драйвер, напрямую общающийся с дисковым контроллером. Эти драйвера также называются драйверами низкого уровня, т. к. они находятся в самом низу цепочки драйверов Windows NT.
  •  Intermediate drivers, такие как драйвер виртуального или зеркального диска. Они используют драйверы устройств для обращения к аппаратуре.
  •  File system drivers (FSDs). Драйверы файловых систем, таких как FAT, NTFS, CDFS, для доступа к аппаратуре используют Intermediate drivers и Device drivers.

Драйвера Windows NT должны удовлетворять следующим требованиям:

  •  Переносимы с одной платформы на другую.
  •  Конфигурируемые программно.
  •  Всегда прерываемые.
  •  Поддерживающие мультипроцессорные платформы.
  •  Объектно-ориентированные.
  •  Поддерживающие пакетный ввод-вывод с повторно используемыми I/O request packets (IRPs, запросы ввода-вывода).
  •  Поддерживающими асинхронный ввод-вывод.

Каждая операционная система имеет модель ввода-вывода для управления потоками данных к и от периферийных устройств. Модель ввода-вывода Windows NT имеет следующие особенности:

  •  Менеджер ввода-вывода NT представляет интерфейс для всех kernel-mode драйверов, включая драйвера физических устройств, драйвера логических устройств и драйвера файловых систем.
  •  Операции ввода-вывода послойные. Это значит, что вызов, сделанный пользователем, проходит через несколько слоев, генерируя несколько пакетных запросов ввода-вывода и обращаясь к необходимым драйверам (см. рис.2).
  •  Менеджер ввода-вывода определяет множество стандартных процедур, которые должны быть реализованы разработчиком драйвера.
  •  Подобно NT в целом, драйвера имеют объектную архитектуру. Драйвера, их устройства и системное оборудование представлены как объекты Windows NT.

Рисунок 2.

Стандартные процедуры.

Любой драйвер должен реализовывать основное множество процедур и, возможно, еще несколько дополнительных подмножеств в зависимости от разновидности драйвера. На рис. 3 показан стандартный цикл работы драйвера, заключающийся в обработке запроса на прерывание (IRP). Для получения дополнительной информации читайте документацию к Windows NT Driver Development Kit.

–  Каждый драйвер должен иметь следующие процедуры:

  •  DriverEntry

   NTSTATUS  

   (*PDRIVER_INITIALIZE) (  

       IN PDRIVER_OBJECT DriverObject,

       IN PUNICODE_STRING RegistryPath

       );

 Каждый драйвер должен иметь инициализационную процедуру, которую менеджер ввода-вывода вызывает автоматически, если эта процедура называется DriverEntry.

 

  •  Dispatch

   NTSTATUS  

   (*PDRIVER_DISPATCH) (  

       IN PDEVICE_OBJECT DeviceObject,

       IN PIRP Irp

       );

Каждый драйвер должен иметь по крайней мере одну процедуру Dispatch.

  •  StartIo (или Queue-management)

   VOID  

   (*PDRIVER_STARTIO) (  

       IN PDEVICE_OBJECT DeviceObject,

       IN PIRP Irp

       );

Если драйвер устройства не может завершить все возможные запросы ввода-вывода в его Dispatch процедуре, он должен иметь либо процедуру StartIo,  либо заводить одну или более внутренних очередей и управлять собственным механизмом отложеных запросов на прерывание.

В зависимости от уровня, занимаемого драйвером в стеке обработки запроса на прерывание, драйвер может обладать следующими процедурами:

  •  Reinitialize

   VOID  

   (*PDRIVER_REINITIALIZE) (  

       IN PDRIVER_OBJECT DriverObject,

       IN PVOID Context,

       IN ULONG Count

       );

 

В добавок к процедуре DriverEntry драйвер может иметь процедуру Reinitialize, вызываемую один или несколько раз в процессе загрузки системы после того, как DriverEntry вернет управление.

  •  InterruptService (ISR)

   BOOLEAN  

   (*PKSERVICE_ROUTINE) (

       IN PKINTERRUPT Interrupt,

       IN PVOID ServiceContext // usually points to device object

       );

 

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

Рисунок 3. Стандартные процедуры драйвера.

 

  •  DpcForIsr или CustomDpc

   VOID  

   (*PIO_DPC_ROUTINE) (  

       IN PKDPC Dpc,

       IN PDEVICE_OBJECT DeviceObject,

       IN PIRP Irp,

       IN PVOID Context

       );

 

   VOID

   (*PKDEFERRED_ROUTINE) (

       IN PKDPC Dpc,

       IN PVOID DeferredContext,

       IN PVOID SystemArgument1,

       IN PVOID SystemArgument2

       );

 Любой драйвер, имеющий ISR должен иметь DpcForIsr или CustomDpc.

  •  SynchCritSection

   BOOLEAN  

   (*PKSYNCHRONIZE_ROUTINE) (  

       IN PVOID SynchronizeContext

       );

 

Любой низкоуровневый драйвер устройства, данные которого или регистры сопряженного устройства могут изменятся в его ISR и других процедурах драйвера, должен иметь одну или более процедур SynchCritSection.

  •  AdapterControl и/или ControllerControl

   IO_ALLOCATION_ACTION  

   (*PDRIVER_CONTROL) (  

       IN PDEVICE_OBJECT DeviceObject,

       IN PIRP Irp,

       IN PVOID MapRegisterBase,

       IN PVOID Context

       );

 

Любой драйвер устройства использующий DMA, должен иметь процедуру AdapterControl. Любой драйвер устройства, который должен синхронизировать операции с физическим контроллером для нескольких устройств или каналов устройства, должен иметь ControllerControl.

  •  Cancel

   VOID  

   (*PDRIVER_CANCEL) (  

       IN PDEVICE_OBJECT DeviceObject,

       IN PIRP Irp

       );

 

Клавиатура, мышь, последовательный, параллельный, звуковой драйверы и драйвер файловой системы имеют процедуру Cancel. Любой драйвер, обрабатывающий запрос в течении длительного промежутка времени (в течении которого пользователь может отменить операцию), должен иметь процедуру Cancel. Обычно эту процедуру имеет высший драйвер в стеке обработки запроса.

  •  IoCompletion

   NTSTATUS  

   (*PIO_COMPLETION_ROUTINE) (  

       IN PDEVICE_OBJECT DeviceObject,

       IN PIRP Irp,

       IN PVOID Context

       );

 

Любой драйвер верхнего уровня, который создает запросы к более низкоуровневым драйверам, должен иметь по крайней мере одну процедуру IoCompletion для освобождения всех структур IRP, созданных драйвером. Таким образом, любой драйвер высшего уровня должен иметь процедуру IoCompletion. Другие процедуры драйвера могут сказать, чтобы IoCompletion была вызвана когда все низкоуровневые драйверы обработают текущий запрос.

  •  IoTimer и/или CustomTimerDpc

   VOID  

   (*PIO_TIMER_ROUTINE) (  

       IN PDEVICE_OBJECT DeviceObject,

       IN PVOID Context

       );

 

   VOID

   (*PKDEFERRED_ROUTINE) (

       IN PKDPC Dpc,

       IN PVOID DeferredContext,

       IN PVOID SystemArgument1,        // reserved for system use

       IN PVOID SystemArgument2            // reserved for system use

       );

 

Для отслеживания времени, занимаемого процедурой ввода-вывода, или для некоторой другой цели, определяемой разработчиком, любой драйвер должен иметь процедуры IoTimer и/или CustomTimerDpc. IoTimer вызывается раз в секунду когда драйвер включает таймер. CustomTimerDpc может быть вызвана в более мелкий или переменный интервал.

  •  Unload

   VOID  

   (*PDRIVER_UNLOAD) (  

       IN PDRIVER_OBJECT DriverObject

       );

 

Драйвер должен иметь процедуру Unload если он может быть выгружен во время работы системы.
Сервисные системные вызовы.
Для осуществления обращений в микроядру, работы с реестром, памятью, объектами, синхронизацией и пр. существует набор функций, называющихся функциями поддержки ядра. Я приведу только самые необходимые. Для дополнительной информации обращайтесь к Microsoft Windows NT DDK.
  •  IoCreateDevice
Создает новый объект устройства и инициализирует его для использования драйвером. Объект устройства представляет собой физическое, виртуальное или логическое устройство, которое необходимо драйверу для поддержки динамического управления этим устройством.

NTSTATUS 
IoCreateDevice(
 
IN PDRIVER_OBJECT  DriverObject, Указатель на объект драйвера
 
IN ULONG  DeviceExtensionSize, размер блока пользовательской информации в байтах
 
IN PUNICODE_STRING  DeviceName,  имя устройства (иногда опускается)
 
IN DEVICE_TYPE  DeviceType, тип устройства (последованельное, диск, мышь и т.д.)
 
IN ULONG  DeviceCharacteristics, параметры устройства (вынимаемое и пр.)
 
IN BOOLEAN  Exclusive, параллельность доступа к устройству
 
OUT PDEVICE_OBJECT  *DeviceObject указатель на объект создаваемого устройства  );

  •  IoCreateSymbolicLink
Создает символическую ссылку между устройством и видимым пользователем именем.

NTSTATUS
IoCreateSymbolicLink(
 
IN PUNICODE_STRING  SymbolicLinkName, символическое имя, видимое пользователю
 
IN PUNICODE_STRING  DeviceName имя устройства в пространстве имен ядра Windows  );

  •  IoCompleteRequest
Объявляет менеджеру ввода-вывода, что обработка текущего запроса ввода-вывода закончена.

VOID 
IoCompleteRequest(
 
IN PIRP  Irp, указатель на запрос ввода-вывода
 
IN CCHAR  PriorityBoost повышение приоритета драйвера для обработки запроса. Зависит     от обрабатываемого устройства. IO_NO_INCREMENT при      ошибке или очень быстрой обработке запроса
 );

Основным средством разработки является Microsoft Windows DDK, Device Driver Kit, — пакет разработки драйверов, включающий компилятор, редактор связей (линкер), заголовочные файлы, библиотеки, большой набор примеров (часть из которых является драйверами, реально работающими в операционной системе) и, разумеется, документацию. В состав пакета входит также отладчик WinDbg, позволяющий проводить интерактивную отладку драйвера на двухкомпьютерной конфигурации и при наличии файлов отладочных идентификаторов операционной системы WinDbg кроме того, позволяет просматривать файлы дампа (образа) памяти, полученного при фатальных сбоях операционной системы (так называемый crash dump file).

Следует особо отметить, что языком программирования, который используется в DDK является язык С, разумеется, допускающий вставки на языке ассемблер, который в былые времена был основным и единственным языком программирования драйверов.

В бесплатно распространяемом пакете DDK всегда отсутствовала интегрированная среда разработки. Поэтому программисты драйверов всегда были вынуждены подбирать для себя и средство редактирования исходного кода. Выбор был, практически, безальтернативен — пакет Visual С++ (теперь это Visual Studio 7 Net). При должной настройке этой среды процесс выявлений синтаксических ошибок существенно облегчается — неотъемлемое преимущество интегрированных сред программирования. Компилятор и редактор связей Visual Studio C++ создают нормальный бинарный код, вполне работоспособный при указании соответствующих опций (настроек) компиляции, однако эталоном следует считать бинарный код, получающийся при компиляции кода драйвера с использованием утилиты Build из состава пакета DDK. Разумеется, встроенный интерактивный отладчик Visual Studio и прилагаемая документация становятся для разработки драйвера совершенно бесполезными, поскольку не предназначены для работы с программным обеспечением для режима ядра.

В настоящее время две фирмы, Jungo Ltd. и CompuWare Corp., предлагают собственные коммерческие пакеты проектирования драйверов.

Фирма Jungo Ltd. предлагает разработчикам пакет WinDriver, позволяющий быстро создавать драйверы пользовательского режима (практически — динамические библиотеки), и пакет KernelDriver для создания кода, работающего в режиме ядра (что более эффективно в смысле производительности драйвера). Оба пакета имеют удобные заготовки для программирования устройств, подключаемых к шинам PCI, USB, ISA, и позволяют работать с ними программистам на Delphi и Basic. Однако собственный базис функций представляет собой почти что новый язык программирования (в той степени, как это можно сказать, например, о наборе функций MFC для программиста, ранее работавшего только с API функциями Windows). Кроме того, для уверенной работы с данными пакетами крайне необходима постоянная лицензионная поддержка.

Пакет Numega Driver Studio (от CompuWare Corp.) содержит в своем составе мощный отладчик SoftIce, ориентированный исключительно на платформу Intel. Отладчик SoftIce позволяет проводить отладку на одном компьютере (хотя опытные разработчики в категоричной форме рекомендуют не проводить отладку драйвера на компьютере с ценными данными и там, где установлены все программные средства разработки — время, потраченное на восстановление системы квалифицированным специалистом, зачастую стоит дороже дополнительного компьютера). И хотя интерфейс с пользователем остается практически неизменным со времен MS DOS, отладчик SoftIce обладает мощными возможностями, по функциональности вряд ли уступающими возможностям отладчиков Visual Studio для пользовательского режима.

Несколько полезных программных средств от CompuWare Corporation рассматриваются ниже.

Программа Monitor от CompuWare Corporation

Программа Monitor от Numega (теперь CompuWare Corporation) позволяет динамически загружать, запускать, останавливать и выгружать драйверы, выполненные в-стиле-NT (не-WDM), в большинстве случаев без перезапуска системы и без создания собственной программы загрузки драйвера при помощи SCM сервисов, а также без использования inf файлов и системного Менеджера Устройств. Таким образом, достаточно подготовить лишь .sys файл и затем воспользоваться программой Monitor.

Вообще говоря, имеются и иные программы с данным сервисом, однако Monitor от CompuWare Corporation имеет наиболее завершенный вид (младшие версии работали еще с VxD драйверами) и удобный графический интерфейс.

Первые четыре кнопки в панели инструментов, см. рисунок 2.10, посвящены загрузке (внесению записи о драйвере в Системный Реестр), запуску, останову, выгрузке драйвера и удалению записи о драйвере из Системного Реестра, соответственно. По мере выполнения этих действий в окне появляются диагностические сообщения о надлежащем выполнении операции или сообщения об ошибках.

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

Программа трансляции файла sources в проект Visual Studio

В составе пакета Driver Studio имеется утилита, которая выполняет достаточно корректное создание файла описания проекта Visual Studio (.dsp, файла описания проекта для Microsoft Visual Studio 6).

Для программы SrcToDsp (рисунок 2.11) требуется в качестве входной информации файл sources, управляющий обычно сборкой драйвера утилитой Build в пакете DDK. Среда программирование Microsoft Visual Studio 7 Net также способна воспринимать .dsp файлы, однако при первой загрузке проекта она предпочитает перевести их в формат .vcproj (текстовый XML формат, вполне читаемый и похожий на HTML).

Следует, тем не менее, критически относиться к результатам работы этой программы и не принимать все на веру, тщательно проверяя настройки проекта в Visual Studio. Кроме того, следует помнить, что чистовую сборку драйвера следует выполнять средствами пакета DDK (в котором настройки компиляции и сборки можно считать эталоном).

Программа Numega SymLinks

В составе пакета Driver Studio имеется утилита, которая позволяет просматривать все символьные ссылки, созданные реально функционирующими на данный момент драйверами.

На рисунке 2.12 показаны некоторые из символьных ссылок, имеющихся в системе. В частности, в двух первых строчках указаны символьные имена HCD0 и HCD1, соответствующие функциональным объектам устройств (с именами USBFDO-0 и USBFDO-1), которые обслуживаются драйвером USB контроллера. То есть в системе физически присутствуют два USB контроллера, к которым их клиенты могут обращаться с вызовом пользовательского режима CreateFiIe("\\\\.\\HCD0",...) или вызовом режима ядра ZwCreateFile (внутри параметров которого передается это же имя, правда, ритуал такой передачи несколько сложнее).

Следует отметить, что программа SymLinks существенно лаконичнее программ WinObj и DevView, которые будут рассмотрены ниже.

Особенности использования порта COM

COM-порт - последовательный порт для передачи данных между ПК, телефонами, карманными компьютерами, а также для подключения периферии.

Через последовательный порт информация передаётся последовательно бит за битом; для передачи информации используют только один провод. При обычной конфигурации устройств последовательных портов два. В системе они обозначаются как COM1 и COM2. Эти порты имеют сравнительно не большую скорость передачи данных. Windows может изменять их скорость в пределах от 110 и до 921600 бит за 1 секунду. В основном порты COM1 и COM2 используются для подключения различных устройств, но при надобности эти порты можно использовать в качестве источника для обмена информации между двумя компьютерами.

1. COM порт

Берем системный блок ПК и смотрим в тыловую часть. Примечаем там 9-ти штырьковй разъем - это и есть COM порт. Реально их может быть неколько (до 4-х). (см. фото).

После́довательный порт или COM-порт (произносится «ком-порт», от англ. COMmunication port) — двунаправленный последовательный интерфейс, предназначенный для обмена байтовой информацией. Последовательный потому, что информация через него передаётся по одному биту, бит за битом(в отличие от параллельного порта). Наиболее часто для последовательного порта персональных компьютеров используется стандарт RS-232C. Ранее последовательный порт использовался для подключения терминала, позже для модема или мыши. Сейчас он используется для соединения с источниками бесперебойного питания, для связи с аппаратными средствами разработки встраиваемых вычислительных систем.

Ethernet, FireWire и USB — также используют последовательный способ обмена, название «последовательный порт» закрепилось за портом, имеющим стандарт RS-232C, и предназначенным изначально для обмена информацией с модемом.

С помощью COM-порта можно соединить два компьютера, используя так называемый "нуль-модемный кабель".

Принятое условное обозначение последовательного порта:

Варианты разъёма COM-порта типа DE-9F

Наиболее часто используются Д-образные разъёмы: 9- и 25-контактные, (DE-9 и DB-25 соответственно). Раньше использовались также DB-31 и круглые восьмиконтактные DIN-8. Максимальная скорость передачи обычно составляет 115200 бит/с.

Стандарт на него был разработан в 1969 году.

В настоящее время в персональных компьютерах всё ещё встречается данный вид интерфейса, не смотря на значительное вытеснения другими портами: PS/2 (подключение мыши и клавиатуры), USB универсальная последовательная шина с питанием.

COM-порты в операционной системе типа Windows - это именованные каналы для передачи данных, называемые обычно COM1,COM2 и т.д. по порядку обнаружения драйверов соответствующих устройств. Например, для обмена информации через Bluetooth многие драйверы представляются операционной системе как COM-порт, и резервируют похожее имя.

Начиная с первых моделей в PC имелся последовательный интерфейс - СОМ-порт . Этот порт обеспечивает асинхронный обмен по стандарту RS-232C. Компьютер может иметь до четырех последовательных портов СОМ 1-COM4 (для машин класса AT типично наличие двух портов). СОМ-порты имеют внешние разъемы-вилки (Male "папа") DB25P или DB9P, выведенные на заднюю панель компьютера (назначение выводов приведено в табл. 1).
СОМ-порты реализуются на микросхемах UART, совместимых с семейством 18250. Они занимают в пространстве ввода/вывода по 8 смежных 8-битных регистров и могут располагаться по стандартным базовым адресам 3F8h (COM1), 2F8h (COM2), 3E8h (COM3), 2E8h (COM4). Для портов COM3 и COM4 возможны альтернативные адреса 3EOh, 338h и 2EOh, 238h соответственно. Для PS/2 стандартными для портов СОМЗ-СОМ8 являются адреса 3220h, 3228h,4220h, 4228h, 5220h и 5228h соответственно.
Порты могут вырабатывать аппаратные прерывания IRQ4 (обычно используются для COM1 и COM3) и IRQ3 (для COM2 и COM4). Кроме того, возможно использование линий прерываний IRQ11 (вместо IRQ4) и IRQ10 (вместо IRQ3).Возможность разделяемого использования одной линии запроса несколькими портами (или ее разделения с другими устройствами) зависит от реализации аппаратного подключения и программного обеспечения. При использовании портов, установленных на шину ISA, разделяемые прерывания обычно не работают.

Вопреки названию, СОМ-порты чаще всего используют для подключения манипуляторов (мышь, трекбол). В этом случае порт используется в режиме последовательного ввода, обеспечивая питание устройства от интерфейса. Мышь может подключаться к любому исправному порту, для согласования разъемов порта и мыши возможно применение переходника DB9S-DB25P или, наоборот,DB25S-DB9P. Для работы с мышью обязательно требуется использование линии прерывания, причем для порта СОМ1 - IRQ4, а для COM2 - IRQ3.

Следующим по популярности идет подключение внешних модемов для связи с удаленными компьютерами или выхода в глобальные сети. Модемы должны подключаться полным (9-проводным) кабелем DTE-DCE. Этот же кабель может использоваться и для согласования разъемов (по количеству контактов), возможно и применение переходников 9-25,предназначенных для мышей. Для работы коммуникационного ПО обычно требуется использование прерываний, но здесь, как правило, больше свободы выбора сочетаний номера (адреса) порта и номера линии прерывания. Если предполагается работа на скоростях 9600 бит/с и выше, то СОМ-порт должен быть реализован на микросхеме UART 16550A или совместимой с ней. Возможности работы с использованием FIFO-буферов и обмена по каналам DMA зависят от коммуникационного ПО.
Для связи двух компьютеров, удаленных друг от друга на небольшое расстояние, используют и непосредственное соединение их СОМ-портов нуль-модемным кабелем . Использование программ типа Norton Commander или Interink MS-DOS позволяет обмениваться файлами со скоростью передачи до 115,2 Кбит/с без использования аппаратных прерываний. Это же соединение может использоваться и сетевым пакетом Lantastic,предоставляющим более развитый сервис.
Подключение принтеров и плоттеров к СОМ-порту требует применения кабеля, соответствующего выбранному протоколу управления потоком: программному XON/XOFF или аппаратному RTS/CTS. Аппаратный протокол предпочтительнее, поскольку он не требует программной поддержки со стороны PC. Прерывания при выводе средствами DOS (командами COPY или PRINT) не используются.
СОМ-порт иногда используется и для подключения электронных ключей (Security Devices), предназначенных для защиты от нелицензированного использования программных продуктов. Эти устройства могут быть как "прозрачными", позволяя воспользоваться тем же портом и для подключения периферии, так и полностью занимающими порт.
СОМ-порт при наличии соответствующей программной поддержки позволяет превратить PC в терминал, эмулируя систему команд распространенных специализированных терминалов (VT-52, VT-100 и других). В принципе простейший терминал получается, если замкнуть друг на друга функции BIOS обслуживания СОМ-порта (Int 14h), функцию телетайпного вывода видеосервиса (Int 10h) и клавиатурный ввод (Int 16h). Однако такой терминал будет работать лишь на малых скоростях обмена (если, конечно, его делать не на Pentium),поскольку функции BIOS хоть и универсальны, но работают не самым быстрым образом.
Этим списком, конечно же, возможности использования СОМ-порта не исчерпываются. Интерфейс RS-232C широко распространен в различных периферийных устройствах и терминалах. Все они, при наличии должной программной поддержки, могут подключаться к PC. Кроме использования по прямому назначению, СОМ-порт может использоваться и как двунаправленный интерфейс,у которого имеется 3 программно-управляемых выходных линии и 4 программно-читаемых входных линии с двуполярными сигналами. Возможность их использования ограничивается только фантазией разработчика. Существует,например, схема однобитного широтно-импульсного преобразователя, позволяющего записывать звуковой сигнал на диск PC, используя входную линию СОМ-порта. Воспроизведение этой записи через обычный динамик обеспечивает разборчивость речи. Конечно, в настоящее время, когда звуковая карта стала почти обязательным устройством PC, это уже не впечатляет, но в свое время такое решение было довольно интересным.

Последовательный интерфейс: COM порт

Последовательный интерфейс для передачи данных в одну сторону использует одну сигнальную линию , по которой информационные биты передаются друг за другом последовательно. Такой способ передачи определяет название интерфейса и порта , его реализующего( Serial Interface и Serial Port).Последовательная передача данных может осуществляться в синхронном и асинхронном режимах.
При асинхронной передачи каждому байту предшествует старт-бит , сигнализирующий приемнику о начале очередной посылки , за которой следуют биты данных или бит паритета(конроля четности).Завершает посылку стоп-бит. Старт-бит (имеющий значение лог."0") следующего посланного байта может посылаться в любой момент после окончания стоп-бита. Старт-бит обеспечивает механизм синхронизации приемника по сигналу от передатчика. Внутренний генератор синхронизации приемника использует счетчик-делитель опорной частоты , обнуляемый в момент приема начала старт-бита .Этот счетчик генерирует внутренние стробы , по которым приемник фиксирует последующие принимаемые биты. 
Формат асинхронной посылки позволяют выявить возможные ошибки передачи.
Для асинхронного режима принят ряд стандартных скоростей обмена : 50,75,110,150,300,600,1200,2400,4800,19200,38400,57600,115200 бит/сек. Количество бит данных может составлять 5,6,7,8 бит . Количество стоп битов может быть 1,1.5,2 бита. Асинхронный в РС реализуется с помощью СОМ-порта с использованием протокола RS-232C.
Синхронный режим передачи предполагает постоянную активность канала связи . Посылка начинаетя с синхробайта , за которым плотно следует поток информационных бит. Если у передатчика нет данных для передачи , он заполняет паузу непрерывной посылкой байтов синхронизации . При передаче больших массивов данных накладные расходы на синхронизацию в даном режиме необходима будет ниже , чем в асинхронном .Однако в синхронном режиме необходима внешняя синхронизация приемника с передатчиком , поскольку даже малое отклонение частот приведет к быстро накапливающейся ошибке и искажению принимаемых данных . Внешняя синхронизация возможна либо с помощью отдельной линии передачи для передачи сигнала синхронизации , либо с использованием самосинхронизирующего кодирования данных ,при котором на приемной стороне из принятого сигнала могут быть и импульсы синхронизации. В любом случае синхронный режим требует либо дорогих линий связи , либо дорогого оконеченного оборудования .Для РС существуют специальные платы - адаптеры SDLC , поддерживающие синхронный режим обмена .Они используются в основном для связи с большими машинами IBM и в настоящеее время мало распространены. Из синхронных адаптеров в настоящее время чаще всего применяются адаптеры интерфейса V.35.
Последовательный интерфейс на физическом уровне может иметь различные реализации , различающиеся способом передачи электрических сигналов .Существует ряд родственных международных стандартов: RS-232C,RS-432A,RS-422A,RS485. 
Несимметричные линии интерфейсов RS-232C ,RS-432A имеют самую низкую защищенность от синфазной помехи .Лучшие параметры имеет двухточечный интерфейс 
RS-422A и его магистральный(шинный) родственник RS-485 , работающие на симметричных линиях связи .В них для каждого сигнала используются дифференциальные сигналы с отдельной(витий) парой приводов .
Наибольшее распространение в РС получил простейший из этих - стандарт RS-232C.В промышленной автоматике широко применяется RS- 422А, а также RS-485, встречающийся и в некоторых принтерах. Существуют относительно несложные преобразователи сигналов для согласования всех этих интерфейсов.

Интерфейс RS-232C

Интерфейс RS-232C предназначен для подключения аппаратуры ,
передающей или принимающей данные (АПД-аппаратура передачи данных) , к оконечной аппаратуре каналов данных(АКД).В роли АПД может выступать компьютер , принтер , плоттер и другие ПУ. Этой аппаратуре соответствует аббревиатура DTE-Data Terminal Equipment. В роли АКД обычно выступает модем -DCE(Data Communication Equipment) .Конечной целью подключения является соединение двух устройств DTE , полная схема соединения приведена на рис.2.Интерфейс позволяет исключать канал удаленной связи вместе с парой устройств DTE , соединив устройства непосредственно с помощью нуль-модемного кабеля(рис.3).
Стандарт описывает управляющие сигналы интерфейса , пересылку данных , электрический интерфейс и типы разъемов. Стандарт описывает синхронный и асинхронный режимы обмена , но СОМ-порты поддерживают только асинхронный режим . Функционально RS-232C эквивалентен стандарту МККТТ V.24/V.28 и стыку С2 , но они имеют различные названия одних и тех же используемых сигналов. 


Рис.1-Стандарт последовательного интерфейса.


Рис.2-Полная схема соединения по RS-232C.


Рис.3-Соединение по RS-232C нуль-модемным кабелем.

Электрический  интерфейс

Стандарт RS-232C использует несимметричные передатчики и приемники - сигнал передается относительно общего провода - схемной земли cимметричные дифференциальные сигналы используются в других интерфейсах - например,RS-422). Интерфейс НЕ ОБЕСПЕЧИВАЕТ ГАЛЬВАНИЧЕСКОЙ РАЗВЯЗКИ устройств. Логической единице соответствует уровень напряжения на входе приемника в диапазоне -12...-3 В. Для линий управляющих сигналов это состояние называется ON ("включено"), для линий последовательных данных называется MARK. Логическому нулю соответствует напряжение в диапазоне +3...+12 В. Для линий управляющих сигналов это состояние называется OFF ("выключено"), для линий последовательных данных называется SPACE. Между уровнями -3...+3 В имеется зона нечувствительности, обусловливающая гистерезис приемника: состояние линии будет считаться измененным только после пересечения соответствующего порога . Уровни сигналов на выходах передатчиков должны быть в диапазонах -12...-5 В и +5...+12 В для представления единицы и нуля соответственно. Разность потенциалов между схемными землями (SG)соединяемых устройств должна быть менее 2 В, при более высокой разности потенциалов возможно неверное восприятие сигналов.
Интерфейс предполагает наличие ЗАЩИТНОГО ЗАЗЕМЛЕНИЯ для соединяемых устройств, если они оба питаются от сети переменного тока и имеют сетевые фильтры.
Подключение и отключение интерфейсных кабелей устройств с автономным питанием (не питающихся от интерфейса, таких как, например, мышь) должно производиться при отключении питания. В противном случае разность не выровненных потенциалов устройств в момент коммутации (присоединения или отсоединения разъема) может оказаться приложенной к выходны или входным (что опаснее) цепям интерфейса и вывести из строя микросхемы.
Для интерфейса RS-232C специально выпускаются буферные микросхемы приемников (с гистерезисом) и передатчиков двуполярного сигнала. При несоблюдении правил заземления и коммутации включенных устройств они обычно являются первыми (хорошо, если единственными) жертвами "пиротехнических"эффектов. Иногда их устанавливают в "кроватках", что сильно облегчает замену. Часто буферные схемы входят прямо в состав интерфейсных БИС.Это удешевляет изделие, экономит место на плате, но в случае аварии обычно оборачивается крупными финансовыми потерями. Вывести из строя интерфейсные микросхемы замыканием сигнальных цепей маловероятно, поскольку ток короткого замыкания передатчиков обычно ограничен на уровне 20 мА.
Стандарт RS-232C регламентирует типы применяемых разъемов, что обеспечивает высокий уровень совместимости аппаратуры различных производителей.
На аппаратуре DTE (в том числе, и на СОМ-портах PC) принято устанавливать вилки, (male - "папа") DB25-P или более компактный вариант --DB9-P.
Девятиштырьковые разъемы не имеют контактов для дополнительных сигналов,необходимых для синхронного режима (в большинстве 25тырьковых разъемов эти контакты не используются).
На аппаратуре DCE (модемах) устанавливают розетки (female - "мама") DB25-S или DB-9S.
Это правило предполагает, что разъемы DCE могут подключаться к разъемам DTE непосредственно (если позволяет геометрия конструктива) или через переходные "прямые" кабели с розеткой и вилкой, у которых контакты cоединены"один в один". Переходные кабели могут являться и переходниками с 9 на 25-штырьковые разъемы.
Если аппаратура DTE соединяется без модемов, то разъемы устройств (вилки) соединяются между собой нуль-модемным кабелем (Zero-modem или Z-modem), имеющим на обоих концах розетки, контакты которых соединяются перекрестно.
Если на каком-либо устройстве DTE (принтер, плоттер, дигитайзер) установлена розетка - это почти стопроцентный признак того, что к другому устройству (компьютеру) оно должно подключаться прямым кабелем, аналогичным кабелю подключения модема. Розетка устанавливается обычно на тех устройствах, у которых удаленное подключение через модем не предусмотрено (или бессмысленно, как, например, у дигитайзера).
В табл. 1 приведено назначение контактов разъемов СОМ-портов (и любой другой аппаратуры DTE). Назначение контактов разъема DB25S определено стандартом EIA/TIA-232-Е, разъем DB9S определен стандартом EIA/ TIA-574.
У модемов (DCE) название цепей и назначение контактов, естественно, совпадает, но роли сигналов (вход-выход) меняются на противоположные.

Таблица 1- Разъемы и сигналы интерфейса RS-232C

1* - шлейф 8-битных мультикарт.
2* - шлейф 16-битных мультикарт и портов на системных платах.
3* -- вариант шлейфа портов на системных платах.
4* - широкий шлейф к 25-контактному разъему.

Подмножество сигналов RS-232C, относящихся к асинхронному режиму, рассмотрим с точки зрения СОМ-порта PC, являющегося по терминологии RS-232C терминалом данных (DTE). Следует помнить, что активному состоянию сигнала ("включено") и логической единице передаваемых данных соответствует отрицательный потенциал (ниже -3 В) сигнала интерфейса, а состоянию "выключено" и логическому нулю - положительный (выше +3 В). Назначение сигналов интерфейса приведено в табл.2.

Таблица 2-Назначение сигналов интерфейса

Ресурсы СОМ-портов

Начиная с первых моделей в PC имелся последовательный интерфейс - СОМ-порт (Communications Port - коммуникационный порт). Этот порт обеспечивает асинхронный обмен по стандарту RS-232C. Компьютер может иметь до четырех последовательных портов СОМ 1-COM4 (для машин класса AT типично наличие двух портов). СОМ-порты имеют внешние разъемы-вилки (Male "папа") DB25P или DB9P, выведенные на заднюю панель компьютера (назначение выводов приведено в табл. 1).
СОМ-порты реализуются на микросхемах UART, совместимых с семейством 18250. Они занимают в пространстве ввода/вывода по 8 смежных 8-битных регистров и могут располагаться по стандартным базовым адресам 3F8h (COM1), 2F8h (COM2), 3E8h (COM3), 2E8h (COM4). Для портов COM3 и COM4 возможны альтернативные адреса 3EOh, 338h и 2EOh, 238h соответственно. Для PS/2 стандартными для портов СОМЗ-СОМ8 являются адреса 3220h, 3228h,4220h, 4228h, 5220h и 5228h соответственно.
Порты могут вырабатывать аппаратные прерывания IRQ4 (обычно используются для COM1 и COM3) и IRQ3 (для COM2 и COM4). Кроме того, возможно использование линий прерываний IRQ11 (вместо IRQ4) и IRQ10 (вместо IRQ3).Возможность разделяемого использования одной линии запроса несколькими портами (или ее разделения с другими устройствами) зависит от реализации аппаратного подключения и программного обеспечения. При использовании портов, установленных на шину ISA, разделяемые прерывания обычно не работают.

Конфигурирование СОМ-портов

Управление последовательным портом разделяется на два этапа - предварительное конфигурирование (Setup) аппаратных средств порта и текущее (оперативное) переключение режимов работы прикладным или системным ПО.Способ и возможности конфигурирования СОМ-портов зависят от его исполнения и местоположения. Порт, расположенный на плате расширения (обычно на мультикарте), устанавливаемой в слот ISA или ISA+VLB, обычно конфигурируется джамперами на самой плате. Порт, расположенный на системной плате, обычно конфигурируется через BIOS Setup.
Конфигурированию подлежат следующие параметры:

* Базовый адрес, который может иметь значение 3F8h, 2F8h, 3E8h (3EOh,338h), 2E8h (2EOh, 238h). При инициализации BIOS проверяет наличие портов по адресам именно в этом порядке и, соответственно, присваивает обнаруженным портам логические имена СОМ1, COM2, COM3 и COM4.

* Используемая линия запроса прерывания: для СОМ1 и COM3 обычно используется IRQ4 или IRQ11, для COM2 и COM4 - IRQ3 или IRQ10.В принципе номер прерывания можно назначать в произвольных сочетаниях с базовым адресом (номером порта), но некоторые программы и драйверы (например, драйверы последовательной мыши) настроены только на стандартные сочетания. Каждому порту, нуждающемуся в аппаратном прерывании, обычно назначают отдельную линию, не совпадающую с линиями запроса прерываний других портов или устройств. Разделяемое использование линий прерывания адаптеров шин ISA проблематично.Прерывания необходимы для портов, к которым подключаются устройства ввода (мышь, дигитайзер), UPS и модемы. При подключении принтера или плоттера прерываниями пользуются только многозадачные ОС (и то не всегда), и этот дефицитный ресурс PC можно сэкономить. Также прерываниями обычно не пользуются и при связи двух компьютеров нуль-модемным кабелем.

*Использование канала DMA (для UART 16450 или 16550, расположенных на системной плате) - разрешение использования и номер канала DMA.Режим DMA при работе с СОМ-портами используют редко, поэтому в большинстве случаев каналы DMA порту не назначают.
Режим работы порта по умолчанию (2400 бит/с, 7 бит данных, 1 стоп-бит и контроль четности), заданный при инициализации порта во время BIOS POST, может изменяться в любой момент при настройке коммуникационных программ или командой DOS MODE COMx: с указанием параметров.

Примеры драйверов

В качестве примера можно привести разработку драйвера портов ввода- вывода.

Писать драйвера при помощи только DDK не самый удобный на сегодня способ, а посему не плохо обратить внимания на два продукта.

  1.  Jungo WinDriver 
  2.  Numega Driver Studio. 

Оба по сути похожи, а именно позволяют создавать драйвера двух типов.

  •  Работающие через некий универсальный драйвер.
  •  Полноценные драйвера работающие в режиме ядра.

Мастер создания драйверов, DriverWizard (Jungo) сгенерит код, который вы сможете вставить в свои программы и обращаться к портам в-в, памяти и даже использовать прерывания. Все очень просто: Утром установите WinDriver, вечером ваша программа будет работать с аппаратурой, но остерегайтесь WinDrivera.  Покупать вы его конечно не будете, и при установке, выберете 30-дневную копию. В течении месяца все будет работать и Driver Wizard и все программы его использующие. Потом DriverWizard работать перестанет, но к тому времени вы то уже поймете, что он и не нужен. Нужна только библиотека WINDRVR.SYS, которая и обеспечивает взаимодействие с портами Вашей программе. Так вот этот самый WINDRVR.SYS, через который будет работать ваша программа, в отличии от DriverWizarda не подает никаких признаков того, что срок истек и он больше работать не будет. Драйвер открывается как и раньше, все функции возвращают результат SUCCESS однако программа не работает, потому что драйвер пишет не то и не туда и читает не оттуда и не всегда. При этом можно подумать, что проблемы с аппаратурой, поэтому при использовании WinDrivera лучше отыскать serial number и зарегистрировать. Слишком коварная у него система защиты.

Numega Driver Studio.имеет в своем составе аналогичный компонент: Driver Agent сгенерирует все необходимое для использования универсального драйвера. Вы даже сможете создать свой файл.sys, который будет работать в составе ядра и делать там все, что вы запрограммируете, например обрабатывать прерывания. При этом вникать опять же ни во что не придется. За день разработаете свой драйвер.

Оба пакета содержат средства для написания настоящих драйверов, НО при помощи DriverStudio или WinDriver это делать значительно проще, чем при помощи только DDK, в дополнение они имеют  хорошую документацию касающуюся общих вопросов драйверов, более читаемую чем в DDK. Кстати DDK для работы с ними необходимо установить.

Установив Numega Driver Works, Вы открываете студию (не Driver , а Microsoft Visual Studio), выбираете там NewProject и видете в окне мастера рядом с
MFC App Wizard
NT/WDM Driver Wizard
Мастер за 9 шагов, сгенерит проект из которого получается драйвер и exe-шник, который этот драйвер тестирует. Кроме того в Driver Studio входит (я бы назвал это
Driver Developmen Foundational Classes) набор классов, которые содержат все необходимое для разработки драйверов, так же как MFC для разработки приложений.

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

Универсальный драйвер, который позволяет обращаться к портам ввода-вывода. Больше он ничего не может, но в большинстве случаев можно обойтись и этим. Драйвер этот называется PortIo.sys и входит в состав примеров прилагаемых к Numega Driver Works. Я его скомпилировал, вам остается скачать и использовать. Драйвер предоставляет 4 функции: Open, Close,Read и Write. Есть тестовое приложение которое демонстрирует как эти функции использовать.
Чтобы установить драйвер надо:

  1.  Поместить файл portio.sys в C:\WINDOWS\SYSTEM32\DRIVERS\
  2.  Прописать его в реестре. Для XP и 2000 это делается командой regini portio.ini в результате в разделе HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services появится раздел PortIo.
    В нем параметры:

ErrorControl

0x00000001

ImagePath

\SystemRoot\System32\Drivers\portio.sys

Type

0x00000001

Start

0x00000002

  1.  Перезагрузите систему.
  2.  Драйвер установлен можно использовать.
    Смотрите тестовое приложение.

Текст програмы на С++:

// testport.cpp - test application for port i/o example

//=============================================================================

//

// Compuware Corporation

// NuMega Lab

// 9 Townsend West

// Nashua, NH 03060  USA

//

// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.

// Unpublished - rights reserved under the Copyright laws of the

// United States.

//

//=============================================================================

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <windows.h>

#include <winioctl.h>

#include "common.h"

// -------------------------------------------------------------------------

//

// Main

//

void __cdecl main(int ac, char* av[])

{

CHAR op;

ULONG addr;

ULONG size;

ULONG data;

HANDLE hPortIo;

CHAR buffer[128];

BOOLEAN status;

ULONG nBytesReturned;

ULONG PortHandle;

PORTOPENPARAMS OpenPort;

PORTREADPARAMS ReadPort;

PORTWRITEPARAMS WritePort;

PORTCLOSEPARAMS ClosePort;

hPortIo = CreateFile("\\\\.\\PortIo",

             GENERIC_READ | GENERIC_WRITE,

                FILE_SHARE_READ,

                NULL,

                OPEN_EXISTING,

                0,

                NULL);

if (hPortIo == INVALID_HANDLE_VALUE)

{

 printf("failed to open PortIo device: error=%x\n",

   GetLastError());

 exit(1);

}

printf("command syntax: {R|W} hex-address size [hex-write-data]\n");

while (TRUE)

{

 printf("* ");

 gets(buffer);

 if (sscanf(buffer, "%c %x %d %x", &op, &addr, &size, &data) < 2)

  break;

 printf("(");

 if (op == 'R' || op == 'r')

 {

  op = 'R';

  printf("read ");

 }

 else if (op == 'W' || op == 'w')

 {

  op = 'W';

  printf("write ");

 }

 else if (op == 'X' || op == 'x')

  break;  

 else

 {

  printf("bad op)\n");

  continue;

 }

 printf(" port=%08x size=%08x", addr, size);

 if (op == 'W')

  printf(" data=%08x)\n", data);

 else

  printf(")\n");

 if (size!=1 && size!=2 && size!=4)

 {

  printf(" size must be 1, 2, or 4\n");

  continue;

 }

 OpenPort.open_Address = addr;

 OpenPort.open_PortSize = size;

 OpenPort.open_PortCount = 1;

 status = DeviceIoControl(

  hPortIo,

  IOCTL_PORTIO_OPENPORT,

  &OpenPort,

  sizeof(OpenPort),

  &PortHandle,

  sizeof(PortHandle),

  &nBytesReturned,

  NULL

  );

 if ( !status || (PortHandle == NULL) )

 {

  printf("Port open failed\n");

  continue;

 }

 if (op == 'R')

 {

  ReadPort.rd_Handle = PortHandle;

  ReadPort.rd_Index = 0;

  status = DeviceIoControl(

   hPortIo,

   IOCTL_PORTIO_READPORT,

   &ReadPort,

   sizeof(ReadPort),

   &data,

   sizeof(data),

   &nBytesReturned,

   NULL

   );

  if ( !status || (nBytesReturned==0) )

   printf("read failed: %x\n", GetLastError());

  else

   printf("result = %x\n", data);

 }

 else

 {

  WritePort.wr_Handle = PortHandle;

  WritePort.wr_Index = 0;

  WritePort.wr_Data = data;

  status = DeviceIoControl(

   hPortIo,

   IOCTL_PORTIO_WRITEPORT,

   &WritePort,

   sizeof(WritePort),

   NULL,

   0,

   &nBytesReturned,

   NULL

   );

  if ( !status )

   printf("write failed: %x\n", GetLastError());

  else

   printf("write OK\n", data);

 }

 ClosePort.close_Handle = PortHandle;    

 status = DeviceIoControl(

  hPortIo,

  IOCTL_PORTIO_CLOSEPORT,

  &ClosePort,

  sizeof(ClosePort),

  NULL,

  0,

  &nBytesReturned,

  NULL

  );

 if ( !status )

  printf("close failed: %x\n", GetLastError());

 }

CloseHandle(hPortIo);

А вот еще один пример написания драйвера:

Драйвер виртуального диска
Драйвер создает виртуальный диск, отформатированный по умолчанию как FAT. Выбор этого типа драйвера обусловлен следующим:
  •  Простота реализации. Не требуется кода для работы с оборудованием.
  •  Легкость демонстрации. Пример, не требуя специфичных устройств, может быть продемонстрирован практически на любой машине.
  •  Малый объем исходного текста, позволяющий изучить основные принципы работы, не вдаваясь в подробности.
В целях экономии места и концентрации на основной теме я опущу незначительные, но необходимые детали – инициализацию и освобождение памяти, получение параметров из реестра, обработку ошибок, – заменив  их комментариями, вкратце описывающими процесс.
Начнем с рассмотрения функции DriverEntry – точки входа в драйвер, служащей для инициализации программы. С нее начинается выполнение драйвера. Функция устанавливает, какие системные вызовы она будет обрабатывать и создает собственно виртуальный диск.

NTSTATUS

  •  DriverEntry(
    IN OUT PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING      RegistryPath
    )

Аргументы:
   DriverObject – указатель на объект, представляющий этот драйвер.
   RegistryPath – указатель на строку, задающую точку входа в реестре, отведенную для этого драйвера. Через реестр может осуществляться конфигурирование драйвера.
Возвращаемое значение:
   STATUS_SUCCESS если драйвер нормально инициализировался, иначе код ошибки

{

   NTSTATUS        ntStatus;

   UNICODE_STRING  paramPath;

   static  WCHAR   SubKeyString[] = L"\\Parameters";

… Считывание параметров из реестра

…Инициализация объекта драйвера и его точек входа. Соответствующим элементам массива DriverObject->MajorFunction присваиваются адреса поддерживаемых функций.

   DriverObject->MajorFunction[IRP_MJ_CREATE] = RamDiskCreateClose;

   DriverObject->MajorFunction[IRP_MJ_CLOSE] = RamDiskCreateClose;

   DriverObject->MajorFunction[IRP_MJ_READ] = RamDiskReadWrite;

   DriverObject->MajorFunction[IRP_MJ_WRITE] = RamDiskReadWrite;

   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RamDiskDeviceControl;

   ntStatus = RamDiskInitializeDisk(DriverObject, &paramPath);

   return ntStatus;

}

  •  NTSTATUS
    RamDiskInitializeDisk(
    IN PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING  ParamPath
    )
RamDiskInitializeDisk  вызывается во время инициализации функцией DriverEntry().
Создает и инициализирует объект устройства для диска. Память для образа выделяется в несвопируемой области. RamDiskFormatFat вызывается для создания файловой системы FAT.
Два параметра могут быть заданы при помощи реестра:
  •  DiskSize определяет размер виртуального диска в байтах. Если система не может выделить достаточно памяти, возвращается STATUS_INSUFFICIENT_RESOURCES. По умолчанию – 1 МБ.
  •  DriveLetter используется для указания имени диска. Строка должна быть буквой или буквой с двоеточием.

Аргументы:
   DriverObject – указатель на объект, представляющий этот драйвер.
   ParamPath – указатель на подключ Parameters реестра.
Возвращаемое значение:
   STATUS_SUCCESS если драйвер нормально инициализировался, иначе код ошибки

{

   STRING              ntNameString;       Имя устройства NT "\Device\RamDisk"

   UNICODE_STRING      ntUnicodeString;    Unicode версия ntNameString

   UNICODE_STRING      Win32PathString;    Имя Win32 "\DosDevices\Z:"

   

   PDEVICE_OBJECT      deviceObject = NULL;    указатель на объект устройства

   PRAMDISK_EXTENSION  diskExtension = NULL;   указатель на специфические данные устройства

   

   NTSTATUS            ntStatus;

   ULONG               defaultDiskSize = DEFAULT_DISK_SIZE;

   ULONG               diskSize = DEFAULT_DISK_SIZE;

   UNICODE_STRING      driveLetterString;

   WCHAR               driveLetterBuffer[sizeof(WCHAR) * 10];

… Инициализация и считывание параметров конфигурации из реестра

   

… Создание устройства «виртуальный диск»

   ntStatus = IoCreateDevice(

       DriverObject,                    Наш драйвер устройства

       sizeof( RAMDISK_EXTENSION ),     Размер дополнительной информации

       &ntUnicodeString,                Имя устройства "\Device\RamDisk"

       FILE_DEVICE_VIRTUAL_DISK,        Тип устройства

       0,                               Свойства устройства

       FALSE,                           Особое устройство. Драйвер обрабатывает только одного клиента

       &deviceObject );                 Возвращает указатель на объект устройства

   

… Размещение и обнуление образа диска, установление данных boot сектора, корневого каталога и пр.
   Форматирование файловой системы FAT

   RamDiskFormatFat(diskExtension, ParamPath);

… Создание символической связи между именем устройства "\Device\RamDisk" и именем Win32 "\DosDevices\Z:"

   ntStatus = IoCreateSymbolicLink(

                       &diskExtension->Win32NameString, &ntUnicodeString );

RamDiskInitializeDiskExit:

   return ntStatus;

}

  •  Функция RamDiskFormatFat не представляет интереса. Она размечает выделенный образ диска в соответствии со стандартом файловой системы Fat.
  •  NTSTATUS
    RamDiskCreateClose(
       IN PDEVICE_OBJECT DeviceObject,
       IN PIRP Irp
       )
Функция вызывается системой ввода-вывода каждый раз, когда RamDisk открывается или закрывается. Реализация ничего не выполняет, просто корректно закрывая запрос.
Аргументы:
   DeviceObject – указатель на объект представляемого устройства
   Irp – указатель на запрос ввода-вывода для этого вызова
Возвращаемое значение:
   STATUS_INVALID_PARAMETER если параметры заданы неверно, иначе STATUS_SUCCESS.

{

   Irp->IoStatus.Status = STATUS_SUCCESS;

   Irp->IoStatus.Information = 0;

   

   IoCompleteRequest( Irp, IO_NO_INCREMENT );

   

   return STATUS_SUCCESS;

}

  •  NTSTATUS
    RamDiskDeviceControl(
       IN PDEVICE_OBJECT DeviceObject,
       IN PIRP Irp
       )
Функция реализует ioctl функции
Аргументы:
   DeviceObject – указатель на объект устройства
   Irp – указатель на запрос ввода-вывода
Возвращаемое значение:
STATUS_SUCCESS если поддерживаемый запрос, иначе STATUS_INVALID_DEVICE_REQUEST.

{

   PRAMDISK_EXTENSION  diskExtension;

   PIO_STACK_LOCATION  irpSp;

   NTSTATUS            ntStatus;

… Инициализация
По умолчанию – неверный запрос

   Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;

Определяет, какая функция требуется

   switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )

   {

   

   case IOCTL_DISK_GET_MEDIA_TYPES:

   case IOCTL_DISK_GET_DRIVE_GEOMETRY:

… Возвращает параметры диска, так называемую геометрию

       {

           PDISK_GEOMETRY outputBuffer;

           outputBuffer = ( PDISK_GEOMETRY ) Irp->AssociatedIrp.SystemBuffer;

           outputBuffer->MediaType = RemovableMedia;

           outputBuffer->Cylinders = RtlConvertUlongToLargeInteger(

               diskExtension->NumberOfCylinders );

           outputBuffer->TracksPerCylinder = diskExtension->TracksPerCylinder;

           outputBuffer->SectorsPerTrack = diskExtension->SectorsPerTrack;

           outputBuffer->BytesPerSector = diskExtension->BytesPerSector;

           Irp->IoStatus.Status = STATUS_SUCCESS;

           Irp->IoStatus.Information = sizeof( DISK_GEOMETRY );

       }

       break;

   case IOCTL_DISK_GET_PARTITION_INFO:

 … Возвращает информацию о разделе

       {

           PPARTITION_INFORMATION outputBuffer;

           PBOOT_SECTOR    bootSector = (PBOOT_SECTOR) diskExtension->DiskImage;

       

           outputBuffer = ( PPARTITION_INFORMATION )Irp->AssociatedIrp.SystemBuffer;

       

           outputBuffer->PartitionType =

               (bootSector->bsFileSystemType[4] == '6') ?

                   PARTITION_FAT_16 : PARTITION_FAT_12;

       

           outputBuffer->BootIndicator = FALSE;

           outputBuffer->RecognizedPartition = TRUE;

           outputBuffer->RewritePartition = FALSE;

           outputBuffer->StartingOffset = RtlConvertUlongToLargeInteger(0);

           outputBuffer->PartitionLength = RtlConvertUlongToLargeInteger(diskExtension->DiskLength);

    outputBuffer->HiddenSectors =  1L;

       

           Irp->IoStatus.Status = STATUS_SUCCESS;

           Irp->IoStatus.Information = sizeof( PARTITION_INFORMATION );

       }

       break;

   case IOCTL_DISK_VERIFY:

       {

 Выполняет проверку носителя. Операция идентична чтению

           PVERIFY_INFORMATION verifyInformation;

           verifyInformation = Irp->AssociatedIrp.SystemBuffer;

           irpSp->Parameters.Read.ByteOffset.LowPart =

               verifyInformation->StartingOffset.LowPart;

           irpSp->Parameters.Read.ByteOffset.HighPart =

               verifyInformation->StartingOffset.HighPart;

           irpSp->Parameters.Read.Length = verifyInformation->Length;

           ntStatus = RamDiskReadWrite( DeviceObject, Irp );

       }

       return ntStatus;

   default:

 Нераспознанная функция. Ошибка

       break;

   }

Закончить операцию ввода-вывода.

   ntStatus = Irp->IoStatus.Status;

   IoCompleteRequest( Irp, IO_NO_INCREMENT );

   return ntStatus;

}

  •  NTSTATUS
    RamDiskReadWrite(
       IN PDEVICE_OBJECT DeviceObject,
       IN PIRP Irp
       )
Эта процедура вызывается для чтения и записи данных.
Аргументы:
   DeviceObject – указатель объект драйвера
   Irp – указатель на запрос ввода-вывода
Возвращаемое значение:
   STATUS_INVALID_PARAMETER если параметр неверен, иначе STATUS_SUCCESS.

{

   PRAMDISK_EXTENSION  diskExtension;

   PIO_STACK_LOCATION  irpSp;

   PUCHAR              CurrentAddress;

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

  

… Получить указатель на данные пользователя в системном контексте

   CurrentAddress = MmGetSystemAddressForMdl( Irp->MdlAddress );

   Irp->IoStatus.Information = irpSp->Parameters.Read.Length;

   switch (irpSp->MajorFunction)

   {

   case IRP_MJ_READ:

Чтение

       RtlMoveMemory(

           CurrentAddress,

           diskExtension->DiskImage + irpSp->Parameters.Read.ByteOffset.LowPart,

           irpSp->Parameters.Read.Length);

       break;

   case IRP_MJ_DEVICE_CONTROL:

       … Проверка. Всегда все в порядке

       break;

   case IRP_MJ_WRITE:

Запись

       RtlMoveMemory(

           diskExtension->DiskImage + irpSp->Parameters.Read.ByteOffset.LowPart,

           CurrentAddress, irpSp->Parameters.Read.Length);

       break;

   default:

… Что-то не поддерживаемое

       Irp->IoStatus.Information = 0;

       break;

   }

   Irp->IoStatus.Status = STATUS_SUCCESS;

   IoCompleteRequest( Irp, IO_NO_INCREMENT );

   return STATUS_SUCCESS;

}

  •  VOID
    RamDiskUnloadDriver(
       IN PDRIVER_OBJECT DriverObject
       )
Эта процедура вызывается системой для выгрузки драйвера. Требуется освободить все занятые ресурсы
Аргументы:
   DriverObject – указатель на объект драйвера

{

… Освобождает всю выделенную для драйвера память.
Удаление объекта устройства. Символическая связь рвется автоматически

       IoDeleteDevice( deviceObject );

}


Защищенная подсистема

(серверы)

Подсистема защиты

одсистема OS/2

Подсистема

POSIX

Подсистема

Win32

Режим пользователя

Режим ядра

LAN

Системные процессы

Менеджер ввода-вывода

Менеджер конфигурации

Менеджер памяти.

Поддержка выполнения

Вызов удаленных процедур

Менеджер объектов

Монитор защиты

Ядро

HAL (уровень абстракции аппаратуры)

Аппаратура

Пользовательский вызов

Драйвер файловой системы

Драйвер дискового устройства

Накопитель


 

А также другие работы, которые могут Вас заинтересовать

48566. ОСНОВНЫЕ БИЗНЕС-ПРОЦЕССЫ В ОРГАНИЗАЦИИ 75.5 KB
  Субъектами предпринимательства могут быть как отдельные частные лица, так и объединения партнеров. Частные лица как субъекты предпринимательства выступают в этом качестве, как правило, путем организации единоличного или семейного предприятия. Такие предприниматели могут ограничиваться затратами собственного труда или использовать наемный труд.
48567. Конспект лекцій. Економіка підприємства 1.92 MB
  УДК Конспект лекцій по дисципліні “Економіка підприємства†Укл. Містить конспект лекцій по дисципліні “Економіка підприємства†для студентів економічних спеціальностей усіх форм навчання. ЗМІСТ Тема1: Організаційно правові аспекти діяльності підприємства 1.
48568. Коммерческое (предпринимательское) право 3.26 MB
  Понятие коммерческого права Принципы коммерческого права История коммерческого права Очерк истории науки и преподавания коммерческого торгового права в России
48570. ОСНОВИ І МЕТОДИ АРХІТЕКТУРНОГО ПРОЕКТУВАННЯ. КУРС ЛЕКЦІЙ 476 KB
  Поняття і види архітектурного проектування МЕТОДИ АРХІТЕКТУРНОГО ПРОЕКТУВАННЯ за Б. Поняття методу і методики проектування.
48572. Промышленная безопасность во взрывном деле 3.75 MB
  Правила безопасности при перевозке взрывчатых материалов автомобильным транспортом Специальные требования по обеспечению безопасности при транспортировании промышленных ВМ разработанные в соответствии с постановлением Правительства Российской Федерации от 23 апреля 1994 г. Перечень взрывчатых материалов оборудования и приборов взрывного дела допущенных к применению в Российской Федерации [Текст] А. Положение о порядке выдачи разрешений на применение взрывчатых материалов промышленного назначения и проведение взрывных работ РД 13537 03...
48573. Процеживающие решетки и усреднители сточных вод. Конструкции фильтров для сточных вод 163 KB
  Процеживание сточных вод осуществляется пропусканием воды через решетки и волокноуловители. Решетки применяют для улавливания из сточных вод крупных нерастворенных плавающих загрязнений. Грабельная механизированная решетка Решетки устанавливают на очистных станциях при поступлении на них сточных вод самотеком.
48574. Психология цвета. Курс лекций 123 KB
  Но оно – не более чем попытка обосновать причины внимательного отношения в практическом использовании цвета на экране. Когда я пришел работать на телевидение областные студии еще понятия не имели о цвете. Цвет пришел к нам только в начале 80х а 16мм.