Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Программное обеспечение параллельного порта



Нижеследующее обсуждение посвящено соответствующей функции для этого проекта. Полный листинг программы для parll. с вместе с файлом parll. h приведен в конце этой книги.

Настройка файловых операций (fops)

Как говорилось ранее, этот модуль использует open (), close () и ioctl (), как и опи­санные ранее init и cleanup.

Первым шагом является настройка структуры файловых операций. Эта структура определена в /linux/f s.h, перечисляющем все функции, которые можно реализовать в нашем модуле. Нам не нужно использовать все операции, достаточно только самых не­обходимых. Поиск в сети по запросу С99 или linux module даст вам больше информации об этих методах. Используя эту структуру, мы сообщаем ядру о местонахождении наших реализаций (или точках вхождения) open, release и iotcl.

par11.с

struct file_operations parlport_fops = {.open = parlport_open, .ioctl = parlport_ioctl, .release = parlport_close };

Далее мы создаем функции open () и close (). Данные функции-пустышки исполь­зуются для сигнализации об открытии и закрытии:

parll.с

static int parlport_open(struct inode *ino, struct file *filp)

{

printk(" \n parlport open function" );

return 0; } static int parlport_close(struct inode *ino, struct file *filp) {

printk(" \n parlport close function" );

return 0; }



Глава 5* Ввод-Вывод


Создадим функцию ioctl (). Обратите внимание, что определение функции делает­ся в начале parll. с:

#define MODULEJNAME " parll"

static int base = 0x378;

parll.с

static int parlport_ioctl(struct inode *ino, struct file *filp,

unsigned int ioctl_cmd, unsigned long parm) {

printk(" \n parlport ioctl function" ); if(_IOC_TYPE(ioctl_cmd)! = IOCTL_TYPE) {

printk(" \n%s wrong ioctl type", MODULE_NAME); return -1; >

switch(ioctl_cmd) { case DATA_OUT:

printk(" \n%s ioctl data out=%x", MODULE_NAME, (unsigned int)parm);

outb(parm & Oxff, base+0);

return (parm & Oxff); case GET.JSTATUS:

parm = inb(base+l);

printk(" \n%s ioctl get status=%x", MODULE_NAME, (unsigned int)parm);

return parm; case CTRL_OUT:

printk(" \n%s ioctl Ctrl out=%x", MODULE_NAME, (unsigned int)parm);

outbfparm & & Oxff, base+2);

return 0; } //end switch return 0; } //end ioctl

Функция ioctl () делает возможной обработку любых определенных пользовате­лем команд. В нашем модуле мы используем три регистра, связанные с параллельным портом пользователя. Команда DATA_OUT посылает значение из регистра data, команда GET_STATUS читает из регистра status, и, наконец, команда CTRL_OUT позволяет уста­новить сигнал для порта. Несмотря на то что лучше было бы скрыть специфические для устройства операции внутри функций read() и write (), этот модуль, работоспосо­бен, так как служит только для экспериментов с вводом-выводом, а не для реального применения.


Резюме



Эти три команды определены в заголовочном файле parll. h. Они создаются с при­менением вспомогательных функций IOCTL для проверки типов. Вместо использования целого для представления функции IOCTL мы используем IOCTL-макрос проверки типов 10 (type, number), где параметр type определен как р (для параллельного порта), a number как текущий номер IOCTL, используемый в выражении. В начале parlport_ ioctl () мы проверяем тип, которым должен быть р. Так как код приложения исполь­зует тот же заголовочный файл, что и драйвер, интерфейс будет согласованным.

Настройка функции инициализации модуля

Модуль инициализации используется для связи модуля с операционной системой. Он мо­жет применяться для ранней инициализации необходимых структур данных. Так как драйверу параллельного порта не требуется сложных структур данных, мы просто реги­стрируем модуль.

parll.с

static int parll_init (void)

{

int retval;

retval= register_chrdev(Major, MODULE_NAME, & parlport_fops); if(retval < 0) {

printk( " \n%s: can't register", MODULE_NAME); return retval; }

else {

Maj or=retval;

printk(" \n%s: registered, Major=%d", MODULE_NAME, Major); if(request_region(base, 3, MODULE_NAME)) printk(" \n%s: I/0 region busy.", MODULE_NAME); }

return 0; }

Функция init_module() отвечает за регистрацию модуля в ядре. Функция regis ter_chrdev () получает старший номер запроса (описывается в разд. 5.2 и далее в гл. 10; если 0, ядро назначает ее модулю). Вспомните, что старший номер хранится в структуре inode, на которую указывает структура dentry, на которую указывает структура файла. Вторым параметром является имя устройства, отображаемое в /ргос/ devices. Третьим параметром является только что описанная структура операций.



Глава 5 • Ввод-Вывод


В случае успешной регистрации функция init вызывает request_region() с базовым адресом параллельного порта и длины диапазона (в байтах) вставляемых реги­стров.

Функция init_module () возвращает отрицательное число в случае неудачи.

3) Настройка функции очистки модуля

Функция cleanup__module () отвечает за отмену регистрации модуля и освобождение

запрошенного ранее диапазона ввода-вывода:

parll.с

static void parll_cleanup( void )

{

printk(и\n%s: cleanup H, MODULE_NAME);

release_region(base/3);

unregis ter_chrdev (Maj or, MODULE_NAME); }

И наконец, мы помещаем запрашиваемый init и точку очистки:

parll.с

module_init (parll_init);

module_exit(parll_cleanup);

4) Вставка модуля

Теперь мы вставляем наш модуль в ядро, как в предыдущем проекте, с помощью Lkp: ~# insmod parll.ko

Загляните в /var/ log/messages, где отображается вывод нашей функции init () и уделите особое внимание отображающимся там старшим возвращаемым но­мерам.

Как в предыдущем проекте, мы просто вставляем наш модуль в ядро и удаляем его оттуда. Теперь нам нужно связать наш модуль с файловой системой с помощью команды mknod. Введите в командной строке следующее:

Lkp: ~# znknode /dev/parll с < ХХХ> О

Параметры:

с. Создается символьный специальный файл (в отличие от блочного).

/dev/parll. Путь к нашему устройству (для открытого вызова).

XXX. Старший номер, возвращаемый во время init (из var/log/messages).


Резюме



• 0. Младший номер нашего устройства (в данном примере не используется).

Например, если вы увидите старший номер 254 в /var/log/messages, команда будет выглядеть следующим образом:

Lkp: ~# mknode /dev/parll с 254 О

Код приложения

Мы создаем простое приложение, которое открывает наш модуль и начинает бинарный

отчет на штырьках с DO до D7.

Этот код компилируется с помощью дсс арр. с. По умолчанию программа собира­ется в а. out.

арр. с

000 //Приложение, использующее драйвер параллельного порта

tinclude < fcntl.h> tinclude < linux/ioctl.h> 004 #include " parll.h"

main() {

int fptr;

int i, retval, parm =0;

printf(H\nopening driver now" ); 012 if((fptr = open(-/dev/parll-, 0_WR0NLY))< 0)

{

printf (" \nopen failed, returned=? %d-, fptr); exit(l);

}

018 for(i=0; i< 0xff; i++)
{

20 system(" sleep.2" );

21 retval=ioctl(fptr, DATA_OUT, parm);

22 retval=ioctl(fptr, GET_STATUS, parm);

024 if(! (retval & 0x80))

printf(H\nBusy signal count=%xH, parm); if(retval & 0x40)

027 printf(-\nAck signal count=%x", parm);

028 // if(retval & 0x20)

// printf(" \nPaper end signal count=%x", parm);

// if(retval & 0x10)

// printf(-\nSelect signal count=%x-, parm);

// if(retval & 0x08)



Глава 5* Ввод-Вывод


033 // printf(" \nError signal count=%x", parm);

parm++; }

038 close(fptr);

}

Строка 4

Общий для приложения и драйвера заголовочный файл, содержащий главные макросы IOCTL для проверки типов.

Строка 12

Открытие драйвера для получения файлового описателя нашего модуля.

Строка 18

Вход в цикл.

Строка 20

Замедление цикла, чтобы мы могли увидеть огоньки и отсчет.

Строка 21

Используя файловый указатель, посылаем команду DATA_OUT в модуль, который, в свою очередь, использует outb () для записи последних значащих 8 бит параметров для порта данных.

Строка 22

Чтение байта состояния с помощью ioctl с команды GET__STATUS.

Строки 24-27

Смотрим интересующие нас биты. Обратите внимание, что Busy — это низкий ак­тивный сигнал, поэтому, когда ввода-вывода нет, мы читаем его как true.

Строки 28-33

Эти строки вы сможете раскомментировать, когда захотите усовершенствовать ди­зайн.

Строка 38

Закрытие модуля

Если вы собрали разъем, как показано на рис. 5.5, сигналы busy и аск посылаются, когда два значащих бита счетчика включены. Код приложения считывает эти биты и производит соответствующий вывод.

Мы осветили только основные элементы драйвера символьного устройства. Зная эти функции, легко проследить работу кода или создать собственный драйвер. Добавление


Резюме



V

V

V

V

Рис. 5.5. Собранный разъем

в этот модуль обработчика прерывания породит вызов к request_irq () и передачу но­мера желаемого IRQ и имени обработчика. Его нужно добавить в init_module (). Вот несколько возможных способов усовершенствования драйвера:

Заставить модуль параллельного порта обрабатывать прерывания таймера в качестве ввода.

Как можно превратить 8 бит ввода-вывода в 16, 32, 64? Чем мы жертвуем?

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

Добавить функцию прерывания для использования сигнала аск.



Глава 5 • Ввод-Вывод


Упражнения

1. Загрузите модуль. В качестве какого файла модуль отобразится в файловой сис­теме?


Поделиться:



Популярное:

  1. III. ОБЕСПЕЧЕНИЕ БЕЗОПАСНОСТИ УЧАСТНИКОВ И ЗРИТЕЛЕЙ, МЕДИЦИНСКОЕ ОБЕСПЕЧЕНИЕ, АНТИДОПИНГОВОЕ ОБЕСПЕЧЕНИЕ СПОРТИВНЫХ СОРЕВНОВАНИЙ
  2. IV. Организация функционирования сооружений и устройств железнодорожного транспорта
  3. XIX. Обеспечение объектов первичными средствами пожаротушения
  4. Автоматика пунктов параллельного соединения
  5. АВТОМОБИЛЬНОГО ТРАНСПОРТА № 9
  6. Аппаратные платформы. Кроссплатформенное программное обеспечение.
  7. Безопасность при работе конвейерного транспорта
  8. В какой фазе особенно необходимо обеспечение деревьев влагой и питательными веществами?
  9. В МФЦ г. Петрозаводска состоялось торжественное вручение паспорта гражданина РФ.
  10. Ведомственный надзор за охраной труда на предприятиях ж.д. транспорта и транспортного строительства.
  11. ВЛИЯНИЕ АВТОТРАНСПОРТА НА ГОРОДСКУЮ СРЕДУ
  12. Воздействие промышленности и транспорта на окружающую среду


Последнее изменение этой страницы: 2016-03-25; Просмотров: 744; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.035 с.)
Главная | Случайная страница | Обратная связь