1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
#include "FloppyController.class.h"
#include "FloppyDrive.class.h"
#include <TaskManager/Task.ns.h>
#include <DeviceManager/Dev.ns.h>
#include <VFS/Part.ns.h>
using namespace Sys; //For outb/inb
//***********************************************************
// STATIC, FOR DMA
//***********************************************************
Mutex FloppyController::dmaMutex(false);
u8int FloppyController::dmabuff[FLOPPY_DMALEN]
__attribute__((aligned(0x8000)));
bool FloppyController::dmaInit(u8int direction, u32int length) {
dmaMutex.waitLock();
union {
u8int b[4];
u32int l;
} a, c; //Address, count
//We want the physical address of dmabuff. We simply remove 0xC0000000, because we've mapped memory linearly.
a.l = (u32int) &dmabuff - 0xC0000000;
c.l = (u32int) length - 1;
if (
(a.l >> 24) || //Address must be under 16mb
(c.l >> 16) || //Count must be < 64k
(((a.l & 0xFFFF) + c.l) >> 16) //We must not cross a 64k boundary
) { //Something is wrong
dmaMutex.unlock();
return false;
}
u8int mode;
switch (direction) {
case FD_READ:
mode = 0x46;
break;
case FD_WRITE:
mode = 0x4A;
break;
default: //Invalid direction
dmaMutex.unlock();
return false;
}
outb(0x0a, 0x06); //Mask chan 2
outb(0x0c, 0xff); //Reset flip-flop
outb(0x04, a.b[0]); //Address low
outb(0x04, a.b[1]); //Address high
outb(0x81, a.b[2]); //External page register
outb(0x0c, 0xff); //Reset flip-flop
outb(0x05, c.b[0]); //Count low
outb(0x05, c.b[1]); //Count high
outb(0x0b, mode); //Mode
outb(0x0a, 0x02); //Unmask chan 2
return true;
}
void FloppyController::dmaRelease() {
dmaMutex.unlock();
}
//*********************************************************
// FOR THE CONTROLLER
//*********************************************************
u32int floppyMotorTimer(void* plop) { //This will be an independant thread
while(1) {
Task::currThread()->sleep(1000); //Check only every second
Vector<Device*> floppys = Dev::findDevices("block.floppy");
for (u32int i = 0; i < floppys.size(); i++) {
FloppyDrive* f = (FloppyDrive*)floppys[i];
if (f->m_motorTimeout > 0 && f->m_motorState == FS_MOTORWAIT) {
f->m_motorTimeout--;
if (f->m_motorTimeout == 0)
f->killMotor();
}
}
}
return 0;
}
FloppyController::FloppyController(u32int base, u8int irq) : m_driveMutex(false) {
m_activeDrive = 0;
m_base = base;
m_irq = irq;
m_drives[0] = NULL;
m_drives[1] = NULL;
m_first = false;
Dev::requestIRQ(this, m_irq);
}
void FloppyController::detect() { //TODO : do this better
FloppyController *fdc = new FloppyController(0x03F0, 6); //Standard controller, IRQ6 and base port 0x03F0
Dev::registerDevice(fdc);
outb(0x70, 0x10); //CMOS detect
u8int drives = inb(0x71);
u8int fdd0 = (drives >> 4), fdd1 = (drives & 0x0F);
if (fdd0 != FT_NONE)
Dev::registerDevice(new FloppyDrive(fdc, 0, fdd0));
if (fdd1 != FT_NONE)
Dev::registerDevice(new FloppyDrive(fdc, 1, fdd1));
fdc->reset();
Vector<Device*> fdds = Dev::findDevices("block.floppy");
for (u32int i = 0; i < fdds.size(); i++) {
Part::registerDevice((BlockDevice*)fdds[i]);
}
new Thread(floppyMotorTimer, 0, true);
}
String FloppyController::getClass() {
return "controller.floppy";
}
String FloppyController::getName() {
String irq = String::number(m_irq);
return String("Floppy controller at IRQ ") += irq;
}
void FloppyController::checkInterrupt(int *st0, int *cyl) {
writeCmd(FC_SENSE_INTERRUPT);
*st0 = readData();
*cyl = readData();
}
void FloppyController::setDOR() {
u8int dor = 0x0C;
if (m_activeDrive == 1)
dor |= 0x01;
if (m_drives[0] != NULL and m_drives[0]->m_motorState != 0)
dor |= 0x10;
if (m_drives[1] != NULL and m_drives[1]->m_motorState != 0)
dor |= 0x20;
resetIrq();
outb(m_base + FR_DOR, dor);
if (m_first) { //First time we set the DOR, controller initialized
waitIrq();
int st0, cyl;
checkInterrupt(&st0, &cyl);
m_first = false;
}
}
void FloppyController::setActiveDrive(u8int drive) {
m_driveMutex.waitLock();
m_activeDrive = drive;
setDOR();
}
void FloppyController::setNoActiveDrive() {
m_driveMutex.unlock();
}
bool FloppyController::writeCmd(u8int cmd) {
for (int i = 0; i < 600; i++) {
if (0x80 & inb(m_base + FR_MSR)) {
outb(m_base + FR_FIFO, cmd);
return true;
}
Task::currThread()->sleep(10);
}
return false;
}
u8int FloppyController::readData() {
for (int i = 0; i < 600; i++) {
if (0x80 & inb(m_base + FR_MSR)) {
return inb(m_base + FR_FIFO);
}
Task::currThread()->sleep(10);
}
return 0;
}
bool FloppyController::reset() {
outb(m_base + FR_DOR, 0x00); //Disable controller
m_first = true;
if (m_drives[0] != NULL) m_drives[0]->m_motorState = 0;
if (m_drives[1] != NULL) m_drives[1]->m_motorState = 0;
setNoActiveDrive();
for (int i = 0; i < 2; i++) {
if (m_drives[i] != NULL) {
if (!m_drives[i]->setup())
return false;
}
}
return true;
}
void FloppyController::handleIRQ(registers_t regs, int irq) {
m_irqHappened = true;
}
void FloppyController::waitIrq() {
while (!m_irqHappened) Task::currThread()->sleep(10);
}
|