#include <stdlib.h> #include <string.h> #include <conio.h> #include <printf.h> #include <stdio.h> #include "ata.h" #include <kernel/driver.h> #define CLRSCR L"\x1b[2J" #define DEBUG(s) volatile word _interrupt_occurred; void __cdecl AtaIrq(dword context, int irq) { //wprintf(L"ATA(PI) interrupt %d\n", irq); _interrupt_occurred |= 1 << irq; } CAtaDrive::CAtaDrive() { m_refs = 0; } // IUnknown methods HRESULT CAtaDrive::QueryInterface(REFIID iid, void ** ppvObject) { if (InlineIsEqualGUID(iid, IID_IUnknown) || InlineIsEqualGUID(iid, IID_IDevice)) { *ppvObject = (IDevice*) this; AddRef(); return S_OK; } else if (InlineIsEqualGUID(iid, IID_IBlockDevice)) { *ppvObject = (IBlockDevice*) this; AddRef(); return S_OK; } return E_FAIL; } // IDevice method HRESULT CAtaDrive::GetInfo(device_t* buf) { if (buf->size < sizeof(device_t)) return E_FAIL; wcscpy(buf->name, m_name); return S_OK; } HRESULT CAtaDrive::DeviceOpen() { return S_OK; } // IBlockDevice methods HRESULT CAtaDrive::GetSize(blocksize_t *size) { size_t old_size = size->size; if (old_size < sizeof(blocksize_t)) return E_FAIL; *size = m_size; size->size = old_size; return S_OK; } bool CAtaDrive::WaitStatus(word mask, word bits) { dword end; word stat; end = sysUpTime() + 2000; while (((stat = in(m_port + ATA_REG_STATUS)) & mask) != bits) { if (sysUpTime() >= end) { wprintf(L"ATA: wait failed; stat = %x\n", stat); return false; } } return true; } void CAtaDrive::Select() { out(m_port + ATA_REG_DRVHD, m_unit); } void CAtaDrive::BlockToChs(int block, int *cyl, int *head, int *sect) { *sect = block % m_sectors + 1; block /= m_sectors; *head = block % m_heads; block /= m_heads; *cyl = block; /**cyl = block / (m_heads * m_sectors); block %= m_heads * m_sectors; *head = block / m_sectors; block %= m_sectors; *sect = block;*/ } size_t CAtaDrive::BlockRead(addr_t start, size_t blocks, void* buffer) { unsigned short *buf; int cyl, head, sect; size_t i, read, per = min(blocks, m_mult_max); if (!m_heads || !m_sectors) return 0; buf = (unsigned short *) buffer; start += m_start_sector; read = 0; while (read < blocks) { BlockToChs(start, &cyl, &head, §); //wprintf(L"%d = %d:%d:%d\t", start, cyl, head, sect); //IDE_WAIT_0 (STATUS, 7); if (!WaitStatus(ATA_BUSY, 0)) return read; //IDE_SEL_DH (bus, device, head); //IDE_WAIT_0 (STATUS, 7); //IDE_WAIT_1 (STATUS, 6); Select(); /*if (!WaitStatus(ATA_BUSY, 0) || !WaitStatus(ATA_READY, ATA_READY)) return read;*/ if (!WaitStatus(ATA_BUSY | ATA_READY, ATA_READY)) return read; out(m_port + ATA_REG_LOCYL, cyl & 0xff); out(m_port + ATA_REG_HICYL, (cyl >> 8) & 0xff); out(m_port + ATA_REG_SECTOR, sect /*+ 1*/); out(m_port + ATA_REG_DRVHD, head); out(m_port + ATA_REG_COUNT, per); out(m_port + ATA_REG_CMD, ATA_CMD_READ); //IDE_WAIT_0 (STATUS, 7); //IDE_WAIT_1 (STATUS, 3); /*if (!WaitStatus(ATA_BUSY, 0) || !WaitStatus(ATA_DRQ, ATA_DRQ)) return read;*/ if (!WaitStatus(ATA_BUSY | ATA_DRQ, ATA_DRQ)) return read; for (i = 0; i < 256 * per; i++) buf[i] = in16(m_port + ATA_REG_DATA); read += per; start += per; buf += per * 256; } return read; } size_t CAtaDrive::BlockWrite(addr_t start, size_t blocks, const void* buffer) { return 0; } wchar_t *ConvertName(const word* in_data, int off_start, int off_end) { static wchar_t ret_val[255]; int loop, loop1, last_space = 0; for (loop = off_start, loop1 = 0; loop <= off_end; loop++) { ret_val [loop1++] = (char) (in_data [loop] / 256); /* Get High byte */ ret_val [loop1++] = (char) (in_data [loop] % 256); /* Get Low byte */ } for (loop1--; loop1 >= 0 && ret_val[loop1] == ' '; loop1--) ; ret_val[loop1 + 1] = '\0'; /* Make sure it ends in a NULL character */ return ret_val; } #pragma pack(push, 1) struct partition_t { byte bBoot; byte bStartHead; byte bStartSector; byte bStartCylinder; byte bSystem; byte bEndHead; byte bEndSector; byte bEndCylinder; dword dwStartSector; dword dwSectorCount; }; #pragma pack(pop) const wchar_t* part_type(int type) { switch (type) { case 0x00: return L"FDISK_TYPE_EMPTY"; case 0x01: return L"FDISK_TYPE_FAT12"; case 0x04: return L"FDISK_TYPE_FAT16_SMALL"; case 0x05: return L"FDISK_TYPE_EXTENDED"; case 0x06: return L"FDISK_TYPE_FAT16_BIG"; //case 0x07: case 0x0C: return L"FDISK_TYPE_FAT32"; case 0x0F: return L"FDISK_TYPE_NTFS"; case 0x82: return L"FDISK_TYPE_LINUX_SWAP"; case 0x83: return L"FDISK_TYPE_EXT2"; case 0xa5: return L"FDISK_TYPE_FREEBSD"; case 0xa6: return L"FDISK_TYPE_OPENBSD"; case 0xeb: return L"FDISK_TYPE_BFS"; default: return L"unknown"; } } void ataDetect() { word dd[256]; int dd_off, i, j; word ports[4] = { 0x1F0, 0x1F0, 0x170, 0x170 }; byte units[4] = { 0xA0, 0xB0, 0xA0, 0xB0 }; word irqs[4] = { 0x4000, 0x4000, 0x8000, 0x8000 }; dword end; bool fail = false; byte stat; CAtaDrive *drive, *partdrive; wchar_t str[10]; partition_t *parts; sysRegisterIrq(14, AtaIrq, NULL); sysRegisterIrq(15, AtaIrq, NULL); parts = (partition_t*) (dd + 0xdf); for (i = 0; i < 4; i++) /* Loop through drives */ { wprintf(L"Detecting drive %d...\n", i); if (units[i] == 0xA0) { out(ports[i] + ATA_REG_DEVCTRL, 0x06); nsleep(400); /* release soft reset AND enable interrupts from drive */ out(ports[i] + ATA_REG_DEVCTRL, 0x00); nsleep(400); /* wait up to 2 seconds for status = BUSY=0 READY=1 DF=? DSC=? DRQ=? CORR=? IDX=? ERR=0 */ end = sysUpTime() + 5000; fail = false; while (((stat = in(ports[i] + 7)) & 0xC1) != 0x40) { if (sysUpTime() >= end) { fail = true; break; } } if (fail) { wprintf(L"stat = %x, no master detected\n", stat); i++; // Skip slave as well continue; } } fail = false; // Get IDE Drive info //_interrupt_occurred = 0; //end = sysUpTime() + 2000; //while (/*(_interrupt_occurred & irqs[i]) == 0 &&*/ //((stat = in(ports[i] + 7)) & ATA_READY) == 0) /*{ //putwchar('.'); //wprintf(L"%d %d\r", sysUpTime(), end); if (sysUpTime() >= end) { fail = true; break; } } if (fail) { wprintf(L"%d: Drive isn't ready (stat = %x), trying anyway\n", i, stat); //continue; }*/ end = sysUpTime() + 2000; while ((stat = in(ports[i] + ATA_REG_STATUS) & ATA_BUSY)) { if (sysUpTime() >= end) { fail = true; break; } } if (fail) { wprintf(L"stat=%x: fail on wait BUSY = 0\n", stat); continue; } //_interrupt_occurred = 0; out(ports[i] + 6, units[i]); // Get first/second drive end = sysUpTime() + 2000; while (((stat = in(ports[i] + ATA_REG_STATUS) & ATA_READY) == 0)) { if (sysUpTime() >= end) { fail = true; break; } } if (fail) { wprintf(L"stat=%x: fail on wait READY = 1\n", stat); continue; } out(ports[i] + 7, ATA_CMD_ID); // Get drive info data end = sysUpTime() + 2000; while (((stat = in(ports[i] + ATA_REG_STATUS) & ATA_DRQ) == 0)) { if ((stat & ATA_ERR) || sysUpTime() >= end) { fail = true; break; } } /*end = sysUpTime() + 2000; fail = false; while (!_interrupt_occurred) { if (sysUpTime() >= end) { fail = true; break; } } if (fail) { _cputws(L"not present\n"); continue; }*/ /* Wait for data ready */ /* was ATA_READY | ATA_DSC | ATA_DRQ 58 */ //while ((stat = in(ports[i] + 7)) != (ATA_READY | ATA_DSC)) //while (//!_interrupt_occurred && //(stat = in(ports[i] + 7)) != (ATA_READY | ATA_DSC | ATA_DRQ)) //while (/*(_interrupt_occurred & irqs[i]) == 0 &&*/ /* ((stat = in(ports[i] + 7)) & ATA_DRQ) == 0) { if (sysUpTime() >= end) { fail = true; break; } }*/ //if (((stat = in(ports[i] + 7)) & ATA_DRQ) == 0) if (fail) { wprintf(L"stat = %x, ATAPI? ", stat); _interrupt_occurred = 0; out(ports[i] + 7, ATA_CMD_PID); /* Get ATAPI drive info data */ end = sysUpTime() + 2000; fail = false; /* Wait for data ready */ //while ((stat = in(ports[i] + 7)) != (ATA_READY | ATA_DSC)) while ((_interrupt_occurred & irqs[i]) == 0 && ((stat = in(ports[i] + 7)) & ATA_DRQ) == 0) { if (sysUpTime() >= end) { fail = true; break; } } if (fail) { wprintf(L"stat = %x, not present\n", stat); continue; } } for (dd_off = 0; dd_off != 256; dd_off++) /* Read "sector" */ dd[dd_off] = in16(ports[i]); /*wprintf(L"Model Number______________________: %s\n", ConvertName(dd, 27, 46)); wprintf(L"Serial Number_____________________: %s\n", ConvertName(dd, 10, 19)); wprintf(L"Controller Revision Number________: %s\n\n", ConvertName(dd, 23, 26)); wprintf(L"Able to do Double Word Transfer___: %6s\n", (dd [48] == 0 ? L"No" : L"Yes")); wprintf(L"Controller type___________________: %04X\n", dd [20]); wprintf(L"Controller buffer size (bytes)____: %6u\n", dd [21] * 512); wprintf(L"Number of ECC bytes transferred___: %6u\n", dd [22]); wprintf(L"Number of sectors per interrupt___: %6u\n\n", dd [47]); wprintf(L"Number of Cylinders (Fixed)_______: %6u\n", dd [1]); wprintf(L"Number of Heads___________________: %6u\n", dd [3]); wprintf(L"Number of Sectors per Track_______: %6u\n\n", dd [6]);*/ drive = new CAtaDrive; drive->m_port = ports[i]; drive->m_irq = irqs[i]; drive->m_unit = units[i]; drive->m_cylinders = dd[1]; drive->m_heads = dd[3]; drive->m_sectors = dd[6]; drive->m_start_sector = 0; drive->m_total_sectors = drive->m_sectors * drive->m_heads * drive->m_cylinders; if (((dd[119] & 1) != 0) && (dd[118] != 0)) drive->m_mult_max = dd[94]; else drive->m_mult_max = 1; wcscpy(drive->m_name, ConvertName(dd, 27, 46)); wcscat(drive->m_name, L" "); wcscat(drive->m_name, ConvertName(dd, 10, 19)); swprintf(str, L"ide%d", i); sysExtRegisterDevice(str, drive); wprintf(L"Registered %s => %s [ ", str, drive->m_name); if (drive->BlockRead(0, 1, dd)) { for (j = 0; j < 4; j++) { word c, h, s; c = parts[j].bStartCylinder | ((word) parts[j].bStartSector & 0xc0) << 2; h = parts[j].bStartHead; s = parts[j].bStartSector & 0x3f; if (parts[j].bSystem) { /*wprintf(L"CHS\t%d:%d:%d\t" L"System\t%x (%s)\t" L"Start\t%d\t", c, h, s, parts[j].bSystem, part_type(parts[j].bSystem), parts[j].dwStartSector); wprintf(L"Size\t"); kb = parts[j].dwSectorCount / 2; if (kb > 1048576) wprintf(L"%d Mb\n", kb / 1024); else wprintf(L"%d Kb\n", kb);*/ partdrive = new CAtaDrive; *partdrive = *drive; partdrive->m_start_sector = parts[j].dwStartSector; /*partdrive->m_start_sector = s + h * partdrive->m_sectors + c * partdrive->m_heads;*/ partdrive->m_total_sectors = parts[j].dwSectorCount; swprintf(str, L"ide%d%c", i, j + 'a'); sysExtRegisterDevice(str, partdrive); //wprintf(L"%c ", j + 'a'); wprintf(L"%s ", part_type(parts[j].bSystem)); /*if (partdrive->BlockRead(0, 2, buf) == 2) DumpBootSector(buf);*/ } } } _cputws(L"]\n"); //_wgetch(); } wprintf(L"Finished detection!\n"); //for (;;) ; }