]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/ide/testutil.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / ide / testutil.c
1
2 #include <stdio.h>
3 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <malloc.h>
8 #include <ctype.h>
9 #include <fcntl.h>
10 #include <dos.h>
11
12 #include <hw/vga/vga.h>
13 #include <hw/pci/pci.h>
14 #include <hw/dos/dos.h>
15 #include <hw/8254/8254.h>               /* 8254 timer */
16 #include <hw/8259/8259.h>               /* 8259 PIC interrupts */
17 #include <hw/vga/vgagui.h>
18 #include <hw/vga/vgatty.h>
19 #include <hw/ide/idelib.h>
20
21 #include "testutil.h"
22
23 unsigned char sanitizechar(unsigned char c) {
24         if (c < 32) return '.';
25         return c;
26 }
27
28 int wait_for_enter_or_escape() {
29         int c;
30
31         do {
32                 c = getch();
33                 if (c == 0) c = getch() << 8;
34         } while (!(c == 13 || c == 27));
35
36         return c;
37 }
38
39 /* construct ATAPI/SCSI-MMC READ command according to user's choice, either READ(10) or READ(12) */
40 void do_construct_atapi_scsi_mmc_read(unsigned char *buf/*must be 12 bytes*/,uint32_t sector,uint32_t tlen_sect,unsigned char read_mode) {
41         memset(buf,0,12);
42         if (read_mode == 12) {
43                 /* command: READ(12) */
44                 buf[0] = 0xA8;
45
46                 /* fill in the Logical Block Address */
47                 buf[2] = sector >> 24;
48                 buf[3] = sector >> 16;
49                 buf[4] = sector >> 8;
50                 buf[5] = sector;
51
52                 buf[6] = tlen_sect >> 24UL;
53                 buf[7] = tlen_sect >> 16UL;
54                 buf[8] = tlen_sect >> 8UL;
55                 buf[9] = tlen_sect;
56         }
57         else {
58                 /* command: READ(10) */
59                 buf[0] = 0x28;
60
61                 /* fill in the Logical Block Address */
62                 buf[2] = sector >> 24;
63                 buf[3] = sector >> 16;
64                 buf[4] = sector >> 8;
65                 buf[5] = sector;
66
67                 buf[7] = tlen_sect >> 8;
68                 buf[8] = tlen_sect;
69         }
70 }
71
72 /* check for another possible case where 16-bit PIO word is in lower half of 32-bit read, junk in upper */
73 int ide_memcmp_every_other_word(unsigned char *pio16,unsigned char *pio32,unsigned int words) {
74         while (words > 0) {
75                 uint16_t a = *((uint16_t*)pio16);
76                 uint16_t b = (uint16_t)(*((uint32_t*)pio32) & 0xFFFF);
77                 if (a != b) return (int)(a-b);
78                 pio16 += 2;
79                 pio32 += 4;
80                 words--;
81         }
82
83         return 0;
84 }
85
86 /* return 0 if all bytes are 0xFF */
87 int ide_memcmp_all_FF(unsigned char *d,unsigned int bytes) {
88         while (bytes > 0) {
89                 if (*d != 0xFF) return 1;
90                 d++;
91                 bytes--;
92         }
93
94         return 0;
95 }
96
97 /* A warning to people who may write their own IDE code: If a drive
98  * has been put to sleep, or put through a host reset, the "drive ready"
99  * bit will NEVER come up. If you are naive, your code will loop forever
100  * waiting for drive ready. To get drive ready to come up you have to
101  * send it a NO-OP command, which it will reply with an error, but it
102  * will then signal readiness.
103  *
104  * Now, in this case the Status register (0x1F7/0x3F6) will always
105  * read back 0x00, but 0x00 is also what would be read back if no
106  * such device existed. How do we tell the two scenarios apart?
107  * Well it turns out that if the device is there, then anything you
108  * read/write from ports 0x1F2-0x1F5 will read back the same value.
109  * If the IDE device does not exist, then ports 0x1F2-0x1F5 will
110  * always return 0x00 (or 0xFF?) no matter what we write.
111  *
112  * Once we know the device is there, we can then "trick" the device
113  * into reporting readiness by issuing ATA NO-OP, which the device
114  * will respond to with an error, but more importantly, it will set
115  * the Device Ready bit. */
116 /* NOTE: The caller must have already gone through the process of writing the
117  *       head & drive select and waiting for controller readiness. if the
118  *       caller doesn't do that, this routine will probably end up running through
119  *       the routine on the wrong IDE device */
120 int do_ide_controller_atapi_device_check_post_host_reset(struct ide_controller *ide) {
121         idelib_controller_update_status(ide);
122         if (idelib_controller_is_busy(ide)) return -1;                  /* YOU'RE SUPPOSED TO WAIT FOR CONTROLLER NOT-BUSY! */
123         if (idelib_controller_is_drive_ready(ide)) return 0;            /* Drive indicates readiness, nothing to do */
124
125         if ((ide->last_status&0xC1) == 0) { /* <- typical post-reset state. VirtualBox/QEMU never raises Drive Ready bit */
126                 struct ide_taskfile *tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
127
128                 /* OK: If I write things to 0x1F2-0x1F5 can I read them back? */
129                 tsk->sector_count = 0x55;
130                 tsk->lba0_3 = 0xAA;
131                 tsk->lba1_4 = 0x3F;
132
133                 idelib_controller_apply_taskfile(ide,0x1C/*regs 2-4*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear*/);
134                 tsk->sector_count = tsk->lba0_3 = tsk->lba1_4 = 0; /* DEBUG: just to be sure */
135                 idelib_controller_update_taskfile(ide,0x1C/*regs 2-4*/,0);
136
137                 if (tsk->sector_count != 0x55 || tsk->lba0_3 != 0xAA || tsk->lba1_4 != 0x3F)
138                         return -1;      /* Nope. IDE device is not there (also possibly the device is fucked up) */
139
140                 idelib_controller_update_status(ide);
141         }
142         if ((ide->last_status&0xC1) == 0) { /* <- if the first test did not trigger drive ready, then whack the command port with ATA NO-OP */
143                 idelib_controller_write_command(ide,0x00);
144                 t8254_wait(t8254_us2ticks(100000)); /* <- give it 100ms to respond */
145                 idelib_controller_update_status(ide);
146         }
147         if ((ide->last_status&0xC1) == 0) { /* <- if the NO-OP test didn't work, then forget it, I'm out of ideas */
148                 return -1;
149         }
150
151         idelib_controller_ack_irq(ide);
152         return 0;
153 }
154