]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/ide/testcdrm.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / ide / testcdrm.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 #include "testmbox.h"
23 #include "testcmui.h"
24 #include "testbusy.h"
25 #include "testpiot.h"
26 #include "testrvfy.h"
27 #include "testrdwr.h"
28 #include "testidnt.h"
29 #include "testcdej.h"
30 #include "testpiom.h"
31 #include "testtadj.h"
32 #include "testcdrm.h"
33 #include "test.h"
34
35 #include "testnop.h"
36 #include "testpwr.h"
37
38 static void do_cdrom_drive_read_test(struct ide_controller *ide,unsigned char which,unsigned char continuous) {
39         uint16_t drq_log[((unsigned long)sizeof(cdrom_sector))/2048UL];
40         unsigned long sector = 16; /* read the ISO 9660 table of contents */
41         unsigned long tlen = 2048; /* one sector */
42         unsigned long tlen_sect = 1;
43         unsigned char user_esc = 0;
44         struct vga_msg_box vgabox;
45         unsigned int drq_log_ent;
46         unsigned int cleared=0;
47         uint8_t buf[12] = {0};
48         unsigned int x,y,i;
49         int c;
50
51         sector = prompt_cdrom_sector_number();
52         if (sector == ~0UL)
53                 return;
54         tlen_sect = prompt_cdrom_sector_count();
55         if (tlen_sect == 0UL || tlen_sect == ~0UL)
56                 return;
57         if (tlen_sect > ((unsigned long)sizeof(cdrom_sector) / 2048UL))
58                 tlen_sect = ((unsigned long)sizeof(cdrom_sector) / 2048UL);
59         if (tlen_sect > ((65536UL/2048UL)-1UL)) /* don't try ATAPI requests 64KB or larger, the size field is 16-bit wide */
60                 tlen_sect = ((65536UL/2048UL)-1UL);
61         tlen = tlen_sect * 2048UL;
62
63 again:  /* jump point: send execution back here for another sector */
64         if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
65                 return;
66         idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
67         if (idelib_controller_atapi_prepare_packet_command(ide,/*xfer=to host no DMA*/0x04,/*byte count=*/tlen) < 0) /* fill out taskfile with command */
68                 return;
69         if (idelib_controller_apply_taskfile(ide,0xBE/*base_io+1-5&7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0) /* also writes command */
70                 return;
71
72         /* NTS: Despite OSDev ATAPI advice, IRQ doesn't seem to fire at this stage, we must poll wait */
73         if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
74                 return;
75
76         idelib_controller_update_atapi_state(ide);
77         if (!(ide->last_status&1)) { /* if no error, read result from count register */
78                 do_warn_if_atapi_not_in_command_state(ide); /* sector count register should signal we're in the command stage */
79
80                 do_construct_atapi_scsi_mmc_read(buf,sector,tlen_sect,cdrom_read_mode);
81                 idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
82                 idelib_controller_atapi_write_command(ide,buf,12); /* write 12-byte ATAPI command data */
83                 if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
84                         if (do_ide_controller_user_wait_irq(ide,1) < 0)
85                                 return;
86                         idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
87                 }
88
89                 if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
90                         return;
91
92                 if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
93                         unsigned int ret_len = 0,drq_len,ey;
94
95                         /* NTS: I hate to break it to newbie IDE programmers, but reading back the sector isn't
96                          *      quite the simple "read N bytes" from the drive. In reality, you wait for the drive
97                          *      to signal DRQ, and then read back the length of data it has available for you to
98                          *      read by, then you read that amount, and if more data is due, then you wait for
99                          *      another IRQ and DRQ signal.
100                          *
101                          *      In most cases, the DRQ returned by the drive is the same length you passed in,
102                          *      but NOT ALWAYS. Many cheap laptop drives for example will only return "2048"
103                          *      because they don't have a lot of buffer, and many DVD-ROM drives like to vary
104                          *      the DRQ size per transfer for whatever reason, whether "dynamically" according
105                          *      to CD-ROM spin speed or based on whatever data it's managed to read and buffer
106                          *      so far.
107                          *
108                          *      On the positive side, it means that on an error, the transfer can abort early if
109                          *      it needs to. */
110                         drq_log_ent = 0;
111                         memset(cdrom_sector,0,tlen);
112                         while (ret_len < tlen) {
113                                 if (idelib_controller_is_error(ide)) {
114                                         vga_msg_box_create(&vgabox,"Error",0,0);
115                                         wait_for_enter_or_escape();
116                                         vga_msg_box_destroy(&vgabox);
117                                         break;
118                                 }
119
120                                 idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
121                                 idelib_controller_update_atapi_drq(ide); /* also need to read back the DRQ (data) length the drive has chosen */
122                                 if (idelib_controller_atapi_complete_state(ide)) { /* if suddenly in complete state, exit out */
123                                         do_warn_if_atapi_not_in_data_input_state(ide); /* sector count register should signal we're in the completed stage (command/data=0 input/output=1) */
124                                         break;
125                                 }
126
127                                 if (do_ide_controller_user_wait_drive_drq(ide) < 0) {
128                                         user_esc = 1;
129                                         break;
130                                 }
131                                 idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
132                                 idelib_controller_update_atapi_drq(ide); /* also need to read back the DRQ (data) length the drive has chosen */
133                                 do_warn_if_atapi_not_in_data_input_state(ide); /* sector count register should signal we're in the completed stage (command/data=0 input/output=1) */
134
135                                 assert(drq_log_ent < (sizeof(drq_log)/sizeof(drq_log[0])));
136                                 drq_len = idelib_controller_read_atapi_drq(ide);
137                                 drq_log[drq_log_ent++] = drq_len;
138                                 if (drq_len < 2048UL || (drq_len % 2048UL) != 0UL || (drq_len+ret_len) > tlen) {
139                                         /* we're asking for one sector (2048) bytes, the drive should return that, if not, something's wrong.
140                                          * even cheap POS drives in old laptops will at least always return 2048! */
141                                         sprintf(tmp,"Warning: ATAPI device returned unexpected DRQ=%u (%u+%u = %u)",
142                                                 drq_len,ret_len,tlen);
143                                         vga_msg_box_create(&vgabox,tmp,0,0);
144                                         wait_for_enter_or_escape();
145                                         vga_msg_box_destroy(&vgabox);
146                                         break;
147                                 }
148
149                                 /* OK. read it in */
150                                 idelib_read_pio_general(cdrom_sector+ret_len,drq_len,ide,IDELIB_PIO_WIDTH_DEFAULT);
151                                 if (ide->flags.io_irq_enable) { /* NOW we wait for another IRQ (completion) */
152                                         if (do_ide_controller_user_wait_irq(ide,1) < 0) {
153                                                 user_esc = 1;
154                                                 break;
155                                         }
156                                         idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
157                                 }
158
159                                 if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0) {
160                                         user_esc = 1;
161                                         break;
162                                 }
163
164                                 ret_len += drq_len;
165                         }
166                         idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
167                         do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
168
169                         /* ---- draw contents on the screen ---- */
170                         vga_write_color(0x0E);
171                         if (!cleared) {
172                                 vga_clear();
173                                 cleared = 1;
174                         }
175
176                         vga_moveto(0,0);
177                         vga_write("Contents of CD-ROM sector ");
178                         sprintf(tmp,"%lu-%lu",sector,sector+tlen_sect-1UL); vga_write(tmp);
179                         sprintf(tmp,"(%lu) bytes",(unsigned long)tlen); vga_write(tmp);
180
181                         ey = 3+16+3;
182                         vga_moveto(0,3+16+1);
183                         sprintf(tmp,"%u/%lu in %u DRQ transfers: ",ret_len,tlen,drq_log_ent);
184                         vga_write(tmp);
185                         for (x=0;x < drq_log_ent;x++) {
186                                 int len = sprintf(tmp,"%u ",drq_log[x]);
187                                 if ((vga_pos_x+len) > vga_width) vga_write("\n ");
188                                 vga_write(tmp);
189                         }
190                         while (vga_pos_y <= ey) vga_write(" ");
191
192                         vga_moveto(0,2);
193                         vga_write_color(0x08);
194                         vga_write("BYTE ");
195
196                         vga_moveto(5,2);
197                         for (x=0;x < 16;x++) {
198                                 sprintf(tmp,"+%X ",x);
199                                 vga_write(tmp);
200                         }
201
202                         vga_moveto(5+(16*3)+1,2);
203                         for (x=0;x < 16;x++) {
204                                 sprintf(tmp,"%X",x);
205                                 vga_write(tmp);
206                         }
207
208                         for (i=0;i < (tlen/256UL);i++) { /* 16x16x8 = 2^(4+4+3) = 2^11 = 2048 */
209                                 for (y=0;y < 16;y++) {
210                                         vga_moveto(0,y+3);
211                                         vga_write_color(0x08);
212                                         sprintf(tmp,"%04X ",(i*256)+(y*16));
213                                         vga_write(tmp);
214                                 }
215
216                                 for (y=0;y < 16;y++) {
217                                         vga_moveto(5,y+3);
218                                         vga_write_color(0x0F);
219                                         for (x=0;x < 16;x++) {
220                                                 sprintf(tmp,"%02X ",cdrom_sector[(i*256)+(y*16)+x]);
221                                                 vga_write(tmp);
222                                         }
223
224                                         vga_moveto(5+(16*3)+1,y+3);
225                                         vga_write_color(0x0E);
226                                         for (x=0;x < 16;x++) {
227                                                 vga_writec(sanitizechar(cdrom_sector[(i*256)+(y*16)+x]));
228                                         }
229                                 }
230
231                                 if (continuous && !user_esc) {
232                                         if (kbhit()) {
233                                                 c = getch();
234                                                 if (c == 0) c = getch() << 8;
235                                         }
236                                         break;
237                                 }
238                                 else {
239                                         if ((c=wait_for_enter_or_escape()) == 27)
240                                                 break; /* allow user to exit early by hitting ESC */
241                                 }
242                         }
243
244                         if (c != 27 && !user_esc) {
245                                 /* if the user hit ENTER, then read another sector and display that too */
246                                 sector += tlen_sect;
247                                 goto again;
248                         }
249                 }
250                 else {
251                         common_ide_success_or_error_vga_msg_box(ide,&vgabox);
252                         wait_for_enter_or_escape();
253                         vga_msg_box_destroy(&vgabox);
254
255                         idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
256                         do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
257                 }
258         }
259         else {
260                 common_ide_success_or_error_vga_msg_box(ide,&vgabox);
261                 wait_for_enter_or_escape();
262                 vga_msg_box_destroy(&vgabox);
263         }
264 }
265
266 static const char *drive_cdrom_reading_menustrings[] = {
267         "Show IDE register taskfile",           /* 0 */
268         "Read CD-ROM data sectors",
269         "Read CD-ROM data continuously"
270 };
271
272 void do_drive_cdrom_reading(struct ide_controller *ide,unsigned char which) {
273         struct menuboxbounds mbox;
274         char backredraw=1;
275         VGA_ALPHA_PTR vga;
276         unsigned int x,y;
277         int select=-1;
278         char redraw=1;
279         int c;
280
281         /* UI element vars */
282         menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
283         menuboxbounds_set_item_strings_arraylen(&mbox,drive_cdrom_reading_menustrings);
284
285         /* most of the commands assume a ready controller. if it's stuck,
286          * we'd rather the user have a visual indication that it's stuck that way */
287         c = do_ide_controller_user_wait_busy_controller(ide);
288         if (c != 0) return;
289
290         /* select the drive we want */
291         idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
292
293         /* in case the IDE controller is busy for that time */
294         c = do_ide_controller_user_wait_busy_controller(ide);
295         if (c != 0) return;
296
297         /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
298         c = do_ide_controller_drive_check_select(ide,which);
299         if (c < 0) return;
300
301         /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
302         do_ide_controller_atapi_device_check_post_host_reset(ide);
303
304         /* wait for the drive to indicate readiness */
305         /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
306          *      possibility that the device doesn't exist. This can happen for example if there
307          *      is a master attached but no slave. */
308         c = do_ide_controller_user_wait_drive_ready(ide);
309         if (c < 0) return;
310
311         /* for completeness, clear pending IRQ */
312         idelib_controller_ack_irq(ide);
313
314         while (1) {
315                 if (backredraw) {
316                         vga = vga_alpha_ram;
317                         backredraw = 0;
318                         redraw = 1;
319
320                         for (y=0;y < vga_height;y++) {
321                                 for (x=0;x < vga_width;x++) {
322                                         *vga++ = 0x1E00 + 177;
323                                 }
324                         }
325
326                         vga_moveto(0,0);
327
328                         vga_write_color(0x1F);
329                         vga_write("        IDE controller ");
330                         sprintf(tmp,"@%X",ide->base_io);
331                         vga_write(tmp);
332                         if (ide->alt_io != 0) {
333                                 sprintf(tmp," alt %X",ide->alt_io);
334                                 vga_write(tmp);
335                         }
336                         if (ide->irq >= 0) {
337                                 sprintf(tmp," IRQ %d",ide->irq);
338                                 vga_write(tmp);
339                         }
340                         vga_write(which ? " Slave" : " Master");
341                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
342
343                         vga_write_color(0xC);
344                         vga_write("WARNING: This code talks directly to your hard disk controller.");
345                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
346                         vga_write_color(0xC);
347                         vga_write("         If you value the data on your hard drive do not run this program.");
348                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
349                 }
350
351                 if (redraw) {
352                         redraw = 0;
353
354                         vga_moveto(mbox.ofsx,mbox.ofsy - 2);
355                         vga_write_color((select == -1) ? 0x70 : 0x0F);
356                         vga_write("Back to IDE drive main menu");
357                         while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
358
359                         menuboxbound_redraw(&mbox,select);
360                 }
361
362                 c = getch();
363                 if (c == 0) c = getch() << 8;
364
365                 if (c == 27) {
366                         break;
367                 }
368                 else if (c == 13) {
369                         if (select == -1)
370                                 break;
371
372                         switch (select) {
373                                 case 0: /* show IDE register taskfile */
374                                         do_common_show_ide_taskfile(ide,which);
375                                         redraw = backredraw = 1;
376                                         break;
377                                 case 1: /*Read sectors*/
378                                 case 2: /*Read sectors continuously*/
379                                         do_cdrom_drive_read_test(ide,which,/*continuous=*/(select==2));
380                                         redraw = backredraw = 1;
381                                         break;
382                         };
383                 }
384                 else if (c == 0x4800) {
385                         if (--select < -1)
386                                 select = mbox.item_max;
387
388                         redraw = 1;
389                 }
390                 else if (c == 0x4B00) { /* left */
391                         redraw = 1;
392                 }
393                 else if (c == 0x4D00) { /* right */
394                         redraw = 1;
395                 }
396                 else if (c == 0x5000) {
397                         if (++select > mbox.item_max)
398                                 select = -1;
399
400                         redraw = 1;
401                 }
402         }
403 }
404