1 #define _LARGEFILE_SOURCE
2 #define _LARGEFILE64_SOURCE
3 #define _GNU_SOURCE
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <stdlib.h>
9
10 #include <sys/types.h>
11
12 #include "ibm.h"
13 #include "device.h"
14 #include "hdd_file.h"
15 #include "io.h"
16 #include "mem.h"
17 #include "pic.h"
18 #include "rom.h"
19 #include "timer.h"
20
21 #include "esdi_at.h"
22
23
24 #define IDE_TIME (TIMER_USEC*10)//(5 * 100 * (1 << TIMER_SHIFT))
25
26 #define STAT_ERR 0x01
27 #define STAT_INDEX 0x02
28 #define STAT_CORRECTED_DATA 0x04
29 #define STAT_DRQ 0x08 /* Data request */
30 #define STAT_DSC 0x10
31 #define STAT_SEEK_COMPLETE 0x20
32 #define STAT_READY 0x40
33 #define STAT_BUSY 0x80
34
35 #define ERR_DAM_NOT_FOUND 0x01 /*Data Address Mark not found*/
36 #define ERR_TR000 0x02 /*Track 0 not found*/
37 #define ERR_ABRT 0x04 /*Command aborted*/
38 #define ERR_ID_NOT_FOUND 0x10 /*ID not found*/
39 #define ERR_DATA_CRC 0x40 /*Data CRC error*/
40 #define ERR_BAD_BLOCK 0x80 /*Bad Block detected*/
41
42 #define CMD_NOP 0x00
43 #define CMD_RESTORE 0x10
44 #define CMD_READ 0x20
45 #define CMD_WRITE 0x30
46 #define CMD_VERIFY 0x40
47 #define CMD_FORMAT 0x50
48 #define CMD_SEEK 0x70
49 #define CMD_DIAGNOSE 0x90
50 #define CMD_SET_PARAMETERS 0x91
51 #define CMD_READ_PARAMETERS 0xec
52
53 extern char ide_fn[4][512];
54
55 typedef struct esdi_drive_t
56 {
57 int cfg_spt;
58 int cfg_hpc;
59 int current_cylinder;
60 hdd_file_t hdd_file;
61 } esdi_drive_t;
62
63 typedef struct esdi_t
64 {
65 uint8_t status;
66 uint8_t error;
67 int secount,sector,cylinder,head,cylprecomp;
68 uint8_t command;
69 uint8_t fdisk;
70 int pos;
71
72 int drive_sel;
73 int reset;
74 uint16_t buffer[256];
75 int irqstat;
76
77 int callback;
78
79 esdi_drive_t drives[2];
80
81 rom_t bios_rom;
82 } esdi_t;
83
84 uint16_t esdi_readw(uint16_t port, void *p);
85 void esdi_writew(uint16_t port, uint16_t val, void *p);
86
esdi_irq_raise(esdi_t * esdi)87 static inline void esdi_irq_raise(esdi_t *esdi)
88 {
89 // pclog("IDE_IRQ_RAISE\n");
90 if (!(esdi->fdisk&2))
91 picint(1 << 14);
92
93 esdi->irqstat=1;
94 }
95
esdi_irq_lower(esdi_t * esdi)96 static inline void esdi_irq_lower(esdi_t *esdi)
97 {
98 picintc(1 << 14);
99 }
100
esdi_irq_update(esdi_t * esdi)101 void esdi_irq_update(esdi_t *esdi)
102 {
103 if (esdi->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(esdi->fdisk & 2))
104 picint(1 << 14);
105 }
106
107 /*
108 * Return the sector offset for the current register values
109 */
esdi_get_sector(esdi_t * esdi,off64_t * addr)110 int esdi_get_sector(esdi_t *esdi, off64_t *addr)
111 {
112 esdi_drive_t *drive = &esdi->drives[esdi->drive_sel];
113 int heads = drive->cfg_hpc;
114 int sectors = drive->cfg_spt;
115
116 if (esdi->head > heads)
117 {
118 pclog("esdi_get_sector: past end of configured heads\n");
119 return 1;
120 }
121 if (esdi->sector >= sectors+1)
122 {
123 pclog("esdi_get_sector: past end of configured sectors\n");
124 return 1;
125 }
126
127 if (drive->cfg_spt == drive->hdd_file.spt && drive->cfg_hpc == drive->hdd_file.hpc)
128 {
129 *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) *
130 sectors) + (esdi->sector - 1);
131 }
132 else
133 {
134 /*When performing translation, the firmware seems to leave 1
135 sector per track inaccessible (spare sector)*/
136 int c, h, s;
137 *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) *
138 sectors) + (esdi->sector - 1);
139
140 s = *addr % (drive->hdd_file.spt - 1);
141 h = (*addr / (drive->hdd_file.spt - 1)) % drive->hdd_file.hpc;
142 c = (*addr / (drive->hdd_file.spt - 1)) / drive->hdd_file.hpc;
143
144 *addr = ((((off64_t) c * drive->hdd_file.hpc) + h) *
145 drive->hdd_file.spt) + s;
146 }
147
148 return 0;
149 }
150
151 /**
152 * Move to the next sector using CHS addressing
153 */
esdi_next_sector(esdi_t * esdi)154 void esdi_next_sector(esdi_t *esdi)
155 {
156 esdi_drive_t *drive = &esdi->drives[esdi->drive_sel];
157
158 esdi->sector++;
159 if (esdi->sector == (drive->cfg_spt + 1))
160 {
161 esdi->sector = 1;
162 esdi->head++;
163 if (esdi->head == drive->cfg_hpc)
164 {
165 esdi->head = 0;
166 esdi->cylinder++;
167 if (drive->current_cylinder < drive->hdd_file.tracks)
168 drive->current_cylinder++;
169 }
170 }
171 }
172
esdi_write(uint16_t port,uint8_t val,void * p)173 void esdi_write(uint16_t port, uint8_t val, void *p)
174 {
175 esdi_t *esdi = (esdi_t *)p;
176
177 // pclog("esdi_write: addr=%04x val=%02x\n", port, val);
178 switch (port)
179 {
180 case 0x1F0: /* Data */
181 esdi_writew(port, val | (val << 8), p);
182 return;
183
184 case 0x1F1: /* Write precompenstation */
185 esdi->cylprecomp = val;
186 return;
187
188 case 0x1F2: /* Sector count */
189 esdi->secount = val;
190 return;
191
192 case 0x1F3: /* Sector */
193 esdi->sector = val;
194 return;
195
196 case 0x1F4: /* Cylinder low */
197 esdi->cylinder = (esdi->cylinder & 0xFF00) | val;
198 return;
199
200 case 0x1F5: /* Cylinder high */
201 esdi->cylinder = (esdi->cylinder & 0xFF) | (val << 8);
202 return;
203
204 case 0x1F6: /* Drive/Head */
205 esdi->head = val & 0xF;
206 esdi->drive_sel = (val & 0x10) ? 1 : 0;
207 if (esdi->drives[esdi->drive_sel].hdd_file.f == NULL)
208 esdi->status = 0;
209 else
210 esdi->status = STAT_READY | STAT_DSC;
211 return;
212
213 case 0x1F7: /* Command register */
214 // if (esdi->drives[esdi->drive_sel].hdd_file.f == NULL && val != CMD_SET_PARAMETERS && val != CMD_NOP && val != 0xe0 && (val & ~3) != 0x20 && (val & ~3) != 0x30 && (val & ~3) != 0x40 && val != 0x90 && val != CMD_READ_PARAMETERS)
215 // fatal("Command %02x on non-present drive\n", val);
216
217 esdi_irq_lower(esdi);
218 esdi->command = val;
219 esdi->error = 0;
220
221 switch (val & 0xf0)
222 {
223 case CMD_RESTORE:
224 // pclog("Restore\n");
225 esdi->command &= ~0x0f; /*Mask off step rate*/
226 esdi->status = STAT_BUSY;
227 timer_clock();
228 esdi->callback = 200*IDE_TIME;
229 timer_update_outstanding();
230 break;
231
232 case CMD_SEEK:
233 // pclog("Seek to cylinder %i\n", esdi->cylinder);
234 esdi->command &= ~0x0f; /*Mask off step rate*/
235 esdi->status = STAT_BUSY;
236 timer_clock();
237 esdi->callback = 200*IDE_TIME;
238 timer_update_outstanding();
239 break;
240
241 default:
242 switch (val)
243 {
244 case CMD_NOP:
245 esdi->status = STAT_BUSY;
246 timer_clock();
247 esdi->callback = 200*IDE_TIME;
248 timer_update_outstanding();
249 break;
250
251 case CMD_READ: case CMD_READ+1:
252 case CMD_READ+2: case CMD_READ+3:
253 // pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head,ins);
254 esdi->command &= ~3;
255 if (val & 2)
256 fatal("Read with ECC\n");
257 case 0xa0:
258 esdi->status = STAT_BUSY;
259 timer_clock();
260 esdi->callback = 200*IDE_TIME;
261 timer_update_outstanding();
262 break;
263
264 case CMD_WRITE: case CMD_WRITE+1:
265 case CMD_WRITE+2: case CMD_WRITE+3:
266 // pclog("Write %i sectors to sector %i cylinder %i head %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head);
267 esdi->command &= ~3;
268 if (val & 2)
269 fatal("Write with ECC\n");
270 esdi->status = STAT_DRQ | STAT_DSC;// | STAT_BUSY;
271 esdi->pos=0;
272 break;
273
274 case CMD_VERIFY: case CMD_VERIFY+1:
275 // pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head);
276 esdi->command &= ~1;
277 esdi->status = STAT_BUSY;
278 timer_clock();
279 esdi->callback = 200 * IDE_TIME;
280 timer_update_outstanding();
281 break;
282
283 case CMD_FORMAT:
284 // pclog("Format track %i head %i\n", esdi->cylinder, esdi->head);
285 esdi->status = STAT_DRQ;// | STAT_BUSY;
286 esdi->pos=0;
287 break;
288
289 case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */
290 esdi->status = STAT_BUSY;
291 timer_clock();
292 esdi->callback = 30*IDE_TIME;
293 timer_update_outstanding();
294 break;
295
296 case CMD_DIAGNOSE: /* Execute Drive Diagnostics */
297 esdi->status = STAT_BUSY;
298 timer_clock();
299 esdi->callback = 200*IDE_TIME;
300 timer_update_outstanding();
301 break;
302
303 case 0xe0: /*???*/
304 case CMD_READ_PARAMETERS:
305 esdi->status = STAT_BUSY;
306 timer_clock();
307 esdi->callback = 200*IDE_TIME;
308 timer_update_outstanding();
309 break;
310
311 default:
312 pclog("Bad esdi command %02X\n", val);
313 case 0xe8: /*???*/
314 esdi->status = STAT_BUSY;
315 timer_clock();
316 esdi->callback = 200*IDE_TIME;
317 timer_update_outstanding();
318 break;
319 }
320 }
321 break;
322
323 case 0x3F6: /* Device control */
324 if ((esdi->fdisk & 4) && !(val & 4))
325 {
326 timer_clock();
327 esdi->callback = 500*IDE_TIME;
328 timer_update_outstanding();
329 esdi->reset = 1;
330 esdi->status = STAT_BUSY;
331 // pclog("esdi Reset\n");
332 }
333 if (val & 4)
334 {
335 /*Drive held in reset*/
336 timer_clock();
337 esdi->callback = 0;
338 timer_update_outstanding();
339 esdi->status = STAT_BUSY;
340 }
341 esdi->fdisk = val;
342 esdi_irq_update(esdi);
343 return;
344 }
345 // fatal("Bad ESDI write %04X %02X\n", port, val);
346 }
347
esdi_writew(uint16_t port,uint16_t val,void * p)348 void esdi_writew(uint16_t port, uint16_t val, void *p)
349 {
350 esdi_t *esdi = (esdi_t *)p;
351
352 // pclog("Write ESDIw %04X\n",val);
353 esdi->buffer[esdi->pos >> 1] = val;
354 esdi->pos += 2;
355
356 if (esdi->pos >= 512)
357 {
358 esdi->pos = 0;
359 esdi->status = STAT_BUSY;
360 timer_clock();
361 esdi->callback = 6*IDE_TIME;
362 timer_update_outstanding();
363 }
364 }
365
esdi_read(uint16_t port,void * p)366 uint8_t esdi_read(uint16_t port, void *p)
367 {
368 esdi_t *esdi = (esdi_t *)p;
369 uint8_t temp = 0xff;
370
371 switch (port)
372 {
373 case 0x1F0: /* Data */
374 temp = esdi_readw(port, esdi) & 0xff;
375 break;
376
377 case 0x1F1: /* Error */
378 temp = esdi->error;
379 break;
380
381 case 0x1F2: /* Sector count */
382 temp = (uint8_t)esdi->secount;
383 break;
384
385 case 0x1F3: /* Sector */
386 temp = (uint8_t)esdi->sector;
387 break;
388
389 case 0x1F4: /* Cylinder low */
390 temp = (uint8_t)(esdi->cylinder&0xFF);
391 break;
392
393 case 0x1F5: /* Cylinder high */
394 temp = (uint8_t)(esdi->cylinder>>8);
395 break;
396
397 case 0x1F6: /* Drive/Head */
398 temp = (uint8_t)(esdi->head | (esdi->drive_sel ? 0x10 : 0) | 0xa0);
399 break;
400
401 case 0x1F7: /* Status */
402 esdi_irq_lower(esdi);
403 temp = esdi->status;
404 break;
405 }
406
407 // if (port != 0x1f7) pclog("esdi_read: addr=%04x val=%02x %04X:%04x\n", port, temp, CS, cpu_state.pc);
408 return temp;
409 }
410
esdi_readw(uint16_t port,void * p)411 uint16_t esdi_readw(uint16_t port, void *p)
412 {
413 esdi_t *esdi = (esdi_t *)p;
414 uint16_t temp;
415
416 temp = esdi->buffer[esdi->pos >> 1];
417 esdi->pos += 2;
418
419 if (esdi->pos >= 512)
420 {
421 // pclog("Over! packlen %i %i\n",ide->packlen,ide->pos);
422 esdi->pos=0;
423 esdi->status = STAT_READY | STAT_DSC;
424 if (esdi->command == CMD_READ || esdi->command == 0xa0)
425 {
426 esdi->secount = (esdi->secount - 1) & 0xff;
427 if (esdi->secount)
428 {
429 esdi_next_sector(esdi);
430 esdi->status = STAT_BUSY;
431 timer_clock();
432 esdi->callback = 6*IDE_TIME;
433 timer_update_outstanding();
434 }
435 }
436 }
437
438 // pclog("esdi_readw: temp=%04x %i\n", temp, esdi->pos);
439 return temp;
440 }
441
esdi_callback(void * p)442 void esdi_callback(void *p)
443 {
444 esdi_t *esdi = (esdi_t *)p;
445 esdi_drive_t *drive = &esdi->drives[esdi->drive_sel];
446 off64_t addr;
447
448 // pclog("esdi_callback: command=%02x reset=%i\n", esdi->command, esdi->reset);
449 esdi->callback = 0;
450 if (esdi->reset)
451 {
452 esdi->status = STAT_READY | STAT_DSC;
453 esdi->error = 1;
454 esdi->secount = 1;
455 esdi->sector = 1;
456 esdi->head = 0;
457 esdi->cylinder = 0;
458 esdi->reset = 0;
459 // pclog("Reset callback\n");
460 return;
461 }
462 switch (esdi->command)
463 {
464 case CMD_RESTORE:
465 if (!drive->hdd_file.f)
466 {
467 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
468 esdi->error = ERR_ABRT;
469 esdi_irq_raise(esdi);
470 }
471 else
472 {
473 drive->current_cylinder = 0;
474 esdi->status = STAT_READY | STAT_DSC;
475 esdi_irq_raise(esdi);
476 }
477 break;
478
479 case CMD_SEEK:
480 if (!drive->hdd_file.f)
481 {
482 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
483 esdi->error = ERR_ABRT;
484 esdi_irq_raise(esdi);
485 }
486 else
487 {
488 esdi->status = STAT_READY | STAT_DSC;
489 esdi_irq_raise(esdi);
490 }
491 break;
492
493 case CMD_READ:
494 if (!drive->hdd_file.f)
495 {
496 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
497 esdi->error = ERR_ABRT;
498 esdi_irq_raise(esdi);
499 }
500 else
501 {
502 if (esdi_get_sector(esdi, &addr))
503 {
504 esdi->error = ERR_ID_NOT_FOUND;
505 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
506 esdi_irq_raise(esdi);
507 break;
508 }
509 if (hdd_read_sectors(&drive->hdd_file, addr, 1, esdi->buffer))
510 {
511 esdi->error = ERR_ID_NOT_FOUND;
512 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
513 esdi_irq_raise(esdi);
514 break;
515 }
516 esdi->pos = 0;
517 esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
518 // pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]);
519 // if (addr) output=3;
520 esdi_irq_raise(esdi);
521 readflash_set(READFLASH_HDC, esdi->drive_sel);
522 }
523 break;
524
525 case CMD_WRITE:
526 if (!drive->hdd_file.f)
527 {
528 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
529 esdi->error = ERR_ABRT;
530 esdi_irq_raise(esdi);
531 }
532 else
533 {
534 if (esdi_get_sector(esdi, &addr))
535 {
536 esdi->error = ERR_ID_NOT_FOUND;
537 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
538 esdi_irq_raise(esdi);
539 break;
540 }
541 if (hdd_write_sectors(&drive->hdd_file, addr, 1, esdi->buffer))
542 {
543 esdi->error = ERR_ID_NOT_FOUND;
544 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
545 esdi_irq_raise(esdi);
546 break;
547 }
548 esdi_irq_raise(esdi);
549 esdi->secount = (esdi->secount - 1) & 0xff;
550 if (esdi->secount)
551 {
552 esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
553 esdi->pos = 0;
554 esdi_next_sector(esdi);
555 }
556 else
557 esdi->status = STAT_READY | STAT_DSC;
558 readflash_set(READFLASH_HDC, esdi->drive_sel);
559 }
560 break;
561
562 case CMD_VERIFY:
563 if (!drive->hdd_file.f)
564 {
565 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
566 esdi->error = ERR_ABRT;
567 esdi_irq_raise(esdi);
568 }
569 else
570 {
571 if (esdi_get_sector(esdi, &addr))
572 {
573 esdi->error = ERR_ID_NOT_FOUND;
574 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
575 esdi_irq_raise(esdi);
576 break;
577 }
578 if (hdd_read_sectors(&drive->hdd_file, addr, 1, esdi->buffer))
579 {
580 esdi->error = ERR_ID_NOT_FOUND;
581 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
582 esdi_irq_raise(esdi);
583 break;
584 }
585 readflash_set(READFLASH_HDC, esdi->drive_sel);
586 esdi_next_sector(esdi);
587 esdi->secount = (esdi->secount - 1) & 0xff;
588 if (esdi->secount)
589 esdi->callback = 6*IDE_TIME;
590 else
591 {
592 esdi->pos = 0;
593 esdi->status = STAT_READY | STAT_DSC;
594 // pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount);
595 esdi_irq_raise(esdi);
596 }
597 }
598 break;
599
600 case CMD_FORMAT:
601 if (!drive->hdd_file.f)
602 {
603 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
604 esdi->error = ERR_ABRT;
605 esdi_irq_raise(esdi);
606 }
607 else
608 {
609 if (esdi_get_sector(esdi, &addr))
610 {
611 esdi->error = ERR_ID_NOT_FOUND;
612 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
613 esdi_irq_raise(esdi);
614 break;
615 }
616 if (hdd_format_sectors(&drive->hdd_file, addr, esdi->secount))
617 {
618 esdi->error = ERR_ID_NOT_FOUND;
619 esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
620 esdi_irq_raise(esdi);
621 break;
622 }
623 esdi->status = STAT_READY | STAT_DSC;
624 esdi_irq_raise(esdi);
625 readflash_set(READFLASH_HDC, esdi->drive_sel);
626 }
627 break;
628
629 case CMD_DIAGNOSE:
630 if (!drive->hdd_file.f)
631 {
632 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
633 esdi->error = ERR_ABRT;
634 esdi_irq_raise(esdi);
635 }
636 else
637 {
638 esdi->error = 1; /*No error detected*/
639 esdi->status = STAT_READY | STAT_DSC;
640 esdi_irq_raise(esdi);
641 }
642 break;
643
644 case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */
645 if (!drive->hdd_file.f)
646 {
647 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
648 esdi->error = ERR_ABRT;
649 esdi_irq_raise(esdi);
650 }
651 else
652 {
653 drive->cfg_spt = esdi->secount;
654 drive->cfg_hpc = esdi->head+1;
655 pclog("Parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc);
656 if (!esdi->secount)
657 fatal("secount=0\n");
658 esdi->status = STAT_READY | STAT_DSC;
659 esdi_irq_raise(esdi);
660 }
661 break;
662
663 case CMD_NOP:
664 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
665 esdi->error = ERR_ABRT;
666 esdi_irq_raise(esdi);
667 break;
668
669 case 0xe0:
670 if (!drive->hdd_file.f)
671 {
672 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
673 esdi->error = ERR_ABRT;
674 esdi_irq_raise(esdi);
675 }
676 else
677 {
678 switch (esdi->cylinder >> 8)
679 {
680 case 0x31:
681 esdi->cylinder = drive->hdd_file.tracks;
682 break;
683 case 0x33:
684 esdi->cylinder = drive->hdd_file.hpc;
685 break;
686 case 0x35:
687 esdi->cylinder = 0x200;
688 break;
689 case 0x36:
690 esdi->cylinder = drive->hdd_file.spt;
691 break;
692 default:
693 pclog("EDSI Bad read config %02x\n", esdi->cylinder >> 8);
694 }
695 esdi->status = STAT_READY | STAT_DSC;
696 esdi_irq_raise(esdi);
697 }
698 break;
699
700 case 0xa0:
701 if (!drive->hdd_file.f)
702 {
703 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
704 esdi->error = ERR_ABRT;
705 esdi_irq_raise(esdi);
706 }
707 else
708 {
709 memset(esdi->buffer, 0, 512);
710 memset(&esdi->buffer[3], 0xff, 512-6);
711 esdi->pos = 0;
712 esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
713 // pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]);
714 // if (addr) output=3;
715 esdi_irq_raise(esdi);
716 }
717 break;
718
719 case CMD_READ_PARAMETERS:
720 if (!drive->hdd_file.f)
721 {
722 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
723 esdi->error = ERR_ABRT;
724 esdi_irq_raise(esdi);
725 }
726 else
727 {
728 memset(esdi->buffer, 0, 512);
729
730 esdi->buffer[0] = 0x44; /* general configuration */
731 esdi->buffer[1] = drive->hdd_file.tracks; /* number of non-removable cylinders */
732 esdi->buffer[2] = 0; /* number of removable cylinders */
733 esdi->buffer[3] = drive->hdd_file.hpc; /* number of heads */
734 esdi->buffer[5] = esdi->buffer[4] * drive->hdd_file.spt; /* number of unformatted bytes/sector */
735 esdi->buffer[4] = 600; /* number of unformatted bytes/track */
736 esdi->buffer[6] = drive->hdd_file.spt; /* number of sectors */
737 esdi->buffer[7] = 0; /*minimum bytes in inter-sector gap*/
738 esdi->buffer[8] = 0; /* minimum bytes in postamble */
739 esdi->buffer[9] = 0; /* number of words of vendor status */
740 /* controller info */
741 // char wdp_cnsn[20]; /* controller serial number */
742 esdi->buffer[20] = 2; /* controller type */
743 esdi->buffer[21] = 1; /* sector buffer size, in sectors */
744 esdi->buffer[22] = 0; /* ecc bytes appended */
745 // char wdp_rev[8]; /* firmware revision */
746 //27
747 esdi->buffer[27] = 'W' | ('D' << 8);
748 esdi->buffer[28] = '1' | ('0' << 8);
749 esdi->buffer[29] = '0' | ('7' << 8);
750 esdi->buffer[30] = 'V' | ('-' << 8);
751 esdi->buffer[31] = 'S' | ('E' << 8);
752 esdi->buffer[32] = '1';
753 esdi->buffer[47] = 0; /* sectors per interrupt */
754 esdi->buffer[48] = 0;/* can use double word read/write? */
755 esdi->pos = 0;
756 esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
757 esdi_irq_raise(esdi);
758 }
759 break;
760
761 default:
762 pclog("ESDI Callback on unknown command %02x\n", esdi->command);
763 case 0xe8:
764 esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
765 esdi->error = ERR_ABRT;
766 esdi_irq_raise(esdi);
767 break;
768 }
769 }
770
esdi_rom_write(uint32_t addr,uint8_t val,void * p)771 static void esdi_rom_write(uint32_t addr, uint8_t val, void *p)
772 {
773 rom_t *rom = (rom_t *)p;
774
775 addr &= rom->mask;
776
777 if (addr >= 0x1f00 && addr < 0x2000)
778 rom->rom[addr] = val;
779 }
780
wd1007vse1_init()781 void *wd1007vse1_init()
782 {
783 esdi_t *esdi = malloc(sizeof(esdi_t));
784 memset(esdi, 0, sizeof(esdi_t));
785
786 hdd_load(&esdi->drives[0].hdd_file, 0, ide_fn[0]);
787 hdd_load(&esdi->drives[1].hdd_file, 1, ide_fn[1]);
788
789 esdi->drives[0].cfg_spt = esdi->drives[0].hdd_file.spt;
790 esdi->drives[0].cfg_hpc = esdi->drives[0].hdd_file.hpc;
791 esdi->drives[1].cfg_spt = esdi->drives[1].hdd_file.spt;
792 esdi->drives[1].cfg_hpc = esdi->drives[1].hdd_file.hpc;
793
794 esdi->status = STAT_READY | STAT_DSC;
795 esdi->error = 1; /*No errors*/
796
797 rom_init(&esdi->bios_rom, "62-000279-061.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
798
799 mem_mapping_set_handler(&esdi->bios_rom.mapping,
800 rom_read, rom_readw, rom_readl,
801 esdi_rom_write, NULL, NULL);
802
803 io_sethandler(0x01f0, 0x0001, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi);
804 io_sethandler(0x01f1, 0x0007, esdi_read, NULL, NULL, esdi_write, NULL, NULL, esdi);
805 io_sethandler(0x03f6, 0x0001, NULL, NULL, NULL, esdi_write, NULL, NULL, esdi);
806
807 timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi);
808
809 return esdi;
810 }
811
wd1007vse1_close(void * p)812 void wd1007vse1_close(void *p)
813 {
814 esdi_t *esdi = (esdi_t *)p;
815
816 hdd_close(&esdi->drives[0].hdd_file);
817 hdd_close(&esdi->drives[1].hdd_file);
818
819 free(esdi);
820 }
821
wd1007vse1_available()822 static int wd1007vse1_available()
823 {
824 return rom_present("62-000279-061.bin");
825 }
826
827 device_t wd1007vse1_device =
828 {
829 "Western Digital WD1007V-SE1 (ESDI)",
830 DEVICE_AT,
831 wd1007vse1_init,
832 wd1007vse1_close,
833 wd1007vse1_available,
834 NULL,
835 NULL,
836 NULL,
837 NULL
838 };
839