Rev 8055 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2288 | clevermous | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
5363 | yogev_ezra | 3 | ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; |
2288 | clevermous | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
7 | |||
8 | $Revision: 9932 $ |
||
9 | |||
10 | |||
11 | ;********************************************************** |
||
8054 | rgimad | 12 | ; Direct work with floppy disk drive |
2288 | clevermous | 13 | ;********************************************************** |
8055 | rgimad | 14 | ; Source code author - Kulakov Vladimir Gennadievich. |
15 | ; Adaptation and improvement - Mario79. |
||
2288 | clevermous | 16 | |
17 | give_back_application_data_1: |
||
18 | mov esi, FDD_BUFF;FDD_DataBuffer ;0x40000 |
||
4273 | clevermous | 19 | mov ecx, 128 |
2288 | clevermous | 20 | cld |
21 | rep movsd |
||
22 | ret |
||
23 | |||
24 | take_data_from_application_1: |
||
25 | mov edi, FDD_BUFF;FDD_DataBuffer ;0x40000 |
||
4273 | clevermous | 26 | mov ecx, 128 |
2288 | clevermous | 27 | cld |
28 | rep movsd |
||
29 | ret |
||
30 | |||
8054 | rgimad | 31 | ; Controller operations result codes (FDC_Status) |
32 | FDC_Normal = 0 ; normal finish |
||
33 | FDC_TimeOut = 1 ; time out error |
||
34 | FDC_DiskNotFound = 2 ; no disk in drive |
||
35 | FDC_TrackNotFound = 3 ; track not found |
||
36 | FDC_SectorNotFound = 4 ; sector not found |
||
2288 | clevermous | 37 | |
8054 | rgimad | 38 | ; Maximum values of the sector coordinates (specified |
39 | ; values correspond to the parameters of the standard |
||
40 | ; 3-inch 1.44 MB floppy disk) |
||
7136 | dunkaist | 41 | MAX_Track = 79 |
42 | MAX_Head = 1 |
||
43 | MAX_Sector = 18 |
||
2288 | clevermous | 44 | |
45 | uglobal |
||
8054 | rgimad | 46 | ; Timer tick counter |
2288 | clevermous | 47 | TickCounter dd ? |
8054 | rgimad | 48 | ; Operation completion code with the floppy disk drive controller |
2288 | clevermous | 49 | FDC_Status DB ? |
8054 | rgimad | 50 | ; Interrupt flag from floppy disk drive |
2288 | clevermous | 51 | FDD_IntFlag DB ? |
8054 | rgimad | 52 | ; The moment of the beginning of the last operation with FDD |
2288 | clevermous | 53 | FDD_Time DD ? |
8054 | rgimad | 54 | ; Drive number |
2288 | clevermous | 55 | FDD_Type db 0 |
8054 | rgimad | 56 | ; Sector coordinates |
2288 | clevermous | 57 | FDD_Track DB ? |
58 | FDD_Head DB ? |
||
59 | FDD_Sector DB ? |
||
60 | |||
8054 | rgimad | 61 | ; Operation result block |
2288 | clevermous | 62 | FDC_ST0 DB ? |
63 | FDC_ST1 DB ? |
||
64 | FDC_ST2 DB ? |
||
65 | FDC_C DB ? |
||
66 | FDC_H DB ? |
||
67 | FDC_R DB ? |
||
68 | FDC_N DB ? |
||
8054 | rgimad | 69 | ; Read operation repetition counter |
2288 | clevermous | 70 | ReadRepCounter DB ? |
8054 | rgimad | 71 | ; Recalibration operation repetition counter |
2288 | clevermous | 72 | RecalRepCounter DB ? |
73 | endg |
||
8054 | rgimad | 74 | ; Memory area for storing the readed sector |
2288 | clevermous | 75 | ;FDD_DataBuffer: times 512 db 0 ;DB 512 DUP (?) |
76 | fdd_motor_status db 0 |
||
77 | timer_fdd_motor dd 0 |
||
78 | |||
8054 | rgimad | 79 | ;************************************** |
80 | ;* INITIALIZATION OF DMA MODE FOR FDD * |
||
81 | ;************************************** |
||
2288 | clevermous | 82 | Init_FDC_DMA: |
83 | pushad |
||
84 | mov al, 0 |
||
85 | out 0x0c, al; reset the flip-flop to a known state. |
||
86 | mov al, 6 ; mask channel 2 so we can reprogram it. |
||
87 | out 0x0a, al |
||
88 | mov al, [dmamode]; 0x46 -> Read from floppy - 0x4A Write to floppy |
||
89 | out 0x0b, al |
||
90 | mov al, 0 |
||
91 | out 0x0c, al; reset the flip-flop to a known state. |
||
92 | mov eax, 0xD000 |
||
93 | out 0x04, al; set the channel 2 starting address to 0 |
||
94 | shr eax, 8 |
||
95 | out 0x04, al |
||
96 | shr eax, 8 |
||
97 | out 0x81, al |
||
98 | mov al, 0 |
||
99 | out 0x0c, al; reset flip-flop |
||
100 | mov al, 0xff;set count (actual size -1) |
||
101 | out 0x5, al |
||
102 | mov al, 0x1;[dmasize] ;(0x1ff = 511 / 0x23ff =9215) |
||
103 | out 0x5, al |
||
104 | mov al, 2 |
||
105 | out 0xa, al |
||
106 | popad |
||
107 | ret |
||
108 | |||
109 | ;*********************************** |
||
8054 | rgimad | 110 | ;* WRITE BYTE TO FDC DATA PORT * |
111 | ;* Parameters: * |
||
112 | ;* AL - byte to write. * |
||
2288 | clevermous | 113 | ;*********************************** |
114 | FDCDataOutput: |
||
4273 | clevermous | 115 | ; DEBUGF 1,'K : FDCDataOutput(%x)',al |
2288 | clevermous | 116 | ; pusha |
117 | push eax ecx edx |
||
8054 | rgimad | 118 | mov AH, AL ; remember byte to AH |
119 | ; Reset controller state variable |
||
2288 | clevermous | 120 | mov [FDC_Status], FDC_Normal |
8054 | rgimad | 121 | ; Check the readiness of the controller to receive data |
122 | mov DX, 3F4h ; (FDC state port) |
||
123 | mov ecx, 0x10000 ; set timeout counter |
||
2288 | clevermous | 124 | @@TestRS: |
8054 | rgimad | 125 | in AL, DX ; read the RS register |
126 | and AL, 0C0h ; get digits 6 and 7 |
||
127 | cmp AL, 80h ; check digits 6 and 7 |
||
2288 | clevermous | 128 | je @@OutByteToFDC |
129 | loop @@TestRS |
||
8054 | rgimad | 130 | ; Time out error |
4273 | clevermous | 131 | ; DEBUGF 1,' timeout\n' |
2288 | clevermous | 132 | mov [FDC_Status], FDC_TimeOut |
133 | jmp @@End_5 |
||
8054 | rgimad | 134 | ; Write byte to data port |
2288 | clevermous | 135 | @@OutByteToFDC: |
136 | inc DX |
||
137 | mov AL, AH |
||
138 | out DX, AL |
||
4273 | clevermous | 139 | ; DEBUGF 1,' ok\n' |
2288 | clevermous | 140 | @@End_5: |
141 | ; popa |
||
142 | pop edx ecx eax |
||
143 | ret |
||
144 | |||
145 | ;****************************************** |
||
8054 | rgimad | 146 | ;* READ BYTE FROM FDC DATA PORT * |
147 | ;* Procedure doesnt have input params. * |
||
148 | ;* Output : * |
||
149 | ;* AL - byte read. * |
||
2288 | clevermous | 150 | ;****************************************** |
151 | FDCDataInput: |
||
152 | push ECX |
||
153 | push DX |
||
8054 | rgimad | 154 | ; Reset controller state variable |
2288 | clevermous | 155 | mov [FDC_Status], FDC_Normal |
8054 | rgimad | 156 | ; Check the readiness of the controller to receive data |
157 | mov DX, 3F4h ;(FDC state port) |
||
158 | mov ecx, 0x10000 ; set timeout counter |
||
2288 | clevermous | 159 | @@TestRS_1: |
8054 | rgimad | 160 | in AL, DX ; read the RS register |
161 | and AL, 0C0h ; get digits 6 and 7 |
||
162 | cmp AL, 0C0h ; check digits 6 and 7 |
||
2288 | clevermous | 163 | je @@GetByteFromFDC |
164 | loop @@TestRS_1 |
||
8054 | rgimad | 165 | ; Time out error |
4273 | clevermous | 166 | ; DEBUGF 1,'K : FDCDataInput: timeout\n' |
2288 | clevermous | 167 | mov [FDC_Status], FDC_TimeOut |
168 | jmp @@End_6 |
||
8054 | rgimad | 169 | ; Get byte from data port |
2288 | clevermous | 170 | @@GetByteFromFDC: |
171 | inc DX |
||
172 | in AL, DX |
||
4273 | clevermous | 173 | ; DEBUGF 1,'K : FDCDataInput: %x\n',al |
2288 | clevermous | 174 | @@End_6: |
175 | pop DX |
||
176 | pop ECX |
||
177 | ret |
||
178 | |||
179 | ;********************************************* |
||
8054 | rgimad | 180 | ;* FDC INTERRUPT HANDLER * |
2288 | clevermous | 181 | ;********************************************* |
182 | FDCInterrupt: |
||
4273 | clevermous | 183 | ; dbgstr 'FDCInterrupt' |
8054 | rgimad | 184 | ; Set the interrupt flag |
2288 | clevermous | 185 | mov [FDD_IntFlag], 1 |
3771 | mario79 | 186 | mov al, 1 |
2288 | clevermous | 187 | ret |
188 | |||
189 | ;******************************************* |
||
8054 | rgimad | 190 | ;* WAIT FOR INTERRUPT FROM FDC * |
2288 | clevermous | 191 | ;******************************************* |
192 | WaitFDCInterrupt: |
||
193 | pusha |
||
8054 | rgimad | 194 | ; Reset operation status byte |
2288 | clevermous | 195 | mov [FDC_Status], FDC_Normal |
8054 | rgimad | 196 | ; Zero out the tick counter |
2288 | clevermous | 197 | mov eax, [timer_ticks] |
198 | mov [TickCounter], eax |
||
8054 | rgimad | 199 | ; Wait for the floppy disk interrupt flag to be set |
2288 | clevermous | 200 | @@TestRS_2: |
3771 | mario79 | 201 | call change_task |
2288 | clevermous | 202 | cmp [FDD_IntFlag], 0 |
8054 | rgimad | 203 | jnz @@End_7 ; interrupt occured |
2288 | clevermous | 204 | mov eax, [timer_ticks] |
205 | sub eax, [TickCounter] |
||
8054 | rgimad | 206 | cmp eax, 200;50 ;25 ;5 ; wait 5 ticks |
2288 | clevermous | 207 | jb @@TestRS_2 |
208 | ; jl @@TestRS_2 |
||
8054 | rgimad | 209 | ; Time out error |
4273 | clevermous | 210 | ; dbgstr 'WaitFDCInterrupt: timeout' |
2288 | clevermous | 211 | mov [FDC_Status], FDC_TimeOut |
212 | @@End_7: |
||
213 | popa |
||
214 | ret |
||
215 | |||
8054 | rgimad | 216 | ;*********************************** |
217 | ;* Turn on the motor of drive "A:" * |
||
218 | ;*********************************** |
||
2288 | clevermous | 219 | FDDMotorON: |
4273 | clevermous | 220 | ; dbgstr 'FDDMotorON' |
2288 | clevermous | 221 | pusha |
222 | ; cmp [fdd_motor_status],1 |
||
223 | ; je fdd_motor_on |
||
224 | mov al, [flp_number] |
||
225 | cmp [fdd_motor_status], al |
||
226 | je fdd_motor_on |
||
8054 | rgimad | 227 | ; Reset the FDD controller |
228 | mov DX, 3F2h ; motor control port |
||
2288 | clevermous | 229 | mov AL, 0 |
230 | out DX, AL |
||
8054 | rgimad | 231 | ; Select and turn on the drive motor |
2288 | clevermous | 232 | cmp [flp_number], 1 |
233 | jne FDDMotorON_B |
||
234 | ; call FDDMotorOFF_B |
||
235 | mov AL, 1Ch ; Floppy A |
||
236 | jmp FDDMotorON_1 |
||
237 | FDDMotorON_B: |
||
238 | ; call FDDMotorOFF_A |
||
239 | mov AL, 2Dh ; Floppy B |
||
240 | FDDMotorON_1: |
||
241 | out DX, AL |
||
8054 | rgimad | 242 | ; Zero out the tick counter |
2288 | clevermous | 243 | mov eax, [timer_ticks] |
244 | mov [TickCounter], eax |
||
8054 | rgimad | 245 | ; wait 0.5 s |
2288 | clevermous | 246 | @@dT: |
247 | call change_task |
||
248 | mov eax, [timer_ticks] |
||
249 | sub eax, [TickCounter] |
||
250 | cmp eax, 50 ;10 |
||
251 | jb @@dT |
||
4273 | clevermous | 252 | ; Read results of RESET command |
253 | push 4 |
||
254 | ; DEBUGF 1,'K : floppy reset results:' |
||
255 | @@: |
||
256 | mov al, 8 |
||
257 | call FDCDataOutput |
||
258 | call FDCDataInput |
||
259 | ; DEBUGF 1,' %x',al |
||
260 | call FDCDataInput |
||
261 | ; DEBUGF 1,' %x',al |
||
262 | dec dword [esp] |
||
263 | jnz @b |
||
264 | ; DEBUGF 1,'\n' |
||
265 | pop eax |
||
2288 | clevermous | 266 | cmp [flp_number], 1 |
267 | jne fdd_motor_on_B |
||
268 | mov [fdd_motor_status], 1 |
||
269 | jmp fdd_motor_on |
||
270 | fdd_motor_on_B: |
||
271 | mov [fdd_motor_status], 2 |
||
272 | fdd_motor_on: |
||
273 | call save_timer_fdd_motor |
||
274 | popa |
||
275 | ret |
||
276 | |||
277 | ;***************************************** |
||
8054 | rgimad | 278 | ;* SAVING TIME STAMP * |
2288 | clevermous | 279 | ;***************************************** |
280 | save_timer_fdd_motor: |
||
281 | mov eax, [timer_ticks] |
||
282 | mov [timer_fdd_motor], eax |
||
283 | ret |
||
284 | |||
285 | ;***************************************** |
||
8054 | rgimad | 286 | ;* CHECK THE MOTOR SHUTDOWN DELAY * |
2288 | clevermous | 287 | ;***************************************** |
3534 | clevermous | 288 | proc check_fdd_motor_status_has_work? |
289 | cmp [fdd_motor_status], 0 |
||
290 | jz .no |
||
291 | mov eax, [timer_ticks] |
||
292 | sub eax, [timer_fdd_motor] |
||
293 | cmp eax, 500 |
||
294 | jb .no |
||
295 | .yes: |
||
296 | xor eax, eax |
||
297 | inc eax |
||
298 | ret |
||
299 | .no: |
||
300 | xor eax, eax |
||
301 | ret |
||
302 | endp |
||
303 | |||
2288 | clevermous | 304 | align 4 |
305 | check_fdd_motor_status: |
||
306 | cmp [fdd_motor_status], 0 |
||
307 | je end_check_fdd_motor_status_1 |
||
308 | mov eax, [timer_ticks] |
||
309 | sub eax, [timer_fdd_motor] |
||
310 | cmp eax, 500 |
||
311 | jb end_check_fdd_motor_status |
||
312 | call FDDMotorOFF |
||
313 | mov [fdd_motor_status], 0 |
||
314 | end_check_fdd_motor_status_1: |
||
315 | end_check_fdd_motor_status: |
||
316 | ret |
||
317 | |||
318 | ;********************************** |
||
8054 | rgimad | 319 | ;* TURN OFF MOTOR OF DRIVE * |
2288 | clevermous | 320 | ;********************************** |
321 | FDDMotorOFF: |
||
4273 | clevermous | 322 | ; dbgstr 'FDDMotorOFF' |
2288 | clevermous | 323 | push AX |
324 | push DX |
||
325 | cmp [flp_number], 1 |
||
326 | jne FDDMotorOFF_1 |
||
327 | call FDDMotorOFF_A |
||
328 | jmp FDDMotorOFF_2 |
||
329 | FDDMotorOFF_1: |
||
330 | call FDDMotorOFF_B |
||
331 | FDDMotorOFF_2: |
||
332 | pop DX |
||
333 | pop AX |
||
8054 | rgimad | 334 | ; clearing caching flags due to information obsolescence |
4273 | clevermous | 335 | or [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN |
336 | or [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN |
||
2288 | clevermous | 337 | ret |
338 | |||
339 | FDDMotorOFF_A: |
||
8054 | rgimad | 340 | mov DX, 3F2h ; motor control port |
341 | mov AL, 0Ch ; Floppy A |
||
2288 | clevermous | 342 | out DX, AL |
343 | ret |
||
344 | |||
345 | FDDMotorOFF_B: |
||
8054 | rgimad | 346 | mov DX, 3F2h ; motor control port |
347 | mov AL, 5h ; Floppy B |
||
2288 | clevermous | 348 | out DX, AL |
349 | ret |
||
350 | |||
351 | ;******************************* |
||
8054 | rgimad | 352 | ;* RECALIBRATE DRIVE "A:" * |
2288 | clevermous | 353 | ;******************************* |
354 | RecalibrateFDD: |
||
4273 | clevermous | 355 | ; dbgstr 'RecalibrateFDD' |
2288 | clevermous | 356 | pusha |
357 | call save_timer_fdd_motor |
||
8054 | rgimad | 358 | ; Clear the interrupt flag |
4273 | clevermous | 359 | mov [FDD_IntFlag], 0 |
8054 | rgimad | 360 | ; Send the "Recalibration" command |
2288 | clevermous | 361 | mov AL, 07h |
362 | call FDCDataOutput |
||
6814 | dunkaist | 363 | mov AL, [flp_number] |
364 | dec AL |
||
2288 | clevermous | 365 | call FDCDataOutput |
8054 | rgimad | 366 | ; Wait for the operation to complete |
2288 | clevermous | 367 | call WaitFDCInterrupt |
4273 | clevermous | 368 | cmp [FDC_Status], 0 |
369 | jne .fail |
||
370 | ; Read results of RECALIBRATE command |
||
371 | ; DEBUGF 1,'K : floppy recalibrate results:' |
||
372 | mov al, 8 |
||
373 | call FDCDataOutput |
||
374 | call FDCDataInput |
||
4695 | clevermous | 375 | push eax |
4273 | clevermous | 376 | ; DEBUGF 1,' %x',al |
377 | call FDCDataInput |
||
378 | ; DEBUGF 1,' %x',al |
||
379 | ; DEBUGF 1,'\n' |
||
4695 | clevermous | 380 | pop eax |
381 | test al, 0xC0 |
||
382 | jz @f |
||
383 | mov [FDC_Status], FDC_DiskNotFound |
||
384 | @@: |
||
4273 | clevermous | 385 | .fail: |
2288 | clevermous | 386 | call save_timer_fdd_motor |
387 | popa |
||
388 | ret |
||
389 | |||
390 | ;***************************************************** |
||
8054 | rgimad | 391 | ;* TRACK SEARCH * |
392 | ;* Parameters are passed through global variables: * |
||
393 | ;* FDD_Track - track number (0-79); * |
||
394 | ;* FDD_Head - head number (0-1). * |
||
395 | ;* Result of operation is written to FDC_Status. * |
||
2288 | clevermous | 396 | ;***************************************************** |
397 | SeekTrack: |
||
4273 | clevermous | 398 | ; dbgstr 'SeekTrack' |
2288 | clevermous | 399 | pusha |
400 | call save_timer_fdd_motor |
||
8054 | rgimad | 401 | ; Clear the interrupt flag |
4115 | mario79 | 402 | mov [FDD_IntFlag], 0 |
8054 | rgimad | 403 | ; Send "Search" command |
2288 | clevermous | 404 | mov AL, 0Fh |
405 | call FDCDataOutput |
||
8054 | rgimad | 406 | ; Send head / drive number byte |
2288 | clevermous | 407 | mov AL, [FDD_Head] |
408 | shl AL, 2 |
||
409 | call FDCDataOutput |
||
8054 | rgimad | 410 | ; Send track number byte |
2288 | clevermous | 411 | mov AL, [FDD_Track] |
412 | call FDCDataOutput |
||
8054 | rgimad | 413 | ; Wait for the operation to complete |
2288 | clevermous | 414 | call WaitFDCInterrupt |
415 | cmp [FDC_Status], FDC_Normal |
||
416 | jne @@Exit |
||
8054 | rgimad | 417 | ; Save search result |
2288 | clevermous | 418 | mov AL, 08h |
419 | call FDCDataOutput |
||
420 | call FDCDataInput |
||
421 | mov [FDC_ST0], AL |
||
422 | call FDCDataInput |
||
423 | mov [FDC_C], AL |
||
8054 | rgimad | 424 | ; Check search result |
425 | ; Is search finished? |
||
2288 | clevermous | 426 | test [FDC_ST0], 100000b |
427 | je @@Err |
||
8054 | rgimad | 428 | ; Is the specified track found? |
2288 | clevermous | 429 | mov AL, [FDC_C] |
430 | cmp AL, [FDD_Track] |
||
431 | jne @@Err |
||
8054 | rgimad | 432 | ; Does the head number match the specified one? |
4273 | clevermous | 433 | ; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet, |
434 | ; description of SEEK command. So we can not verify the proper head. |
||
435 | ; mov AL, [FDC_ST0] |
||
436 | ; and AL, 100b |
||
437 | ; shr AL, 2 |
||
438 | ; cmp AL, [FDD_Head] |
||
439 | ; jne @@Err |
||
8054 | rgimad | 440 | ; Operation completed successfully |
4273 | clevermous | 441 | ; dbgstr 'SeekTrack: FDC_Normal' |
2288 | clevermous | 442 | mov [FDC_Status], FDC_Normal |
443 | jmp @@Exit |
||
8054 | rgimad | 444 | @@Err: ; Track not found |
4273 | clevermous | 445 | ; dbgstr 'SeekTrack: FDC_TrackNotFound' |
2288 | clevermous | 446 | mov [FDC_Status], FDC_TrackNotFound |
447 | @@Exit: |
||
448 | call save_timer_fdd_motor |
||
449 | popa |
||
450 | ret |
||
451 | |||
452 | ;******************************************************* |
||
8054 | rgimad | 453 | ;* READING A DATA SECTOR * |
454 | ;* Parameters are passed through global variables: * |
||
455 | ;* FDD_Track - track number (0-79); * |
||
456 | ;* FDD_Head - head number (0-1); * |
||
457 | ;* FDD_Sector - sector number (1-18). * |
||
458 | ;* Result of operation is written to FDC_Status. * |
||
459 | ;* If the read operation is successful, the contents * |
||
460 | ;* of the sector will be written to FDD_DataBuffer. * |
||
2288 | clevermous | 461 | ;******************************************************* |
462 | ReadSector: |
||
4273 | clevermous | 463 | ; dbgstr 'ReadSector' |
2288 | clevermous | 464 | pushad |
465 | call save_timer_fdd_motor |
||
8054 | rgimad | 466 | ; Clear the interrupt flag |
4115 | mario79 | 467 | mov [FDD_IntFlag], 0 |
8054 | rgimad | 468 | ; Set transmit speed to 500 Kb / s |
2288 | clevermous | 469 | mov AX, 0 |
470 | mov DX, 03F7h |
||
471 | out DX, AL |
||
8054 | rgimad | 472 | ; Initialize the DMA channel |
2288 | clevermous | 473 | mov [dmamode], 0x46 |
474 | call Init_FDC_DMA |
||
8054 | rgimad | 475 | ; Send "Data read" command |
476 | mov AL, 0E6h ; reading in multi-track mode |
||
2288 | clevermous | 477 | call FDCDataOutput |
478 | mov AL, [FDD_Head] |
||
479 | shl AL, 2 |
||
6814 | dunkaist | 480 | or AL, [flp_number] |
481 | dec AL |
||
2288 | clevermous | 482 | call FDCDataOutput |
483 | mov AL, [FDD_Track] |
||
484 | call FDCDataOutput |
||
485 | mov AL, [FDD_Head] |
||
486 | call FDCDataOutput |
||
487 | mov AL, [FDD_Sector] |
||
488 | call FDCDataOutput |
||
8054 | rgimad | 489 | mov AL, 2 ; sector size code (512 byte) |
2288 | clevermous | 490 | call FDCDataOutput |
8054 | rgimad | 491 | mov AL, 18 ;+1; 3Fh ;number of sectors per track |
2288 | clevermous | 492 | call FDCDataOutput |
8054 | rgimad | 493 | mov AL, 1Bh ; GPL value |
2288 | clevermous | 494 | call FDCDataOutput |
8054 | rgimad | 495 | mov AL, 0FFh; DTL value |
2288 | clevermous | 496 | call FDCDataOutput |
8054 | rgimad | 497 | ; Waiting for an interrupt at the end of the operation |
2288 | clevermous | 498 | call WaitFDCInterrupt |
499 | cmp [FDC_Status], FDC_Normal |
||
500 | jne @@Exit_1 |
||
8054 | rgimad | 501 | ; Read the operation completion status |
2288 | clevermous | 502 | call GetStatusInfo |
503 | test [FDC_ST0], 11011000b |
||
504 | jnz @@Err_1 |
||
4273 | clevermous | 505 | ; dbgstr 'ReadSector: FDC_Normal' |
2288 | clevermous | 506 | mov [FDC_Status], FDC_Normal |
507 | jmp @@Exit_1 |
||
508 | @@Err_1: |
||
4273 | clevermous | 509 | ; dbgstr 'ReadSector: FDC_SectorNotFound' |
2288 | clevermous | 510 | mov [FDC_Status], FDC_SectorNotFound |
511 | @@Exit_1: |
||
512 | call save_timer_fdd_motor |
||
513 | popad |
||
514 | ret |
||
515 | |||
516 | ;******************************************************* |
||
8054 | rgimad | 517 | ;* READ SECTOR (WITH RETRY OF OPERATION ON FAILURE) * |
518 | ;* Parameters are passed through global variables: * |
||
519 | ;* FDD_Track - track number (0-79); * |
||
520 | ;* FDD_Head - head number (0-1); * |
||
521 | ;* FDD_Sector - sector number (1-18). * |
||
522 | ;* Result of operation is written to FDC_Status. * |
||
523 | ;* If the read operation is successful, the contents * |
||
524 | ;* of the sector will be written to FDD_DataBuffer. * |
||
2288 | clevermous | 525 | ;******************************************************* |
526 | ReadSectWithRetr: |
||
527 | pusha |
||
8054 | rgimad | 528 | ; Reset the recalibration repetition counter |
2288 | clevermous | 529 | mov [RecalRepCounter], 0 |
530 | @@TryAgain: |
||
8054 | rgimad | 531 | ; Reset the read operation retry counter |
2288 | clevermous | 532 | mov [ReadRepCounter], 0 |
533 | @@ReadSector_1: |
||
534 | call ReadSector |
||
535 | cmp [FDC_Status], 0 |
||
536 | je @@Exit_2 |
||
537 | cmp [FDC_Status], 1 |
||
538 | je @@Err_3 |
||
8054 | rgimad | 539 | ; Three times repeat reading |
2288 | clevermous | 540 | inc [ReadRepCounter] |
541 | cmp [ReadRepCounter], 3 |
||
542 | jb @@ReadSector_1 |
||
8054 | rgimad | 543 | ; Three times repeat recalibration |
2288 | clevermous | 544 | call RecalibrateFDD |
545 | call SeekTrack |
||
546 | inc [RecalRepCounter] |
||
547 | cmp [RecalRepCounter], 3 |
||
548 | jb @@TryAgain |
||
549 | @@Exit_2: |
||
550 | popa |
||
551 | ret |
||
552 | @@Err_3: |
||
553 | popa |
||
554 | ret |
||
555 | |||
556 | ;******************************************************* |
||
8054 | rgimad | 557 | ;* WRITE DATA SECTOR * |
558 | ;* Parameters are passed through global variables: * |
||
559 | ;* FDD_Track - track number (0-79); * |
||
560 | ;* FDD_Head - head number (0-1); * |
||
561 | ;* FDD_Sector - sector number (1-18). * |
||
562 | ;* Result of operation is written to FDC_Status. * |
||
563 | ;* If the write operation is successful, the contents * |
||
564 | ;* of FDD_DataBuffer will be written to the sector * |
||
2288 | clevermous | 565 | ;******************************************************* |
566 | WriteSector: |
||
4273 | clevermous | 567 | ; dbgstr 'WriteSector' |
2288 | clevermous | 568 | pushad |
569 | call save_timer_fdd_motor |
||
8054 | rgimad | 570 | ; Clear the interrupt flag |
4115 | mario79 | 571 | mov [FDD_IntFlag], 0 |
8054 | rgimad | 572 | ; Set transmit speed to 500 Kb / s |
2288 | clevermous | 573 | mov AX, 0 |
574 | mov DX, 03F7h |
||
575 | out DX, AL |
||
8054 | rgimad | 576 | ; Initialize the DMA channel |
2288 | clevermous | 577 | mov [dmamode], 0x4A |
578 | call Init_FDC_DMA |
||
8054 | rgimad | 579 | ; Send "Write data" command |
580 | mov AL, 0xC5 ;0x45 ; write in multi-track mode |
||
2288 | clevermous | 581 | call FDCDataOutput |
582 | mov AL, [FDD_Head] |
||
583 | shl AL, 2 |
||
6814 | dunkaist | 584 | or AL, [flp_number] |
585 | dec AL |
||
2288 | clevermous | 586 | call FDCDataOutput |
587 | mov AL, [FDD_Track] |
||
588 | call FDCDataOutput |
||
589 | mov AL, [FDD_Head] |
||
590 | call FDCDataOutput |
||
591 | mov AL, [FDD_Sector] |
||
592 | call FDCDataOutput |
||
8054 | rgimad | 593 | mov AL, 2 ; sector size code (512 bytes) |
2288 | clevermous | 594 | call FDCDataOutput |
8054 | rgimad | 595 | mov AL, 18; 3Fh ; sectors per track |
2288 | clevermous | 596 | call FDCDataOutput |
8054 | rgimad | 597 | mov AL, 1Bh ; GPL value |
2288 | clevermous | 598 | call FDCDataOutput |
8054 | rgimad | 599 | mov AL, 0FFh; DTL value |
2288 | clevermous | 600 | call FDCDataOutput |
8054 | rgimad | 601 | ; Waiting for an interrupt at the end of the operation |
2288 | clevermous | 602 | call WaitFDCInterrupt |
603 | cmp [FDC_Status], FDC_Normal |
||
604 | jne @@Exit_3 |
||
8054 | rgimad | 605 | ; Reading the completion status of the operation |
2288 | clevermous | 606 | call GetStatusInfo |
607 | test [FDC_ST0], 11000000b ;11011000b |
||
608 | jnz @@Err_2 |
||
609 | mov [FDC_Status], FDC_Normal |
||
610 | jmp @@Exit_3 |
||
611 | @@Err_2: |
||
612 | mov [FDC_Status], FDC_SectorNotFound |
||
613 | @@Exit_3: |
||
614 | call save_timer_fdd_motor |
||
615 | popad |
||
616 | ret |
||
617 | |||
618 | ;******************************************************* |
||
8054 | rgimad | 619 | ;* WRITE SECTOR (WITH REPEAT ON FAILURE) * |
620 | ;* Parameters are passed through global variables: * |
||
621 | ;* FDD_Track - track number (0-79); * |
||
622 | ;* FDD_Head - head number (0-1); * |
||
623 | ;* FDD_Sector - sector number (1-18). * |
||
624 | ;* Result of operation is written to FDC_Status. * |
||
625 | ;* If the write operation is successful, the contents * |
||
626 | ;* of FDD_DataBuffer will be written to the sector * |
||
2288 | clevermous | 627 | ;******************************************************* |
628 | WriteSectWithRetr: |
||
629 | pusha |
||
8054 | rgimad | 630 | ; Reset the recalibration repetition counter |
2288 | clevermous | 631 | mov [RecalRepCounter], 0 |
632 | @@TryAgain_1: |
||
8054 | rgimad | 633 | ; Reset the read operation retry counter |
2288 | clevermous | 634 | mov [ReadRepCounter], 0 |
635 | @@WriteSector_1: |
||
636 | call WriteSector |
||
637 | cmp [FDC_Status], 0 |
||
638 | je @@Exit_4 |
||
639 | cmp [FDC_Status], 1 |
||
640 | je @@Err_4 |
||
8054 | rgimad | 641 | ; Three times repeat writing |
2288 | clevermous | 642 | inc [ReadRepCounter] |
643 | cmp [ReadRepCounter], 3 |
||
644 | jb @@WriteSector_1 |
||
8054 | rgimad | 645 | ; Three times repeat recalibration |
2288 | clevermous | 646 | call RecalibrateFDD |
647 | call SeekTrack |
||
648 | inc [RecalRepCounter] |
||
649 | cmp [RecalRepCounter], 3 |
||
650 | jb @@TryAgain_1 |
||
651 | @@Exit_4: |
||
652 | popa |
||
653 | ret |
||
654 | @@Err_4: |
||
655 | popa |
||
656 | ret |
||
657 | |||
658 | ;********************************************* |
||
8054 | rgimad | 659 | ;* GET INFORMATION ABOUT THE RESULT OF THE OPERATION |
2288 | clevermous | 660 | ;********************************************* |
661 | GetStatusInfo: |
||
662 | push AX |
||
663 | call FDCDataInput |
||
664 | mov [FDC_ST0], AL |
||
665 | call FDCDataInput |
||
666 | mov [FDC_ST1], AL |
||
667 | call FDCDataInput |
||
668 | mov [FDC_ST2], AL |
||
669 | call FDCDataInput |
||
670 | mov [FDC_C], AL |
||
671 | call FDCDataInput |
||
672 | mov [FDC_H], AL |
||
673 | call FDCDataInput |
||
674 | mov [FDC_R], AL |
||
675 | call FDCDataInput |
||
676 | mov [FDC_N], AL |
||
677 | pop AX |
||
678 | ret |
||
679 | |||
4273 | clevermous | 680 | ; Interface for disk subsystem. |
681 | ; Assume fixed capacity for 1.44M. |
||
682 | FLOPPY_CAPACITY = 2880 ; in sectors |
||
683 | |||
684 | iglobal |
||
685 | align 4 |
||
686 | floppy_functions: |
||
687 | dd .size |
||
688 | dd 0 ; no close() function |
||
689 | dd 0 ; no closemedia() function |
||
690 | dd floppy_querymedia |
||
691 | dd floppy_read |
||
692 | dd floppy_write |
||
693 | dd 0 ; no flush() function |
||
694 | dd 0 ; no adjust_cache_size() function |
||
695 | .size = $ - floppy_functions |
||
696 | endg |
||
697 | |||
698 | uglobal |
||
699 | floppy_media_flags rb 2 |
||
700 | n_sector dd 0 ; temporary save for sector value |
||
701 | flp_number db 0 ; 1- Floppy A, 2-Floppy B |
||
702 | old_track db 0 ; old value track |
||
703 | flp_label rb 15*2 ; Label and ID of inserted floppy disk |
||
704 | align 4 |
||
705 | ; Hardware does not allow to work with two floppies in parallel, |
||
706 | ; so there is one mutex guarding access to any floppy. |
||
707 | floppy_mutex MUTEX |
||
708 | endg |
||
709 | ; Meaning of bits in floppy_media_flags |
||
710 | FLOPPY_MEDIA_PRESENT = 1 ; media was present when last asked |
||
711 | FLOPPY_MEDIA_NEED_RESCAN = 2 ; media was possibly changed, need to rescan |
||
712 | FLOPPY_MEDIA_LABEL_CHANGED = 4 ; temporary state |
||
713 | |||
714 | iglobal |
||
715 | floppy1_name db 'fd',0 |
||
716 | floppy2_name db 'fd2',0 |
||
717 | endg |
||
718 | |||
719 | ; This function is called in boot process. |
||
720 | ; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives. |
||
721 | proc floppy_init |
||
722 | mov ecx, floppy_mutex |
||
723 | call mutex_init |
||
724 | ; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero. |
||
725 | test byte [DRIVE_DATA], 0xF0 |
||
726 | jz .no1 |
||
727 | stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION |
||
728 | .no1: |
||
729 | ; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero. |
||
730 | test byte [DRIVE_DATA], 0x0F |
||
731 | jz .no2 |
||
732 | stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION |
||
733 | .no2: |
||
734 | ret |
||
735 | endp |
||
736 | |||
737 | ; Returns information about disk media. |
||
738 | ; Floppy drives do not support insert notifications, |
||
739 | ; DISK_NO_INSERT_NOTIFICATION is set, |
||
740 | ; the disk subsystem calls this function before each filesystem operation. |
||
741 | ; If the media has changed, return error for the first call as signal |
||
742 | ; to finalize work with old media and the true geometry for the second call. |
||
743 | ; Assume that media is (possibly) changed anytime when motor is off. |
||
744 | proc floppy_querymedia |
||
745 | virtual at esp+4 |
||
746 | .userdata dd ? |
||
747 | .info dd ? |
||
748 | end virtual |
||
749 | ; 1. Acquire the global lock. |
||
750 | mov ecx, floppy_mutex |
||
751 | call mutex_lock |
||
752 | mov edx, [.userdata] ; 1 for /fd, 2 for /fd2 |
||
753 | ; 2. If the media was reported and has been changed, forget it and report an error. |
||
754 | mov al, [floppy_media_flags+edx-1] |
||
755 | and al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN |
||
756 | cmp al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN |
||
757 | jnz .not_reported |
||
758 | .no_media: |
||
759 | mov [floppy_media_flags+edx-1], 0 |
||
760 | .return_no_media: |
||
761 | mov ecx, floppy_mutex |
||
762 | call mutex_unlock |
||
763 | mov eax, DISK_STATUS_NO_MEDIA |
||
764 | retn 8 |
||
765 | .not_reported: |
||
766 | ; 3. If we are in the temporary state LABEL_CHANGED, this is the second call |
||
767 | ; after intermediate DISK_STATUS_NO_MEDIA due to media change; |
||
768 | ; clear the flag and return the current geometry without rereading the bootsector. |
||
769 | cmp [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED |
||
770 | jz .report_geometry |
||
771 | ; 4. Try to read the bootsector. |
||
772 | mov [flp_number], dl |
||
773 | mov [FDC_Status], 0 |
||
774 | call floppy_read_bootsector |
||
775 | ; 5. If reading bootsector failed, assume that media is not present. |
||
776 | mov edx, [.userdata] |
||
777 | cmp [FDC_Status], 0 |
||
778 | jnz .no_media |
||
779 | ; 6. Check whether the previous status is "present". If not, go to 10. |
||
780 | push esi edi |
||
781 | imul edi, edx, 15 |
||
782 | add edi, flp_label-15 |
||
783 | mov esi, FDD_BUFF+39 |
||
784 | mov ecx, 15 |
||
785 | test [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT |
||
786 | jz .set_label |
||
787 | ; 7. Compare the old label with the current one. |
||
788 | rep cmpsb |
||
789 | ; 8. If the label has not changed, go to 11. |
||
790 | jz .ok |
||
791 | ; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED |
||
792 | ; and report DISK_STATUS_NO_MEDIA. |
||
793 | ; dbgstr 'floppy label changed' |
||
794 | add esi, ecx |
||
795 | add edi, ecx |
||
796 | mov ecx, 15 |
||
797 | sub esi, ecx |
||
798 | sub edi, ecx |
||
799 | rep movsb |
||
800 | mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED |
||
801 | pop edi esi |
||
802 | jmp .return_no_media |
||
803 | .set_label: |
||
804 | ; 10. The previous state was "not present". Copy the label. |
||
805 | rep movsb |
||
806 | .ok: |
||
807 | pop edi esi |
||
808 | .report_geometry: |
||
809 | ; 11. Fill DISKMEDIAINFO structure. |
||
810 | mov ecx, [.info] |
||
811 | and [ecx+DISKMEDIAINFO.Flags], 0 |
||
812 | mov [ecx+DISKMEDIAINFO.SectorSize], 512 |
||
813 | mov dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY |
||
814 | and dword [ecx+DISKMEDIAINFO.Capacity+4], 0 |
||
815 | ; 12. Update state: media is present, data are actual. |
||
816 | mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT |
||
817 | ; 13. Release the global lock and return successful status. |
||
818 | mov ecx, floppy_mutex |
||
819 | call mutex_unlock |
||
820 | xor eax, eax |
||
821 | retn 8 |
||
822 | endp |
||
823 | |||
824 | proc floppy_read_bootsector |
||
825 | pushad |
||
8054 | rgimad | 826 | mov [FDD_Track], 0 ; Cylinder |
827 | mov [FDD_Head], 0 ; Head |
||
828 | mov [FDD_Sector], 1 ; Sector |
||
4273 | clevermous | 829 | call FDDMotorON |
830 | call RecalibrateFDD |
||
831 | cmp [FDC_Status], 0 |
||
832 | jne .nothing |
||
833 | call SeekTrack |
||
834 | cmp [FDC_Status], 0 |
||
835 | jne .nothing |
||
836 | call ReadSectWithRetr |
||
837 | .nothing: |
||
838 | popad |
||
839 | ret |
||
840 | endp |
||
841 | |||
842 | read_chs_sector: |
||
843 | call calculate_chs |
||
844 | call ReadSectWithRetr |
||
845 | ret |
||
846 | |||
847 | save_chs_sector: |
||
848 | call calculate_chs |
||
849 | call WriteSectWithRetr |
||
850 | ret |
||
851 | |||
852 | calculate_chs: |
||
853 | mov bl, [FDD_Track] |
||
854 | mov [old_track], bl |
||
855 | mov ebx, 18 |
||
856 | xor edx, edx |
||
857 | div ebx |
||
858 | inc edx |
||
859 | mov [FDD_Sector], dl |
||
860 | mov edx, eax |
||
861 | shr eax, 1 |
||
862 | and edx, 1 |
||
863 | mov [FDD_Track], al |
||
864 | mov [FDD_Head], dl |
||
865 | mov dl, [old_track] |
||
866 | cmp dl, [FDD_Track] |
||
867 | je no_seek_track_1 |
||
868 | call SeekTrack |
||
869 | no_seek_track_1: |
||
870 | ret |
||
871 | |||
872 | ; Writes one or more sectors to the device. |
||
873 | proc floppy_write |
||
874 | mov dl, 1 |
||
875 | jmp floppy_read_write |
||
876 | endp |
||
877 | |||
878 | ; Reads one or more sectors from the device. |
||
879 | proc floppy_read |
||
880 | mov dl, 0 |
||
881 | endp |
||
882 | |||
883 | ; Common part of floppy_read and floppy_write. |
||
884 | proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword |
||
885 | virtual at ebp-8 |
||
886 | .sectors_todo dd ? |
||
887 | .operation db ? |
||
888 | end virtual |
||
889 | push edx ; save operation code to [.operation] |
||
890 | ; 1. Get number of sectors to read/write |
||
891 | ; and zero number of sectors that were actually read/written. |
||
892 | mov eax, [numsectors_ptr] |
||
893 | push dword [eax] ; initialize [.sectors_todo] |
||
894 | and dword [eax], 0 |
||
895 | push ebx esi edi ; save used registers to be stdcall |
||
896 | ; 2. Acquire the global lock. |
||
897 | mov ecx, floppy_mutex |
||
898 | call mutex_lock |
||
899 | ; 3. Set floppy number for this operation. |
||
900 | mov edx, [userdata] |
||
901 | mov [flp_number], dl |
||
902 | ; 4. Read/write sector-by-sector. |
||
903 | .operation_loop: |
||
904 | ; 4a. Check that the sector is inside the media. |
||
905 | cmp dword [start_sector+4], 0 |
||
906 | jnz .end_of_media |
||
907 | mov eax, dword [start_sector] |
||
908 | cmp eax, FLOPPY_CAPACITY |
||
909 | jae .end_of_media |
||
910 | ; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer]. |
||
911 | ; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector. |
||
912 | cmp [.operation], 0 |
||
913 | jz .read |
||
914 | mov esi, [buffer] |
||
915 | mov edi, FDD_BUFF |
||
916 | mov ecx, 512/4 |
||
917 | rep movsd |
||
918 | mov [buffer], esi |
||
919 | call save_chs_sector |
||
920 | jmp @f |
||
921 | .read: |
||
922 | call read_chs_sector |
||
923 | mov esi, FDD_BUFF |
||
924 | mov edi, [buffer] |
||
925 | mov ecx, 512/4 |
||
926 | rep movsd |
||
927 | mov [buffer], edi |
||
928 | @@: |
||
929 | ; 4c. If there was an error, propagate it to the caller. |
||
930 | cmp [FDC_Status], 0 |
||
931 | jnz .fail |
||
932 | ; 4d. Otherwise, increment number of sectors processed and continue the loop. |
||
933 | mov eax, [numsectors_ptr] |
||
934 | inc dword [eax] |
||
935 | inc dword [start_sector] |
||
936 | dec [.sectors_todo] |
||
937 | jnz .operation_loop |
||
938 | ; 5. Release the global lock and return with the correct status. |
||
939 | push 0 |
||
940 | .return: |
||
941 | mov ecx, floppy_mutex |
||
942 | call mutex_unlock |
||
943 | pop eax |
||
944 | pop edi esi ebx ; restore used registers to be stdcall |
||
945 | ret ; this translates to leave/retn N and purges local variables |
||
946 | .fail: |
||
947 | push -1 |
||
948 | jmp .return |
||
949 | .end_of_media: |
||
950 | push DISK_STATUS_END_OF_MEDIA |
||
951 | jmp .return |
||
952 | endp |