ATAPI can identify a device correctly
This commit is contained in:
parent
5a68f77b33
commit
2db83b33e1
6
Makefile
6
Makefile
@ -17,7 +17,8 @@ $(BUILD_DIR)/idt.o \
|
||||
$(BUILD_DIR)/pci.o \
|
||||
$(BUILD_DIR)/pic.o \
|
||||
$(BUILD_DIR)/string.o \
|
||||
$(BUILD_DIR)/pcidevice.o
|
||||
$(BUILD_DIR)/pcidevice.o \
|
||||
$(BUILD_DIR)/atapiDevice.o
|
||||
|
||||
|
||||
|
||||
@ -108,3 +109,6 @@ $(BUILD_DIR)/pci.o:
|
||||
|
||||
$(BUILD_DIR)/pcidevice.o:
|
||||
$(CPP) -c $(SRC_DIR)/kernel/pci/pciDevice.cpp -o $(BUILD_DIR)/pcidevice.o $(CFLAGS) -fno-exceptions -fno-rtti
|
||||
|
||||
$(BUILD_DIR)/atapiDevice.o:
|
||||
$(CPP) -c $(SRC_DIR)/kernel/drivers/atapi/atapiDevice.cpp -o $(BUILD_DIR)/atapiDevice.o $(CFLAGS) -fno-exceptions -fno-rtti
|
||||
|
@ -19,6 +19,10 @@ Multiboot information can be read by the kernel.
|
||||
|
||||
![PCI enumeration](screenshots/PCIBusEnumeration.png) \
|
||||
Enumerating the PCI bus
|
||||
|
||||
![ATAPI CD-ROM Identification](screenshots/CD-ROM_Identify.png) \
|
||||
Correctly identified our ATAPI device 🎉
|
||||
|
||||
________________________
|
||||
|
||||
### The goal
|
||||
|
BIN
screenshots/CD-ROM_Identify.png
(Stored with Git LFS)
Normal file
BIN
screenshots/CD-ROM_Identify.png
(Stored with Git LFS)
Normal file
Binary file not shown.
131
src/kernel/drivers/ata/ataDevice.cpp
Normal file
131
src/kernel/drivers/ata/ataDevice.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "atapiDevice.h"
|
||||
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
|
||||
|
||||
void ATA_DEVICE::Soft_Reset(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive){
|
||||
printf("Soft reseting drive...\n");
|
||||
outb(channels[DEVICE_CHANNEL].base + 7 , 0x4);
|
||||
// wait a bit..
|
||||
for(int i = 0 ; i < 1000000; i++){
|
||||
asm volatile("NOP");
|
||||
}
|
||||
outb(channels[DEVICE_CHANNEL].base + 7 , 0x0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ATA_DEVICE::Identify(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive ){
|
||||
// lets ignore which port we actually want to check for now !
|
||||
|
||||
/*
|
||||
THE STEPS INVOLVED
|
||||
|
||||
1. Select the target drive by sending master (0x0A) or slave (0x0B) to the
|
||||
drive select IO port
|
||||
|
||||
2. Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
|
||||
|
||||
3. Send the identify command (0xEC) to the command IO port
|
||||
|
||||
4. Read the status port
|
||||
4.2 If the value is 0x0 the drive does not exist
|
||||
4.3 If it has any other value continue
|
||||
5. poll the status port until bit 7 is clear.
|
||||
6. Check if the LBAmid and LBAhi ports are non-zero
|
||||
6.2. If non-zero stop polling this is not an ATA device
|
||||
6.3 If zero continue
|
||||
|
||||
7. poll status port until bit 3 is set or bit 0 is set
|
||||
|
||||
8. if err is clear, read the data from the data port
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// Assuming Master here
|
||||
// Select the target drive
|
||||
outb(0x176, 0x0A); // on the primary bus select the master drive
|
||||
|
||||
// Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
|
||||
outb(0x172, 0);
|
||||
|
||||
outb(0x173, 0);
|
||||
|
||||
outb(0x174, 0);
|
||||
|
||||
outb(0x175, 0);
|
||||
|
||||
// send the identify command;
|
||||
outb(0x177, 0xA1);
|
||||
|
||||
// read the status port
|
||||
uint8_t status = inb(0x177);
|
||||
if( status == 0x00){
|
||||
printf("No drive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while(true){
|
||||
status = inb(0x177);
|
||||
|
||||
if( status & (~8))
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Is this an ATA device?\n");
|
||||
uint8_t LBAmid = inb(0x174);
|
||||
uint8_t LBAhi = inb(0x175);
|
||||
|
||||
printf("LBAmid: 0x%x, LBAhi: 0x%x\n", LBAmid, LBAhi);
|
||||
|
||||
|
||||
if( LBAhi != 0x0 || LBAmid != 0x0){
|
||||
printf("Not ATA device.. Stopping..\n");
|
||||
// return;
|
||||
}
|
||||
|
||||
while(true){
|
||||
status = inb(0x177);
|
||||
printf( "Status bit: 0x%x\n", status);
|
||||
if ( IS_BIT_SET(status, 3)){
|
||||
printf("Status: ready!\n");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if( IS_BIT_SET(status, 0)){
|
||||
printf("Status: error!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( IS_BIT_SET(status, 0) == false){
|
||||
// READ DATA
|
||||
|
||||
uint16_t deviceIdentify [256];
|
||||
|
||||
for (int i= 0; i < 256; i++){
|
||||
uint8_t data = inb(0x170);
|
||||
uint8_t data2 = inb(0x170);
|
||||
|
||||
deviceIdentify[i] = (uint16_t) ( (uint16_t) data << 8 | (uint16_t) data2 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
printf("Data received!\n");
|
||||
}
|
||||
|
||||
printf("Error bit was set!\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ATA_DEVICE::Read(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
|
||||
printf("Not implemented");
|
||||
}
|
||||
|
||||
void ATA_DEVICE::Write(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
|
||||
printf("Not implemented");
|
||||
}
|
29
src/kernel/drivers/ata/ataDevice.h
Normal file
29
src/kernel/drivers/ata/ataDevice.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../io.h"
|
||||
#include "../ide/ideCommands.h"
|
||||
#include "../ide/sampleIDE.definitions.h"
|
||||
|
||||
#include "../tty/kterm.h"
|
||||
|
||||
/*
|
||||
* This first driver wil make use of IO ports.
|
||||
* Doing so means reading or writing from disk is going
|
||||
* to be very cpu intensive.
|
||||
*
|
||||
*/
|
||||
|
||||
enum DEVICE_DRIVE{
|
||||
MASTER = 0xA0,
|
||||
SLAVE = 0xB0
|
||||
};
|
||||
|
||||
|
||||
namespace ATA_DEVICE
|
||||
{
|
||||
void Identify ( uint8_t, DEVICE_DRIVE );
|
||||
void Read ( uint8_t, DEVICE_DRIVE );
|
||||
void Write ( uint8_t, DEVICE_DRIVE );
|
||||
void Soft_Reset ( uint8_t, DEVICE_DRIVE );
|
||||
|
||||
};
|
145
src/kernel/drivers/atapi/atapiDevice.cpp
Normal file
145
src/kernel/drivers/atapi/atapiDevice.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
#include "atapiDevice.h"
|
||||
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
|
||||
|
||||
bool isPacketDevice(){
|
||||
|
||||
uint8_t LBAmid = inb(0x174);
|
||||
uint8_t LBAhi = inb(0x175);
|
||||
|
||||
printf(" LBAmid: 0x%x, LBAhi: 0x%x");
|
||||
return LBAmid == 0x14 && LBAhi == 0xEB;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ATAPI_DEVICE::Identify(uint8_t DEVICE_CHANNEL,DEVICE_DRIVE drive ){
|
||||
// lets ignore which port we actually want to check for now !
|
||||
|
||||
/* THE STEPS INVOLVED
|
||||
|
||||
1. Select the target drive by sending master (0x0A) or slave (0x0B) to the
|
||||
drive select IO port
|
||||
|
||||
2. Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
|
||||
|
||||
3. Send the identify command (0xEC) to the command IO port
|
||||
|
||||
4. Read the status port
|
||||
4.2 If the value is 0x0 the drive does not exist
|
||||
4.3 If it has any other value continue
|
||||
5. poll the status port until bit 7 is clear.
|
||||
6. Check if the LBAmid and LBAhi ports are non-zero
|
||||
6.2. If non-zero stop polling this is not an ATA device
|
||||
6.3 If zero continue
|
||||
|
||||
7. poll status port until bit 3 is set or bit 0 is set
|
||||
|
||||
8. if err is clear, read the data from the data port
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// Select the target drive
|
||||
outb(0x176, 0xA0); // on the secondary bus select the master drive
|
||||
outb(0x170 + 0x206 , 0x0); // write 0 to the controlport for some reason
|
||||
|
||||
outb(0x176, 0xA0);
|
||||
// read the status port
|
||||
uint8_t status = inb(0x177);
|
||||
printf("status after drive select: 0x%x\n",status);
|
||||
if( status == 0x00){
|
||||
printf("No drive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
outb(0x176, 0xA0);
|
||||
|
||||
|
||||
// Set the Sectorcount, LBAlo, LBAmid and LBAhi IO ports to 0
|
||||
outb(0x172, 0);
|
||||
|
||||
outb(0x173, 0);
|
||||
|
||||
outb(0x174, 0);
|
||||
|
||||
outb(0x175, 0);
|
||||
|
||||
// send the identify command;
|
||||
printf("command sent!\n");
|
||||
outb(0x177, 0xA1);
|
||||
|
||||
// read the status port
|
||||
uint8_t status2 = inb(0x177);
|
||||
if( status2 == 0x00){
|
||||
printf("No drive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
printf("Waiting until ready...\n");
|
||||
|
||||
while(((status2 & 0x80 == 0x80)
|
||||
&& (status2 & 0x01) != 0x01)
|
||||
) status2 = inb(0x177);
|
||||
|
||||
|
||||
if(status2 & 0x01){
|
||||
printf("Error!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// READ DATA
|
||||
|
||||
uint16_t deviceIdentify [256] ={0};
|
||||
|
||||
for (int i= 0; i < 256; i++){
|
||||
uint16_t data;
|
||||
asm volatile ( "in %1, %0"
|
||||
: "=a"(data)
|
||||
: "Nd"(0x170) );
|
||||
|
||||
|
||||
deviceIdentify[i] = data ;
|
||||
|
||||
|
||||
}
|
||||
|
||||
printf("Model-label (ASCII hex):\n");
|
||||
for(int i = 27; i < 47; i++){
|
||||
printf(" %x ",deviceIdentify[i]);
|
||||
}
|
||||
|
||||
printf("\nSerial number (ASCII hex):\n");
|
||||
for (int i = 10; i < 19; i++){
|
||||
printf(" %x ", deviceIdentify[i]);
|
||||
}
|
||||
|
||||
printf("\nFirmware revision (ASCII hex):\n");
|
||||
for (int i = 23; i < 26; i++){
|
||||
printf(" %x ", deviceIdentify[i]);
|
||||
}
|
||||
|
||||
printf("\nConfiguration: %x\n", deviceIdentify[0]);
|
||||
|
||||
|
||||
|
||||
printf("\nData received!\n");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ATAPI_DEVICE::Read(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
|
||||
printf("Not implemented");
|
||||
}
|
||||
|
||||
void ATAPI_DEVICE::Write(uint8_t DEVICE_CHANNEL, DEVICE_DRIVE drive) {
|
||||
printf("Not implemented");
|
||||
}
|
||||
|
||||
|
29
src/kernel/drivers/atapi/atapiDevice.h
Normal file
29
src/kernel/drivers/atapi/atapiDevice.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../io.h"
|
||||
#include "../../ide/ideCommands.h"
|
||||
#include "../../ide/sampleIDE.definitions.h"
|
||||
|
||||
#include "../../tty/kterm.h"
|
||||
|
||||
/*
|
||||
* This first driver wil make use of IO ports.
|
||||
* Doing so means reading or writing from disk is going
|
||||
* to be very cpu intensive.
|
||||
*
|
||||
*/
|
||||
|
||||
enum DEVICE_DRIVE{
|
||||
MASTER = 0xA0,
|
||||
SLAVE = 0xB0
|
||||
};
|
||||
|
||||
|
||||
namespace ATAPI_DEVICE
|
||||
{
|
||||
bool isPacketDevice();
|
||||
void Identify ( uint8_t, DEVICE_DRIVE );
|
||||
void Read ( uint8_t, DEVICE_DRIVE );
|
||||
void Write ( uint8_t, DEVICE_DRIVE );
|
||||
|
||||
};
|
@ -7,6 +7,8 @@
|
||||
|
||||
#define IS_BIT_SET(x, bit) ((x >> bit & 0x1) == 1)
|
||||
|
||||
IDEChannelRegisters channels[2];
|
||||
IDE_DEVICE ide_devices[4];
|
||||
|
||||
inline void CheckProgIF(uint8_t ProgIF){
|
||||
if( IS_BIT_SET(ProgIF, 0) ) // Is the 0th bit set
|
||||
|
@ -5,11 +5,8 @@ struct IDEChannelRegisters{
|
||||
unsigned short ctrl; // Control Base
|
||||
unsigned short bmide; // Bus Master IDE
|
||||
unsigned char nIEN; // IEN (no interrupt)
|
||||
}channels[2];
|
||||
};
|
||||
|
||||
extern unsigned char ide_buf[2048];
|
||||
extern unsigned char ide_irq_invoked;
|
||||
extern unsigned char atapi_packet[12];
|
||||
|
||||
struct IDE_DEVICE {
|
||||
unsigned char Reserved; // 0 (Empty) or 1 (This device exists).
|
||||
@ -19,7 +16,14 @@ struct IDE_DEVICE {
|
||||
unsigned short Signature; // Drive Signature
|
||||
unsigned short Capabilities; // Features.
|
||||
unsigned int CommandSets; // Command Sets Supported.
|
||||
unsigned int Size; // Size in Sectors
|
||||
unsigned int Size; // Size in Sectors (NOTE: Seems unused nowadays as i've only seen the value be zero
|
||||
unsigned char Model[41]; // Model in string.
|
||||
} ide_devices[4];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
extern IDEChannelRegisters channels[2];
|
||||
extern IDE_DEVICE ide_devices[4];
|
||||
extern unsigned char ide_buf[2048];
|
||||
extern unsigned char ide_irq_invoked;
|
||||
extern unsigned char atapi_packet[12];
|
||||
|
@ -71,6 +71,33 @@ extern "C" void kernel_main (void);
|
||||
|
||||
TestIDEController();
|
||||
|
||||
int devNumber = 0 ;
|
||||
for ( auto device : ide_devices){
|
||||
if (!device.Reserved)
|
||||
continue;
|
||||
|
||||
|
||||
printf("Device %d\n" , devNumber);
|
||||
printf (" Device on Channel: (0x%x) %s\n" ,device.Channel, device.Channel == 0 ? "Primary" : "Secondary");
|
||||
printf (" Device drive:(0x%x) %s\n" , device.Drive, device.Drive? "Slave" : "Master");
|
||||
printf (" Device Type:(0x%x) %s\n" , device.Type, device.Type ? "ATAPI" : "ATA");
|
||||
devNumber ++;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// ATAPI_DEVICE::isPacketDevice();
|
||||
|
||||
|
||||
|
||||
|
||||
ATAPI_DEVICE::Identify(ATA_SECONDARY, DEVICE_DRIVE::MASTER);
|
||||
|
||||
|
||||
|
||||
while (true){
|
||||
//Read time indefinetely
|
||||
|
@ -20,6 +20,8 @@ extern "C"{
|
||||
#include "serial.h"
|
||||
#include "pci.h"
|
||||
#include "ide/ide.h"
|
||||
#include "drivers/atapi/atapiDevice.h"
|
||||
|
||||
|
||||
|
||||
#define CHECK_FLAG(flags, bit) ((flags) & (1 <<(bit)))
|
||||
|
Loading…
Reference in New Issue
Block a user