mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-14 03:16:40 +10:00
Add preliminary SimpleIO support
This commit is contained in:
@@ -33,7 +33,7 @@ namespace WPinternals.Config
|
||||
internal const bool IsPrerelease = false;
|
||||
#endif
|
||||
|
||||
internal static readonly DateTime ExpirationDate = new(2026, 4, 1);
|
||||
internal static readonly DateTime ExpirationDate = new(2027, 4, 1);
|
||||
|
||||
internal static void CheckExpiration()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2026 The DuoWOA authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
using MadWizard.WinUSBNet;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Resources;
|
||||
using System.Text;
|
||||
|
||||
namespace WPinternals.Models.SimpleIO
|
||||
{
|
||||
public partial class SimpleIOModel : IDisposable
|
||||
{
|
||||
// TODO: Use Locks!
|
||||
// TODO: Timeouts!!
|
||||
// TODO: Handle timeout
|
||||
// TODO: Check functionality on true proto
|
||||
// TODO: WIM Transfers!
|
||||
// TODO: FFU Transfers!
|
||||
// TODO: Missing command implementations nowhere to be found!
|
||||
|
||||
private bool Disposed = false;
|
||||
private readonly USBDevice USBDevice;
|
||||
private readonly USBPipe InputPipe;
|
||||
private readonly USBPipe OutputPipe;
|
||||
private readonly object UsbLock = new();
|
||||
|
||||
private bool HasCachedV2Results = false;
|
||||
private (long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) CachedV2Results = (0, new Guid(), false, false, 0, new Guid(), "");
|
||||
|
||||
public SimpleIOModel(string DevicePath)
|
||||
{
|
||||
USBDevice = new USBDevice(DevicePath);
|
||||
|
||||
// LineSetState, 1
|
||||
// Not sure why this is needed
|
||||
byte LineSetState = 34;
|
||||
USBDevice.ControlOut(33, LineSetState, 1, 0);
|
||||
|
||||
foreach (USBPipe Pipe in USBDevice.Pipes)
|
||||
{
|
||||
if (Pipe.IsIn)
|
||||
{
|
||||
InputPipe = Pipe;
|
||||
}
|
||||
|
||||
if (Pipe.IsOut)
|
||||
{
|
||||
OutputPipe = Pipe;
|
||||
}
|
||||
}
|
||||
|
||||
if (InputPipe == null || OutputPipe == null)
|
||||
{
|
||||
throw new Exception("Invalid USB device!");
|
||||
}
|
||||
}
|
||||
|
||||
public byte[]? ExecuteRawMethod(byte[] RawMethod)
|
||||
{
|
||||
return ExecuteRawMethod(RawMethod, RawMethod.Length);
|
||||
}
|
||||
|
||||
public byte[]? ExecuteRawMethod(byte[] RawMethod, int Length)
|
||||
{
|
||||
byte[] Buffer = new byte[0xF000]; // Should be at least 0x4408 for receiving the GPT packet.
|
||||
byte[]? Result = null;
|
||||
lock (UsbLock)
|
||||
{
|
||||
OutputPipe.Write(RawMethod, 0, Length);
|
||||
try
|
||||
{
|
||||
int OutputLength = InputPipe.Read(Buffer);
|
||||
Result = new byte[OutputLength];
|
||||
System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength);
|
||||
}
|
||||
catch { } // Reboot command looses connection
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void ExecuteRawVoidMethod(byte[] RawMethod)
|
||||
{
|
||||
ExecuteRawVoidMethod(RawMethod, RawMethod.Length);
|
||||
}
|
||||
|
||||
public void ExecuteRawVoidMethod(byte[] RawMethod, int Length)
|
||||
{
|
||||
lock (UsbLock)
|
||||
{
|
||||
OutputPipe.Write(RawMethod, 0, Length);
|
||||
}
|
||||
}
|
||||
|
||||
public (long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) GetIdV2()
|
||||
{
|
||||
if (HasCachedV2Results)
|
||||
{
|
||||
return CachedV2Results;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
|
||||
(long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) ID;
|
||||
|
||||
do
|
||||
{
|
||||
ID = GetId();
|
||||
num++;
|
||||
}
|
||||
while (!ID.supportsFastFlash && !ID.supportsCompatFastFlash && ID.clientVersion < 2 && num < COMPATFLASH_MagicSequence);
|
||||
|
||||
CachedV2Results = ID;
|
||||
HasCachedV2Results = true;
|
||||
|
||||
return ID;
|
||||
}
|
||||
|
||||
private const int COMPATFLASH_MagicSequence = 1000;
|
||||
|
||||
private const byte INDEX_SUPPORTCOMPATFLASH = 15;
|
||||
private const byte INDEX_SUPPORTV2CMDS = 14;
|
||||
private const byte INDEX_SUPPORTFASTFLASH = 0;
|
||||
|
||||
// 1
|
||||
public (long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) GetId()
|
||||
{
|
||||
bool supportsFastFlash = false;
|
||||
bool supportsCompatFastFlash = false;
|
||||
int clientVersion = 1;
|
||||
|
||||
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioId])!;
|
||||
using MemoryStream stream = new(buffer);
|
||||
using BinaryReader binaryReader = new(stream);
|
||||
|
||||
long curPosition = binaryReader.ReadInt64();
|
||||
byte[] guidBuffer = binaryReader.ReadBytes(16);
|
||||
Guid guid = new(guidBuffer);
|
||||
|
||||
if (guidBuffer[INDEX_SUPPORTFASTFLASH] >= 1)
|
||||
{
|
||||
supportsFastFlash = true;
|
||||
}
|
||||
else if (guidBuffer[INDEX_SUPPORTCOMPATFLASH] == 1)
|
||||
{
|
||||
supportsCompatFastFlash = true;
|
||||
}
|
||||
|
||||
if (guidBuffer[INDEX_SUPPORTV2CMDS] >= 1)
|
||||
{
|
||||
clientVersion = guidBuffer[INDEX_SUPPORTV2CMDS] + 1;
|
||||
}
|
||||
|
||||
Guid DeviceUniqueID = new(binaryReader.ReadBytes(16));
|
||||
string DeviceFriendlyName = binaryReader.ReadString();
|
||||
|
||||
return (curPosition, guid, supportsFastFlash, supportsCompatFastFlash, clientVersion, DeviceUniqueID, DeviceFriendlyName);
|
||||
}
|
||||
|
||||
// 7
|
||||
public bool ContinueBoot()
|
||||
{
|
||||
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioSkip])!;
|
||||
return buffer[0] == 3;
|
||||
}
|
||||
|
||||
// 8
|
||||
public bool EndTransfer()
|
||||
{
|
||||
HasCachedV2Results = false;
|
||||
GetIdV2();
|
||||
|
||||
if (CachedV2Results.curPosition == 0L)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioSkip]);
|
||||
|
||||
byte[] array = new byte[16376];
|
||||
do
|
||||
{
|
||||
InputPipe.Read(array, 0, array.Length);
|
||||
}
|
||||
while (array[0] == 5);
|
||||
|
||||
if (array[0] == 6)
|
||||
{
|
||||
HasCachedV2Results = false;
|
||||
GetIdV2();
|
||||
if (CachedV2Results.curPosition == 0L)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 9
|
||||
public void FlashDataFile(string path)
|
||||
{
|
||||
/*string fileName = Path.GetFileName(path);
|
||||
this.InitFlashingStream();*/
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioFile]);
|
||||
/*this.packets.DataStream = this.GetStringStream(fileName);
|
||||
this.TransferPackets(false);
|
||||
this.WaitForEndResponse(false);
|
||||
this.packets.DataStream = this.GetBufferedFileStream(path);
|
||||
this.TransferPackets(false);
|
||||
this.WaitForEndResponse(false);*/
|
||||
}
|
||||
|
||||
// 10
|
||||
public void Reboot()
|
||||
{
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioReboot]);
|
||||
}
|
||||
|
||||
// 11
|
||||
public bool EnterMassStorage()
|
||||
{
|
||||
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioMassStorage])!;
|
||||
return buffer[0] == 3;
|
||||
}
|
||||
|
||||
// 12
|
||||
public void ReadDiskInfo(out int transferSize, out uint blockSize, out ulong lastBlock)
|
||||
{
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioGetDiskInfo]);
|
||||
|
||||
byte[] array = new byte[16];
|
||||
lock (UsbLock)
|
||||
{
|
||||
InputPipe.Read(array, 0, array.Length);
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
transferSize = BitConverter.ToInt32(array, num);
|
||||
num += 4;
|
||||
blockSize = BitConverter.ToUInt32(array, num);
|
||||
num += 4;
|
||||
lastBlock = BitConverter.ToUInt64(array, num);
|
||||
num += 8;
|
||||
}
|
||||
|
||||
// 13
|
||||
public void ReadDataToBuffer(ulong diskOffset, byte[] buffer, int offset, int count, int diskTransferSize)
|
||||
{
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioReadDisk]);
|
||||
byte[] buffer1 = new byte[16];
|
||||
BitConverter.GetBytes(diskOffset).CopyTo(buffer1, 0);
|
||||
BitConverter.GetBytes((ulong)count).CopyTo(buffer1, 8);
|
||||
ExecuteRawVoidMethod(buffer1);
|
||||
|
||||
int offset1 = offset;
|
||||
int count1;
|
||||
for (int index = offset + count; offset1 < index; offset1 += count1)
|
||||
{
|
||||
count1 = diskTransferSize;
|
||||
if (count1 > index - offset1)
|
||||
{
|
||||
count1 = index - offset1;
|
||||
}
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
InputPipe.Read(buffer, offset1, count1);
|
||||
}
|
||||
|
||||
byte[] singlebyte = new byte[1];
|
||||
if (count1 % 512 == 0)
|
||||
{
|
||||
lock (UsbLock)
|
||||
{
|
||||
//InputPipe.Read(singlebyte, 0, singlebyte.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 14
|
||||
public bool WriteDataFromBuffer(ulong diskOffset, byte[] buffer, int offset, int count, int diskTransferSize)
|
||||
{
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioWriteDisk]);
|
||||
|
||||
byte[] array = new byte[16];
|
||||
BitConverter.GetBytes(diskOffset).CopyTo(array, 0);
|
||||
BitConverter.GetBytes((ulong)((long)count)).CopyTo(array, 8);
|
||||
ExecuteRawVoidMethod(array);
|
||||
|
||||
int i = offset;
|
||||
int num2 = offset + count;
|
||||
|
||||
while (i < num2)
|
||||
{
|
||||
int num3 = diskTransferSize;
|
||||
if (num3 > num2 - i)
|
||||
{
|
||||
num3 = num2 - i;
|
||||
}
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
OutputPipe.Write(buffer, i, num3);
|
||||
}
|
||||
|
||||
if (num3 % 512 == 0)
|
||||
{
|
||||
byte[] array2 = [];
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
OutputPipe.Write(array2, 0, array2.Length);
|
||||
}
|
||||
}
|
||||
i += num3;
|
||||
}
|
||||
byte[] array3 = new byte[8];
|
||||
lock (UsbLock)
|
||||
{
|
||||
InputPipe.Read(array3, 0, array3.Length);
|
||||
}
|
||||
|
||||
if (count != (long)BitConverter.ToUInt64(array3, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 15
|
||||
public bool ClearIdOverride()
|
||||
{
|
||||
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioClearIdOverride])!;
|
||||
bool result = buffer[0] == 3;
|
||||
|
||||
// Refresh the ID
|
||||
if (result)
|
||||
{
|
||||
HasCachedV2Results = false;
|
||||
GetIdV2();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 17
|
||||
public Guid? GetSerialNumber()
|
||||
{
|
||||
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioSerialNumber])!;
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
// 19
|
||||
public uint SetBootMode(uint bootMode, string profileName)
|
||||
{
|
||||
uint num = 0x80000015U;
|
||||
|
||||
if (Encoding.Unicode.GetByteCount(profileName) >= 128)
|
||||
{
|
||||
num = 0x80000002U;
|
||||
throw new Win32Exception(87);
|
||||
}
|
||||
|
||||
uint num2 = 132U;
|
||||
byte[] array = new byte[num2];
|
||||
Array.Clear(array, 0, array.Length);
|
||||
byte[] array2 = BitConverter.GetBytes(bootMode);
|
||||
array2.CopyTo(array, 0);
|
||||
array2 = Encoding.Unicode.GetBytes(profileName);
|
||||
array2.CopyTo(array, 4);
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioSetBootMode]);
|
||||
|
||||
OutputPipe.Write(array, 0, array.Length);
|
||||
byte[] array3 = new byte[4];
|
||||
InputPipe.Read(array3, 0, array3.Length);
|
||||
num = BitConverter.ToUInt32(array3, 0);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
// 22
|
||||
public void GetDeviceVersion()
|
||||
{
|
||||
byte[] buffer = ExecuteRawMethod([(byte)SioOpcode.SioDeviceVersion])!;
|
||||
Console.WriteLine(Convert.ToHexString(buffer));
|
||||
}
|
||||
|
||||
// 23
|
||||
public bool QueryForCommandAvailable(SioOpcode Cmd)
|
||||
{
|
||||
(_, Guid _, bool supportsFastFlash, bool _, int clientVersion, Guid _, string _) = GetIdV2();
|
||||
|
||||
if (clientVersion < 2)
|
||||
{
|
||||
return Cmd < SioOpcode.SioFastFlash || supportsFastFlash;
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryForCmd]);
|
||||
byte[] buffer = ExecuteRawMethod([(byte)Cmd])!;
|
||||
return buffer[0] != 0;
|
||||
}
|
||||
|
||||
// 24
|
||||
public string GetServicingLogs(string logFolderPath)
|
||||
{
|
||||
string? text = null;
|
||||
|
||||
if (!QueryForCommandAvailable(SioOpcode.SioGetUpdateLogs))
|
||||
{
|
||||
throw new Exception("Command not available");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(logFolderPath))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logFolderPath));
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioGetUpdateLogs]);
|
||||
|
||||
byte[] array = new byte[262144];
|
||||
int num = 0;
|
||||
|
||||
byte[] array2 = new byte[4];
|
||||
int num2 = InputPipe.Read(array2, 0, array2.Length);
|
||||
|
||||
int num3 = BitConverter.ToInt32(array2, 0);
|
||||
|
||||
string text2 = Path.GetFullPath(logFolderPath);
|
||||
Directory.CreateDirectory(text2);
|
||||
text2 = Path.Combine(text2, Path.GetRandomFileName() + ".cab");
|
||||
|
||||
using (FileStream fileStream = File.Open(text2, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
do
|
||||
{
|
||||
Array.Clear(array, 0, array.Length);
|
||||
num2 = InputPipe.Read(array, 0, array.Length);
|
||||
num += num2;
|
||||
fileStream.Write(array, 0, array.Length);
|
||||
}
|
||||
while (num != num3);
|
||||
text = text2;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// 25
|
||||
public void QueryDeviceUnlockId(out byte[] unlockId, out byte[] oemId, out byte[] platformId)
|
||||
{
|
||||
unlockId = new byte[32];
|
||||
oemId = new byte[16];
|
||||
platformId = new byte[16];
|
||||
|
||||
if (!QueryForCommandAvailable(SioOpcode.SioQueryDeviceUnlockId))
|
||||
{
|
||||
throw new Exception("Command not available");
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryDeviceUnlockId]);
|
||||
|
||||
byte[] numBuffer = new byte[4];
|
||||
InputPipe.Read(numBuffer, 0, 4);
|
||||
|
||||
int num = BitConverter.ToInt32(numBuffer);
|
||||
|
||||
byte[] tmpBuffer = new byte[4];
|
||||
InputPipe.Read(tmpBuffer, 0, 4);
|
||||
|
||||
InputPipe.Read(unlockId, 0, 32);
|
||||
InputPipe.Read(oemId, 0, 16);
|
||||
InputPipe.Read(platformId, 0, 16);
|
||||
|
||||
if (num != 0)
|
||||
{
|
||||
throw new Exception("Error while reading device unlock id, " + num);
|
||||
}
|
||||
}
|
||||
|
||||
// 26
|
||||
public void RelockDeviceUnlockId()
|
||||
{
|
||||
if (!QueryForCommandAvailable(SioOpcode.SioRelockDeviceUnlockId))
|
||||
{
|
||||
throw new Exception("Command not available");
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioRelockDeviceUnlockId]);
|
||||
|
||||
byte[] numBuffer = new byte[4];
|
||||
InputPipe.Read(numBuffer, 0, 4);
|
||||
|
||||
int num = BitConverter.ToInt32(numBuffer);
|
||||
|
||||
if (num != 0)
|
||||
{
|
||||
throw new Exception("Error while relocking device unlock id, " + num);
|
||||
}
|
||||
}
|
||||
|
||||
// 27
|
||||
public uint[] QueryUnlockTokenFiles()
|
||||
{
|
||||
byte[] array = new byte[16];
|
||||
List<uint> list = [];
|
||||
|
||||
if (!QueryForCommandAvailable(SioOpcode.SioQueryUnlockTokenFiles))
|
||||
{
|
||||
throw new Exception("Command not available");
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryUnlockTokenFiles]);
|
||||
|
||||
byte[] numBuffer = new byte[4];
|
||||
InputPipe.Read(numBuffer, 0, 4);
|
||||
|
||||
int num = BitConverter.ToInt32(numBuffer);
|
||||
|
||||
byte[] tmpBuffer = new byte[4];
|
||||
InputPipe.Read(tmpBuffer, 0, 4);
|
||||
|
||||
InputPipe.Read(array, 0, 16);
|
||||
|
||||
BitArray bitArray = new BitArray(array);
|
||||
uint num2 = 0U;
|
||||
while (num2 < (ulong)((long)bitArray.Count))
|
||||
{
|
||||
if (bitArray.Get(Convert.ToInt32(num2)))
|
||||
{
|
||||
list.Add(num2);
|
||||
}
|
||||
num2 += 1U;
|
||||
}
|
||||
|
||||
if (num != 0)
|
||||
{
|
||||
throw new Exception("Error while querying unlock token files, " + num);
|
||||
}
|
||||
|
||||
return [.. list];
|
||||
}
|
||||
|
||||
// 28
|
||||
public void WriteUnlockTokenFile(uint unlockTokenId, byte[] fileData)
|
||||
{
|
||||
uint num = 0U;
|
||||
uint num2 = (uint)fileData.Length;
|
||||
|
||||
if (1048576 < fileData.Length)
|
||||
{
|
||||
throw new ArgumentException("fileData");
|
||||
}
|
||||
|
||||
if (127U < unlockTokenId)
|
||||
{
|
||||
throw new ArgumentException("unlockTokenId");
|
||||
}
|
||||
|
||||
if (!QueryForCommandAvailable(SioOpcode.SioWriteUnlockTokenFile))
|
||||
{
|
||||
throw new Exception("Command not available");
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioWriteUnlockTokenFile]);
|
||||
|
||||
OutputPipe.Write(BitConverter.GetBytes(num));
|
||||
OutputPipe.Write(BitConverter.GetBytes(num2));
|
||||
OutputPipe.Write(BitConverter.GetBytes(unlockTokenId));
|
||||
OutputPipe.Write(fileData, 0, fileData.Length);
|
||||
|
||||
byte[] numBuffer = new byte[4];
|
||||
InputPipe.Read(numBuffer, 0, 4);
|
||||
|
||||
int num3 = BitConverter.ToInt32(numBuffer);
|
||||
|
||||
if (num3 != 0)
|
||||
{
|
||||
throw new Exception("Error while writing unlock token files, " + num3);
|
||||
}
|
||||
}
|
||||
|
||||
// 29
|
||||
public bool QueryBitlockerState()
|
||||
{
|
||||
if (!QueryForCommandAvailable(SioOpcode.SioQueryBitlockerState))
|
||||
{
|
||||
throw new Exception("Command not available");
|
||||
}
|
||||
|
||||
ExecuteRawVoidMethod([(byte)SioOpcode.SioQueryBitlockerState]);
|
||||
|
||||
byte[] numBuffer = new byte[4];
|
||||
InputPipe.Read(numBuffer, 0, 4);
|
||||
|
||||
int num = BitConverter.ToInt32(numBuffer);
|
||||
|
||||
byte[] flagBuffer = new byte[1];
|
||||
InputPipe.Read(flagBuffer, 0, 1);
|
||||
|
||||
bool flag = flagBuffer[0] != 0;
|
||||
|
||||
if (num != 0)
|
||||
{
|
||||
throw new Exception("Error while reading bitlocker state, " + num);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~SimpleIOModel()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
USBDevice?.Dispose();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// Other disposables
|
||||
}
|
||||
|
||||
// Clean unmanaged resources here.
|
||||
Close();
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2026 The DuoWOA authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WPinternals.Models.SimpleIO
|
||||
{
|
||||
public enum SioOpcode : byte
|
||||
{
|
||||
SioId = 1, //
|
||||
SioFlash,
|
||||
SioAck,
|
||||
SioNack,
|
||||
SioLog,
|
||||
SioErr,
|
||||
SioSkip, //
|
||||
SioReset, //
|
||||
SioFile, // WIP!
|
||||
SioReboot, //
|
||||
SioMassStorage, //
|
||||
SioGetDiskInfo, //
|
||||
SioReadDisk, //
|
||||
SioWriteDisk, //
|
||||
SioClearIdOverride, //
|
||||
SioWim,
|
||||
SioSerialNumber, //
|
||||
SioExternalWim,
|
||||
SioSetBootMode, //
|
||||
SioFastFlash,
|
||||
SioDeviceParams,
|
||||
SioDeviceVersion,
|
||||
SioQueryForCmd, //
|
||||
SioGetUpdateLogs, //
|
||||
SioQueryDeviceUnlockId, //
|
||||
SioRelockDeviceUnlockId, //
|
||||
SioQueryUnlockTokenFiles, //
|
||||
SioWriteUnlockTokenFile, //
|
||||
SioQueryBitlockerState, //
|
||||
SioLast = 29
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
using System;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -91,6 +92,9 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaMassStorageViewModel((MassStorage)CurrentModel));
|
||||
break;
|
||||
case PhoneInterfaces.SimpleIO:
|
||||
ActivateSubContext(new SimpleIOViewModel((SimpleIOModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
using System;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -109,6 +110,9 @@ namespace WPinternals
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaModeMassStorageViewModel((MassStorage)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.SimpleIO:
|
||||
ActivateSubContext(new SimpleIOModeViewModel((SimpleIOModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ namespace WPinternals
|
||||
Qualcomm_Download,
|
||||
Qualcomm_Flash,
|
||||
Lumia_BadMassStorage,
|
||||
Lumia_PhoneInfo
|
||||
Lumia_PhoneInfo,
|
||||
SimpleIO
|
||||
};
|
||||
|
||||
// Create this class on the UI thread, after the main-window of the application is initialized.
|
||||
|
||||
@@ -27,6 +27,7 @@ using System.Threading.Tasks;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.Lumia.UEFI;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -47,6 +48,7 @@ namespace WPinternals
|
||||
private USBNotifier LumiaEmergencyNotifier;
|
||||
private USBNotifier LumiaLabelNotifier;
|
||||
private USBNotifier HidInterfaceNotifier;
|
||||
private USBNotifier SimpleIONotifier;
|
||||
|
||||
public PhoneInterfaces? CurrentInterface = null;
|
||||
private PhoneInterfaces? LastInterface = null;
|
||||
@@ -67,6 +69,8 @@ namespace WPinternals
|
||||
private Guid LumiaFlashInterfaceGuid = new("{9e3bd5f7-9690-4fcc-8810-3e2650cd6ecc}");
|
||||
private Guid LumiaEmergencyInterfaceGuid = new("{71DE994D-8B7C-43DB-A27E-2AE7CD579A0C}");
|
||||
|
||||
private Guid SimpleIOInterfaceGuid = new("{82809dd0-51f5-11e1-b86c-0800200c9a66}");
|
||||
|
||||
private readonly object ModelLock = new();
|
||||
|
||||
private readonly EventWaitHandle NewInterfaceWaitHandle = new(false, EventResetMode.AutoReset);
|
||||
@@ -113,6 +117,10 @@ namespace WPinternals
|
||||
HidInterfaceNotifier.Arrival += LumiaNotifier_Arrival;
|
||||
HidInterfaceNotifier.Removal += LumiaNotifier_Removal;
|
||||
|
||||
SimpleIONotifier = new USBNotifier(SimpleIOInterfaceGuid);
|
||||
SimpleIONotifier.Arrival += LumiaNotifier_Arrival;
|
||||
SimpleIONotifier.Removal += LumiaNotifier_Removal;
|
||||
|
||||
try
|
||||
{
|
||||
EventLogQuery LogQuery = new("Microsoft-Windows-Kernel-PnP/Configuration", PathType.LogName, "*[System[(EventID = 411)]]");
|
||||
@@ -150,6 +158,7 @@ namespace WPinternals
|
||||
ComPortNotifier.Dispose();
|
||||
LumiaEmergencyNotifier.Dispose();
|
||||
HidInterfaceNotifier.Dispose();
|
||||
SimpleIONotifier.Dispose();
|
||||
LogWatcher.Dispose();
|
||||
}
|
||||
|
||||
@@ -176,7 +185,18 @@ namespace WPinternals
|
||||
if (e.DevicePath.Contains("VID_0421&", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("VID_045E&", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (e.DevicePath.Contains("&PID_0660&MI_04", StringComparison.OrdinalIgnoreCase) ||
|
||||
if (e.DevicePath.Contains("&PID_062A", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
CurrentModel = new SimpleIOModel(e.DevicePath);
|
||||
|
||||
CurrentInterface = PhoneInterfaces.SimpleIO;
|
||||
LogFile.Log("Found device on interface: " + ((USBNotifier)sender).Guid.ToString(), LogType.FileOnly);
|
||||
LogFile.Log("Device path: " + e.DevicePath, LogType.FileOnly);
|
||||
LogFile.Log("Connected device: Lumia", LogType.FileAndConsole);
|
||||
LogFile.Log("Mode: SimpleIO", LogType.FileAndConsole);
|
||||
NewDeviceArrived(new ArrivalEventArgs((PhoneInterfaces)CurrentInterface, CurrentModel));
|
||||
}
|
||||
else if (e.DevicePath.Contains("&PID_0660&MI_04", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("&PID_0713&MI_04", StringComparison.OrdinalIgnoreCase) || // for Spec B
|
||||
e.DevicePath.Contains("&PID_0A01&MI_04", StringComparison.OrdinalIgnoreCase)) // for Spec B (650)
|
||||
{
|
||||
@@ -530,6 +550,7 @@ namespace WPinternals
|
||||
e.DevicePath.Contains("VID_0421&PID_05EE", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("VID_045E&PID_0A00", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("VID_045E&PID_0A02", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("VID_045E&PID_062A", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("VID_05C6&PID_9008", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("DISK&VEN_QUALCOMM&PROD_MMC_STORAGE", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.DevicePath.Contains("DISK&VEN_MSFT&PROD_PHONE_MMC_STOR", StringComparison.OrdinalIgnoreCase)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using WPinternals.Models.Lumia;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class SimpleIOModeViewModel : ContextViewModel
|
||||
{
|
||||
private readonly SimpleIOModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces?> RequestModeSwitch;
|
||||
|
||||
internal SimpleIOModeViewModel(SimpleIOModel CurrentModel, Action<PhoneInterfaces?> RequestModeSwitch)
|
||||
: base()
|
||||
{
|
||||
this.CurrentModel = CurrentModel;
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
}
|
||||
|
||||
public void RebootTo(string Mode)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "MassStorage":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_MassStorage);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Terminal;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
// Create this class on the UI thread, after the main-window of the application is initialized.
|
||||
// It is necessary to create the object on the UI thread, because notification events to the View need to be fired on that thread.
|
||||
// The Model for this ViewModel communicates over USB and for that it uses the hWnd of the main window.
|
||||
// Therefore the main window must be created before the ViewModel is created.
|
||||
|
||||
internal class SimpleIOViewModel : ContextViewModel
|
||||
{
|
||||
private readonly SimpleIOModel CurrentModel;
|
||||
private readonly Action<PhoneInterfaces> RequestModeSwitch;
|
||||
|
||||
internal SimpleIOViewModel(SimpleIOModel CurrentModel, Action<PhoneInterfaces> RequestModeSwitch)
|
||||
: base()
|
||||
{
|
||||
this.RequestModeSwitch = RequestModeSwitch;
|
||||
|
||||
this.CurrentModel = CurrentModel;
|
||||
|
||||
new Thread(() => StartLoadDeviceInfo()).Start();
|
||||
}
|
||||
|
||||
private void StartLoadDeviceInfo()
|
||||
{
|
||||
(long curPosition, Guid guid, bool supportsFastFlash, bool supportsCompatFastFlash, int clientVersion, Guid DeviceUniqueID, string DeviceFriendlyName) ID = CurrentModel.GetIdV2();
|
||||
|
||||
PlatformName = ID.DeviceFriendlyName;
|
||||
}
|
||||
|
||||
|
||||
private string _PlatformName = null;
|
||||
public string PlatformName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _PlatformName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_PlatformName = value;
|
||||
OnPropertyChanged(nameof(PlatformName));
|
||||
}
|
||||
}
|
||||
|
||||
public void RebootTo(string Mode)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case "Normal":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_Normal);
|
||||
break;
|
||||
case "MassStorage":
|
||||
RequestModeSwitch(PhoneInterfaces.Lumia_MassStorage);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ using WPinternals.HelperClasses;
|
||||
using WPinternals.Models.Lumia;
|
||||
using WPinternals.Models.Lumia.NCSd;
|
||||
using WPinternals.Models.Lumia.UEFI;
|
||||
using WPinternals.Models.SimpleIO;
|
||||
using WPinternals.Models.UEFIApps.BootMgr;
|
||||
using WPinternals.Models.UEFIApps.Flash;
|
||||
using WPinternals.Models.UEFIApps.PhoneInfo;
|
||||
@@ -94,7 +95,7 @@ namespace WPinternals
|
||||
else
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.CurrentModel = (NokiaPhoneModel)PhoneNotifier.CurrentModel;
|
||||
this.CurrentModel = PhoneNotifier.CurrentModel;
|
||||
this.CurrentMode = PhoneNotifier.CurrentInterface;
|
||||
this.TargetMode = TargetMode;
|
||||
if (ModeSwitchProgress != null)
|
||||
@@ -217,6 +218,26 @@ namespace WPinternals
|
||||
// Make switch and set message or navigate to error
|
||||
switch (CurrentMode)
|
||||
{
|
||||
case PhoneInterfaces.SimpleIO:
|
||||
IsSwitchingInterface = true;
|
||||
switch (TargetMode)
|
||||
{
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
((SimpleIOModel)CurrentModel).ContinueBoot();
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Normal mode...", null);
|
||||
LogFile.Log("Rebooting phone to Normal mode", LogType.FileAndConsole);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
((SimpleIOModel)CurrentModel).EnterMassStorage();
|
||||
ModeSwitchProgressWrapper("Rebooting phone to Mass Storage mode...", null);
|
||||
LogFile.Log("Rebooting phone to Mass Storage mode", LogType.FileAndConsole);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
string DeviceMode;
|
||||
|
||||
@@ -115,6 +115,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
<DataTemplate DataType="{x:Type local:ContextViewModel}">
|
||||
<local:ContextView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type local:SimpleIOViewModel}">
|
||||
<local:SimpleIOView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type local:SimpleIOModeViewModel}">
|
||||
<local:SimpleIOModeView />
|
||||
</DataTemplate>
|
||||
<BitmapImage x:Key="LogoImageSource" UriSource="..\Assets\Logo.png" />
|
||||
<BitmapImage x:Key="LogoSmallImageSource" UriSource="..\Assets\Logo-Small.png" />
|
||||
<Style x:Key="MenuButtonStyle" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="{x:Type Button}">
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<!--
|
||||
Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<UserControl x:Class="WPinternals.SimpleIOModeView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:WPinternals"
|
||||
xmlns:helpers="clr-namespace:WPinternals.HelperClasses"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="700">
|
||||
<UserControl.Resources>
|
||||
<helpers:BooleanConverter x:Key="VisibilityConverter" OnTrue="Visible" OnFalse="Collapsed" />
|
||||
<helpers:BooleanConverter x:Key="InvisibilityConverter" OnTrue="Collapsed" OnFalse="Visible" />
|
||||
<helpers:BooleanConverter x:Key="InverseConverter" OnTrue="False" OnFalse="True" />
|
||||
</UserControl.Resources>
|
||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25">
|
||||
<helpers:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0,0,0" VerticalScrollBarVisibility="Auto" >
|
||||
<FlowDocument x:Name="Document" FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" TextAlignment="Left">
|
||||
<FlowDocument.Resources>
|
||||
<!-- This style is used to set the margins for all paragraphs in the FlowDocument to 0. -->
|
||||
<Style TargetType="{x:Type Paragraph}">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type Section}">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
</Style>
|
||||
</FlowDocument.Resources>
|
||||
<helpers:Paragraph>
|
||||
<Run Text="Nokia Lumia - Switch mode" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Run Text="Current mode: " />
|
||||
<Run Text="SimpleIO" Foreground="#FF3753A6" FontWeight="Bold" />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="Normal">Switch to Normal-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This will switch back to Windows Phone OS." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Hyperlink NavigateUri="MassStorage">Switch to Mass-Storage-mode</Hyperlink>
|
||||
<LineBreak />
|
||||
<Run Text="This mode allows you to access the complete file-system of the phone. " />
|
||||
<Run Text="To enter this mode the phone will first be booted to Flash mode. After that this tool will immediately attempt to boot the phone to Mass Storage mode. So you may see your phone reboot multiple times." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Run Text="Warning 1: " Foreground="Red" FontWeight="Bold"/>
|
||||
<Run Text="Once you've entered Mass Storage mode, be very careful with altering files. You can easily brick your phone, when you make invalid changes to the file-system of the phone." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Run Text="Warning 2: " Foreground="Red" FontWeight="Bold"/>
|
||||
<Run Text="Before switching to Mass Storage Mode, verify that you do not have any other Windows Phone disks or partitions mounted. The partitions may have equal identifiers, which will result in a conflict. The phone partitions will be mounted "offline" and if you try to switch them "online" in the Disk Manager, it will corrupt the partitions on the phone. Unmount any Windows Phone partitions before you continue." />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Run Text="Warning 3: " Foreground="Red" FontWeight="Bold"/>
|
||||
<Run Text="Switching to Mass Storage mode should take about 10 seconds. Phones with Bootloader Spec A should be unlocked using an Engineering SBL3 to enable Mass Storage mode. When you unlocked the bootloader, but you did not use an Engineering SBL3, an attempt to boot to Mass Storage mode may result in an unresponsive state. Installing drivers for this interface may also cause to hang the PC. So when this switch is taking too long, you should reboot both the PC and the phone." />
|
||||
</helpers:Paragraph>
|
||||
</FlowDocument>
|
||||
</helpers:FlowDocumentScrollViewerNoMouseWheel>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// 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.
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SimpleIOModeView.xaml
|
||||
/// </summary>
|
||||
public partial class SimpleIOModeView : UserControl
|
||||
{
|
||||
public SimpleIOModeView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (args.Source is Hyperlink link)
|
||||
{
|
||||
(this.DataContext as SimpleIOModeViewModel)?.RebootTo(link.NavigateUri.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void Document_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
(sender as FlowDocument)?.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(HandleHyperlinkClick));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<!--
|
||||
Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<UserControl x:Class="WPinternals.SimpleIOView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:WPinternals"
|
||||
xmlns:helpers="clr-namespace:WPinternals.HelperClasses"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="700">
|
||||
<UserControl.Resources>
|
||||
<helpers:HexConverter x:Key="HexConverter" />
|
||||
<helpers:BooleanConverter x:Key="VisibilityConverter" OnTrue="Visible" OnFalse="Collapsed" OnNull="Collapsed"/>
|
||||
<helpers:BooleanConverter x:Key="InverseVisibilityConverter" OnTrue="Collapsed" OnFalse="Visible" OnNull="Collapsed" />
|
||||
<helpers:ObjectToVisibilityConverter x:Key="ObjectToVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<Border BorderThickness="1" BorderBrush="#FFD4D4D4" HorizontalAlignment="Stretch" VerticalAlignment="Center" Padding="25" Margin="0,0,0,20">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<helpers:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0" VerticalScrollBarVisibility="Auto">
|
||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" PagePadding="1">
|
||||
<helpers:Paragraph>
|
||||
<Run Text="General info" FontSize="18" FontWeight="Bold" Foreground="#FF3753A6" />
|
||||
<LineBreak />
|
||||
<LineBreak />
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Platform name" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" Text="{Binding PlatformName, Mode=OneWay}" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Operating mode" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="SimpleIO" FontWeight="Bold" Foreground="#FF3753A6" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</helpers:Paragraph>
|
||||
</FlowDocument>
|
||||
</helpers:FlowDocumentScrollViewerNoMouseWheel>
|
||||
<helpers:FlowDocumentScrollViewerNoMouseWheel Grid.Column="1" Margin="20,0" VerticalScrollBarVisibility="Auto">
|
||||
<FlowDocument FontFamily="Segoe UI" FontSize="12" Loaded="Document_Loaded" PagePadding="1">
|
||||
<helpers:Paragraph>
|
||||
<LineBreak />
|
||||
<Run Text="To let the phone go back to Windows, boot to " />
|
||||
<Hyperlink NavigateUri="Normal">Normal</Hyperlink>
|
||||
<Run Text=" mode." />
|
||||
</helpers:Paragraph>
|
||||
</FlowDocument>
|
||||
</helpers:FlowDocumentScrollViewerNoMouseWheel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// 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.
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SimpleIOView.xaml
|
||||
/// </summary>
|
||||
public partial class SimpleIOView : UserControl
|
||||
{
|
||||
public SimpleIOView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void HandleHyperlinkClick(object sender, RoutedEventArgs args)
|
||||
{
|
||||
Hyperlink link = args.Source as Hyperlink;
|
||||
if (link?.NavigateUri != null)
|
||||
{
|
||||
(this.DataContext as SimpleIOViewModel)?.RebootTo(link.NavigateUri.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void Document_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
(sender as FlowDocument)?.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(HandleHyperlinkClick));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user