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