Commit 39b7e092 authored by svn-freakypenguin's avatar svn-freakypenguin
Browse files

! cdi.storage: Position in der Datei beim Lesen und Schreiben aktualisieren

+ cdi.ata: Anfaenge eines ATA(PI) Treibers



git-svn-id: svn+ssh://overgames.de/lost/trunk@685 1fb02b30-9e10-0410-89f7-8f5a202ca6a9
No related merge requests found
Showing with 18593 additions and 0 deletions
+18593 -0
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "cdi.h"
#include "cdi/storage.h"
#include "cdi/misc.h"
#include "cdi/io.h"
#include "device.h"
/**
* Resultat beim IDENTIFY DEVICE Befehl
*/
struct ata_identfiy_data {
struct {
uint8_t : 7;
uint8_t removable : 1;
uint8_t : 7;
uint8_t ata : 1;
} __attribute__((packed)) general_config;
uint16_t log_cyl; // Veraltet
uint16_t : 16;
uint16_t log_heads; // Veraltet
uint16_t : 16;
uint16_t : 16;
uint16_t log_spt; // Veraltet
uint16_t : 16;
// 8
uint16_t : 16;
uint16_t : 16;
char serial_number[20];
// 20
uint16_t : 16;
uint16_t : 16;
uint16_t : 16;
char firmware_revision[8];
// 27
char model_number[40];
uint8_t : 8; // Immer 0x80
uint8_t max_sec_per_irq;
// 48
uint16_t : 16;
struct {
uint16_t : 8;
uint8_t dma : 1;
uint8_t lba : 1;
uint8_t iordy_disabled : 1;
uint8_t irdy_supported : 1;
uint8_t : 1;
uint8_t : 1; // Irgendwas mit Standbytimer
uint8_t : 2;
} __attribute__((packed)) capabilities;
uint16_t : 16; // Noch ein paar Faehigkeiten,
// die wir aber sicher nicht
// brauchen
uint8_t : 8;
uint8_t pio_mode_number;
uint16_t : 16;
struct {
uint8_t current_chs : 1; // Words 54-56
uint8_t transfer_settings : 1; // Words 64-70
uint8_t ultra_dma : 1; // Word 88
uint16_t : 13;
} __attribute__((packed)) valid_words;
uint16_t cur_log_cyl; // Veraltet
uint16_t cur_log_heads; // Veraltet
// 56
uint16_t cur_log_spt; // Veraltet
uint16_t chs_capacity[2]; // Veraltet
struct {
uint8_t cur_sec_per_int : 8;
uint8_t setting_valid : 1;
uint8_t : 7;
} __attribute__((packed)) multi_sector;
uint32_t lba_sector_count; // LBA28
uint16_t : 16;
struct {
uint8_t : 1;
uint8_t mode0_supported : 1;
uint8_t mode1_supported : 1;
uint8_t mode2_supported : 1;
uint8_t : 4;
uint8_t mode0_selected : 1;
uint8_t mode1_selected : 1;
uint8_t mode2_selected : 1;
uint8_t : 5;
} __attribute__((packed)) multiword_dma;
// 64
uint8_t pio_modes_supported;
uint8_t : 8;
// Multiword dma Zeiten
uint16_t mwd_time1;
uint16_t mwd_time2;
uint16_t mwd_time3;
uint16_t mwd_time4;
uint16_t : 16;
uint16_t : 16;
uint16_t : 16;
// 72
uint16_t : 16;
uint16_t : 16;
uint16_t : 16;
struct {
uint8_t max_depth : 5;
uint16_t : 11;
} __attribute__((packed)) queue_depth;
uint16_t : 16;
uint16_t : 16;
uint16_t : 16;
uint16_t : 16;
// 80
union {
uint16_t raw;
struct {
uint8_t : 1;
uint8_t ata1 : 1;
uint8_t ata2 : 1;
uint8_t ata3 : 1;
uint8_t ata4 : 1;
uint8_t ata5 : 1;
uint8_t ata6 : 1;
uint8_t ata7 : 1;
uint16_t : 8;
} __attribute__((packed)) bits;
} major_version;
uint16_t minor_version;
union {
uint16_t raw[2];
struct {
// Word 82
uint8_t smart : 1;
uint8_t security_mode : 1;
uint8_t removable_media : 1;
uint8_t power_management : 1;
uint8_t packet : 1;
uint8_t write_cache : 1;
uint8_t look_ahead : 1;
uint8_t release_int : 1;
uint8_t service_int : 1;
uint8_t device_reset : 1;
uint8_t hpa : 1; // Host protected area
uint8_t : 1;
uint8_t write_buffer : 1;
uint8_t read_buffer : 1;
uint8_t nop : 1;
uint8_t : 1;
// Word 83
uint8_t download_microcode : 1;
uint8_t rw_dma_queued : 1;
uint8_t cfa : 1;
uint8_t apm : 1; // Advanced power management
uint8_t removable_media_sn : 1; // R. Media Status notification
uint8_t power_up_standby : 1;
uint8_t set_features_spinup : 1;
uint8_t : 1;
uint8_t set_max_security : 1;
uint8_t auto_acoustic_mngmnt: 1; // Automatic acoustic management
uint8_t lba48 : 1;
uint8_t dev_config_overlay : 1;
uint8_t flush_cache : 1;
uint8_t flush_cache_ext : 1;
uint8_t : 2;
} __attribute__((packed)) bits;
} features_support;
// 83
uint16_t todo[17];
// 100
uint64_t max_lba48_address;
// 107
uint16_t todo2[153];
} __attribute__((packed));
/**
* ATA-Geraet identifizieren
*
* @return 0 Wenn das Geraet erfolgreich identifiziert wurde, != 0 sonst
*/
int ata_drv_identify(struct ata_device* dev)
{
struct ata_identfiy_data id;
// Request vorbereiten
struct ata_request request = {
.dev = dev,
.flags.direction = READ,
.flags.poll = 1,
.flags.lba = 0,
// Die Identifikationsdaten werden ueber PIO DATA IN gelesen
.protocol = PIO,
.registers.ata.command = IDENTIFY_DEVICE,
.block_count = 1,
.block_size = ATA_SECTOR_SIZE,
.buffer = &id,
.error = 0
};
// Request starten
if (!ata_request(&request)) {
// Wenn ein Fehler aufgetreten ist, koennen wir es noch mit einem
// IDENTIFY PACKET DEVICE probieren.
return atapi_drv_identify(dev);
}
// Pruefen, welche LBA-Modi dabei sind
if (id.features_support.bits.lba48) {
dev->lba48 = 1;
dev->storage.block_count = id.max_lba48_address;
}
if (id.capabilities.lba) {
dev->lba28 = 1;
if (!dev->lba48) {
dev->storage.block_count = id.lba_sector_count;
}
}
// Wenn keiner der LBA-Modi unterstuetzt wird, muss abgebrochen werden, da
// CHS noch nicht implementiert ist.
if (!dev->lba48 && !dev->lba28) {
printf("ata: Geraet unterstuetzt nur CHS.\n");
return 0;
}
// Ein ATA-Geraet
dev->atapi = 0;
return 1;
}
/**
* Sektoren von einem ATA-Geraet lesen oder darauf schreiben
*
* @param direction 0 fuer lesen, 1 fuer schreiben
* @param start LBA des Startsektors
* @param count Anzahl der Sektoren
* @param buffer Pointer auf den Puffer in dem die Daten abgelegt werden
* sollen, respektiv aus dem sie gelesen werden sollen.
*
* @return 1 wenn die Blocks erfolgreich gelesen/geschrieben wurden, 0 sonst
*/
static int ata_drv_rw_sectors(struct ata_device* dev, int direction,
uint64_t start, size_t count, void* buffer)
{
int result = 1;
struct ata_request request;
// Da nicht mehr als 256 Sektoren auf einmal gelesen/geschrieben werden
// koennen, muss unter Umstaenden mehrmals gelesen/geschrieben werden.
uint16_t current_count;
void* current_buffer = buffer;
uint64_t lba = start;
// Anzahl der Sektoren die noch uebrig sind
size_t count_left = count;
// Solange wie noch Sektoren uebrig sind, wird gelesen
while (count_left > 0) {
// Entscheiden wieviele Sektoren im aktuellen Durchlauf gelesen werden
if (count_left > 256) {
current_count = 256;
} else {
current_count = count_left;
}
// Request vorbereiten
request.dev = dev;
// TODO: DMA, UltraDMA...
request.protocol = PIO;
// FIXME
request.flags.poll = 1;
request.flags.ata = 0;
request.flags.lba = 1;
// Richtung festlegen
if (direction == 0) {
request.flags.direction = READ;
request.registers.ata.command = READ_SECTORS;
} else {
request.flags.direction = WRITE;
request.registers.ata.command = WRITE_SECTORS;
}
// Achtung: Beim casten nach uint8_t wird bei 256 Sektoren eine 0.
// Das macht aber nichts, da in der Spezifikation festgelegt ist,
// dass 256 Sektoren gelesen werden sollen, wenn im count-Register
// 0 steht.
request.registers.ata.count = (uint8_t) current_count;
request.registers.ata.lba = lba;
request.block_count = current_count;
request.block_size = ATA_SECTOR_SIZE;
request.blocks_done = 0;
request.buffer = current_buffer;
request.error = NO_ERROR;
// TODO: LBA48
// TODO: CHS
// Request ausfuehren
if (!ata_request(&request)) {
result = 0;
break;
}
// Pufferpointer und Anzahl der uebrigen Blocks anpassen
current_buffer += current_count * ATA_SECTOR_SIZE;
count_left -= current_count;
lba += current_count;
}
return result;
}
/**
* Sektoren von einem ATA-Geraet lesen
*
* @param start LBA des Startsektors
* @param count Anzahl der Sektoren
* @param buffer Pointer auf den Puffer in dem die Daten abgelegt werden sollen
*
* @return 1 wenn die Blocks erfolgreich gelesen wurden, 0 sonst
*/
int ata_drv_read_sectors(struct ata_device* dev, uint64_t start, size_t count,
void* buffer)
{
return ata_drv_rw_sectors(dev, 0, start, count, buffer);
}
/**
* Sektoren auf eine ATA-Geraet schreiben
*
* @param start LBA des Startsektors
* @param count Anzahl der Sektoren
* @param buffer Pointer auf den Puffer aus dem die Daten gelesen werden sollen
*
* @return 1 wenn die Blocks erfolgreich geschrieben wurden, 0 sonst
*/
int ata_drv_write_sectors(struct ata_device* dev, uint64_t start, size_t count,
void* buffer)
{
return ata_drv_rw_sectors(dev, 1, start, count, buffer);
}
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "cdi.h"
#include "cdi/storage.h"
#include "cdi/misc.h"
#include "cdi/io.h"
#include "device.h"
/**
* ATAPI-Geraet identifizieren
*
* @return 0 Wenn das Geraet erfolgreich identifiziert wurde, != 0 sonst
*/
int atapi_drv_identify(struct ata_device* dev)
{
uint8_t buffer[ATA_SECTOR_SIZE];
// Request vorbereiten
struct ata_request request = {
.dev = dev,
.flags.direction = READ,
.flags.poll = 1,
.flags.lba = 0,
// Die Identifikationsdaten werden ueber PIO DATA IN gelesen
.protocol = PIO,
.registers.ata.command = IDENTIFY_PACKET_DEVICE,
.block_count = 1,
.block_size = ATA_SECTOR_SIZE,
.buffer = buffer,
.error = 0
};
// Request starten
if (!ata_request(&request)) {
// Pech gehabt
return 0;
}
// Es handelt sich um ein ATAPI-Geraet
dev->atapi = 1;
// TODO: Informationen verarbeiten
return 1;
}
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "cdi.h"
#include "cdi/storage.h"
#include "cdi/misc.h"
#include "cdi/io.h"
#include "device.h"
#include "libpartition.h"
#define MAX(a, b) (a > b ? a : b)
// IRQ-Handler
static inline void ata_controller_irq(struct cdi_device* dev);
/**
* Diese Funktion prueft, ob der Bus leer ist. Denn wenn der Bus leer ist, wird
* jeder Versuch das Status-Register zu lesen 0xFF zurueck geben, was ein
* ungueltiger Wert ist. Das haengt damit zusammen, dass der Bus mit
* Pullup-Widerstaenden auf hohem Pegel gehalten wird, wenn keine Geraete
* angeschlossen sind.
*
* @return 1 wenn der Bus leer ist, 0 sonst
*/
static int ata_bus_floating(struct ata_controller* controller)
{
uint8_t status;
// Master auswaehlen und Status auslesen
ata_reg_outb(controller, REG_DEVICE, DEVICE_DEV(0));
ATA_DELAY();
status = ata_reg_inb(controller, REG_STATUS);
// Wenn alle Bits gesetzt sind, ist der Bus floating
return (status == 0xFF);
}
/**
* Diese Funktion prueft, ob mindestens ein Antwortendes Geraet am Bus haengt.
* Das laesst sich herausfinden, indem irgendwelche Werte in die LBA-Register
* geschrieben werden. Wenn ein Geraet vorhanden ist, muessen die Werte wieder
* ausgelesen werden koennen.
*
* @return 1 wenn ein Geraet vorhanden ist, 0 sonst
*/
static bool ata_bus_responsive_drv(struct ata_controller* controller)
{
// Slave auswaehlen, da so sicher jemand reagiert, da der Master antworten
// muss, wenn kein Slave existiert. So sieht es zumindest in der Theorie
// aus. In der Praxis scheint vmware das nicht so zu machen. Deshalb drehen
// wir weiter unten noch eine Sonderrunde fuer vmware. ;-)
ata_reg_outb(controller, REG_DEVICE, DEVICE_DEV(1));
ATA_DELAY();
// Jetzt wird irgendwas auf die Ports geschrieben. Die Werte sind absolut
// egal, solange das selbe beim auslesen zurueckkommt ist gut.
ata_reg_outb(controller, REG_LBA_LOW, 0xAF);
ata_reg_outb(controller, REG_LBA_MID, 0xBF);
ata_reg_outb(controller, REG_LBA_HIG, 0xCF);
// Wenn die ausgelesenen Werte stimmen ist mindestens ein Geraet vorhanden
if ((ata_reg_inb(controller, REG_LBA_LOW) == 0xAF) &&
(ata_reg_inb(controller, REG_LBA_MID) == 0xBF) &&
(ata_reg_inb(controller, REG_LBA_HIG) == 0xCF))
{
return 1;
}
// Hier noch die kleine Ehrenrunde fuer vmware ;-)
ata_reg_outb(controller, REG_DEVICE, DEVICE_DEV(0));
ATA_DELAY();
// Jetzt wird irgendwas auf die Ports geschrieben. Die Werte sind absolut
// egal, solange das selbe beim auslesen zurueckkommt ist gut.
ata_reg_outb(controller, REG_LBA_LOW, 0xAF);
ata_reg_outb(controller, REG_LBA_MID, 0xBF);
ata_reg_outb(controller, REG_LBA_HIG, 0xCF);
// Wenn die ausgelesenen Werte stimmen ist mindestens ein Geraet vorhanden
if ((ata_reg_inb(controller, REG_LBA_LOW) == 0xAF) &&
(ata_reg_inb(controller, REG_LBA_MID) == 0xBF) &&
(ata_reg_inb(controller, REG_LBA_HIG) == 0xCF))
{
return 1;
}
return 0;
}
/**
* IRQ-Handler fuer ATA-Controller
*
* @param dev Achtung hier handelt es sich um kein echtes Geraet!!! Das wurde
* nur zum Registrieren des Handlers angelegt.
*/
static void ata_controller_irq(struct cdi_device* dev)
{
struct ata_device* ata_dev = (struct ata_device*) dev;
struct ata_controller* ctrl = ata_dev->controller;
ctrl->irq_cnt++;
}
/**
* Auf einen IRQ warten
*
* @param timeout Timeout nachdem die Funktion abbricht
*
* @return 1 Wenn der IRQ wie erwartet aufgetreten ist, 0 sonst
*/
int ata_wait_irq(struct ata_controller* controller, uint32_t timeout)
{
uint32_t time = 0;
// Warten bis der IRQ-Zaehler vom Handler erhoeht wird
while (controller->irq_cnt == 0) {
cdi_sleep_ms(20);
time += 20;
if (timeout <= time) {
return 0;
}
}
return 1;
}
/**
* Partitionstabelle auf einem ATA-Geraet verarbeiten
*/
void ata_parse_partitions(struct ata_device* dev)
{
struct partition_table partition_table;
uint8_t mbr[ATA_SECTOR_SIZE];
int i;
// Die Partitionstabelle liegt im MBR
if (!dev->read_sectors(dev, 0, 1, mbr)) {
printf("ata: Fehler beim Einlesen der Partitionstabelle");
return;
}
// Partitionstabelle Verarbeiten
if (!partition_table_fill(&partition_table, mbr)) {
printf("ata: Fehler beim Verarbeiten der Partitionstabelle");
return;
}
// Ansonsten wird die Tabelle jetzt verarbeitet
for (i = 0; i < 4; i++) {
if (partition_table.entries[i].used) {
// Erweiterter Eintrag => ueberspringen
if (partition_table.entries[i].type == PARTITION_TYPE_EXTENDED) {
printf("ata: TODO Erweiterte Partitionstabelleneintraege\n");
continue;
}
struct ata_partition* partition = malloc(sizeof(*partition));
partition->dev = dev;
partition->null = NULL;
partition->start = partition_table.entries[i].start;
partition->storage.block_size = ATA_SECTOR_SIZE;
partition->storage.block_count = partition_table.entries[i].size;
printf("ata: Partition von %d bis %d\n", partition->start, partition->storage.block_count + partition->start - 1);
asprintf((char**) &(partition->storage.dev.name), "ata%01d%01d_p%01d",
(uint32_t) dev->controller->id, dev->id, cdi_list_size(dev->
partition_list));
// Geraet registrieren
cdi_list_push(dev->controller->driver->drv.devices, partition);
// An Partitionsliste fuer das aktuelle Geraet anhaengen
cdi_list_push(dev->partition_list, partition);
}
}
}
/**
* ATA-Geraet initialisieren
*/
void ata_init_controller(struct ata_controller* controller)
{
int i;
// Ports registrieren
if (cdi_ioports_alloc(controller->port_cmd_base, 8) != 0) {
printf("ata: Fehler beim allozieren der I/O-Ports\n");
return;
}
if (cdi_ioports_alloc(controller->port_ctl_base, 1) != 0) {
printf("ata: Fehler beim allozieren der I/O-Ports\n");
cdi_ioports_free(controller->port_cmd_base, 8);
return;
}
// Da NIEN nicht ueberall sauber funktioniert, muss jetzt trotzdem schon
// ein IRQ-Handler registriert werden. Und dafuer brauchen wir nun mal ein
// Geraet.
controller->irq_dev.controller = controller;
cdi_register_irq(controller->irq, ata_controller_irq, (struct cdi_device*)
&controller->irq_dev);
// Laut osdev-Forum sollte das HOB-Bit fuer alle Geraete geloescht werden,
// da noch nicht sicher ist, ob diese LBA48 unterstuetzen. Gleichzeitig
// werden auch noch interrupts deaktiviert, da die erst benutzt werden
// koennen, wenn feststeht, welche geraete existieren.
//
// ACHTUNG: NIEN scheint nicht ueberall zu funktionieren!! Auf einem meiner
// Testrechner kommen da Trotzdem Interrupts.
for (i = 0; i < 2; i++) {
// Geraet auswaehlen
ata_reg_outb(controller, REG_DEVICE, DEVICE_DEV(i));
ATA_DELAY();
// HOB loeschen und NIEN setzen
ata_reg_outb(controller, REG_CONTROL, CONTROL_NIEN);
}
// Jetzt pruefen wir ob der Bus leer ist (mehr dazu bei ata_bus_floating).
if (ata_bus_floating(controller)) {
printf("ata: Floating Bus %d\n", controller->id);
return;
}
// Testen ob mindestens ein antwortendes Geraet am Bus haengt. Hier muss
// darauf geachtet werden, dass der Master auch antworten muss, wenn zwar
// der Slave ausgewaehlt ist, aber nicht existiert.
if (!ata_bus_responsive_drv(controller)) {
printf("ata: No responsive drive on Bus %d\n", controller->id);
return;
}
// Jetzt werden die einzelnen geraete identifiziert. Hier ist es
// anscheinend geschickter mit dem Slave zu beginnen.
for (i = 1; i >= 0; i--) {
struct ata_device* dev = malloc(sizeof(*dev));
dev->controller = controller;
dev->id = i;
dev->storage.block_size = ATA_SECTOR_SIZE;
dev->partition_list = cdi_list_create();
if (ata_drv_identify(dev)) {
printf("Bus %d Device %d: ATAPI=%d\n", (uint32_t) controller->id, i, dev->atapi);
if (dev->atapi == 0) {
// Handler setzen
dev->read_sectors = ata_drv_read_sectors;
dev->write_sectors = ata_drv_write_sectors;
// Name setzen
asprintf((char**) &(dev->storage.dev.name), "ata%01d%01d",
(uint32_t) controller->id, i);
// Partitionen parsen
ata_parse_partitions(dev);
} else {
// Name setzen
asprintf((char**) &(dev->storage.dev.name), "atapi%01d%01d",
(uint32_t) controller->id, i);
}
// Geraet registrieren
cdi_list_push(controller->driver->drv.devices, dev);
} else {
free(dev);
}
}
}
void ata_remove_controller(struct ata_controller* controller)
{
}
void ata_init_device(struct cdi_device* device)
{
}
void ata_remove_device(struct cdi_device* device)
{
}
/**
* Blocks von einem ATA(PI) Geraet lesen
*/
int ata_read_blocks(struct cdi_storage_device* device, uint64_t block,
uint64_t count, void* buffer)
{
struct ata_device* dev = (struct ata_device*) device;
struct ata_partition* partition = NULL;
// Wenn der Pointer auf den Controller NULL ist, handelt es sich um eine
// Partition
if (dev->controller == NULL) {
partition = (struct ata_partition*) dev;
dev = partition->dev;
}
// Natuerlich nur ausfuehren wenn ein Handler eingetragen ist
if (dev->read_sectors == NULL) {
return -1;
}
// Bei einer Partition noch den Offset dazurechnen
if (partition == NULL) {
return !dev->read_sectors(dev, block, count, buffer);
} else {
return !dev->read_sectors(dev, block + partition->start, count,
buffer);
}
}
/**
* Blocks auf ein ATA(PI) Geraet schreiben
*/
int ata_write_blocks(struct cdi_storage_device* device, uint64_t block,
uint64_t count, void* buffer)
{
struct ata_device* dev = (struct ata_device*) device;
struct ata_partition* partition = NULL;
// Wenn der Pointer auf den Controller NULL ist, handelt es sich um eine
// Partition
if (dev->controller == NULL) {
partition = (struct ata_partition*) dev;
dev = partition->dev;
}
// Natuerlich nur ausfuehren wenn ein Handler eingetragen ist
if (dev->write_sectors == NULL) {
return -1;
}
// Bei einer Partition muss noch ein Offset drauf addiert werden
if (partition == NULL) {
return !dev->write_sectors(dev, block, count, buffer);
} else {
return !dev->write_sectors(dev, block + partition->start, count,
buffer);
}
}
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ATA_DEVICE_H_
#define _ATA_DEVICE_H_
#include <stdint.h>
#include "cdi.h"
#include "cdi/storage.h"
#include "cdi/io.h"
#include "cdi/lists.h"
#define ATA_PRIMARY_CMD_BASE 0x1F0
#define ATA_PRIMARY_CTL_BASE 0x3F6
#define ATA_PRIMARY_IRQ 14
#define ATA_SECONDARY_CMD_BASE 0x170
#define ATA_SECONDARY_CTL_BASE 0x376
#define ATA_SECONDARY_IRQ 15
#define ATA_DELAY()
// Hinweis: Worst Case nach ATA-Spec waeren 30 Sekunden
#define ATA_IDENTIFY_TIMEOUT 5000
// So lange wird gewartet, bis ein Geraet bereit ist, wenn ein Befehl
// ausgefuehrt werden soll
#define ATA_READY_TIMEOUT 500
// Timeout beim Warten auf einen IRQ
#define ATA_IRQ_TIMEOUT 500
// Normale Sektorgroesse
#define ATA_SECTOR_SIZE 512
// Diese Register werden ueber die port_cmd_base angesprochen
#define REG_DATA 0x0
#define REG_ERROR 0x1
#define REG_SEC_CNT 0x2
#define REG_LBA_LOW 0x3
#define REG_LBA_MID 0x4
#define REG_LBA_HIG 0x5
#define REG_DEVICE 0x6
#define REG_STATUS 0x7
#define REG_COMMAND 0x7
// Diese Register werden ueber port_ctl_base angesprochen. Das wird den
// Funktionen fuer den Registerzugriff mit den 0x10 mitgeteilt.
#define REG_CONTROL 0x10
#define REG_ALT_STATUS 0x10
// Device Register
#define DEVICE_DEV(x) (x << 4)
// Status Register
#define STATUS_BSY (1 << 7)
#define STATUS_DRDY (1 << 6)
#define STATUS_DF (1 << 5)
#define STATUS_DRQ (1 << 3)
#define STATUS_ERR (1 << 0)
#define STATUS_MASK (STATUS_BSY | STATUS_DRDY | STATUS_DF | \
STATUS_DRQ | STATUS_ERR)
// Befehle
#define COMMAND_IDENTIFY 0xEC
// Control Register
#define CONTROL_HOB (1 << 7)
#define CONTROL_SRST (1 << 2)
#define CONTROL_NIEN (1 << 1)
struct ata_partition {
struct cdi_storage_device storage;
// Muss auf NULL gesetzt werden
void* null;
struct ata_device* dev;
// Startsektor
uint32_t start;
};
struct ata_device {
struct cdi_storage_device storage;
// In der Partitionstruktur ist dieses Feld null, um Partitionen erkennen
// zu koennen.
struct ata_controller* controller;
// Liste mit den Partitionen
cdi_list_t partition_list;
uint8_t id;
// 1 wenn es sich um ein ATAPI-Gerat handelt, 0 sonst
uint8_t atapi;
// 1 Wenn das Geraet lba48 unterstuetzt
uint8_t lba48;
// 1 Wenn das Geraet lba28 unterstuetzt
uint8_t lba28;
// Funktionen fuer den Zugriff auf dieses Geraet
int (*read_sectors) (struct ata_device* dev, uint64_t start, size_t count,
void* dest);
int (*write_sectors) (struct ata_device* dev, uint64_t start,
size_t count, void* dest);
};
struct ata_controller {
struct cdi_storage_driver* driver;
uint8_t id;
uint16_t port_cmd_base;
uint16_t port_ctl_base;
uint16_t irq;
uint16_t irq_cnt;
// Wird auf 1 gesetzt wenn IRQs benutzt werden sollen, also das NIEN-Bit im
// Control register nicht aktiviert ist.
int irq_use;
// HACKKK ;-)
struct ata_device irq_dev;
};
struct ata_request {
struct ata_device* dev;
enum {
NON_DATA,
PIO
} protocol;
// Flags fuer die Uebertragung
struct {
enum {
READ,
WRITE
} direction;
// 1 fuer Polling; 0 fuer Interrupts
uint8_t poll;
// 1 fuer ATAPI; 0 fuer ata
uint8_t ata;
// 1 Wenn das LBA-Bit im Geraeteregister
uint8_t lba;
} flags;
union {
// Registersatz fuer ATA-Operationen
struct {
enum {
IDENTIFY_DEVICE = 0xEC,
IDENTIFY_PACKET_DEVICE = 0xA1,
READ_SECTORS = 0x20,
WRITE_SECTORS = 0x30
} command;
uint8_t count;
uint64_t lba;
} ata;
// Parameter fuer ATAPI-Operationen
struct {
} atapi;
} registers;
// Anzahl der Blocks die uebertragen werden sollen
uint16_t block_count;
// Groesse eines Blocks
uint16_t block_size;
// Anzahl der schon verarbeitetn Blocks
uint16_t blocks_done;
// Puffer in den die Daten geschrieben werden sollen/aus dem sie gelesen
// werden sollen.
void* buffer;
// Moegliche Fehler
enum {
NO_ERROR = 0,
DEVICE_READY_TIMEOUT,
IRQ_TIMEOUT
} error;
};
void ata_init_controller(struct ata_controller* controller);
void ata_remove_controller(struct ata_controller* controller);
void ata_init_device(struct cdi_device* device);
void ata_remove_device(struct cdi_device* device);
int ata_read_blocks(struct cdi_storage_device* device, uint64_t block,
uint64_t count, void* buffer);
int ata_write_blocks(struct cdi_storage_device* device, uint64_t block,
uint64_t count, void* buffer);
// Einen ATA-Request absenden und ausfuehren
int ata_request(struct ata_request* request);
// ATA-Funktionen
int ata_drv_identify(struct ata_device* dev);
int ata_drv_read_sectors(struct ata_device* dev, uint64_t start, size_t count,
void* buffer);
int ata_drv_write_sectors(struct ata_device* dev, uint64_t start, size_t count,
void* buffer);
// ATAPI-Funktionen
int atapi_drv_identify(struct ata_device* dev);
// Auf einen IRQ warten
int ata_wait_irq(struct ata_controller* controller, uint32_t timeout);
/**
* Basis fuer ein bestimmtes Register ausfindig machen
*/
static inline uint16_t ata_reg_base(struct ata_controller* controller,
uint8_t reg)
{
// Fuer alle Register die ueber die ctl_base angesprochen werden muessen
// setzen wir Bit 4.
if ((reg & 0x10) == 0) {
return controller->port_cmd_base;
} else {
return controller->port_ctl_base;
}
}
/**
* Byte aus Kontrollerregister lesen
*/
static inline uint8_t ata_reg_inb(struct ata_controller* controller,
uint8_t reg)
{
uint16_t base = ata_reg_base(controller, reg);
return cdi_inb(base + (reg & 0xF));
}
/**
* Byte in Kontrollerregister schreiben
*/
static inline void ata_reg_outb(struct ata_controller* controller,
uint8_t reg, uint8_t value)
{
uint16_t base = ata_reg_base(controller, reg);
cdi_outb(base + (reg & 0xF), value);
}
/**
* Word aus Kontrollerregister lesen
*/
static inline uint16_t ata_reg_inw(struct ata_controller* controller,
uint8_t reg)
{
uint16_t base = ata_reg_base(controller, reg);
return cdi_inw(base + (reg & 0xF));
}
/**
* Byte in Kontrollerregister schreiben
*/
static inline void ata_reg_outw(struct ata_controller* controller,
uint8_t reg, uint16_t value)
{
uint16_t base = ata_reg_base(controller, reg);
cdi_outw(base + (reg & 0xF), value);
}
/**
* Geraet auwaehlen
*/
static inline void ata_drv_select(struct ata_device* dev)
{
ata_reg_outb(dev->controller, REG_DEVICE, DEVICE_DEV(dev->id));
ATA_DELAY();
}
#endif
This diff is collapsed.
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libpartition.h"
#include <stdint.h>
/**
* Roher Partitionstabelleneintrag
*/
struct raw_entry {
uint8_t active;
uint8_t begin_chs[3];
uint8_t type;
uint8_t end_chs[3];
uint32_t start;
uint32_t size;
} PACKED;
/**
* Uebergebene Partitionstabelle anhand des Sektors fuellen
*
* @return 1 wenn die Tabelle erfolgreich gefuellt wurde, 0 sonst
*/
int partition_table_fill(struct partition_table* table, void* sector)
{
struct raw_entry* entry = (struct raw_entry*) (sector +
PARTITION_TABLE_OFFSET);
uint16_t* signature = sector + PARTITION_TABLE_SIG_OFFSET;
int i;
// Zuerst die Signatur pruefen, denn ohne die muss garnicht weiter gesucht
// werden.
if (*signature != PARTITION_TABLE_SIGNATURE) {
return 0;
}
// Wenn die Signatur existiert koennen die einzelnen Eintraege ausgelesen
// werden
for (i = 0; i < 4; i++) {
// Wenn 0 als Groesse eingetragen ist, ist der Eintrag unbenutzt
if (entry->size == 0) {
table->entries[i].used = 0;
} else {
table->entries[i].used = 1;
// Fuer erweiterte Partitionen wollen wir generell Typ 0x5, die
// anderen aus Windows und Linux werden deshalb ausgetauscht.
if ((entry->type == 0x0F) || (entry->type == 0x85)) {
table->entries[i].type = PARTITION_TYPE_EXTENDED;
} else {
table->entries[i].type = entry->type;
}
table->entries[i].start = entry->start;
table->entries[i].size = entry->size;
}
entry++;
}
return 1;
}
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LIBPARTITION_H_
#define _LIBPARTITION_H_
#include <stdint.h>
#define PACKED __attribute__((packed))
#define PARTITION_TABLE_OFFSET 446
#define PARTITION_TABLE_SIG_OFFSET 510;
#define PARTITION_TABLE_SIGNATURE 0xAA55
// Typ fuer eine Erweiterte Partition, deren Startsektor wieder eine
// Partitionstabelle beinhaltet.
#define PARTITION_TYPE_EXTENDED 0x05
struct partition {
uint8_t used;
uint8_t type;
uint32_t start;
uint32_t size;
};
struct partition_table {
struct partition entries[4];
};
// Fuellt die Angegebene Partitionstabelle anhand des uebergebenen Sektors auf
int partition_table_fill(struct partition_table* table, void* sector);
#endif // ifndef _LIBPARTITION_H_
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "cdi/storage.h"
#include "cdi/pci.h"
#include "cdi/lists.h"
#include "device.h"
struct ata_driver {
struct cdi_storage_driver storage;
};
static struct ata_driver driver;
static const char* driver_name = "ata";
static cdi_list_t controller_list = NULL;
static void ata_driver_init();
static void ata_driver_destroy();
#ifdef CDI_STANDALONE
int main()
#else
int init_ata
#endif
{
cdi_init();
ata_driver_init();
cdi_storage_driver_register((struct cdi_storage_driver*) &driver);
#ifdef CDI_STANDALONE
cdi_run_drivers();
#endif
return 0;
}
/**
* Initialisiert die Datenstrukturen fuer den sis900-Treiber
*/
static void ata_driver_init()
{
struct ata_controller* controller;
// Konstruktor der Vaterklasse
cdi_storage_driver_init((struct cdi_storage_driver*) &driver);
// Namen setzen
driver.storage.drv.name = driver_name;
// Funktionspointer initialisieren
driver.storage.drv.destroy = ata_driver_destroy;
driver.storage.drv.init_device = ata_init_device;
driver.storage.drv.remove_device = ata_remove_device;
driver.storage.read_blocks = ata_read_blocks;
driver.storage.write_blocks = ata_write_blocks;
// Liste mit Controllern initialisieren
controller_list = cdi_list_create();
// Primaeren Controller vorbereiten
controller = malloc(sizeof(*controller));
controller->port_cmd_base = ATA_PRIMARY_CMD_BASE;
controller->port_ctl_base = ATA_PRIMARY_CTL_BASE;
controller->irq = ATA_PRIMARY_IRQ;
controller->id = 0;
controller->driver = (struct cdi_storage_driver*) &driver;
ata_init_controller(controller);
cdi_list_push(controller_list, controller);
// Sekundaeren Controller vorbereiten
controller = malloc(sizeof(*controller));
controller->port_cmd_base = ATA_SECONDARY_CMD_BASE;
controller->port_ctl_base = ATA_SECONDARY_CTL_BASE;
controller->irq = ATA_SECONDARY_IRQ;
controller->id = 1;
controller->driver = (struct cdi_storage_driver*) &driver;
ata_init_controller(controller);
cdi_list_push(controller_list, controller);
}
/**
* Deinitialisiert die Datenstrukturen fuer den sis900-Treiber
*/
static void ata_driver_destroy(void)
{
cdi_storage_driver_destroy((struct cdi_storage_driver*) &driver);
// TODO Alle Karten deinitialisieren
}
/*
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the LOST Project
* and its contributors.
* 4. Neither the name of the LOST Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "cdi.h"
#include "cdi/storage.h"
#include "cdi/misc.h"
#include "cdi/io.h"
#include "device.h"
/**
* Warten bis ein ATA-Geraet bereit ist
*
* @param bits Bits die gesetzt sein muessen
* @param timeout Timeout in Millisekunden
*
* @return 1 wenn das Geraet bereit ist, 0 sonst
*/
static inline int ata_drv_wait_ready(struct ata_device* dev, uint8_t bits,
uint32_t timeout)
{
struct ata_controller* ctrl = dev->controller;
uint32_t time = 0;
// Zuerst warten, bis das Busy-Bit nicht meht gesetzt ist, denn erst dann
// sind die anderen Bits gueltig
while (((ata_reg_inb(ctrl, REG_STATUS) & STATUS_BSY)) &&
(time < timeout))
{
time += 10;
cdi_sleep_ms(10);
}
// Dem Geraet etwas Zeit geben
ATA_DELAY();
// Jetzt koennen wir warten bis die gewuenschten Bits gesetzt sind
while (((ata_reg_inb(ctrl, REG_STATUS) & bits) != bits) &&
(time < timeout))
{
time += 10;
cdi_sleep_ms(10);
}
return (time < timeout);
}
/**
* Befehlsausfuehrung von einem ATA-Request starten
*
* @return 1 wenn der Befehl erfolgreich gestartet wurde, 0 sonst
*/
static int ata_request_command(struct ata_request* request)
{
struct ata_device* dev = request->dev;
struct ata_controller* ctrl = dev->controller;
uint8_t control;
// IRQ-Zaehler zuruecksetzen, egal ob er gebraucht wird oder nicht, stoert
// ja niemanden
ctrl->irq_cnt = 0;
ata_drv_select(dev);
// Warten bis das Geraet bereit ist
if (!ata_drv_wait_ready(dev, 0, ATA_READY_TIMEOUT)) {
request->error = DEVICE_READY_TIMEOUT;
return 0;
}
// Device Register schreiben
// TODO: nicht lba?
ata_reg_outb(ctrl, REG_DEVICE, (request->flags.lba << 6) | (request->dev->
id << 4) | ((request->registers.ata.lba >> 24) & 0xF));
// Control Register schreiben
control = 0;
if (request->flags.poll) {
// Wenn nur gepollt werden soll, muessen Interrupts deaktiviert werden
control |= CONTROL_NIEN;
}
// TODO: HOB
ata_reg_outb(ctrl, REG_CONTROL, control);
// Count-Register schrieben
ata_reg_outb(ctrl, REG_SEC_CNT, request->registers.ata.count);
// LBA Register schreiben
ata_reg_outb(ctrl, REG_LBA_LOW, request->registers.ata.lba & 0xFF);
ata_reg_outb(ctrl, REG_LBA_MID, (request->registers.ata.lba >> 8) & 0xFF);
ata_reg_outb(ctrl, REG_LBA_HIG, (request->registers.ata.lba >> 16) &
0xFF);
// Befehl ausfuehren
ata_reg_outb(ctrl, REG_COMMAND, request->registers.ata.command);
return 1;
}
/**
* Verarbeitet einen ATA-Request bei dem keine Daten uebertragen werden
*/
static int ata_protocol_non_data(struct ata_request* request)
{
struct ata_device* dev = request->dev;
struct ata_controller* ctrl = dev->controller;
// Aktueller Status im Protokol
enum {
IRQ_WAIT,
CHECK_STATUS
} state;
// Der Anfangsstatus haengt davon ab, ob gepollt werden soll oder nicht.
if (request->flags.poll) {
state = CHECK_STATUS;
} else {
state = IRQ_WAIT;
}
while (1) {
switch (state) {
case IRQ_WAIT:
// Auf IRQ warten
if (ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
request->error = IRQ_TIMEOUT;
printf("ata: non_data IRQ-Timeout\n");
return 0;
}
// Jetzt muss der Status ueberprueft werden
state = CHECK_STATUS;
break;
case CHECK_STATUS: {
uint8_t status = ata_reg_inb(ctrl, REG_STATUS);
// Status ueberpruefen
if ((status & STATUS_BSY) == STATUS_BSY) {
// Wenn das Busy-Flag gesetzt ist, muss gewartet werden,
// bis es geloescht wird.
cdi_sleep_ms(20);
} else {
return 1;
}
break;
}
}
}
}
/**
* Verarbeitet einen ATA-Request bei dem Daten ueber PIO eingelesen werden
* sollen.
* Nach Kapitel 11 in der ATA7-Spec
*/
static int ata_protocol_pio_in(struct ata_request* request)
{
struct ata_device* dev = request->dev;
struct ata_controller* ctrl = dev->controller;
// Aktueller Status im Protokol
enum {
IRQ_WAIT,
CHECK_STATUS,
TRANSFER_DATA
} state;
// Der Anfangsstatus haengt davon ab, ob gepollt werden soll oder nicht.
if (request->flags.poll) {
state = CHECK_STATUS;
} else {
state = IRQ_WAIT;
}
while (1) {
switch (state) {
case IRQ_WAIT:
// Auf IRQ warten
if (ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
request->error = IRQ_TIMEOUT;
printf("ata: pio_in IRQ-Timeout\n");
return 0;
}
// Jetzt muss der Status ueberprueft werden
state = CHECK_STATUS;
break;
case CHECK_STATUS: {
uint8_t status = ata_reg_inb(ctrl, REG_STATUS);
// Status ueberpruefen
// Wenn DRQ und BSY geloescht wurden ist irgendetwas schief
// gelaufen.
if ((status & (STATUS_BSY | STATUS_DRQ)) == 0) {
// TODO: Fehlerbehandlung
printf("ata: pio_in unerwarteter Status: 0x%x\n", status);
return 0;
} else if ((status & STATUS_BSY) == STATUS_BSY) {
// Wenn das Busy-Flag gesetzt ist, muss gewartet werden,
// bis es geloescht wird.
cdi_sleep_ms(20);
} else if ((status & (STATUS_BSY | STATUS_DRQ)) == STATUS_DRQ)
{
// Wenn nur DRQ gesetzt ist, sind Daten bereit um abgeholt
// zu werden. Transaktion nach Transfer Data
state = TRANSFER_DATA;
}
break;
}
case TRANSFER_DATA: {
uint16_t i;
uint16_t* buffer = (uint16_t*) (request->buffer + (request->
blocks_done * request->block_size));
// Einen Block einlesen
for (i = 0; i < request->block_size / 2; i++) {
buffer[i] = ata_reg_inw(ctrl, REG_DATA);
}
// Anzahl der gelesenen Block erhoehen
request->blocks_done++;
// Naechste Transaktion ausfindig machen
if (request->blocks_done >= request->block_count) {
// Wenn alle Blocks gelesen wurden ist der Transfer
// abgeschlossen.
return 1;
} else if (request->flags.poll) {
// Wenn gepollt wird, muss jetzt gewartet werden, bis der
// Status wieder stimmt um den naechsten Block zu lesen.
state = CHECK_STATUS;
} else {
// Bei der Benutzung von Interrupts wird jetzt auf den
// naechsten Interrupt gewartet
state = IRQ_WAIT;
}
}
}
}
}
/**
* Verarbeitet einen ATA-Request bei dem Daten ueber PIO geschrieben werden
* sollen
*/
static int ata_protocol_pio_out(struct ata_request* request)
{
struct ata_device* dev = request->dev;
struct ata_controller* ctrl = dev->controller;
// Aktueller Status im Protokol
enum {
IRQ_WAIT,
CHECK_STATUS,
TRANSFER_DATA
} state;
state = CHECK_STATUS;
while (1) {
switch (state) {
case IRQ_WAIT:
// Auf IRQ warten
if (ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
request->error = IRQ_TIMEOUT;
printf("ata: pio_out IRQ-Timeout\n");
return 0;
}
// Jetzt muss der Status ueberprueft werden
state = CHECK_STATUS;
break;
case CHECK_STATUS: {
uint8_t status = ata_reg_inb(ctrl, REG_STATUS);
// Status ueberpruefen
// Wenn DRQ und BSY geloescht wurden ist irgendetwas schief
// gelaufen, falls der Befehl noch nicht zu Ende ist
if ((status & (STATUS_BSY | STATUS_DRQ)) == 0) {
if (request->blocks_done != request->block_count) {
// TODO: Fehlerbehandlung
printf("ata: pio_out unerwarteter Status: 0x%x\n",
status);
return 0;
} else {
return 1;
}
} else if ((status & STATUS_BSY) == STATUS_BSY) {
// Wenn das Busy-Flag gesetzt ist, muss gewartet werden,
// bis es geloescht wird.
cdi_sleep_ms(20);
} else if ((status & (STATUS_BSY | STATUS_DRQ)) == STATUS_DRQ)
{
// Wenn nur DRQ gesetzt ist, ist der Kontroller bereit um
// Daten zu empfangen.
// Transaktion nach Transfer Data
state = TRANSFER_DATA;
}
break;
}
case TRANSFER_DATA: {
uint16_t i;
uint16_t* buffer = (uint16_t*) (request->buffer + (request->
blocks_done * request->block_size));
// Einen Block schreiben
for (i = 0; i < request->block_size / 2; i++) {
ata_reg_outw(ctrl, REG_DATA, buffer[i]);
}
// Anzahl der geschriebenen Block erhoehen
request->blocks_done++;
// Naechste Transaktion ausfindig machen
if (request->flags.poll) {
// Wenn gepollt wird, muss jetzt gewartet werden, bis der
// Status wieder stimmt um den naechsten Block zu
// schreiben.
state = CHECK_STATUS;
} else {
// Bei der Benutzung von Interrupts wird jetzt auf den
// naechsten Interrupt gewartet
state = IRQ_WAIT;
}
}
}
}
}
/**
* Fuehrt einen ATA-Request aus.
*
* @return 1 Wenn der Request erfolgreich bearbeitet wurde, 0 sonst
*/
int ata_request(struct ata_request* request)
{
// printf("ata: [%d:%d] Request command=%x count=%x lba=%llx protocol=%x\n", request->dev->controller->id, request->dev->id, request->registers.ata.command, request->registers.ata.count, request->registers.ata.lba, request->protocol);
// Befehl ausfuehren
if (!ata_request_command(request)) {
printf("ata: Fehler bei der Befehlsausfuehrung\n");
return 0;
}
// Je nach Protokoll werden jetzt die Daten uebertragen
switch (request->protocol) {
case NON_DATA:
if (!ata_protocol_non_data(request)) {
return 0;
}
break;
case PIO:
if ((request->flags.direction == READ) &&
(!ata_protocol_pio_in(request)))
{
return 0;
} else if ((request->flags.direction == WRITE) &&
(!ata_protocol_pio_out(request)))
{
return 0;
}
break;
}
return 1;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment