aboutsummaryrefslogtreecommitdiffstats
path: root/heimdall/source
diff options
context:
space:
mode:
Diffstat (limited to 'heimdall/source')
-rw-r--r--heimdall/source/.DS_Storebin0 -> 15364 bytes
-rw-r--r--heimdall/source/._.DS_Storebin0 -> 4096 bytes
-rw-r--r--heimdall/source/._BridgeManager.cppbin0 -> 4096 bytes
-rw-r--r--heimdall/source/._InterfaceManager.cppbin0 -> 4096 bytes
-rw-r--r--heimdall/source/._InterfaceManager.hbin0 -> 4096 bytes
-rw-r--r--heimdall/source/.dirstamp0
-rw-r--r--heimdall/source/BeginDumpPacket.h72
-rw-r--r--heimdall/source/BridgeManager.cpp1086
-rw-r--r--heimdall/source/BridgeManager.h124
-rw-r--r--heimdall/source/ControlPacket.h71
-rw-r--r--heimdall/source/DeviceInfoPacket.h74
-rw-r--r--heimdall/source/DeviceInfoResponse.h58
-rw-r--r--heimdall/source/DumpPartFileTransferPacket.h56
-rw-r--r--heimdall/source/DumpPartPitFilePacket.h56
-rw-r--r--heimdall/source/DumpResponse.h58
-rw-r--r--heimdall/source/EndFileTransferPacket.h120
-rw-r--r--heimdall/source/EndModemFileTransferPacket.h59
-rw-r--r--heimdall/source/EndPhoneFileTransferPacket.h86
-rw-r--r--heimdall/source/FileTransferPacket.h73
-rw-r--r--heimdall/source/FlashPartFileTransferPacket.h65
-rw-r--r--heimdall/source/FlashPartPitFilePacket.h56
-rw-r--r--heimdall/source/Heimdall.h43
-rw-r--r--heimdall/source/InboundPacket.h77
-rw-r--r--heimdall/source/InterfaceManager.cpp265
-rw-r--r--heimdall/source/InterfaceManager.h109
-rw-r--r--heimdall/source/OutboundPacket.h71
-rw-r--r--heimdall/source/Packet.h65
-rw-r--r--heimdall/source/PitFilePacket.h73
-rw-r--r--heimdall/source/PitFileResponse.h58
-rw-r--r--heimdall/source/RebootDevicePacket.h64
-rw-r--r--heimdall/source/ReceiveFilePartPacket.h49
-rw-r--r--heimdall/source/ResponsePacket.h81
-rw-r--r--heimdall/source/SendFilePartPacket.h63
-rw-r--r--heimdall/source/SendFilePartResponse.h58
-rw-r--r--heimdall/source/main.cpp660
35 files changed, 3850 insertions, 0 deletions
diff --git a/heimdall/source/.DS_Store b/heimdall/source/.DS_Store
new file mode 100644
index 0000000..b244d9f
--- /dev/null
+++ b/heimdall/source/.DS_Store
Binary files differ
diff --git a/heimdall/source/._.DS_Store b/heimdall/source/._.DS_Store
new file mode 100644
index 0000000..338bd7b
--- /dev/null
+++ b/heimdall/source/._.DS_Store
Binary files differ
diff --git a/heimdall/source/._BridgeManager.cpp b/heimdall/source/._BridgeManager.cpp
new file mode 100644
index 0000000..5b4b4a0
--- /dev/null
+++ b/heimdall/source/._BridgeManager.cpp
Binary files differ
diff --git a/heimdall/source/._InterfaceManager.cpp b/heimdall/source/._InterfaceManager.cpp
new file mode 100644
index 0000000..a322a67
--- /dev/null
+++ b/heimdall/source/._InterfaceManager.cpp
Binary files differ
diff --git a/heimdall/source/._InterfaceManager.h b/heimdall/source/._InterfaceManager.h
new file mode 100644
index 0000000..a322a67
--- /dev/null
+++ b/heimdall/source/._InterfaceManager.h
Binary files differ
diff --git a/heimdall/source/.dirstamp b/heimdall/source/.dirstamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/heimdall/source/.dirstamp
diff --git a/heimdall/source/BeginDumpPacket.h b/heimdall/source/BeginDumpPacket.h
new file mode 100644
index 0000000..4bd6d88
--- /dev/null
+++ b/heimdall/source/BeginDumpPacket.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef BEGINDUMPPACKET_H
+#define BEGINDUMPPACKET_H
+
+// Heimdall
+#include "FileTransferPacket.h"
+
+namespace Heimdall
+{
+ class BeginDumpPacket : public FileTransferPacket
+ {
+ public:
+
+ enum
+ {
+ kChipTypeRam = 0,
+ kChipTypeNand = 1
+ };
+
+ private:
+
+ unsigned int chipType;
+ unsigned int chipId;
+
+ public:
+
+ BeginDumpPacket(unsigned int chipType, unsigned int chipId) : FileTransferPacket(FileTransferPacket::kRequestDump)
+ {
+ this->chipType = chipType;
+ this->chipId = chipId;
+ }
+
+ unsigned int GetChipType(void) const
+ {
+ return (chipType);
+ }
+
+ unsigned int GetChipId(void) const
+ {
+ return (chipId);
+ }
+
+ virtual void Pack(void)
+ {
+ FileTransferPacket::Pack();
+
+ PackInteger(FileTransferPacket::kDataSize, chipType);
+ PackInteger(FileTransferPacket::kDataSize + 4, chipId);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp
new file mode 100644
index 0000000..0b94dfb
--- /dev/null
+++ b/heimdall/source/BridgeManager.cpp
@@ -0,0 +1,1086 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+// C Standard Library
+#include <stdio.h>
+
+// libusb
+#include <libusb.h>
+
+// Heimdall
+#include "BeginDumpPacket.h"
+#include "BridgeManager.h"
+#include "DumpPartFileTransferPacket.h"
+#include "DumpPartPitFilePacket.h"
+#include "DumpResponse.h"
+#include "EndModemFileTransferPacket.h"
+#include "EndPhoneFileTransferPacket.h"
+#include "FileTransferPacket.h"
+#include "FlashPartFileTransferPacket.h"
+#include "FlashPartPitFilePacket.h"
+#include "InboundPacket.h"
+#include "InterfaceManager.h"
+#include "OutboundPacket.h"
+#include "PitFilePacket.h"
+#include "PitFileResponse.h"
+#include "ReceiveFilePartPacket.h"
+#include "RebootDevicePacket.h"
+#include "ResponsePacket.h"
+#include "SendFilePartPacket.h"
+#include "SendFilePartResponse.h"
+
+// Future versions of libusb will use usb_interface instead of interface.
+#define usb_interface interface
+
+#define CLASS_CDC 0x0A
+
+using namespace Heimdall;
+
+const DeviceIdentifier BridgeManager::supportedDevices[BridgeManager::kSupportedDeviceCount] = {
+ DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidGalaxySDownloadMode)/*,
+ DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidGalaxySInternational),
+ DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidGalaxySNewInternational),
+ DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidVibrantCanadaBell)*/
+};
+
+enum
+{
+ kMaxSequenceLength = 800
+};
+
+BridgeManager::BridgeManager(bool verbose, int communicationDelay)
+{
+ this->verbose = verbose;
+ this->communicationDelay = communicationDelay;
+
+ libusbContext = nullptr;
+ deviceHandle = nullptr;
+ heimdallDevice = nullptr;
+ inEndpoint = -1;
+ outEndpoint = -1;
+ interfaceIndex = -1;
+
+#ifdef OS_LINUX
+
+ detachedDriver = false;
+
+#endif
+}
+
+BridgeManager::~BridgeManager()
+{
+ if (interfaceIndex >= 0)
+ libusb_release_interface(deviceHandle, interfaceIndex);
+
+#ifdef OS_LINUX
+
+ if (detachedDriver)
+ {
+ InterfaceManager::Print("Re-attaching kernel driver...\n");
+ libusb_attach_kernel_driver(deviceHandle, interfaceIndex);
+ }
+
+#endif
+
+ if (deviceHandle)
+ libusb_close(deviceHandle);
+
+ if (heimdallDevice)
+ libusb_unref_device(heimdallDevice);
+
+ if (libusbContext)
+ libusb_exit(libusbContext);
+}
+
+bool BridgeManager::Initialise(void)
+{
+ // Initialise libusb-1.0
+ int result = libusb_init(&libusbContext);
+ if (result != LIBUSB_SUCCESS)
+ {
+ InterfaceManager::PrintError("Failed to initialise libusb. Error: %i\n", result);
+ return (false);
+ }
+
+ // Get handle to Galaxy S device
+ struct libusb_device **devices;
+ int deviceCount = libusb_get_device_list(libusbContext, &devices);
+
+ for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
+ {
+ libusb_device_descriptor descriptor;
+ libusb_get_device_descriptor(devices[deviceIndex], &descriptor);
+
+ for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++)
+ {
+ if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId)
+ {
+ heimdallDevice = devices[deviceIndex];
+ libusb_ref_device(heimdallDevice);
+ break;
+ }
+ }
+
+ if (heimdallDevice)
+ break;
+ }
+
+ libusb_free_device_list(devices, deviceCount);
+
+ if (!heimdallDevice)
+ {
+ InterfaceManager::PrintError("Failed to detect compatible device\n");
+ return (false);
+ }
+
+ result = libusb_open(heimdallDevice, &deviceHandle);
+ if (result != LIBUSB_SUCCESS)
+ {
+ InterfaceManager::PrintError("Failed to access device. Error: %i\n", result);
+ return (false);
+ }
+
+ libusb_device_descriptor deviceDescriptor;
+ result = libusb_get_device_descriptor(heimdallDevice, &deviceDescriptor);
+ if (result != LIBUSB_SUCCESS)
+ {
+ InterfaceManager::PrintError("Failed to retrieve device description\n");
+ return (false);
+ }
+
+ if (verbose)
+ {
+ unsigned char stringBuffer[128];
+ if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iManufacturer,
+ stringBuffer, 128) >= 0)
+ {
+ InterfaceManager::Print(" Manufacturer: \"%s\"\n", stringBuffer);
+ }
+
+ if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iProduct,
+ stringBuffer, 128) >= 0)
+ {
+ InterfaceManager::Print(" Product: \"%s\"\n", stringBuffer);
+ }
+
+ if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iSerialNumber,
+ stringBuffer, 128) >= 0)
+ {
+ InterfaceManager::Print(" Serial No: \"%s\"\n", stringBuffer);
+ }
+
+ InterfaceManager::Print("\n length: %d\n", deviceDescriptor.bLength);
+ InterfaceManager::Print(" device class: %d\n", deviceDescriptor.bDeviceClass);
+ InterfaceManager::Print(" S/N: %d\n", deviceDescriptor.iSerialNumber);
+ InterfaceManager::Print(" VID:PID: %04X:%04X\n", deviceDescriptor.idVendor, deviceDescriptor.idProduct);
+ InterfaceManager::Print(" bcdDevice: %04X\n", deviceDescriptor.bcdDevice);
+ InterfaceManager::Print(" iMan:iProd:iSer: %d:%d:%d\n", deviceDescriptor.iManufacturer, deviceDescriptor.iProduct,
+ deviceDescriptor.iSerialNumber);
+ InterfaceManager::Print(" nb confs: %d\n", deviceDescriptor.bNumConfigurations);
+ }
+
+ libusb_config_descriptor *configDescriptor;
+ result = libusb_get_config_descriptor(heimdallDevice, 0, &configDescriptor);
+ if (result != LIBUSB_SUCCESS || !configDescriptor)
+ {
+ InterfaceManager::PrintError("Failed to retrieve config descriptor\n");
+ return (false);
+ }
+
+ int interfaceIndex = -1;
+ int altSettingIndex;
+
+ for (int i = 0; i < configDescriptor->bNumInterfaces; i++)
+ {
+ for (int j = 0 ; j < configDescriptor->usb_interface[i].num_altsetting; j++)
+ {
+ if (verbose)
+ {
+ InterfaceManager::Print("\ninterface[%d].altsetting[%d]: num endpoints = %d\n",
+ i, j, configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints);
+ InterfaceManager::Print(" Class.SubClass.Protocol: %02X.%02X.%02X\n",
+ configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass,
+ configDescriptor->usb_interface[i].altsetting[j].bInterfaceSubClass,
+ configDescriptor->usb_interface[i].altsetting[j].bInterfaceProtocol);
+ }
+
+ int inEndpointAddress = -1;
+ int outEndpointAddress = -1;
+
+ for (int k = 0; k < configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints; k++)
+ {
+ const libusb_endpoint_descriptor *endpoint =
+ &configDescriptor->usb_interface[i].altsetting[j].endpoint[k];
+
+ if (verbose)
+ {
+ InterfaceManager::Print(" endpoint[%d].address: %02X\n", k, endpoint->bEndpointAddress);
+ InterfaceManager::Print(" max packet size: %04X\n", endpoint->wMaxPacketSize);
+ InterfaceManager::Print(" polling interval: %02X\n", endpoint->bInterval);
+ }
+
+ if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN)
+ inEndpointAddress = endpoint->bEndpointAddress;
+ else
+ outEndpointAddress = endpoint->bEndpointAddress;
+ }
+
+ if (interfaceIndex < 0
+ && configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints == 2
+ && configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass == CLASS_CDC
+ && inEndpointAddress != -1 && outEndpointAddress != -1)
+ {
+ interfaceIndex = i;
+ altSettingIndex = j;
+ inEndpoint = inEndpointAddress;
+ outEndpoint = outEndpointAddress;
+ }
+ }
+ }
+
+ libusb_free_config_descriptor(configDescriptor);
+
+ if (result != LIBUSB_SUCCESS)
+ {
+ InterfaceManager::PrintError("Failed to find correct interface configuration\n");
+ return (false);
+ }
+
+ InterfaceManager::Print("\nClaiming interface...");
+ result = libusb_claim_interface(deviceHandle, interfaceIndex);
+
+#ifdef OS_LINUX
+
+ if (result != LIBUSB_SUCCESS)
+ {
+ detachedDriver = true;
+ InterfaceManager::Print(" Failed. Attempting to detach driver...\n");
+ libusb_detach_kernel_driver(deviceHandle, interfaceIndex);
+ InterfaceManager::Print("Claiming interface again...");
+ result = libusb_claim_interface(deviceHandle, interfaceIndex);
+ }
+
+#endif
+
+ if (result != LIBUSB_SUCCESS)
+ {
+ InterfaceManager::PrintError(" Failed!\n");
+ return (false);
+ }
+
+ InterfaceManager::Print(" Success\n");
+
+ InterfaceManager::Print("Setting up interface...");
+ result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex);
+ if (result != LIBUSB_SUCCESS)
+ {
+ InterfaceManager::PrintError(" Failed!\n");
+ return (false);
+ }
+
+ InterfaceManager::Print(" Success\n");
+
+ return (true);
+}
+
+bool BridgeManager::BeginSession(void) const
+{
+ InterfaceManager::Print("Beginning session...\n");
+
+ unsigned char *dataBuffer = new unsigned char[7];
+
+ int result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000);
+
+ if (result < 0)
+ {
+ InterfaceManager::PrintError("Failed to initialise usb communication!\n");
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ memset(dataBuffer, 0, 7);
+ dataBuffer[1] = 0xC2;
+ dataBuffer[2] = 0x01;
+ dataBuffer[6] = 0x07;
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError("Failed to initialise usb communication!\n");
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError("Failed to initialise usb communication!\n");
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError("Failed to initialise usb communication!\n");
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ memset(dataBuffer, 0, 7);
+ dataBuffer[1] = 0xC2;
+ dataBuffer[2] = 0x01;
+ dataBuffer[6] = 0x08;
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError("Failed to initialise usb communication!\n");
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError("Failed to initialise usb communication!\n");
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ InterfaceManager::Print("Handshaking with Loke...");
+
+ int dataTransferred;
+
+ // Send "ODIN"
+ strcpy((char *)dataBuffer, "ODIN");
+
+ result = libusb_bulk_transfer(deviceHandle, outEndpoint, dataBuffer, 4, &dataTransferred, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError(" Failed!\n");
+
+ if (verbose)
+ InterfaceManager::PrintError("ERROR: Failed to send data: \"%s\"\n", dataBuffer);
+
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ if (dataTransferred != 4)
+ {
+ InterfaceManager::PrintError(" Failed!\n");
+
+ if (verbose)
+ InterfaceManager::PrintError("ERROR: Failed to complete sending data: \"%s\"\n", dataBuffer);
+
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ // Expect "LOKE"
+ memset(dataBuffer, 0, 7);
+
+ result = libusb_bulk_transfer(deviceHandle, inEndpoint, dataBuffer, 7, &dataTransferred, 1000);
+ if (result < 0)
+ {
+ InterfaceManager::PrintError(" Failed!\n");
+
+ if (verbose)
+ InterfaceManager::PrintError("ERROR: Failed to receive response\n");
+ delete [] dataBuffer;
+ return (false);;
+ }
+
+ if (dataTransferred != 4 || memcmp(dataBuffer, "LOKE", 4) != 0)
+ {
+ InterfaceManager::PrintError(" Failed!\n");
+
+ if (verbose)
+ InterfaceManager::PrintError("ERROR: Unexpected communication.\nExpected: \"%s\"\nReceived: \"%s\"\n", "LOKE", dataBuffer);
+
+ delete [] dataBuffer;
+ return (false);
+ }
+
+ InterfaceManager::Print(" Success\n\n");
+ return (true);
+}
+
+bool BridgeManager::EndSession(void) const
+{
+ InterfaceManager::Print("Ending session...\n");
+
+ RebootDevicePacket *rebootDevicePacket = new RebootDevicePacket(RebootDevicePacket::kRequestEndSession);
+ bool success = SendPacket(rebootDevicePacket);
+ delete rebootDevicePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send end session packet!\n");
+ return (false);
+ }
+
+ ResponsePacket *rebootDeviceResponse = new ResponsePacket(ResponsePacket::kResponseTypeRebootDevice);
+ success = ReceivePacket(rebootDeviceResponse);
+ delete rebootDeviceResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive session end confirmation!\n");
+ return (false);
+ }
+
+ return (true);
+}
+
+bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout) const
+{
+ packet->Pack();
+
+ int dataTransferred;
+ int result = libusb_bulk_transfer(deviceHandle, outEndpoint, packet->GetData(), packet->GetSize(),
+ &dataTransferred, timeout);
+
+ if (result < 0)
+ {
+ // max(250, communicationDelay)
+ int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
+
+ if (verbose)
+ InterfaceManager::PrintError("Error %i whilst sending packet. ", result);
+
+ // Retry
+ for (int i = 0; i < 5; i++)
+ {
+ if (verbose)
+ InterfaceManager::PrintError(" Retrying...\n");
+
+ // Wait longer each retry
+ Sleep(retryDelay * (i + 1));
+
+ result = libusb_bulk_transfer(deviceHandle, outEndpoint, packet->GetData(), packet->GetSize(),
+ &dataTransferred, timeout);
+
+ if (result >= 0)
+ break;
+
+ if (verbose)
+ InterfaceManager::PrintError("Error %i whilst sending packet. ", result);
+ }
+
+ if (verbose)
+ InterfaceManager::PrintError("\n");
+ }
+
+ if (communicationDelay != 0)
+ Sleep(communicationDelay);
+
+ if (result < 0 || dataTransferred != packet->GetSize())
+ return (false);
+
+ return (true);
+}
+
+bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout) const
+{
+ int dataTransferred;
+ int result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(),
+ &dataTransferred, timeout);
+
+ if (result < 0)
+ {
+ // max(250, communicationDelay)
+ int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
+
+ if (verbose)
+ InterfaceManager::PrintError("Error %i whilst receiving packet. ", result);
+
+ // Retry
+ for (int i = 0; i < 5; i++)
+ {
+ if (verbose)
+ InterfaceManager::PrintError(" Retrying\n");
+
+ // Wait longer each retry
+ Sleep(retryDelay * (i + 1));
+
+ result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(),
+ &dataTransferred, timeout);
+
+ if (result >= 0)
+ break;
+
+ if (verbose)
+ InterfaceManager::PrintError("Error %i whilst receiving packet. ", result);
+
+ if (i >= 3)
+ {
+ int breakHere = 0;
+ breakHere++;
+ }
+ }
+
+ if (verbose)
+ InterfaceManager::PrintError("\n");
+ }
+
+ if (communicationDelay != 0)
+ Sleep(communicationDelay);
+
+ if (result < 0 || (dataTransferred != packet->GetSize() && !packet->IsSizeVariable()))
+ return (false);
+
+ packet->SetReceivedSize(dataTransferred);
+
+ return (packet->Unpack());
+}
+
+bool BridgeManager::SendPitFile(FILE *file) const
+{
+ fseek(file, 0, SEEK_END);
+ long fileSize = ftell(file);
+ rewind(file);
+
+ // Start file transfer
+ PitFilePacket *pitFilePacket = new PitFilePacket(PitFilePacket::kRequestFlash);
+ bool success = SendPacket(pitFilePacket);
+ delete pitFilePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to request sending of PIT file!\n");
+ return (false);
+ }
+
+ PitFileResponse *pitFileResponse = new PitFileResponse();
+ success = ReceivePacket(pitFileResponse);
+ delete pitFileResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to confirm sending of PIT file!\n");
+ return (false);
+ }
+
+ // Transfer file size
+ FlashPartPitFilePacket *flashPartPitFilePacket = new FlashPartPitFilePacket(fileSize);
+ success = SendPacket(flashPartPitFilePacket);
+ delete flashPartPitFilePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send PIT file part information!\n");
+ return (false);
+ }
+
+ pitFileResponse = new PitFileResponse();
+ success = ReceivePacket(pitFileResponse);
+ delete pitFileResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to confirm sending of PIT file part information!\n");
+ return (false);
+ }
+
+ // Flash pit file
+ SendFilePartPacket *sendFilePartPacket = new SendFilePartPacket(file, fileSize);
+ success = SendPacket(sendFilePartPacket);
+ delete sendFilePartPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send file part packet!\n");
+ return (false);
+ }
+
+ pitFileResponse = new PitFileResponse();
+ success = ReceivePacket(pitFileResponse);
+ delete pitFileResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive PIT file transfer count!\n");
+ return (false);
+ }
+
+ return (true);
+}
+
+int BridgeManager::ReceivePitFile(unsigned char **pitBuffer) const
+{
+ *pitBuffer = nullptr;
+
+ bool success;
+
+ // Start file transfer
+ PitFilePacket *pitFilePacket = new PitFilePacket(PitFilePacket::kRequestDump);
+ success = SendPacket(pitFilePacket);
+ delete pitFilePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to request receival of PIT file!\n");
+ return (0);
+ }
+
+ PitFileResponse *pitFileResponse = new PitFileResponse();
+ success = ReceivePacket(pitFileResponse);
+ int fileSize = pitFileResponse->GetFileSize();
+ delete pitFileResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive PIT file size!\n");
+ return (0);
+ }
+
+ int transferCount = fileSize / ReceiveFilePartPacket::kDataSize;
+ if (fileSize % ReceiveFilePartPacket::kDataSize != 0)
+ transferCount++;
+
+ unsigned char *buffer = new unsigned char[fileSize];
+ int offset = 0;
+
+ // NOTE: The PIT file appears to always be padded out to exactly 4 kilobytes.
+ for (int i = 0; i < transferCount; i++)
+ {
+ DumpPartPitFilePacket *requestPacket = new DumpPartPitFilePacket(i);
+ success = SendPacket(requestPacket);
+ delete requestPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to request PIT file part #%i!\n", i);
+ delete [] buffer;
+ return (0);
+ }
+
+ ReceiveFilePartPacket *receiveFilePartPacket = new ReceiveFilePartPacket();
+ success = ReceivePacket(receiveFilePartPacket);
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive PIT file part #%i!\n", i);
+ delete receiveFilePartPacket;
+ delete [] buffer;
+ return (0);
+ }
+
+ // Copy the whole packet data into the buffer.
+ memcpy(buffer + offset, receiveFilePartPacket->GetData(), receiveFilePartPacket->GetReceivedSize());
+ offset += receiveFilePartPacket->GetReceivedSize();
+
+ delete receiveFilePartPacket;
+ }
+
+ // End file transfer
+ pitFilePacket = new PitFilePacket(PitFilePacket::kRequestEndTransfer);
+ success = SendPacket(pitFilePacket);
+ delete pitFilePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send request to end PIT file transfer!\n");
+ delete [] buffer;
+ return (0);
+ }
+
+ pitFileResponse = new PitFileResponse();
+ success = ReceivePacket(pitFileResponse);
+ delete pitFileResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive end PIT file transfer verification!\n");
+ delete [] buffer;
+ return (0);
+ }
+
+ *pitBuffer = buffer;
+ return (fileSize);
+}
+
+bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) const
+{
+ if (destination != EndFileTransferPacket::kDestinationModem && destination != EndFileTransferPacket::kDestinationPhone)
+ {
+ InterfaceManager::PrintError("ERROR: Attempted to send file to unknown destination!\n");
+ return (false);
+ }
+
+ if (destination == EndFileTransferPacket::kDestinationModem && fileIdentifier != -1)
+ {
+ InterfaceManager::PrintError("ERROR: The modem file does not have an identifier!\n");
+ return (false);
+ }
+
+ FileTransferPacket *flashFileTransferPacket = new FileTransferPacket(FileTransferPacket::kRequestFlash);
+ bool success = SendPacket(flashFileTransferPacket);
+ delete flashFileTransferPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to initialise transfer!\n");
+ return (false);
+ }
+
+ fseek(file, 0, SEEK_END);
+ long fileSize = ftell(file);
+ rewind(file);
+
+ ResponsePacket *fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer);
+ success = ReceivePacket(fileTransferResponse);
+ delete fileTransferResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to confirm transfer initialisation!\n");
+ return (false);
+ }
+
+ int sequenceCount = fileSize / (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize);
+ int lastSequenceSize = kMaxSequenceLength;
+ int partialPacketLength = fileSize % SendFilePartPacket::kDefaultPacketSize;
+ if (fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize) != 0)
+ {
+ sequenceCount++;
+
+ int lastSequenceBytes = fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize);
+ lastSequenceSize = lastSequenceBytes / SendFilePartPacket::kDefaultPacketSize;
+ if (partialPacketLength != 0)
+ lastSequenceSize++;
+ }
+
+ long bytesTransferred = 0;
+ int currentPercent;
+ int previousPercent = 0;
+ InterfaceManager::Print("0%%");
+
+ for (int sequenceIndex = 0; sequenceIndex < sequenceCount; sequenceIndex++)
+ {
+ // Min(lastSequenceSize, 131072)
+ bool isLastSequence = sequenceIndex == sequenceCount - 1;
+ int sequenceSize = (isLastSequence) ? lastSequenceSize : kMaxSequenceLength;
+
+ FlashPartFileTransferPacket *beginFileTransferPacket = new FlashPartFileTransferPacket(0, 2 * sequenceSize);
+ success = SendPacket(beginFileTransferPacket);
+ delete beginFileTransferPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to begin file transfer sequence!\n");
+ return (false);
+ }
+
+ fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer);
+ bool success = ReceivePacket(fileTransferResponse);
+ delete fileTransferResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to confirm beginning of file transfer sequence!\n");
+ return (false);
+ }
+
+ SendFilePartPacket *sendFilePartPacket;
+ SendFilePartResponse *sendFilePartResponse;
+
+ for (int filePartIndex = 0; filePartIndex < sequenceSize; filePartIndex++)
+ {
+ // Send
+ sendFilePartPacket = new SendFilePartPacket(file);
+ success = SendPacket(sendFilePartPacket);
+ delete sendFilePartPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to send file part packet!\n");
+ return (false);
+ }
+
+ // Response
+ sendFilePartResponse = new SendFilePartResponse();
+ success = ReceivePacket(sendFilePartResponse);
+ int receivedPartIndex = sendFilePartResponse->GetPartIndex();
+
+ if (verbose)
+ {
+ const unsigned char *data = sendFilePartResponse->GetData();
+ InterfaceManager::Print("File Part #%i... Response: %X %X %X %X %X %X %X %X \n", filePartIndex,
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+ }
+
+ delete sendFilePartResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to receive file part response!\n");
+
+ for (int retry = 0; retry < 4; retry++)
+ {
+ InterfaceManager::PrintError("\nRetrying...");
+
+ // Send
+ sendFilePartPacket = new SendFilePartPacket(file);
+ success = SendPacket(sendFilePartPacket);
+ delete sendFilePartPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to send file part packet!\n");
+ return (false);
+ }
+
+ // Response
+ sendFilePartResponse = new SendFilePartResponse();
+ success = ReceivePacket(sendFilePartResponse);
+ int receivedPartIndex = sendFilePartResponse->GetPartIndex();
+
+ if (verbose)
+ {
+ const unsigned char *data = sendFilePartResponse->GetData();
+ InterfaceManager::Print("File Part #%i... Response: %X %X %X %X %X %X %X %X \n", filePartIndex,
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+ }
+
+ delete sendFilePartResponse;
+
+ if (receivedPartIndex != filePartIndex)
+ {
+ InterfaceManager::PrintError("\nERROR: Expected file part index: %i Received: %i\n",
+ filePartIndex, receivedPartIndex);
+ return (false);
+ }
+
+ if (success)
+ break;
+ }
+
+ if (!success)
+ return (false);
+ }
+
+ if (receivedPartIndex != filePartIndex)
+ {
+ InterfaceManager::PrintError("\nERROR: Expected file part index: %i Received: %i\n",
+ filePartIndex, receivedPartIndex);
+ return (false);
+ }
+
+ bytesTransferred += SendFilePartPacket::kDefaultPacketSize;
+ if (bytesTransferred > fileSize)
+ bytesTransferred = fileSize;
+
+ currentPercent = (int)(100.0f * ((float)bytesTransferred / (float)fileSize));
+
+ if (!verbose)
+ {
+ if (currentPercent != previousPercent)
+ {
+ if (previousPercent < 10)
+ InterfaceManager::Print("\b\b%i%%", currentPercent);
+ else
+ InterfaceManager::Print("\b\b\b%i%%", currentPercent);
+ }
+ }
+
+ previousPercent = currentPercent;
+ }
+
+ int lastFullPacketIndex = 2 * ((isLastSequence && partialPacketLength != 0) ? sequenceSize - 1 : sequenceSize);
+
+ if (destination == EndFileTransferPacket::kDestinationPhone)
+ {
+ EndPhoneFileTransferPacket *endPhoneFileTransferPacket = new EndPhoneFileTransferPacket(
+ (isLastSequence) ? partialPacketLength : 0, lastFullPacketIndex, 0, 0, fileIdentifier, isLastSequence);
+
+ success = SendPacket(endPhoneFileTransferPacket, 3000);
+ delete endPhoneFileTransferPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to end phone file transfer sequence!\n");
+ return (false);
+ }
+ }
+ else // destination == EndFileTransferPacket::kDestinationModem
+ {
+ EndModemFileTransferPacket *endModemFileTransferPacket = new EndModemFileTransferPacket(
+ (isLastSequence) ? partialPacketLength : 0, lastFullPacketIndex, 0, 0, isLastSequence);
+
+ success = SendPacket(endModemFileTransferPacket, 3000);
+ delete endModemFileTransferPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to end modem file transfer sequence!\n");
+ return (false);
+ }
+ }
+
+ fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer);
+ success = ReceivePacket(fileTransferResponse, 30000);
+ delete fileTransferResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("\nFailed to confirm end of file transfer sequence!\n");
+ return (false);
+ }
+ }
+
+ if (!verbose)
+ InterfaceManager::Print("\n");
+
+ return (true);
+}
+
+bool BridgeManager::ReceiveDump(int chipType, int chipId, FILE *file) const
+{
+ bool success;
+
+ // Start file transfer
+ BeginDumpPacket *beginDumpPacket = new BeginDumpPacket(chipType, chipId);
+ success = SendPacket(beginDumpPacket);
+ delete beginDumpPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to request dump!\n");
+ return (false);
+ }
+
+ DumpResponse *dumpResponse = new DumpResponse();
+ success = ReceivePacket(dumpResponse);
+ unsigned int dumpSize = dumpResponse->GetDumpSize();
+ delete dumpResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive dump size!\n");
+ return (false);
+ }
+
+ unsigned int transferCount = dumpSize / ReceiveFilePartPacket::kDataSize;
+ if (transferCount % ReceiveFilePartPacket::kDataSize != 0)
+ transferCount++;
+
+ char *buffer = new char[kDumpBufferSize * ReceiveFilePartPacket::kDataSize];
+ int bufferOffset = 0;
+
+ for (unsigned int i = 0; i < transferCount; i++)
+ {
+ DumpPartFileTransferPacket *dumpPartPacket = new DumpPartFileTransferPacket(i);
+ success = SendPacket(dumpPartPacket);
+ delete dumpPartPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to request dump part #%i!\n", i);
+ delete [] buffer;
+ return (false);
+ }
+
+ ReceiveFilePartPacket *receiveFilePartPacket = new ReceiveFilePartPacket();
+ success = ReceivePacket(receiveFilePartPacket);
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive dump part #%i!\n", i);
+ continue;
+ delete receiveFilePartPacket;
+ delete [] buffer;
+ return (true);
+ }
+
+ if (bufferOffset + receiveFilePartPacket->GetReceivedSize() > kDumpBufferSize * ReceiveFilePartPacket::kDataSize)
+ {
+ // Write the buffer to the output file
+ fwrite(buffer, 1, bufferOffset, file);
+ bufferOffset = 0;
+ }
+
+ // Copy the packet data into pitFile.
+ memcpy(buffer + bufferOffset, receiveFilePartPacket->GetData(), receiveFilePartPacket->GetReceivedSize());
+ bufferOffset += receiveFilePartPacket->GetReceivedSize();
+
+ delete receiveFilePartPacket;
+ }
+
+ if (bufferOffset != 0)
+ {
+ // Write the buffer to the output file
+ fwrite(buffer, 1, bufferOffset, file);
+ }
+
+ delete [] buffer;
+
+ // End file transfer
+ FileTransferPacket *fileTransferPacket = new FileTransferPacket(FileTransferPacket::kRequestEnd);
+ success = SendPacket(fileTransferPacket);
+ delete fileTransferPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send request to end dump transfer!\n");
+ return (false);
+ }
+
+ ResponsePacket *responsePacket = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer);
+ success = ReceivePacket(responsePacket);
+ delete responsePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive end dump transfer verification!\n");
+ return (false);
+ }
+
+ return (true);
+}
+
+bool BridgeManager::RebootDevice(void) const
+{
+ InterfaceManager::Print("Rebooting device...\n");
+
+ RebootDevicePacket *rebootDevicePacket = new RebootDevicePacket(RebootDevicePacket::kRequestRebootDevice);
+ bool success = SendPacket(rebootDevicePacket);
+ delete rebootDevicePacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send end session packet!\n");
+ return (false);
+ }
+
+ ResponsePacket *rebootDeviceResponse = new ResponsePacket(ResponsePacket::kResponseTypeRebootDevice);
+ success = ReceivePacket(rebootDeviceResponse);
+ delete rebootDeviceResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive reboot confirmation!\n");
+ return (false);
+ }
+
+ return (true);
+}
diff --git a/heimdall/source/BridgeManager.h b/heimdall/source/BridgeManager.h
new file mode 100644
index 0000000..40a7ceb
--- /dev/null
+++ b/heimdall/source/BridgeManager.h
@@ -0,0 +1,124 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef BRIDGEMANAGER_H
+#define BRIDGEMANAGER_H
+
+// Heimdall
+#include "Heimdall.h"
+
+struct libusb_context;
+struct libusb_device;
+struct libusb_device_handle;
+
+namespace Heimdall
+{
+ class InboundPacket;
+ class OutboundPacket;
+
+ class DeviceIdentifier
+ {
+ public:
+
+ const int vendorId;
+ const int productId;
+
+ DeviceIdentifier(int vid, int pid) :
+ vendorId(vid),
+ productId(pid)
+ {
+ }
+ };
+
+ class BridgeManager
+ {
+ public:
+
+ enum
+ {
+ kSupportedDeviceCount = 1,
+
+ kCommunicationDelayDefault = 0,
+ kDumpBufferSize = 4096
+ };
+
+ enum
+ {
+ kVidSamsung = 0x04E8
+ };
+
+ enum
+ {
+ kPidGalaxySDownloadMode = 0x6601/*,
+ kPidGalaxySInternational = 0x681C,
+ kPidGalaxySNewInternational = 0x681D,
+ kPidVibrantCanadaBell = 0x6877*/
+ };
+
+ private:
+
+ static const DeviceIdentifier supportedDevices[kSupportedDeviceCount];
+
+ bool verbose;
+
+ libusb_context *libusbContext;
+ libusb_device_handle *deviceHandle;
+ libusb_device *heimdallDevice;
+ int interfaceIndex;
+ int inEndpoint;
+ int outEndpoint;
+
+ int communicationDelay;
+
+#ifdef OS_LINUX
+
+ bool detachedDriver;
+
+#endif
+
+ public:
+
+ BridgeManager(bool verbose, int communicationDelay);
+ ~BridgeManager();
+
+ bool Initialise(void);
+
+ bool BeginSession(void) const;
+ bool EndSession(void) const;
+
+ bool SendPacket(OutboundPacket *packet, int timeout = 3000) const;
+ bool ReceivePacket(InboundPacket *packet, int timeout = 3000) const;
+
+ bool SendPitFile(FILE *file) const;
+ int ReceivePitFile(unsigned char **pitBuffer) const;
+
+ bool SendFile(FILE *file, int destination, int fileIdentifier = -1) const;
+ bool ReceiveDump(int chipType, int chipId, FILE *file) const;
+
+ bool RebootDevice(void) const;
+
+ bool IsVerbose(void) const
+ {
+ return (verbose);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/ControlPacket.h b/heimdall/source/ControlPacket.h
new file mode 100644
index 0000000..2379073
--- /dev/null
+++ b/heimdall/source/ControlPacket.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef CONTROLPACKET_H
+#define CONTROLPACKET_H
+
+// Heimdall
+#include "OutboundPacket.h"
+
+namespace Heimdall
+{
+ class ControlPacket : public OutboundPacket
+ {
+ public:
+
+ enum
+ {
+ kControlTypeDeviceInfo = 0x64,
+ kControlTypePitFile = 0x65,
+ kControlTypeFileTransfer = 0x66,
+ kControlTypeRebootDevice = 0x67
+ };
+
+ protected:
+
+ enum
+ {
+ kDataSize = 4
+ };
+
+ private:
+
+ unsigned int controlType;
+
+ public:
+
+ ControlPacket(unsigned int controlType) : OutboundPacket(1024)
+ {
+ this->controlType = controlType;
+ }
+
+ unsigned int GetControlType(void) const
+ {
+ return (controlType);
+ }
+
+ virtual void Pack(void)
+ {
+ PackInteger(0, controlType);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/DeviceInfoPacket.h b/heimdall/source/DeviceInfoPacket.h
new file mode 100644
index 0000000..153cdc5
--- /dev/null
+++ b/heimdall/source/DeviceInfoPacket.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef DEVICEINFOPACKET_H
+#define DEVICEINFOPACKET_H
+
+// Heimdall
+#include "ControlPacket.h"
+
+namespace Heimdall
+{
+ class DeviceInfoPacket : public ControlPacket
+ {
+ public:
+
+ enum
+ {
+ kUnknown1 = 0, // Begin device info?
+ kUnknown2 = 1, // End device info?
+ kTotalBytes = 2 // Total no. bytes that will be flashed, seems to be ignored though.
+ };
+
+ private:
+
+ unsigned int request;
+ unsigned int unknown3Parameter; // TODO: Subclass for unknown2.
+
+ public:
+
+ DeviceInfoPacket(unsigned int request, unsigned int unknown3Parameter = 0)
+ : ControlPacket(ControlPacket::kControlTypeDeviceInfo)
+ {
+ this->request = request;
+ this->unknown3Parameter = unknown3Parameter;
+ }
+
+ unsigned int GetRequest(void) const
+ {
+ return (request);
+ }
+
+ unsigned int GetUnknown3Parameter(void) const
+ {
+ return (unknown3Parameter);
+ }
+
+ void Pack(void)
+ {
+ ControlPacket::Pack();
+
+ PackInteger(ControlPacket::kDataSize, request);
+ PackInteger(ControlPacket::kDataSize + 4, unknown3Parameter);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/DeviceInfoResponse.h b/heimdall/source/DeviceInfoResponse.h
new file mode 100644
index 0000000..3bf2d8f
--- /dev/null
+++ b/heimdall/source/DeviceInfoResponse.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef DEVICEINFORESPONSE_H
+#define DEVICEINFORESPONSE_H
+
+// Heimdall
+#include "ResponsePacket.h"
+
+namespace Heimdall
+{
+ class DeviceInfoResponse : public ResponsePacket
+ {
+ private:
+
+ unsigned int unknown;
+
+ public:
+
+ DeviceInfoResponse() : ResponsePacket(ResponsePacket::kResponseTypeDeviceInfo)
+ {
+ }
+
+ int GetUnknown(void) const
+ {
+ return (unknown);
+ }
+
+ bool Unpack(void)
+ {
+ if (!ResponsePacket::Unpack())
+ return (false);
+
+ unknown = UnpackInteger(ResponsePacket::kDataSize);
+
+ return (true);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/DumpPartFileTransferPacket.h b/heimdall/source/DumpPartFileTransferPacket.h
new file mode 100644
index 0000000..60fb8c5
--- /dev/null
+++ b/heimdall/source/DumpPartFileTransferPacket.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef DUMPPARTFILETRANSFERPACKET_H
+#define DUMPPARTFILETRANSFERPACKET_H
+
+// Heimdall
+#include "FileTransferPacket.h"
+
+namespace Heimdall
+{
+ class DumpPartFileTransferPacket : public FileTransferPacket
+ {
+ private:
+
+ unsigned int partIndex;
+
+ public:
+
+ DumpPartFileTransferPacket(unsigned int partIndex) : FileTransferPacket(FileTransferPacket::kRequestPart)
+ {
+ this->partIndex = partIndex;
+ }
+
+ unsigned int GetPartIndex(void) const
+ {
+ return (partIndex);
+ }
+
+ virtual void Pack(void)
+ {
+ FileTransferPacket::Pack();
+
+ PackInteger(FileTransferPacket::kDataSize, partIndex);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/DumpPartPitFilePacket.h b/heimdall/source/DumpPartPitFilePacket.h
new file mode 100644
index 0000000..29025c2
--- /dev/null
+++ b/heimdall/source/DumpPartPitFilePacket.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef DUMPPARTPITFILEPACKET_H
+#define DUMPPARTPITFILEPACKET_H
+
+// Heimdall
+#include "PitFilePacket.h"
+
+namespace Heimdall
+{
+ class DumpPartPitFilePacket : public PitFilePacket
+ {
+ private:
+
+ unsigned int partIndex;
+
+ public:
+
+ DumpPartPitFilePacket(unsigned int partIndex) : PitFilePacket(PitFilePacket::kRequestPart)
+ {
+ this->partIndex = partIndex;
+ }
+
+ unsigned int GetPartIndex(void) const
+ {
+ return (partIndex);
+ }
+
+ void Pack(void)
+ {
+ PitFilePacket::Pack();
+
+ PackInteger(PitFilePacket::kDataSize, partIndex);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/DumpResponse.h b/heimdall/source/DumpResponse.h
new file mode 100644
index 0000000..126982a
--- /dev/null
+++ b/heimdall/source/DumpResponse.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef DUMPRESPONSE_H
+#define DUMPRESPONSE_H
+
+// Heimdall
+#include "ResponsePacket.h"
+
+namespace Heimdall
+{
+ class DumpResponse : public ResponsePacket
+ {
+ private:
+
+ unsigned int dumpSize;
+
+ public:
+
+ DumpResponse() : ResponsePacket(kResponseTypeFileTransfer)
+ {
+ }
+
+ unsigned int GetDumpSize(void) const
+ {
+ return (dumpSize);
+ }
+
+ bool Unpack(void)
+ {
+ if (!ResponsePacket::Unpack())
+ return (false);
+
+ dumpSize = UnpackInteger(ResponsePacket::kDataSize);
+
+ return (true);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/EndFileTransferPacket.h b/heimdall/source/EndFileTransferPacket.h
new file mode 100644
index 0000000..3f3d689
--- /dev/null
+++ b/heimdall/source/EndFileTransferPacket.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef ENDFILETRANSFERPACKET_H
+#define ENDFILETRANSFERPACKET_H
+
+// Heimdall
+#include "FileTransferPacket.h"
+
+namespace Heimdall
+{
+ class EndFileTransferPacket : public FileTransferPacket
+ {
+ public:
+
+ enum
+ {
+ kDestinationPhone = 0x00,
+ kDestinationModem = 0x01
+ };
+
+ protected:
+
+ enum
+ {
+ kDataSize = FileTransferPacket::kDataSize + 16
+ };
+
+ private:
+
+ unsigned int destination; // Chip identifier perhaps
+ unsigned short partialPacketLength; // Length or (length - 65536) if lastFullPacket is odd.
+ unsigned int lastFullPacketIndex;
+ unsigned short unknown1;
+ unsigned int unknown2;
+
+ protected:
+
+ EndFileTransferPacket(unsigned int destination, unsigned int partialPacketLength, unsigned int lastFullPacketIndex,
+ unsigned short unknown1, unsigned int unknown2)
+ : FileTransferPacket(FileTransferPacket::kRequestEnd)
+ {
+ this->destination = destination;
+
+ if (partialPacketLength > 65535)
+ {
+ this->partialPacketLength = (partialPacketLength - 65536);
+ this->lastFullPacketIndex = lastFullPacketIndex + 1;
+ }
+ else
+ {
+ this->partialPacketLength = partialPacketLength;
+ this->lastFullPacketIndex = lastFullPacketIndex;
+ }
+
+ this->unknown1 = unknown1;
+ this->unknown2 = unknown2;
+ }
+
+ public:
+
+ unsigned int GetDestination(void) const
+ {
+ return (destination);
+ }
+
+ unsigned int GetPartialPacketLength(void) const
+ {
+ if (lastFullPacketIndex % 2 == 0)
+ return (partialPacketLength);
+ else
+ return (partialPacketLength + 65536);
+ }
+
+ unsigned int GetLastFullPacketIndex(void) const
+ {
+ return (lastFullPacketIndex - lastFullPacketIndex % 2);
+ }
+
+ unsigned short GetUnknown1(void) const
+ {
+ return (unknown1);
+ }
+
+ unsigned int GetUnknown2(void) const
+ {
+ return (unknown2);
+ }
+
+ virtual void Pack(void)
+ {
+ FileTransferPacket::Pack();
+
+ PackInteger(FileTransferPacket::kDataSize, destination);
+ PackShort(FileTransferPacket::kDataSize + 4, partialPacketLength);
+ PackInteger(FileTransferPacket::kDataSize + 6, lastFullPacketIndex);
+ PackShort(FileTransferPacket::kDataSize + 10, unknown1);
+ PackInteger(FileTransferPacket::kDataSize + 12, unknown2);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/EndModemFileTransferPacket.h b/heimdall/source/EndModemFileTransferPacket.h
new file mode 100644
index 0000000..9dc4c78
--- /dev/null
+++ b/heimdall/source/EndModemFileTransferPacket.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef ENDMODEMFILETRANSFERPACKET_H
+#define ENDMODEMFILETRANSFERPACKET_H
+
+// Heimdall
+#include "EndFileTransferPacket.h"
+
+namespace Heimdall
+{
+ class EndModemFileTransferPacket : public EndFileTransferPacket
+ {
+ private:
+
+ unsigned int endOfFile;
+
+ public:
+
+ EndModemFileTransferPacket(unsigned int partialPacketLength, unsigned int lastFullPacketIndex, unsigned short unknown1,
+ unsigned int unknown2, bool endOfFile)
+ : EndFileTransferPacket(EndFileTransferPacket::kDestinationModem, partialPacketLength,
+ lastFullPacketIndex, unknown1, unknown2)
+ {
+ this->endOfFile = (endOfFile) ? 1 : 0;
+ }
+
+ bool IsEndOfFile(void) const
+ {
+ return (endOfFile == 1);
+ }
+
+ void Pack(void)
+ {
+ EndFileTransferPacket::Pack();
+
+ PackInteger(EndFileTransferPacket::kDataSize, endOfFile);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/EndPhoneFileTransferPacket.h b/heimdall/source/EndPhoneFileTransferPacket.h
new file mode 100644
index 0000000..24650a2
--- /dev/null
+++ b/heimdall/source/EndPhoneFileTransferPacket.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef ENDPHONEFILETRANSFERPACKET_H
+#define ENDPHONEFILETRANSFERPACKET_H
+
+// Heimdall
+#include "EndFileTransferPacket.h"
+
+namespace Heimdall
+{
+ class EndPhoneFileTransferPacket : public EndFileTransferPacket
+ {
+ public:
+
+ enum
+ {
+ kFilePrimaryBootloader = 0x00,
+ kFilePit = 0x01, // New 1.1 - Don't flash the pit this way!
+ kFileSecondaryBootloader = 0x03,
+ kFileSecondaryBootloaderBackup = 0x04, // New 1.1
+ kFileKernel = 0x06,
+ kFileRecovery = 0x07, // New 1.1
+ kFileEfs = 0x14, // New 1.1
+ kFileParamLfs = 0x15,
+ kFileFactoryFilesystem = 0x16,
+ kFileDatabaseData = 0x17,
+ kFileCache = 0x18,
+
+ kFileModem = 0x0B // New 1.1 - Kies flashes the modem this way rather than using the EndModemFileTransferPacket.
+ };
+
+ private:
+
+ unsigned int fileIdentifier;
+ unsigned int endOfFile;
+
+ public:
+
+ EndPhoneFileTransferPacket(unsigned int partialPacketLength, unsigned int lastFullPacketIndex, unsigned short unknown1,
+ unsigned int unknown2, unsigned int fileIdentifier, bool endOfFile)
+ : EndFileTransferPacket(EndFileTransferPacket::kDestinationPhone, partialPacketLength,
+ lastFullPacketIndex, unknown1, unknown2)
+ {
+ this->fileIdentifier = fileIdentifier;
+ this->endOfFile = (endOfFile) ? 1 : 0;
+ }
+
+ unsigned int GetFileIdentifier(void)
+ {
+ return (fileIdentifier);
+ }
+
+ bool IsEndOfFile(void) const
+ {
+ return (endOfFile == 1);
+ }
+
+ void Pack(void)
+ {
+ EndFileTransferPacket::Pack();
+
+ PackInteger(EndFileTransferPacket::kDataSize, fileIdentifier);
+ PackInteger(EndFileTransferPacket::kDataSize + 4, endOfFile);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/FileTransferPacket.h b/heimdall/source/FileTransferPacket.h
new file mode 100644
index 0000000..daa6a75
--- /dev/null
+++ b/heimdall/source/FileTransferPacket.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef FILETRANSFERPACKET_H
+#define FILETRANSFERPACKET_H
+
+// Heimdall
+#include "ControlPacket.h"
+
+namespace Heimdall
+{
+ class FileTransferPacket : public ControlPacket
+ {
+ public:
+
+ enum
+ {
+ kRequestFlash = 0x00,
+ kRequestDump = 0x01,
+ kRequestPart = 0x02,
+ kRequestEnd = 0x03
+ };
+
+ protected:
+
+ enum
+ {
+ kDataSize = ControlPacket::kDataSize + 4
+ };
+
+ private:
+
+ unsigned int request;
+
+ public:
+
+ FileTransferPacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeFileTransfer)
+ {
+ this->request = request;
+ }
+
+ unsigned int GetRequest(void) const
+ {
+ return (request);
+ }
+
+ virtual void Pack(void)
+ {
+ ControlPacket::Pack();
+
+ PackInteger(ControlPacket::kDataSize, request);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/FlashPartFileTransferPacket.h b/heimdall/source/FlashPartFileTransferPacket.h
new file mode 100644
index 0000000..6aa57da
--- /dev/null
+++ b/heimdall/source/FlashPartFileTransferPacket.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef FLASHPARTFILETRANSFERPACKET_H
+#define FLASHPARTFILETRANSFERPACKET_H
+
+// Heimdall
+#include "FileTransferPacket.h"
+
+namespace Heimdall
+{
+ class FlashPartFileTransferPacket : public FileTransferPacket
+ {
+ private:
+
+ unsigned short unknown;
+ unsigned int transferCount;
+
+ public:
+
+ FlashPartFileTransferPacket(unsigned short unknown, unsigned int transferCount)
+ : FileTransferPacket(FileTransferPacket::kRequestPart)
+ {
+ this->unknown = unknown;
+ this->transferCount = transferCount;
+ }
+
+ unsigned short GetUnknown(void) const
+ {
+ return (unknown);
+ }
+
+ unsigned int GetTransferCount(void) const
+ {
+ return (transferCount);
+ }
+
+ void Pack(void)
+ {
+ FileTransferPacket::Pack();
+
+ PackShort(FileTransferPacket::kDataSize, unknown);
+ PackInteger(FileTransferPacket::kDataSize + 2, transferCount);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/FlashPartPitFilePacket.h b/heimdall/source/FlashPartPitFilePacket.h
new file mode 100644
index 0000000..3974c3c
--- /dev/null
+++ b/heimdall/source/FlashPartPitFilePacket.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef FLASHPARTPITFILEPACKET_H
+#define FLASHPARTPITFILEPACKET_H
+
+// Heimdall
+#include "PitFilePacket.h"
+
+namespace Heimdall
+{
+ class FlashPartPitFilePacket : public PitFilePacket
+ {
+ private:
+
+ unsigned int partSize;
+
+ public:
+
+ FlashPartPitFilePacket(unsigned int partSize) : PitFilePacket(PitFilePacket::kRequestPart)
+ {
+ this->partSize = partSize;
+ }
+
+ unsigned int GetPartSize(void) const
+ {
+ return (partSize);
+ }
+
+ void Pack(void)
+ {
+ PitFilePacket::Pack();
+
+ PackInteger(PitFilePacket::kDataSize, partSize);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/Heimdall.h b/heimdall/source/Heimdall.h
new file mode 100644
index 0000000..672cf14
--- /dev/null
+++ b/heimdall/source/Heimdall.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef HEIMDALL_H
+#define HEIMDALL_H
+
+#ifdef OS_WINDOWS
+#include <Windows.h>
+#else
+
+#include "../config.h"
+
+#if defined(OS_DARWIN) || defined(OS_LINUX)
+#include <unistd.h>
+#define Sleep(t) usleep(1000*t)
+#else
+#error operating system not supported
+#endif
+
+#endif
+
+#ifndef nullptr
+#define nullptr 0
+#endif
+
+#endif
diff --git a/heimdall/source/InboundPacket.h b/heimdall/source/InboundPacket.h
new file mode 100644
index 0000000..bf393fa
--- /dev/null
+++ b/heimdall/source/InboundPacket.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef INBOUNDPACKET_H
+#define INBOUNDPACKET_H
+
+// Heimdall
+#include "Packet.h"
+
+namespace Heimdall
+{
+ class InboundPacket : public Packet
+ {
+ private:
+
+ bool sizeVariable;
+ unsigned int receivedSize;
+
+ protected:
+
+ int UnpackInteger(int offset)
+ {
+#ifdef PPC
+ int value = (data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3];
+#else
+ // Flip endianness
+ int value = data[offset] | (data[offset + 1] << 8) |
+ (data[offset + 2] << 16) | (data[offset + 3] << 24);
+#endif
+ return (value);
+ }
+
+ public:
+
+ InboundPacket(unsigned int size, bool sizeVariable = false) : Packet(size)
+ {
+ this->sizeVariable = sizeVariable;
+ }
+
+ bool IsSizeVariable(void) const
+ {
+ return (sizeVariable);
+ }
+
+ unsigned int GetReceivedSize(void) const
+ {
+ return (receivedSize);
+ }
+
+ void SetReceivedSize(unsigned int receivedSize)
+ {
+ this->receivedSize = receivedSize;
+ }
+
+ virtual bool Unpack(void) = 0;
+ };
+}
+
+#endif
diff --git a/heimdall/source/InterfaceManager.cpp b/heimdall/source/InterfaceManager.cpp
new file mode 100644
index 0000000..23791bc
--- /dev/null
+++ b/heimdall/source/InterfaceManager.cpp
@@ -0,0 +1,265 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+// C/C++ Standard Library
+#include <cstdarg>
+#include <stdio.h>
+
+// Heimdall
+#include "Heimdall.h"
+#include "InterfaceManager.h"
+
+using namespace std;
+using namespace Heimdall;
+
+string InterfaceManager::actionNames[kActionCount] = { "flash", "close-pc-screen", "dump", "help" };
+
+string InterfaceManager::flashArgumentNames[kFlashArgCount * 2] = {
+ // --- Long Names ---
+ "-repartition",
+
+ "-pit", "-factoryfs", "-cache", "-dbdata", "-primary-boot", "-secondary-boot", "-secondary-boot-backup", "-param", "-kernel", "-recovery", "-efs", "-modem",
+
+ // --- Short Names ---
+ "r",
+
+ "pit", "fs", "cache", "db", "boot", "sbl", "sbl2", "param", "z", "rec", "efs", "m"
+};
+
+string InterfaceManager::dumpArgumentNames[kDumpArgCount * 2] = {
+ // --- Long Names ---
+ "-chip-type", "-chip-id", "-output",
+
+ // --- Short Names ---
+ "type", "id", "out"
+};
+
+string InterfaceManager::commonArgumentNames[kCommonArgCount * 2] = {
+ // --- Long Names ---
+ "-verbose",
+
+ "-delay",
+
+ // --- Short Names ---
+ "v",
+
+ "d"
+};
+
+// argumentNames[kActionCount][] stores common arguments.
+string *InterfaceManager::actionArgumentNames[kActionCount + 1] = {
+ // kActionFlash
+ flashArgumentNames,
+
+ // kActionClosePcScreen
+ nullptr,
+
+ // kActionDump
+ dumpArgumentNames,
+
+ // kActionHelp
+ nullptr,
+
+ // Common (kActionCount)
+ commonArgumentNames
+};
+
+int InterfaceManager::actionArgumentCounts[kActionCount + 1] = {
+ kFlashArgCount, 0, kDumpArgCount, 0, kCommonArgCount
+};
+
+int InterfaceManager::actionValuelessArgumentCounts[kActionCount + 1] = {
+ kFlashArgPit, 0, kDumpArgChipType, 0, kCommonArgDelay
+};
+
+const char *InterfaceManager::usage = "Usage: heimdall <action> <arguments> [--verbose] [--delay <ms>]\n\
+\n\
+action: flash\n\
+arguments:\n\
+ --repartition --pit <filename> --factoryfs <filename>\n\
+ --cache <filename> --dbdata <filename> --primary-boot <filename>\n\
+ --secondary-boot <filename> --param <filename> --kernel <filename>\n\
+ --modem <filename>\n\
+ or:\n\
+ [--pit <filename>] [--factoryfs <filename>] [--cache <filename>]\n\
+ [--dbdata <filename>] [--primary-boot <filename>]\n\
+ [--secondary-boot <filename>] [--secondary-boot-backup <filename>]\n\
+ [--param <filename>] [--kernel <filename>] [--recovery <filename>]\n\
+ [--efs <filename>] [--modem <filename>]\n\
+description: Flashes firmware files to your phone.\n\
+\n\
+action: close-pc-screen\n\
+description: Attempts to get rid off the \"connect phone to PC\" screen.\n\
+\n\
+action: dump\n\
+arguments: --chip-type <NAND | RAM> --chip-id <integer> --output <filename>\n\
+description: Attempts to dump data from the phone corresponding to the\n\
+ specified chip type and chip ID.\n\
+NOTE: Galaxy S phones don't appear to properly support this functionality.\n\
+\n\
+action: help\n\
+description: Display this dialogue.\n";
+
+bool InterfaceManager::GetArguments(int argc, char **argv, map<string, string>& argumentMap, int *actionIndex)
+{
+ if (argc < 2)
+ {
+ Print(usage);
+ return (false);
+ }
+
+ const char *actionName = argv[1];
+ *actionIndex = -1;
+
+ for (int i = 0; i < kActionCount; i++)
+ {
+ if (actionNames[i] == actionName)
+ {
+ *actionIndex = i;
+ break;
+ }
+ }
+
+ if (*actionIndex < 0)
+ {
+ Print("Unknown action \"%s\"\n\n", actionName);
+ Print(usage);
+ return (false);
+ }
+
+ int actionArgumentCount = actionArgumentCounts[*actionIndex];
+ int commonArgumentCount = actionArgumentCounts[kActionCount];
+
+ int actionValuelessArgumentCount = actionValuelessArgumentCounts[*actionIndex];
+ int commonValuelessArgumentCount = actionValuelessArgumentCounts[kActionCount];
+
+ string *argumentNames = actionArgumentNames[*actionIndex];
+ string *commonArgumentNames = actionArgumentNames[kActionCount];
+
+ for (int argIndex = 2; argIndex < argc; argIndex++)
+ {
+ if (*(argv[argIndex]) != '-')
+ {
+ Print(usage);
+ return (false);
+ }
+
+ string argumentName = (char *)(argv[argIndex] + 1);
+
+ // Check if the argument is a valid valueless argument
+ bool valid = false;
+
+ for (int i = 0; i < actionValuelessArgumentCount; i++)
+ {
+ if (argumentName == argumentNames[i] || argumentName == argumentNames[actionArgumentCount + i])
+ {
+ argumentName = argumentNames[i];
+ valid = true;
+ break;
+ }
+ }
+
+ if (!valid)
+ {
+ // Check if it's a common valueless argument
+ for (int i = 0; i < commonValuelessArgumentCount; i++)
+ {
+ if (argumentName == commonArgumentNames[i] || argumentName == commonArgumentNames[commonArgumentCount + i])
+ {
+ argumentName = commonArgumentNames[i];
+ valid = true;
+ break;
+ }
+ }
+ }
+
+ if (valid)
+ {
+ // The argument is valueless
+ argumentMap.insert(pair<string, string>(argumentName, ""));
+ continue;
+ }
+
+ // Check if the argument is a valid regular argument
+ for (int i = actionValuelessArgumentCount; i < actionArgumentCount; i++)
+ {
+ if (argumentName == argumentNames[i] || argumentName == argumentNames[actionArgumentCount + i])
+ {
+ argumentName = argumentNames[i];
+ valid = true;
+ break;
+ }
+ }
+
+ if (!valid)
+ {
+ // Check if it's a common regular argument
+ for (int i = commonValuelessArgumentCount; i < commonArgumentCount; i++)
+ {
+ if (argumentName == commonArgumentNames[i] || argumentName == commonArgumentNames[commonArgumentCount + i])
+ {
+ argumentName = commonArgumentNames[i];
+ valid = true;
+ break;
+ }
+ }
+ }
+
+ if (!valid)
+ {
+ PrintError("\"%s\" is not a valid argument\n", argumentName.c_str());
+ return (false);
+ }
+
+ argIndex++;
+
+ if (argIndex >= argc)
+ {
+ PrintError("\"%s\" is missing a value\n", argumentName.c_str());
+ return (false);
+ }
+
+ argumentMap.insert(pair<string, string>(argumentName, argv[argIndex]));
+ }
+
+ return (true);
+}
+
+void InterfaceManager::Print(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+
+ fflush(stdout); // Make sure output isn't buffered.
+}
+
+void InterfaceManager::PrintError(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+
+ fflush(stderr); // Make sure output isn't buffered.
+}
diff --git a/heimdall/source/InterfaceManager.h b/heimdall/source/InterfaceManager.h
new file mode 100644
index 0000000..734c086
--- /dev/null
+++ b/heimdall/source/InterfaceManager.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef INTERFACEMANAGER_H
+#define INTERFACEMANAGER_H
+
+// C/C++ Standard Library
+#include <map>
+#include <string>
+
+using namespace std;
+
+namespace Heimdall
+{
+ class InterfaceManager
+ {
+ public:
+
+ enum
+ {
+ kActionFlash = 0,
+ kActionClosePcScreen,
+ kActionDump,
+ kActionHelp,
+ kActionCount
+ };
+
+ enum
+ {
+ // Valueless arguments
+ kFlashArgRepartition = 0,
+
+ // Regular arguments
+ kFlashArgPit,
+ kFlashArgFactoryFs,
+ kFlashArgCache,
+ kFlashArgData,
+ kFlashArgPrimaryBootloader,
+ kFlashArgSecondaryBootloader,
+ kFlashArgSecondaryBootloaderBackup,
+ kFlashArgParam,
+ kFlashArgKernel,
+ kFlashArgRecovery,
+ kFlashArgEfs,
+ kFlashArgModem,
+
+ kFlashArgCount
+ };
+
+ enum
+ {
+ // Regular arguments
+ kDumpArgChipType = 0,
+ kDumpArgChipId,
+ kDumpArgOutput,
+
+ kDumpArgCount
+ };
+
+ enum
+ {
+ // Valueless arguments
+ kCommonArgVerbose = 0,
+
+ // Regular arguments
+ kCommonArgDelay,
+
+ kCommonArgCount
+ };
+
+ static string actionNames[kActionCount];
+
+ static string flashArgumentNames[kFlashArgCount * 2];
+ static string dumpArgumentNames[kDumpArgCount * 2];
+ static string commonArgumentNames[kCommonArgCount * 2];
+
+ // argumentNames[kActionCount][] defines common arguments.
+ static string *actionArgumentNames[kActionCount + 1];
+
+ static int actionArgumentCounts[kActionCount + 1];
+ static int actionValuelessArgumentCounts[kActionCount + 1];
+
+ static const char *usage;
+
+ static bool GetArguments(int argc, char **argv, map<string, string>& argumentMap, int *actionIndex);
+
+ static void Print(const char *format, ...);
+ static void PrintError(const char *format, ...);
+ };
+}
+
+#endif
diff --git a/heimdall/source/OutboundPacket.h b/heimdall/source/OutboundPacket.h
new file mode 100644
index 0000000..d433d84
--- /dev/null
+++ b/heimdall/source/OutboundPacket.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef OUTBOUNDPACKET_H
+#define OUTBOUNDPACKET_H
+
+// Heimdall include
+#include "Packet.h"
+
+namespace Heimdall
+{
+ class OutboundPacket : public Packet
+ {
+ protected:
+
+ void PackInteger(unsigned int offset, unsigned int value)
+ {
+#ifdef PPC
+ data[offset] = (value & 0xFF000000) >> 24;
+ data[offset + 1] = (value & 0x00FF0000) >> 16;
+ data[offset + 2] = (value & 0x0000FF00) >> 8;
+ data[offset + 3] = value & 0x000000FF;
+#else
+ // Flip endianness
+ data[offset] = value & 0x000000FF;
+ data[offset + 1] = (value & 0x0000FF00) >> 8;
+ data[offset + 2] = (value & 0x00FF0000) >> 16;
+ data[offset + 3] = (value & 0xFF000000) >> 24;
+#endif
+ }
+
+ void PackShort(unsigned int offset, unsigned short value)
+ {
+#ifdef PPC
+ data[offset] = (value & 0xFF00) >> 8;
+ data[offset + 1] = value & 0x00FF;
+#else
+ // Flip endianness
+ data[offset] = value & 0x00FF;
+ data[offset + 1] = (value & 0xFF00) >> 8;
+#endif
+ }
+
+ public:
+
+ OutboundPacket(unsigned int size) : Packet(size)
+ {
+ }
+
+ virtual void Pack(void) = 0;
+ };
+}
+
+#endif
diff --git a/heimdall/source/Packet.h b/heimdall/source/Packet.h
new file mode 100644
index 0000000..33469f1
--- /dev/null
+++ b/heimdall/source/Packet.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef PACKET_H
+#define PACKET_H
+
+// C++ Standard Library
+#include <cstring>
+
+namespace Heimdall
+{
+ class Packet
+ {
+ private:
+
+ unsigned int size;
+
+ protected:
+
+ unsigned char *data;
+
+ public:
+
+ Packet(unsigned int size)
+ {
+ this->size = size;
+ data = new unsigned char[size];
+ memset(data, 0, size);
+ }
+
+ ~Packet()
+ {
+ delete [] data;
+ }
+
+ int GetSize(void) const
+ {
+ return (size);
+ }
+
+ unsigned char *GetData(void)
+ {
+ return (data);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/PitFilePacket.h b/heimdall/source/PitFilePacket.h
new file mode 100644
index 0000000..d23314e
--- /dev/null
+++ b/heimdall/source/PitFilePacket.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef PITFILEPACKET_H
+#define PITFILEPACKET_H
+
+// Heimdall
+#include "ControlPacket.h"
+
+namespace Heimdall
+{
+ class PitFilePacket : public ControlPacket
+ {
+ public:
+
+ enum
+ {
+ kRequestFlash = 0x00,
+ kRequestDump = 0x01,
+ kRequestPart = 0x02,
+ kRequestEndTransfer = 0x03
+ };
+
+ protected:
+
+ enum
+ {
+ kDataSize = ControlPacket::kDataSize + 4
+ };
+
+ private:
+
+ unsigned int request;
+
+ public:
+
+ PitFilePacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypePitFile)
+ {
+ this->request = request;
+ }
+
+ unsigned int GetRequest(void) const
+ {
+ return (request);
+ }
+
+ void Pack(void)
+ {
+ ControlPacket::Pack();
+
+ PackInteger(ControlPacket::kDataSize, request);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/PitFileResponse.h b/heimdall/source/PitFileResponse.h
new file mode 100644
index 0000000..bf8f6f6
--- /dev/null
+++ b/heimdall/source/PitFileResponse.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef PITFILERESPONSE_H
+#define PITFILERESPONSE_H
+
+// Heimdall
+#include "ResponsePacket.h"
+
+namespace Heimdall
+{
+ class PitFileResponse : public ResponsePacket
+ {
+ private:
+
+ unsigned int fileSize;
+
+ public:
+
+ PitFileResponse() : ResponsePacket(ResponsePacket::kResponseTypePitFile)
+ {
+ }
+
+ unsigned int GetFileSize(void) const
+ {
+ return (fileSize);
+ }
+
+ bool Unpack(void)
+ {
+ if (!ResponsePacket::Unpack())
+ return (false);
+
+ fileSize = UnpackInteger(ResponsePacket::kDataSize);
+
+ return (true);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/RebootDevicePacket.h b/heimdall/source/RebootDevicePacket.h
new file mode 100644
index 0000000..f40a227
--- /dev/null
+++ b/heimdall/source/RebootDevicePacket.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef REBOOTDEVICEPACKET_H
+#define REBOOTDEVICEPACKET_H
+
+// Heimdall
+#include "ControlPacket.h"
+
+namespace Heimdall
+{
+ class RebootDevicePacket : public ControlPacket
+ {
+ public:
+
+ enum
+ {
+ kRequestEndSession = 0,
+ kRequestRebootDevice = 1
+ };
+
+ private:
+
+ unsigned int request;
+
+ public:
+
+ RebootDevicePacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeRebootDevice)
+ {
+ this->request = request;
+ }
+
+ unsigned int GetRequest(void) const
+ {
+ return (request);
+ }
+
+ void Pack(void)
+ {
+ ControlPacket::Pack();
+
+ PackInteger(ControlPacket::kDataSize, request);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/ReceiveFilePartPacket.h b/heimdall/source/ReceiveFilePartPacket.h
new file mode 100644
index 0000000..5671ed4
--- /dev/null
+++ b/heimdall/source/ReceiveFilePartPacket.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef RECEIVEFILEPARTPACKET_H
+#define RECEIVEFILEPARTPACKET_H
+
+// Heimdall
+#include "InboundPacket.h"
+
+namespace Heimdall
+{
+ class ReceiveFilePartPacket : public InboundPacket
+ {
+ public:
+
+ enum
+ {
+ kDataSize = 500
+ };
+
+ ReceiveFilePartPacket() : InboundPacket(kDataSize, true)
+ {
+ }
+
+ bool Unpack(void)
+ {
+ return (true);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/ResponsePacket.h b/heimdall/source/ResponsePacket.h
new file mode 100644
index 0000000..ce799b5
--- /dev/null
+++ b/heimdall/source/ResponsePacket.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef RESPONSEPACKET_H
+#define RESPONSEPACKET_H
+
+// Heimdall
+#include "InboundPacket.h"
+
+namespace Heimdall
+{
+ class ResponsePacket : public InboundPacket
+ {
+ public:
+
+ enum
+ {
+ kResponseTypeSendFilePart = 0x00,
+ kResponseTypeDeviceInfo = 0x64,
+ kResponseTypePitFile = 0x65,
+ kResponseTypeFileTransfer = 0x66,
+ kResponseTypeRebootDevice = 0x67
+ };
+
+ private:
+
+ unsigned int responseType;
+
+ protected:
+
+ enum
+ {
+ kDataSize = 4
+ };
+
+ public:
+
+ ResponsePacket(int responseType) : InboundPacket(8)
+ {
+ this->responseType = responseType;
+ }
+
+ unsigned int GetResponseType(void) const
+ {
+ return (responseType);
+ }
+
+ virtual bool Unpack(void)
+ {
+ const unsigned char *data = GetData();
+
+ unsigned int receivedResponseType = UnpackInteger(0);
+ if (receivedResponseType != responseType)
+ {
+ responseType = receivedResponseType;
+ return (false);
+ }
+
+ return (true);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/SendFilePartPacket.h b/heimdall/source/SendFilePartPacket.h
new file mode 100644
index 0000000..0b41830
--- /dev/null
+++ b/heimdall/source/SendFilePartPacket.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef SENDFILEPARTPACKET_H
+#define SENDFILEPARTPACKET_H
+
+// C Standard Library
+#include <stdio.h>
+#include <string.h>
+
+// Heimdall
+#include "Packet.h"
+
+namespace Heimdall
+{
+ class SendFilePartPacket : public OutboundPacket
+ {
+ public:
+
+ enum
+ {
+ kDefaultPacketSize = 131072
+ };
+
+ SendFilePartPacket(FILE *file, int size = SendFilePartPacket::kDefaultPacketSize) : OutboundPacket(size)
+ {
+ memset(data, 0, size);
+
+ long position = ftell(file);
+
+ fseek(file, 0, SEEK_END);
+ long fileSize = ftell(file);
+ fseek(file, position, SEEK_SET);
+
+ // min(fileSize, size)
+ int bytesToRead = (fileSize < size) ? fileSize - position : size;
+ fread(data, 1, bytesToRead, file);
+ }
+
+ void Pack(void)
+ {
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/SendFilePartResponse.h b/heimdall/source/SendFilePartResponse.h
new file mode 100644
index 0000000..ba6eb6b
--- /dev/null
+++ b/heimdall/source/SendFilePartResponse.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef SENDFILEPARTRESPONSE_H
+#define SENDFILEPARTRESPONSE_H
+
+// Heimdall
+#include "ResponsePacket.h"
+
+namespace Heimdall
+{
+ class SendFilePartResponse : public ResponsePacket
+ {
+ private:
+
+ unsigned int partIndex;
+
+ public:
+
+ SendFilePartResponse() : ResponsePacket(ResponsePacket::kResponseTypeSendFilePart)
+ {
+ }
+
+ unsigned int GetPartIndex(void) const
+ {
+ return (partIndex);
+ }
+
+ bool Unpack(void)
+ {
+ if (!ResponsePacket::Unpack())
+ return (false);
+
+ partIndex = UnpackInteger(ResponsePacket::kDataSize);
+
+ return (true);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/main.cpp b/heimdall/source/main.cpp
new file mode 100644
index 0000000..037d097
--- /dev/null
+++ b/heimdall/source/main.cpp
@@ -0,0 +1,660 @@
+/* Copyright (c) 2010 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+// C/C++ Standard Library
+#include <algorithm>
+#include <map>
+#include <stdio.h>
+#include <string>
+
+// Heimdall
+#include "BridgeManager.h"
+#include "DeviceInfoPacket.h"
+#include "DeviceInfoResponse.h"
+#include "EndModemFileTransferPacket.h"
+#include "EndPhoneFileTransferPacket.h"
+#include "InterfaceManager.h"
+
+using namespace std;
+using namespace Heimdall;
+
+enum
+{
+ kFilePit = 0,
+ kFileFactoryFs,
+ kFileCache,
+ kFileData,
+ kFilePrimaryBootloader,
+ kFileSecondaryBootloader,
+ kFileSecondaryBootloaderBackup,
+ kFileParam,
+ kFileKernel,
+ kFileRecovery,
+ kFileEfs,
+ kFileModem,
+ kFileCount
+};
+
+bool flashFile(BridgeManager *bridgeManager, FILE *file, int fileIndex)
+{
+ switch (fileIndex)
+ {
+ case kFilePit:
+
+ InterfaceManager::Print("Uploading PIT file\n");
+ if (bridgeManager->SendPitFile(file))
+ {
+ InterfaceManager::Print("PIT file upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("PIT file upload failed!\n");
+ return (false);
+ }
+
+ case kFileFactoryFs:
+
+ InterfaceManager::Print("Uploading factory filesytem\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileFactoryFilesystem))
+ {
+ InterfaceManager::Print("Factory filesytem upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Factory filesytem upload failed!\n");
+ return (false);
+ }
+
+ case kFileCache:
+
+ InterfaceManager::Print("Uploading cache\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileCache))
+ {
+ InterfaceManager::Print("Cache upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Cache upload failed!\n");
+ return (false);
+ }
+
+ case kFileData:
+
+ InterfaceManager::Print("Uploading data database\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileDatabaseData))
+ {
+ InterfaceManager::Print("Data database upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Data database upload failed!\n");
+ return (false);
+ }
+
+ case kFilePrimaryBootloader:
+
+ InterfaceManager::Print("Uploading primary bootloader\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFilePrimaryBootloader))
+ {
+ InterfaceManager::Print("Primary bootloader upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Primary bootloader upload failed!\n");
+ return (false);
+ }
+
+ case kFileSecondaryBootloader:
+
+ InterfaceManager::Print("Uploading secondary bootloader\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileSecondaryBootloader))
+ {
+ InterfaceManager::Print("Secondary bootloader upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Secondary bootloader upload failed!\n");
+ return (false);
+ }
+
+ case kFileSecondaryBootloaderBackup:
+
+ InterfaceManager::Print("Uploading backup secondary bootloader\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileSecondaryBootloaderBackup))
+ {
+ InterfaceManager::Print("Backup secondary bootloader upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Backup secondary bootloader upload failed!\n");
+ return (false);
+ }
+
+ case kFileParam:
+ InterfaceManager::Print("Uploading param.lfs\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileParamLfs))
+ {
+ InterfaceManager::Print("param.lfs upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("param.lfs upload failed!\n");
+ return (false);
+ }
+
+ case kFileKernel:
+
+ InterfaceManager::Print("Uploading kernel\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileKernel))
+ {
+ InterfaceManager::Print("Kernel upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Kernel upload failed!\n");
+ return (false);
+ }
+
+ case kFileModem:
+
+ InterfaceManager::Print("Uploading modem\n");
+
+ /*if (bridgeManager->SendFile(file, EndModemFileTransferPacket::kDestinationModem))*/ // <-- Odin method
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, // <-- Kies method
+ EndPhoneFileTransferPacket::kFileModem))
+ {
+ InterfaceManager::Print("Modem upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Modem upload failed!\n");
+ return (false);
+ }
+
+ case kFileRecovery:
+
+ InterfaceManager::Print("Uploading recovery\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileRecovery))
+ {
+ InterfaceManager::Print("Recovery upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("Recovery upload failed!\n");
+ return (false);
+ }
+
+ case kFileEfs:
+
+ InterfaceManager::Print("Uploading EFS\n");
+ if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone,
+ EndPhoneFileTransferPacket::kFileEfs))
+ {
+ InterfaceManager::Print("EFS upload successful\n");
+ return (true);
+ }
+ else
+ {
+ InterfaceManager::PrintError("EFS upload failed!\n");
+ return (false);
+ }
+
+ default:
+
+ InterfaceManager::PrintError("ERROR: Attempted to flash unknown file!\n");
+ return (false);
+ }
+}
+
+bool attemptFlash(BridgeManager *bridgeManager, FILE **fileArray, bool repartition)
+{
+ bool success;
+
+ // ---------- GET DEVICE INFORMATION ----------
+
+ DeviceInfoPacket *deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kUnknown1);
+ success = bridgeManager->SendPacket(deviceInfoPacket);
+ delete deviceInfoPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send device info packet!\nFailed Request: kUnknown1\n");
+ return (false);
+ }
+
+ DeviceInfoResponse *deviceInfoResponse = new DeviceInfoResponse();
+ success = bridgeManager->ReceivePacket(deviceInfoResponse);
+ int unknown = deviceInfoResponse->GetUnknown();
+ delete deviceInfoResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive device info response!\n");
+ return (false);
+ }
+
+ if (unknown != 0)
+ {
+ InterfaceManager::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", unknown);
+
+ if (!bridgeManager->EndSession())
+ return (false);
+ bridgeManager->RebootDevice();
+
+ return (false);
+ }
+
+ // -------------------- KIES DOESN'T DO THIS --------------------
+ deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kUnknown2);
+ success = bridgeManager->SendPacket(deviceInfoPacket);
+ delete deviceInfoPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send device info packet!\nFailed Request: kUnknown2\n");
+ return (false);
+ }
+
+ deviceInfoResponse = new DeviceInfoResponse();
+ success = bridgeManager->ReceivePacket(deviceInfoResponse);
+ unknown = deviceInfoResponse->GetUnknown();
+ delete deviceInfoResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive device info response!\n");
+ return (false);
+ }
+
+ // TODO: Work out what this value is... it has been either 180 or 0 for Galaxy S phones, and 3 on the Galaxy Tab.
+ if (unknown != 180 && unknown != 0 && unknown != 3)
+ {
+ InterfaceManager::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%i\n", unknown);
+
+ if (!bridgeManager->EndSession())
+ return (false);
+ bridgeManager->RebootDevice();
+
+ return (false);
+ }
+ // --------------------------------------------------------------
+
+ int totalBytes = 0;
+ for (int i = kFileFactoryFs; i < kFileCount; i++)
+ {
+ if (fileArray[i])
+ {
+ fseek(fileArray[i], 0, SEEK_END);
+ totalBytes += ftell(fileArray[i]);
+ rewind(fileArray[i]);
+ }
+ }
+
+ if (repartition)
+ {
+ // When repartitioning we send the PIT file to the device.
+ fseek(fileArray[kFilePit], 0, SEEK_END);
+ totalBytes += ftell(fileArray[kFilePit]);
+ rewind(fileArray[kFilePit]);
+ }
+
+ deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kTotalBytes, totalBytes);
+ success = bridgeManager->SendPacket(deviceInfoPacket);
+ delete deviceInfoPacket;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to send total bytes device info packet!\n");
+ return (false);
+ }
+
+ deviceInfoResponse = new DeviceInfoResponse();
+ success = bridgeManager->ReceivePacket(deviceInfoResponse);
+ unknown = deviceInfoResponse->GetUnknown();
+ delete deviceInfoResponse;
+
+ if (!success)
+ {
+ InterfaceManager::PrintError("Failed to receive device info response!\n");
+ return (false);
+ }
+
+ if (unknown != 0)
+ {
+ InterfaceManager::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", unknown);
+
+ if (!bridgeManager->EndSession())
+ return (false);
+ bridgeManager->RebootDevice();
+
+ return (false);
+ }
+
+ // -----------------------------------------------------
+
+ if (fileArray[kFilePit])
+ {
+ if (repartition)
+ {
+ flashFile(bridgeManager, fileArray[kFilePit], kFilePit);
+ }
+ else // We're performing a PIT check
+ {
+ // Load the local pit file into memory.
+ char *localPit = new char[4096];
+ memset(localPit, 0, 4096);
+
+ fseek(fileArray[kFilePit], 0, SEEK_END);
+ long localPitFileSize = ftell(fileArray[kFilePit]);
+ rewind(fileArray[kFilePit]);
+
+ fread(localPit, 1, localPitFileSize, fileArray[kFilePit]);
+
+ InterfaceManager::Print("Downloading device's PIT file...\n");
+
+ unsigned char *devicePit;
+ int devicePitFileSize = bridgeManager->ReceivePitFile(&devicePit);
+
+ if (!devicePit)
+ {
+ InterfaceManager::PrintError("Failed to download PIT file!\n");
+
+ if (!bridgeManager->EndSession())
+ return (false);
+ bridgeManager->RebootDevice();
+
+ return (false);
+ }
+
+ InterfaceManager::Print("PIT file download sucessful\n\n");
+
+ bool pitFilesMatch = !memcmp(localPit, devicePit, localPitFileSize);
+
+ delete [] localPit;
+ delete [] devicePit;
+
+ if (!pitFilesMatch)
+ {
+ InterfaceManager::Print("Optional PIT check failed! To disable this check don't use the --pit parameter.");
+
+ if (!bridgeManager->EndSession())
+ return (false);
+ bridgeManager->RebootDevice();
+
+ return (false);
+ }
+ }
+ }
+
+ // Flash specified files
+ for (int fileIndex = kFileFactoryFs; fileIndex < kFileCount; fileIndex++)
+ {
+ if (fileArray[fileIndex])
+ {
+ if (!flashFile(bridgeManager, fileArray[fileIndex], fileIndex))
+ return (false);
+ }
+ }
+
+ return (bridgeManager->EndSession() && bridgeManager->RebootDevice());
+}
+
+bool openFiles(const map<string, string>& argumentMap, FILE **fileArray)
+{
+ for (int fileIndex = 0; fileIndex < kFileCount; fileIndex++)
+ {
+ // kFlashArgPit + kFile<Name> == kFlashArg<Name>
+ map<string, string>::const_iterator it = argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit + fileIndex]);
+ if (it == argumentMap.end())
+ continue;
+
+ fileArray[fileIndex] = fopen(it->second.c_str(), "rb");
+ if (!fileArray[fileIndex])
+ {
+ InterfaceManager::PrintError("Failed to open file \"%s\"\n", it->second.c_str());
+ return (false);
+ }
+ }
+
+ return (true);
+}
+
+void closeFiles(FILE **fileArray)
+{
+ for (int fileIndex = 0; fileIndex < kFileCount; fileIndex++)
+ {
+ if (fileArray[fileIndex] != nullptr)
+ fclose(fileArray[fileIndex]);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ map<string, string> argumentMap;
+ int actionIndex;
+
+ if (!InterfaceManager::GetArguments(argc, argv, argumentMap, &actionIndex))
+ {
+ Sleep(1000);
+ return (0);
+ }
+
+ if (actionIndex == InterfaceManager::kActionHelp)
+ {
+ InterfaceManager::Print(InterfaceManager::usage);
+ return (0);
+ }
+ else if (actionIndex == InterfaceManager::kActionFlash)
+ {
+ if (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end()
+ && (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgFactoryFs]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgCache]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgData]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPrimaryBootloader]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgSecondaryBootloader]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgParam]) == argumentMap.end()
+ || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgKernel]) == argumentMap.end()))
+ {
+ InterfaceManager::Print("If you wish to repartition then factoryfs, cache, dbdata, primary and secondary\nbootloaders, param, kernel and a PIT file must all be specified.\n");
+ return (0);
+ }
+ }
+ else if (actionIndex == InterfaceManager::kActionDump)
+ {
+ if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgOutput]) == argumentMap.end())
+ {
+ InterfaceManager::Print("Output file not specified.\n\n");
+ InterfaceManager::Print(InterfaceManager::usage);
+ return (0);
+ }
+
+ if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType]) == argumentMap.end())
+ {
+ InterfaceManager::Print("You must specify a chip type.\n\n");
+ InterfaceManager::Print(InterfaceManager::usage);
+ return (0);
+ }
+
+ string chipType = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType])->second;
+ if (!(chipType == "RAM" || chipType == "ram" || chipType == "NAND" || chipType == "nand"))
+ {
+ InterfaceManager::Print("Unknown chip type: %s.\n\n", chipType.c_str());
+ InterfaceManager::Print(InterfaceManager::usage);
+ return (0);
+ }
+
+ if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId]) == argumentMap.end())
+ {
+ InterfaceManager::Print("You must specify a Chip ID.\n\n");
+ InterfaceManager::Print(InterfaceManager::usage);
+ return (0);
+ }
+
+ int chipId = atoi(argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId])->second.c_str());
+ if (chipId < 0)
+ {
+ InterfaceManager::Print("Chip ID must be a non-negative integer.\n");
+ return (0);
+ }
+ }
+
+ InterfaceManager::Print("\nHeimdall, Copyright (c) 2010, Benjamin Dobell, Glass Echidna\n");
+ InterfaceManager::Print("http://www.glassechidna.com.au\n\n");
+ InterfaceManager::Print("This software is provided free of charge. Copying and redistribution is\nencouraged.\n\n");
+ InterfaceManager::Print("If you appreciate this software and you would like to support future\ndevelopment please consider donating:\n");
+ InterfaceManager::Print("http://www.glassechidna.com.au/donate/\n\n");
+
+ Sleep(1000);
+
+ bool verbose = argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgVerbose]) != argumentMap.end();
+
+ int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+ if (argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgDelay]) != argumentMap.end())
+ communicationDelay = atoi(argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgDelay])->second.c_str());
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
+
+ if (!bridgeManager->Initialise())
+ {
+ delete bridgeManager;
+ return (-2);
+ }
+
+ bool success;
+
+ switch (actionIndex)
+ {
+ case InterfaceManager::kActionFlash:
+ {
+ FILE **fileArray = new FILE *[kFileCount];
+ for (int i = 0; i < kFileCount; i++)
+ fileArray[i] = nullptr;
+
+ // We open the files before doing anything else to ensure they exist.
+ if (!openFiles(argumentMap, fileArray))
+ {
+ closeFiles(fileArray);
+ delete [] fileArray;
+
+ delete bridgeManager;
+
+ return (0);
+ }
+
+ if (!bridgeManager->BeginSession())
+ {
+ closeFiles(fileArray);
+ delete [] fileArray;
+
+ delete bridgeManager;
+
+ return (-1);
+ }
+
+ bool repartition = argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end();
+ success = attemptFlash(bridgeManager, fileArray, repartition);
+
+ closeFiles(fileArray);
+ delete [] fileArray;
+
+ break;
+ }
+
+ case InterfaceManager::kActionClosePcScreen:
+ {
+ if (!bridgeManager->BeginSession())
+ {
+ delete bridgeManager;
+ return (-1);
+ }
+
+ InterfaceManager::Print("Attempting to close connect to pc screen...\n");
+ success = bridgeManager->EndSession() && bridgeManager->RebootDevice();
+
+ if (success)
+ InterfaceManager::Print("Attempt complete\n");
+
+ break;
+ }
+
+ case InterfaceManager::kActionDump:
+ {
+ const char *outputFilename = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgOutput])->second.c_str();
+ FILE *dumpFile = fopen(outputFilename, "wb");
+ if (!dumpFile)
+ {
+ InterfaceManager::PrintError("Failed to open file \"%s\"\n", outputFilename);
+
+ delete bridgeManager;
+ return (-1);
+ }
+
+ int chipType = 0;
+ string chipTypeName = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType])->second;
+ if (chipTypeName == "NAND" || chipTypeName == "nand")
+ chipType = 1;
+
+ int chipId = atoi(argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId])->second.c_str());
+
+ if (!bridgeManager->BeginSession())
+ {
+ fclose(dumpFile);
+
+ delete bridgeManager;
+
+ return (-1);
+ }
+
+ success = bridgeManager->ReceiveDump(chipType, chipId, dumpFile);
+
+ fclose(dumpFile);
+
+ if (success)
+ success = bridgeManager->EndSession() && bridgeManager->RebootDevice();
+
+ break;
+ }
+ }
+
+ delete bridgeManager;
+
+ return ((success) ? 0 : -1);
+} \ No newline at end of file