1
1
#include "IDE.h"
2
2
#include "../printf.h"
3
3
#include "../System_Specific.h"
4
+ #include "../Timers/System_Clock.h"
5
+ #include "../misc.h"
6
+ #include "../Interrupts/IDT.h"
7
+ #include "../Interrupts/Interrupts.h"
8
+
4
9
// TODO: Support multiple IDE controllers
5
10
uint8_t IDE_bus ;
6
11
uint8_t IDE_slot ;
7
12
uint8_t IDE_function ;
8
13
bool IDE_Present ;
9
14
10
- IDE_CHANNEL_REGISTERS channels [2 ];
15
+ IDE_CHANNEL_INFO channels [2 ];
11
16
12
17
uint8_t ide_buf [2048 ] = { 0 };
13
18
bool ide_irq_invoked = 0 ;
14
- uint8_t atapi_packet [12 ] = { 0xA8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
19
+ //uint8_t atapi_packet[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
20
+
21
+ void _declspec (naked ) IDE_primary_channel_interrupt_handler ()
22
+ {
23
+ __asm
24
+ {
25
+ push ebp
26
+ mov ebp , esp
27
+ }
28
+
29
+ ++ interrupts_fired ;
30
+
31
+ if (debugLevel )
32
+ terminal_writestring (" --------- IDE 0 interrupt fired! -------\n" );
33
+
34
+ ide_irq_invoked = true;
35
+
36
+ PIC_sendEOI (HARDWARE_INTERRUPTS_BASE + channels [0 ].irq );
37
+
38
+ if (debugLevel )
39
+ terminal_writestring (" --------- IDE 0 interrupt done! -------\n" );
40
+
41
+ _asm
42
+ {
43
+ pop ebp
44
+ iretd
45
+ }
46
+ }
47
+ void _declspec (naked ) IDE_secondary_channel_interrupt_handler ()
48
+ {
49
+ __asm
50
+ {
51
+ push ebp
52
+ mov ebp , esp
53
+ }
54
+
55
+ ++ interrupts_fired ;
56
+
57
+ if (debugLevel )
58
+ terminal_writestring (" --------- IDE 1 interrupt fired! -------\n" );
59
+
60
+ ide_irq_invoked = true;
61
+
62
+ PIC_sendEOI (HARDWARE_INTERRUPTS_BASE + channels [1 ].irq );
63
+
64
+ if (debugLevel )
65
+ terminal_writestring (" --------- IDE 1 interrupt done! -------\n" );
66
+
67
+ _asm
68
+ {
69
+ pop ebp
70
+ iretd
71
+ }
72
+ }
15
73
16
74
void IDE_Init (uint8_t bus , uint8_t slot , uint8_t function )
17
75
{
@@ -50,27 +108,139 @@ void IDE_Init(uint8_t bus, uint8_t slot, uint8_t function)
50
108
channels [1 ].irq = 15 ;
51
109
kprintf (" - IRQs %d&%d\n" , channels [0 ].irq , channels [1 ].irq );
52
110
111
+ // Register the IRQ handlers
112
+ Set_IDT_Entry ((unsigned long )IDE_primary_channel_interrupt_handler ,
113
+ HARDWARE_INTERRUPTS_BASE + channels [0 ].irq );
114
+ Set_IDT_Entry ((unsigned long )IDE_secondary_channel_interrupt_handler ,
115
+ HARDWARE_INTERRUPTS_BASE + channels [1 ].irq );
116
+
117
+ // Tell the PIC to enable the IRQ
118
+ IRQ_Enable_Line (channels [0 ].irq );
119
+ IRQ_Enable_Line (channels [1 ].irq );
120
+
53
121
IDE_Present = true;
54
122
123
+ channels [0 ].bmide = PCI_GetBaseAddress4 (bus , slot , function ) & ~3 ; // Bus Master IDE
124
+ channels [1 ].bmide = (PCI_GetBaseAddress4 (bus , slot , function ) & ~3 ) + 8 ; // Bus Master IDE
125
+
126
+ // 2- Disable IRQs: TODO: Need to disable interrupts per-device
127
+ IDE_WriteRegister (ATA_PRIMARY_CHANNEL , ATA_REG_CONTROL , ATA_CONTROL_REG_DISABLE_INTERRUPTS );
128
+ IDE_WriteRegister (ATA_SECONDARY_CHANNEL , ATA_REG_CONTROL , ATA_CONTROL_REG_DISABLE_INTERRUPTS );
129
+
130
+ // 3- Detect ATA-ATAPI Devices:
131
+ int driveNumber = 0 ;
132
+ for (uint8_t channel = 0 ; channel < 2 ; channel ++ )
133
+ {
134
+ for (uint8_t device = 0 ; device < 2 ; device ++ )
135
+ {
136
+ uint8_t err = 0 , type = IDE_ATA , status ;
137
+ ide_devices [driveNumber ].Present = 0 ; // Assuming that no drive here.
138
+
139
+ // (I) Select Drive:
140
+ IDE_WriteRegister (channel , ATA_REG_HDDEVSEL , 0xA0 | (device << 4 )); // Select Drive.
141
+ TimeDelayMS (1 ); // Wait 1ms for drive select to work.
142
+ //return;
143
+ // (II) Send ATA Identify Command:
144
+ IDE_WriteRegister (channel , ATA_REG_COMMAND , ATA_CMD_IDENTIFY );
145
+ TimeDelayMS (1 );
146
+
147
+ // (III) Polling:
148
+ if (IDE_ReadRegister (channel , ATA_REG_STATUS ) == 0 )
149
+ continue ; // If Status = 0, No Device.
150
+
151
+ // TODO: Timeout
152
+ while (1 )
153
+ {
154
+ status = IDE_ReadRegister (channel , ATA_REG_STATUS );
155
+ if ((status & ATA_SR_ERR ))
156
+ {
157
+ err = 1 ; break ;
158
+ } // If Err, Device is not ATA.
159
+ if (!(status & ATA_SR_BSY ) && (status & ATA_SR_DRQ ))
160
+ break ; // Everything is right.
161
+ }
162
+
163
+ // (IV) Probe for ATAPI Devices:
164
+ if (err != 0 )
165
+ {
166
+ unsigned char cl = IDE_ReadRegister (channel , ATA_REG_LBA1 );
167
+ unsigned char ch = IDE_ReadRegister (channel , ATA_REG_LBA2 );
168
+
169
+ if (cl == 0x14 && ch == 0xEB )
170
+ type = IDE_ATAPI ;
171
+ else if (cl == 0x69 && ch == 0x96 )
172
+ type = IDE_ATAPI ;
173
+ else
174
+ continue ; // Unknown Type (may not be a device).
175
+
176
+ IDE_WriteRegister (channel , ATA_REG_COMMAND , ATA_CMD_IDENTIFY_PACKET );
177
+ TimeDelayMS (1 );
178
+ }
179
+
180
+ // (V) Read Identification Space of the Device:
181
+ IDE_ReadBuffer (channel , ATA_REG_DATA , (uint32_t * )ide_buf , 128 );
182
+
183
+ // (VI) Read Device Parameters:
184
+ ide_devices [driveNumber ].Present = 1 ;
185
+ ide_devices [driveNumber ].Type = type ;
186
+ ide_devices [driveNumber ].Channel = channel ;
187
+ ide_devices [driveNumber ].Drive = device ;
188
+ ide_devices [driveNumber ].Signature = * ((unsigned short * )(ide_buf + ATA_IDENT_DEVICETYPE ));
189
+ ide_devices [driveNumber ].Capabilities = * ((unsigned short * )(ide_buf + ATA_IDENT_CAPABILITIES ));
190
+ ide_devices [driveNumber ].CommandSets = * ((unsigned int * )(ide_buf + ATA_IDENT_COMMANDSETS ));
191
+
192
+ // (VII) Get Size:
193
+ if (ide_devices [driveNumber ].CommandSets & (1 << 26 ))
194
+ // Device uses 48-Bit Addressing:
195
+ ide_devices [driveNumber ].Size = * ((unsigned int * )(ide_buf + ATA_IDENT_MAX_LBA_EXT ));
196
+ else
197
+ // Device uses CHS or 28-bit Addressing:
198
+ ide_devices [driveNumber ].Size = * ((unsigned int * )(ide_buf + ATA_IDENT_MAX_LBA ));
199
+
200
+ // (VIII) String indicates model of device (like Western Digital HDD and SONY DVD-RW...):
201
+ // model string is stored with every two bytes swapped
202
+ for (int k = 0 ; k < IDE_MODEL_STRING_LENGTH ; k += 2 )
203
+ {
204
+ ide_devices [driveNumber ].Model [k ] = ide_buf [ATA_IDENT_MODEL + k + 1 ];
205
+ ide_devices [driveNumber ].Model [k + 1 ] = ide_buf [ATA_IDENT_MODEL + k ];
206
+ }
207
+ ide_devices [driveNumber ].Model [IDE_MODEL_STRING_LENGTH ] = 0 ; // Terminate String.
208
+
209
+ driveNumber ++ ;
210
+ }
211
+ }
212
+
213
+ // 4- Print Summary:
214
+ for (int i = 0 ; i < 4 ; i ++ )
215
+ {
216
+ if (ide_devices [i ].Present == 1 )
217
+ {
218
+ kprintf (" Found %s Drive - %s\n" ,
219
+ ide_devices [i ].Type ? "ATAPI" : "ATA" , // type
220
+ //ide_devices[i].Size / 1024 / 1024 / 2, // size
221
+ ide_devices [i ].Model );
222
+ }
223
+ }
224
+
55
225
kprintf (" IDE controller driver initialized\n" );
56
226
}
57
227
58
- uint8_t ide_polling (uint8_t channel , uint8_t advanced_check )
228
+ uint8_t IDE_PollUntilNotBSY (uint8_t channel , uint8_t advanced_check )
59
229
{
60
230
61
231
// (I) Delay 400 nanosecond for BSY to be set:
62
232
// -------------------------------------------------
63
233
for (int i = 0 ; i < 4 ; i ++ )
64
- ide_read (channel , ATA_REG_ALTSTATUS ); // Reading the Alternate Status port wastes 100ns; loop four times.
234
+ IDE_ReadRegister (channel , ATA_REG_ALTSTATUS ); // Reading the Alternate Status port wastes 100ns; loop four times.
65
235
66
236
// (II) Wait for BSY to be cleared:
67
237
// TODO: add timeout
68
- while (ide_read (channel , ATA_REG_STATUS ) & ATA_SR_BSY )
238
+ while (IDE_ReadRegister (channel , ATA_REG_STATUS ) & ATA_SR_BSY )
69
239
; // Wait for BSY to be zero.
70
240
71
241
if (advanced_check )
72
242
{
73
- uint8_t state = ide_read (channel , ATA_REG_STATUS ); // Read Status Register.
243
+ uint8_t state = IDE_ReadRegister (channel , ATA_REG_STATUS ); // Read Status Register.
74
244
75
245
// (III) Check For Errors:
76
246
if (state & ATA_SR_ERR )
@@ -89,13 +259,13 @@ uint8_t ide_polling(uint8_t channel, uint8_t advanced_check)
89
259
return 0 ; // No Error.
90
260
}
91
261
92
- uint8_t ide_read (uint8_t channel , uint8_t reg )
262
+ uint8_t IDE_ReadRegister (uint8_t channel , uint8_t reg )
93
263
{
94
- uint8_t result ;
264
+ uint8_t result = 0 ;
95
265
96
- // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
266
+ // If we're reading from register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
97
267
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5 )
98
- ide_write (channel , ATA_REG_CONTROL , 0x80 | channels [channel ].disableInterrupts );
268
+ IDE_WriteRegister (channel , ATA_REG_CONTROL , 0x80 | channels [channel ].disableInterrupts );
99
269
100
270
if (reg <= ATA_REG_COMMAND )
101
271
result = inb (channels [channel ].base + reg - 0x00 );
@@ -106,18 +276,47 @@ uint8_t ide_read(uint8_t channel, uint8_t reg)
106
276
else if (reg < 0x16 )
107
277
result = inb (channels [channel ].bmide + reg - 0x0E );
108
278
109
- // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
279
+ // If we're reading from register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
110
280
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5 )
111
- ide_write (channel , ATA_REG_CONTROL , channels [channel ].disableInterrupts );
281
+ IDE_WriteRegister (channel , ATA_REG_CONTROL , channels [channel ].disableInterrupts );
112
282
113
283
return result ;
114
284
}
115
285
116
- void ide_write (uint8_t channel , uint8_t reg , uint8_t data )
286
+ // TODO: Adapted from OSDev.org, need to rewrite in my own style
287
+ void IDE_ReadBuffer (uint8_t channel , uint8_t reg , uint32_t * buffer , unsigned int quads )
288
+ {
289
+ if (reg > 0x07 && reg < 0x0C )
290
+ IDE_WriteRegister (channel , ATA_REG_CONTROL , 0x80 | channels [channel ].disableInterrupts );
291
+
292
+ for (unsigned int i = 0 ; i < quads ; ++ i )
293
+ {
294
+ if (reg < 0x08 )
295
+ buffer [i ] = inl (channels [channel ].base + reg - 0x00 );
296
+ else if (reg < 0x0C )
297
+ buffer [i ] = inl (channels [channel ].base + reg - 0x06 );
298
+ else if (reg < 0x0E )
299
+ buffer [i ] = inl (channels [channel ].ctrl + reg - 0x0A );
300
+ else if (reg < 0x16 )
301
+ buffer [i ] = inl (channels [channel ].bmide + reg - 0x0E );
302
+ }
303
+
304
+ if (reg > 0x07 && reg < 0x0C )
305
+ IDE_WriteRegister (channel , ATA_REG_CONTROL , channels [channel ].disableInterrupts );
306
+ }
307
+
308
+ void IDE_WaitForIRQ ()
309
+ {
310
+ while (!ide_irq_invoked )
311
+ ;
312
+ ide_irq_invoked = false;
313
+ }
314
+
315
+ void IDE_WriteRegister (uint8_t channel , uint8_t reg , uint8_t data )
117
316
{
118
- // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
317
+ // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
119
318
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5 )
120
- ide_write (channel , ATA_REG_CONTROL , 0x80 | channels [channel ].disableInterrupts );
319
+ IDE_WriteRegister (channel , ATA_REG_CONTROL , 0x80 | channels [channel ].disableInterrupts );
121
320
122
321
if (reg <= ATA_REG_COMMAND )
123
322
outb (channels [channel ].base + reg - 0x00 , data );
@@ -128,7 +327,7 @@ void ide_write(uint8_t channel, uint8_t reg, uint8_t data)
128
327
else if (reg < 0x16 )
129
328
outb (channels [channel ].bmide + reg - 0x0E , data );
130
329
131
- // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
330
+ // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
132
331
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5 )
133
- ide_write (channel , ATA_REG_CONTROL , channels [channel ].disableInterrupts );
332
+ IDE_WriteRegister (channel , ATA_REG_CONTROL , channels [channel ].disableInterrupts );
134
333
}
0 commit comments