Абзац
:: Поиск
:: Поддержка проекта
Webmoney:
  • Z610389805629
  • R427996570517
  • E023541002978
  • :: №32 (10.10.2009) Просмотров: 5053

    Автор: Александр Синяков / SAM style.

    Рубрика: В помощь разработчику.

    Номер: №32 (10.10.2009).



    Автоопределение схемы IDE и подключенных устройств

    В этой статье рассматривается авто­матическое определение схемы IDE программным способом. На данный момент широкое распространение получили схемы Nemo (и её модифи­кация Nemo-A8), ATM и SMUC. Наша задача - программно определить тип схемы и подключенные устройства (HDD, CD-ROM, DVD-ROM).

    Для начала, составим таблицу портов данных схем:

    Назначение порта                         SMUC  ATM   Nemo  NemoA8
    команда (in)/состояние (out)             #FFBE #FEEF #FFF0 #FEF0
    регистр головки, устройства, режима LBA  #FEBE #FECF #FFD0 #FED0
    цилиндр (старшая часть)                  #FDBE #FEAF #FFB0 #FEB0
    цилиндр (младшая часть)                  #FCBE #FE8F #FF90 #FE90
    сектор                                   #FBBE #FE6F #FF70 #FE70
    счётчик                                  #FABE #FE4F #FF50 #FE50
    регистр ошибки                           #F9BE #FE2F #FF30 #FE30
    данные (старшая часть)                   #D8BE #FF0F #FF11 #FF10
    данные (младшая часть)                   #F8BE #FE0F #FF10 #FE10

    Стоит заметить, что SMUC и ATM используют для работы теневые порты, и для корректного чтения из портов нам необходимо знать адрес, по которому в TRDOS расположена пара команд:

        IN A,(C)
        RET

    Обозначим этот адрес TRD_IN_ADR.

    Работа с разными схемами подключения IDE различается лишь номерами портов, поэтому ло­гично использовать одни и те же процедуры с различными входными параметрами. В рассмат­риваемой программе номера портов передаются через таблицу, на которую указывает регистр IX.


    Проверка на тип схемы и устройства произ­водится по следующей схеме:

    1. Выбираем устройство MASTER, проверяем его на занятость (бит 7 в регистре состояний)

    - если он занят - полагается, что его нет. Тогда также проверяем устройство SLAVE.

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

    2. Записываем в регистры цилиндра 0 и даём команду #EC - идентификация винчестера

    - если команда принята без ошибок, то это вин­честер. Необходимо считать в буфер 512 байт и проверить байт по смещению +256. Это делает­ся, чтобы различить Nemo и Nemo-A8, если этот байт равен 255 - тест провален, иначе - прошёл ус­пешно.

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

    - если команда выдала ошибку и регистр ци­линдра равен #EB14, мы имеем дело с ATAPI-уст­ройством (это может быть либо CDROM, либо DVDROM). В этом случае даём команду #A1 (ана­лог команды #EC для atapi) и считываем в буфер 2048 байт (?) и аналогично проверяем байт +1024

    3. Если тест данной схемы провален, перехо­дим на тест следующей схемы.

    (здесь возникли неувязочки, потому как при тесте в Unreal0.32b7 с DVD считалось только 512 байт, остальные были забиты значениями 255).

    Далее следует листинг программы.

    ide_detect    ld ix,ide_tab    ;IX - указатель на таблицу портов
    ide_next    ld a,(ix)    ;проверяем конец таблицы
        or (ix+1)
        jr z,no_ide    ;если конец - подстановка «ложной таблицы»
        ld a,#a0    ;тестируем master
        call test_ide
        ld (master),a
        push af
        ld a,#b0    ;тестируем slave
        call test_ide
        ld (slave),a
        pop bc
        or b
        ret nz    ;если хоть одно устройство 
            ;определилось нормально - выход
        ld de,23
        add ix,de
        jr ide_next
    no_ide    ld ix,fake_ide    ;когда все тесты провалены - 
            ;подсовываем «ложный IDE»
        scf
        ret
    test_ide    call out_head    ;выбираем устройство (master/slave)
        call in_state    ;устройство должно быть не занято!
        rla
        ld a,0
        ret c
        ld de,0    ;регистр цилиндра = 0
        call out_cylind
        ld a,#EC    ;#EC - команда идентификации hdd
        call ide_command
        jr nc,hdd_detect    ;если ошибки нет - это винчестер
        call in_cylind    ;иначе проверяем регистр цилиндра
        ld hl,#EB14    ;если он не #EB14 - устройство не определено
        and a
        sbc hl,de
        ld a,h
        or l
        jr nz,test_fail
        ld a,#A1    ;#A1 - команда идентификации atapi
        call ide_command
        jr c,test_fail
        ld hl,bufer    ;считываем в буфер 2048 байт
        ld bc,1024
        call ide_read
        ld a,(bufer+1024)    ;и проверяем байт +1024 на равенство 255
        inc a
        jr z,test_fail
        ld a,2
        ret
    hdd_detect    ld hl,bufer    ;для винчестера - считываем в буфер 512 байт
        ld bc,256
        call ide_read
        ld a,(bufer+256)    ;и проверяем +256 на равенство 255
        inc a
        jr z,test_fail
        ld a,1
        ret
    test_fail    xor a
        ret
    ;Далее следует таблица портов IDE
    ;+0 comand/state
    ;+2 head
    ;+4 cyl.hi
    ;+6 cyl.low
    ;+8 sector
    ;+10 counter
    ;+12 error
    ;+14 data.hi
    ;+16 data.low
    ;+18 IN prog adr
    ;+20 OUT prog adr
    ;+22 sheme ID
    ide_tab
        dw #FFBE    ;порты SMUC (см. таблицу выше)
        dw #FEBE
        dw #FDBE
        dw #FCBE 
        dw #FBBE
        dw #FABE
        dw #F9BE
        dw #D8BE
        dw #F8BE
        dw shadow_in    ;адреса чтения и записи в/из портов
        dw shadow_out
        db 1    ;идентификатор (для удобства)
        dw #FEEF    ;порты ATM2+
        dw #FECF 
        dw #FEAF 
        dw #FE8F 
        dw #FE6F 
        dw #FE4F 
        dw #FE2F
        dw #FF0F
        dw #FE0F 
        dw shadow_in
        dw shadow_out
        db 2
        dw #FFF0    ;порты Nemo
        dw #FFD0
        dw #FFB0 
        dw #FF90 
        dw #FF70 
        dw #FF50
        dw #FF30
        dw #FF11
        dw #FF10
        dw open_in
        dw open_out
        db 3
        dw #FEF0    ;порты Nemo-A8
        dw #FED0
        dw #FEB0
        dw #FE90
        dw #FE70
        dw #FE50
        dw #FE30
        dw #FF10
        dw #FE10 
        dw open_in
        dw open_out
        db 4
    fake_ide    ds 18,#FF    ;ложная таблица
        dw fake_in
        dw fake_out
        db 0
    ide_command    call out_com    ;подать устройству команду
        call ide_busy
    ide_error    call in_state
        rra
        ret nc
        call in_error
        scf
        ret
    ide_busy    call in_state    ;дождаться освобождения устройства
        rla
        jr c,ide_busy
        ret
    ide_read    push bc    ;считать bc слов на hl
        call in_data_l    ;устройство должно быть готово к передаче
        ld (hl),a
        inc hl
        call in_data_h
        ld (hl),a
        inc hl
        pop bc
        dec bc
        ld a,b
        or c
        jr nz,ide_read
        ret
    out_cylind    ld a,d    ;вывод de в регистр цилиндра
        call out_cyl_h
        ld a,e
        jr out_cyl_l
    in_cylind    call in_cyl_h    ;чтение регистра цилиндра в de
        ld d,a
        call in_cyl_l
        ld e,a
        ret
    in_state    ld c,(ix)    ;подпрограммы чтения из регистров IDE
        ld b,(ix+1)
        jr in_bc
    in_head    ld c,(ix+2)
        ld b,(ix+3)
        jr in_bc
    in_cyl_h    ld c,(ix+4)
        ld b,(ix+5)
        jr in_bc
    in_cyl_l    ld c,(ix+6)
        ld b,(ix+7)
        jr in_bc
    in_sector    ld c,(ix+8)
        ld b,(ix+9)
        jr in_bc
    in_count    ld c,(ix+10)
        ld b,(ix+11)
        jr in_bc
    in_error    ld c,(ix+12)
        ld b,(ix+13)
        jr in_bc
    in_data_h    ld c,(ix+14)
        ld b,(ix+15)
        jr in_bc
    in_data_l    ld c,(ix+16)
        ld b,(ix+17)
    in_bc    push hl
        ld l,(ix+18)
        ld h,(ix+19)
        ex (sp),hl
        ret
    out_com    ld c,(ix)    ;подпрограммы записи в регистры IDE
        ld b,(ix+1)
        jr out_bc
    out_head    ld c,(ix+2)
        ld b,(ix+3)
        jr out_bc
    out_cyl_h    ld c,(ix+4)
        ld b,(ix+5)
        jr out_bc
    out_cyl_l    ld c,(ix+6)
        ld b,(ix+7)
        jr out_bc
    out_sector    ld c,(ix+8)
        ld b,(ix+9)
        jr out_bc
    out_count    ld c,(ix+10)
        ld b,(ix+11)
        jr out_bc
    out_error    ld c,(ix+12)
        ld b,(ix+13)
        jr out_bc
    out_data_h    ld c,(ix+14)
        ld b,(ix+15)
        jr out_bc
    out_data_l    ld c,(ix+16)
        ld b,(ix+17)
    out_bc    push hl
        ld l,(ix+20)
        ld h,(ix+21)
        ex (sp),hl
        ret
    open_in    in a,(c)    ;вывод/ввод для открытых портов
        ret
    open_out    out (c),a
        ret
    shadow_in    push hl    ;вывод/ввод для закрытых портов
        ld hl,trd_in_adr
        jr to_dos
    shadow_out    push hl
        ld hl,10835
    to_dos    ex (sp),hl
        jp 15663
    fake_in    ld a,#FF
    fake_out    ret
    master    db 0
    slave    db 0
    bufer    ds 2048

    После вызова ide_detect регистр IX будет ука­зывать на таблицу портов определённой схемы IDE (или на ложную таблицу). В ячейке (IX+22) со­держится идентификатор схемы.

    После этого можно использовать подпрограм­мы записи/чтения в/из портов, не заботясь о том, какая схема подключена (и подключена ли). Но перед этим необходимо записывать в IX адрес таблицы, который нам выдала программа.


    P.S. Метод обкатан и работает, а вот в самой программе могут быть ошибки - я её писал по памяти, не проверяя. Если кого-то заинтересует, могу найти рабочие исходники.

    © 2004-2013 Perspective group