/* Copyright (C) 2000 Eric Wagner (Loki@meson.engin.umich.edu) This program is free software; you can redistribute it and/or modify it. 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. */ /* prior work copyrights for the pdisk code: */ /* * Copyright 1997,1998 by Apple Computer, Inc. * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This source also contains code that has descended from Apple Sample Code package ATADemo Copyright: © 1996, 1997, 1998,1999 by Apple Computer, Inc. all rights reserved. From the ATADemo source : Disclaimer: You may incorporate this sample code into your applications without restriction, though the sample code has been provided "AS IS" and the responsibility for its operation is 100% yours. However, what you are not permitted to do is to redistribute the source as "DSC Sample Code" after having made changes. If you're going to re-distribute the source, we require that you make it clear in the source that the code was descended from Apple Sample Code, but that you've made changes. */ #include "TivoFormat.h" #define NumToolboxTraps() ( \ (NGetTrapAddress(_InitGraf, ToolTrap) \ == NGetTrapAddress(0xAA6E, ToolTrap)) \ ? 0x200 : 0x400 \ ) #define GetTrapType(theTrap) ( \ (((theTrap) & 0x800) != 0) ? ToolTrap : OSTrap \ ) /* .AppleCD contants */ enum { csSetPowerMode = 70, csQuiescence = 0x437 }; enum { pmActive = 0, pmStandby = 1, pmIdle = 2, pmSleep = 3 }; enum { quiescenceON = 0, quiescenceOFF = 1 }; /* custom structures */ static UInt32* ATADRefChain = NULL; /* Stores the driver refNum for each drive */ static UInt32* ATADeviceChain = NULL; static UInt32 numDevices = 0; // Each partition map entry (blocks 1 through n) has this format struct dpme { UInt16 dpme_signature ; UInt16 dpme_reserved_1 ; UInt32 dpme_map_entries ; UInt32 dpme_pblock_start ; UInt32 dpme_pblocks ; SInt8 dpme_name[32] ; /* name of partition */ SInt8 dpme_type[32] ; /* type of partition */ UInt32 dpme_lblock_start ; UInt32 dpme_lblocks ; UInt32 dpme_flags; #if 0 UInt32 dpme_reserved_2 : 23 ; /* Bit 9 through 31. */ UInt32 dpme_os_specific_1 : 1 ; /* Bit 8. */ UInt32 dpme_os_specific_2 : 1 ; /* Bit 7. */ UInt32 dpme_os_pic_code : 1 ; /* Bit 6. */ UInt32 dpme_writable : 1 ; /* Bit 5. */ UInt32 dpme_readable : 1 ; /* Bit 4. */ UInt32 dpme_bootable : 1 ; /* Bit 3. */ UInt32 dpme_in_use : 1 ; /* Bit 2. */ UInt32 dpme_allocated : 1 ; /* Bit 1. */ UInt32 dpme_valid : 1 ; /* Bit 0. */ #endif UInt32 dpme_boot_block ; UInt32 dpme_boot_bytes ; UInt8 *dpme_load_addr ; UInt8 *dpme_load_addr_2 ; UInt8 *dpme_goto_addr ; UInt8 *dpme_goto_addr_2 ; UInt32 dpme_checksum ; SInt8 dpme_process_id[16] ; UInt32 dpme_boot_args[32] ; UInt32 dpme_reserved_3[62] ; }; typedef struct dpme DPME; /* prototypes */ int Initialize(void); Boolean writeableHD(UInt32 deviceID); Boolean TrapAvailable (short theTrap); OSErr DisableCDDriver (SInt16 refNum); OSErr EnableCDDriver (SInt16 refNum); OSErr WakeUpCDDrive (SInt16 refNum); OSErr SetQuiescence (SInt16 refNum, UInt16 mode); void InvokeDialogWindow(void); void SetCells(ListHandle aList); Boolean dialogEventFilter(DialogRef theDialog, EventRecord *theEvent , DialogItemIndex *itemHit); void FormatDrive(void); OSErr WriteBlockZero(); OSErr PartitionDrive(); OSErr WriteSignature(); void DisplayError(OSErr err); /* code */ int main(void) { OSErr err; UInt32 accept; /* Initialize all the needed managers. */ InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(nil); InitCursor(); /* refuse the liability */ accept = CautionAlert(130, NULL); if(accept == 1) return 0; /* check the hardware */ err = Initialize(); if(err) DisplayError(err); /* Choose a disk and format it */ InvokeDialogWindow(); /* if we get this far the user canceled. */ NoteAlert(131, NULL); return 0; } int Initialize(void) { OSErr status = noErr; SInt16 drvrRefNum = 0; ataDrvrRegister pb = {0}; /* check for ATA hardware */ if(! (LMGetHWCfgFlags() & 0x0080) ) { return 1+ErrorOffset; } /* check for the ATA manager */ if(! TrapAvailable(kATATrap)) return 2+ErrorOffset; /* Disable the CD driver so we can scan the bus quitely */ status = OpenDriver("\p.AppleCD", &drvrRefNum); if(status == noErr) { if(status = DisableCDDriver(drvrRefNum)) return 5+ErrorOffset; } else status = noErr; /* pull the bus info */ /* set the first device ID */ pb.ataPBFunctionCode = kATAMgrFindDriverRefnum; pb.ataPBVers = kATAPBVers1; pb.ataPBDeviceID = (UInt32)0x0000ffff; status = ataManager((ataPB*) &pb ); if(status) return 3+ErrorOffset; /* loop through devices */ for(pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID; pb.ataPBDeviceID != 0xff; pb.ataPBDeviceID = (UInt32) pb.ataDeviceNextID) { status = ataManager((ataPB*)&pb); if(status) return 3+ErrorOffset; else { /* check for an ATA device */ if(writeableHD(pb.ataPBDeviceID)) { numDevices++; ATADRefChain = realloc(ATADRefChain, sizeof(UInt32)*numDevices); ATADeviceChain = realloc(ATADeviceChain, sizeof(UInt32)*numDevices); if(!ATADRefChain || !ATADeviceChain) return 4+ErrorOffset; ATADRefChain[numDevices-1] = pb.ataDrvrRefNum; ATADeviceChain[numDevices-1] = pb.ataPBDeviceID; } } } /* reenable the CD driver */ if(drvrRefNum != 0) { if(status = EnableCDDriver(drvrRefNum)) return 6+ErrorOffset; } return status; } /* ---------------------------------------------------------------------------*/ Boolean TrapAvailable (short theTrap) { TrapType trapType; trapType = GetTrapType(theTrap); if (trapType == ToolTrap) { theTrap &= 0x07FF; if (theTrap >= NumToolboxTraps()) theTrap = _Unimplemented; } return ( NGetTrapAddress(theTrap, trapType) != NGetTrapAddress(_Unimplemented, ToolTrap) ); } /* ---------------------------------------------------------------------------*/ OSErr DisableCDDriver (SInt16 refNum) /* --------------------------------------------------------------------------- Disable the CD driver */ { OSErr status; /* wake up drive */ status = WakeUpCDDrive (refNum); if (status != noErr) return status; /* move driver to quiescent mode */ status = SetQuiescence (refNum, quiescenceON); if (status != noErr) return status; return noErr; } /* ---------------------------------------------------------------------------*/ OSErr EnableCDDriver (SInt16 refNum) /* --------------------------------------------------------------------------- Re-enable the CD driver */ { OSErr status; /* move driver to quiescent mode*/ status = SetQuiescence (refNum, quiescenceOFF); if (status != noErr) return status; return noErr; } /* ---------------------------------------------------------------------------*/ OSErr WakeUpCDDrive (SInt16 refNum) /* --------------------------------------------------------------------------- Re-enable the CD driver */ { CntrlParam pb = {0}; OSErr status; pb.ioCRefNum = refNum; pb.csCode = csSetPowerMode; *(UInt8 *) &pb.csParam[0] = pmActive; /*send command to the CD/DVD driver*/ status = PBControlImmed ((ParmBlkPtr) &pb); return status; } /* ---------------------------------------------------------------------------*/ OSErr SetQuiescence (SInt16 refNum, UInt16 mode) /* --------------------------------------------------------------------------- Re-enable the CD driver */ { CntrlParam pb = {0}; OSErr status; pb.ioCRefNum = refNum; pb.csCode = csQuiescence; pb.csParam[0] = mode; /* send command to the CD/DVD driver*/ status = PBControlImmed ((ParmBlkPtr) &pb); return status; } Boolean writeableHD(UInt32 deviceID) { /* Checks if the device is an ATA device */ OSErr status; ataDevConfiguration pb = {0}; pb.ataPBFunctionCode = kATAMgrGetDrvConfiguration; pb.ataPBVers = kATAPBVers2; pb.ataPBDeviceID = deviceID; status = ataManager((ataPB*) &pb ); if(status) { return FALSE; } if(pb.ataDeviceType == 1) return TRUE; return FALSE; } void SetCells(ListHandle aList) { /* this function fills in the drives available on the ATA bus */ Cell aCell ={0}; long i; for(i=0;i 40) modelName[40] = 0; /* write out the model name */ stringLength += sprintf(&lineString[stringLength], "%s SN#", modelName); serialNum = (char*)&buffer[10]; length = strlen(serialNum); if(length > 20) serialNum[20] = 0; /* write out the serial number */ stringLength += sprintf(&lineString[stringLength], "(%s)", serialNum); /* write out the bus/device id */ stringLength += sprintf(&lineString[stringLength], " Bus %d, Device %d", ATADeviceChain[i] & 0x000000FF, (ATADeviceChain[i] & 0x0000FF00)>>8); LSetCell(&lineString, stringLength, aCell, aList); aCell.v++; } } void InvokeDialogWindow(void) { DialogRef theDialog; ControlRef aControl; Boolean outline=1; ListHandle aListHandle; Cell aCell ={0,0}; DialogItemIndex anIndex =4; DialogItemType aType; Rect listBox; Handle tHand; ListBounds lBounds = { 0}; ModalFilterUPP aFilterUPP = NewModalFilterProc(dialogEventFilter); GrafPtr savedPort; OSErr err; UInt32 driveType; Str255 priorFormat[] = {"\pDOS/Windows drive", "\pPC Linuxª drive", "\pMacOSª drive", "\pTivoª drive"}; lBounds.bottom = numDevices; lBounds.right = 1; theDialog = GetNewDialog(128, NULL,(WindowRef) -1); /* create the list */ GetDialogItem(theDialog, 4, &aType, &tHand, &listBox); listBox.bottom -= 16; listBox.right -= 16; aListHandle = LNew(&listBox, &lBounds, aCell,0, GetDialogWindow(theDialog), TRUE, FALSE, TRUE, TRUE); /* Title the window */ SetWTitle(GetDialogWindow(theDialog), "\pChoose a drive to formatÉ"); /* Set default/cancel buttons */ GetDialogItemAsControl(theDialog, 1, &aControl); SetControlData(aControl, kControlEntireControl, kControlPushButtonDefaultTag, sizeof(Boolean), (char*)&outline); GetDialogItemAsControl(theDialog, 2, &aControl); SetControlData(aControl, kControlEntireControl, kControlPushButtonCancelTag, sizeof(Boolean), (char*)&outline); /* store the list handle so event filter can see the list */ SetWRefCon(GetDialogWindow(theDialog), (long)aListHandle); /* Set cell names */ SetCells(aListHandle); /* select the first cell */ LSetSelect(1,aCell,aListHandle); /* draw box around list */ GetPort(&savedPort); SetPort(theDialog); /* make room for the scroll bars */ listBox.bottom += 15; listBox.right += 15; DrawThemeListBoxFrame(&listBox,kThemeStateActive); /* wait until a button is pushed */ while (anIndex>3) { ModalDialog(aFilterUPP, &anIndex); } SetPort(savedPort); /* user hit cancel button */ if(anIndex == 2) return; LGetSelect(1,&aCell, aListHandle); /* open the drive and check for prior partition/formatting then confirm format */ driveType = open_drive(ATADeviceChain[aCell.v]); if(anIndex == 3 ) { /* Unlock a drive */ err = UnlockDrive(); if(err) DisplayError(err); NoteAlert(134, NULL); exit(0); } if(driveType>0) { ParamText(priorFormat[driveType-1], NULL, NULL, NULL); anIndex = CautionAlert(128, nil); } else if(driveType < 0) {/* unknown error */ DisplayError(driveType); } else { anIndex = CautionAlert(132, nil); } /* quit if format cancled */ if(anIndex==1) return; FormatDrive(); /* report successful format */ NoteAlert(133, NULL); exit(0); } Boolean dialogEventFilter(DialogRef theDialog, EventRecord *theEvent, DialogItemIndex *itemHit){ ListHandle aList = (ListHandle)GetWRefCon(GetDialogWindow(theDialog)); GrafPtr savedPort; Boolean temp; Rect listBox = (**aList).rView; UInt8 character; Cell aCell = {0}; *itemHit = 4; GetPort(&savedPort); SetPort(theDialog); /* handle GUI events */ switch (theEvent->what) { case mouseDown: { /* check for mouse hits in list */ GlobalToLocal(&theEvent->where); if(MacPtInRect(theEvent->where, &listBox)) { LClick(theEvent->where, theEvent->modifiers, aList); *itemHit= 4; SetPort(savedPort); return true; } LocalToGlobal(&theEvent->where); } break; case activateEvt: /* handle another program being brought to the fore */ LActivate(0x00000001 & theEvent->modifiers, aList); SetPort(savedPort); break; case updateEvt: { /* handle window draw event */ BeginUpdate(GetDialogWindow(theDialog)); listBox.bottom += 15; listBox.right += 15; DrawThemeListBoxFrame(&listBox, FrontWindow() == GetDialogWindow(theDialog) ? kThemeStateActive : kThemeStateInactive); LUpdate(((DialogPeek)theDialog)->window.port.visRgn, aList); UpdateDialog (theDialog, ((DialogPeek)theDialog)->window.port.visRgn); EndUpdate(GetDialogWindow(theDialog)); SetPort(savedPort); break; } case keyDown: { /* handle arrow key selections */ character = charCodeMask & theEvent->message; temp = LGetSelect(1, &aCell, aList); if((character == kUpArrowCharCode) && temp) { if(aCell.v >0 ){ LSetSelect(0, aCell,aList); aCell.v--; LSetSelect(1, aCell, aList); } return TRUE; } if((character == kDownArrowCharCode) && temp) { if(aCell.v <(numDevices-1)) { LSetSelect(0, aCell, aList); aCell.v++; LSetSelect(1, aCell, aList); } return TRUE; } } } return FALSE; } OSErr WriteBlockZero() { int i; UInt32 bytesWritten; struct { UInt16 signature; UInt8 pKernelPartition; UInt8 aKernelPartition; UInt8 BootParams[128]; UInt8 Hostname[32]; UInt32 IPaddress; UInt8 MACaddress[6]; UInt8 undefined[338]; } diskHeader = {0}; diskHeader.signature = 0x1492; diskHeader.pKernelPartition = 3; diskHeader.aKernelPartition = 6; strcpy((char*)diskHeader.BootParams, (const char*)"root=/dev/hdb4"); strcpy((char*)diskHeader.Hostname, (const char*)"unnamed"); diskHeader.IPaddress = 0x0ABCDEF0; for(i=0;i<6;i++) diskHeader.MACaddress[i] = i+1; bytesWritten = WriteData(0, sizeof(diskHeader), (UInt8*)&diskHeader); if(bytesWritten != sizeof(diskHeader)) return 9+ErrorOffset; return noErr; } OSErr PartitionDrive(){ /* Three partitions plus one zero pad */ DPME partition[4]= {0}; UInt32 bytesWritten; /* the partition partition */ partition[0].dpme_signature = 0x504D; partition[0].dpme_map_entries = 3; partition[0].dpme_pblock_start = 1; partition[0].dpme_pblocks = 63; strcpy((char*)partition[0].dpme_name, (const char*)"Apple"); strcpy((char*)partition[0].dpme_type, (const char*)"Apple_partition_map"); partition[0].dpme_lblocks = 63; partition[0].dpme_flags = 0x00000033; /* valid, allocated, readable, writable */ /* the MFS App partition */ partition[1].dpme_signature = 0x504D; partition[1].dpme_map_entries = 3; partition[1].dpme_pblock_start = 64; partition[1].dpme_pblocks = 8192; /* 8192 * 0.5k = 4 Meg */ strcpy((char*)partition[1].dpme_name, (const char*)"Second MFS application region"); strcpy((char*)partition[1].dpme_type, (const char*)"MFS"); partition[1].dpme_lblocks = 8192; partition[1].dpme_flags = 0x00000033; /* valid, allocated, readable, writable */ /* the MFS media partition */ partition[2].dpme_signature = 0x504D; partition[2].dpme_map_entries = 3; partition[2].dpme_pblock_start = 8256; partition[2].dpme_pblocks = GetDriveSize() - 8256; strcpy((char*)partition[2].dpme_name, (const char*)"Second MFS media region"); strcpy((char*)partition[2].dpme_type, (const char*)"MFS"); partition[2].dpme_lblocks = GetDriveSize() - 8256; partition[2].dpme_flags = 0x00000133; /* valid, allocated, readable, writable, reserved*/ bytesWritten = WriteData(512, sizeof(DPME)*4, (UInt8*)partition); if(bytesWritten != sizeof(DPME)*4) return 10+ErrorOffset; return 0; } OSErr WriteSignature(){ UInt8 sig1[57]= "Add-on media file system disk, copyright TiVo Inc. 1999."; UInt8 sig2[8]={'T','i','V','o',0x06,0x0b,0x63,0x00}; UInt8 sig3[6]="asccd"; UInt8 block[512]; UInt32 bytesWritten; /* WriteData only works with block size data chunks. So we pad a little */ memcpy(block,sig1, 57); bytesWritten = WriteData(0x07B00000 + 512*8256, 512, block); if(bytesWritten != 512) return 11+ErrorOffset; /* 0x1C6AA390 isn't aligned on a 512 boundary */ memcpy(&block[400],sig2, 8); bytesWritten = WriteData(0x1C6AA390 + 512*8256 - 400, 512, block); if(bytesWritten != 512) return 11+ErrorOffset; memcpy(&block[252],sig3, 6); bytesWritten = WriteData(0x30F9D8FC + 512*8256 - 252, 512, block); if(bytesWritten != 512) return 11+ErrorOffset; return noErr; } void DisplayError(OSErr err){ /* error codes start at ErrorOffset */ Str255 number="\p"; Str255 errorMessages[] = { /*0*/ "\pA really unexpected error. The number is:", /*1*/ "\pNo ATA hardware found!", /*2*/ "\pATA Manager not available.", /*3*/ "\pATA Driver not found. Try formatting drive as MacOS first.", /*4*/ "\pMemory Allocation Failure. That shouldn't happen :-(", /*5*/ "\pCouldn't disable CD driver.", /*6*/ "\pCouldn't enable CD driver.", /*7*/ "\pATA GetDrvConfiguration failed.", /*8*/ "\pATA manager drive identify failed.", /*9*/ "\pWrite Block 0 failed.", /*10*/ "\pPartitioning failed.", /*11*/ "\pSignature write failed.", /*12*/ "\pGrain size is unsupported.", /*13*/ "\pCouldn't get the size." }; if(err==0) return; /* trap unexpected errors */ if(err(ErrorOffset+13) ) { NumToString(err, number); err = ErrorOffset; } ParamText(errorMessages[err-ErrorOffset],number, NULL,NULL); StopAlert(129, NULL); exit(err); } void FormatDrive(void) { OSErr err = 0; /* Write Block Zero */ if(err = WriteBlockZero()) DisplayError(err); /* Partition Drive */ if(err = PartitionDrive()) DisplayError(err); /* Write the Signature */ if(err = WriteSignature()) DisplayError(err); }