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
23int 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
42 : Device(inode, FileSystem::BlockDeviceFile)
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
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
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
160{
161 while (true)
162 {
164
165 if (!(status & ATA_STATUS_BUSY) &&
166 (status & ATA_STATUS_DATA || noData))
167 {
168 break;
169 }
170 }
171}
AT Attachment (ATA) Host Controller Device.
Arch::IO m_io
Port I/O object.
virtual FileSystem::Result initialize()
Configures the ATA controller.
ATAController(const u32 inode)
Constructor.
List< ATADrive * > drives
Drives detected on the ATA bus.
virtual FileSystem::Result read(IOBuffer &buffer, Size &size, const Size offset)
Read bytes from a drive attached to the ATA controller.
virtual FileSystem::Result interrupt(const Size vector)
Process ATA interrupts.
void pollReady(bool noData=false)
Polls the Regular Status register.
int run()
Enters an infinite loop, serving incoming requests.
Device driver server.
virtual FileSystem::Result initialize()
Initialize DeviceServer.
void registerDevice(Device *dev, const char *path)
Add a Device.
Abstract device class interface.
Definition Device.h:36
String m_identifier
Unique identifier for this Device.
Definition Device.h:79
u32 getNextInode()
Get next unused inode.
virtual FileSystem::Result status(FileSystem::FileStat &st)
Retrieve file statistics.
Definition File.cpp:62
Abstract Input/Output buffer.
Definition IOBuffer.h:38
FileSystem::Result bufferedWrite(const void *buffer, const Size size)
Buffered write bytes to the I/O buffer.
Definition IOBuffer.cpp:146
Log to the kernel using PrivExec().
Definition KernelLog.h:35
void append(T t)
Insert an item at the end of the list.
Definition List.h:139
T first()
Get the first value in the list.
Definition List.h:292
virtual bool isEmpty() const
Check if the List is empty.
Definition List.h:382
#define ATA_SEL_MASTER
Master Drive in Legacy mode.
#define ATA_REG_DATA
Data port.
#define ATA_REG_STATUS
Regular Status port.
#define ATA_REG_ADDR1
Partial Disk Sector address.
#define ATA_STATUS_DATA
Drive data ready for transfer.
#define ATA_CMD_IDENTIFY
Identifies an ATA device, if any.
#define ATA_STATUS_BUSY
Drive is preparing to accept or send data.
#define IDENTIFY_TEXT_SWAP(field, size)
Swap ASCII bytes from IDENTIFY.
#define ATA_REG_ADDR0
Partial Disk Sector address.
#define ATA_CMD_READ
Reads sectors from an ATA device.
#define ATA_BASE_CMD0
First ATA Bus Command I/O Base.
#define ATA_SEL_MASTER_28
Master Drive in 28-bit LBA mode.
#define ATA_REG_SELECT
Drive Select bit, Flag bits, Extra address bits.
#define ATA_REG_ADDR2
Partial Disk Sector address.
#define ATA_REG_COUNT
Sector Count.
#define ATA_REG_CMD
Command port and Regular Status port.
int main(int argc, char **argv)
Program entry point.
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
#define INFO(msg)
Output a regular message to standard output.
Definition Log.h:82
#define ERROR(msg)
Output an error message.
Definition Log.h:61
#define NOTICE(msg)
Output a notice message.
Definition Log.h:75
unsigned short u16
Unsigned 16-bit number.
Definition Types.h:56
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define CEIL(number, divisor)
Calculate a division, and round to up any remaining.
Definition Macros.h:88
unsigned char u8
Unsigned 8-bit number.
Definition Types.h:59
Result
Result code for filesystem Actions.
Definition FileSystem.h:53
Represents a Drive on the ATA bus.
IdentifyData identity
Bytes returned from IDENTIFY.