PCem
view src/ide.c @ 147:a221bebd5ff3
Fixed IDE transfers of 256 sectors, Windows 2000 now works.
| author | TomW |
|---|---|
| date | Wed Aug 20 19:37:23 2014 +0100 |
| parents | 42d0b879eb9e |
| children |
line source
1 /*RPCemu v0.6 by Tom Walker
2 IDE emulation*/
3 //#define RPCEMU_IDE
5 #define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT))
7 #define _LARGEFILE_SOURCE
8 #define _LARGEFILE64_SOURCE
9 #define _GNU_SOURCE
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <string.h>
15 #include <sys/types.h>
17 #ifdef RPCEMU_IDE
18 #include "rpcemu.h"
19 #include "iomd.h"
20 #include "arm.h"
21 #else
22 #include "ibm.h"
23 #include "io.h"
24 #include "pic.h"
25 #include "timer.h"
26 #endif
27 #include "ide.h"
29 /* Bits of 'atastat' */
30 #define ERR_STAT 0x01
31 #define DRQ_STAT 0x08 /* Data request */
32 #define DSC_STAT 0x10
33 #define SERVICE_STAT 0x10
34 #define READY_STAT 0x40
35 #define BUSY_STAT 0x80
37 /* Bits of 'error' */
38 #define ABRT_ERR 0x04 /* Command aborted */
39 #define MCR_ERR 0x08 /* Media change request */
41 /* ATA Commands */
42 #define WIN_SRST 0x08 /* ATAPI Device Reset */
43 #define WIN_RECAL 0x10
44 #define WIN_RESTORE WIN_RECAL
45 #define WIN_READ 0x20 /* 28-Bit Read */
46 #define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/
47 #define WIN_WRITE 0x30 /* 28-Bit Write */
48 #define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */
49 #define WIN_VERIFY 0x40 /* 28-Bit Verify */
50 #define WIN_FORMAT 0x50
51 #define WIN_SEEK 0x70
52 #define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */
53 #define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */
54 #define WIN_PACKETCMD 0xA0 /* Send a packet command. */
55 #define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */
56 #define WIN_READ_MULTIPLE 0xC4
57 #define WIN_WRITE_MULTIPLE 0xC5
58 #define WIN_SET_MULTIPLE_MODE 0xC6
59 #define WIN_READ_DMA 0xC8
60 #define WIN_WRITE_DMA 0xCA
61 #define WIN_SETIDLE1 0xE3
62 #define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */
64 /* ATAPI Commands */
65 #define GPCMD_INQUIRY 0x12
66 #define GPCMD_MODE_SELECT_10 0x55
67 #define GPCMD_MODE_SENSE_10 0x5a
68 #define GPCMD_PAUSE_RESUME 0x4b
69 #define GPCMD_PLAY_AUDIO_12 0xa5
70 #define GPCMD_PLAY_AUDIO_MSF 0x47
71 #define GPCMD_PREVENT_REMOVAL 0x1e
72 #define GPCMD_READ_10 0x28
73 #define GPCMD_READ_CD 0xbe
74 #define GPCMD_READ_CDROM_CAPACITY 0x25
75 #define GPCMD_READ_HEADER 0x44
76 #define GPCMD_READ_SUBCHANNEL 0x42
77 #define GPCMD_READ_TOC_PMA_ATIP 0x43
78 #define GPCMD_REQUEST_SENSE 0x03
79 #define GPCMD_SEEK 0x2b
80 #define GPCMD_SEND_DVD_STRUCTURE 0xad
81 #define GPCMD_SET_SPEED 0xbb
82 #define GPCMD_START_STOP_UNIT 0x1b
83 #define GPCMD_TEST_UNIT_READY 0x00
85 /* Mode page codes for mode sense/set */
86 #define GPMODE_R_W_ERROR_PAGE 0x01
87 #define GPMODE_CDROM_PAGE 0x0d
88 #define GPMODE_CDROM_AUDIO_PAGE 0x0e
89 #define GPMODE_CAPABILITIES_PAGE 0x2a
90 #define GPMODE_ALL_PAGES 0x3f
92 /* ATAPI Sense Keys */
93 #define SENSE_NONE 0
94 #define SENSE_NOT_READY 2
95 #define SENSE_ILLEGAL_REQUEST 5
96 #define SENSE_UNIT_ATTENTION 6
98 /* ATAPI Additional Sense Codes */
99 #define ASC_ILLEGAL_OPCODE 0x20
100 #define ASC_MEDIUM_NOT_PRESENT 0x3a
102 /* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw).
103 Not that it means anything */
104 #define CDROM_SPEED 706
106 /** Evaluate to non-zero if the currently selected drive is an ATAPI device */
107 #define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM)
108 /*
109 \
110 (!ide.drive)*/
112 ATAPI *atapi;
114 enum
115 {
116 IDE_NONE = 0,
117 IDE_HDD,
118 IDE_CDROM
119 };
121 typedef struct IDE
122 {
123 int type;
124 int board;
125 uint8_t atastat;
126 uint8_t error;
127 int secount,sector,cylinder,head,drive,cylprecomp;
128 uint8_t command;
129 uint8_t fdisk;
130 int pos;
131 int packlen;
132 int spt,hpc;
133 int tracks;
134 int packetstatus;
135 int cdpos,cdlen;
136 uint8_t asc;
137 int discchanged;
138 int reset;
139 FILE *hdfile;
140 uint16_t buffer[65536];
141 int irqstat;
142 int service;
143 int lba;
144 uint32_t lba_addr;
145 int skip512;
146 int blocksize, blockcount;
147 } IDE;
149 IDE ide_drives[4];
151 IDE *ext_ide;
153 char ide_fn[2][512];
155 int (*ide_bus_master_read_sector)(int channel, uint8_t *data);
156 int (*ide_bus_master_write_sector)(int channel, uint8_t *data);
157 void (*ide_bus_master_set_irq)(int channel);
159 static void callreadcd(IDE *ide);
160 static void atapicommand(int ide_board);
162 int idecallback[2] = {0, 0};
164 int cur_ide[2];
166 uint8_t getstat(IDE *ide) { return ide->atastat; }
168 static inline void ide_irq_raise(IDE *ide)
169 {
170 // pclog("IDE_IRQ_RAISE\n");
171 if (!(ide->fdisk&2)) {
172 #ifdef RPCEMU_IDE
173 iomd.irqb.status |= IOMD_IRQB_IDE;
174 updateirqs();
175 #else
176 // if (ide->board && !ide->irqstat) pclog("IDE_IRQ_RAISE\n");
177 picint((ide->board)?(1<<15):(1<<14));
178 #endif
179 }
180 ide->irqstat=1;
181 ide->service=1;
182 }
184 static inline void ide_irq_lower(IDE *ide)
185 {
186 // pclog("IDE_IRQ_LOWER\n");
187 // if (ide.board == 0) {
188 #ifdef RPCEMU_IDE
189 iomd.irqb.status &= ~IOMD_IRQB_IDE;
190 updateirqs();
191 #else
192 picintc((ide->board)?(1<<15):(1<<14));
193 #endif
194 // }
195 ide->irqstat=0;
196 }
198 void ide_irq_update(IDE *ide)
199 {
200 #ifdef RPCEMU_IDE
201 if (ide->irqstat && !(iomd.irqb.status & IOMD_IRQB_IDE) && !(ide->fdisk & 2)) {
202 iomd.irqb.status |= IOMD_IRQB_IDE;
203 updateirqs();
204 }
205 else if (iomd.irqb.status & IOMD_IRQB_IDE)
206 {
207 iomd.irqb.status &= ~IOMD_IRQB_IDE;
208 updateirqs();
209 }
210 #else
211 if (ide->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(ide->fdisk & 2))
212 picint((ide->board)?(1<<15):(1<<14));
213 else if ((pic2.pend|pic2.ins)&0x40)
214 picintc((ide->board)?(1<<15):(1<<14));
215 #endif
216 }
217 /**
218 * Copy a string into a buffer, padding with spaces, and placing characters as
219 * if they were packed into 16-bit values, stored little-endian.
220 *
221 * @param str Destination buffer
222 * @param src Source string
223 * @param len Length of destination buffer to fill in. Strings shorter than
224 * this length will be padded with spaces.
225 */
226 static void
227 ide_padstr(char *str, const char *src, int len)
228 {
229 int i, v;
231 for (i = 0; i < len; i++) {
232 if (*src != '\0') {
233 v = *src++;
234 } else {
235 v = ' ';
236 }
237 str[i ^ 1] = v;
238 }
239 }
241 /**
242 * Copy a string into a buffer, padding with spaces. Does not add string
243 * terminator.
244 *
245 * @param buf Destination buffer
246 * @param buf_size Size of destination buffer to fill in. Strings shorter than
247 * this length will be padded with spaces.
248 * @param src Source string
249 */
250 static void
251 ide_padstr8(uint8_t *buf, int buf_size, const char *src)
252 {
253 int i;
255 for (i = 0; i < buf_size; i++) {
256 if (*src != '\0') {
257 buf[i] = *src++;
258 } else {
259 buf[i] = ' ';
260 }
261 }
262 }
264 /**
265 * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command
266 */
267 static void ide_identify(IDE *ide)
268 {
269 memset(ide->buffer, 0, 512);
271 //ide->buffer[1] = 101; /* Cylinders */
273 #ifdef RPCEMU_IDE
274 ide->buffer[1] = 65535; /* Cylinders */
275 ide->buffer[3] = 16; /* Heads */
276 ide->buffer[6] = 63; /* Sectors */
277 #else
278 ide->buffer[1] = hdc[cur_ide[0]].tracks; /* Cylinders */
279 ide->buffer[3] = hdc[cur_ide[0]].hpc; /* Heads */
280 ide->buffer[6] = hdc[cur_ide[0]].spt; /* Sectors */
281 #endif
282 ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */
283 ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */
284 #ifdef RPCEMU_IDE
285 ide_padstr((char *) (ide->buffer + 27), "RPCemuHD", 40); /* Model */
286 #else
287 ide_padstr((char *) (ide->buffer + 27), "PCemHD", 40); /* Model */
288 #endif
289 ide->buffer[20] = 3; /*Buffer type*/
290 ide->buffer[21] = 512; /*Buffer size*/
291 ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/
292 ide->buffer[48] = 1; /*Dword transfers supported*/
293 ide->buffer[49] = (1 << 9) | (1 << 8); /* LBA and DMA supported */
294 ide->buffer[50] = 0x4000; /* Capabilities */
295 ide->buffer[51] = 2 << 8; /*PIO timing mode*/
296 ide->buffer[52] = 2 << 8; /*DMA timing mode*/
297 ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0;
298 #ifdef RPCEMU_IDE
299 ide->buffer[60] = (65535 * 16 * 63) & 0xFFFF; /* Total addressable sectors (LBA) */
300 ide->buffer[61] = (65535 * 16 * 63) >> 16;
301 #else
302 ide->buffer[60] = (hdc[cur_ide[0]].tracks * hdc[cur_ide[0]].hpc * hdc[cur_ide[0]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */
303 ide->buffer[61] = (hdc[cur_ide[0]].tracks * hdc[cur_ide[0]].hpc * hdc[cur_ide[0]].spt) >> 16;
304 #endif
305 ide->buffer[63] = 7; /*Multiword DMA*/
306 ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/
307 }
309 /**
310 * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command
311 */
312 static void ide_atapi_identify(IDE *ide)
313 {
314 memset(ide->buffer, 0, 512);
316 ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */
317 ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */
318 ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */
319 #ifdef RPCEMU_IDE
320 ide_padstr((char *) (ide->buffer + 27), "RPCemuCD", 40); /* Model */
321 #else
322 ide_padstr((char *) (ide->buffer + 27), "PCemCD", 40); /* Model */
323 #endif
324 ide->buffer[49] = 0x200; /* LBA supported */
325 }
327 /**
328 * Fill in ide->buffer with the output of the ATAPI "MODE SENSE" command
329 *
330 * @param pos Offset within the buffer to start filling in data
331 *
332 * @return Offset within the buffer after the end of the data
333 */
334 static uint32_t ide_atapi_mode_sense(IDE *ide, uint32_t pos, uint8_t type)
335 {
336 uint8_t *buf = (uint8_t *) ide->buffer;
337 // pclog("ide_atapi_mode_sense %02X\n",type);
338 if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE)
339 {
340 /* &01 - Read error recovery */
341 buf[pos++] = GPMODE_R_W_ERROR_PAGE;
342 buf[pos++] = 6; /* Page length */
343 buf[pos++] = 0; /* Error recovery parameters */
344 buf[pos++] = 3; /* Read retry count */
345 buf[pos++] = 0; /* Reserved */
346 buf[pos++] = 0; /* Reserved */
347 buf[pos++] = 0; /* Reserved */
348 buf[pos++] = 0; /* Reserved */
349 }
351 if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE)
352 {
353 /* &0D - CD-ROM Parameters */
354 buf[pos++] = GPMODE_CDROM_PAGE;
355 buf[pos++] = 6; /* Page length */
356 buf[pos++] = 0; /* Reserved */
357 buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */
358 buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */
359 buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */
360 }
362 if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE)
363 {
364 /* &0e - CD-ROM Audio Control Parameters */
365 buf[pos++] = GPMODE_CDROM_AUDIO_PAGE;
366 buf[pos++] = 0xE; /* Page length */
367 buf[pos++] = 4; /* Reserved */
368 buf[pos++] = 0; /* Reserved */
369 buf[pos++] = 0; /* Reserved */
370 buf[pos++] = 0; /* Reserved */
371 buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */
372 buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */
373 buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */
374 buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */
375 buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */
376 buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */
377 buf[pos++] = 0; /* CDDA Output Port 2 Volume */
378 buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */
379 buf[pos++] = 0; /* CDDA Output Port 3 Volume */
380 }
382 if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE)
383 {
384 // pclog("Capabilities page\n");
385 /* &2A - CD-ROM capabilities and mechanical status */
386 buf[pos++] = GPMODE_CAPABILITIES_PAGE;
387 buf[pos++] = 0x12; /* Page length */
388 buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */
389 buf[pos++] = 1; /* Supports audio play, not multisession */
390 buf[pos++] = 0; /* Some other stuff not supported */
391 buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */
392 buf[pos++] = 0; /* Some other stuff not supported */
393 buf[pos++] = (uint8_t) (CDROM_SPEED >> 8);
394 buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */
395 buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */
396 buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */
397 buf[pos++] = (uint8_t) (CDROM_SPEED >> 8);
398 buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */
399 buf[pos++] = 0; /* Reserved */
400 buf[pos++] = 0; /* Drive digital format */
401 buf[pos++] = 0; /* Reserved */
402 buf[pos++] = 0; /* Reserved */
403 }
405 return pos;
406 }
408 /*
409 * Return the sector offset for the current register values
410 */
411 static off64_t ide_get_sector(IDE *ide)
412 {
413 if (ide->lba)
414 {
415 return (off64_t)ide->lba_addr + ide->skip512;
416 }
417 else
418 {
419 int heads = ide->hpc;
420 int sectors = ide->spt;
422 return ((((off64_t) ide->cylinder * heads) + ide->head) *
423 sectors) + (ide->sector - 1) + ide->skip512;
424 }
425 }
427 /**
428 * Move to the next sector using CHS addressing
429 */
430 static void ide_next_sector(IDE *ide)
431 {
432 if (ide->lba)
433 {
434 ide->lba_addr++;
435 }
436 else
437 {
438 ide->sector++;
439 if (ide->sector == (ide->spt + 1)) {
440 ide->sector = 1;
441 ide->head++;
442 if (ide->head == ide->hpc) {
443 ide->head = 0;
444 ide->cylinder++;
445 }
446 }
447 }
448 }
450 #ifdef RPCEMU_IDE
451 static void loadhd(IDE *ide, int d, const char *fn)
452 {
453 char pathname[512];
455 append_filename(pathname, rpcemu_get_datadir(), fn, 512);
457 rpclog("Loading %s\n",pathname);
458 if (ide->hdfile == NULL) {
459 /* Try to open existing hard disk image */
460 ide->hdfile = fopen64(pathname, "rb+");
461 if (ide->hdfile == NULL) {
462 /* Failed to open existing hard disk image */
463 if (errno == ENOENT) {
464 /* Failed because it does not exist,
465 so try to create new file */
466 ide->hdfile = fopen64(pathname, "wb+");
467 if (ide->hdfile == NULL) {
468 fatal("Cannot create file '%s': %s",
469 pathname, strerror(errno));
470 }
471 } else {
472 /* Failed for another reason */
473 fatal("Cannot open file '%s': %s",
474 pathname, strerror(errno));
475 }
476 }
477 }
479 fseek(ide->hdfile, 0xfc1, SEEK_SET);
480 ide->spt = getc(ide->hdfile);
481 ide->hpc = getc(ide->hdfile);
482 ide->skip512 = 1;
483 // rpclog("First check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]);
484 if (!ide->spt || !ide->hpc)
485 {
486 fseek(ide->hdfile, 0xdc1, SEEK_SET);
487 ide->spt = getc(ide->hdfile);
488 ide->hpc = getc(ide->hdfile);
489 // rpclog("Second check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]);
490 ide->skip512 = 0;
491 if (!ide->spt || !ide->hpc)
492 {
493 ide->spt=63;
494 ide->hpc=16;
495 ide->skip512 = 1;
496 // rpclog("Final check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]);
497 }
498 }
500 ide->type = IDE_HDD;
502 rpclog("%i %i %i\n",ide->spt,ide->hpc,ide->skip512);
503 }
504 #else
505 static void loadhd(IDE *ide, int d, const char *fn)
506 {
507 if (ide->hdfile == NULL) {
508 /* Try to open existing hard disk image */
509 ide->hdfile = fopen64(fn, "rb+");
510 if (ide->hdfile == NULL) {
511 /* Failed to open existing hard disk image */
512 if (errno == ENOENT) {
513 /* Failed because it does not exist,
514 so try to create new file */
515 ide->hdfile = fopen64(fn, "wb+");
516 if (ide->hdfile == NULL) {
517 ide->type = IDE_NONE;
518 /* fatal("Cannot create file '%s': %s",
519 fn, strerror(errno));*/
520 return;
521 }
522 } else {
523 /* Failed for another reason */
524 ide->type = IDE_NONE;
525 /* fatal("Cannot open file '%s': %s",
526 fn, strerror(errno));*/
527 return;
528 }
529 }
530 }
532 ide->spt = hdc[d].spt;
533 ide->hpc = hdc[d].hpc;
534 ide->tracks = hdc[d].tracks;
535 ide->type = IDE_HDD;
536 }
537 #endif
539 void resetide(void)
540 {
541 int d;
543 /* Close hard disk image files (if previously open) */
544 for (d = 0; d < 4; d++) {
545 ide_drives[d].type = IDE_NONE;
546 if (ide_drives[d].hdfile != NULL) {
547 fclose(ide_drives[d].hdfile);
548 ide_drives[d].hdfile = NULL;
549 }
550 ide_drives[d].atastat = READY_STAT | DSC_STAT;
551 ide_drives[d].service = 0;
552 ide_drives[d].board = (d & 2) ? 1 : 0;
553 }
555 idecallback[0]=idecallback[1]=0;
556 #ifdef RPCEMU_IDE
557 loadhd(&ide_drives[0], 0, "hd4.hdf");
558 if (!config.cdromenabled) {
559 loadhd(&ide_drives[1], 1, "hd5.hdf");
560 }
561 else
562 ide_drives[1].type = IDE_CDROM;
563 #else
564 loadhd(&ide_drives[0], 0, ide_fn[0]);
565 loadhd(&ide_drives[1], 1, ide_fn[1]);
566 if (cdrom_enabled)
567 ide_drives[2].type = IDE_CDROM;
568 #endif
570 cur_ide[0] = 0;
571 cur_ide[1] = 2;
573 // ide_drives[1].type = IDE_CDROM;
574 }
576 int idetimes=0;
577 void writeidew(int ide_board, uint16_t val)
578 {
579 IDE *ide = &ide_drives[cur_ide[ide_board]];
580 #ifndef RPCEMU_IDE
581 /* if (ide_board && (cr0&1) && !(eflags&VM_FLAG))
582 {
583 // pclog("Failed write IDE %04X:%08X\n",CS,pc);
584 return;
585 }*/
586 #endif
587 #ifdef _RPCEMU_BIG_ENDIAN
588 val=(val>>8)|(val<<8);
589 #endif
590 // pclog("Write IDEw %04X\n",val);
591 ide->buffer[ide->pos >> 1] = val;
592 ide->pos+=2;
594 if (ide->packetstatus==4)
595 {
596 if (ide->pos>=(ide->packlen+2))
597 {
598 ide->packetstatus=5;
599 timer_process();
600 idecallback[ide_board]=6*IDE_TIME;
601 timer_update_outstanding();
602 // pclog("Packet over!\n");
603 ide_irq_lower(ide);
604 }
605 return;
606 }
607 else if (ide->packetstatus==5) return;
608 else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC)
609 {
610 ide->pos=0;
611 ide->atastat = BUSY_STAT;
612 ide->packetstatus=1;
613 /* idecallback[ide_board]=6*IDE_TIME;*/
614 timer_process();
615 callbackide(ide_board);
616 timer_update_outstanding();
617 // idecallback[ide_board]=60*IDE_TIME;
618 // if ((ide->buffer[0]&0xFF)==0x43) idecallback[ide_board]=1*IDE_TIME;
619 // pclog("Packet now waiting!\n");
620 /* if (ide->buffer[0]==0x243)
621 {
622 idetimes++;
623 output=3;
624 }*/
625 }
626 else if (ide->pos>=512)
627 {
628 ide->pos=0;
629 ide->atastat = BUSY_STAT;
630 timer_process();
631 if (ide->command == WIN_WRITE_MULTIPLE)
632 callbackide(ide_board);
633 else
634 idecallback[ide_board]=6*IDE_TIME;
635 timer_update_outstanding();
636 }
637 }
639 void writeidel(int ide_board, uint32_t val)
640 {
641 // pclog("WriteIDEl %08X\n", val);
642 writeidew(ide_board, val);
643 writeidew(ide_board, val >> 16);
644 }
646 void writeide(int ide_board, uint16_t addr, uint8_t val)
647 {
648 IDE *ide = &ide_drives[cur_ide[ide_board]];
649 IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1];
650 #ifndef RPCEMU_IDE
651 /* if (ide_board && (cr0&1) && !(eflags&VM_FLAG))
652 {
653 // pclog("Failed write IDE %04X:%08X\n",CS,pc);
654 return;
655 }*/
656 #endif
657 // if ((cr0&1) && !(eflags&VM_FLAG))
658 // pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, pc, ins);
659 // return;
660 addr|=0x80;
661 // if (ide_board) pclog("Write IDEb %04X %02X %04X(%08X):%04X %i %02X %02X\n",addr,val,CS,cs,pc,ins,ide->atastat,ide_drives[0].atastat);
662 /*if (idedebug) */
663 // pclog("Write IDE %08X %02X %04X:%08X\n",addr,val,CS,pc);
664 // int c;
665 // rpclog("Write IDE %08X %02X %08X %08X\n",addr,val,PC,armregs[12]);
667 if (ide->type == IDE_NONE && addr != 0x1f6) return;
669 switch (addr)
670 {
671 case 0x1F0: /* Data */
672 writeidew(ide_board, val | (val << 8));
673 return;
675 case 0x1F1: /* Features */
676 ide->cylprecomp = val;
677 ide_other->cylprecomp = val;
678 return;
680 case 0x1F2: /* Sector count */
681 ide->secount = val;
682 ide_other->secount = val;
683 return;
685 case 0x1F3: /* Sector */
686 ide->sector = val;
687 ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val;
688 ide_other->sector = val;
689 ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val;
690 return;
692 case 0x1F4: /* Cylinder low */
693 ide->cylinder = (ide->cylinder & 0xFF00) | val;
694 ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8);
695 ide_other->cylinder = (ide_other->cylinder&0xFF00) | val;
696 ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8);
697 // pclog("Write cylinder low %02X\n",val);
698 return;
700 case 0x1F5: /* Cylinder high */
701 ide->cylinder = (ide->cylinder & 0xFF) | (val << 8);
702 ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16);
703 ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8);
704 ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16);
705 return;
707 case 0x1F6: /* Drive/Head */
708 /* if (val==0xB0)
709 {
710 dumpregs();
711 exit(-1);
712 }*/
714 if (cur_ide[ide_board] != ((val>>4)&1)+(ide_board<<1))
715 {
716 cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1);
718 if (ide->reset)
719 {
720 ide->atastat = READY_STAT | DSC_STAT;
721 ide->error=1;
722 ide->secount=1;
723 ide->sector=1;
724 ide->head=0;
725 ide->cylinder=0;
726 ide->reset = 0;
727 idecallback[ide_board] = 0;
728 timer_update_outstanding();
729 return;
730 }
732 ide = &ide_drives[cur_ide[ide_board]];
733 }
735 ide->head = val & 0xF;
736 ide->lba = val & 0x40;
737 ide_other->head = val & 0xF;
738 ide_other->lba = val & 0x40;
740 ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24);
741 ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24);
743 ide_irq_update(ide);
744 return;
746 case 0x1F7: /* Command register */
747 if (ide->type == IDE_NONE) return;
748 // pclog("IDE command %02X drive %i\n",val,ide.drive);
749 ide_irq_lower(ide);
750 ide->command=val;
752 // pclog("New IDE command - %02X %i %i\n",ide->command,cur_ide[ide_board],ide_board);
753 ide->error=0;
754 switch (val)
755 {
756 case WIN_SRST: /* ATAPI Device Reset */
757 if (IDE_DRIVE_IS_CDROM(ide)) ide->atastat = BUSY_STAT;
758 else ide->atastat = READY_STAT;
759 timer_process();
760 idecallback[ide_board]=100*IDE_TIME;
761 timer_update_outstanding();
762 return;
764 case WIN_RESTORE:
765 case WIN_SEEK:
766 // pclog("WIN_RESTORE start\n");
767 ide->atastat = READY_STAT;
768 timer_process();
769 idecallback[ide_board]=100*IDE_TIME;
770 timer_update_outstanding();
771 return;
773 case WIN_READ_MULTIPLE:
774 if (!ide->blocksize)
775 fatal("READ_MULTIPLE - blocksize = 0\n");
776 #if 0
777 if (ide->lba) pclog("Read Multiple %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr);
778 else pclog("Read Multiple %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins);
779 #endif
780 ide->blockcount = 0;
782 case WIN_READ:
783 case WIN_READ_NORETRY:
784 case WIN_READ_DMA:
785 /* if (ide.secount>1)
786 {
787 fatal("Read %i sectors from sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head);
788 }*/
789 #if 0
790 if (ide->lba) pclog("Read %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr);
791 else pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins);
792 #endif
793 ide->atastat = BUSY_STAT;
794 timer_process();
795 idecallback[ide_board]=200*IDE_TIME;
796 timer_update_outstanding();
797 return;
799 case WIN_WRITE_MULTIPLE:
800 if (!ide->blocksize)
801 fatal("Write_MULTIPLE - blocksize = 0\n");
802 #if 0
803 if (ide->lba) pclog("Write Multiple %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr);
804 else pclog("Write Multiple %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head);
805 #endif
806 ide->blockcount = 0;
808 case WIN_WRITE:
809 case WIN_WRITE_NORETRY:
810 /* if (ide.secount>1)
811 {
812 fatal("Write %i sectors to sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head);
813 }*/
814 #if 0
815 if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr);
816 else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head);
817 #endif
818 ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT;
819 ide->pos=0;
820 return;
822 case WIN_WRITE_DMA:
823 #if 0
824 if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr);
825 else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head);
826 #endif
827 ide->atastat = BUSY_STAT;
828 timer_process();
829 idecallback[ide_board]=200*IDE_TIME;
830 timer_update_outstanding();
831 return;
833 case WIN_VERIFY:
834 #if 0
835 if (ide->lba) pclog("Read verify %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr);
836 else pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head);
837 #endif
838 ide->atastat = BUSY_STAT;
839 timer_process();
840 idecallback[ide_board]=200*IDE_TIME;
841 timer_update_outstanding();
842 return;
844 case WIN_FORMAT:
845 // pclog("Format track %i head %i\n",ide.cylinder,ide.head);
846 ide->atastat = DRQ_STAT;
847 // idecallback[ide_board]=200;
848 ide->pos=0;
849 return;
851 case WIN_SPECIFY: /* Initialize Drive Parameters */
852 ide->atastat = BUSY_STAT;
853 timer_process();
854 idecallback[ide_board]=200*IDE_TIME;
855 timer_update_outstanding();
856 // pclog("SPECIFY\n");
857 // output=1;
858 return;
860 case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */
861 case WIN_PIDENTIFY: /* Identify Packet Device */
862 case WIN_SET_MULTIPLE_MODE: /*Set Multiple Mode*/
863 // output=1;
864 case WIN_SETIDLE1: /* Idle */
865 ide->atastat = BUSY_STAT;
866 timer_process();
867 callbackide(ide_board);
868 // idecallback[ide_board]=200*IDE_TIME;
869 timer_update_outstanding();
870 return;
872 case WIN_IDENTIFY: /* Identify Device */
873 case 0xEF:
874 // output=3;
875 // timetolive=500;
876 ide->atastat = BUSY_STAT;
877 timer_process();
878 idecallback[ide_board]=200*IDE_TIME;
879 timer_update_outstanding();
880 return;
882 case WIN_PACKETCMD: /* ATAPI Packet */
883 ide->packetstatus=0;
884 ide->atastat = BUSY_STAT;
885 timer_process();
886 idecallback[ide_board]=1;//30*IDE_TIME;
887 timer_update_outstanding();
888 ide->pos=0;
889 return;
891 case 0xF0:
892 default:
893 ide->atastat = READY_STAT | ERR_STAT | DSC_STAT;
894 ide->error = ABRT_ERR;
895 ide_irq_raise(ide);
896 /* fatal("Bad IDE command %02X\n", val);*/
897 return;
898 }
900 return;
902 case 0x3F6: /* Device control */
903 if ((ide->fdisk&4) && !(val&4) && (ide->type != IDE_NONE))
904 {
905 timer_process();
906 idecallback[ide_board]=500*IDE_TIME;
907 timer_update_outstanding();
908 ide->reset = 1;
909 ide->atastat = BUSY_STAT;
910 // pclog("IDE Reset\n");
911 }
912 ide->fdisk=val;
913 ide_irq_update(ide);
914 return;
915 }
916 // fatal("Bad IDE write %04X %02X\n", addr, val);
917 }
919 uint8_t readide(int ide_board, uint16_t addr)
920 {
921 IDE *ide = &ide_drives[cur_ide[ide_board]];
922 uint8_t temp;
923 uint16_t tempw;
925 addr|=0x80;
926 #ifndef RPCEMU_IDE
927 /* if (ide_board && (cr0&1) && !(eflags&VM_FLAG))
928 {
929 // pclog("Failed read IDE %04X:%08X\n",CS,pc);
930 return 0xFF;
931 }*/
932 #endif
933 // if ((cr0&1) && !(eflags&VM_FLAG))
934 // pclog("ReadIDE %04X from %04X(%08X):%08X\n", addr, CS, cs, pc);
935 // return 0xFF;
937 if (ide->type == IDE_NONE && addr != 0x1f6) return 0;
938 // /*if (addr!=0x1F7 && addr!=0x3F6) */pclog("Read IDEb %04X %02X %02X %i %04X:%04X %i %04X\n",addr,ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board, BX);
939 //rpclog("Read IDE %08X %08X %02X\n",addr,PC,iomd.irqb.mask);
940 switch (addr)
941 {
942 case 0x1F0: /* Data */
943 tempw = readidew(ide_board);
944 // pclog("Read IDEW %04X\n", tempw);
945 temp = tempw & 0xff;
946 break;
948 case 0x1F1: /* Error */
949 // pclog("Read error %02X\n",ide.error);
950 temp = ide->error;
951 break;
953 case 0x1F2: /* Sector count */
954 // pclog("Read sector count %02X\n",ide->secount);
955 temp = (uint8_t)ide->secount;
956 break;
958 case 0x1F3: /* Sector */
959 temp = (uint8_t)ide->sector;
960 break;
962 case 0x1F4: /* Cylinder low */
963 // pclog("Read cyl low %02X\n",ide.cylinder&0xFF);
964 temp = (uint8_t)(ide->cylinder&0xFF);
965 break;
967 case 0x1F5: /* Cylinder high */
968 // pclog("Read cyl low %02X\n",ide.cylinder>>8);
969 temp = (uint8_t)(ide->cylinder>>8);
970 break;
972 case 0x1F6: /* Drive/Head */
973 temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0);
974 break;
976 case 0x1F7: /* Status */
977 if (ide->type == IDE_NONE)
978 {
979 // pclog("Return status 00\n");
980 temp = 0;
981 break;
982 }
983 ide_irq_lower(ide);
984 if (ide->fdisk & 4)
985 temp = 0x80;
986 else if (ide->type == IDE_CDROM)
987 {
988 // pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0));
989 temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0);
990 }
991 else
992 {
993 // && ide->service) return ide.atastat[ide.board]|SERVICE_STAT;
994 // pclog("Return status %02X %04X:%04X %02X %02X\n",ide->atastat, CS ,pc, AH, BH);
995 temp = ide->atastat;
996 }
997 break;
999 case 0x3F6: /* Alternate Status */
1000 // pclog("3F6 read %02X\n",ide.atastat[ide.board]);
1001 // if (output) output=0;
1002 if (ide->type == IDE_NONE)
1003 {
1004 // pclog("Return status 00\n");
1005 temp = 0;
1006 break;
1007 }
1008 if (ide->type == IDE_CDROM)
1009 {
1010 // pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0));
1011 temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0);
1012 }
1013 else
1014 {
1015 // && ide->service) return ide.atastat[ide.board]|SERVICE_STAT;
1016 // pclog("Return status %02X\n",ide->atastat);
1017 temp = ide->atastat;
1018 }
1019 break;
1020 }
1021 // if (ide_board) pclog("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board);
1022 return temp;
1023 // fatal("Bad IDE read %04X\n", addr);
1024 }
1026 uint16_t readidew(int ide_board)
1027 {
1028 IDE *ide = &ide_drives[cur_ide[ide_board]];
1029 uint16_t temp;
1030 #ifndef RPCEMU_IDE
1031 /* if (ide_board && (cr0&1) && !(eflags&VM_FLAG))
1032 {
1033 // pclog("Failed read IDEw %04X:%08X\n",CS,pc);
1034 return 0xFFFF;
1035 }*/
1036 #endif
1037 // return 0xFFFF;
1038 // pclog("Read IDEw %04X %04X:%04X %02X %i %i\n",ide->buffer[ide->pos >> 1],CS,pc,opcode,ins, ide->pos);
1040 //if (idedebug) pclog("Read IDEW %08X\n",PC);
1042 temp = ide->buffer[ide->pos >> 1];
1043 #ifdef _RPCEMU_BIG_ENDIAN
1044 temp=(temp>>8)|(temp<<8);
1045 #endif
1046 ide->pos+=2;
1047 if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen))
1048 {
1049 // pclog("Over! packlen %i %i\n",ide->packlen,ide->pos);
1050 ide->pos=0;
1051 if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6)
1052 {
1053 // pclog("Call readCD\n");
1054 callreadcd(ide);
1055 }
1056 else
1057 {
1058 ide->atastat = READY_STAT | DSC_STAT;
1059 ide->packetstatus=0;
1060 if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE)
1061 {
1062 ide->secount = (ide->secount - 1) & 0xff;
1063 if (ide->secount)
1064 {
1065 ide_next_sector(ide);
1066 ide->atastat = BUSY_STAT;
1067 timer_process();
1068 if (ide->command == WIN_READ_MULTIPLE)
1069 callbackide(ide_board);
1070 else
1071 idecallback[ide_board]=6*IDE_TIME;
1072 timer_update_outstanding();
1073 // pclog("set idecallback\n");
1074 // callbackide(ide_board);
1075 }
1076 // else
1077 // pclog("readidew done %02X\n", ide->atastat);
1078 }
1079 }
1080 }
1081 // pclog("Read IDEw %04X\n",temp);
1082 return temp;
1083 }
1085 uint32_t readidel(int ide_board)
1086 {
1087 uint16_t temp;
1088 // pclog("Read IDEl %i\n", ide_board);
1089 temp = readidew(ide_board);
1090 return temp | (readidew(ide_board) << 16);
1091 }
1093 int times30=0;
1094 void callbackide(int ide_board)
1095 {
1096 IDE *ide = &ide_drives[cur_ide[ide_board]];
1097 off64_t addr;
1098 int c;
1099 ext_ide = ide;
1100 // return;
1101 if (ide->command==0x30) times30++;
1102 // if (times30==2240) output=1;
1103 //if (times30==2471 && ide->command==0xA0) output=1;
1104 ///*if (ide_board) */pclog("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]);
1105 // if (times30==1294)
1106 // output=1;
1107 if (ide->reset)
1108 {
1109 ide->atastat = READY_STAT | DSC_STAT;
1110 ide->error=1;
1111 ide->secount=1;
1112 ide->sector=1;
1113 ide->head=0;
1114 ide->cylinder=0;
1115 ide->reset = 0;
1116 ide->blocksize = 0;
1117 // pclog("Reset callback\n");
1118 return;
1119 }
1120 switch (ide->command)
1121 {
1122 //Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h.
1123 case WIN_SRST: /*ATAPI Device Reset */
1124 ide->atastat = READY_STAT | DSC_STAT;
1125 ide->error=1; /*Device passed*/
1126 ide->secount = ide->sector = 1;
1127 if (IDE_DRIVE_IS_CDROM(ide)) {
1128 ide->cylinder = 0xeb14;
1129 ide->atastat = 0;
1130 } else {
1131 ide->cylinder = 0;
1132 }
1133 ide_irq_raise(ide);
1134 if (IDE_DRIVE_IS_CDROM(ide))
1135 ide->service = 0;
1136 return;
1138 case WIN_RESTORE:
1139 case WIN_SEEK:
1140 if (IDE_DRIVE_IS_CDROM(ide)) {
1141 pclog("WIN_RESTORE callback on CD-ROM\n");
1142 goto abort_cmd;
1143 }
1144 // pclog("WIN_RESTORE callback\n");
1145 ide->atastat = READY_STAT | DSC_STAT;
1146 ide_irq_raise(ide);
1147 return;
1149 case WIN_READ:
1150 case WIN_READ_NORETRY:
1151 if (IDE_DRIVE_IS_CDROM(ide)) {
1152 goto abort_cmd;
1153 }
1154 addr = ide_get_sector(ide) * 512;
1155 // pclog("Read %i %i %i %08X\n",ide.cylinder,ide.head,ide.sector,addr);
1156 /* if (ide.cylinder || ide.head)
1157 {
1158 fatal("Read from other cylinder/head");
1159 }*/
1160 fseeko64(ide->hdfile, addr, SEEK_SET);
1161 fread(ide->buffer, 512, 1, ide->hdfile);
1162 ide->pos=0;
1163 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1164 // 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]);
1165 // if (addr) output=3;
1166 ide_irq_raise(ide);
1167 #ifndef RPCEMU_IDE
1168 readflash=1;
1169 #endif
1170 return;
1172 case WIN_READ_DMA:
1173 if (IDE_DRIVE_IS_CDROM(ide)) {
1174 goto abort_cmd;
1175 }
1176 addr = ide_get_sector(ide) * 512;
1177 fseeko64(ide->hdfile, addr, SEEK_SET);
1178 fread(ide->buffer, 512, 1, ide->hdfile);
1179 ide->pos=0;
1181 if (ide_bus_master_read_sector)
1182 {
1183 if (ide_bus_master_read_sector(ide_board, (uint8_t *)ide->buffer))
1184 idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/
1185 else
1186 {
1187 /*DMA successful*/
1188 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1190 ide->secount = (ide->secount - 1) & 0xff;
1191 if (ide->secount)
1192 {
1193 ide_next_sector(ide);
1194 ide->atastat = BUSY_STAT;
1195 idecallback[ide_board]=6*IDE_TIME;
1196 }
1197 else
1198 {
1199 ide_irq_raise(ide);
1200 ide_bus_master_set_irq(ide_board);
1201 }
1202 }
1203 }
1204 #ifndef RPCEMU_IDE
1205 readflash=1;
1206 #endif
1207 return;
1209 case WIN_READ_MULTIPLE:
1210 if (IDE_DRIVE_IS_CDROM(ide)) {
1211 goto abort_cmd;
1212 }
1213 addr = ide_get_sector(ide) * 512;
1214 // pclog("Read multiple from %08X %i (%i) %i\n", addr, ide->blockcount, ide->blocksize, ide->secount);
1215 fseeko64(ide->hdfile, addr, SEEK_SET);
1216 fread(ide->buffer, 512, 1, ide->hdfile);
1217 ide->pos=0;
1218 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1219 if (!ide->blockcount)// || ide->secount == 1)
1220 {
1221 // pclog("Read multiple int\n");
1222 ide_irq_raise(ide);
1223 }
1224 ide->blockcount++;
1225 if (ide->blockcount >= ide->blocksize)
1226 ide->blockcount = 0;
1227 #ifndef RPCEMU_IDE
1228 readflash=1;
1229 #endif
1230 return;
1232 case WIN_WRITE:
1233 case WIN_WRITE_NORETRY:
1234 if (IDE_DRIVE_IS_CDROM(ide)) {
1235 goto abort_cmd;
1236 }
1237 addr = ide_get_sector(ide) * 512;
1238 // pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt);
1239 fseeko64(ide->hdfile, addr, SEEK_SET);
1240 fwrite(ide->buffer, 512, 1, ide->hdfile);
1241 ide_irq_raise(ide);
1242 ide->secount = (ide->secount - 1) & 0xff;
1243 if (ide->secount)
1244 {
1245 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1246 ide->pos=0;
1247 ide_next_sector(ide);
1248 }
1249 else
1250 ide->atastat = READY_STAT | DSC_STAT;
1251 #ifndef RPCEMU_IDE
1252 readflash=1;
1253 #endif
1254 return;
1256 case WIN_WRITE_DMA:
1257 if (IDE_DRIVE_IS_CDROM(ide)) {
1258 goto abort_cmd;
1259 }
1261 if (ide_bus_master_write_sector)
1262 {
1263 if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer))
1264 idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/
1265 else
1266 {
1267 /*DMA successful*/
1268 addr = ide_get_sector(ide) * 512;
1269 fseeko64(ide->hdfile, addr, SEEK_SET);
1270 fwrite(ide->buffer, 512, 1, ide->hdfile);
1272 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1274 ide->secount = (ide->secount - 1) & 0xff;
1275 if (ide->secount)
1276 {
1277 ide_next_sector(ide);
1278 ide->atastat = BUSY_STAT;
1279 idecallback[ide_board]=6*IDE_TIME;
1280 }
1281 else
1282 {
1283 ide_irq_raise(ide);
1284 ide_bus_master_set_irq(ide_board);
1285 }
1286 }
1287 }
1288 #ifndef RPCEMU_IDE
1289 readflash=1;
1290 #endif
1291 return;
1293 case WIN_WRITE_MULTIPLE:
1294 if (IDE_DRIVE_IS_CDROM(ide)) {
1295 goto abort_cmd;
1296 }
1297 addr = ide_get_sector(ide) * 512;
1298 // pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt);
1299 fseeko64(ide->hdfile, addr, SEEK_SET);
1300 fwrite(ide->buffer, 512, 1, ide->hdfile);
1301 ide->blockcount++;
1302 if (ide->blockcount >= ide->blocksize || ide->secount == 1)
1303 {
1304 ide->blockcount = 0;
1305 ide_irq_raise(ide);
1306 }
1307 ide->secount = (ide->secount - 1) & 0xff;
1308 if (ide->secount)
1309 {
1310 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1311 ide->pos=0;
1312 ide_next_sector(ide);
1313 }
1314 else
1315 ide->atastat = READY_STAT | DSC_STAT;
1316 #ifndef RPCEMU_IDE
1317 readflash=1;
1318 #endif
1319 return;
1321 case WIN_VERIFY:
1322 if (IDE_DRIVE_IS_CDROM(ide)) {
1323 goto abort_cmd;
1324 }
1325 ide->pos=0;
1326 ide->atastat = READY_STAT | DSC_STAT;
1327 // pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount);
1328 ide_irq_raise(ide);
1329 #ifndef RPCEMU_IDE
1330 readflash=1;
1331 #endif
1332 return;
1334 case WIN_FORMAT:
1335 if (IDE_DRIVE_IS_CDROM(ide)) {
1336 goto abort_cmd;
1337 }
1338 addr = ide_get_sector(ide) * 512;
1339 // pclog("Format cyl %i head %i offset %08X %08X %08X secount %i\n",ide.cylinder,ide.head,addr,addr>>32,addr,ide.secount);
1340 fseeko64(ide->hdfile, addr, SEEK_SET);
1341 memset(ide->buffer, 0, 512);
1342 for (c=0;c<ide->secount;c++)
1343 {
1344 fwrite(ide->buffer, 512, 1, ide->hdfile);
1345 }
1346 ide->atastat = READY_STAT | DSC_STAT;
1347 ide_irq_raise(ide);
1348 #ifndef RPCEMU_IDE
1349 readflash=1;
1350 #endif
1351 return;
1353 case WIN_DRIVE_DIAGNOSTICS:
1354 ide->error=1; /*No error detected*/
1355 ide->atastat = READY_STAT | DSC_STAT;
1356 ide_irq_raise(ide);
1357 return;
1359 case WIN_SPECIFY: /* Initialize Drive Parameters */
1360 if (IDE_DRIVE_IS_CDROM(ide)) {
1361 #ifndef RPCEMU_IDE
1362 pclog("IS CDROM - ABORT\n");
1363 #endif
1364 goto abort_cmd;
1365 }
1366 ide->spt=ide->secount;
1367 ide->hpc=ide->head+1;
1368 ide->atastat = READY_STAT | DSC_STAT;
1369 #ifndef RPCEMU_IDE
1370 // pclog("SPECIFY - %i sectors per track, %i heads per cylinder %i %i\n",ide->spt,ide->hpc,cur_ide[ide_board],ide_board);
1371 #endif
1372 ide_irq_raise(ide);
1373 return;
1375 case WIN_PIDENTIFY: /* Identify Packet Device */
1376 if (IDE_DRIVE_IS_CDROM(ide)) {
1377 // pclog("ATAPI identify\n");
1378 ide_atapi_identify(ide);
1379 ide->pos=0;
1380 ide->error=0;
1381 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1382 ide_irq_raise(ide);
1383 return;
1384 }
1385 // pclog("Not ATAPI\n");
1386 goto abort_cmd;
1388 case WIN_SET_MULTIPLE_MODE:
1389 if (IDE_DRIVE_IS_CDROM(ide)) {
1390 #ifndef RPCEMU_IDE
1391 pclog("IS CDROM - ABORT\n");
1392 #endif
1393 goto abort_cmd;
1394 }
1395 ide->blocksize = ide->secount;
1396 ide->atastat = READY_STAT | DSC_STAT;
1397 #ifndef RPCEMU_IDE
1398 pclog("Set multiple mode - %i\n", ide->blocksize);
1399 #endif
1400 ide_irq_raise(ide);
1401 return;
1403 case WIN_SETIDLE1: /* Idle */
1404 case 0xEF:
1405 goto abort_cmd;
1407 case WIN_IDENTIFY: /* Identify Device */
1408 if (IDE_DRIVE_IS_CDROM(ide)) {
1409 ide->secount=1;
1410 ide->sector=1;
1411 ide->cylinder=0xEB14;
1412 ide->drive=ide->head=0;
1413 goto abort_cmd;
1414 }
1415 if (ide->type != IDE_NONE)
1416 {
1417 ide_identify(ide);
1418 ide->pos=0;
1419 ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
1420 // pclog("ID callback\n");
1421 ide_irq_raise(ide);
1422 }
1423 return;
1425 case WIN_PACKETCMD: /* ATAPI Packet */
1426 if (!IDE_DRIVE_IS_CDROM(ide)) goto abort_cmd;
1427 // pclog("Packet callback! %i %08X\n",ide->packetstatus,ide);
1428 if (!ide->packetstatus)
1429 {
1430 ide->pos=0;
1431 ide->secount = (uint8_t)((ide->secount&0xF8)|1);
1432 ide->atastat = DRQ_STAT |(ide->atastat&ERR_STAT);
1433 //ide_irq_raise(ide);
1434 // pclog("1 Preparing to recieve packet max DRQ count %04X\n",ide->cylinder);
1435 }
1436 else if (ide->packetstatus==1)
1437 {
1438 ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT);
1439 // pclog("Running ATAPI command 2\n");
1440 atapicommand(ide_board);
1441 // exit(-1);
1442 }
1443 else if (ide->packetstatus==2)
1444 {
1445 // pclog("packetstatus==2\n");
1446 ide->atastat = READY_STAT;
1447 ide->secount=3;
1448 ide_irq_raise(ide);
1449 // if (iomd.irqb.mask&2) output=1;
1450 }
1451 else if (ide->packetstatus==3)
1452 {
1453 ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT);
1454 // rpclog("Recieve data packet 3! %02X\n",ide->atastat);
1455 ide_irq_raise(ide);
1456 ide->packetstatus=0xFF;
1457 }
1458 else if (ide->packetstatus==4)
1459 {
1460 ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT);
1461 // pclog("Send data packet 4!\n");
1462 ide_irq_raise(ide);
1463 // ide.packetstatus=5;
1464 ide->pos=2;
1465 }
1466 else if (ide->packetstatus==5)
1467 {
1468 // pclog("Packetstatus 5 !\n");
1469 atapicommand(ide_board);
1470 }
1471 else if (ide->packetstatus==6) /*READ CD callback*/
1472 {
1473 ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT);
1474 // pclog("Recieve data packet 6!\n");
1475 ide_irq_raise(ide);
1476 // ide.packetstatus=0xFF;
1477 }
1478 else if (ide->packetstatus==0x80) /*Error callback*/
1479 {
1480 // pclog("Packet error\n");
1481 ide->atastat = READY_STAT | ERR_STAT;
1482 ide_irq_raise(ide);
1483 }
1484 return;
1485 }
1487 abort_cmd:
1488 ide->atastat = READY_STAT | ERR_STAT | DSC_STAT;
1489 ide->error = ABRT_ERR;
1490 ide_irq_raise(ide);
1491 }
1493 void ide_callback_pri()
1494 {
1495 idecallback[0] = 0;
1496 callbackide(0);
1497 }
1499 void ide_callback_sec()
1500 {
1501 idecallback[1] = 0;
1502 callbackide(1);
1503 }
1505 /*ATAPI CD-ROM emulation
1506 This mostly seems to work. It is implemented only on Windows at the moment as
1507 I haven't had time to implement any interfaces for it in the generic gui.
1508 It mostly depends on driver files - cdrom-iso.c for ISO image files (in theory
1509 on any platform) and cdrom-ioctl.c for Win32 IOCTL access. There's an ATAPI
1510 interface defined in ide.h.
1511 There are a couple of bugs in the CD audio handling.
1512 */
1514 struct
1515 {
1516 int sensekey,asc,ascq;
1517 } atapi_sense;
1519 static void atapi_notready(IDE *ide)
1520 {
1521 /*Medium not present is 02/3A/--*/
1522 /*cylprecomp is error number*/
1523 /*SENSE/ASC/ASCQ*/
1524 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1525 ide->error = (SENSE_NOT_READY << 4) | ABRT_ERR;
1526 if (ide->discchanged) {
1527 ide->error |= MCR_ERR;
1528 atapi_sense.sensekey=6;
1529 atapi_sense.asc=0x28;
1530 } else {
1531 atapi_sense.sensekey=2;
1532 atapi_sense.asc = ASC_MEDIUM_NOT_PRESENT;
1533 }
1534 ide->discchanged=0;
1535 ide->packetstatus=0x80;
1536 idecallback[ide->board]=50*IDE_TIME;
1537 }
1539 void atapi_discchanged()
1540 {
1541 ext_ide->discchanged=1;
1542 atapi_sense.sensekey=6;
1543 atapi_sense.asc=0x28;
1544 }
1546 uint8_t atapi_prev;
1547 int toctimes=0;
1548 static void atapicommand(int ide_board)
1549 {
1550 IDE *ide = &ide_drives[cur_ide[ide_board]];
1551 uint8_t *idebufferb = (uint8_t *) ide->buffer;
1552 int c;
1553 int len;
1554 int msf;
1555 int pos=0;
1556 unsigned char temp;
1557 uint32_t size;
1558 #ifndef RPCEMU_IDE
1559 pclog("New ATAPI command %02X %i\n",idebufferb[0],ins);
1560 #endif
1561 // readflash=1;
1562 msf=idebufferb[1]&2;
1563 ide->cdlen=0;
1564 if (idebufferb[0]!=GPCMD_REQUEST_SENSE)
1565 {
1566 atapi_prev=idebufferb[0];
1567 atapi_sense.sensekey=0;
1568 atapi_sense.asc=0;
1569 }
1570 switch (idebufferb[0])
1571 {
1572 case GPCMD_TEST_UNIT_READY:
1573 if (!atapi->ready()) { atapi_notready(ide); return; }
1574 // if (atapi->ready())
1575 // {
1576 ide->packetstatus=2;
1577 idecallback[ide_board]=50*IDE_TIME;
1578 // }
1579 // else
1580 // {
1581 // pclog("Medium not present!\n");
1582 // }
1583 break;
1585 case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */
1586 /*Will return 18 bytes of 0*/
1587 memset(idebufferb,0,512);
1588 // switch (atapi_prev)
1589 // {
1590 // case GPCMD_TEST_UNIT_READY:
1591 idebufferb[0]=0x80|0x70;
1592 idebufferb[2]=atapi_sense.sensekey;
1593 idebufferb[12]=atapi_sense.asc;
1594 idebufferb[13]=atapi_sense.ascq;
1595 // break;
1596 //
1597 // default:
1598 // fatal("Bad REQUEST_SENSE following command %02X\n",atapi_prev);
1599 // }
1600 ide->packetstatus=3;
1601 ide->cylinder=18;
1602 ide->secount=2;
1603 ide->pos=0;
1604 idecallback[ide_board]=60*IDE_TIME;
1605 ide->packlen=18;
1606 break;
1608 case GPCMD_SET_SPEED:
1609 ide->packetstatus=2;
1610 idecallback[ide_board]=50*IDE_TIME;
1611 break;
1613 case GPCMD_READ_TOC_PMA_ATIP:
1614 // pclog("Read TOC ready? %08X\n",ide);
1615 if (!atapi->ready()) { atapi_notready(ide); return; }
1616 toctimes++;
1617 // if (toctimes==2) output=3;
1618 // pclog("Read TOC %02X\n",idebufferb[9]);
1619 switch (idebufferb[9]>>6)
1620 {
1621 case 0: /*Normal*/
1622 len=idebufferb[8]+(idebufferb[7]<<8);
1623 len=atapi->readtoc(idebufferb,idebufferb[6],msf,len,0);
1624 break;
1625 case 1: /*Multi session*/
1626 len=idebufferb[8]+(idebufferb[7]<<8);
1627 atapi->readtoc_session(idebufferb,msf,len);
1628 idebufferb[0]=0; idebufferb[1]=0xA;
1629 break;
1630 default:
1631 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1632 ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR;
1633 if (ide->discchanged) {
1634 ide->error |= MCR_ERR;
1635 }
1636 ide->discchanged=0;
1637 atapi_sense.asc = ASC_ILLEGAL_OPCODE;
1638 ide->packetstatus=0x80;
1639 idecallback[ide_board]=50*IDE_TIME;
1640 break;
1641 /* pclog("Bad read TOC format\n");
1642 pclog("Packet data :\n");
1643 for (c=0;c<12;c++)
1644 pclog("%02X ",idebufferb[c]);
1645 pclog("\n");
1646 exit(-1);*/
1647 }
1648 // pclog("ATAPI buffer len %i\n",len);
1649 ide->packetstatus=3;
1650 ide->cylinder=len;
1651 ide->secount=2;
1652 ide->pos=0;
1653 idecallback[ide_board]=60*IDE_TIME;
1654 ide->packlen=len;
1655 return;
1657 case GPCMD_READ_CD:
1658 if (!atapi->ready()) { atapi_notready(ide); return; }
1659 // pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]);
1660 if (idebufferb[9]!=0x10)
1661 {
1662 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1663 ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR;
1664 if (ide->discchanged) {
1665 ide->error |= MCR_ERR;
1666 }
1667 ide->discchanged=0;
1668 atapi_sense.asc = ASC_ILLEGAL_OPCODE;
1669 ide->packetstatus=0x80;
1670 idecallback[ide_board]=50*IDE_TIME;
1671 break;
1672 // pclog("Bad flags bits %02X\n",idebufferb[9]);
1673 // exit(-1);
1674 }
1675 /* if (idebufferb[6] || idebufferb[7] || (idebufferb[8]!=1))
1676 {
1677 pclog("More than 1 sector!\n");
1678 exit(-1);
1679 }*/
1680 ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8];
1681 ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
1682 // pclog("Read at %08X %08X\n",ide.cdpos,ide.cdpos*2048);
1683 atapi->readsector(idebufferb,ide->cdpos);
1684 #ifndef RPCEMU_IDE
1685 readflash=1;
1686 #endif
1687 ide->cdpos++;
1688 ide->cdlen--;
1689 if (ide->cdlen>=0) ide->packetstatus=6;
1690 else ide->packetstatus=3;
1691 ide->cylinder=2048;
1692 ide->secount=2;
1693 ide->pos=0;
1694 idecallback[ide_board]=60*IDE_TIME;
1695 ide->packlen=2048;
1696 return;
1698 case GPCMD_READ_10:
1699 if (!atapi->ready()) { atapi_notready(ide); return; }
1700 // pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]);
1702 ide->cdlen=(idebufferb[7]<<8)|idebufferb[8];
1703 ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
1704 if (!ide->cdlen)
1705 {
1706 // pclog("All done - callback set\n");
1707 ide->packetstatus=2;
1708 idecallback[ide_board]=20*IDE_TIME;
1709 break;
1710 }
1712 atapi->readsector(idebufferb,ide->cdpos);
1713 #ifndef RPCEMU_IDE
1714 readflash=1;
1715 #endif
1716 ide->cdpos++;
1717 ide->cdlen--;
1718 if (ide->cdlen>=0) ide->packetstatus=6;
1719 else ide->packetstatus=3;
1720 ide->cylinder=2048;
1721 ide->secount=2;
1722 ide->pos=0;
1723 idecallback[ide_board]=60*IDE_TIME;
1724 ide->packlen=2048;
1725 return;
1727 case GPCMD_READ_HEADER:
1728 if (!atapi->ready()) { atapi_notready(ide); return; }
1729 if (msf)
1730 {
1731 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1732 ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR;
1733 if (ide->discchanged) {
1734 ide->error |= MCR_ERR;
1735 }
1736 ide->discchanged=0;
1737 atapi_sense.asc = ASC_ILLEGAL_OPCODE;
1738 ide->packetstatus=0x80;
1739 idecallback[ide_board]=50*IDE_TIME;
1740 break;
1741 // pclog("Read Header MSF!\n");
1742 // exit(-1);
1743 }
1744 for (c=0;c<4;c++) idebufferb[c+4]=idebufferb[c+2];
1745 idebufferb[0]=1; /*2048 bytes user data*/
1746 idebufferb[1]=idebufferb[2]=idebufferb[3]=0;
1748 ide->packetstatus=3;
1749 ide->cylinder=8;
1750 ide->secount=2;
1751 ide->pos=0;
1752 idecallback[ide_board]=60*IDE_TIME;
1753 ide->packlen=8;
1754 return;
1756 case GPCMD_MODE_SENSE_10:
1757 // output=3;
1758 // pclog("Mode sense - ready?\n");
1759 if (!atapi->ready()) { atapi_notready(ide); return; }
1760 len=(idebufferb[8]|(idebufferb[7]<<8));
1762 //pclog("Mode sense %02X %i\n",idebufferb[2],len);
1763 temp=idebufferb[2];
1764 // switch (idebufferb[2])
1765 // {
1766 // case GPMODE_ALL_PAGES:
1767 // case GPMODE_CAPABILITIES_PAGE:
1768 for (c=0;c<len;c++) idebufferb[c]=0;
1769 len = ide_atapi_mode_sense(ide,8,temp);
1770 // break;
1771 // default:
1772 // for (c=0;c<len;c++) idebufferb[c]=0;
1773 /* pclog("Bad mode sense\n");
1774 pclog("Packet data :\n");
1775 for (c=0;c<12;c++)
1776 pclog("%02X\n",idebufferb[c]);
1777 exit(-1);*/
1778 // }
1780 /*Set mode parameter header - bytes 0 & 1 are data length (filled out later),
1781 byte 2 is media type*/
1782 idebufferb[0]=len>>8;
1783 idebufferb[1]=len&255;
1784 idebufferb[2]=3; /*120mm data CD-ROM*/
1785 // pclog("ATAPI buffer len %i\n",len);
1786 /* for (c=0;c<len;c++) pclog("%02X ",idebufferb[c]);
1787 pclog("\n");*/
1788 ide->packetstatus=3;
1789 ide->cylinder=len;
1790 ide->secount=2;
1791 // ide.atastat = DRQ_STAT;
1792 ide->pos=0;
1793 idecallback[ide_board]=1000*IDE_TIME;
1794 ide->packlen=len;
1795 // pclog("Sending packet\n");
1796 return;
1798 case GPCMD_MODE_SELECT_10:
1799 // if (!atapi->ready()) { atapi_notready(); return; }
1800 if (ide->packetstatus==5)
1801 {
1802 ide->atastat = 0;
1803 // pclog("Recieve data packet!\n");
1804 ide_irq_raise(ide);
1805 ide->packetstatus=0xFF;
1806 ide->pos=0;
1807 // pclog("Length - %02X%02X\n",idebufferb[0],idebufferb[1]);
1808 // pclog("Page %02X length %02X\n",idebufferb[8],idebufferb[9]);
1809 }
1810 else
1811 {
1812 len=(idebufferb[7]<<8)|idebufferb[8];
1813 ide->packetstatus=4;
1814 ide->cylinder=len;
1815 ide->secount=2;
1816 ide->pos=0;
1817 idecallback[ide_board]=6*IDE_TIME;
1818 ide->packlen=len;
1819 /* pclog("Waiting for ARM to send packet %i\n",len);
1820 pclog("Packet data :\n");
1821 for (c=0;c<12;c++)
1822 pclog("%02X ",idebufferb[c]);
1823 pclog("\n");*/
1824 }
1825 return;
1827 case GPCMD_PLAY_AUDIO_12:
1828 if (!atapi->ready()) { atapi_notready(ide); return; }
1829 /*This is apparently deprecated in the ATAPI spec, and apparently
1830 has been since 1995 (!). Hence I'm having to guess most of it*/
1831 pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
1832 len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9];
1833 atapi->playaudio(pos,len,0);
1834 ide->packetstatus=2;
1835 idecallback[ide_board]=50*IDE_TIME;
1836 break;
1838 case GPCMD_PLAY_AUDIO_MSF:
1839 if (!atapi->ready()) { atapi_notready(ide); return; }
1840 pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
1841 len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8];
1842 atapi->playaudio(pos,len,1);
1843 ide->packetstatus=2;
1844 idecallback[ide_board]=50*IDE_TIME;
1845 break;
1847 case GPCMD_READ_SUBCHANNEL:
1848 if (!atapi->ready()) { /*pclog("Read subchannel not ready\n"); */atapi_notready(ide); return; }
1849 temp=idebufferb[2]&0x40;
1850 if (idebufferb[3]!=1)
1851 {
1852 // pclog("Read subchannel check condition %02X\n",idebufferb[3]);
1853 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1854 ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR;
1855 if (ide->discchanged) {
1856 ide->error |= MCR_ERR;
1857 }
1858 ide->discchanged=0;
1859 atapi_sense.asc = ASC_ILLEGAL_OPCODE;
1860 ide->packetstatus=0x80;
1861 idecallback[ide_board]=50*IDE_TIME;
1862 break;
1863 /* pclog("Bad read subchannel!\n");
1864 pclog("Packet data :\n");
1865 for (c=0;c<12;c++)
1866 pclog("%02X\n",idebufferb[c]);
1867 dumpregs();
1868 exit(-1);*/
1869 }
1870 pos=0;
1871 idebufferb[pos++]=0;
1872 idebufferb[pos++]=0; /*Audio status*/
1873 idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/
1874 idebufferb[pos++]=1; /*Format code*/
1875 idebufferb[1]=atapi->getcurrentsubchannel(&idebufferb[5],msf);
1876 // pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]);
1877 len=11+5;
1878 if (!temp) len=4;
1879 ide->packetstatus=3;
1880 ide->cylinder=len;
1881 ide->secount=2;
1882 ide->pos=0;
1883 idecallback[ide_board]=1000*IDE_TIME;
1884 ide->packlen=len;
1885 break;
1887 case GPCMD_START_STOP_UNIT:
1888 if (idebufferb[4]!=2 && idebufferb[4]!=3 && idebufferb[4])
1889 {
1890 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1891 ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR;
1892 if (ide->discchanged) {
1893 ide->error |= MCR_ERR;
1894 }
1895 ide->discchanged=0;
1896 atapi_sense.asc = ASC_ILLEGAL_OPCODE;
1897 ide->packetstatus=0x80;
1898 idecallback[ide_board]=50*IDE_TIME;
1899 break;
1900 /* pclog("Bad start/stop unit command\n");
1901 pclog("Packet data :\n");
1902 for (c=0;c<12;c++)
1903 pclog("%02X\n",idebufferb[c]);
1904 exit(-1);*/
1905 }
1906 if (!idebufferb[4]) atapi->stop();
1907 else if (idebufferb[4]==2) atapi->eject();
1908 else atapi->load();
1909 ide->packetstatus=2;
1910 idecallback[ide_board]=50*IDE_TIME;
1911 break;
1913 case GPCMD_INQUIRY:
1914 idebufferb[0] = 5; /*CD-ROM*/
1915 idebufferb[1] = 0x80; /*Removable*/
1916 idebufferb[2] = 0;
1917 idebufferb[3] = 0x21;
1918 idebufferb[4] = 31;
1919 idebufferb[5] = 0;
1920 idebufferb[6] = 0;
1921 idebufferb[7] = 0;
1922 #ifdef RPCEMU_IDE
1923 ide_padstr8(idebufferb + 8, 8, "RPCemu"); /* Vendor */
1924 ide_padstr8(idebufferb + 16, 16, "RPCemuCD"); /* Product */
1925 #else
1926 ide_padstr8(idebufferb + 8, 8, "PCem"); /* Vendor */
1927 ide_padstr8(idebufferb + 16, 16, "PCemCD"); /* Product */
1928 #endif
1929 ide_padstr8(idebufferb + 32, 4, "v1.0"); /* Revision */
1931 len=36;
1932 ide->packetstatus=3;
1933 ide->cylinder=len;
1934 ide->secount=2;
1935 ide->pos=0;
1936 idecallback[ide_board]=60*IDE_TIME;
1937 ide->packlen=len;
1938 break;
1940 case GPCMD_PREVENT_REMOVAL:
1941 if (!atapi->ready()) { atapi_notready(ide); return; }
1942 ide->packetstatus=2;
1943 idecallback[ide_board]=50*IDE_TIME;
1944 break;
1946 case GPCMD_PAUSE_RESUME:
1947 if (!atapi->ready()) { atapi_notready(ide); return; }
1948 if (idebufferb[8]&1) atapi->resume();
1949 else atapi->pause();
1950 ide->packetstatus=2;
1951 idecallback[ide_board]=50*IDE_TIME;
1952 break;
1954 case GPCMD_SEEK:
1955 if (!atapi->ready()) { atapi_notready(ide); return; }
1956 pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
1957 atapi->seek(pos);
1958 ide->packetstatus=2;
1959 idecallback[ide_board]=50*IDE_TIME;
1960 break;
1962 case GPCMD_READ_CDROM_CAPACITY:
1963 if (!atapi->ready()) { atapi_notready(ide); return; }
1964 size = atapi->size();
1965 idebufferb[0] = (size >> 24) & 0xff;
1966 idebufferb[1] = (size >> 16) & 0xff;
1967 idebufferb[2] = (size >> 8) & 0xff;
1968 idebufferb[3] = size & 0xff;
1969 idebufferb[4] = (2048 >> 24) & 0xff;
1970 idebufferb[5] = (2048 >> 16) & 0xff;
1971 idebufferb[6] = (2048 >> 8) & 0xff;
1972 idebufferb[7] = 2048 & 0xff;
1973 len=8;
1974 ide->packetstatus=3;
1975 ide->cylinder=len;
1976 ide->secount=2;
1977 ide->pos=0;
1978 idecallback[ide_board]=60*IDE_TIME;
1979 ide->packlen=len;
1980 break;
1982 case GPCMD_SEND_DVD_STRUCTURE:
1983 default:
1984 ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/
1985 ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR;
1986 if (ide->discchanged) {
1987 ide->error |= MCR_ERR;
1988 }
1989 ide->discchanged=0;
1990 atapi_sense.asc = ASC_ILLEGAL_OPCODE;
1991 ide->packetstatus=0x80;
1992 idecallback[ide_board]=50*IDE_TIME;
1993 break;
1995 /* default:
1996 pclog("Bad ATAPI command %02X\n",idebufferb[0]);
1997 pclog("Packet data :\n");
1998 for (c=0;c<12;c++)
1999 pclog("%02X\n",idebufferb[c]);
2000 exit(-1);*/
2001 }
2002 }
2004 static void callreadcd(IDE *ide)
2005 {
2006 ide_irq_lower(ide);
2007 if (ide->cdlen<=0)
2008 {
2009 // pclog("All done - callback set\n");
2010 ide->packetstatus=2;
2011 idecallback[ide->board]=20*IDE_TIME;
2012 return;
2013 }
2014 // pclog("Continue readcd! %i blocks left\n",ide->cdlen);
2015 ide->atastat = BUSY_STAT;
2017 atapi->readsector((uint8_t *) ide->buffer, ide->cdpos);
2018 #ifndef RPCEMU_IDE
2019 readflash=1;
2020 #endif
2021 ide->cdpos++;
2022 ide->cdlen--;
2023 ide->packetstatus=6;
2024 ide->cylinder=2048;
2025 ide->secount=2;
2026 ide->pos=0;
2027 idecallback[ide->board]=60*IDE_TIME;
2028 ide->packlen=2048;
2029 }
2033 void ide_write_pri(uint16_t addr, uint8_t val, void *priv)
2034 {
2035 writeide(0, addr, val);
2036 }
2037 void ide_write_pri_w(uint16_t addr, uint16_t val, void *priv)
2038 {
2039 writeidew(0, val);
2040 }
2041 void ide_write_pri_l(uint16_t addr, uint32_t val, void *priv)
2042 {
2043 writeidel(0, val);
2044 }
2045 uint8_t ide_read_pri(uint16_t addr, void *priv)
2046 {
2047 return readide(0, addr);
2048 }
2049 uint16_t ide_read_pri_w(uint16_t addr, void *priv)
2050 {
2051 return readidew(0);
2052 }
2053 uint32_t ide_read_pri_l(uint16_t addr, void *priv)
2054 {
2055 return readidel(0);
2056 }
2058 void ide_write_sec(uint16_t addr, uint8_t val, void *priv)
2059 {
2060 writeide(1, addr, val);
2061 }
2062 void ide_write_sec_w(uint16_t addr, uint16_t val, void *priv)
2063 {
2064 writeidew(1, val);
2065 }
2066 void ide_write_sec_l(uint16_t addr, uint32_t val, void *priv)
2067 {
2068 writeidel(1, val);
2069 }
2070 uint8_t ide_read_sec(uint16_t addr, void *priv)
2071 {
2072 return readide(1, addr);
2073 }
2074 uint16_t ide_read_sec_w(uint16_t addr, void *priv)
2075 {
2076 return readidew(1);
2077 }
2078 uint32_t ide_read_sec_l(uint16_t addr, void *priv)
2079 {
2080 return readidel(1);
2081 }
2083 void ide_pri_enable()
2084 {
2085 io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL);
2086 io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL);
2087 }
2089 void ide_pri_disable()
2090 {
2091 io_removehandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL);
2092 io_removehandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL);
2093 }
2095 void ide_sec_enable()
2096 {
2097 io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL);
2098 io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL);
2099 }
2101 void ide_sec_disable()
2102 {
2103 io_removehandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL);
2104 io_removehandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL);
2105 }
2107 void ide_init()
2108 {
2109 ide_pri_enable();
2110 ide_sec_enable();
2111 ide_bus_master_read_sector = ide_bus_master_write_sector = NULL;
2113 timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL);
2114 timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL);
2115 }
2117 void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel))
2118 {
2119 ide_bus_master_read_sector = read_sector;
2120 ide_bus_master_write_sector = write_sector;
2121 ide_bus_master_set_irq = set_irq;
2122 }
