/* 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