tape-kernel 1.0
a modular modern independent kernel
Loading...
Searching...
No Matches
ide.c
Go to the documentation of this file.
1//ide.c - integrated device electronics driver
2
3#include "ide.h"
4#include "../io/io.h"
5#include "../lib/err.h"
6
7/**
8 * @brief ideinit initializes the ide disk controller
9 *
10 * ideinit is a function that resets the ide controller, selects the master
11 * drive, and verifies the drive is present and ready
12 *
13 * using ideinit is done with
14 * @code{.c}
15 * #include "../fs/ide.h" //or just ide.h
16 * ideinit();
17 * @endcode
18 *
19 * @see ffsinit(), irsec(), iwrt()
20 */
21void __ideinit(void) {
22 //reset the ide controller
23 outb(IDE_PRIMARY_CONTROL, 0x04); //assert reset
24 for (int i = 0; i < 1000; i++) inb(IDE_STATUS); //short delay
25 outb(IDE_PRIMARY_CONTROL, 0x00); //deassert reset
26 for (int i = 0; i < 1000; i++) inb(IDE_STATUS); //short delay
27
28 //select master drive
29 outb(IDE_DEVICE, 0xA0);
30
31 //wait for drive ready with timeout
32 int timeout = 1000000;
33 while ((inb(IDE_STATUS) & 0x80) && timeout--) {
34 //wait
35 }
36 assert(timeout > 0, "ide: drive stuck busy");
37
38 // check if drive exists
39 uint8_t status = inb(IDE_STATUS);
40 assert(status != 0xFF, "ide: no drive detected");
41}
42
43/**
44 * @brief irsec reads a single 512 byte sector from disk
45 *
46 * irsec is a function that reads one sector from the ide drive at the given lba
47 * @param lba, the logical block address to read from
48 * @param buff, the 512 byte buffer to store the read data
49 *
50 * using irsec is done with
51 * @code{.c}
52 * #include "../fs/ide.h" //or just ide.h
53 * uint8_t sector[512];
54 * irsec(0, sector); //read the boot sector
55 * @endcode
56 *
57 * @see iwrt(), idesize()
58 */
59void __irsec(uint32_t lba, uint8_t *buff) {
60 assert(buff != NULL, "irsec: buffer is NULL");
61 //wait for drive to be ready (not busy)
62 while (inb(IDE_STATUS) & 0x80);
63
64 //select drive and send lba
65 outb(IDE_DEVICE, 0xE0 | ((lba >> 24) & 0x0F));
66 outb(IDE_SECTORS, 1); //one sector
68 outb(IDE_LBA_MID, (uint8_t)(lba >> 8));
69 outb(IDE_LBA_HIGH, (uint8_t)(lba >> 16));
70
71 //read cmd
72 outb(IDE_COMMAND, 0x20);
73
74 //wait for data ready
75 while (!(inb(IDE_STATUS) & 0x08));
76
77 //read 256 words (512 bytes) from data port
78 for (int i = 0; i < 256; i++) {
79 ((uint16_t*)buff)[i] = inw(IDE_DATA); //warn: inw not inb be careful
80 }
81}
82
83/**
84 * @brief iwrt writes a single 512 byte sector to disk
85 *
86 * iwrt is a function that writes one sector to the ide drive at the given lba
87 * @param lba, the logical block address to write to
88 * @param buff, the 512 byte buffer containing the data to write
89 *
90 * using iwrt is done with
91 * @code{.c}
92 * #include "../fs/ide.h" //or just ide.h
93 * uint8_t sector[512];
94 * iwrt(1, sector); //write to sector 1
95 * @endcode
96 *
97 * @see irsec(), fswrite()
98 */
99void __iwrt(uint32_t lba, uint8_t *buff) {
100 assert(buff != NULL, "iwrt: buffer is NULL");
101 //wait for drive to be ready
102 while (inb(IDE_STATUS) & 0x80);
103
104 //select drive and send lba
105 outb(IDE_DEVICE, 0xE0 | ((lba >> 24) & 0x0F)); //calculate for out
106 outb(IDE_SECTORS, 1);
107 outb(IDE_LBA_LOW, (uint8_t)lba); //shifts, low is normal, mid is shfl 8, high is shfl 16
108 outb(IDE_LBA_MID, (uint8_t)(lba >> 8));
109 outb(IDE_LBA_HIGH, (uint8_t)(lba >> 16));
110
111 //write command
112 outb(IDE_COMMAND, 0x30);
113
114 //wait for drive ready for data
115 while (!(inb(IDE_STATUS) & 0x08));
116
117 //write 256 words
118 for (int i = 0; i < 256; i++) {
119 outw(IDE_DATA, ((uint16_t*)buff)[i]);
120 }
121
122 //wait for write to complete
123 while (inb(IDE_STATUS) & 0x80);
124}
125
126/**
127 * @brief idesize queries the ide drive for its total sector count
128 *
129 * idesize is a function that sends the IDENTIFY command to the ide drive
130 * and reads back the total number of lba28 sectors
131 * @param secs, a pointer to store the total sector count
132 *
133 * using idesize is done with
134 * @code{.c}
135 * #include "../fs/ide.h" //or just ide.h
136 * uint32_t total_secs;
137 * if (idesize(&total_secs)) {
138 * //total_secs now holds the drive sector count
139 * }
140 * @endcode
141 *
142 * @see disksize(), ideinit()
143 */
144int __idesize(uint32_t *secs) {
145 //wait for drive ready
146 while (inb(IDE_STATUS) & 0x80);
147
148 //select drive
149 outb(IDE_DEVICE, 0xA0);
150
151 //send IDENTIFY cmd (0xEC)
152 outb(IDE_COMMAND, 0xEC);
153
154 //wait for drq or err
155 uint8_t status;
156 int timeout = 1000000;
157 do {
158 status = inb(IDE_STATUS);
159 if (status & 0x01) return 0; //error
160 timeout--; //decrement timeout to actually wait
161 } while (!(status & 0x08) && timeout > 0);
162
163 if (timeout == 0) return 0;
164
165 //read 256 words of identify data
166 uint16_t identify[256];
167 for (int i = 0; i < 256; i++) {
168 identify[i] = inw(IDE_DATA);
169 }
170
171 //lba28 sectors are at words 60-61 (28 bit)
172 //for lba28
173 *secs = identify[60] | (identify[61] << 16);
174
175 return 1; //success
176}
177
178
#define assert
Definition err.h:4
void __ideinit(void)
ideinit initializes the ide disk controller
Definition ide.c:21
void __iwrt(uint32_t lba, uint8_t *buff)
iwrt writes a single 512 byte sector to disk
Definition ide.c:99
void __irsec(uint32_t lba, uint8_t *buff)
irsec reads a single 512 byte sector from disk
Definition ide.c:59
int __idesize(uint32_t *secs)
idesize queries the ide drive for its total sector count
Definition ide.c:144
#define IDE_STATUS
Definition ide.h:15
#define IDE_LBA_HIGH
Definition ide.h:12
#define IDE_LBA_MID
Definition ide.h:11
#define IDE_LBA_LOW
Definition ide.h:10
#define IDE_DATA
Definition ide.h:6
#define IDE_SECTORS
Definition ide.h:9
#define IDE_COMMAND
Definition ide.h:14
#define IDE_DEVICE
Definition ide.h:13
#define IDE_PRIMARY_CONTROL
Definition ide.h:7
#define inb
Definition io.h:6
#define inw
Definition io.h:8
#define outb
Definition io.h:7
#define outw
Definition io.h:9
#define NULL
Definition types.h:38
unsigned short uint16_t
Definition types.h:29
unsigned int uint32_t
Definition types.h:30
unsigned char uint8_t
Definition types.h:28