Теорія операційної системи

:: Меню ::

Головна
Представлення даних в обчислювальних системах
Машинні мови
Завантаження програм
Управління оперативною пам'яттю
Сегментна і сторінкова віртуальна пам'ять
Комп'ютер і зовнішні події
Паралелізм з точки зору програміста
Реалізація багатозадачності на однопроцесорних комп'ютерах  
Зовнішні пристрої
Драйвери зовнішніх пристроїв
Файлові системи
Безпека
Огляд архітектури сучасних ОС

:: Друзі ::

Карта сайту
 

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

 

 

 

 

 

Архітектура драйвера

Драйвер, таким чином, складається з основної нитки, обробника переривання, і, можливо, однієї або декількох високопріоритетних ниток, що створюються обробником. Всі ці нитки спільно (і, як правило, гарантуючи те, що взаємовиключає) виконують більш менш складний кінцевий автомат, достатки якого відповідають етапам виконання чергового запиту до пристрою.
Як правило, перший достаток автомата обробляється основною ниткою драйвера, а подальші — обробником переривань. У фінальному достатку автомата ми повідомляємо процес, породжувачу запит, що запит відпрацьований. Залежно від протоколу взаємодії цього процесу основною ниткою драйвера, таке повідомлення може здійснюватися як fork-процессом, так і пробудженням основної нитки.

Драйвер Ide/ata для Linux
У прикладі 10.5 приведена основна функція обробки запиту і функція об робітки переривання, використовувана при записі декількох секторів. Обидві ці функції викликаються драйвером контроллера Ide/ata, який є диспетчер запитів до підключених до контроллера пристроїв.
Структура *hwgroup є блоком змінних достатків контроллера пристрою. Ця структура містить також покажчик на поточний запит до пристрою. Інформації, що міститься в цих структурах, досить, щоб чергова функція кінцевого автомата драйвера взнала все, необхідне їй для виконання чергового етапу запиту. В даному випадку кінцевий автомат вельми простий і складається з багатократного виклику функції ide_multiwriteщо копіює в контроллер черговий блок даних. Умовою завершення автомата служать помилка контроллера або завершення запиту. Функції ide__dma_read, ide_dma_write, ide_read і ide_write виконувані машиною достатків при обробці інших запитів не приводяться.

Приклад 10.5. Фрагменти драйвера диска Ide/ata ОС Linux 2.2, переклад коментарів автора

/*
* ide_multwrite() передає приводу блок з не більш, ніж mcount
* секторів як частина багатосекторної операції запису. *
* Повертає 0 при успіху. *
* Звернете увагу, що ми можемо бути викликані з двох контекстів -
* контексту do_rw і контексту IRQ. IRQ (Interrupt Request
* запит переривання)может статися в будь-якій
* момент після того, як ми виведемо повну кількість секторів
* тому ми повинні оновлювати достаток _до_ того, як ми виведемо
* останню частину даних! */
int ide_multwrite (ide_drive__t *drive, unsigned int mcount) {
ide_hwgroup_t *hwgroup= HWGROUP(drive);
'struct request *rq = &hwgroup->wrq;
do {
char *buffer;
int nsect = rq->current_nr_sectors;
if (nsect > mcount)
nsect = mcount; mcount -= nsect; buffer = rq->buffer;
rq->sector += nsect; rq->buffer += nsect « 9; rq->nr_sectors -= nsect; rq->current nr sectors -= nsect;
/* Чи переходимо ми до наступного bh після цього? */ if (!rq->current_nr_sectors) {
struct buffer_head *bh = rq->bh->b_reqnext;
/* Завершитися, якщо у нас кінчилися запити V if (!bh) {
mcount = 0; } else (
rq->bh = bh;
rq->current_nr_sectors = bh->b_size » 9;
rq->buffer = bh->b_data;
/*
* Тепер ми всі набудували, щоб переривання
* знову викликало нас після останньої передачі. */
idedisk_output_data(drive, buffer, nsect«7); } while (mcount);
return 0;
/*
* multwrite_intr() — обробник переривання багатосекторного запису */
static ide_startstop_t multwrite_intr (ide_drive_t *drive) {
byte stat;
ir.t i;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
struct request *rq = &hwgroup->wrq;
if (Ok_stat(stat=get_stat(),DRIVE_READY,drive->bad_wstat)) { if (stat & Drq_stat) { /*
* Привід вимагає даних. Пам'ятаємо що rq -
* копія запиту. */
if (rq->nr_sectors) {
if (ide_multwrite(drive, drive->mult_count))
return ide_stopped; «
ide_set__handler (drive &multwrite_intr, Wait_cmd, NULL); return ide_started; }
} else { /*
* Якщо копіювання всіх блоків завершилося
* ми можемо завершити вихідний запит. */
if ( ! rq->nr__sectors) { /* all done? */ rq = hwgroup->rq; for (i = rq->nr_sectors; i > 0;){ i - = rq->current_nr_sectors; ide_end_request(1, hwgroup); } return ide stopped;
return ide_stopped; /* Оригінальний код робив це тут (?) */
! ьнешніх
[return ide_errcr(drive, "multwrite_intr", stat);
/*
i do rw disk() передає команди READ і WRITE приводу
* використовуючи LBA якщо підтримується, або CHS якщо немає, для адресації
* секторів. Функція do_rw_disk також передає спеціальні запити.
*/
static ide_startstop__t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{ if (Ide_control_reg)
Out_byte (drive->ctl, Ide_control_reg) ; Out_byte (rq->nr_sectors, Ide_nsector_reg) ; if (drive->select.b.lba) (
Out_byte (block, Ide_sector_reg) ;
Out_byte (block»=8, Ide_lcyl_reg) ;
Out_byte (block»=8, I De_hc Yl_reg ) ;
Out_byte( ( (block»8) &0x0f) I drive->select . all, Ide_select_reg); } else f
unsigned int sect, head, cyl, track;
track = block / drive->sect;
sect = block % drive->sect + 1;
Odt^byte (sect, IDE__SECTOR_REG) ;
head = track % drive->head;
cyl = track / drive->head;
OUT__BYTE (cyl, Ide_lcyl_reg) ;
Out_byte (cyl»8, Ide_hcyl_reg) ;
Out_byte (head I drive->select .all, Ide_select_reg) ;
if (rq->cmd == READ) { ^#ifdef Config_blk_dev_idedma
if (drive- >using_dma && ! (HWIF (drive) ->dmaproc (ide_dma_read, drive))
return ide_started; #endif /* Config_blk_dev_idedma */
ide_set_handler (drive, iread_intr, Wait_cmd, NULL) ; Out_byte(drive->mult_count ? Win_multread : Win_read, IDE COMMAND REG);
''—-^
return ide started;
if (rq->cmd == WRITE) (
ide_startstop_t startstop; lifdef Config_blk_dev_idedma
if (drive->using_drna && !(HWIF(drive)->dmaproc(ide dma^write
drive)))
return ide_started; lendif /* Config_blk_dev_idedma */
Out_byte(drive->mult_count ? Win_multwrite : Win_write
Ide_command_reg); if (ide_wait_stat(Sstartstop, drive, Data_ready, drive->bad_wstat
Wait^drq)) ( printk(Kern_err "%s: no DRQ after issuing %s\n", drive->na:r.e,
drive->mult_count ? "MULTWRITE" : "WRITE"); return startstop;
if (!drive->unmask)
__cli(); /* лише локальне ЦПУ */
if (drive->mult_count) (
ide_hwgroup_t *hwgroup = HWGROUP(drive);
/*
* Ця частина виглядає непривабливо, бо ми ПОВИННІ встановити
* обробник перед виведенням першого блоку даних.
* Якщо ми виявляємо помилку (зіпсований список буферів)
* у ide_multiwrite(),
* нам необхідно видалити обробник і таймер перед поверненням.
* На щастя, це НІКОЛИ не відбувається (правильно?).
* Видається, крім випадків, коли ми отримуємо помилку... */
hwgroup->wrq = *rq; /* scratchpad */
ide_set_handler (drive &multwrite_intr, WAIT__CMD, NULL);
if (ide_multwrite(drive, drive->mult_count)) {
unsigned long flags;
spin_lock_irqsave (&io__request_lock, flags) ;
hwgroup->handler = NULL;
del_timer(&hwgroup->timer);
spin unlock_irqrestore(&io_request_lock, flags);
return ide_stopped;
Глава 10. Драйвери зовнішніх
} else {
ide_set_handler (drive &write_intr, Wait_cmd, NULL); idedisk_output_data(drive, rq->buffer, Sector_words);
}
i return ide_started;
)
i'-printk (Kern_err "%s: bad command: %d\n", drive->name, rq->cmd)
ide_end_request(0, HWGROUP(drive)); return ide_stopped;

 

:: Реклама ::

 

:: Посилання ::


 

 

 


Copyright © Kivik, 2017