11 #include <drv/disk/floppy.h>
13 #include "sys/timer.h"
15 #include "drv/disk/dpm.h"
19 bool _FloppyDebug =
false;
24 static const char * drive_types[8] = {
37 volatile bool interrupted =
false;
40 return floppy_data[device];
43 void irq_waitFloppy() {
53 int _FloppyError(
int Device,
int Error){
54 if (_FloppyDebug) qemu_log(
"FD%c ERROR! Code: %d",(Device==FDB?
'B':
'A'),Error);
55 floppy_data[Device].
LastErr = Error;
59 static void _FloppyROOT(
int device,
int offset,
int cmd){
60 size_t addr = Floppy(device).
Addr + offset;
63 qemu_log(
" [FD%c] ROOT | Addr: %x | Offset: %x | Input: %x | Cmd: %x",(device?
'B':
'A'),Floppy(device).Addr,offset,addr,cmd);
70 static void _FloppyDMA(FloppyMode dir) {
77 a.l = (unsigned) &FLOPPY_DMABUFA;
78 c.l = (unsigned) FLOPPY_144_CYLINDER_SIZE - 1;
80 if((a.l >> 24) || (c.l >> 16) || (((a.l&0xffff)+c.l)>>16)) {
81 qemu_log(
"_FloppyDMA: static buffer problem\n");
87 case FLOPPY_READ:
mode = 0x46;
break;
89 case FLOPPY_WRITE:
mode = 0x4a;
break;
90 default: qemu_log(
"_FloppyDMA: invalid direction");
105 void _FloppyMotor(
int device,
int status){
108 _FloppyROOT(device,FLOPPY_DIGITAL_OUTPUT_REGISTER,0x0C);
110 floppy_data[device].
Motor = 0;
111 if (_FloppyDebug) qemu_log(
" [FD%c] Motor Offline",(device?
'B':
'A'));
112 }
else if (status == 1){
113 if (_FloppyDebug) qemu_log(
" [FD%c] Motor Online",(device?
'B':
'A'));
115 if (Floppy(device).Motor == 0){
117 if (device == 0) _FloppyROOT(device,FLOPPY_DIGITAL_OUTPUT_REGISTER,0x1C);
118 if (device == 1) _FloppyROOT(device,FLOPPY_DIGITAL_OUTPUT_REGISTER,0x2D);
121 floppy_data[device].
Motor = 1;
124 if (_FloppyDebug) qemu_log(
" [FD%c] Motor Waiting",(device?
'B':
'A'));
125 if (Floppy(device).Motor == 2){
126 if (_FloppyDebug) qemu_log(
" [FD%c] Strange, fd motor-state already waiting..",(device?
'B':
'A'));
128 floppy_data[device].
Motor = 2;
129 floppy_data[device].
Ticks = 300;
133 int _FloppyCMD(
int device,
char cmd){
134 if (_FloppyDebug) qemu_log(
" [FD%c] Addr: %x | Command: %x",(device?
'B':
'A'),Floppy(device).Addr,cmd);
135 for(
int i = 0; i < 600; i++) {
137 if(0x80 & inb(Floppy(device).Addr + FLOPPY_MAIN_STATUS_REGISTER)) {
138 _FloppyROOT(device,FLOPPY_DATA_FIFO,cmd);
143 return _FloppyError(device,FLOPPY_ERROR_CMD);
146 unsigned char _FloppyData(
int device){
147 for(
int i = 0; i < 600; i++) {
149 if(0x80 & inb(Floppy(device).Addr + FLOPPY_MAIN_STATUS_REGISTER)) {
150 return inb(Floppy(device).Addr + FLOPPY_DATA_FIFO);
153 qemu_log(
"floppy_read_data: timeout");
158 void _FloppyCI(
int device,
int *st0,
int *cyl){
159 _FloppyCMD(device, CMD_SENSE_INTERRUPT);
161 *st0 = _FloppyData(device);
162 *cyl = _FloppyData(device);
166 int _FloppyCalibrate(
int device){
167 int i, st0, cyl = -1;
168 _FloppyMotor(device,1);
169 for(i = 0; i < 10; i++) {
170 if (_FloppyDebug) qemu_log(
" [FD%c] Attempt Calibrate %d",(device?
'B':
'A'),i);
172 _FloppyCMD(device, CMD_RECALIBRATE);
173 _FloppyCMD(device, 0);
175 _FloppyCI(device, &st0, &cyl);
176 if(st0 & 0xC0)
continue;
178 _FloppyMotor(device, 0);
182 if (_FloppyDebug) qemu_log(
"floppy_calibrate: 10 retries exhausted\n");
183 _FloppyMotor(device, 0);
184 return _FloppyError(device,FLOPPY_ERROR_CALIBRATE);
187 int _FloppyReset(
int device){
189 _FloppyROOT(device,FLOPPY_DIGITAL_OUTPUT_REGISTER,0x00);
190 _FloppyROOT(device,FLOPPY_DIGITAL_OUTPUT_REGISTER,0x0C);
194 _FloppyCI(device, &st0, &cyl);
196 _FloppyROOT(device,FLOPPY_CONFIGURATION_CONTROL_REGISTER,0x00);
197 _FloppyCMD(device, CMD_SPECIFY);
198 _FloppyCMD(device, 0xdf);
199 _FloppyCMD(device, 0x02);
202 if(_FloppyCalibrate(device) != 0)
203 return _FloppyError(device,FLOPPY_ERROR_RESET);
210 int _FloppySeek(
int device,
unsigned cyli,
int head){
211 int i, st0, cyl = -1;
212 _FloppyMotor(device, 1);
213 for(i = 0; i < 10; i++) {
214 if (_FloppyDebug) qemu_log(
" [FD%c] Attempt Seek %d | Cyli: %c | Head: %d",(device?
'B':
'A'),i,cyli,head);
216 _FloppyCMD(device, CMD_SEEK);
217 _FloppyCMD(device, head<<2);
218 _FloppyCMD(device, cyli & 0xFF);
220 _FloppyCI(device, &st0, &cyl);
221 if(st0 & 0xC0)
continue;
223 _FloppyMotor(device, 0);
227 qemu_log(
"floppy_seek: 10 retries exhausted\n");
228 _FloppyMotor(device, 0);
229 _FloppyError(device,FLOPPY_ERROR_SEEK);
235 static const int flags = 0xC0;
238 cmd = CMD_READ_DATA | flags;
241 cmd = CMD_WRITE_DATA | flags;
245 qemu_log(
"floppy_do_track: invalid direction");
249 if(_FloppySeek(device, cyl, 0))
return -1;
250 if(_FloppySeek(device, cyl, 1))
return -1;
253 for(i = 0; i < 20; i++) {
254 _FloppyMotor(device, 1);
257 _FloppyCMD(device, cmd);
258 _FloppyCMD(device, 0);
259 _FloppyCMD(device, cyl);
260 _FloppyCMD(device, 0);
261 _FloppyCMD(device, 1);
262 _FloppyCMD(device, 2);
263 _FloppyCMD(device, 18);
264 _FloppyCMD(device, 0x1b);
265 _FloppyCMD(device, 0xff);
269 unsigned char st0, st1, st2, rcy, rhe, rse, bps;
270 st0 = _FloppyData(device);
271 st1 = _FloppyData(device);
272 st2 = _FloppyData(device);
273 rcy = _FloppyData(device);
274 rhe = _FloppyData(device);
275 rse = _FloppyData(device);
276 bps = _FloppyData(device);
285 if ((st0 >> 6) == 0)
return _FloppyError(device,FLOPPY_ERROR_NOSUPPORT);
286 if ((st0 >> 6) == 1)
return _FloppyError(device,FLOPPY_ERROR_NOSUPPORT);
287 if ((st0 >> 6) == 2)
return _FloppyError(device,FLOPPY_ERROR_CMD_UNK);
288 if ((st0 >> 6) == 3)
return _FloppyError(device,FLOPPY_ERROR_NOREADY);
290 if(st1 & 0x80)
return _FloppyError(device,FLOPPY_ERROR_EOL);
291 if(st0 & 0x08)
return _FloppyError(device,FLOPPY_ERROR_NOREADY);
292 if(st1 & 0x20)
return _FloppyError(device,FLOPPY_ERROR_CRC);
293 if(st1 & 0x10)
return _FloppyError(device,FLOPPY_ERROR_CONTROLLER);
294 if(st1 & 0x04)
return _FloppyError(device,FLOPPY_ERROR_NODATA);
295 if((st1|st2) & 0x01)
return _FloppyError(device,FLOPPY_ERROR_NOADDR);
296 if(st2 & 0x40)
return _FloppyError(device,FLOPPY_ERROR_DELADDR);
297 if(st2 & 0x20)
return _FloppyError(device,FLOPPY_ERROR_CRC);
298 if(st2 & 0x10)
return _FloppyError(device,FLOPPY_ERROR_CYLINDER);
299 if(st2 & 0x04)
return _FloppyError(device,FLOPPY_ERROR_UPD765);
300 if(st2 & 0x02)
return _FloppyError(device,FLOPPY_ERROR_CYLINDER);
301 if(bps != 0x2)
return _FloppyError(device,FLOPPY_ERROR_512B);
302 if(st1 & 0x02)
return _FloppyError(device,FLOPPY_ERROR_WRITE);
303 _FloppyMotor(device, 0);
309 qemu_log(
"floppy_do_sector: 20 retries exhausted\n");
310 _FloppyMotor(device, 0);
311 return _FloppyError(device,FLOPPY_ERROR_TRACK);
315 void addr_2_coff(uint32_t addr, uint16_t* cyl, uint32_t* offset, uint32_t* size) {
316 if (offset) *offset = addr % FLOPPY_144_CYLINDER_SIZE;
317 if (size) *size = FLOPPY_144_CYLINDER_SIZE - (addr % FLOPPY_144_CYLINDER_SIZE);
318 if (cyl) *cyl = addr / FLOPPY_144_CYLINDER_SIZE;
323 int _FloppyCache(
int device,FloppyMode
mode,
unsigned int addr,
unsigned int* offset,
unsigned int* size){
327 addr_2_coff(addr, &cyl, offset, size);
328 if (
mode == FLOPPY_READ && cyl == floppy_data[device].Cyr)
return 0;
330 if (ret >= 0) floppy_data[device].
Cyr = cyl;
343 size_t _FloppyRead(
int device,
char* dst,uint32_t addr,uint32_t size){
344 if (Floppy(device).Status != 1)
return _FloppyError(FDA,FLOPPY_ERROR_NOREADY);
346 floppy_data[device].
LastErr = 0;
347 uint32_t offset=0, ws=0;
351 ret = _FloppyCache(device,FLOPPY_READ,addr+ds,&offset,&ws);
352 if (ret < 0)
return ret;
353 if (ws > size - ds) ws = size - ds;
354 memcpy(dst + ds, (
void*) &FLOPPY_DMABUFA[offset], ws);
360 size_t _FloppyWrite(
int device,
const char* dst,uint32_t addr,uint32_t size){
361 if (Floppy(device).Status != 1)
return _FloppyError(FDA,FLOPPY_ERROR_NOREADY);
364 uint32_t offset=0, ws=0;
368 ret = _FloppyCache(device,FLOPPY_READ,addr+ds, &offset, &ws);
369 if (ret < 0)
return ret;
370 if (ws > size - ds) ws = size - ds;
371 memcpy((
void*) &FLOPPY_DMABUFA[offset],dst+ds,ws);
372 ret = _FloppyCache(device,FLOPPY_WRITE,addr+ds,
nullptr,
nullptr);
373 if (ret < 0)
return ret;
379 void _FloppyServiceA(){
381 unsigned drives = inb(0x71);
382 int DiskA = drives >> 4;
383 if (DiskA != floppy_data[FDA].Type){
385 floppy_data[FDA].
Type = DiskA;
386 floppy_data[FDA].
Status = (floppy_data[FDA].
Type == 4?1:0);
387 dpm_unmount(
'A',
false);
388 dpm_reg(
'A',
"Disk A",
"Unknown",floppy_data[FDA].Status,0,0,0,3,
"FLOP-PYDA",0);
397 unsigned drives = inb(0x71);
398 if (Floppy(FDA).Type != drives >> 4){
399 floppy_data[FDA].
Type = drives >> 4;
400 if (_FloppyDebug) qemu_log(
"[FDA] Change disk type: %d",Floppy(FDA).Type);
402 if (Floppy(FDB).Type != (drives & 0xf)){
403 floppy_data[FDB].
Type = (drives & 0xf);
404 if (_FloppyDebug) qemu_log(
"[FDB] Change disk type: %d",Floppy(FDB).Type);
406 if (Floppy(FDA).Type == 0) {
407 floppy_data[FDA].
Status = _FloppyError(FDA,FLOPPY_ERROR_NOREADY);
408 }
else if (Floppy(FDA).Type != 4){
409 floppy_data[FDA].
Status = _FloppyError(FDA,FLOPPY_ERROR_NOSUPPORT);
411 floppy_data[FDA].
Status = 1;
414 if (Floppy(FDB).Type == 0) {
415 floppy_data[FDB].
Status = _FloppyError(FDB,FLOPPY_ERROR_NOREADY);
416 }
else if (Floppy(FDB).Type != 4){
417 floppy_data[FDB].
Status = _FloppyError(FDB,FLOPPY_ERROR_NOSUPPORT);
419 floppy_data[FDB].
Status = 1;
425 char fda_fs[6],fdb_fs[6] = {0};
426 char fda_label[12],fdb_label[12] = {0};
427 char fs_fat12[6] = {
'F',
'A',
'T',
'1',
'2',0};
430 if (Floppy(FDA).Status == 1){
432 read = Floppy(FDA).
Read(FDA,fda_fs,54,5);
433 if (_FloppyDebug) qemu_log(
"[FDA] Read File System => (%d) '%s'",read,fda_fs);
434 if (Floppy(FDA).LastErr != 0){
435 floppy_data[FDA].
Status = FLOPPY_ERROR_NOREADY;
436 if (_FloppyDebug) qemu_log(
"[FDA] No ready drive!");
439 read = Floppy(FDA).
Read(FDA,fda_fs,54,8);
440 if (Floppy(FDA).LastErr == 0 &&
strcmp(fs_fat12, fda_fs) == 0){
441 if (_FloppyDebug) qemu_log(
"[FDA] File System: FAT12");
442 Floppy(FDA).
Read(FDA, fda_label, 43, 11);
444 memcpy((
void*) floppy_data[FDA].Name, fda_label, 12);
445 memcpy((
void*) floppy_data[FDA].FileSystem, fda_fs, 6);
446 if (_FloppyDebug) qemu_log(
"[FDA] Label: %s",floppy_data[FDA].Name);
450 if (Floppy(FDB).Status == 1){
451 read = Floppy(FDB).
Read(FDB,fdb_fs,54,5);
452 if (_FloppyDebug) qemu_log(
"[FDB] Read File System => (%d) '%s'",read,fdb_fs);
453 if (Floppy(FDB).LastErr != 0){
454 floppy_data[FDB].
Status = FLOPPY_ERROR_NOREADY;
455 if (_FloppyDebug) qemu_log(
"[FDB] No ready drive!");
457 }
else if (
strcmp(fs_fat12,fdb_fs) == 0){
458 if (_FloppyDebug) qemu_log(
"[FDB] File System: FAT12");
459 Floppy(FDB).
Read(FDB,fdb_label,43,11);
461 memcpy((
void*) floppy_data[FDB].Name, fdb_label, 12);
462 if (_FloppyDebug) qemu_log(
"[FDB] Label: %s",floppy_data[FDB].Name);
463 memcpy((
void*) floppy_data[FDB].FileSystem, fdb_fs, 6);
471 size_t _FloppyDPMWriteA(
size_t Disk, uint64_t high_offset, uint64_t low_offset,
size_t Size,
void* Buffer){
472 qemu_log(
"[DPM] Floppy A Write! Offset: %d | Size: %d",low_offset, Size);
473 if (Floppy(0).Status != 1)
return 0;
476 uint32_t _offset = 0, ws = 0;
480 ret = _FloppyCache(0,FLOPPY_READ, low_offset+ds, &_offset, &ws);
481 if (ret < 0)
return ret;
482 if (ws > Size - ds) ws = Size - ds;
483 memcpy((
void*) &FLOPPY_DMABUFA[_offset], Buffer+ds, ws);
484 ret = _FloppyCache(0,FLOPPY_WRITE, low_offset+ds,
nullptr,
nullptr);
485 if (ret < 0)
return ret;
491 size_t _FloppyDPMReadA(
size_t Disk, uint64_t high_offset, uint64_t low_offset,
size_t Size,
void* Buffer){
492 qemu_log(
"[DPM] Floppy A Read! Offset: %d | Size: %d",low_offset, Size);
493 if (Floppy(0).Status != 1)
return 0;
495 uint32_t _offset=0, ws=0;
499 ret = _FloppyCache(0, FLOPPY_READ, low_offset+ds, &_offset, &ws);
500 if (ret < 0)
return ret;
501 if (ws > Size - ds) ws = Size - ds;
502 memcpy(Buffer + ds, (
void*) &FLOPPY_DMABUFA[_offset], ws);
510 _tty_printf(
"[-] Floppy Disk A\n");
511 _tty_printf(
" |--- Status: %d\n",Floppy(FDA).Status);
512 _tty_printf(
" |--- Type: %s\n",drive_types[Floppy(FDA).Type]);
513 if (Floppy(FDA).Status == 1){
514 _tty_printf(
" |--- File System: %s\n",Floppy(FDA).FileSystem);
515 _tty_printf(
" |--- Label: %s\n",Floppy(FDA).Name);
520 _tty_printf(
"[-] Floppy Disk B\n");
521 _tty_printf(
" |--- Status: %d\n",Floppy(FDB).Status);
522 _tty_printf(
" |--- Type: %s\n",drive_types[Floppy(FDB).Type]);
523 if (Floppy(FDB).Status == 1){
524 _tty_printf(
" |--- File System: %s\n",Floppy(FDB).FileSystem);
525 _tty_printf(
" |--- Label: %s\n",Floppy(FDB).Name);
531 tty_printf(
"Поиск дискет...\n");
533 floppy_data[FDA].
Index = FDA;
534 floppy_data[FDA].
Type = 0;
536 floppy_data[FDA].
Cache = &_FloppyCache;
537 floppy_data[FDB].
Cache = &_FloppyCache;
542 floppy_data[FDA].
Write = &_FloppyWrite;
543 floppy_data[FDB].
Write = &_FloppyWrite;
545 floppy_data[FDA].
Addr = FLOPPY_MAIN;
546 floppy_data[FDB].
Addr = FLOPPY_SECO;
548 floppy_data[FDA].
Cyr = -1;
549 floppy_data[FDB].
Cyr = -1;
551 floppy_data[FDA].
Status = 0;
552 floppy_data[FDB].
Status = 0;
553 floppy_data[FDA].
Motor = 0;
554 floppy_data[FDB].
Motor = 0;
558 register_interrupt_handler(32+6,&irqFloppy);
560 dpm_reg(
'A',
"Disk A",
"Unknown",1,0,0,0,3,
"FLOP-PYDA",0);
561 dpm_metadata_write(
'A', (uint32_t) &floppy_data[FDA]);
562 dpm_fnc_write(
'A',_FloppyDPMReadA,_FloppyDPMWriteA);
567 dpm_reg(
'B',
"Disk B",
"Unknown",0,0,0,0,3,
"FLOP-PYDB",0);
568 dpm_metadata_write(
'B', (uint32_t) &floppy_data[FDB]);
uint32_t mode
Режим работы (0 - Обычный | 1 - Режим логирования)
int dpm_reg(char Letter, char *Name, char *FS, int Status, size_t Size, size_t Sectors, size_t SectorSize, int AddrMode, char *Serial, void *Point)
[DPM] Регистрация дискового раздела
size_t _FloppyRead(int device, char *dst, uint32_t addr, uint32_t size)
[Floppy] Чтение данных на устройство
int _FloppyTrack(int device, unsigned cyl, FloppyMode dir)
void _FloppyCheck()
Автоматическое обновление данных о FD.
int strcmp(const char *s1, const char *s2)
Сравнение строк
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
int Ticks
Тики работы дисковода
int Index
Индекс устройства
FloppyCache_t Cache
Команда для кэша
FloppyR_t Read
Команда для чтения данных
FloppyW_t Write
Команда для записи данных
void sleep_ms(uint32_t milliseconds)
Ожидание по миллисекундам