FreeNOS
ATAController.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 Niek Linnenbank
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <KernelLog.h>
19 #include <DeviceServer.h>
20 #include "ATAController.h"
21 #include <Types.h>
22 
23 int main(int argc, char **argv)
24 {
25  KernelLog log;
26  DeviceServer server("/dev/ata");
27  server.registerDevice(new ATAController(server.getNextInode()), "ata0");
28 
29  // Initialize
30  const FileSystem::Result result = server.initialize();
31  if (result != FileSystem::Success)
32  {
33  ERROR("failed to initialize: result = " << (int) result);
34  return 1;
35  }
36 
37  // Start serving requests
38  return server.run();
39 }
40 
43 {
44  m_identifier << "ata0";
45 }
46 
48 {
49  ATADrive *drive;
50 
51  // Detect ATA Controller
52  if (m_io.inb(ATA_BASE_CMD0 + ATA_REG_STATUS) == 0xff)
53  {
55  }
56  pollReady(true);
57 
58  // Attempt to detect first drive
60  pollReady(true);
62 
63  switch (m_io.inb(ATA_BASE_CMD0 + ATA_REG_STATUS))
64  {
65  case 0:
66  NOTICE("No ATA drive(s) detected");
67  break;
68 
69  default:
70  // Wait until the command completed
71  pollReady();
72 
73  // Allocate a new drive
74  drive = new ATADrive;
75  drives.append(drive);
76 
77  // Read IDENTIFY data
78  for (int i = 0; i < 256; i++)
79  {
80  ((u16 *) &drive->identity)[i] = m_io.inw(ATA_BASE_CMD0 + ATA_REG_DATA);
81  }
82 
83  // Fixup ASCII bytes
86  IDENTIFY_TEXT_SWAP(drive->identity.model, 40);
87 
88  // Print out information
89  NOTICE("ATA drive detected: SERIAL=" << drive->identity.serial <<
90  " FIRMWARE=" << drive->identity.firmware <<
91  " MODEL=" << drive->identity.model <<
92  " MAJOR=" << drive->identity.majorRevision <<
93  " MINOR=" << drive->identity.minorRevision <<
94  " SECTORS=" << drive->identity.sectors28);
95  break;
96  }
97 
98  return FileSystem::Success;
99 }
100 
102  Size & size,
103  const Size offset)
104 {
105  u8 sectors = CEIL(size, 512);
106  u16 block[256];
107  u32 lba = offset / 512;
108  Size result = 0;
109  Size off = offset;
110 
111  // Verify LBA
112  if (drives.isEmpty() || drives.first()->identity.sectors28 < lba)
113  {
114  return FileSystem::IOError;
115  }
116 
117  // Perform ATA Read Command
119  m_io.outb(ATA_BASE_CMD0 + ATA_REG_COUNT, sectors);
120  m_io.outb(ATA_BASE_CMD0 + ATA_REG_ADDR0, (lba) & 0xff);
121  m_io.outb(ATA_BASE_CMD0 + ATA_REG_ADDR1, (lba >> 8) & 0xff);
122  m_io.outb(ATA_BASE_CMD0 + ATA_REG_ADDR2, (lba >> 16) & 0xff);
124 
125  // Read out all requested sectors
126  while(result < size)
127  {
128  // Poll the status register
129  pollReady(true);
130 
131  // Read out bytes
132  for (int i = 0; i < 256; i++)
133  {
134  block[i] = m_io.inw(ATA_BASE_CMD0 + ATA_REG_DATA);
135  }
136 
137  // Calculate maximum bytes
138  Size bytes = (size - result) < 512 - (off % 512) ?
139  (size - result) : 512 - (off % 512);
140 
141  // Copy to buffer
142  buffer.bufferedWrite(((u8 *)block) + (off % 512), bytes);
143 
144  // Update state
145  result += bytes;
146  off += bytes;
147  }
148 
149  size = result;
150  return FileSystem::Success;
151 }
152 
154 {
155  INFO("ATA interrupted on IRQ " << vector);
156  return FileSystem::Success;
157 }
158 
159 void ATAController::pollReady(bool noData)
160 {
161  while (true)
162  {
164 
165  if (!(status & ATA_STATUS_BUSY) &&
166  (status & ATA_STATUS_DATA || noData))
167  {
168  break;
169  }
170  }
171 }
ATA_REG_DATA
#define ATA_REG_DATA
Data port.
Definition: ATAController.h:64
ATA_REG_ADDR2
#define ATA_REG_ADDR2
Partial Disk Sector address.
Definition: ATAController.h:92
ATA_REG_COUNT
#define ATA_REG_COUNT
Sector Count.
Definition: ATAController.h:76
ATAController::interrupt
virtual FileSystem::Result interrupt(const Size vector)
Process ATA interrupts.
Definition: ATAController.cpp:153
DeviceServer.h
ATAController.h
Types.h
NOTICE
#define NOTICE(msg)
Output a notice message.
Definition: Log.h:75
IdentifyData::model
u8 model[40]
Definition: ATAController.h:229
ATAController::initialize
virtual FileSystem::Result initialize()
Configures the ATA controller.
Definition: ATAController.cpp:47
FileSystemServer::getNextInode
u32 getNextInode()
Get next unused inode.
Definition: FileSystemServer.cpp:66
ATADrive
struct ATADrive ATADrive
Represents a Drive on the ATA bus.
ATAController::ATAController
ATAController(const u32 inode)
Constructor.
Definition: ATAController.cpp:41
ATAController
AT Attachment (ATA) Host Controller Device.
Definition: ATAController.h:262
IDENTIFY_TEXT_SWAP
#define IDENTIFY_TEXT_SWAP(field, size)
Swap ASCII bytes from IDENTIFY.
Definition: ATAController.h:206
IOBuffer::bufferedWrite
FileSystem::Result bufferedWrite(const void *buffer, const Size size)
Buffered write bytes to the I/O buffer.
Definition: IOBuffer.cpp:146
ATAController::pollReady
void pollReady(bool noData=false)
Polls the Regular Status register.
Definition: ATAController.cpp:159
ATA_STATUS_BUSY
#define ATA_STATUS_BUSY
Drive is preparing to accept or send data.
Definition: ATAController.h:138
Device
Abstract device class interface.
Definition: Device.h:35
IdentifyData::serial
u8 serial[20]
Definition: ATAController.h:226
ATA_SEL_MASTER_28
#define ATA_SEL_MASTER_28
Master Drive in 28-bit LBA mode.
Definition: ATAController.h:175
ChannelServer::run
int run()
Enters an infinite loop, serving incoming requests.
Definition: ChannelServer.h:161
FileSystem::IOError
@ IOError
Definition: FileSystem.h:58
ATA_BASE_CMD0
#define ATA_BASE_CMD0
First ATA Bus Command I/O Base.
Definition: ATAController.h:39
ATADrive
Represents a Drive on the ATA bus.
Definition: ATAController.h:249
FileSystem::Success
@ Success
Definition: FileSystem.h:54
List::isEmpty
virtual bool isEmpty() const
Check if the List is empty.
Definition: List.h:382
ATA_REG_ADDR1
#define ATA_REG_ADDR1
Partial Disk Sector address.
Definition: ATAController.h:87
DeviceServer
Device driver server.
Definition: DeviceServer.h:43
main
int main(int argc, char **argv)
Program entry point.
Definition: ATAController.cpp:23
IdentifyData::minorRevision
u16 minorRevision
Definition: ATAController.h:237
FileSystem::NotSupported
@ NotSupported
Definition: FileSystem.h:61
KernelLog
Log to the kernel using PrivExec().
Definition: KernelLog.h:34
IdentifyData::firmware
u8 firmware[8]
Definition: ATAController.h:228
DeviceServer::registerDevice
void registerDevice(Device *dev, const char *path)
Add a Device.
Definition: DeviceServer.cpp:67
ATA_CMD_READ
#define ATA_CMD_READ
Reads sectors from an ATA device.
Definition: ATAController.h:193
ATA_REG_SELECT
#define ATA_REG_SELECT
Drive Select bit, Flag bits, Extra address bits.
Definition: ATAController.h:97
List::append
void append(T t)
Insert an item at the end of the list.
Definition: List.h:139
u16
unsigned short u16
Unsigned 16-bit number.
Definition: Types.h:56
IdentifyData::majorRevision
u16 majorRevision
Definition: ATAController.h:236
INFO
#define INFO(msg)
Output a regular message to standard output.
Definition: Log.h:82
IOBuffer
Abstract Input/Output buffer.
Definition: IOBuffer.h:37
u32
unsigned int u32
Unsigned 32-bit number.
Definition: Types.h:53
CEIL
#define CEIL(number, divisor)
Calculate a division, and round to up any remaining.
Definition: Macros.h:88
ATA_REG_ADDR0
#define ATA_REG_ADDR0
Partial Disk Sector address.
Definition: ATAController.h:82
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
ATAController::drives
List< ATADrive * > drives
Drives detected on the ATA bus.
Definition: ATAController.h:315
ATAController::m_io
Arch::IO m_io
Port I/O object.
Definition: ATAController.h:318
DeviceServer::initialize
virtual FileSystem::Result initialize()
Initialize DeviceServer.
Definition: DeviceServer.cpp:30
IdentifyData::sectors28
u32 sectors28
Definition: ATAController.h:234
File::status
virtual FileSystem::Result status(FileSystem::FileStat &st)
Retrieve file statistics.
Definition: File.cpp:62
ATADrive::identity
IdentifyData identity
Bytes returned from IDENTIFY.
Definition: ATAController.h:252
Device::m_identifier
String m_identifier
Unique identifier for this Device.
Definition: Device.h:79
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
ATA_REG_STATUS
#define ATA_REG_STATUS
Regular Status port.
Definition: ATAController.h:110
FileSystem::Result
Result
Result code for filesystem Actions.
Definition: FileSystem.h:52
u8
unsigned char u8
Unsigned 8-bit number.
Definition: Types.h:59
List::first
T first()
Get the first value in the list.
Definition: List.h:292
ATA_STATUS_DATA
#define ATA_STATUS_DATA
Drive data ready for transfer.
Definition: ATAController.h:131
ATA_SEL_MASTER
#define ATA_SEL_MASTER
Master Drive in Legacy mode.
Definition: ATAController.h:172
FileSystem::BlockDeviceFile
@ BlockDeviceFile
Definition: FileSystem.h:74
FileSystem
Definition: FileSystem.h:31
ATA_CMD_IDENTIFY
#define ATA_CMD_IDENTIFY
Identifies an ATA device, if any.
Definition: ATAController.h:190
ATA_REG_CMD
#define ATA_REG_CMD
Command port and Regular Status port.
Definition: ATAController.h:103
ATAController::read
virtual FileSystem::Result read(IOBuffer &buffer, Size &size, const Size offset)
Read bytes from a drive attached to the ATA controller.
Definition: ATAController.cpp:101
KernelLog.h