/*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<numDevices;i++){			ataIdentify				pb = {0};		UInt16					buffer[256] = {0};		OSErr					status;			UInt32					NumSectors;		UInt8					stringLength;		char					lineString[255];		float					NumGigs;			char*					modelName;		UInt16					length;			char*					serialNum;					pb.ataPBFunctionCode 	= kATAMgrDriveIdentify;		pb.ataPBVers			= kATAPBVers1;		pb.ataPBDeviceID		= ATADeviceChain[i];		pb.ataPBFlags			= mATAFlagIORead + mATAFlagByteSwap;		pb.ataPBTimeOut			= kATAtimeout;		pb.ataPBBuffer			= (void*) buffer;				status = ataManager((ataPB*)&pb);		if(status) DisplayError(ErrorOffset+8);				NumSectors = (UInt32)buffer[61] << 16;		NumSectors += buffer[60];								/* convert to gigabytes */		NumGigs = (float)NumSectors/(1024 * 1024 * 1024)*512;		/* write out the gigabytes (7 characters)*/		stringLength=sprintf(lineString,"%6.2f GB ",NumGigs);				modelName = (char*)&buffer[27];		length= strlen(modelName);		if(length > 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 || 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);		}