-
Notifications
You must be signed in to change notification settings - Fork 0
/
fdc.c
240 lines (197 loc) · 5.23 KB
/
fdc.c
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/* Floppy Disk Controlelr Driver.
*
* The following code was ported from FDCDriver.{h,cpp}
* of the MONA operating system (Revision 5332).
* http://www.monaos.org
*
* This code could run only on Qemu.
*/
#define FDC_DMA_BUF_ADDR 0x80000
#define FDC_DMA_BUF_SIZE 512
#define FDC_DOR_PRIMARY 0x3f2
#define FDC_MSR_PRIMARY 0x3f4
#define FDC_DR_PRIMARY 0x3f5
#define FDC_CCR_PRIMARY 0x3f7
#define FDC_DMA_S_SMR 0x0a
#define FDC_DMA_S_MR 0x0b
#define FDC_DMA_S_CBP 0x0c
#define FDC_DMA_S_BASE 0x04
#define FDC_DMA_S_COUNT 0x05
#define FDC_DMA_PAGE2 0x81
#define FDC_MOTA_START 0x10
#define FDC_DMA_ENABLE 0x08
#define FDC_REST_ENABLE 0x04
#define FDC_DR_SELECT_A 0x00
#define FDC_START_MOTOR (FDC_DMA_ENABLE | FDC_MOTA_START | FDC_REST_ENABLE | FDC_DR_SELECT_A)
#define FDC_STOP_MOTOR (FDC_DMA_ENABLE | FDC_REST_ENABLE | FDC_DR_SELECT_A)
#define FDC_COMMAND_SPECIFY 0x03
#define FDC_COMMAND_READ 0xe6
#define FDC_COMMAND_WRITE 0xc5
int fdc_initialize();
int fdc_read(int cylinder, int head, int sector);
int fdc_read2();
int fdc_write(int cylinder, int head, int sector);
int fdc_write2();
static void fdc_send_command(char* command, int length);
static void fdc_stop_dma();
static void fdc_setup_dma_read(char* buf, int size);
static void fdc_setup_dma_write(char* buf, int size);
static void fdc_motor(int on);
static void fdc_send_command(char* command, int length);
static char fdc_get_result();
static void fdc_wait_status(char mask, char status);
static void fdc_delay(int c);
int fdc_initialize() {
char cmd[3];
cmd[0] = FDC_COMMAND_SPECIFY;
cmd[1] = 0xC1; /* SRT=4ms, HUT=16ms */
cmd[2] = 0x10; /* HLT=16ms DMA */
out8(0xda, 0x00);
fdc_delay(1);
out8(0x0d, 0x00);
fdc_delay(1);
out8(0xd0, 0x00);
fdc_delay(1);
out8(0x08, 0x00);
fdc_delay(1);
out8(0xd6, 0xc0);
fdc_delay(1);
out8(0x0b, 0x46);
fdc_delay(1);
out8(0xd4, 0x00);
fdc_delay(1);
out8(FDC_CCR_PRIMARY, 0);
fdc_motor(1); /* on */
fdc_send_command(cmd, sizeof(cmd));
fdc_motor(0); /* off */
return 0;
}
/* cylinder: 0..
head: 0 or 1
sector: 1..18
If the sector is the n-th logical sector, then it is:
cylinder = n / (18 * 2),
head = (n / 18) % 2,
sector = 1 + n % 18.
*/
int fdc_read(int cylinder, int head, int sector) {
char cmd[9];
cmd[0] = FDC_COMMAND_READ;
cmd[1] = (char)((head & 1) << 2);
cmd[2] = (char)cylinder;
cmd[3] = (char)head;
cmd[4] = (char)sector;
cmd[5] = 0x02;
cmd[6] = 0x12;
cmd[7] = 0x1b;
cmd[8] = 0xff;
/* seek(cylinder); */
fdc_setup_dma_read((char*)FDC_DMA_BUF_ADDR, FDC_DMA_BUF_SIZE);
fdc_send_command(cmd, sizeof(cmd));
return 0;
}
int fdc_read2() {
char results[7];
int i;
for (i = 0; i < 7; i++)
results[i] = fdc_get_result();
fdc_stop_dma();
return results[0] & 0xc0 == 0; /* 0 if error */
}
/* cylinder: 0..
head: 0 or 1
sector: 1..18
If the sector is the n-th logical sector, then it is:
cylinder = n / (18 * 2),
head = (n / 18) % 2,
sector = 1 + n % 18.
*/
int fdc_write(int cylinder, int head, int sector) {
char cmd[9];
cmd[0] = FDC_COMMAND_WRITE;
cmd[1] = (char)((head & 1) << 2);
cmd[2] = (char)cylinder;
cmd[3] = (char)head;
cmd[4] = (char)sector;
cmd[5] = (char)0x02;
cmd[6] = (char)0x12;
cmd[7] = (char)0x1b;
cmd[8] = (char)0x00;
fdc_setup_dma_write((char*)FDC_DMA_BUF_ADDR, FDC_DMA_BUF_SIZE);
/* seek(cylinder); */
fdc_send_command(cmd, sizeof(cmd));
return 0;
}
int fdc_write2() {
int i;
char results[7];
fdc_stop_dma();
for (i = 0; i < 7; i++)
results[i] = fdc_get_result();
return results[0] & 0xc0 == 0; /* 0 if error */
}
static void fdc_start_dma() {
/* mask channel 2 */
out8(FDC_DMA_S_SMR, 0x02);
}
static void fdc_stop_dma() {
/* unmask channel2 */
out8(FDC_DMA_S_SMR, 0x06);
}
static void fdc_setup_dma_read(char* buffer, int size) {
int buf = (int)buffer;
size--;
fdc_stop_dma();
/* write */
out8(FDC_DMA_S_MR, 0x46);
out8(FDC_DMA_S_CBP, 0);
out8(FDC_DMA_S_BASE, buf & 0xff);
out8(FDC_DMA_S_BASE, (buf >> 8) & 0xff);
out8(FDC_DMA_S_COUNT, size & 0xff);
out8(FDC_DMA_S_COUNT, (size >>8) & 0xff);
out8(FDC_DMA_PAGE2, (buf >>16) & 0xff);
fdc_start_dma();
}
static void fdc_setup_dma_write(char* buffer, int size) {
int buf = (int)buffer;
size--;
fdc_stop_dma();
/* read */
out8(FDC_DMA_S_MR, 0x4a);
out8(FDC_DMA_S_CBP, 0);
out8(FDC_DMA_S_BASE, buf & 0xff);
out8(FDC_DMA_S_BASE, (buf >> 8) & 0xff);
out8(FDC_DMA_S_COUNT, size & 0xff);
out8(FDC_DMA_S_COUNT, (size >> 8) & 0xff);
out8(FDC_DMA_PAGE2 , (buf >>16) & 0xff);
fdc_start_dma();
}
static void fdc_motor(int on) {
if (on) {
out8(FDC_DOR_PRIMARY, FDC_START_MOTOR);
fdc_delay(4);
}
else
out8(FDC_DOR_PRIMARY, FDC_STOP_MOTOR);
}
static void fdc_send_command(char* command, int length) {
int i;
for (i = 0; i < length; i++) {
fdc_wait_status(0x80 | 0x40, 0x80);
out8(FDC_DR_PRIMARY, command[i]);
}
}
static char fdc_get_result() {
fdc_wait_status(0xd0, 0xd0);
return in8(FDC_DR_PRIMARY);
}
static void fdc_wait_status(char mask, char status) {
char current;
do {
current = in8(FDC_MSR_PRIMARY);
} while ((current & mask) != status);
}
static void fdc_delay(int c) {
while (c-- > 0)
in8(0x80);
}