Compare commits
20 Commits
v0.2-beta-
...
main
Author | SHA1 | Date |
---|---|---|
Marcio T | 4793ffc0d8 | |
Marcio T | b6fa1cad7a | |
Marcio T | 7d96b63ef0 | |
Marcio T | c719c8d7dd | |
Marcio T | dcfa0958a6 | |
Marcio T | bfa9014432 | |
Marcio T | 6b36dfdc0e | |
Marcio T | 49ce1bc093 | |
Marcio T | afb8d6fe8f | |
Marcio T | efd84f0ebc | |
Marcio T | 4ab4a0cc90 | |
Marcio T | bfdf0d8171 | |
Marcio T | a90cdf000f | |
Marcio T | 98edb49670 | |
Marcio T | 37dab8d0b7 | |
Marcio T | b5f0328beb | |
Marcio T | 1af5e74aea | |
Marcio T | 5ab24df256 | |
Marcio T | b00a01b948 | |
Marcio T | d21a0c277b |
75
README.md
75
README.md
|
@ -8,6 +8,15 @@ This is the repository for a Macintosh port of [Gibson Research Corp]'s
|
|||
Jaz Drives. A big thanks goes to Steve Gibson for the x86 source that
|
||||
made this project possible!
|
||||
|
||||
[![Trouble in Paradise Demonstration](https://github.com/marciot/mac-tip/raw/main/images/youtube.png)](https://youtu.be/vtBlOaG2pNw)
|
||||
|
||||
:tv: See a demo on [YouTube]!
|
||||
|
||||
[![Mention in Steve Gibson's Security Now Podcast](https://github.com/marciot/mac-tip/raw/main/images/security-now.png)](https://twit.tv/shows/security-now/episodes/845)
|
||||
|
||||
:tv: Watch Steve Gibson react to my unusual request in the November 16th
|
||||
episode of the "Security Now" podcast at the 1:05:10 mark.
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
|
@ -20,17 +29,19 @@ Power Macintosh G3, released in 1997.
|
|||
|
||||
It has been tested in on the following environments:
|
||||
|
||||
| Computer | Memory | System | Drive | Firmware |
|
||||
|------------------- |--------|--------|-------------------------|----------|
|
||||
| Macintosh Plus | 4MB | 7.0.1 | Zip Plus 100 Ext. SCSI | J.66 |
|
||||
| PowerBook 3400c | 144MB | 8.6 | Zip 100 Ext. SCSI | E.08 |
|
||||
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Ext. SCSI | C.22 |
|
||||
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Int. SCSI | J.03 |
|
||||
| Computer | Memory | System | Drive | Firmware |
|
||||
|------------------- |--------|--------|-------------------------------------|----------|
|
||||
| Macintosh Plus | 4MB | 7.0.1 | Zip Plus 100 Ext. SCSI | J.66 |
|
||||
| PowerBook 3400c | 144MB | 8.6 | Zip 100 Ext. SCSI | E.08 |
|
||||
| PowerBook 3400c | 144MB | 8.6 | Jaz 2GB Ext. SCSI w/ 1GB media | E.17 |
|
||||
| PowerBook 3400c | 144MB | 8.6 | Jaz 2GB Ext. SCSI w/ 2GB media | E.17 |
|
||||
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Ext. SCSI | C.22 |
|
||||
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Int. SCSI | J.03 |
|
||||
|
||||
What will not work or is missing:
|
||||
|
||||
* USB connected Zip drives have been reported to not work.
|
||||
* The functionality for operating with password or write protected disks is missing.
|
||||
* The functionality for operating with password or write protected disks has not been ported.
|
||||
* The partition recovery feature has been removed, since it is meant for PC disks.
|
||||
|
||||
</details>
|
||||
|
@ -47,13 +58,9 @@ port.**
|
|||
Where are the binaries?
|
||||
-----------------------
|
||||
|
||||
Once they are ready, compiled binaries will be made available on the
|
||||
releases page for people who have signed up for
|
||||
Compiled binaries are available on the releases page for people who have signed up for
|
||||
[beta testing in the discussion forum]
|
||||
|
||||
There is always a risk of data loss with a tool like this, so please
|
||||
use it only on non-critical data if you decide to beta test.
|
||||
|
||||
How can you help?
|
||||
-----------------
|
||||
|
||||
|
@ -61,8 +68,14 @@ You can help this project in one of the following ways:
|
|||
|
||||
* Star this project on GitHub to show your support!
|
||||
* Sign up to [beta testing in the discussion forum]!
|
||||
* Donate a 1 or 2GB Jaz cartridge for testing (I have a 2GB SCSI Jaz drive, but no cartridges!).
|
||||
* Become a GitHub sponsor to help fund my work with this and other open-source projects!
|
||||
* Become a GitHub sponsor to help fund my various open-source projects!
|
||||
|
||||
Other Vintage Macintosh Stuff
|
||||
-----------------------------
|
||||
|
||||
* [MiniVNC]: A remote desktop server for vintage Macintoshes!
|
||||
* [ScreenChooser]: A dynamic background changer for vintage Macintoshes!
|
||||
* [Retroweb Vintage Computer Museum]: A web-based museum of vintage computers, including the Macintosh!
|
||||
|
||||
Got work?
|
||||
---------
|
||||
|
@ -74,20 +87,22 @@ for vintage Macs. If you have a project in mind, please hit me up via my
|
|||
Unmounting volumes
|
||||
------------------
|
||||
|
||||
**To avoid data corruption, you must "unmount" the cartridge prior to
|
||||
**To avoid data corruption, a cartridge must be unmounted prior to
|
||||
starting a test with TIP!**
|
||||
|
||||
There is no way to unmount a cartridge (without also ejecting it) in the
|
||||
Finder, but you can either:
|
||||
The best way to accomplish this is to start TIP without a disk in the drive you want to test.
|
||||
Then, insert the cartridge at the testing screen which indicates "Awaiting media...". TIP
|
||||
will recognize it if Mac OS mounts newly inserted cartridge and will give you the choice to
|
||||
unmount it.
|
||||
|
||||
1) Start TIP without a disk in the drive. TIP will recognize when Mac OS mounts newly inserted cartridges and will give you the choice to unmount it.
|
||||
2) Use the command console to unmount a disk **prior to** starting TIP
|
||||
Alternatively, you can use the command line from the "Advanced" menu to unmount a disk
|
||||
**prior to** starting a test.
|
||||
|
||||
<details>
|
||||
<summary>Click here to learn how to use the Command Console</summary></br>
|
||||
<summary>Click here to learn how to use the command line</summary></br>
|
||||
|
||||
The Command Console shows up when you first start the program. This is a
|
||||
unique feature of this port and is not present in the original TIP:
|
||||
The command line is accessible by selecting run "Run Command Line..." from the "Advanced"
|
||||
menu. This is a unique feature of this port and is not present in the original TIP:
|
||||
|
||||
![Command Line][mac-screenshot2]
|
||||
|
||||
|
@ -104,15 +119,10 @@ cartridge will remain in the drive. To unmount a drive:
|
|||
*The unmount process will fail if you have any open files or applications in
|
||||
the volume; if this happens, close those files and try again.*
|
||||
|
||||
### Starting TIP
|
||||
|
||||
To start TIP, you will need to tell it which SCSI device to use:
|
||||
### Listing SCSI devices
|
||||
|
||||
* Type `list` to show a numbered list of all SCSI devices by SCSI ID.
|
||||
* Type `tip` followed by a SCSI ID to run TIP on that device.
|
||||
|
||||
Future versions of this tool may eliminate the Command Console, if I can find
|
||||
the right way to automate all these steps in MacOS :grin:
|
||||
</details>
|
||||
|
||||
About the code
|
||||
|
@ -145,6 +155,7 @@ Credits
|
|||
* Thank you to [Stone Table Software] for providing the tool I used to convert the Windows RTF docs into SimpleText...
|
||||
* ...and to the Internet Archive's Wayback Machine for allowing me to access it long after the website was shut down!
|
||||
* Thank you to Thomas Tempelmann sharing his [LaunchLib code] which I used to open the documents
|
||||
* Thank you to Grant Hutchinson and Nikola Biscan for sending me 1GB and 2GB Jaz cartridges for testing.
|
||||
|
||||
The Original TIP For Windows
|
||||
----------------------------
|
||||
|
@ -164,7 +175,7 @@ his code in this repository with his permission.
|
|||
![TIP Running on a Mac Plus][mac-plus]
|
||||
|
||||
[GitHub account]: https://github.com/marciot
|
||||
[mac-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip1.png "Mac TIP Testing Screen"
|
||||
[mac-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip1.gif "Mac TIP Animation"
|
||||
[mac-screenshot2]: https://github.com/marciot/mac-tip/raw/main/images/mac-cmd.png "Mac TIP Command Line"
|
||||
[mac-screenshot3]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip-cw8.png "Mac TIP Build Environment"
|
||||
[win-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/win-tip1.gif "Windows TIP About Screen"
|
||||
|
@ -178,3 +189,9 @@ his code in this repository with his permission.
|
|||
[beta testing in the discussion forum]: https://github.com/marciot/mac-tip/discussions/1
|
||||
[LaunchLib code]: http://www.tempel.org/macdev/index.html#Libs
|
||||
[Stone Table Software]: https://web.archive.org/web/20010308062807/http://www.stonetablesoftware.com/rtf2text.html
|
||||
[ScreenChooser]: https://archive.org/details/screen-chooser
|
||||
[YouTube]: https://youtu.be/vtBlOaG2pNw
|
||||
[Retroweb Vintage Computer Museum]: http://retroweb.maclab.org
|
||||
[MiniVNC]: https://github.com/marciot/mac-minivnc
|
||||
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 264 KiB |
Binary file not shown.
Before Width: | Height: | Size: 101 KiB |
Binary file not shown.
After Width: | Height: | Size: 693 KiB |
Binary file not shown.
After Width: | Height: | Size: 465 KiB |
|
@ -12,32 +12,13 @@ void main() {
|
|||
SIOUXSettings.leftpixel = 8;
|
||||
SIOUXSettings.toppixel = 44;
|
||||
|
||||
printf(
|
||||
"\n\n"
|
||||
"Trouble in Paradise\n"
|
||||
"===================\n\n"
|
||||
"A Macintosh port of \"Trouble in Paradise\" for Windows, made possible by a\n"
|
||||
"generous code donation by Steve Gibson from Gibson Research Corporation.\n\n"
|
||||
"This freeware utility determines whether an Iomega Zip or Jaz drive is prone\n"
|
||||
"to developing the dreaded \"Click of Death\" (COD) syndrome. Steve Gibson's\n"
|
||||
"research into the maintenance, repair and data recovery of Iomega's removable\n"
|
||||
"media mass storage products led to this capability.\n\n"
|
||||
);
|
||||
|
||||
printf( "------------------------------------------------------------------------------\n" );
|
||||
printf( "This Mac port (c) 2021 Marcio Teixeira http://github.com/marciot/mac-tip\n" );
|
||||
printf( "Based on code (c) 2006 Gibson Research Corp http://grc.com/tip/clickdeath.htm\n" );
|
||||
printf( "------------------------------------------------------------------------------\n" );
|
||||
printf("\nStarting tip ...\n");
|
||||
|
||||
SIOUXSetTitle("\pTrouble in Paradise for Macintosh (" __DATE__ ")");
|
||||
|
||||
// Confirm that the user wants to run TIP
|
||||
|
||||
char cmd[80];
|
||||
printf("\n\nThis program is in BETA TESTING and may cause data loss!\n\nProceed [Y/N]? ");
|
||||
gets( cmd );
|
||||
if(tolower(cmd[0]) == 'y') {
|
||||
run_tip();
|
||||
printf("\n\nYou may need to REBOOT your Mac before cartridges are recognized by Mac OS.");
|
||||
}
|
||||
run_tip();
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -14,7 +14,8 @@ void mac_list_volumes() {
|
|||
for (;;) {
|
||||
OSErr err = PBHGetVInfo(¶mBlock, false);
|
||||
if (err == nsvErr) break;
|
||||
printf(" %d: %#s\n", paramBlock.volumeParam.ioVolIndex, paramBlock.volumeParam.ioNamePtr);
|
||||
size_t size = paramBlock.volumeParam.ioVAlBlkSiz * paramBlock.volumeParam.ioVNmAlBlks;
|
||||
printf("%4d: [%7.2f MBs] %#s\n", paramBlock.volumeParam.ioVolIndex, float(size)/1024/1024, paramBlock.volumeParam.ioNamePtr);
|
||||
paramBlock.volumeParam.ioVolIndex++;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +24,7 @@ OSErr mac_get_drive_volumes(int driveNum, Str255 str) {
|
|||
HParamBlockRec paramBlock;
|
||||
Str255 volName;
|
||||
Boolean first = true;
|
||||
|
||||
str[0] = '\0';
|
||||
paramBlock.volumeParam.ioCompletion = 0;
|
||||
paramBlock.volumeParam.ioNamePtr = volName;
|
||||
paramBlock.volumeParam.ioVRefNum = 0;
|
||||
|
@ -65,6 +66,38 @@ OSErr mac_unmount_drive(int driveNum) {
|
|||
}
|
||||
}
|
||||
|
||||
OSErr mac_mount_drive(int driveNum) {
|
||||
ParamBlockRec paramBlock;
|
||||
|
||||
paramBlock.volumeParam.ioVRefNum = driveNum;
|
||||
|
||||
OSErr err = PBMountVol(¶mBlock);
|
||||
return err;
|
||||
}
|
||||
|
||||
OSErr mac_mount_drives() {
|
||||
const QHdrPtr qh = GetDrvQHdr();
|
||||
for(DrvQElPtr qe = (DrvQElPtr) qh->qHead; qe; qe = (DrvQElPtr) qe->qLink) {
|
||||
OSErr err = mac_mount_drive(qe->dQDrive);
|
||||
switch(err) {
|
||||
case volOnLinErr: continue;
|
||||
default: printf("Error %d while mounting drive %d\n", err, qe->dQDrive);
|
||||
}
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSErr mac_list_drives() {
|
||||
Str255 volumeNames;
|
||||
const QHdrPtr qh = GetDrvQHdr();
|
||||
for(DrvQElPtr qe = (DrvQElPtr) qh->qHead; qe; qe = (DrvQElPtr) qe->qLink) {
|
||||
size_t size = size_t(qe->dQDrvSz) | ((qe->qType == 1) ? size_t(qe->dQDrvSz2) << 16 : 0) ;
|
||||
mac_get_drive_volumes(qe->dQDrive, volumeNames);
|
||||
printf("%4d: [%7.2f MBs] %#s\n", qe->dQDrive, float(size)/2/1024, volumeNames);
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void mac_unmount(int id) {
|
||||
HParamBlockRec paramBlock;
|
||||
paramBlock.volumeParam.ioCompletion = 0;
|
||||
|
|
|
@ -3,3 +3,6 @@ void mac_unmount(int id);
|
|||
void mac_eject(int id);
|
||||
OSErr mac_get_drive_volumes(int driveNum, Str255 str);
|
||||
OSErr mac_unmount_drive(int driveNum);
|
||||
OSErr mac_mount_drive(int driveNum);
|
||||
OSErr mac_mount_drives();
|
||||
OSErr mac_list_drives();
|
|
@ -130,6 +130,9 @@ bool TBMouseDown( TBHandle tb, Point where, WindowPtr whichWindow ) {
|
|||
HLock( (Handle) tb );
|
||||
TBRec &my = **tb;
|
||||
|
||||
// Return if hidden
|
||||
if((*my.scroll)->contrlVis == 0) return 0;
|
||||
|
||||
ControlHandle whichCntl;
|
||||
short partCode = FindControl(where, whichWindow, &whichCntl);
|
||||
if (partCode) {
|
||||
|
@ -189,7 +192,7 @@ void TBSetScroll( TBHandle tb, short scroll ) {
|
|||
my.lastV = scroll;
|
||||
}
|
||||
|
||||
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec) {
|
||||
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec, bool redraw) {
|
||||
short fRefNum;
|
||||
|
||||
TBSetScroll(tb, 0);
|
||||
|
@ -236,7 +239,7 @@ OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec) {
|
|||
Handle hStyle = Get1Resource('styl', 128);
|
||||
if (hStyle) {
|
||||
HNoPurge(hStyle);
|
||||
TEUseStyleScrap(0, dataSize, (StScrpHandle) hStyle, true, my.tbox);
|
||||
TEUseStyleScrap(0, dataSize, (StScrpHandle) hStyle, redraw, my.tbox);
|
||||
TECalText(my.tbox);
|
||||
ReleaseResource(hStyle);
|
||||
}
|
||||
|
|
|
@ -28,4 +28,4 @@ void TBUpdate( TBHandle html );
|
|||
void TBResize( TBHandle html, const Rect *r );
|
||||
void TBSetScroll( TBHandle html, short scroll );
|
||||
bool TBMouseDown( TBHandle html, Point where, WindowPtr whichWindow );
|
||||
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec);
|
||||
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec, bool redraw);
|
||||
|
|
|
@ -38,19 +38,24 @@ bool process_command() {
|
|||
printf("\n");
|
||||
|
||||
char *arg_str = strchr(cmd, ' ');
|
||||
while(*arg_str == ' ') arg_str++;
|
||||
if(arg_str) arg_val = atoi(arg_str);
|
||||
if(arg_str) {
|
||||
while(*arg_str == ' ') arg_str++;
|
||||
arg_val = atoi(arg_str);
|
||||
}
|
||||
|
||||
switch( tolower(cmd[0]) ) {
|
||||
case 'h': print_help(); break;
|
||||
case 'l': scan_bus(); break;
|
||||
case 's': iomega_spin_up_cartridge(arg_val); break;
|
||||
case 'p': iomega_spin_down_cartridge(arg_val); break;
|
||||
case 'r': scsi_reset(); break;
|
||||
case 'e': mac_eject(arg_val); break;
|
||||
case 'i': dev_info(arg_val); break;
|
||||
case 'v': mac_list_volumes(); break;
|
||||
case 'u': mac_unmount(arg_val); break;
|
||||
case 'q': return false;
|
||||
case 'd': mac_list_drives(); break;
|
||||
case 'm': if(arg_str) mac_mount_drive(arg_val); else mac_mount_drives(); break;
|
||||
default: printf("Unknown command, type 'h' for help\n");
|
||||
}
|
||||
return true;
|
||||
|
@ -62,10 +67,15 @@ void print_help() {
|
|||
" help : print this help\n"
|
||||
" quit : exit the command line\n"
|
||||
|
||||
"\nMacintosh commands:\n"
|
||||
"\nMacintosh volume commands:\n"
|
||||
" volumes : list Mac volumes\n"
|
||||
" unmount [n] : unmount a volume\n"
|
||||
" eject [n] : eject a volume\n"
|
||||
" unmount [n] : unmount a volume\n"
|
||||
|
||||
"\nMacintosh drive commands:\n"
|
||||
" drives : list all drives\n"
|
||||
" mount [n] : mount a drive\n"
|
||||
" mount : mount all drives\n"
|
||||
|
||||
"\nGeneral SCSI operations:\n"
|
||||
" reset : reset the SCSI bus\n"
|
||||
|
@ -74,6 +84,7 @@ void print_help() {
|
|||
|
||||
"\nIomega device operations on SCSI device:\n"
|
||||
" spin [n] : spin up a cartridge\n"
|
||||
" pause [n] : spin down a cartridge\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -84,9 +95,9 @@ void scan_bus() {
|
|||
for( id=0; id<8; id++ ) {
|
||||
err = scsi_inquiry( id, 0, &reply);
|
||||
if( err != 0 ) {
|
||||
printf( " %hd: (Not installed)\n", id );
|
||||
printf( "%4hd: (Not installed)\n", id );
|
||||
} else {
|
||||
printf( " %hd: ", id );
|
||||
printf( "%4hd: ", id );
|
||||
printn( reply.vend, 8 );
|
||||
printf( ", " );
|
||||
printn( reply.prod, 16 );
|
||||
|
|
|
@ -29,6 +29,19 @@ OSErr iomega_spin_down_and_eject( int id ) {
|
|||
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
OSErr iomega_spin_down_cartridge( int id ) {
|
||||
// issue an Asynchronous STOP command to induce spindown
|
||||
char cmd[6] = {
|
||||
SCSI_Cmd_StartStopUnit,
|
||||
1, // set the IMMED bit for offline
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
OSErr iomega_set_prevent_removal( int id, bool lock) {
|
||||
OSErr err;
|
||||
char cmd[6] = {
|
||||
|
|
|
@ -4,5 +4,6 @@ typedef Boolean bool;
|
|||
|
||||
OSErr iomega_spin_up_cartridge(int id);
|
||||
OSErr iomega_spin_down_and_eject(int id);
|
||||
OSErr iomega_spin_down_cartridge(int id);
|
||||
OSErr iomega_set_prevent_removal(int id, bool lock);
|
||||
OSErr iomega_eject_cartridge(int id);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define READ_TIMEOUT 60 /* 300 ticks = 5 seconds */
|
||||
#define READ_TIMEOUT 180 /* 300 ticks = 5 seconds */
|
||||
|
||||
OSErr scsi_reset() {
|
||||
return SCSIReset();
|
||||
|
@ -61,18 +61,21 @@ OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cn
|
|||
case SCSI_READ: io_err = SCSIRead( (Ptr) TIB ); break;
|
||||
default: break;
|
||||
}
|
||||
if (io_err != noErr) {
|
||||
printf("SCSI Read/Write Error: %d\n", io_err);
|
||||
if (io_err == scPhaseErr && flags & SCSI_READ) {
|
||||
printf("\nSCSI phase error; less data delivered than requested\n");
|
||||
}
|
||||
else if (io_err != noErr) {
|
||||
printf("\nSCSI Read/Write Error: %d\n", io_err);
|
||||
}
|
||||
} else {
|
||||
printf("SCSICmd Error: %d\n", err);
|
||||
}
|
||||
|
||||
/* Complete the transaction and release the bus */
|
||||
short cstat, cmsg;
|
||||
short cstat = 0, cmsg = 0;
|
||||
OSErr comperr = SCSIComplete( &cstat, &cmsg, READ_TIMEOUT );
|
||||
if(status) *status = cstat;
|
||||
if (comperr != noErr) {printf("SCSIComplete Error: %d (status: %d)\n", err, cstat); return err;}
|
||||
if (comperr != noErr) {printf("SCSIComplete Error: %d (status: %d)\n", comperr, cstat); return err;}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -8,16 +8,17 @@
|
|||
|
||||
#include "tip.h"
|
||||
|
||||
// ----------------------- Test Monitor Panel Definitions -------------------
|
||||
#define SET_RECT(LEFT, TOP, RIGHT, BOTTOM) {TOP, LEFT, BOTTOM, RIGHT}
|
||||
#define TITLE_TOP 11
|
||||
#define BODY_TOP 54
|
||||
#define BODY_LEFT 156
|
||||
#define BODY_RIGHT 445
|
||||
#define BODY_BOTTOM 280
|
||||
|
||||
Rect CS_Stat = SET_RECT(114, 8, 242, 28);
|
||||
Rect TP_Perc = SET_RECT( 12, 56, 409, 72);
|
||||
Rect SS_Jaz = SET_RECT( 12, 94, 409, 126);
|
||||
Rect SS_Sid0 = SET_RECT( 12, 94, 409, 110);
|
||||
Rect TL_Sect = SET_RECT( 75, 154, 203, 170);
|
||||
Rect ES_Read = SET_RECT(346, 154, 409, 170);
|
||||
Rect SE_Rect = SET_RECT(222, 154, 255, 221);
|
||||
#define BODY_WIDTH (BODY_RIGHT - BODY_LEFT)
|
||||
#define BODY_HEIGHT (BODY_BOTTOM - BODY_TOP)
|
||||
|
||||
#define LOGO_1_LEFT 157
|
||||
#define LOGO_1_TOP 57
|
||||
|
||||
/*******************************************************************************
|
||||
* WinMain
|
||||
|
@ -41,6 +42,22 @@ void WinMain(uint8_t *DrivesSkipped) {
|
|||
StartApplicationTimer();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT 3D HEADLINE
|
||||
*******************************************************************************/
|
||||
void Paint3DHeadline(const char *pszText, int Xleft, int Ytop) {
|
||||
TextSize(24);
|
||||
TextFace(bold);
|
||||
TextFont(helvetica);
|
||||
SetColor(WHITE_COLOR);
|
||||
TextOut(Xleft, Ytop, pszText);
|
||||
SetColor(BLACK_COLOR);
|
||||
TextOut(Xleft+1, Ytop+1, pszText);
|
||||
TextFont(applFont);
|
||||
TextFace(0);
|
||||
TextSize(10);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* WndProc
|
||||
*
|
||||
|
@ -53,17 +70,80 @@ void WndProc(long iMessage, uint16_t wParam) {
|
|||
if (iMessage == WM_PAINT) {
|
||||
// Draw the Lower Horz Button Divider
|
||||
|
||||
GetDC(hMainWnd);
|
||||
SetColor(GRAY_COLOR);
|
||||
MoveTo(15, 289);
|
||||
LineTo(446, 289);
|
||||
SetColor(WHITE_COLOR);
|
||||
LineTo(446, 290);
|
||||
LineTo(14, 290);
|
||||
ReleaseDC(hMainWnd);
|
||||
|
||||
// Draw the Gibson 'G' Logo
|
||||
if(CurrentPage == INTRO_PAGE) {
|
||||
GetDC(hIntroWnd);
|
||||
SetColor(GRAY_COLOR, GRAY_COLOR);
|
||||
MoveTo(LOGO_1_LEFT+1, LOGO_1_TOP+29);
|
||||
LineTo(LOGO_1_LEFT+14, LOGO_1_TOP+29);
|
||||
LineTo(LOGO_1_LEFT+14, LOGO_1_TOP+0);
|
||||
SetColor(WHITE_COLOR, LTGRAY_COLOR);
|
||||
LineTo(LOGO_1_LEFT+12, LOGO_1_TOP+0);
|
||||
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+12);
|
||||
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+30);
|
||||
|
||||
SetColor(GRAY_COLOR, GRAY_COLOR);
|
||||
MoveTo(LOGO_1_LEFT+18, LOGO_1_TOP+14);
|
||||
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+14);
|
||||
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+12);
|
||||
LineTo(LOGO_1_LEFT+34, LOGO_1_TOP+0);
|
||||
SetColor(WHITE_COLOR, LTGRAY_COLOR);
|
||||
LineTo(LOGO_1_LEFT+17, LOGO_1_TOP+0);
|
||||
LineTo(LOGO_1_LEFT+17, LOGO_1_TOP+15);
|
||||
|
||||
SetColor(GRAY_COLOR, GRAY_COLOR);
|
||||
MoveTo(LOGO_1_LEFT+33, LOGO_1_TOP+46);
|
||||
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+46);
|
||||
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+29);
|
||||
LineTo(LOGO_1_LEFT+34, LOGO_1_TOP+17);
|
||||
SetColor(WHITE_COLOR, LTGRAY_COLOR);
|
||||
LineTo(LOGO_1_LEFT+32, LOGO_1_TOP+17);
|
||||
LineTo(LOGO_1_LEFT+32, LOGO_1_TOP+47);
|
||||
|
||||
SetColor(GRAY_COLOR, GRAY_COLOR);
|
||||
MoveTo(LOGO_1_LEFT+1, LOGO_1_TOP+35);
|
||||
LineTo(LOGO_1_LEFT+12, LOGO_1_TOP+46);
|
||||
LineTo(LOGO_1_LEFT+29, LOGO_1_TOP+46);
|
||||
LineTo(LOGO_1_LEFT+29, LOGO_1_TOP+32);
|
||||
SetColor(WHITE_COLOR, LTGRAY_COLOR);
|
||||
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+32);
|
||||
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+35);
|
||||
|
||||
// paint the 3D program title
|
||||
Paint3DHeadline(szIntroTitle, BODY_LEFT, TITLE_TOP);
|
||||
|
||||
// now the rest of the stuff ...
|
||||
SetColor(BLACK_COLOR);
|
||||
#define WH_RECT(L,T,W,H) L, T, L + W, T + H
|
||||
|
||||
Rect rect;
|
||||
SetRect(&rect, WH_RECT(221, BODY_TOP, 230, 60));
|
||||
TETextBox(szIntroSubTitle, strlen(szIntroSubTitle), &rect, teFlushDefault);
|
||||
|
||||
SetRect(&rect, WH_RECT(BODY_LEFT, BODY_TOP+64, BODY_WIDTH, 115));
|
||||
TETextBox(szIntroText, strlen(szIntroText), &rect, teFlushDefault);
|
||||
|
||||
// show the current logo bitmap
|
||||
SplashTheBitmap();
|
||||
|
||||
ReleaseDC(hIntroWnd);
|
||||
}
|
||||
|
||||
// Paint the Copyright Notice
|
||||
GetDC(hMainWnd);
|
||||
SetColor(GRAY_COLOR);
|
||||
TextOut(15, 298, szCopyright_1);
|
||||
TextOut(15, 311, szCopyright_2);
|
||||
ReleaseDC(hMainWnd);
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// WM_COMMAND : a button was pressed
|
||||
|
@ -81,7 +161,7 @@ void WndProc(long iMessage, uint16_t wParam) {
|
|||
SpinUpIomegaCartridge(CurrentDevice);
|
||||
break;
|
||||
case DISK_AT_SPEED:
|
||||
printf("Testing the disk\n");
|
||||
printf("\nTesting the disk\n");
|
||||
if(TestingPhase != READY_TO_TEST) {
|
||||
PrepareToBeginTesting();
|
||||
}
|
||||
|
@ -97,6 +177,7 @@ void WndProc(long iMessage, uint16_t wParam) {
|
|||
EjectIomegaCartridge(CurrentDevice);
|
||||
break;
|
||||
case DISK_LOW_SPARES:
|
||||
CartridgeStatus = DISK_AT_SPEED;
|
||||
SetRichEditText(szNotRunning);
|
||||
SetWindowText(hTestButton, szPressToStart);
|
||||
PrepareToBeginTesting();
|
||||
|
@ -110,18 +191,6 @@ void WndProc(long iMessage, uint16_t wParam) {
|
|||
}
|
||||
}
|
||||
|
||||
BtnList tipBtns[] = {
|
||||
{IDB_BACK, szBack, 157, 301, 80, 24},
|
||||
{IDB_NEXT, szNext, 236, 301, 80, 24},
|
||||
{IDB_QUIT, szQuit, 402, 301, 45, 24},
|
||||
// For Mac TIP only
|
||||
{IDB_TEST, szPressToStart, 157, 301, 150, 24},
|
||||
{IDB_EXPL, "Explain", 330, 301, 60, 24},
|
||||
{IDB_OKAY, "Okay", 380, 301, 65, 24},
|
||||
{IDB_READ, "Open in SimpleText...", 210, 301, 160, 24},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* SUNKEN FIELDS
|
||||
*******************************************************************************/
|
||||
|
@ -270,6 +339,15 @@ void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value
|
|||
*
|
||||
* This paints the two columns of testing statistics on the test minitor window.
|
||||
*******************************************************************************/
|
||||
char *FindErrorString(long error) {
|
||||
char *errStr = 0;
|
||||
for (int i = 0; errorTypeList[i].str; i++) {
|
||||
errStr = errorTypeList[i].str;
|
||||
if (errorTypeList[i].code == error) break;
|
||||
}
|
||||
return errStr;
|
||||
}
|
||||
|
||||
void PaintTestStatistics(bool Active) {
|
||||
char szString[40];
|
||||
// assemble and paint the sector testing range
|
||||
|
@ -292,12 +370,7 @@ void PaintTestStatistics(bool Active) {
|
|||
PaintCenteredString(76, 155, 126, 14, szString, Active);
|
||||
|
||||
// show the LastError
|
||||
char *errStr = 0;
|
||||
for (int i = 0; errorTypeList[i].str; i++) {
|
||||
errStr = errorTypeList[i].str;
|
||||
if (errorTypeList[i].code == LastError) break;
|
||||
}
|
||||
PaintCenteredString(76, 172, 126, 14, errStr, Active);
|
||||
PaintCenteredString(76, 172, 126, 14, FindErrorString(LastError), Active);
|
||||
|
||||
// show the elapsed time
|
||||
CvrtSecondsToHMSstring(szString, SecondsElapsed);
|
||||
|
@ -369,7 +442,10 @@ void TestMonitorWndProc() {
|
|||
PaintTextArray(TestGrayText, GRAY_COLOR);
|
||||
PaintTestPhase();
|
||||
|
||||
// TODO: paint the little speaker icon
|
||||
// paint the little speaker icon
|
||||
Rect theRect;
|
||||
SetRect(&theRect, 232, 191, 232+16, 191+16);
|
||||
PlotIconID(&theRect, atTopLeft, 0, 129);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -436,5 +512,7 @@ void AllowProgramExit() {
|
|||
*******************************************************************************/
|
||||
|
||||
void ErrorSound() {
|
||||
SysBeep(10);
|
||||
if(SendMessage(hSoundCheckbox, BM_GETCHECK) == BST_CHECKED) {
|
||||
SysBeep(10);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
#include <stdlib.h>
|
||||
#include "ctype.h"
|
||||
|
||||
extern WindowPtr tipWindow;
|
||||
|
||||
void run_tip();
|
||||
|
||||
typedef enum TipPage {
|
||||
INTRO_PAGE,
|
||||
PERFORM_TEST_PAGE,
|
||||
EXPLAIN_RESULTS,
|
||||
} TipPage;
|
||||
|
||||
#define MINIMUM_JAZ_SPARES 500
|
||||
#define MAXIMUM_JAZ_SPARES 2557
|
||||
#define MINIMUM_ZIP_SPARES 50
|
||||
#define MAXIMUM_ZIP_SPARES 126
|
||||
|
||||
extern TipPage CurrentPage;
|
||||
extern long CurrentDevice;
|
||||
extern long DriveCount;
|
||||
extern long JazDrive; // true if the current drive
|
||||
|
@ -16,6 +24,7 @@ extern long CartridgeStatus;
|
|||
extern long LastLBAOnCartridge;
|
||||
extern uint32_t StartingInstant;
|
||||
extern long NumberOfLBAs;
|
||||
extern long AdapterMaxSectors;
|
||||
extern long Side_0_SparesCount; // JAZ has only one count
|
||||
extern long Side_1_SparesCount; // ZIP has counts for both sides
|
||||
extern long Initial_Side_0_Spares;
|
||||
|
@ -74,6 +83,8 @@ enum {
|
|||
#define WM_COMMAND 2
|
||||
#define SW_SHOW 1
|
||||
#define SW_HIDE 2
|
||||
#define BM_GETCHECK 1
|
||||
#define BST_CHECKED 1
|
||||
|
||||
void SetRGBColor(long color, RGBColor *rgbColor);
|
||||
void SetColor(long color);
|
||||
|
@ -91,6 +102,7 @@ void SetWindowText(int id, const char *str);
|
|||
void EnableWindow(int id, bool enabled);
|
||||
void ShowWindow(ControlHandle hCntl, int state);
|
||||
void ShowWindow(int id, int state);
|
||||
long SendMessage(int id, int msg);
|
||||
void InvalidateRect(int id);
|
||||
void Rectangle(int left, int top, int right, int bottom);
|
||||
void DrawEdge(Rect *qrc, int edge, int grfFlags);
|
||||
|
@ -99,6 +111,8 @@ void StopApplicationTimer();
|
|||
void PostQuitMessage();
|
||||
unsigned long GetSystemTime();
|
||||
bool PrepareDC(int which);
|
||||
void SplashTheBitmap();
|
||||
void Paint3DHeadline();
|
||||
|
||||
#define GetDC(h) {GrafPtr oldPort; \
|
||||
GetPort(&oldPort); \
|
||||
|
@ -141,6 +155,9 @@ enum {
|
|||
/*******************************************************************************
|
||||
* STRINGS
|
||||
*******************************************************************************/
|
||||
extern const char *szIntroTitle;
|
||||
extern const char *szIntroSubTitle;
|
||||
extern const char *szIntroText;
|
||||
|
||||
extern const char *szWindowTitle;
|
||||
extern const char *szCopyright_1;
|
||||
|
@ -221,15 +238,18 @@ extern const char *szQuit;
|
|||
#define IDB_EXPL 0xFF04
|
||||
#define IDB_OKAY 0xFF05
|
||||
#define IDB_READ 0xFF06
|
||||
#define IDB_BEEP 0xFF07
|
||||
|
||||
enum {
|
||||
hDefault,
|
||||
hMainWnd,
|
||||
hTestMonitor,
|
||||
hTestButton = IDB_TEST,
|
||||
hExitButton = IDB_QUIT,
|
||||
hTestButton = IDB_TEST,
|
||||
hExitButton = IDB_QUIT,
|
||||
hSoundCheckbox = IDB_BEEP,
|
||||
// Extras added by MLT
|
||||
hExplainWnd = IDB_EXPL
|
||||
hIntroWnd = 5,
|
||||
hExplainWnd = IDB_EXPL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -239,10 +259,13 @@ typedef struct {
|
|||
int y;
|
||||
int w;
|
||||
int h;
|
||||
int type;
|
||||
ControlHandle hndl;
|
||||
} BtnList;
|
||||
extern BtnList tipBtns[];
|
||||
|
||||
extern Rect CS_Stat, TP_Perc, SS_Jaz, SS_Sid0, TL_Sect, ES_Read, SE_Rect;
|
||||
|
||||
/*******************************************************************************
|
||||
* FUNCTION PROTOTYPES
|
||||
*******************************************************************************/
|
||||
|
@ -259,6 +282,8 @@ void PaintTheBarGraphs(bool Active);
|
|||
void PaintTestStatistics(bool Active);
|
||||
void CvrtSecondsToHMSstring(char *szString, long seconds);
|
||||
|
||||
char *FindErrorString(long error);
|
||||
|
||||
void UpdateCurrentSector();
|
||||
void UpdateRunTimeDisplay();
|
||||
void UpdateRunPhaseDisplay();
|
||||
|
@ -267,6 +292,7 @@ void AllowProgramExit();
|
|||
void ErrorSound();
|
||||
void ProcessPendingMessages();
|
||||
void WinMain(uint8_t *DrivesSkipped);
|
||||
void Paint3DHeadline(const char *pszText, int Xleft, int Ytop);
|
||||
void WndProc(long iMessage, uint16_t wParam);
|
||||
void TestMonitorWndProc();
|
||||
void ApplicationTimerProc();
|
||||
|
@ -274,12 +300,12 @@ void TestButtonClicked();
|
|||
|
||||
int GetDriveEntryOffset(short Device);
|
||||
void GetCommandDetails(char command, char &cmd_flags, char &cmd_length);
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen);
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t IoBufLen);
|
||||
long EnumerateIomegaDevices(uint8_t *DrivesSkipped);
|
||||
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen);
|
||||
long SetModePage(short Device, void *pBuffer);
|
||||
long SetModePage(short Device, void *pBuffer, short BufLen);
|
||||
void ModifyModePage(char *PageBuff, char eec, char retries);
|
||||
void SetErrorRecovery(bool Retries, bool ECC, bool Testing);
|
||||
long SetErrorRecovery(bool Retries, bool ECC, bool Testing);
|
||||
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen);
|
||||
long LockCurrentDrive();
|
||||
long UnlockCurrentDrive();
|
||||
|
@ -287,9 +313,9 @@ void UnlockAllMedia();
|
|||
long SpinUpIomegaCartridge(short Device);
|
||||
void EjectAllMedia();
|
||||
long GetSpareSectorCounts(char);
|
||||
uint8_t GetCartridgeStatus(long Device);
|
||||
uint8_t GetCartridgeStatus(long Device, uint8_t flags);
|
||||
void HandleDriveChanging();
|
||||
void SetCartridgeStatusToEAX(long eax);
|
||||
void SetCartridgeStatusToEAX(long eax, uint8_t flags);
|
||||
void EjectIomegaCartridge(int Device);
|
||||
long PerformRegionTransfer(short XferCmd, void *pBuffer);
|
||||
void TestTheDisk();
|
||||
|
|
|
@ -6,8 +6,28 @@
|
|||
#include "tip.h"
|
||||
|
||||
//#define DEMO
|
||||
|
||||
/* The original TIP seems to request more data than is supplied by
|
||||
* certain commands. While this appears to be allowed, it causes
|
||||
* SCSI phase errors to be reported. Setting NO_EXCESS_READS will
|
||||
* adjust the reads to to the max size before such errors occur.
|
||||
*/
|
||||
#define NO_EXCESS_READS
|
||||
|
||||
/* The original TIP will always try to enable Early Recovery. This
|
||||
* fails on certain Jaz drives. While the original TIP will then
|
||||
* retry without Early Recovery, this will cause many errors to be
|
||||
* reported. Enable SUPRESS_ER_ERRORS to prevent this from problem
|
||||
* from happening as frequently
|
||||
*/
|
||||
#define SUPRESS_ER_ERRORS
|
||||
|
||||
/* The original TIP will always try to read the defects list, but
|
||||
* not all drives support this, causing many errors to be shown.
|
||||
* Setting SUPPRESS_DEFECTS_ERROR will silence these errors.
|
||||
*/
|
||||
#define SUPPRESS_DEFECTS_ERROR
|
||||
|
||||
#define MAKE_LITTLE_ENDIAN(a) a // Don't do anything on 68000
|
||||
#define MAKE_BIG_ENDIAN(a) a // Don't do anything on 68000
|
||||
|
||||
|
@ -71,10 +91,10 @@ struct DEFECT_LIST_HEADER {
|
|||
|
||||
#define DRIVE_A_SUPPORT_BIAS 32 // reduce total by 32 for DRIVE A support
|
||||
|
||||
#define BYTES_PER_SECTOR 512
|
||||
#define MAX_SECTORS_PER_TEST 25
|
||||
#define BYTES_PER_SECTOR 512
|
||||
#define MAX_SECTORS_PER_TEST 128
|
||||
|
||||
#define BADNESS_THRESHOLD 10
|
||||
#define BADNESS_THRESHOLD 10
|
||||
|
||||
#define SS_ERR 0x00000004
|
||||
#define DEFECT_LIST_READ_ERROR 0x001c0003
|
||||
|
@ -89,12 +109,20 @@ struct DEFECT_LIST_HEADER {
|
|||
|
||||
#define CHECK_CONDITION 0x02
|
||||
|
||||
TipPage CurrentPage;
|
||||
long CurrentDevice = -1; // the device that's been recognized
|
||||
long DriveCount = 0;
|
||||
|
||||
long JazDrive = 0; // true if the current drive
|
||||
long CartridgeStatus = DISK_NOT_PRESENT;
|
||||
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
Boolean SupressEarlyRecovery = false;
|
||||
#endif
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
Boolean SupressDefectsError = false;
|
||||
#endif
|
||||
|
||||
unsigned long StartingInstant;
|
||||
|
||||
// ----------------------------- Run Time Variables ------------------------------
|
||||
|
@ -108,6 +136,7 @@ long TestingPhase = 0; // 0 = not testing, no data ...
|
|||
long PercentComplete;
|
||||
long FirstLBASector;
|
||||
long NumberOfLBAs;
|
||||
long AdapterMaxSectors;
|
||||
long LastLBAOnCartridge;
|
||||
long SecondsElapsed;
|
||||
long SoftErrors;
|
||||
|
@ -188,12 +217,14 @@ void GetCommandDetails(char command, char &cmd_flags, char &cmd_length) {
|
|||
* length to an IoBuffer for the command. It returns the complete
|
||||
* three-byte sense code from the command.
|
||||
*******************************************************************************/
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen) {
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t IoBufLen) {
|
||||
char cmd_length, cmd_flags, cmd_status;
|
||||
GetCommandDetails(lpCmdBlk[0], cmd_flags, cmd_length);
|
||||
// call the SCSI interface to forward the command to the device
|
||||
OSErr err = scsi_cmd(Device, lpCmdBlk, cmd_length, lpIoBuf, IoBufLen, 0, cmd_flags, &cmd_status);
|
||||
if(err != noErr) {
|
||||
// else, if it's *NOT* a "Sense Data" error (SS_ERR)
|
||||
LastError = err | 0x00FFFF00; // [00 FF FF er]
|
||||
return SS_ERR;
|
||||
}
|
||||
if(cmd_status == 0) {
|
||||
|
@ -207,15 +238,16 @@ long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen) {
|
|||
printf("SCSI CHECK CONDITION (KEY %x, ASC %x, ASCQ %x)\n", sense_data.key, sense_data.asc, sense_data.ascq);
|
||||
// okay, we have an SS_ERR condition, let's check the SENSE DATA
|
||||
// assemble [00 ASC ASCQ SenseKey]
|
||||
long res = (long(sense_data.asc) << 16) |
|
||||
(long(sense_data.ascq) << 8) |
|
||||
(long(sense_data.key) );
|
||||
const long res = (long(sense_data.asc) << 16) |
|
||||
(long(sense_data.ascq) << 8) |
|
||||
(long(sense_data.key) );
|
||||
if(res == MEDIA_CHANGE_CODE) {
|
||||
printf("Media change signalled. Most recent error can be ignored\n\n");
|
||||
int index = GetDriveEntryOffset(Device);
|
||||
DriveArray[index].flags |= MEDIA_CHANGED;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
// else, if it's *NOT* a "Sense Data" error (SS_ERR)
|
||||
|
@ -274,7 +306,7 @@ long EnumerateIomegaDevices(uint8_t *DrivesSkipped) {
|
|||
|
||||
// On the Mac, we want to ignore drives that have media in them at
|
||||
// program entry, as this means the volume is mounted in Mac OS
|
||||
const bool driveEmpty = GetCartridgeStatus(Device) == DISK_NOT_PRESENT;
|
||||
const bool driveEmpty = (GetCartridgeStatus(Device, flags) == DISK_NOT_PRESENT);
|
||||
if(driveEmpty) {
|
||||
DriveArray[DriveCount].flags = flags;
|
||||
DriveArray[DriveCount].scsi_id = Device;
|
||||
|
@ -308,13 +340,18 @@ long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen) {
|
|||
/*******************************************************************************
|
||||
* SET MODE PAGE
|
||||
*******************************************************************************/
|
||||
long SetModePage(short Device, void *pBuffer) {
|
||||
char* ebx = (char*) pBuffer; // get a pointer to the top of buffer
|
||||
char ecx = ebx[0] + 1; // adjust it up by one
|
||||
long SetModePage(short Device, void *pBuffer, short BufLen) {
|
||||
unsigned char* ebx = (unsigned char*) pBuffer; // get a pointer to the top of buffer
|
||||
unsigned char ecx = ebx[0] + 1; // adjust it up by one
|
||||
|
||||
ebx[0] = 0; // now clear the two reserved bytes
|
||||
ebx[2] = 0;
|
||||
|
||||
if(ecx != BufLen) {
|
||||
printf("Length error in SetModePage %d != %d\n\n", BufLen, (int) ecx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char Scsi[6] = {0}; // init the SCSI parameter block
|
||||
Scsi[0] = SCSI_Cmd_ModeSelect; // set the command
|
||||
Scsi[1] = 0x10; // set the Page Format bit
|
||||
|
@ -339,16 +376,21 @@ void ModifyModePage(char *PageBuff, char ecc, char retries) {
|
|||
ebx[8] = retries; // then set the write count too
|
||||
}
|
||||
|
||||
void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
long SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
char PageBuff[40];
|
||||
|
||||
#ifdef NO_EXCESS_READS
|
||||
// Limit reads to 20 bytes on Zip to prevent controller errors
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, JazDrive ? sizeof(PageBuff) : 20);
|
||||
// Limit reads to 20 bytes on Zip (24 bytes on Jaz) to prevent controller errors
|
||||
const short pageBuffLen = JazDrive ? 24 : 20;
|
||||
#else
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
|
||||
const short pageBuffLen = sizeof(PageBuff);
|
||||
#endif
|
||||
|
||||
long eax = GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
|
||||
if(eax) {
|
||||
printf("SetErrorRecovery failed\n");
|
||||
return eax;
|
||||
}
|
||||
|
||||
#define EARLY_RECOVERY 0x08
|
||||
#define PER 0x04
|
||||
#define SUPPRESS_ECC 0x01
|
||||
|
@ -356,6 +398,9 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
|||
// set the ECC fields
|
||||
char ecc = SUPPRESS_ECC; // presume ECC suppression
|
||||
if(ECC) {
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
if(!SupressEarlyRecovery)
|
||||
#endif
|
||||
ecc = EARLY_RECOVERY; // enable ECC and Early Recovery
|
||||
if(Testing) {
|
||||
ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER
|
||||
|
@ -370,14 +415,22 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
|||
retries = 0;
|
||||
|
||||
ModifyModePage(PageBuff, ecc, retries);
|
||||
const long eax = SetModePage(CurrentDevice, PageBuff);
|
||||
|
||||
eax = SetModePage(CurrentDevice, PageBuff, pageBuffLen);
|
||||
// if we had an invalid field in the CDB (the EER bit was on)
|
||||
if (eax == 0x00260005) {
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
|
||||
ecc &= ~0x08; // same, *BUT*NOT* Early Recovery
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
|
||||
ecc &= ~EARLY_RECOVERY; // same, *BUT*NOT* Early Recovery
|
||||
ModifyModePage(PageBuff, ecc, retries);
|
||||
SetModePage(CurrentDevice, PageBuff);
|
||||
eax = SetModePage(CurrentDevice, PageBuff, pageBuffLen);
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
if(!eax) {
|
||||
printf(" Early recovery not supported on this drive. Ignoring.\n\n");
|
||||
SupressEarlyRecovery = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return eax;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -464,7 +517,18 @@ long GetSpareSectorCounts(char checkPassword) {
|
|||
Scsi[0] = SCSI_Cmd_ReadDefectData;
|
||||
Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits
|
||||
Scsi[8] = 4; // ask for only FOUR bytes
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
if(SupressDefectsError)
|
||||
eax = INCOMPATIBLE_MEDIA;
|
||||
else
|
||||
#endif
|
||||
eax = SCSICommand(CurrentDevice, Scsi, &DefectHeader, sizeof(DefectHeader));
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
if(!SupressDefectsError && eax == INCOMPATIBLE_MEDIA) {
|
||||
printf("Defects list not supported on this drive. Ignoring.\n\n");
|
||||
SupressDefectsError = true;
|
||||
}
|
||||
#endif
|
||||
if ((!eax) || (eax == INCOMPATIBLE_MEDIA)) {
|
||||
// we could read its defect list ... so show it!
|
||||
// --------------------------------------------------------------------------
|
||||
|
@ -570,10 +634,11 @@ Rescan:
|
|||
do {
|
||||
// clear media changed status
|
||||
DriveArray[i].flags &= ~MEDIA_CHANGED;
|
||||
GetCartridgeStatus(scsi_id);
|
||||
GetCartridgeStatus(scsi_id, DriveArray[i].flags);
|
||||
} while(DriveArray[i].flags & MEDIA_CHANGED); // do it until NO media change!
|
||||
//--------------------------------------------------------------------------
|
||||
status = GetCartridgeStatus(scsi_id);
|
||||
status = GetCartridgeStatus(scsi_id, DriveArray[i].flags);
|
||||
if (status == DISK_STATUS_UNKNOWN) continue; // added by MLT
|
||||
// if the device we have is NOT the currently selected one
|
||||
if(scsi_id != CurrentDevice) {
|
||||
// if the disk is ANYTHING other than not present ...
|
||||
|
@ -589,6 +654,7 @@ Rescan:
|
|||
// then set the current drive ...
|
||||
else if ((DriveArray[i].flags & DISK_EJECTING) == 0) {
|
||||
CurrentDevice = scsi_id;
|
||||
printf("Selected SCSI ID %ld\n", CurrentDevice);
|
||||
TestingPhase = 0;
|
||||
Selecting = true;
|
||||
//goto Rescan;
|
||||
|
@ -604,13 +670,13 @@ Rescan:
|
|||
// it is *NOT* empty! If it *IS* empty, kill current
|
||||
if(status == DISK_NOT_PRESENT) {
|
||||
CurrentDevice = -1;
|
||||
SetCartridgeStatusToEAX(status);
|
||||
SetCartridgeStatusToEAX(status, DriveArray[i].flags);
|
||||
}
|
||||
// if it's not already set correctly *and* either
|
||||
// the cart status is one of the pre-test ones, or
|
||||
// the NEW status from the cart is NOT "at speed" ...
|
||||
if((status != CartridgeStatus) && ((CartridgeStatus <= DISK_STALLED) || (status != DISK_AT_SPEED))) {
|
||||
SetCartridgeStatusToEAX(status);
|
||||
SetCartridgeStatusToEAX(status, DriveArray[i].flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -618,18 +684,18 @@ Rescan:
|
|||
if ((CurrentDevice == -1) &&
|
||||
(status == DISK_NOT_PRESENT) &&
|
||||
(CartridgeStatus != DISK_NOT_PRESENT)) {
|
||||
SetCartridgeStatusToEAX(status);
|
||||
SetCartridgeStatusToEAX(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GET CARTRIDGE STATUS
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t GetCartridgeStatus(long Device) {
|
||||
uint8_t GetCartridgeStatus(long Device, uint8_t flags) {
|
||||
long eax;
|
||||
char DiskStat[72];
|
||||
#ifdef NO_EXCESS_READS
|
||||
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, JazDrive ? sizeof(DiskStat) : 63);
|
||||
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, 4);
|
||||
if (eax) return DISK_STATUS_UNKNOWN;
|
||||
#else
|
||||
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat));
|
||||
|
@ -646,7 +712,9 @@ uint8_t GetCartridgeStatus(long Device) {
|
|||
// SetCartridgeStatusToEAX
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SetCartridgeStatusToEAX(long eax) {
|
||||
void SetCartridgeStatusToEAX(long eax, uint8_t flags) {
|
||||
JazDrive = flags & JAZ_DRIVE;
|
||||
|
||||
long PriorStatus = CartridgeStatus;
|
||||
CartridgeStatus = eax;
|
||||
|
||||
|
@ -666,6 +734,7 @@ void SetCartridgeStatusToEAX(long eax) {
|
|||
SetRichEditText(szNotRunning);
|
||||
goto DisableActions;
|
||||
case DISK_AT_SPEED:
|
||||
printf("Disk at speed\n");
|
||||
eax = GetSpareSectorCounts(true); // update the Cart Condition
|
||||
if(eax == MEDIA_NOT_PRESENT) {
|
||||
goto DisableActions;
|
||||
|
@ -678,10 +747,14 @@ void SetCartridgeStatusToEAX(long eax) {
|
|||
FirmErrors = 0;
|
||||
// check to see if we have enough spares to start
|
||||
if(JazDrive) {
|
||||
printf("Spare Sectors: %ld/%d\n", Side_0_SparesCount, MAXIMUM_JAZ_SPARES);
|
||||
if(Side_0_SparesCount < MINIMUM_JAZ_SPARES)
|
||||
goto InsufficientSpares;
|
||||
}
|
||||
else {
|
||||
printf("Spare Sectors:\n");
|
||||
printf(" Side 1: %ld/%d\n", Side_0_SparesCount, MAXIMUM_ZIP_SPARES);
|
||||
printf(" Side 2: %ld/%d\n", Side_1_SparesCount, MAXIMUM_ZIP_SPARES);
|
||||
if(Side_0_SparesCount < MINIMUM_ZIP_SPARES) {
|
||||
goto InsufficientSpares;
|
||||
}
|
||||
|
@ -753,6 +826,12 @@ void PrepareToBeginTesting() {
|
|||
HardErrors = 0;
|
||||
UserInterrupt = 0;
|
||||
LastError = 0;
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
SupressEarlyRecovery = false;
|
||||
#endif
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
SupressDefectsError = false;
|
||||
#endif
|
||||
#ifdef DEMO
|
||||
LastLBAOnCartridge = 99999;
|
||||
SoftErrors = 6;
|
||||
|
@ -782,7 +861,7 @@ void BumpErrorCounts(long ErrorCode) {
|
|||
LastError = eax;
|
||||
if (eax == 0x320003 || eax == 0x328F03)
|
||||
CartridgeStatus = DISK_LOW_SPARES;
|
||||
if (eax & 0xFF == 1) // recovered error
|
||||
if ((eax & 0xFF) == 1) // recovered error
|
||||
SoftErrors++;
|
||||
else
|
||||
HardErrors++;
|
||||
|
@ -812,12 +891,12 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
char Scsi[10] = {0}; // clear out the SCSI CDB
|
||||
const long InitialHardErrors = HardErrors;
|
||||
|
||||
SetErrorRecovery(false, false, true); // disable Retries & ECC
|
||||
long eax = SetErrorRecovery(false, false, true); // disable Retries & ECC
|
||||
|
||||
Scsi[0] = XferCmd;
|
||||
SET_DWORD_AT(Scsi, 2, MAKE_BIG_ENDIAN(FirstLBASector)); // WHICH LBA's to read, BIG endian
|
||||
SET_WORD_AT (Scsi, 7, MAKE_BIG_ENDIAN(NumberOfLBAs)); // HOW MANY to read, BIG endian
|
||||
long eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
|
||||
eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
|
||||
// if we failed somewhere during our transfer ... let's zero in on it
|
||||
if (eax) {
|
||||
if ( eax == SS_ERR || // if it's a CONTROLLER ERROR, skip!
|
||||
|
@ -826,6 +905,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
printf("Starting detailed search...\n");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Save error and current Soft + Hard Error count to see if we do FIND the glitch ...
|
||||
const long GlitchError = eax; // save the error which stopped us!
|
||||
|
@ -855,6 +936,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
|
||||
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
|
||||
|
||||
printf(" Found error, retesting with retries\n");
|
||||
SetErrorRecovery(true, false, true); // enable retries
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
if (eax) {
|
||||
|
@ -862,7 +944,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
|
||||
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
|
||||
|
||||
SetErrorRecovery(true, true, true); // enable retries AND EEC
|
||||
printf(" Found error, retesting with retries & ECC\n");
|
||||
eax = SetErrorRecovery(true, true, true); // enable retries AND EEC
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
if (eax) {
|
||||
// failed with retries and EEC
|
||||
|
@ -880,6 +963,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
}
|
||||
|
||||
PostTheError:
|
||||
printf(" %s (Sector %ld)\n", FindErrorString(eax), SingleTransferLBA);
|
||||
printf("--------------------------------------------\n");
|
||||
BumpErrorCounts(eax); // given eax, count the errors
|
||||
GetSpareSectorCounts(false); // update the Cart's Condition
|
||||
UpdateRunTimeDisplay();
|
||||
|
@ -889,6 +974,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
ProcessPendingMessages();
|
||||
}
|
||||
|
||||
printf("... detailed search finished\n");
|
||||
// now see whether we *did* found something to complain about ...
|
||||
eax = SoftErrors + HardErrors;
|
||||
if (eax == GlitchCount) {
|
||||
|
@ -899,6 +985,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
long ebx = eax & 0x00FF00FF; // strip the ASCQ byte
|
||||
if(ebx == 0x00110003) // if we're about to say "unrecovered read"
|
||||
eax = 0x170101; // change it to: "Read with Retries"
|
||||
printf("%s\n", FindErrorString(eax));
|
||||
BumpErrorCounts(eax); // given eax, count the errors
|
||||
HardErrors = SavedHardErrors; // restore the counts
|
||||
SoftErrors = SavedSoftErrors;
|
||||
|
@ -909,6 +996,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
|||
eax = 0; // now let's return happiness to our caller
|
||||
if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors!
|
||||
eax = -1;
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
@ -921,14 +1009,25 @@ Exit:
|
|||
*******************************************************************************/
|
||||
|
||||
void TestTheDisk() {
|
||||
void *pPatternBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
void *pUserDataBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
// setup the initital maximum tranfer ...
|
||||
AdapterMaxSectors = MAX_SECTORS_PER_TEST; // limit to our max
|
||||
|
||||
if(pPatternBuffer == NULL || pUserDataBuffer == NULL) {
|
||||
printf("Allocation error\n");
|
||||
return;
|
||||
void *pDataBuffer = 0;
|
||||
for(;;) {
|
||||
pDataBuffer = malloc(AdapterMaxSectors * BYTES_PER_SECTOR * 2);
|
||||
if(pDataBuffer) break;
|
||||
AdapterMaxSectors >>= 2; // we need to make it smaller
|
||||
if(AdapterMaxSectors == 0) {
|
||||
printf("Test buffer allocation failed!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Allocated buffer of %ld bytes\n", AdapterMaxSectors * BYTES_PER_SECTOR);
|
||||
|
||||
void *pPatternBuffer = pDataBuffer;
|
||||
void *pUserDataBuffer = (char*) pDataBuffer + AdapterMaxSectors * BYTES_PER_SECTOR;
|
||||
|
||||
StopApplicationTimer();
|
||||
|
||||
PreventProgramExit();
|
||||
|
@ -939,17 +1038,17 @@ void TestTheDisk() {
|
|||
InvalidateRect(hTestMonitor);
|
||||
|
||||
LockCurrentDrive(); // prevent media removal
|
||||
|
||||
GetSpareSectorCounts(false); // update the Cart's Condition
|
||||
UpdateRunTimeDisplay();
|
||||
|
||||
// Standard Testing Operation
|
||||
StartingInstant = GetSystemTime();
|
||||
long eax;
|
||||
|
||||
do {
|
||||
ProcessPendingMessages();
|
||||
|
||||
NumberOfLBAs = MAX_SECTORS_PER_TEST;
|
||||
NumberOfLBAs = AdapterMaxSectors;
|
||||
|
||||
if(LastLBAOnCartridge) {
|
||||
if (FirstLBASector + NumberOfLBAs > LastLBAOnCartridge + 1) {
|
||||
|
@ -966,7 +1065,7 @@ void TestTheDisk() {
|
|||
|
||||
// get a random pattern of data to write
|
||||
const long DataPattern = rand();
|
||||
memset(pPatternBuffer, DataPattern, MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
memset(pPatternBuffer, DataPattern, AdapterMaxSectors * BYTES_PER_SECTOR);
|
||||
|
||||
// update the cartridge's status
|
||||
GetSpareSectorCounts(false); // update the Cart's Condition
|
||||
|
@ -975,7 +1074,7 @@ void TestTheDisk() {
|
|||
|
||||
UpdateRunTimeDisplay();
|
||||
|
||||
long eax = PerformRegionTransfer(SCSI_Cmd_ReadMany, pUserDataBuffer);
|
||||
eax = PerformRegionTransfer(SCSI_Cmd_ReadMany, pUserDataBuffer);
|
||||
|
||||
if(eax == 0) {
|
||||
// -------------------------------
|
||||
|
@ -995,6 +1094,10 @@ void TestTheDisk() {
|
|||
// if we hit the end of the disk ... exit gracefully!
|
||||
goto GetOut;
|
||||
}
|
||||
else if (eax == SS_ERR) {
|
||||
// added by MLT, exit on controller errors
|
||||
goto GetOut;
|
||||
}
|
||||
if (CartridgeStatus != DISK_TEST_UNDERWAY) {
|
||||
break;
|
||||
}
|
||||
|
@ -1004,8 +1107,7 @@ void TestTheDisk() {
|
|||
// show that we're post-test
|
||||
|
||||
GetOut:
|
||||
free(pPatternBuffer);
|
||||
free(pUserDataBuffer);
|
||||
free(pDataBuffer);
|
||||
|
||||
TestingPhase = UNTESTED;
|
||||
UnlockAllMedia();
|
||||
|
@ -1015,24 +1117,24 @@ GetOut:
|
|||
AllowProgramExit();
|
||||
|
||||
// compute the number of serious troubles
|
||||
const char *eax;
|
||||
const char *result;
|
||||
long errors = FirmErrors + HardErrors;
|
||||
if (errors >= BADNESS_THRESHOLD) {
|
||||
eax = szBadResult;
|
||||
result = szBadResult;
|
||||
}
|
||||
else if (UserInterrupt) {
|
||||
eax = szInterrupted;
|
||||
else if (UserInterrupt || (eax == SS_ERR)) {
|
||||
result = szInterrupted;
|
||||
}
|
||||
else {
|
||||
// it wasn't interrupted, nor seriously bad, was it perfect?
|
||||
errors += SoftErrors;
|
||||
if(errors) {
|
||||
eax = szExplainResult;
|
||||
result = szExplainResult;
|
||||
} else {
|
||||
eax = szPerfectResult;
|
||||
result = szPerfectResult;
|
||||
}
|
||||
}
|
||||
SetRichEditText(eax);
|
||||
SetRichEditText(result);
|
||||
InvalidateRect(hTestMonitor);
|
||||
Exit:
|
||||
StartApplicationTimer();
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#include <ctype.h>
|
||||
#include <SIOUX.h>
|
||||
|
||||
#include <Menus.h>
|
||||
#include <Windows.h>
|
||||
#include <Quickdraw.h>
|
||||
|
||||
#include "TrapAvail.h"
|
||||
#include "pstring.h"
|
||||
#include "LaunchLib.h"
|
||||
#include "mac_vol.h"
|
||||
|
@ -15,17 +17,13 @@
|
|||
#include "tip.h"
|
||||
#include "command_line.h"
|
||||
|
||||
enum TipPage {
|
||||
kTestingPage,
|
||||
kExplainPage,
|
||||
} page;
|
||||
|
||||
static int gDone;
|
||||
static bool allowColor;
|
||||
static bool inited = false;
|
||||
static bool timerEnabled = false;
|
||||
static WindowPtr tipWindow;
|
||||
static MenuHandle tipMenu;
|
||||
static PicHandle tipIntroPic;
|
||||
static TBHandle richText;
|
||||
static const char *textFileName;
|
||||
|
||||
|
@ -34,13 +32,14 @@ void DisposeTipWindow();
|
|||
void AddTipMenus();
|
||||
void RunCommandLine();
|
||||
void DoEvent(EventRecord &event, RgnHandle *cursorRgn);
|
||||
void DoMenuEvent(EventRecord &event);
|
||||
void DoMenuEventPostSIOUX(EventRecord &event);
|
||||
bool DoMenuSelection(long choice);
|
||||
void DoUpdate(WindowPtr window);
|
||||
void DoMouseDown(EventRecord &event);
|
||||
void DoMouseMove(EventRecord &event, RgnHandle *cursorRegion);
|
||||
void DoDiskEvent(EventRecord &event);
|
||||
void SetPage(TipPage page);
|
||||
ControlHandle FindControl(int id);
|
||||
ControlHandle FindCntlHandle(int id);
|
||||
OSErr GetExplanationFSSpec(const char *name, FSSpec *docSpec);
|
||||
void OpenExplanationInSimpleText();
|
||||
|
||||
|
@ -55,15 +54,13 @@ void run_tip() {
|
|||
|
||||
NewTipWindow();
|
||||
EnableWindow(hTestButton, false);
|
||||
SetRichEditText(szInstructions);
|
||||
|
||||
gDone = false;
|
||||
do {
|
||||
EventRecord event;
|
||||
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), cursorRgn)) {
|
||||
DoEvent(event, &cursorRgn);
|
||||
if(!inited && page == kTestingPage) {
|
||||
printf("Starting tip\n");
|
||||
if(!inited && CurrentPage == PERFORM_TEST_PAGE) {
|
||||
// Start TIP as soon as the user dismisses the intro screen
|
||||
inited = true;
|
||||
uint8_t drivesSkipped;
|
||||
|
@ -88,6 +85,9 @@ void run_tip() {
|
|||
|
||||
DisposeTipWindow();
|
||||
DisposeRgn(cursorRgn);
|
||||
|
||||
// Remount any drives we may have unmounted
|
||||
mac_mount_drives();
|
||||
}
|
||||
|
||||
void NewTipWindow() {
|
||||
|
@ -128,10 +128,12 @@ void NewTipWindow() {
|
|||
tipBtns[i].y + tipBtns[i].h - mainWndOrigin.v
|
||||
);
|
||||
StrToPascal(title, tipBtns[i].name);
|
||||
tipBtns[i].hndl = NewControl(tipWindow, &rect, title, false, 0, 0, 0, 0, tipBtns[i].id);
|
||||
tipBtns[i].hndl = NewControl(tipWindow, &rect, title, false, 0, 0, 1, tipBtns[i].type, tipBtns[i].id);
|
||||
}
|
||||
|
||||
page = kExplainPage;
|
||||
SetControlValue(FindCntlHandle(IDB_BEEP),1); // Check the sound control
|
||||
|
||||
CurrentPage = EXPLAIN_RESULTS;
|
||||
GetDC(hExplainWnd);
|
||||
|
||||
// Create the text edit widget
|
||||
|
@ -140,10 +142,20 @@ void NewTipWindow() {
|
|||
|
||||
ReleaseDC(hExplainWnd);
|
||||
|
||||
SetPage(kTestingPage);
|
||||
// Load the About box picture
|
||||
tipIntroPic = GetPicture(128);
|
||||
|
||||
SetPage(INTRO_PAGE);
|
||||
}
|
||||
|
||||
void AddTipMenus() {
|
||||
if(!TrapAvailable(0xAA66)) {
|
||||
// If MenuChoice is available, we can let SIOUX handle the menus,
|
||||
// otherwise we have to handle it ourselves
|
||||
SIOUXSettings.setupmenus = FALSE;
|
||||
}
|
||||
|
||||
// Add our menu
|
||||
tipMenu = GetMenu(128);
|
||||
InsertMenu(tipMenu, 0);
|
||||
DrawMenuBar();
|
||||
|
@ -166,7 +178,7 @@ void DisposeTipWindow() {
|
|||
DisposeWindow(tipWindow);
|
||||
}
|
||||
|
||||
ControlHandle FindControl(int id) {
|
||||
ControlHandle FindCntlHandle(int id) {
|
||||
for(int i = 0; tipBtns[i].name; i++) {
|
||||
if (tipBtns[i].id == id)
|
||||
return tipBtns[i].hndl;
|
||||
|
@ -177,11 +189,14 @@ ControlHandle FindControl(int id) {
|
|||
bool PrepareDC(int which) {
|
||||
SetPort(tipWindow);
|
||||
switch(which) {
|
||||
case hIntroWnd:
|
||||
if(CurrentPage != INTRO_PAGE) return false;
|
||||
break;
|
||||
case hExplainWnd:
|
||||
if(page != kExplainPage) return false;
|
||||
if(CurrentPage != EXPLAIN_RESULTS) return false;
|
||||
break;
|
||||
case hTestMonitor:
|
||||
if(page != kTestingPage) return false;
|
||||
if(CurrentPage != PERFORM_TEST_PAGE) return false;
|
||||
SetOrigin(-20, -10);
|
||||
break;
|
||||
case hMainWnd:
|
||||
|
@ -204,36 +219,54 @@ void DoEvent(EventRecord &event, RgnHandle *cursorRgn) {
|
|||
case osEvt: DoMouseMove(event, cursorRgn); break;
|
||||
}
|
||||
} else { // Trap unhandled SIOUX menu events
|
||||
DoMenuEvent(event);
|
||||
DoMenuEventPostSIOUX(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DoMenuEvent(EventRecord &event) {
|
||||
// SIOUX will handle the menu event, but we can check after the fact
|
||||
// to see whether the user selected one of our menus
|
||||
void DoMenuEventPostSIOUX(EventRecord &event) {
|
||||
if(!SIOUXSettings.setupmenus) return;
|
||||
|
||||
/* If MenuChoice is available, it is best to let SIOUX handle the menu
|
||||
* event so Copy and Paste will work. We can check after the fact
|
||||
* to see whether the user selected one of our menus using MenuChoice.
|
||||
* However, if that trap is not available, we must handle the menu
|
||||
* ourselves and certain menu items will not work
|
||||
*/
|
||||
|
||||
WindowPtr thisWindow;
|
||||
if(event.what == mouseDown && FindWindow(event.where, &thisWindow) == inMenuBar) {
|
||||
long int choice = MenuChoice();
|
||||
int menuId = HiWord(choice);
|
||||
int itemId = LoWord(choice);
|
||||
switch(menuId) {
|
||||
case 32000: // Apple menu
|
||||
SysBeep(10);
|
||||
break;
|
||||
case 32001: // File menu
|
||||
if (itemId == 9) {
|
||||
WndProc(WM_COMMAND, IDB_QUIT);
|
||||
}
|
||||
break;
|
||||
case 32002: // Edit menu
|
||||
case 128: // TIP menu
|
||||
switch(itemId) {
|
||||
case 1: HiliteMenu(0); RunCommandLine(); break;
|
||||
}
|
||||
}
|
||||
if((event.what == mouseDown) && (FindWindow(event.where, &thisWindow) == inMenuBar)) {
|
||||
DoMenuSelection(MenuChoice());
|
||||
}
|
||||
}
|
||||
|
||||
bool DoMenuSelection(long choice) {
|
||||
bool handled = false;
|
||||
int menuId = HiWord(choice);
|
||||
int itemId = LoWord(choice);
|
||||
//printf("Menu choice: %d, %d\n", menuId, itemId);
|
||||
switch(menuId) {
|
||||
case 32000: // Apple menu SysBeep(10);
|
||||
break;
|
||||
case 32001: // File menu
|
||||
if (itemId == 9) { // Quit
|
||||
WndProc(WM_COMMAND, IDB_QUIT);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case 32002: // Edit menu
|
||||
break;
|
||||
case 128: // TIP menu
|
||||
switch(itemId) {
|
||||
case 1: // Run Command Line...
|
||||
HiliteMenu(0);
|
||||
RunCommandLine();
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
HiliteMenu(0);
|
||||
return handled;
|
||||
}
|
||||
|
||||
void DoUpdate(WindowPtr window) {
|
||||
|
@ -257,6 +290,7 @@ void DoUpdate(WindowPtr window) {
|
|||
DrawEdge(&(*richText)->frame, BDR_SUNKENOUTER, BF_RECT);
|
||||
ReleaseDC(hExplainWnd);
|
||||
|
||||
SetColor(BLACK_COLOR);
|
||||
UpdateControls(window, window->visRgn);
|
||||
|
||||
EndUpdate(window);
|
||||
|
@ -280,22 +314,32 @@ void DoMouseDown(EventRecord &event) {
|
|||
GetPort(&oldPort);
|
||||
SetPort(thisWindow);
|
||||
GlobalToLocal(&mouse);
|
||||
const bool hitButton = (!TBMouseDown(richText, mouse, thisWindow)) &&
|
||||
(FindControl(mouse, thisWindow, &thisControl) == inButton) &&
|
||||
(TrackControl(thisControl, mouse, 0) == inButton);
|
||||
int part;
|
||||
const bool hitCntl = (!TBMouseDown(richText, mouse, thisWindow)) &&
|
||||
(FindControl(mouse, thisWindow, &thisControl)) &&
|
||||
(part = TrackControl(thisControl, mouse, 0));
|
||||
SetPort(oldPort);
|
||||
if(hitButton) {
|
||||
if(hitCntl && (part == inButton) || (part == inCheckBox)) {
|
||||
int id = GetControlReference(thisControl);
|
||||
switch(id) {
|
||||
case IDB_OKAY:
|
||||
SetPage(kTestingPage);
|
||||
SetPage(PERFORM_TEST_PAGE);
|
||||
break;
|
||||
case IDB_EXPL:
|
||||
SetPage(kExplainPage);
|
||||
SetPage(EXPLAIN_RESULTS);
|
||||
break;
|
||||
case IDB_NEXT:
|
||||
SetRichEditText(szInstructions);
|
||||
break;
|
||||
case IDB_READ:
|
||||
OpenExplanationInSimpleText();
|
||||
break;
|
||||
case IDB_BEEP:
|
||||
SetPort(thisWindow);
|
||||
SetControlValue(thisControl, 1 - GetControlValue(thisControl));
|
||||
SetPort(oldPort);
|
||||
printf("Value: %d\n", GetControlValue(thisControl));
|
||||
break;
|
||||
default:
|
||||
WndProc(WM_COMMAND, id);
|
||||
break;
|
||||
|
@ -311,6 +355,14 @@ void DoMouseDown(EventRecord &event) {
|
|||
gDone = true;
|
||||
}
|
||||
break;
|
||||
case inMenuBar:
|
||||
if(!DoMenuSelection(MenuSelect(event.where))) {
|
||||
SysBeep(10);
|
||||
}
|
||||
break;
|
||||
case inDrag:
|
||||
DragWindow(thisWindow, event.where, &(*GetGrayRgn())->rgnBBox);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,10 +410,21 @@ void StrToPascal(Str255 pStr, const char *str) {
|
|||
}
|
||||
|
||||
void SetPage(TipPage newPage) {
|
||||
if(page == newPage) return;
|
||||
page = newPage;
|
||||
switch(page) {
|
||||
case kTestingPage:
|
||||
if(CurrentPage == newPage) return;
|
||||
CurrentPage = newPage;
|
||||
switch(CurrentPage) {
|
||||
case INTRO_PAGE:
|
||||
ShowWindow(IDB_TEST, SW_HIDE);
|
||||
ShowWindow(IDB_BACK, SW_HIDE);
|
||||
ShowWindow(IDB_EXPL, SW_HIDE);
|
||||
ShowWindow(IDB_BEEP, SW_HIDE);
|
||||
ShowWindow(IDB_OKAY, SW_HIDE);
|
||||
ShowWindow(IDB_READ, SW_HIDE);
|
||||
ShowWindow((*richText)->scroll, SW_HIDE);
|
||||
ShowWindow(IDB_QUIT, SW_SHOW);
|
||||
ShowWindow(IDB_NEXT, SW_SHOW);
|
||||
break;
|
||||
case PERFORM_TEST_PAGE:
|
||||
ShowWindow((*richText)->scroll, SW_HIDE);
|
||||
ShowWindow(IDB_BACK, SW_HIDE);
|
||||
ShowWindow(IDB_NEXT, SW_HIDE);
|
||||
|
@ -370,13 +433,15 @@ void SetPage(TipPage newPage) {
|
|||
ShowWindow(IDB_TEST, SW_SHOW);
|
||||
ShowWindow(IDB_EXPL, SW_SHOW);
|
||||
ShowWindow(IDB_QUIT, SW_SHOW);
|
||||
ShowWindow(IDB_BEEP, SW_SHOW);
|
||||
break;
|
||||
case kExplainPage:
|
||||
case EXPLAIN_RESULTS:
|
||||
ShowWindow(IDB_TEST, SW_HIDE);
|
||||
ShowWindow(IDB_BACK, SW_HIDE);
|
||||
ShowWindow(IDB_NEXT, SW_HIDE);
|
||||
ShowWindow(IDB_EXPL, SW_HIDE);
|
||||
ShowWindow(IDB_QUIT, SW_HIDE);
|
||||
ShowWindow(IDB_BEEP, SW_HIDE);
|
||||
ShowWindow(IDB_OKAY, SW_SHOW);
|
||||
ShowWindow(IDB_READ, SW_SHOW);
|
||||
ShowWindow((*richText)->scroll, SW_SHOW);
|
||||
|
@ -478,10 +543,10 @@ void SetRichEditText(const char *name) {
|
|||
|
||||
// Load the text from the file
|
||||
|
||||
TBReadSimpleText(richText, &docSpec);
|
||||
TBReadSimpleText(richText, &docSpec, false);
|
||||
|
||||
if (name != szRunning && name != szNotRunning) {
|
||||
SetPage(kExplainPage);
|
||||
SetPage(EXPLAIN_RESULTS);
|
||||
} else {
|
||||
InvalidateRect(hDefault);
|
||||
}
|
||||
|
@ -666,7 +731,7 @@ unsigned long GetSystemTime() {
|
|||
void SetWindowText(int id, const char *str) {
|
||||
Str255 pStr;
|
||||
StrToPascal(pStr, str);
|
||||
ControlHandle hCntl = FindControl(id);
|
||||
ControlHandle hCntl = FindCntlHandle(id);
|
||||
if(hCntl) {
|
||||
GetDC(hDefault);
|
||||
SetCTitle(hCntl, pStr);
|
||||
|
@ -678,7 +743,7 @@ void SetWindowText(int id, const char *str) {
|
|||
* ENABLE WINDOW
|
||||
*******************************************************************************/
|
||||
void EnableWindow(int id, bool enabled) {
|
||||
ControlHandle hCntl = FindControl(id);
|
||||
ControlHandle hCntl = FindCntlHandle(id);
|
||||
if(hCntl) {
|
||||
GetDC(hDefault);
|
||||
HiliteControl(hCntl, enabled ? 0 : 255);
|
||||
|
@ -696,7 +761,7 @@ void ShowWindow(ControlHandle hCntl, int state) {
|
|||
}
|
||||
|
||||
void ShowWindow(int id, int state) {
|
||||
ControlHandle hCntl = FindControl(id);
|
||||
ControlHandle hCntl = FindCntlHandle(id);
|
||||
if(hCntl) {
|
||||
GetDC(hDefault);
|
||||
ShowWindow(hCntl, state);
|
||||
|
@ -704,6 +769,19 @@ void ShowWindow(int id, int state) {
|
|||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SEND MESSAGE
|
||||
*******************************************************************************/
|
||||
long SendMessage(int id, int msg) {
|
||||
if(msg == BM_GETCHECK) {
|
||||
ControlHandle hCntl = FindCntlHandle(id);
|
||||
if(hCntl) {
|
||||
return GetControlValue(hCntl) ? BST_CHECKED: 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* INVALIDATE RECT
|
||||
*******************************************************************************/
|
||||
|
@ -744,3 +822,17 @@ void ProcessPendingMessages() {
|
|||
}
|
||||
SystemTask();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SPLASH THE BITMAP
|
||||
*******************************************************************************/
|
||||
void SplashTheBitmap() {
|
||||
GetDC(hIntroWnd);
|
||||
Rect rect;
|
||||
SetRect(&rect, 16, 18, 16+120, 18/*+258*/ +220);
|
||||
if(tipIntroPic) {
|
||||
DrawPicture(tipIntroPic, &rect);
|
||||
}
|
||||
DrawEdge(&rect, BDR_SUNKENOUTER, BF_RECT);
|
||||
ReleaseDC(hIntroWnd);
|
||||
}
|
|
@ -123,11 +123,36 @@ ErrorTypeList errorTypeList[] = {
|
|||
0x0088020B, "Side Switch Error",
|
||||
0x00FFFFE6, "Buffer Too Big",
|
||||
|
||||
/***** Mac SCSI Manager Errors *****/
|
||||
0x00FFFF02, "SCSI comm err, timeout",
|
||||
0x00FFFF03, "SCSI bus arb, timeout",
|
||||
0x00FFFF05, "SCSI phase error",
|
||||
0x00FFFF07, "SCSI Manager busy",
|
||||
0x00FFFF08, "SCSI sequence error",
|
||||
0x00FFFF09, "SCSI blind, timeout",
|
||||
0x00FFFF0A, "SCSI compl, phase err",
|
||||
/***********************************/
|
||||
|
||||
0xFFFFFFFF, "-- Unknown Error --",
|
||||
|
||||
0, 0
|
||||
};
|
||||
|
||||
/********** Main Window Controls Text ************/
|
||||
|
||||
const char *szIntroTitle = "Trouble in Paradise";
|
||||
const char *szIntroSubTitle = "FREEWARE by Steve Gibson\r" \
|
||||
"Gibson Research Corporation\r" \
|
||||
"http://grc.com ( v 2.1b )\r" \
|
||||
"http://github.com/marciot/mac-tip";
|
||||
const char *szIntroText =
|
||||
"A Macintosh port of \"TIP\" for Windows by Marcio Teixeira, made possible by a "
|
||||
"generous code donation by Steve Gibson.\r\r"
|
||||
"This freeware utility determines whether an Iomega Zip or Jaz drive is prone "
|
||||
"to developing the dreaded \"Click of Death\" syndrome. Gibson's "
|
||||
"research into the maintenance, repair and data recovery of Iomega's removable "
|
||||
"media mass storage products led to this capability.";
|
||||
|
||||
/****************** Control Text *****************/
|
||||
|
||||
const char *szBack = "< Back";
|
||||
|
@ -162,7 +187,33 @@ TextList TestGrayText[] = {
|
|||
{155, 39, "Testing Progress"},
|
||||
{129, 77, "Spare Sectors Consumed"},
|
||||
{61, 135, "Testing Location"},
|
||||
/*{219, 135, "Sound"},*/
|
||||
{219, 135, "Sound"},
|
||||
{297, 135, "Error Summary"},
|
||||
{0,0,0}
|
||||
};
|
||||
|
||||
|
||||
// ----------------------- Test Monitor Panel Definitions -------------------
|
||||
|
||||
#define SET_RECT(LEFT, TOP, RIGHT, BOTTOM) {TOP, LEFT, BOTTOM, RIGHT}
|
||||
|
||||
Rect CS_Stat = SET_RECT(114, 8, 242, 28);
|
||||
Rect TP_Perc = SET_RECT( 12, 56, 409, 72);
|
||||
Rect SS_Jaz = SET_RECT( 12, 94, 409, 126);
|
||||
Rect SS_Sid0 = SET_RECT( 12, 94, 409, 110);
|
||||
Rect TL_Sect = SET_RECT( 75, 154, 203, 170);
|
||||
Rect ES_Read = SET_RECT(346, 154, 409, 170);
|
||||
Rect SE_Rect = SET_RECT(222, 154, 255, 221);
|
||||
|
||||
BtnList tipBtns[] = {
|
||||
{IDB_BACK, szBack, 157, 301, 80, 24},
|
||||
{IDB_NEXT, szNext, 236, 301, 80, 24},
|
||||
{IDB_QUIT, szQuit, 402, 301, 45, 24},
|
||||
{IDB_BEEP, "", 252, 211, 22, 22, checkBoxProc},
|
||||
// For Mac TIP only
|
||||
{IDB_TEST, szPressToStart, 157, 301, 150, 24},
|
||||
{IDB_EXPL, "Explain", 330, 301, 60, 24},
|
||||
{IDB_OKAY, "Okay", 380, 301, 65, 24},
|
||||
{IDB_READ, "Open in SimpleText...", 210, 301, 160, 24},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
|
@ -1,16 +1,19 @@
|
|||
/************************************************************
|
||||
|
||||
pstring.c
|
||||
|
||||
AUTHOR: Marcio Luis Teixeira
|
||||
CREATED: 9/17/94
|
||||
|
||||
LAST REVISION: 11/25/21
|
||||
|
||||
(c) 1994-1995 by Marcio Luis Teixeira.
|
||||
All rights reserved.
|
||||
|
||||
*************************************************************/
|
||||
/****************************************************************************
|
||||
* Common Libraries (c) 1994 Marcio Teixeira *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
#include "pstring.h"
|
||||
#include <ctype.h>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
/************************************************************
|
||||
|
||||
pstring.h
|
||||
|
||||
AUTHOR: Marcio Luis Teixeira
|
||||
CREATED: 9/17/94
|
||||
|
||||
LAST REVISION: 11/25/21
|
||||
|
||||
(c) 1994-1995 by Marcio Luis Teixeira.
|
||||
All rights reserved.
|
||||
|
||||
*************************************************************/
|
||||
/****************************************************************************
|
||||
* Common Libraries (c) 1994 Marcio Teixeira *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* To view a copy of the GNU General Public License, go to the following *
|
||||
* location: <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************/
|
||||
|
||||
short pstrlen( unsigned char *str );
|
||||
void psetlen( unsigned char *str, short len );
|
||||
|
|
Loading…
Reference in New Issue