This source file includes following definitions.
- floppy_change
- setup_DMA
- output_byte
- result
- seek_interrupt
- rw_interrupt
- transfer
- recal_interrupt
- unexpected_floppy_interrupt
- reset_interrupt
- reset_floppy
- floppy_on_interrupt
- do_fd_request
- floppy_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include <linux/sched.h>
19 #include <linux/fs.h>
20 #include <linux/kernel.h>
21 #include <linux/fdreg.h>
22 #include <asm/system.h>
23 #include <asm/io.h>
24 #include <asm/segment.h>
25
26 #define MAJOR_NR 2
27 #include "blk.h"
28
29 static void reset_floppy(void);
30 static void seek_interrupt(void);
31 static void rw_interrupt(void);
32
33 extern unsigned char current_DOR;
34 extern unsigned char selected;
35
36 #define immoutb_p(val,port) \
37 __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
38
39 #define TYPE(x) ((x)>>2)
40 #define DRIVE(x) ((x)&0x03)
41
42
43
44
45
46 #define MAX_ERRORS 10
47
48
49
50
51 #define MAX_REPLIES 7
52 static unsigned char reply_buffer[MAX_REPLIES];
53 #define ST0 (reply_buffer[0])
54 #define ST1 (reply_buffer[1])
55 #define ST2 (reply_buffer[2])
56 #define ST3 (reply_buffer[3])
57
58
59
60
61
62
63
64
65
66
67 static struct floppy_struct {
68 int size, sect, head, track, stretch;
69 unsigned char gap,rate,spec1;
70 } floppy_type[] = {
71 { 0, 0,0, 0,0,0x00,0x00,0x00 },
72 { 720, 9,2,40,0,0x2A,0x02,0xDF },
73 { 2400,15,2,80,0,0x1B,0x00,0xDF },
74 { 720, 9,2,40,1,0x2A,0x02,0xDF },
75 { 1440, 9,2,80,0,0x2A,0x02,0xDF },
76 { 720, 9,2,40,1,0x23,0x01,0xDF },
77 { 1440, 9,2,80,0,0x23,0x01,0xDF },
78 { 2880,18,2,80,0,0x1B,0x00,0xCF },
79 };
80
81
82
83
84
85
86
87
88
89 extern void floppy_interrupt(void);
90 extern char tmp_floppy_area[1024];
91
92
93
94
95
96
97 static int cur_spec1 = -1;
98 static int cur_rate = -1;
99 static struct floppy_struct * floppy = floppy_type;
100 static unsigned char current_drive = 0;
101 static unsigned char sector = 0;
102 static unsigned char head = 0;
103 static unsigned char track = 0;
104 static unsigned char seek_track = 0;
105 static unsigned char command = 0;
106
107
108
109
110
111 int floppy_change(unsigned int nr)
112 {
113 floppy_on(nr);
114 floppy_select(nr);
115 if (inb(FD_DIR) & 0x80) {
116 floppy_off(nr);
117 return 1;
118 }
119 floppy_off(nr);
120 return 0;
121 }
122
123 #define copy_buffer(from,to) \
124 __asm__("cld ; rep ; movsl" \
125 ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
126 :"cx","di","si")
127
128 static void setup_DMA(void)
129 {
130 long addr = (long) CURRENT->buffer;
131
132 if (addr >= 0x100000) {
133 addr = (long) tmp_floppy_area;
134 if (command == FD_WRITE)
135 copy_buffer(CURRENT->buffer,tmp_floppy_area);
136 }
137
138 immoutb_p(4|2,10);
139
140
141 __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
142 "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
143 "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
144
145 immoutb_p(addr,4);
146 addr >>= 8;
147
148 immoutb_p(addr,4);
149 addr >>= 8;
150
151 immoutb_p(addr,0x81);
152
153 immoutb_p(0xff,5);
154
155 immoutb_p(3,5);
156
157 immoutb_p(0|2,10);
158 }
159
160 static void output_byte(char byte)
161 {
162 int counter;
163 unsigned char status;
164
165 for(counter = 0 ; counter < 10000 ; counter++) {
166 status = inb(FD_STATUS) & (STATUS_READY | STATUS_DIR);
167 if (status == STATUS_READY) {
168 outb(byte,FD_DATA);
169 return;
170 }
171 }
172 printk("Unable to send byte to FDC\n\r");
173 }
174
175 static int result(void)
176 {
177 int i = 0, counter, status;
178
179 for (counter = 0 ; counter < 10000 ; counter++) {
180 status = inb(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
181 if (status == STATUS_READY)
182 return i;
183 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
184 if (i >= MAX_REPLIES)
185 break;
186 reply_buffer[i++] = inb(FD_DATA);
187 }
188 }
189 printk("Getstatus times out\n\r");
190 return -1;
191 }
192
193
194
195
196
197
198 static void seek_interrupt(void)
199 {
200
201 output_byte(FD_SENSEI);
202 if (result() != 2 || (ST0 & 0xF8) != 0x20) {
203 CURRENT->errors++;
204 if (CURRENT->errors > MAX_ERRORS) {
205 floppy_deselect(current_drive);
206 end_request(0);
207 reset_floppy();
208 return;
209 }
210 output_byte(FD_RECALIBRATE);
211 output_byte(head<<2 | current_drive);
212 return;
213 }
214
215 if (ST1 != seek_track) {
216 CURRENT->errors++;
217 if (CURRENT->errors > MAX_ERRORS) {
218 floppy_deselect(current_drive);
219 end_request(0);
220 reset_floppy();
221 return;
222 }
223 output_byte(FD_SEEK);
224 output_byte(head<<2 | current_drive);
225 output_byte(seek_track);
226 return;
227 }
228
229 setup_DMA();
230 do_floppy = rw_interrupt;
231 output_byte(command);
232 output_byte(head<<2 | current_drive);
233 output_byte(track);
234 output_byte(head);
235 output_byte(sector);
236 output_byte(2);
237 output_byte(floppy->sect);
238 output_byte(floppy->gap);
239 output_byte(0xFF);
240 }
241
242
243
244
245
246 static void rw_interrupt(void)
247 {
248 if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) ||
249 (ST2 & 0x73)) {
250 CURRENT->errors++;
251 if (CURRENT->errors > MAX_ERRORS || (ST1 & 0x02)) {
252 if (ST1 & 0x02)
253 printk("Drive %d is write protected\n\r",
254 current_drive);
255 floppy_deselect(current_drive);
256 end_request(0);
257 do_fd_request();
258 return;
259 }
260 do_floppy = seek_interrupt;
261 output_byte(FD_RECALIBRATE);
262 output_byte(head<<2 | current_drive);
263 return;
264 }
265 if (command == FD_READ && (long)(CURRENT->buffer) >= 0x100000)
266 copy_buffer(tmp_floppy_area,CURRENT->buffer);
267 floppy_deselect(current_drive);
268 end_request(1);
269 do_fd_request();
270 }
271
272
273
274
275
276
277 static void transfer(void)
278 {
279 if (cur_spec1 != floppy->spec1) {
280 cur_spec1 = floppy->spec1;
281 output_byte(FD_SPECIFY);
282 output_byte(cur_spec1);
283 output_byte(6);
284 }
285 if (cur_rate != floppy->rate)
286 outb_p(cur_rate = floppy->rate,FD_DCR);
287 do_floppy = seek_interrupt;
288 if (seek_track) {
289 output_byte(FD_SEEK);
290 output_byte(head<<2 | current_drive);
291 output_byte(seek_track);
292 } else {
293 output_byte(FD_RECALIBRATE);
294 output_byte(head<<2 | current_drive);
295 }
296 }
297
298
299
300
301 static void recal_interrupt(void)
302 {
303 do_floppy = NULL;
304 output_byte(FD_SENSEI);
305 if (result()!=2 || (ST0 & 0xE0) == 0x60) {
306 reset_floppy();
307 return;
308 }
309 do_fd_request();
310 }
311
312 void unexpected_floppy_interrupt(void)
313 {
314 output_byte(FD_SENSEI);
315 if (result()!=2 || (ST0 & 0xE0) == 0x60) {
316 reset_floppy();
317 return;
318 }
319 do_floppy = recal_interrupt;
320 output_byte(FD_RECALIBRATE);
321 output_byte(head<<2 | current_drive);
322 }
323
324 static void reset_interrupt(void)
325 {
326 output_byte(FD_SENSEI);
327 (void) result();
328 do_floppy = recal_interrupt;
329 output_byte(FD_RECALIBRATE);
330 output_byte(head<<2 | current_drive);
331 }
332
333 static void reset_floppy(void)
334 {
335 printk("Reset-floppy called\n\r");
336 do_floppy = reset_interrupt;
337 outb_p(0,FD_DOR);
338 outb(current_DOR,FD_DOR);
339 }
340
341 static void floppy_on_interrupt(void)
342 {
343
344 selected = 1;
345 current_DOR &= 0xFC;
346 current_DOR |= current_drive;
347 transfer();
348 }
349
350 void do_fd_request(void)
351 {
352 unsigned int block;
353
354 INIT_REQUEST;
355 floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
356 current_drive = CURRENT_DEV;
357 block = CURRENT->sector;
358 if (block+2 > floppy->size) {
359 end_request(0);
360 goto repeat;
361 }
362 sector = block % floppy->sect;
363 block /= floppy->sect;
364 head = block % floppy->head;
365 track = block / floppy->head;
366 seek_track = track << floppy->stretch;
367 sector++;
368 if (CURRENT->cmd == READ)
369 command = FD_READ;
370 else if (CURRENT->cmd == WRITE)
371 command = FD_WRITE;
372 else
373 panic("do_fd_request: unknown command");
374 add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
375 }
376
377 void floppy_init(void)
378 {
379 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
380 set_intr_gate(0x26,&floppy_interrupt);
381 outb(inb_p(0x21)&~0x40,0x21);
382 }