/* ATA.c - This file is a part of NutsOS * * NutsOS * Copyright (C) 2013 Free Software Foundation, Inc. * * NutsOS is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * NutsOS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with NutsOS; If not, see . * * Valentin Verdier */ #include "../types.h" #include "../kernLdr.h" #include "ATA.h" int ATA_getDevice(unsigned int ataNumber, unsigned int drive, T_ATA_device* dev) { ataNumber &= 0x3; drive &= 0x1; print("-> Device : ATA %d ", DEFAULT_COLOR, ataNumber); switch(ataNumber) { case 0: dev->ata_port = ATA_0_PORT; dev->ata_ctrl_port = ATA_0_CTRL_PORT; break; case 1: dev->ata_port = ATA_1_PORT; dev->ata_ctrl_port = ATA_1_CTRL_PORT; break; case 2: dev->ata_port = ATA_2_PORT; dev->ata_ctrl_port = ATA_2_CTRL_PORT; break; case 3: dev->ata_port = ATA_3_PORT; dev->ata_ctrl_port = ATA_3_CTRL_PORT; break; } if(drive) { print("Slave drive\n", DEFAULT_COLOR); dev->drive = ATA_SLAVE; } else { print("Master drive\n", DEFAULT_COLOR); dev->drive = ATA_MASTER; } /* On vérifie si les ports I/O sont reliés à un contrôleur */ T_byte testByte; _out(dev->ata_port + 2, 0x45); _in(dev->ata_port + 2, &testByte); if(testByte == 0x45) { /* Le contrôleur éxiste */ T_byte a, b, status; /* On se prépare à utiliser la commande IDENTIFY pour connaitre le type de disque ATA */ _out(dev->ata_port + 6, ATA_CHS_MODE | dev->drive); /* On selectionne le disque */ delay(1000); _out(dev->ata_port + 2, 0); _out(dev->ata_port + 3, 0); _out(dev->ata_port + 4, 0); _out(dev->ata_port + 5, 0); _out(dev->ata_port + 7, ATA_CMD_IDENTIFY); /* envoie de la commande */ _in(dev->ata_port + 7, &status); if(status == 0) { /* Si le status est à 0, il n'y à pas de disque */ print("-> ERROR : Drive doesn't exist !\n", DEFAULT_COLOR); return 0; } else { /* Sinon on attend que le disque soit prêt */ while(status & 0x80) { _in(dev->ata_port + 7, &status); } } /* On récupère les octets de signature */ _in(dev->ata_port + 4, &a); _in(dev->ata_port + 5, &b); if((a == 0) && (b == 0)) { /* Disque dur ATA */ while(!(status & 0x08)) { /* On attend que le disque soit prêt pour la lecture des données d'identification */ _in(dev->ata_port + 7, &status); } unsigned int i; T_word trash; for(i = 0; i < 256; i++) { /* Pas besoin des info d'identification, mais on les transfert pour que le contrôleur termine la commande normalement */ _inw(dev->ata_port, &trash); } return 1; } else { print("-> ERROR : Drive is not ATA !\n", DEFAULT_COLOR); } } else { print("-> ERROR : Controller doesn't exist !\n", DEFAULT_COLOR); } return 0; } void ATA_read(T_ATA_device dev, T_dword baseLBA, T_byte sectorCount, void* baddr) { T_byte* buffer = baddr; T_byte status = 0; unsigned int i, j; T_word word; _out(dev.ata_port + 1, 0); /* Octet nul */ _out(dev.ata_port + 2, sectorCount); _out(dev.ata_port + 3, (T_byte) (baseLBA & 0xFF)); /* 8 bits de poids faible de l'adresse LBA */ _out(dev.ata_port + 4, (T_byte) ((baseLBA >> 8) & 0xFF)); _out(dev.ata_port + 5, (T_byte) ((baseLBA >> 16) & 0xFF)); _out(dev.ata_port + 6, ATA_LBA_MODE | dev.drive | ((baseLBA >> 24) & 0x0F)); for(i = 0; i < 4; i++) { _in(dev.ata_port + 7, &status); } _out(dev.ata_port + 7, ATA_CMD_READ); /* On attend que le contrôleur soit prêt */ for(i = 0; i < sectorCount; i++) { do { _in(dev.ata_port + 7, &status); }while((status & 0x80) || !(status & 0x08)); for(j = 0; j < 256; j++) { _inw(dev.ata_port, &word); buffer[(i * 512) + (j * 2)] = (T_byte) (word & 0xFF); buffer[(i * 512) + (j * 2) + 1] = (T_byte) ((word >> 8) & 0xFF); } } }