:: Статистика ::

 
Індекс цитування

 

 

 

 

 

Функції драйверів

Перш за все, драйвер повинен мати функції, що викликаються ядром при завантаженні і вивантаженні модуля і при підключенні модуля до конкретних пристроїв. Наприклад, в Sun Solans це перераховані функції.

  • int _init(void) — ініціалізація драйвера. Ця функція викликається при завантаженні модуля. Драйвер повинен зарезервувати всі необхідні йому системні ресурси і проинициализировать власні глобальні змінні. Ініціалізація пристрою на цьому етапі не відбувається.
  • int probe (dev_info_t *dip) — перевірити наявність пристрою в системі. У багатьох системах ця функція реалізується не самим драйвером, а спеціальним модулем-"сниффером" (sniffer — дослівно, "нюхач")використовуваним програмою автоконфігурації.
  • int attach (dev_info_t * dip, ddi_attach_cmd_t crtid) — ініціалізація копії драйвера, що управляє конкретним пристроєм. Цю функцію можна розглядати як аналог конструктора об'єкту в об'єктно-орієнтованому програмуванні. Якщо в системі присутньо декілька пристроїв, керованих одним драйвером, деякі ОС завантажують декілька копій коди драйвера, але в системах сімейства Unix функція attach просто викликається багато разів.


Кожна з копій драйвера, що ініціалізували, має власний блок локальних змінних, в яких зберігаються змінні стани пристрою. При виклику attach драйвер повинен прочитати конфігураційний файл, де записані параметри пристрою (номенклатура цих параметрів залежить від пристрою і від драйвера), розмістити і проинициализировать блок змінних стану, зареєструвати обробники переривань, проинициализировать само пристрій і, нарешті, зареєструвати пристрій як доступне для призначених для користувача програм, створивши для нього мінорний запис (minor node). У ряді випадків драйвер створює для одного пристрою декілька таких записів.
Наприклад, кожен жорсткий диск в Unix SVR4 повинен мати 16 записів — по дві (далі ми зрозуміємо, для чого вони потрібні) для кожного з восьми допустимих слайсов (логічних розділів, див. разд. Завантаження самою ОС ) диска. Інший приклад: у більшості систем сімейства Unix стрічкопротяжні пристрої мають два мінорні записи. Один з цих пристроїв при відкритті перемотує стрічку до початку, інше не перемотує. Насправді обоє пристрою управляються одним і тим же драйвером, який визначає поточний режим роботи залежно від вказаного мінорного запису.
Сучасні системи Unix, зокрема Solaris, використовують відкладену ініціалізацію, коли для багатьох пристроїв attach викликається лише при першій спробі доступу призначеної для користувача програми до пристрою.

  • int detach(dev_info_t *dip, ddi_detach_cmd_t cmd) — аналог деструкції об'єкту в ООП. Втім, на відміну від деструкції, ця операція не безумовна — якщо не удається нормально завершити оброблювані в даний момент операції над пристроєм, драйвер може і навіть зобов'язаний відмовитися деинициализироваться. При деингщиализации драйвер повинен звільнити всі системні ресурси, які він зайняв при ініціалізації і в процесі роботи (у тому числі і знищити мінорний запис) і може, якщо це необхідно, виробити якісь операції над пристроєм, наприклад, вимкнути приймач, запарковать голівки читання-запису і так далі Після того, як всі пристрої, керовані драйвером, успішно деинициализированы, система може його вивантажити.
  • int _fini (void) — функція, що викликається системою перед вивантаженням дуля. Драйвер зобов'язаний звільнити всі ресурси, які він зайняв на етапі ініціалізації модуля, а також всі ресурси, зайняті їм під час роботи на рівні модуля (не прив'язані до конкретного керованого пристрою).

Після того, як драйвер проинициализировался і зарегистрироват мино ную запис, призначені для користувача програми можуть починати звертатися до не му і до керованих їм пристроїв. Зрозуміло, що забезпечити єдиний ин терфейс до всіляких категорій пристроїв, перерахованих в главі 9 щонайменше складно. Найрадикальніше підійшли до цієї проблеми розробники системи UNIX, що розділили всі пристрої на два блокові (високошвидкісні пристрої пам'яті з довільним доступом в першу чергу, дискові пристрої) для класу і послідовні або символьні пристрої (все інше) (насправді, біля сучасних систем сімейства Unix типів драйверів дещо більше, але про це далі).
Над послідовними пристроями визначений наступний набір операцій, які можуть здійснюватися прикладною програмою (у простих випадках ці операції безпосередньо транслюються у виклики функцій драйвера).

  • int open (char * fnarne, int flags, mode_t mode) — Процедура відкриття
    пристрої. В деяких випадках вона може містити і додаткові кроки ініціалізації пристрою — наприклад, для лентопротяжек ця процедура може включати перемотування стрічки до початку. Функція повертає цілочисельний идентификатор-"ручку" (handle), часто званий також дескриптором файлу, який використовується програмою при всіх подальших зверненнях до пристрою.
  • int readfint handle, char * where, size_t how_much) — читання даних з пристрою. Якщо пристрій пристосований лише для виводу (наприклад, принтер), ця функція може бути не визначена.
  • int write (int handle, char * what, size_t how_much) — запис даних
    на пристрій. Якщо пристрій пристосований лише для введення, (наприклад, перфоленточный введення або миша), ця функція також може бути не визначена.
  • void dose (int handle) — процедура закриття (звільнення) пристрою.
  • int ioctitint handle, int cmd ...) — процедура завдання спеціальної команди, яка не може бути зведена до операцій читання і запису. Набор таких команд залежить від пристрою. Наприклад, для растрових графічних пристроїв можуть бути визначені операції установки відеорежиму; для послідовних портів RS232 це можуть бути команд^ установки швидкості, кількості бітів, обробки біта парності і т. д., для дисководів — команди форматування носія.
  • off r lseek<int handle, off_t offset, int whence)long seek — команда переміщення голівки чтения/записи до заданої позиції. Драйвери пристроїв, що не є пристроями пам'яті, наприклад модему або Принтера, як правило, не підтримують цю функцію.

Слово long в назві функції з'явилося по історичних причинах: версіях Unix для 16-розрядних машин індекс позиції не міг позначати-я словом, тому що це обмежувало б логічну довжину пристрою недопустимо малим значенням 65334 байт. Тому необхідно було використовувати подвійне слово, що відповідало типові long мови С. Современниє системи використовують 64-розрядний off_t.

  • caddr_t rranap (caddr_t addr, size_t len, int prot, int flags, int handle, off_t offset) memory map — відображення пристрою в адресний простір процесу. Параметр prot задає права доступу до ділянки, що відображує: на читання, на запис і на виконання. Відображення може відбуватися на задану віртуальну адресу, або ж система може вибирати адресу для відображення сама.

Ця функція була відсутня в старих версіях системи, але більшість сучасних систем сімейства (BSD 4.4, ряд спадкоємців BSD 4.3, SVR4 і Linux) підтримують її.
Йдеться про відображенні в пам'ять даних, що зберігаються на пристрої. Для пристроїв введення-виводу, наприклад, для принтера або терміналу, цю функцію неможливо реалізувати розумним чином. Навпаки, для стрічок і інших послідовних пристроїв пам'яті, що підтримують функцію Iseek відображення може бути реалізоване з використанням апаратних засобів віртуалізації пам'яті і операції read і write. Необхідність спеціальної функції відображення з'являється біля драйверів пристроїв, що використовують великі об'єми пам'яті, що відображує в адресний простір системної шини, наприклад, для растрових відеоадаптерів, деяких звукових пристроїв або сторінок загальної пам'яті (backpane memory — двопортовій пам'яті, використовуваній як високошвидкісний канал обміну даними в багатопроцесорних системах).
Механізм відображення доступних прикладній програмі системних викликів у функції драйвера відносно складний. Цей механізм повинен включати наступне.

  • Зміна способу ідентифікації пристрою. "Ручка" є специфічним для призначеного для користувача процесу номером, тоді як до драйвера можуть звертатися різні процеси. У системах сімейства Unix для ідентифікації пристрою використовується згаданий вище мінорний запис, який повинен містити покажчик на блок змінних стану пристрою.
  • Передачу або відображення даних з призначеного для користувача адресного простору в системне і назад.
  • Взаємодія потоків призначеного для користувача процесу (а в загальному випадку -- декількох призначених для користувача процесів, що одночасно використовують пристрій) з потоками драйвера.

Способи, якими ці питання вирішуються в сучасних операційних системах, обговорюються в подальших розділах. А поки що ми детальніше обговоримо, які саме операції над пристроєм слід визначити і чому.
Видно, що пропонований системами сімейства Unix набір операцій розглядає пристрій як неструктурований потік байтів (або, ддя пристроїв введення-виводу, два різноспрямовані потоки — для введення і для виводу). Такий розгляд природний для пристроїв алфавітно-цифрового введення-виводу і простих пристроїв, що запам'ятовують, наприклад магнітних стрічок, проте далеко не настільки природно для складніших пристроїв.
Стандартна відповідь Unix-культуры в цьому випадку така: будь-яка, скільки завгодно складна структура даних може бути сериализована — перетворена в послідовний потік байтів. Наприклад, зображення може бути перетворене в послідовний потік байтів у вигляді растрової бітової карти або послідовності описів графічних примітивів — ліній, прямокутників і ін. Прикладами такої сериализации для зображень можуть бути мова PostScript [partners.adobe.com] і протокол розподіленої віконної системи X Window [www.x.org] (обоє протоколу підтримують як растрові образи, так і досить багаті набори векторних примітивів).
Нерідкі, втім, ситуації, коли нам цікава не лише структура даних, що поступають, але і час їх вступу (у попередній главі ми запропонували класифікувати пристрої, які можуть бути використані так само, як генератори подій) — це буває в додатках реального часу, а також в завданнях, які зараз стало модно називати "завданнями м'якого реального часу", — мультимедійних програмах, що генерують потік звуку, синхронизованного із зображенням, і, особливо, в комп'ютерних іграх.
Для роботи з таким пристроєм прикладна програма, так або інакше, повинна зареєструвати обробник тих, що поступають від пристрою події. У системах Unix така реєстрація полягає у відкритті пристрою для читання, а чекання події полягає у виконанні над цим пристроєм операції читання. Для послідовних пристроїв введення операція читань розблоковується, коли з пристрою поступлять хоч якісь дані (а не тоді, коли буде заповнений весь буфер), тому, якщо прийшла лише одне подія, ми його не пропустимо. Драйвери багатьох пристроїв, здатних працювати генераторами подій, мають команди ioctl що дозволяють тонше управляти умовою розблокування функції read.
Для того, щоб під час чекання події від генератора, займатися ще якоюсь корисною роботою, пропонується або виділити чекаючий події виклик read у окрему нитку, або користуватися системними викликами lect і pollщо дозволяють чекати подій на декількох пристроях (а також засобах межпроцессного взаємодії) одночасно.
Інші ОС надають для роботи з пристроями-генераторами подій складніші механізми, частенько засновані на callback (дослівно — "виклик назад"; механізм взаємодії підсистем, коли підсистема, що запрошує сервіс, передає обслуговуючій підсистемі покажчик на функцію, яку необхідно викликати при настанні певної події).
Робота з генераторами подій вимагає рішення ще однієї задачі — зберігання подій, що поступають, в періоди, коли призначена для користувача програма їх не встигає обробляти. Необхідність відносно складних схем роботи з потрібними для цього буферами змусила розробників Unix System V Release 3 ввести ще одного типа драйверів — потокові (STREAMS) [docs.sun.com 805-7478-10]. Для прикладної програми потоковий драйвер не відрізняється від звичайного символьного пристрою, але відмінностей з точки зору системи досить багато. Деякі з цих відмінностей розглядатимуться далі.
Unix System V Release 3 (SCO Open Desktop, SCO OpenServer), Release (SCO UnixWare, SGI Irix, Sun Solaris) і системи, що випробували вплив OSF Unix (IBM AIX, HP/UX) використовують потокові драйвери для реалізації таких важливих псевдопристроїв, як труби і сокети TCP/IP. Крім того, потоковими в цих системах є драйвери мережевих адаптерів і термінальних пристроїв.
З іншого боку, в OS/2 і Windows NT/2000/XP існують обширні номенклатури типів драйверів з різними наборами функцій. Так, в OS/2 використовуються драйвери фізичних пристроїв наступних типів:

  • прості драйвери послідовних пристроїв введення-виводу, аналогічні драйверам символьних пристроїв в Unix;
  • Драйвери пристроїв прямого доступу, що запам'ятовують, аналогічні драйверам блокових пристроїв в Unix;
  • Драйвери відеоадаптерів, використовувані графічною віконною системою Presentation Manager (PM);
  • Драйвери позиційних пристроїв введення (мишей і ін.), також використовувані РМ;
  • Драйвери принтерів і інших пристроїв виведення твердої копії;
  • Драйвери звукових пристроїв, використовувані підсистемою "мультимедіа" MMOS/2;
  • драйвери мережевих адаптерів стандарту NDIS, використовувані сетевк програмним забезпеченням фірм IBM і Microsoft;
  • драйвери мережевих адаптерів стандарту ODI, використовувані програмним забезпеченням фірми Novell;
  • DMD (Device Manager Driver - - драйвер-менеджер класу пристроїв (у разд. 10.2 ми детальніше розберемося з призначенням драйверів этог типа);
  • різного роду "фільтри", наприклад, ODINSUP.SYS — преобразоватеи ODI-интерфейса в NDIS.
 

рекламодавці:

/ ml lfppюн Лучшие рефераты в каталоге для вас

::  Меню ::

ГОЛОВНА

Введення

Представлення даних в обчислювальних системах 

Машинні мови

Завантаження програм 

Управління оперативною пам'яттю

Сегментна і сторінкова віртуальна пам'ять

Комп'ютер і зовнішні події

Паралелізм з точки зору програміста 

Реалізація багатозадачності на однопроцесорних комп'ютерах 

Зовнішні пристрої

Драйвери зовнішніх пристроїв 

Файлові системи 

Додаток. Огляд архітектури сучасних ОС

 


:: Навігація ::

Головна

Додати у вишукане  

 

 

 


Copyright © Asentli, 2008