]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/ide/testrdws.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / ide / testrdws.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 "testmumo.h"
34 #include "testrdts.h"
35 #include "testrdws.h"
36 #include "test.h"
37
38 #include "testnop.h"
39 #include "testpwr.h"
40
41 static unsigned char drive_write_warning = 1;
42
43 static const char *drive_write_test_menustrings[] = {
44         "Show IDE register taskfile",           /* 0 */
45         "*mode*",                               /* 1 */ /* rewritten (CHS, LBA, CHS MULTI, etc) */
46         drive_readwrite_test_geo,
47         drive_readwrite_test_chs,
48         drive_readwrite_test_numsec,
49         drive_readwrite_test_mult,
50         "Write sectors",
51         "Write sectors continuously"
52 };
53
54 static void do_hdd_drive_write_test(struct ide_controller *ide,unsigned char which,unsigned char continuous,struct drive_rw_test_info *nfo) {
55         unsigned char user_esc = 0;
56         struct vga_msg_box vgabox;
57         struct ide_taskfile *tsk;
58         unsigned long tlen_sect;
59         unsigned int cleared=0;
60         unsigned long tlen;
61         unsigned int i;
62         int c;
63
64         if (nfo->read_sectors == 0) return;
65
66         /* multiple mode: make sure the multiple sector count doesn't exceed our buffer size.
67          * if it does, try to set multiple count to lesser value. */
68         if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
69                 if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL) && nfo->multiple_sectors > 1) {
70                         /* even though most IDE devices really only support power-of-2 sizes, we do a scan downward anyway */
71                         c = ((unsigned long)sizeof(cdrom_sector) / 512UL);
72                         do {
73                                 if (c <= 1) break;
74                                 do_ide_set_multiple_mode(ide,which,c);
75                                 {
76                                         uint16_t info[256];
77
78                                         do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
79                                         drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
80                                 }
81
82                                 if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL))
83                                         c--;
84                                 else
85                                         break;
86                         } while (1);
87                 }
88
89                 if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL))
90                         return;
91                 if (nfo->multiple_sectors == 0)
92                         return;
93         }
94
95         idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
96         tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
97
98 again:  /* jump point: send execution back here for another sector */
99         if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
100                 return;
101         idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
102
103         tlen_sect = nfo->read_sectors;
104         if (tlen_sect > ((unsigned long)sizeof(cdrom_sector) / 512UL))
105                 tlen_sect = ((unsigned long)sizeof(cdrom_sector) / 512UL);
106
107         /* C/H/S continuous: limit reads to within track, don't cross. we can't assume the drive will do that. */
108         if (continuous && (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE)) {
109                 if ((nfo->sector + tlen_sect) > nfo->num_sector)
110                         tlen_sect = (nfo->num_sector + 1 - nfo->sector);
111         }
112
113         tlen = tlen_sect * 512UL;
114
115         if (nfo->mode == DRIVE_RW_MODE_LBA48 || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
116                 tsk->sector_count = tlen_sect;
117                 tsk->lba0_3 = nfo->lba & 0xFF;
118                 tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
119                 tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
120                 tsk->lba0_3 |= ((nfo->lba >> 24) & 0xFF) << 8;
121                 tsk->lba1_4 |= ((nfo->lba >> 32) & 0xFF) << 8;
122                 tsk->lba2_5 |= ((nfo->lba >> 40) & 0xFF) << 8;
123                 tsk->head_select = (which << 4) | 0x40;
124
125                 if (nfo->mode == DRIVE_RW_MODE_LBA48)
126                         tsk->command = 0x34; /* WRITE SECTORS EXT */
127                 else if (nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE)
128                         tsk->command = 0x39; /* WRITE MULTIPLE EXT */
129
130                 if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48/*set LBA48*/) < 0)
131                         return;
132         }
133         else {
134                 if (tsk->sector_count > 256) return;
135                 tsk->sector_count = (tlen_sect&0xFF);
136                 if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
137                         tsk->chs_sector = nfo->sector;
138                         tsk->chs_cylinder_low = nfo->cylinder & 0xFF;
139                         tsk->chs_cylinder_high = (nfo->cylinder >> 8) & 0xFF;
140                         tsk->head_select = (nfo->head & 0xF) | (which << 4) | 0xA0;
141                 }
142                 else if (nfo->mode == DRIVE_RW_MODE_LBA || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE) {
143                         tsk->lba0_3 = nfo->lba & 0xFF;
144                         tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
145                         tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
146                         tsk->head_select = ((nfo->lba >> 24) & 0xF) | (which << 4) | 0xE0;
147                 }
148
149                 if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_LBA)
150                         tsk->command = 0x30; /* WRITE SECTORS */
151                 else if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE)
152                         tsk->command = 0xC5; /* WRITE MULTIPLE */
153
154                 if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0)
155                         return;
156         }
157
158         /* wait for drive ready. drive will NOT fire an IRQ until the write is done. */
159         if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
160                 return;
161
162         if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
163                 unsigned int ret_len = 0,drq_len;
164
165                 /* make test data */
166                 for (i=0;i < tlen;i++) cdrom_sector[i] = i + (i >> 8);
167
168                 while (ret_len < tlen) {
169                         if (idelib_controller_is_error(ide)) {
170                                 vga_msg_box_create(&vgabox,"Error",0,0);
171                                 wait_for_enter_or_escape();
172                                 vga_msg_box_destroy(&vgabox);
173                                 break;
174                         }
175
176                         if (do_ide_controller_user_wait_drive_drq(ide) < 0) {
177                                 user_esc = 1;
178                                 break;
179                         }
180
181                         if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
182                                 nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
183                                 drq_len = nfo->multiple_sectors * 512;
184                                 if ((ret_len+drq_len) > tlen) drq_len = tlen - ret_len;
185                         }
186                         else
187                                 drq_len = 512;
188
189                         /* OK. write it out and acknowledge */
190                         idelib_write_pio_general(cdrom_sector+ret_len,drq_len,ide,IDELIB_PIO_WIDTH_DEFAULT);
191                         ret_len += drq_len;
192
193                         /* you're supposed to wait for IRQ after writing the sector */
194                         if (ide->flags.io_irq_enable) {
195                                 if (do_ide_controller_user_wait_irq(ide,1) < 0) {
196                                         user_esc = 1;
197                                         break;
198                                 }
199                                 idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
200                                 idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
201                         }
202
203                         if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0) {
204                                 user_esc = 1;
205                                 break;
206                         }
207                 }
208
209                 /* ---- draw contents on the screen ---- */
210                 vga_write_color(0x0E);
211                 if (!cleared) {
212                         vga_clear();
213                         cleared = 1;
214                 }
215
216                 vga_moveto(0,0);
217                 vga_write("Sector writing:\n");
218                 if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
219                         sprintf(tmp,"CHS %u/%u/%u    ",nfo->cylinder,nfo->head,nfo->sector); vga_write(tmp);
220                 }
221                 else {
222                         sprintf(tmp,"%llu-%llu",nfo->lba,nfo->lba+(unsigned long long)tlen_sect-1ULL); vga_write(tmp);
223                 }
224
225                 if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
226                         vga_write_color(0x0A);
227                         vga_write(" PASSED\n");
228                 }
229                 else {
230                         vga_write_color(0x0C);
231                         vga_write(" FAILED\n");
232                 }
233
234                 if (continuous && !user_esc) {
235                         if (kbhit()) {
236                                 c = getch();
237                                 if (c == 0) c = getch() << 8;
238                         }
239                         else {
240                                 c = 0;
241                         }
242                 }
243                 else {
244                         if ((c=wait_for_enter_or_escape()) == 27)
245                                 return; /* allow user to exit early by hitting ESC */
246                 }
247
248                 if (c != 27 && !user_esc) {
249                         /* if the user hit ENTER, then read another sector and display that too */
250                         if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
251                                 nfo->sector += (unsigned long long)tlen_sect;
252                                 while (nfo->sector > nfo->num_sector) {
253                                         nfo->sector -= nfo->num_sector;
254                                         nfo->head++;
255                                 }
256                                 while (nfo->head >= nfo->num_head) {
257                                         nfo->head -= nfo->num_head;
258                                         nfo->cylinder++;
259                                 }
260
261                                 if (nfo->cylinder >= 16384) {
262                                         nfo->cylinder = 16383;
263                                         nfo->sector = nfo->num_sector;
264                                         nfo->head = nfo->num_head - 1;
265                                 }
266
267                                 nfo->lba  = (unsigned long long)nfo->cylinder * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
268                                 nfo->lba += (unsigned long long)nfo->head * (unsigned long long)nfo->num_sector;
269                                 nfo->lba += (unsigned long long)nfo->sector - 1ULL;
270                         }
271                         else {
272                                 nfo->lba += (unsigned long long)tlen_sect;
273
274                                 nfo->sector = (int)(nfo->lba % (unsigned long long)nfo->num_sector) + 1;
275                                 nfo->head = (int)((nfo->lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
276                                 if (nfo->lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
277                                         nfo->cylinder = 16383;
278                                         nfo->sector = nfo->num_sector;
279                                         nfo->head = nfo->num_head - 1;
280                                 }
281                                 else {
282                                         nfo->cylinder = (int)((nfo->lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
283                                 }
284                         }
285
286                         goto again;
287                 }
288         }
289         else {
290                 common_ide_success_or_error_vga_msg_box(ide,&vgabox);
291                 wait_for_enter_or_escape();
292                 vga_msg_box_destroy(&vgabox);
293         }
294 }
295
296 void do_drive_write_test(struct ide_controller *ide,unsigned char which) {
297         struct menuboxbounds mbox;
298         char backredraw=1;
299         VGA_ALPHA_PTR vga;
300         unsigned int x,y;
301         int select=-1;
302         char redraw=1;
303         int c;
304
305         if (drive_write_warning) {
306                 struct vga_msg_box box;
307
308                 vga_msg_box_create(&box,
309                         "WARNING: This test is destructive. It overwrites the data on the disk.\n"
310                         "         If you value the data on your hard drive DO NOT RUN THIS TEST.\n"
311                         "\n"
312                         "Hit ESC to cancel, ENTER to continue"
313                         ,0,0);
314                 c = wait_for_enter_or_escape();
315                 vga_msg_box_destroy(&box);
316                 if (c == 27) return;
317
318                 vga_msg_box_create(&box,
319                         "WARNING: Are you sure? The contents of the hard disk will be overwritten\n"
320                         "         in the process of carrying out this test!\n"
321                         "\n"
322                         "Hit ESC to cancel, ENTER to continue"
323                         ,0,0);
324                 c = wait_for_enter_or_escape();
325                 vga_msg_box_destroy(&box);
326                 if (c == 27) return;
327
328                 vga_msg_box_create(&box,
329                         "FINAL WARNING: This test will overwrite the sectors on the disk with\n"
330                         "               test data. The test is not undoable. ARE YOU SURE?\n"
331                         "\n"
332                         "If you confirm, this warning will not show again until the test program\n"
333                         "is restarted.\n"
334                         "\n"
335                         "Hit ESC to cancel, ENTER to continue"
336                         ,0,0);
337                 c = wait_for_enter_or_escape();
338                 vga_msg_box_destroy(&box);
339                 if (c == 27) return;
340
341                 /* if you say so! */
342                 drive_write_warning = 0;
343         }
344
345         /* UI element vars */
346         menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
347         menuboxbounds_set_item_strings_arraylen(&mbox,drive_write_test_menustrings);
348
349         while (1) {
350                 if (backredraw) {
351                         vga = vga_alpha_ram;
352                         backredraw = 0;
353                         redraw = 1;
354
355                         for (y=0;y < vga_height;y++) {
356                                 for (x=0;x < vga_width;x++) {
357                                         *vga++ = 0x1E00 + 177;
358                                 }
359                         }
360
361                         vga_moveto(0,0);
362
363                         vga_write_color(0x1F);
364                         vga_write("        IDE r/w tests ");
365                         sprintf(tmp,"@%X",ide->base_io);
366                         vga_write(tmp);
367                         if (ide->alt_io != 0) {
368                                 sprintf(tmp," alt %X",ide->alt_io);
369                                 vga_write(tmp);
370                         }
371                         if (ide->irq >= 0) {
372                                 sprintf(tmp," IRQ %d",ide->irq);
373                                 vga_write(tmp);
374                         }
375                         vga_write(which ? " Slave" : " Master");
376
377                         sprintf(tmp," lba=%u lba48=%u multiple=%u",
378                                 drive_rw_test_nfo.can_do_lba?1:0,
379                                 drive_rw_test_nfo.can_do_lba48?1:0,
380                                 drive_rw_test_nfo.can_do_multiple?1:0);
381                         vga_write(tmp);
382
383                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
384
385                         vga_write_color(0xC);
386                         vga_write("WARNING: This code talks directly to your hard disk controller.");
387                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
388                         vga_write_color(0xC);
389                         vga_write("         If you value the data on your hard drive do not run this program.");
390                         while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
391                 }
392
393                 if (redraw) {
394                         redraw = 0;
395
396                         drive_write_test_menustrings[1] = drive_readwrite_test_modes[drive_rw_test_nfo.mode];
397
398                         sprintf(drive_readwrite_test_geo,"Geometry: C/H/S %u/%u/%u LBA %llu",
399                                 drive_rw_test_nfo.num_cylinder,
400                                 drive_rw_test_nfo.num_head,
401                                 drive_rw_test_nfo.num_sector,
402                                 drive_rw_test_nfo.max_lba);
403
404                         sprintf(drive_readwrite_test_chs,"Position: C/H/S %u/%u/%u LBA %llu",
405                                 drive_rw_test_nfo.cylinder,
406                                 drive_rw_test_nfo.head,
407                                 drive_rw_test_nfo.sector,
408                                 drive_rw_test_nfo.lba);
409
410                         sprintf(drive_readwrite_test_numsec,"Number of sectors per read: %u",
411                                 drive_rw_test_nfo.read_sectors);
412
413                         sprintf(drive_readwrite_test_mult,"Multiple mode: %u sectors (max=%u)",
414                                 drive_rw_test_nfo.multiple_sectors,
415                                 drive_rw_test_nfo.max_multiple_sectors);
416
417                         vga_moveto(mbox.ofsx,mbox.ofsy - 2);
418                         vga_write_color((select == -1) ? 0x70 : 0x0F);
419                         vga_write("Back to IDE controller main menu");
420                         while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
421
422                         menuboxbound_redraw(&mbox,select);
423                 }
424
425                 c = getch();
426                 if (c == 0) c = getch() << 8;
427
428                 if (c == 27) {
429                         break;
430                 }
431                 else if (c == 13) {
432                         if (select == -1)
433                                 break;
434
435                         switch (select) {
436                                 case 0: /* show IDE register taskfile */
437                                         do_common_show_ide_taskfile(ide,which);
438                                         redraw = backredraw = 1;
439                                         break;
440                                 case 1: /* Mode */
441                                         do_drive_readwrite_test_choose_mode(ide,which,&drive_rw_test_nfo);
442                                         redraw = backredraw = 1;
443                                         break;
444                                 case 2: /* Edit geometry/max LBA */
445                                         do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/1);
446                                         redraw = 1;
447                                         break;
448                                 case 3: /* Edit position */
449                                         do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/0);
450                                         redraw = 1;
451                                         break;
452                                 case 4: /* Number of sectors */
453                                         c = prompt_sector_count();
454                                         if (c >= 1 && c <= 256) {
455                                                 drive_rw_test_nfo.read_sectors = c;
456                                                 redraw = 1;
457                                         }
458                                         break;
459                                 case 5: /* Multiple mode sector count */
460                                         c = prompt_sector_count();
461                                         if (c >= 0 && c <= 255) {
462                                                 do_ide_set_multiple_mode(ide,which,c);
463                                                 {
464                                                         uint16_t info[256];
465
466                                                         do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
467                                                         drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
468                                                 }
469                                                 redraw = 1;
470                                         }
471                                         break;
472                                 case 6: /*Read sectors*/
473                                 case 7: /*Read sectors continuously*/
474                                         do_hdd_drive_write_test(ide,which,/*continuous=*/(select==7),&drive_rw_test_nfo);
475                                         redraw = backredraw = 1;
476                                         break;
477                         };
478                 }
479                 else if (c == 0x4800) {
480                         if (--select < -1)
481                                 select = mbox.item_max;
482
483                         redraw = 1;
484                 }
485                 else if (c == 0x4B00) { /* left */
486                         switch (select) {
487                                 case 1: /* Mode */
488                                         do {
489                                                 if (drive_rw_test_nfo.mode == 0)
490                                                         drive_rw_test_nfo.mode = DRIVE_RW_MODE_MAX-1;
491                                                 else
492                                                         drive_rw_test_nfo.mode--;
493                                         } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
494                                         break;
495                                 case 4: /* Number of sectors */
496                                         if (drive_rw_test_nfo.read_sectors > 1)
497                                                 drive_rw_test_nfo.read_sectors--;
498                                         break;
499                         };
500
501                         redraw = 1;
502                 }
503                 else if (c == 0x4D00) { /* right */
504                         switch (select) {
505                                 case 1: /* Mode */
506                                         do {
507                                                 if (++drive_rw_test_nfo.mode >= DRIVE_RW_MODE_MAX)
508                                                         drive_rw_test_nfo.mode = 0;
509                                         } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
510                                         break;
511                                 case 4: /* Number of sectors */
512                                         if (drive_rw_test_nfo.read_sectors < 256)
513                                                 drive_rw_test_nfo.read_sectors++;
514                                         break;
515                         };
516
517                         redraw = 1;
518                 }
519                 else if (c == 0x5000) {
520                         if (++select > mbox.item_max)
521                                 select = -1;
522
523                         redraw = 1;
524                 }
525         }
526 }
527