/*Copyright (C) 2000, 2001  Eric Wagner (ewagner@mac.com)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. */  #define LBA_CAPABLE 0x0200#define FORCE_LBA	1#include "TivoFormat.h"#include "ATA_powerpc.h"void		DisplayError(OSErr err);OSErrReadDiskBlock(UInt32 block, UInt8	*buffer);OSErrWriteDiskBlock(UInt32 block, UInt8 *buffer);/* drive specific data */static	UInt32					lba;static	UInt32					heads;static	UInt32					sectors;static	UInt32					grain;static 	UInt32					deviceID;static	UInt64					diskSize; /* in blocks, currently assuming											 512 bytes per block */UInt64 GetDriveSize(){ 	return diskSize;	}	int open_drive(UInt32	dev) {	/* returns 1 for prior DOS drive */	/* returns 2 for prior Linux drive */	/* returns 3 for prior HFS drive */	/* returns 4 for prior Tivo drive */	/* returns various ATA manager errors */	ataIdentify				pb = {0};	OSErr					err;	unsigned short			buffer[256]={0};	UInt32					total;			unsigned char			*buf;		deviceID				= 	dev;		pb.ataPBFunctionCode 	= 	kATAMgrDriveIdentify;	pb.ataPBVers            =   kATAPBVers1;    pb.ataPBDeviceID        =   deviceID;    pb.ataPBFlags           =   mATAFlagIORead | mATAFlagByteSwap;    pb.ataPBTimeOut         =   kATAtimeout;    pb.ataPBBuffer          =   (void*) buffer;	if(err = ataManager((ataPB*)&pb)) DisplayError(err);	/* check the capabilities */#if !FORCE_LBA	if((buffer[49] & LBA_CAPABLE) != 0 ) {#endif		total = (UInt32)buffer[61] << 16;		total += buffer[60];		lba = 1;		heads = 0;		sectors = 0;#if !FORCE_LBA	} else {		/* Only CHS - Cylinder Head Sector addressing */		total = ((UInt32)buffer[58])<<16		total += buffer[57];		lba = 0;		heads = buffer[55];		sectors = buffer[56];	}#endif	#if 0	if(buffer[5] == 0 ) {		buf = malloc(2048);		grain = 512;		if(ReadDiskBlock(0, buf) != noErr)			DisplayError(12+ErrorOffset); /* grain size not 512, freak out */		/*	grain = 2048;		else err = ReadDiskBlock(0, buf);*/			} else {		grain = buffer[5];		if(grain != 512) DisplayError(12+ErrorOffset); /* huh? */		buf = malloc(grain);		if(err = ReadDiskBlock(0, buf)) return err;	}#endif	grain = 512;	buf = malloc(512);	if(err = ReadDiskBlock(0, buf)) return err;		/* check for previous formatting */		/* DOS */	if(buf[0]==0x33 && buf[1]==0xC0 && buf[2]==0x8E)  err = 1;		/* PC Linux */	else if(buf[0] == 0xFA) err = 2;		/* Mac */	else if(buf[0] == 0x45 && buf[1] == 0x52) err = 3;		/* Tivo */	else if(buf[0] == 0x14 && buf[1] == 0x92) err = 4;		free(buf);		if(total == 0) 		/*diskSize = ((UInt64) 1000);*/		DisplayError(13+ErrorOffset); /* couldn't get the correct size */	else		diskSize = ((UInt64) total);	return err;}/* ********************** *//*   Disk Write			  *//* ********************** */UInt32WriteData(SInt64 offset, UInt32 count, UInt8 *buffer){/* offset is in bytes */    long block;    long block_count;    long success = 0;    int i;        if (count <= 0 || count % grain != 0) {	/* can't handle size */    } else if (offset < 0 || offset % grain != 0) {	/* can't handle offset */    } else if ( (offset + count) > (diskSize * grain)) {	/* check for offset (and offset+count) too large */    } else {	/* do a write on the physical device */	block = offset / grain;	block_count = count / grain;	for (i = 0; i < block_count; i++) {	    if (WriteDiskBlock(block, buffer) != noErr) {			return 0;		}	    buffer += grain;	    block += 1;		success ++;	}    }    return success*grain;}/* ********************** *//*   Disk Read 			  *//* ********************** */UInt32ReadData(SInt64 offset, UInt32 count, UInt8 *buffer){    long block;    long block_count;    int i;    long success=0;            if (count <= 0 || count % grain != 0) {	/* can't handle size */    } else if (offset < 0 || offset % grain != 0) {	/* can't handle offset */    } else if (offset + count > (diskSize*grain)) {	/* check for offset (and offset+count) too large */    } else {	/* do a read on the physical device */	block = offset / grain;	block_count = count / grain;	for (i = 0; i < block_count; i++) {	    if (ReadDiskBlock(block, buffer) != noErr) {			return 0;	    }	    buffer += grain;	    block += 1;	    success++;	}    }    return success*grain;}/* ********************** *//*   Disk Read Block	  *//* ********************** */OSErrReadDiskBlock(UInt32 block, UInt8	*buffer){	ataIOPB		pb={0};	OSErr		err;	long		slave;	long		llba, sector, head, cyl;		pb.ataPBFunctionCode    =   kATAMgrExecIO;    pb.ataPBVers            =   kATAPBVers1;    pb.ataPBDeviceID        =   deviceID;    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIORead | mATAFlagByteSwap;    pb.ataPBTimeOut         =   kATAtimeout;        pb.ataPBLogicalBlockSize =  grain;    pb.ataPBBuffer          =   buffer;    pb.ataPBByteCount 		= 	grain;	if(lba) {		llba = 0x40;		sector = block & 0xFF;		head = (block >> 24) & 0xF;		cyl = (block >> 8 ) & 0xFFFF;	} else {		llba = 0x00;		sector = (block % sectors) + 1;		cyl = block / sectors;		head = cyl % heads;		cyl = cyl / heads;	}		pb.ataPBTaskFile.ataTFCount = 1;    pb.ataPBTaskFile.ataTFSector = sector;    pb.ataPBTaskFile.ataTFCylinder = cyl;    if (deviceID & 0x0FF00) {		slave = 0x10;    } else {		slave = 0x00;    }			      /* std | L/C  | Drive | head */    pb.ataPBTaskFile.ataTFSDH = 0xA0 | llba | slave | head;    pb.ataPBTaskFile.ataTFCommand = kATAcmdRead;    err = ataManager((ataPB*) &pb );        return err;}/* ********************** *//*   Disk Write Block	  *//* ********************** */OSErrWriteDiskBlock(UInt32 block, UInt8 *buffer){    ataIOPB     pb = {0};    OSErr       err;    long        slave;    long	llba, cyl, head, sector;    pb.ataPBFunctionCode    =   kATAMgrExecIO;    pb.ataPBVers            =   kATAPBVers1;    pb.ataPBDeviceID        =   deviceID;    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIOWrite | mATAFlagByteSwap;    pb.ataPBTimeOut         =   kATAtimeout;        pb.ataPBLogicalBlockSize =  grain;    pb.ataPBBuffer          =   buffer;    pb.ataPBByteCount 		= 	grain;    if (lba) {    	llba = 0x40;    	sector = block & 0xFF;    	head = (block >> 24) & 0xF;    	cyl = (block >> 8) & 0xFFFF;    } else {    	llba = 0x00;		sector = (block % sectors) + 1;		cyl = block / sectors;		head = cyl % heads;		cyl = cyl / heads;    }    pb.ataPBTaskFile.ataTFCount = 1;    pb.ataPBTaskFile.ataTFSector = sector;    pb.ataPBTaskFile.ataTFCylinder = cyl;    if (deviceID & 0x0FF00) {		slave = 0x10;    } else {		slave = 0x0;    }			      /* std | L/C  | Drive | head */    pb.ataPBTaskFile.ataTFSDH = 0xA0 | llba | slave | head;    pb.ataPBTaskFile.ataTFCommand = kATAcmdWrite;    err = ataManager((ataPB*) &pb );		return err;    }/* ********************** *//*   Unlock a drive 	  *//* ********************** */OSErrUnlockDrive(void) {	ataIOPB		pb={0};	OSErr		err;	UInt32		buffer[128];	UInt32		i;	UInt8		*dPtr;	/* get the challenge */	dPtr= (UInt8*)buffer;	/* this is actually a warped type of read command */	pb.ataPBFunctionCode    =   kATAMgrExecIO;    pb.ataPBVers            =   kATAPBVers1;    pb.ataPBDeviceID        =   deviceID;    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIORead | mATAFlagByteSwap;    pb.ataPBTimeOut         =   kATAtimeout;        pb.ataPBLogicalBlockSize =  grain;    pb.ataPBBuffer          =   dPtr;    pb.ataPBByteCount 		= 	512;		/* now set the registers */	pb.ataPBTaskFile.ataTFCount = 0x82; /* sub-command */	pb.ataPBTaskFile.ataTFSector = 0x6F; /* password */	pb.ataPBTaskFile.ataTFCylinder = 0x50BE; /* password */	pb.ataPBTaskFile.ataTFCommand = 0xF0; /* qntm extended cmd*/		err = ataManager((ataPB*)&pb);	if(err) return err;	if(pb.ataPBResult) return pb.ataPBResult;/* calculate the response */	/*	buffer[0] ^= 'TiVo';	*/	/* Type 1 */	buffer[0] ^= 'oViT';		/* Type 2 *//*	buffer[0] ^= 'VoTi'; 	*/	/* Type 3 *//*	buffer[0] ^= 'iToV'; 	*/	/* Type 4 */		/* send the response */	/* zero out the other bytes just for sanity */		for(i=1;i<128;i++) buffer[1]=0;	dPtr = (UInt8*)(&pb);	for(i=0;i<sizeof(pb);i++) dPtr[i] = 0;	dPtr = (UInt8*)buffer;	    pb.ataPBFunctionCode    =   kATAMgrExecIO;    pb.ataPBVers            =   kATAPBVers1;    pb.ataPBDeviceID        =   deviceID;    pb.ataPBFlags           =   mATAFlagTFRead | mATAFlagIOWrite | mATAFlagByteSwap;    pb.ataPBTimeOut         =   kATAtimeout;        pb.ataPBLogicalBlockSize =  grain;    pb.ataPBBuffer          =   dPtr;    pb.ataPBByteCount 		= 	512;	/* now set the registers */	pb.ataPBTaskFile.ataTFCount = 0x83; /* sub-command */	pb.ataPBTaskFile.ataTFSector = 0xEF; /* password */	pb.ataPBTaskFile.ataTFCylinder = 0x86C2; /* password */	pb.ataPBTaskFile.ataTFCommand = 0xF0; /* qntm extended cmd*/	err = ataManager((ataPB*)&pb);	if(err) return err;	if(pb.ataPBResult) return pb.ataPBResult;	return noErr;}