Опубликован: 24.04.2009 | Доступ: свободный | Студентов: 1180 / 358 | Оценка: 4.39 / 4.28 | Длительность: 18:45:00
Специальности: Программист
Лекция 9:

Введение в драйверы устройств ввода/вывода

< Лекция 8 || Лекция 9: 1234 || Лекция 10 >

Вспомните, что Device Manager проверяет в реестре имя устройства, переданное в вызов API CreateFile, чтобы определить, какой драйвер должен использоваться. Эту запись реестра необходимо настроить для нашего нового драйвера, редактируя файл platform.reg подпроекта. Файлы *.reg автоматически сливаются и копируются в начальный реестр на целевом устройстве. Сделайте двойной щелчок на файле *.reg, чтобы отредактировать его с помощью regedit, или отредактируйте его с помощью Notepad. Он должен содержать следующую запись реестра в файле *.reg подпроекта, чтобы менеджер устройств смог его найти:

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\KOM_DRIVER]
"Dll" = "KOM_Port.Dll"
"Prefix" ="KOM"
"Index"= dword:1
"Order"= dword:0
"FriendlyName" = "KOM Port Demo Driver"
"Ioctl" = dword:0

Существует много различных настроек реестра, которые управляют загрузкой драйвера. Большинство из них являются необязательными. Некоторые настройки реестра используются менеджером устройств и могут при желании использоваться всеми драйверами. Можно также добавить пользовательские записи реестра, на которые указывает непосредственно сам драйвер после загрузки. DLL является строковым значением, которое определяет имя файла dll для загрузки. Это значение является обязательным. Префикс является трехсимвольной строкой, которая дополняет имя драйвера. Это значение должно быть представлено в определенном порядке, чтобы иметь указатель файла на основе интерфейса драйвера. Значение Prefix является тем же значением, которое должно использоваться в точках входа потокового драйвера, если не задан флаг DEVFLAGS_NAKEDENTRIES.

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

Index является значением dword, которое составляет цифровую часть имени устройства. Это значение является необязательным, так как менеджер устройств выберет следующее последовательное значение, если оно не существует. IClass обеспечивает механизм объявления возможностей для различных системных компонентов. Flags предоставляет механизм управления способом загрузки драйвера.

DLL можно загружать в пространство процесса с помощью функций LoadLibrary или LoadDriver. В этом примере мы хотим разработать драйвер реального устройства, который является частью ядра. Для этого файл DLL нового драйвера также необходимо включить в образ ядра времени выполнения. Чтобы включить новый файл в ядро, откройте файл *.bib подпроекта драйвера и подтвердите/добавьте следующую запись:

MODULES
KOM_Port.dll  $(_FLATRELEASEDIR)\KOM_Port.dll      NK   SHK

Этот файл автоматически задается в подпроектах. Затем подпроекту требуется файл *.def для представления своих функций. Создайте файл *.def, используя Notepad или редактор в Platform builder со следующим содержанием:

LIBRARY DemoDriver

EXPORTS
KOM_Init
KOM_Deinit
KOM_Open
KOM_Close
KOM_IOControl
KOM_PowerUp
KOM_PowerDown
KOM_Read
KOM_Write
KOM_Seek

В качестве альтернативы созданию файла *.def можно объявить каждую внешнюю функцию с помощью "__declspec(dllexport) " и extern "c" (in C++) перед определением каждой внешней функции в исходном коде C++.

Теперь после сборки файл DLL нового драйвера будет в ядре. Менеджер устройств сможет найти драйвер, когда делается вызов API CreateFile "KOM", выполняя поиск в реестре. Точки входа драйвера будут доступны для других программ.

Теперь приложение должно протестировать новый драйвер KOM, вызывая его и проверяя, что менеджер устройств может найти драйвер, и что функции драйвера работают правильно. Еще один подпроект создается для KOM_Tester. Код KOM_Tester показан ниже:

// KOM_Tester.cpp : Определяет точку входа для консольного приложения 
//
// Тестовая программа в/в файла последовательного порта для драйвера KOM_Port
//
// Для демонстрации: Соедините Ebox COM2: с ПК с помощью 
// null-модемного кабеля
// Выполните HyperTerminal со скоростью 9600 бод, 8 битами данных, 
// 1 стоп-битом, без контроля четности и без контроля потока

#include "stdafx.h"

HANDLE hSerial;

int _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
	DWORD cBytes_out, cBytes_in;

	char cBuffer_out[] = "\f\n    
     Hello KOM Serial World!\n\rType something and watch it echo back\n\rCtrl C to exit\n\r";
	TCHAR cBuffer_in[80];
		// Вывод сообщения на консоли 
	printf("\nOpening KOM2: Serial Port to test new KOM Driver - Type ctrl C on other device to exit\n\r");
		// Открыть последовательный порт COM2: для чтения и записи
		// Примечание: COM1: задан для отправки информации Отладчика
            // поэтому COM2 становится COM1
hSerial = CreateFile(_T("KOM1:"), GENERIC_READ | GENERIC_WRITE,
       0, NULL, OPEN_EXISTING, 0, NULL);
		// Проверка ошибок открытия файла 
	if (hSerial == INVALID_HANDLE_VALUE){
		printf("file open errors\n","%X", hSerial);
		Sleep(4000);
		return 0;
	}
		// Записываем заголовок в последовательный порт.
	if (!WriteFile(hSerial, cBuffer_out, strlen(cBuffer_out),
         &cBytes_out, NULL)) {
		printf("file write errors\n");
		Sleep(4000);
		return 0;
	}

	cBuffer_in[0] = 0;		


// Читаем символы, копируем на экран консоли и Echo (записываем) назад 
	// Цикл, пока не вводится ctrl C (0x03) 
	while (cBuffer_in[0] != 0x03){
		// Повторное считывание любых последовательных данных и вывод
		  if (ReadFile(hSerial, cBuffer_in, 1, &cBytes_in, NULL)){
			if (cBytes_in == 0) break;
		// Вывод данных повторного считывания 
			printf("%s",cBuffer_in, cBytes_in);
		// Echo-передача символов назад отправителю
if (!WriteFile(hSerial, cBuffer_in, cBytes_in,               
  &cBytes_out, NULL)){
				printf("\rfile write errors\n");
				Sleep(4000);
				return 0;
				}
		  }
		
	}
		// Закрываем файл 
	CloseHandle(hSerial);
    return 1;
}
9.3.

После сборки новое ядро загружается и программа KOM_Tester выполняется для тестирования драйвера KOM_Port.DLL. Соединяются последовательные кабели и на системе разработки запускается HyperTerminal. Текстовый вывод на eBox и системе разработки должен совпадать, как и в предыдущих примерах программ с последовательным портом. В отладочной сборке сообщения отладчика в окне вывода будут указывать, когда вызываются различные точки входа KOM_XXXX.

Следующие отладочные сообщения драйвера были выведены в окне вывода отладки во время выполнения KOM_Tester:

Run Programs s KOM_Tester
PB Debugger Loaded symbols for 'C:\WINCE600\OSDESIGNS\OSDESIGN7\OSDESIGN7\ 
 RELDIR\ ICOP_VORTEX86_60A_X86_RELEASE\KOM_TESTER.EXE'
s KOM_Tester  22:33:23 11/25/2006 Eastern Standard Time
End s KOM_Tester  22:33:23 11/25/2006 Eastern Standard Time

PB Debugger Loaded symbols for 'C:\WINCE600\OSDESIGNS\OSDESIGN7\OSDESIGN7\ 
 RELDIR\ ICOP_VORTEX86_60A_X86_RELEASE\CONSOLE.DLL'
  61200 PID:400002 TID:4880012 DemoDriver - KOM_Open
  61200 PID:400002 TID:4880012 hDeviceContext - 
  61200 PID:400002 TID:4880012 4660
  61201 PID:400002 TID:4880012 
  61202 PID:400002 TID:4880012 DemoDriver - Exit KOM_Open
  61203 PID:400002 TID:4880012 KOM_DRIVER - KOM_Write
  61203 PID:400002 TID:4880012 hOpenContext - 
  61204 PID:400002 TID:4880012 22136
  61204 PID:400002 TID:4880012 
  61317 PID:400002 TID:4880012 KOM_DRIVER - Exit KOM_Write
  61318 PID:400002 TID:4880012 KOM_DRIVER - KOM_Read
  61318 PID:400002 TID:4880012 hOpenContext - 
  61319 PID:400002 TID:4880012 22136
  61319 PID:400002 TID:4880012 
  69052 PID:400002 TID:4880012 KOM_DRIVER - Exit KOM_Read
  69066 PID:400002 TID:4880012 KOM_DRIVER - KOM_Write
  69067 PID:400002 TID:4880012 hOpenContext - 
  69067 PID:400002 TID:4880012 22136
  69067 PID:400002 TID:4880012 
  69067 PID:400002 TID:4880012 KOM_DRIVER - Exit KOM_Write
  69068 PID:400002 TID:4880012 KOM_DRIVER - KOM_Read
  69068 PID:400002 TID:4880012 hOpenContext - 
  69069 PID:400002 TID:4880012 22136
  69069 PID:400002 TID:4880012 
  69221 PID:400002 TID:4e80012 KOM_DRIVER - DLL_THREAD_DETACH
.
.
.
185145 PID:400002 TID:4880012 KOM_DRIVER - Exit KOM_Read
185159 PID:400002 TID:4880012 KOM_DRIVER - KOM_Close
185160 PID:400002 TID:4880012 hOpenContext - 
185160 PID:400002 TID:4880012 22136
185162 PID:400002 TID:4880012 
185162 PID:400002 TID:4880012 KOM_DRIVER - Exit KOM_Close
PB Debugger Unloaded symbols for 'C:\WINCE600\OSDESIGNS\OSDESIGN7\ 
    OSDESIGN7\RELDIR\ICOP_VORTEX86_60A_X86_RELEASE\CONSOLE.DLL'
PB Debugger Unloaded symbols for 'C:\WINCE600\OSDESIGNS\OSDESIGN7\  
    OSDESIGN7\ RELDIR\ICOP_VORTEX86_60A_X86_RELEASE\KOM_TESTER.EXE'
206855 PID:400002 TID:40b0002 KOM_DRIVER - DLL_THREAD_DETACH
9.4.

Как можно видеть из вывода отладки, была загружена тестовая программа. Во время выполнения она вызвала KOM_Open. Было сделано несколько вызовов KOM_Write и KOM_Read для пересылки введенных данных на последовательный порт, соединенный с Hyperterminal, выполняющимся на ПК системы разработки. Прежде чем программа закончится после получения символа ввода CTL+C в последней операции KOM_Read, она делает вызов KOM_Close. Также во время процесса начальной загрузки вызывается KOM_init.

Драйверы производственного качества

Для реального драйвера производственного качества, такого как поставляется вместе с ОС, понадобиться сделать еще большее число усовершенствований в примере простого драйвера KOM. Он должен разрешать только один вызов KOM_OPEN в данный момент времени, чтобы два приложения не получили одновременно доступ к последовательному порту. Должно быть разработано полное множество функций IOCTL для поддержки настройки различных значений скорости в бодах, битов данных, битов контроля четности, стоп битов, и режимов квитирования. Он должен проверять ошибки переполнения, формирования кадра, и контроля четности, сообщаемые UART. Для более высоких скоростей передачи он может быть полностью буферизирован и управляться прерываниями. Программные циклы ошибок задержки должны рассматриваться для любого аппаратного отказа, который будут вызывать зависание драйвера. Вызов KOM_CLOSE, за которым сразу следует KOM_OPEN с другой скоростью в бодах, может вызывать ошибки, так как несколько символов буферизуются внутри UART. Функция KOM_CLOSE или KOM_OPEN может ожидать, пока буферы UART станут пустыми, чтобы разрешить эту проблему. Многие вызовы API имеют также параметры, так что они могут быть заданы для синхронной работы (ожидать, пока завершится операция, чтобы вернуть управление), или асинхронной (возвращать управление до завершения операции). Менеджер ресурсов В/В должен быть информирован о портах В/В, используемых драйвером.

Если устройство имеет несколько портов KOM, его можно преобразовать в многослойный драйвер устройства (слои MDD и PDD). Запись реестра нужна для каждого экземпляра порта KOM с отличным индексом массива устройств, и базовый адрес В/В, который будет использовать драйвер, также должен быть добавлен, как новый ключ реестра. Наконец, все эти новые свойства, должно быть хорошо прокомментированы, полностью документированы, и тщательно протестированы.

Можно найти реальный исходный код драйвера последовательного устройства CE в нескольких модулях в основном каталоге общего исходного кода драйвера \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\SERIAL.

Библиотека DLL высоко-скоростного дополнительного драйвера последовательного порта, управляемого прерываниями доступна в файле \WINCE600\PUBLIC\COMMON\OAK\DRIVERS\SERIAL\ISR16550.dll. ISR16550.dll, минимизирует время сигнала потока службы прерываний (IST). Это позволяет выполнять более быструю передачу данных, так как существует некоторый штраф за планирование системой передачи данных IST.ISR16550.dll из аппаратного буфера UART в программный буфер получения (FIFO) типа первый вошел, первый вышел, и заполняет данные FIFO передачи оборудования UART из буфера FIFO программной передачи без какого-либо вмешательства IST. IST будет сигнализировать, только когда получающий буфер достигнет своего порогового значения, а буфер передачи будет пустым. IST сигнализирует также, когда входящий поток данных прерывается.

Дополнительная информация

  • Оперативная справочная система в Visual Studio, предоставляемая Windows Embedded CE 6.0, содержит дополнительную информацию по разработке драйверов устройств. Исходный код широкого ассортимента связанных с ПК драйверов устройств В/В поставляется вместе с CE в каталоге WINCE600\PUBLIC\COMMON\OAK\DRIVERS
  • Общедоступные общественные проекты исходного кода Phidgets и Logitech Web-камеры являются прекрасным источником информации по драйверам USB. Адресом URL общедоступных общественных проектов исходного кода CE является: http://msdn2.microsoft.com/en-us/embedded/aa731151.aspx
  • Пример драйвера потокового интерфейса для CE 5.0 разработан и описан в статье, "SPOT the Geek and Windows CE Drivers" Майка Холла (Mike Hall) по адресу http://msdn2.microsoft.com/en-us/library/aa459176.aspx

Лабораторные упражнения

  1. Запустите драйвер KOM и выполните пример тестовой программы драйвера KOM и воспроизведите результаты, описанные в тексте.
  2. Модифицируйте драйвер KOM, так чтобы только один процесс мог успешно его открыть в данный момент времени. Второе открытие должно возвращать код ошибки. Разработайте новую тестовую программу, и проверьте, что это работает.
  3. Добавьте свойства IOCTRL в драйвер KOM, которые позволят задавать скорость в бодах, контроль четности, и число стоп-битов. Разработайте новую тестовую программу и проверьте, что это работает.
  4. Разработайте тестовую программу, которая изменяет скорость в бодах во время отправки постоянных структур данных. Если имеются какие-либо проблемы, такие как недопустимые или пропущенные символы, модифицируйте код, чтобы их разрешить.
  5. Сконфигурируйте данные менеджера ресурсов В/В, так чтобы он знал о диапазоне адресов В/В, используемом драйвером KOM. Попытайтесь открыть оба порта KOM и COM, и посмотрите, не будут ли возникать ошибки открытия в связи с конфликтом адресов В/В.
  6. Изучите исходный код примера управляемого прерываниями драйвера последовательного устройства 16550 и модифицируйте драйвер KOM, чтобы сделать его управляемым прерываниями.
< Лекция 8 || Лекция 9: 1234 || Лекция 10 >