mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
DOCUMENTATION: Added XML documentation to DiscImageChef.Devices.
This commit is contained in:
@@ -54,6 +54,7 @@ namespace DiscImageChef.Devices
|
||||
/// <param name="direction">SCSI command transfer direction</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer"/> contains SCSI sense</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendScsiCommand(object fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer,
|
||||
uint timeout, ScsiDirection direction, out double duration, out bool sense)
|
||||
{
|
||||
@@ -76,6 +77,7 @@ namespace DiscImageChef.Devices
|
||||
/// <param name="direction">SCSI command transfer direction</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer"/> contains SCSI sense</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendScsiCommand(PlatformID ptId, object fd, byte[] cdb, ref byte[] buffer,
|
||||
out byte[] senseBuffer, uint timeout, ScsiDirection direction,
|
||||
out double duration, out bool sense)
|
||||
@@ -158,6 +160,21 @@ namespace DiscImageChef.Devices
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS format
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(object fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
@@ -168,6 +185,22 @@ namespace DiscImageChef.Devices
|
||||
timeout, transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS format
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersChs registers,
|
||||
out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -205,6 +238,21 @@ namespace DiscImageChef.Devices
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS format
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(object fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -216,6 +264,22 @@ namespace DiscImageChef.Devices
|
||||
timeout, transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 28-bit LBA format
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -253,6 +317,21 @@ namespace DiscImageChef.Devices
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 48-bit LBA format
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(object fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -264,6 +343,22 @@ namespace DiscImageChef.Devices
|
||||
timeout, transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 48-bit format
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -292,6 +387,24 @@ namespace DiscImageChef.Devices
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a MMC/SD command
|
||||
/// </summary>
|
||||
/// <returns>The result of the command.</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="command">MMC/SD opcode</param>
|
||||
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
||||
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
||||
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
||||
/// <param name="flags">Flags indicating kind and place of response</param>
|
||||
/// <param name="blocks">How many blocks to transfer</param>
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendMmcCommand(object fd, MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 0)
|
||||
@@ -302,6 +415,25 @@ namespace DiscImageChef.Devices
|
||||
ref buffer, out response, out duration, out sense, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a MMC/SD command
|
||||
/// </summary>
|
||||
/// <returns>The result of the command.</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="command">MMC/SD opcode</param>
|
||||
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
||||
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
||||
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
||||
/// <param name="flags">Flags indicating kind and place of response</param>
|
||||
/// <param name="blocks">How many blocks to transfer</param>
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendMmcCommand(PlatformID ptId, object fd, MmcCommands command, bool write,
|
||||
bool isApplication, MmcFlags flags, uint argument, uint blockSize, uint blocks,
|
||||
ref byte[] buffer, out uint[] response, out double duration, out bool sense,
|
||||
|
||||
@@ -255,6 +255,11 @@ namespace DiscImageChef.Devices.FreeBSD
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts ATA protocol to CAM flags
|
||||
/// </summary>
|
||||
/// <param name="protocol">ATA protocol</param>
|
||||
/// <returns>CAM flags</returns>
|
||||
static CcbFlags AtaProtocolToCamFlags(AtaProtocol protocol)
|
||||
{
|
||||
switch(protocol)
|
||||
@@ -273,6 +278,18 @@ namespace DiscImageChef.Devices.FreeBSD
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="dev">CAM device</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(IntPtr dev, AtaRegistersChs registers,
|
||||
out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -359,6 +376,18 @@ namespace DiscImageChef.Devices.FreeBSD
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 28-bit LBA mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="dev">CAM device</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(IntPtr dev, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -445,6 +474,18 @@ namespace DiscImageChef.Devices.FreeBSD
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 48-bit mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="dev">CAM device</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(IntPtr dev, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
|
||||
@@ -43,6 +43,10 @@ namespace DiscImageChef.Devices.FreeBSD
|
||||
{
|
||||
static class ListDevices
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a list of all known storage devices on FreeBSD
|
||||
/// </summary>
|
||||
/// <returns>List of devices</returns>
|
||||
internal static DeviceInfo[] GetList()
|
||||
{
|
||||
string[] passDevices = Directory.GetFiles("/dev/", "pass*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
@@ -101,6 +101,11 @@ namespace DiscImageChef.Devices.Linux
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts ATA protocol to SG_IO direction
|
||||
/// </summary>
|
||||
/// <param name="protocol">ATA protocol</param>
|
||||
/// <returns>SG_IO direction</returns>
|
||||
static ScsiIoctlDirection AtaProtocolToScsiDirection(AtaProtocol protocol)
|
||||
{
|
||||
switch(protocol)
|
||||
@@ -119,6 +124,20 @@ namespace DiscImageChef.Devices.Linux
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">Which register contains the transfer count</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
||||
internal static int SendAtaCommand(int fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister,
|
||||
ref byte[] buffer, uint timeout, bool transferBlocks, out double duration,
|
||||
@@ -180,6 +199,20 @@ namespace DiscImageChef.Devices.Linux
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 28-bit LBA mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">Which register contains the transfer count</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
||||
internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -241,6 +274,20 @@ namespace DiscImageChef.Devices.Linux
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 48-bit LBA mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">Which register contains the transfer count</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
||||
internal static int SendAtaCommand(int fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
@@ -375,7 +422,12 @@ namespace DiscImageChef.Devices.Linux
|
||||
return error;
|
||||
}
|
||||
|
||||
public static string ReadLink(string path)
|
||||
/// <summary>
|
||||
/// Reads the contents of a symbolic link
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the symbolic link</param>
|
||||
/// <returns>Contents of the symbolic link</returns>
|
||||
internal static string ReadLink(string path)
|
||||
{
|
||||
IntPtr buf = Marshal.AllocHGlobal(4096);
|
||||
int resultSize;
|
||||
|
||||
@@ -40,6 +40,10 @@ namespace DiscImageChef.Devices.Linux
|
||||
{
|
||||
const string PATH_SYS_DEVBLOCK = "/sys/block/";
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all known storage devices on Linux
|
||||
/// </summary>
|
||||
/// <returns>List of devices</returns>
|
||||
internal static DeviceInfo[] GetList()
|
||||
{
|
||||
string[] sysdevs = Directory.GetFileSystemEntries(PATH_SYS_DEVBLOCK, "*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
@@ -110,6 +110,18 @@ namespace DiscImageChef.Devices.Windows
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersChs registers,
|
||||
out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -199,6 +211,18 @@ namespace DiscImageChef.Devices.Windows
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 28-bit LBA mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -288,6 +312,18 @@ namespace DiscImageChef.Devices.Windows
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 48-bit LBA mode
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -389,6 +425,18 @@ namespace DiscImageChef.Devices.Windows
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in CHS mode using undocumented Windows XP ioctl
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersChs registers,
|
||||
out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -446,6 +494,18 @@ namespace DiscImageChef.Devices.Windows
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an ATA command in 28-bit LBA mode using undocumented Windows XP ioctl
|
||||
/// </summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
@@ -503,6 +563,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device number for a specified handle
|
||||
/// </summary>
|
||||
/// <param name="deviceHandle">Device handle</param>
|
||||
/// <returns>Device number</returns>
|
||||
static uint GetDeviceNumber(SafeFileHandle deviceHandle)
|
||||
{
|
||||
StorageDeviceNumber sdn = new StorageDeviceNumber {deviceNumber = -1};
|
||||
@@ -514,6 +579,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
return (uint)sdn.deviceNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal device path for a specified handle
|
||||
/// </summary>
|
||||
/// <param name="fd">Device handle</param>
|
||||
/// <returns>Device path</returns>
|
||||
internal static string GetDevicePath(SafeFileHandle fd)
|
||||
{
|
||||
uint devNumber = GetDeviceNumber(fd);
|
||||
@@ -587,6 +657,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the specified handle is controlled by a SFFDISK (aka SDHCI) driver
|
||||
/// </summary>
|
||||
/// <param name="fd">Device handle</param>
|
||||
/// <returns><c>true</c> if SDHCI, false otherwise</returns>
|
||||
internal static bool IsSdhci(SafeFileHandle fd)
|
||||
{
|
||||
SffdiskQueryDeviceProtocolData queryData1 = new SffdiskQueryDeviceProtocolData();
|
||||
|
||||
@@ -43,6 +43,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
{
|
||||
static class ListDevices
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a hex dump string to the ASCII string it represents
|
||||
/// </summary>
|
||||
/// <param name="hex">Hex dump</param>
|
||||
/// <returns>Decoded string</returns>
|
||||
static string HexStringToString(string hex)
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
@@ -53,6 +58,10 @@ namespace DiscImageChef.Devices.Windows
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all known storage devices on Windows
|
||||
/// </summary>
|
||||
/// <returns>List of devices</returns>
|
||||
[SuppressMessage("ReSharper", "RedundantCatchClause")]
|
||||
internal static DeviceInfo[] GetList()
|
||||
{
|
||||
|
||||
@@ -41,6 +41,9 @@ using System.Text;
|
||||
namespace DiscImageChef.Devices.Windows
|
||||
{
|
||||
// TODO: Even after cleaning, refactoring and xml-documenting, this code needs some love
|
||||
/// <summary>
|
||||
/// Implements functions for getting and accesing information from the USB bus
|
||||
/// </summary>
|
||||
static partial class Usb
|
||||
{
|
||||
#region "API Region"
|
||||
@@ -78,27 +81,12 @@ namespace DiscImageChef.Devices.Windows
|
||||
|
||||
// ********************** Enumerations ************************
|
||||
|
||||
//typedef enum _USB_HUB_NODE {
|
||||
// UsbHub,
|
||||
// UsbMIParent
|
||||
//} USB_HUB_NODE;
|
||||
enum UsbHubNode
|
||||
{
|
||||
UsbHub,
|
||||
UsbMiParent
|
||||
}
|
||||
|
||||
//typedef enum _USB_CONNECTION_STATUS {
|
||||
// NoDeviceConnected,
|
||||
// DeviceConnected,
|
||||
// DeviceFailedEnumeration,
|
||||
// DeviceGeneralFailure,
|
||||
// DeviceCausedOvercurrent,
|
||||
// DeviceNotEnoughPower,
|
||||
// DeviceNotEnoughBandwidth,
|
||||
// DeviceHubNestedTooDeeply,
|
||||
// DeviceInLegacyHub
|
||||
//} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;
|
||||
enum UsbConnectionStatus
|
||||
{
|
||||
NoDeviceConnected,
|
||||
@@ -112,11 +100,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
DeviceInLegacyHub
|
||||
}
|
||||
|
||||
//typedef enum _USB_DEVICE_SPEED {
|
||||
// UsbLowSpeed = 0,
|
||||
// UsbFullSpeed,
|
||||
// UsbHighSpeed
|
||||
//} USB_DEVICE_SPEED;
|
||||
enum UsbDeviceSpeed : byte
|
||||
{
|
||||
UsbLowSpeed,
|
||||
@@ -126,12 +109,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
|
||||
// ********************** Stuctures ************************
|
||||
|
||||
//typedef struct _SP_DEVINFO_DATA {
|
||||
// DWORD cbSize;
|
||||
// GUID ClassGuid;
|
||||
// DWORD DevInst;
|
||||
// ULONG_PTR Reserved;
|
||||
//} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SpDevinfoData
|
||||
{
|
||||
@@ -141,12 +118,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal IntPtr Reserved;
|
||||
}
|
||||
|
||||
//typedef struct _SP_DEVICE_INTERFACE_DATA {
|
||||
// DWORD cbSize;
|
||||
// GUID InterfaceClassGuid;
|
||||
// DWORD Flags;
|
||||
// ULONG_PTR Reserved;
|
||||
//} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SpDeviceInterfaceData
|
||||
{
|
||||
@@ -156,10 +127,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal IntPtr Reserved;
|
||||
}
|
||||
|
||||
//typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
|
||||
// DWORD cbSize;
|
||||
// TCHAR DevicePath[ANYSIZE_ARRAY];
|
||||
//} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct SpDeviceInterfaceDetailData
|
||||
{
|
||||
@@ -167,10 +134,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string DevicePath;
|
||||
}
|
||||
|
||||
//typedef struct _USB_HCD_DRIVERKEY_NAME {
|
||||
// ULONG ActualLength;
|
||||
// WCHAR DriverKeyName[1];
|
||||
//} USB_HCD_DRIVERKEY_NAME, *PUSB_HCD_DRIVERKEY_NAME;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct UsbHcdDriverkeyName
|
||||
{
|
||||
@@ -178,10 +141,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string DriverKeyName;
|
||||
}
|
||||
|
||||
//typedef struct _USB_ROOT_HUB_NAME {
|
||||
// ULONG ActualLength;
|
||||
// WCHAR RootHubName[1];
|
||||
//} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct UsbRootHubName
|
||||
{
|
||||
@@ -189,15 +148,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string RootHubName;
|
||||
}
|
||||
|
||||
//typedef struct _USB_HUB_DESCRIPTOR {
|
||||
// UCHAR bDescriptorLength;
|
||||
// UCHAR bDescriptorType;
|
||||
// UCHAR bNumberOfPorts;
|
||||
// USHORT wHubCharacteristics;
|
||||
// UCHAR bPowerOnToPowerGood;
|
||||
// UCHAR bHubControlCurrent;
|
||||
// UCHAR bRemoveAndPowerMask[64];
|
||||
//} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct UsbHubDescriptor
|
||||
{
|
||||
@@ -210,10 +160,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] internal byte[] bRemoveAndPowerMask;
|
||||
}
|
||||
|
||||
//typedef struct _USB_HUB_INFORMATION {
|
||||
// USB_HUB_DESCRIPTOR HubDescriptor;
|
||||
// BOOLEAN HubIsBusPowered;
|
||||
//} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct UsbHubInformation
|
||||
{
|
||||
@@ -221,13 +167,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal byte HubIsBusPowered;
|
||||
}
|
||||
|
||||
//typedef struct _USB_NODE_INFORMATION {
|
||||
// USB_HUB_NODE NodeType;
|
||||
// union {
|
||||
// USB_HUB_INFORMATION HubInformation;
|
||||
// USB_MI_PARENT_INFORMATION MiParentInformation;
|
||||
// } u;
|
||||
//} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct UsbNodeInformation
|
||||
{
|
||||
@@ -235,17 +174,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal UsbHubInformation HubInformation; // Yeah, I'm assuming we'll just use the first form
|
||||
}
|
||||
|
||||
//typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
|
||||
// ULONG ConnectionIndex;
|
||||
// USB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
||||
// UCHAR CurrentConfigurationValue;
|
||||
// UCHAR Speed;
|
||||
// BOOLEAN DeviceIsHub;
|
||||
// USHORT DeviceAddress;
|
||||
// ULONG NumberOfOpenPipes;
|
||||
// USB_CONNECTION_STATUS ConnectionStatus;
|
||||
// USB_PIPE_INFO PipeList[0];
|
||||
//} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct UsbNodeConnectionInformationEx
|
||||
{
|
||||
@@ -261,22 +189,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
//internal IntPtr PipeList;
|
||||
}
|
||||
|
||||
//typedef struct _USB_DEVICE_DESCRIPTOR {
|
||||
// UCHAR bLength;
|
||||
// UCHAR bDescriptorType;
|
||||
// USHORT bcdUSB;
|
||||
// UCHAR bDeviceClass;
|
||||
// UCHAR bDeviceSubClass;
|
||||
// UCHAR bDeviceProtocol;
|
||||
// UCHAR bMaxPacketSize0;
|
||||
// USHORT idVendor;
|
||||
// USHORT idProduct;
|
||||
// USHORT bcdDevice;
|
||||
// UCHAR iManufacturer;
|
||||
// UCHAR iProduct;
|
||||
// UCHAR iSerialNumber;
|
||||
// UCHAR bNumConfigurations;
|
||||
//} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR ;
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
internal struct UsbDeviceDescriptor
|
||||
@@ -297,11 +209,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal byte bNumConfigurations;
|
||||
}
|
||||
|
||||
//typedef struct _USB_STRING_DESCRIPTOR {
|
||||
// UCHAR bLength;
|
||||
// UCHAR bDescriptorType;
|
||||
// WCHAR bString[1];
|
||||
//} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct UsbStringDescriptor
|
||||
{
|
||||
@@ -310,17 +217,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXIMUM_USB_STRING_LENGTH)] internal string bString;
|
||||
}
|
||||
|
||||
//typedef struct _USB_DESCRIPTOR_REQUEST {
|
||||
// ULONG ConnectionIndex;
|
||||
// struct {
|
||||
// UCHAR bmRequest;
|
||||
// UCHAR bRequest;
|
||||
// USHORT wValue;
|
||||
// USHORT wIndex;
|
||||
// USHORT wLength;
|
||||
// } SetupPacket;
|
||||
// UCHAR Data[0];
|
||||
//} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct UsbSetupPacket
|
||||
{
|
||||
@@ -340,11 +236,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
//internal byte[] Data;
|
||||
}
|
||||
|
||||
//typedef struct _USB_NODE_CONNECTION_NAME {
|
||||
// ULONG ConnectionIndex;
|
||||
// ULONG ActualLength;
|
||||
// WCHAR NodeName[1];
|
||||
//} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct UsbNodeConnectionName
|
||||
{
|
||||
@@ -353,11 +244,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string NodeName;
|
||||
}
|
||||
|
||||
//typedef struct _USB_NODE_CONNECTION_DRIVERKEY_NAME {
|
||||
// ULONG ConnectionIndex;
|
||||
// ULONG ActualLength;
|
||||
// WCHAR DriverKeyName[1];
|
||||
//} USB_NODE_CONNECTION_DRIVERKEY_NAME, *PUSB_NODE_CONNECTION_DRIVERKEY_NAME;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct UsbNodeConnectionDriverkeyName // Yes, this is the same as the structure above...
|
||||
{
|
||||
@@ -368,12 +254,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
|
||||
// ********************** API Definitions ************************
|
||||
|
||||
//HDEVINFO SetupDiGetClassDevs(
|
||||
// const GUID* ClassGuid,
|
||||
// PCTSTR Enumerator,
|
||||
// HWND hwndParent,
|
||||
// DWORD Flags
|
||||
//);
|
||||
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
|
||||
static extern IntPtr SetupDiGetClassDevs( // 1st form using a ClassGUID
|
||||
ref Guid classGuid, int enumerator, IntPtr hwndParent, int flags);
|
||||
@@ -381,26 +261,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
[DllImport("setupapi.dll", CharSet = CharSet.Auto)] // 2nd form uses an Enumerator
|
||||
static extern IntPtr SetupDiGetClassDevs(int classGuid, string enumerator, IntPtr hwndParent, int flags);
|
||||
|
||||
//BOOL SetupDiEnumDeviceInterfaces(
|
||||
// HDEVINFO DeviceInfoSet,
|
||||
// PSP_DEVINFO_DATA DeviceInfoData,
|
||||
// const GUID* InterfaceClassGuid,
|
||||
// DWORD MemberIndex,
|
||||
// PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
|
||||
//);
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData,
|
||||
ref Guid interfaceClassGuid, int memberIndex,
|
||||
ref SpDeviceInterfaceData deviceInterfaceData);
|
||||
|
||||
//BOOL SetupDiGetDeviceInterfaceDetail(
|
||||
// HDEVINFO DeviceInfoSet,
|
||||
// PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
||||
// PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
|
||||
// DWORD DeviceInterfaceDetailDataSize,
|
||||
// PDWORD RequiredSize,
|
||||
// PSP_DEVINFO_DATA DeviceInfoData
|
||||
//);
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet,
|
||||
ref SpDeviceInterfaceData deviceInterfaceData,
|
||||
@@ -409,87 +274,42 @@ namespace DiscImageChef.Devices.Windows
|
||||
int deviceInterfaceDetailDataSize, ref int requiredSize,
|
||||
ref SpDevinfoData deviceInfoData);
|
||||
|
||||
//BOOL SetupDiGetDeviceRegistryProperty(
|
||||
// HDEVINFO DeviceInfoSet,
|
||||
// PSP_DEVINFO_DATA DeviceInfoData,
|
||||
// DWORD Property,
|
||||
// PDWORD PropertyRegDataType,
|
||||
// PBYTE PropertyBuffer,
|
||||
// DWORD PropertyBufferSize,
|
||||
// PDWORD RequiredSize
|
||||
//);
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool SetupDiGetDeviceRegistryProperty(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData,
|
||||
int iProperty, ref int propertyRegDataType,
|
||||
IntPtr propertyBuffer, int propertyBufferSize,
|
||||
ref int requiredSize);
|
||||
|
||||
//BOOL SetupDiEnumDeviceInfo(
|
||||
// HDEVINFO DeviceInfoSet,
|
||||
// DWORD MemberIndex,
|
||||
// PSP_DEVINFO_DATA DeviceInfoData
|
||||
//);
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, int memberIndex,
|
||||
ref SpDevinfoData deviceInfoData);
|
||||
|
||||
//BOOL SetupDiDestroyDeviceInfoList(
|
||||
// HDEVINFO DeviceInfoSet
|
||||
//);
|
||||
[DllImport("setupapi.dll", SetLastError = true)]
|
||||
static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
|
||||
|
||||
//WINSETUPAPI BOOL WINAPI SetupDiGetDeviceInstanceId(
|
||||
// IN HDEVINFO DeviceInfoSet,
|
||||
// IN PSP_DEVINFO_DATA DeviceInfoData,
|
||||
// OUT PTSTR DeviceInstanceId,
|
||||
// IN DWORD DeviceInstanceIdSize,
|
||||
// OUT PDWORD RequiredSize OPTIONAL
|
||||
//);
|
||||
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool SetupDiGetDeviceInstanceId(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData,
|
||||
StringBuilder deviceInstanceId, int deviceInstanceIdSize,
|
||||
out int requiredSize);
|
||||
|
||||
//BOOL DeviceIoControl(
|
||||
// HANDLE hDevice,
|
||||
// DWORD dwIoControlCode,
|
||||
// LPVOID lpInBuffer,
|
||||
// DWORD nInBufferSize,
|
||||
// LPVOID lpOutBuffer,
|
||||
// DWORD nOutBufferSize,
|
||||
// LPDWORD lpBytesReturned,
|
||||
// LPOVERLAPPED lpOverlapped
|
||||
//);
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize,
|
||||
IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned,
|
||||
IntPtr lpOverlapped);
|
||||
|
||||
//HANDLE CreateFile(
|
||||
// LPCTSTR lpFileName,
|
||||
// DWORD dwDesiredAccess,
|
||||
// DWORD dwShareMode,
|
||||
// LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
// DWORD dwCreationDisposition,
|
||||
// DWORD dwFlagsAndAttributes,
|
||||
// HANDLE hTemplateFile
|
||||
//);
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
|
||||
IntPtr lpSecurityAttributes, int dwCreationDisposition,
|
||||
int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
|
||||
//BOOL CloseHandle(
|
||||
// HANDLE hObject
|
||||
//);
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
static extern bool CloseHandle(IntPtr hObject);
|
||||
#endregion
|
||||
|
||||
//
|
||||
// Return a list of USB Host Controllers
|
||||
//
|
||||
/// <summary>
|
||||
/// Return a list of USB Host Controllers
|
||||
/// </summary>
|
||||
/// <returns>List of USB Host Controllers</returns>
|
||||
static IEnumerable<UsbController> GetHostControllers()
|
||||
{
|
||||
List<UsbController> hostList = new List<UsbController>();
|
||||
@@ -554,15 +374,17 @@ namespace DiscImageChef.Devices.Windows
|
||||
return new ReadOnlyCollection<UsbController>(hostList);
|
||||
}
|
||||
|
||||
//
|
||||
// The USB Host Controller Class
|
||||
//
|
||||
/// <summary>
|
||||
/// Represents a USB Host Controller
|
||||
/// </summary>
|
||||
class UsbController
|
||||
{
|
||||
internal int ControllerIndex;
|
||||
internal string ControllerDriverKeyName, ControllerDevicePath, ControllerDeviceDesc;
|
||||
|
||||
// A simple default constructor
|
||||
/// <summary>
|
||||
/// A simple default constructor
|
||||
/// </summary>
|
||||
internal UsbController()
|
||||
{
|
||||
ControllerIndex = 0;
|
||||
@@ -571,19 +393,19 @@ namespace DiscImageChef.Devices.Windows
|
||||
ControllerDriverKeyName = "";
|
||||
}
|
||||
|
||||
// Return the index of the instance
|
||||
/// <summary>Return the index of the instance</summary>
|
||||
internal int Index => ControllerIndex;
|
||||
|
||||
// Return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0&58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"
|
||||
/// <summary>Return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0&58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"</summary>
|
||||
internal string DevicePath => ControllerDevicePath;
|
||||
|
||||
// The DriverKeyName may be useful as a search key
|
||||
/// <summary>The DriverKeyName may be useful as a search key</summary>
|
||||
internal string DriverKeyName => ControllerDriverKeyName;
|
||||
|
||||
// Return the Friendly Name, such as "VIA USB Enhanced Host Controller"
|
||||
/// <summary>Return the Friendly Name, such as "VIA USB Enhanced Host Controller"</summary>
|
||||
internal string Name => ControllerDeviceDesc;
|
||||
|
||||
// Return Root Hub for this Controller
|
||||
/// <summary>Return Root Hub for this Controller</summary>
|
||||
internal UsbHub GetRootHub()
|
||||
{
|
||||
IntPtr h, h2;
|
||||
@@ -637,9 +459,7 @@ namespace DiscImageChef.Devices.Windows
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The Hub class
|
||||
//
|
||||
/// <summary>The Hub class</summary>
|
||||
internal class UsbHub
|
||||
{
|
||||
internal int HubPortCount;
|
||||
@@ -647,7 +467,7 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal string HubManufacturer, HubProduct, HubSerialNumber, HubInstanceId;
|
||||
internal bool HubIsBusPowered, HubIsRootHub;
|
||||
|
||||
// a simple default constructor
|
||||
/// <summary>a simple default constructor</summary>
|
||||
internal UsbHub()
|
||||
{
|
||||
HubPortCount = 0;
|
||||
@@ -662,25 +482,25 @@ namespace DiscImageChef.Devices.Windows
|
||||
HubInstanceId = "";
|
||||
}
|
||||
|
||||
// return Port Count
|
||||
/// <summary>return Port Count</summary>
|
||||
internal int PortCount => HubPortCount;
|
||||
|
||||
// return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0&58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"
|
||||
/// <summary>return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0&58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"</summary>
|
||||
internal string DevicePath => HubDevicePath;
|
||||
|
||||
// The DriverKey may be useful as a search key
|
||||
/// <summary>The DriverKey may be useful as a search key</summary>
|
||||
internal string DriverKey => HubDriverKey;
|
||||
|
||||
// return the Friendly Name, such as "VIA USB Enhanced Host Controller"
|
||||
/// <summary>return the Friendly Name, such as "VIA USB Enhanced Host Controller"</summary>
|
||||
internal string Name => HubDeviceDesc;
|
||||
|
||||
// the device path of this device
|
||||
/// <summary>the device path of this device</summary>
|
||||
internal string InstanceId => HubInstanceId;
|
||||
|
||||
// is is this a self-powered hub?
|
||||
/// <summary>is is this a self-powered hub?</summary>
|
||||
internal bool IsBusPowered => HubIsBusPowered;
|
||||
|
||||
// is this a root hub?
|
||||
/// <summary>is this a root hub?</summary>
|
||||
internal bool IsRootHub => HubIsRootHub;
|
||||
|
||||
internal string Manufacturer => HubManufacturer;
|
||||
@@ -689,7 +509,10 @@ namespace DiscImageChef.Devices.Windows
|
||||
|
||||
internal string SerialNumber => HubSerialNumber;
|
||||
|
||||
// return a list of the down stream ports
|
||||
/// <summary>
|
||||
/// return a list of the down stream ports
|
||||
/// </summary>
|
||||
/// <returns>List of downstream ports</returns>
|
||||
internal IEnumerable<UsbPort> GetPorts()
|
||||
{
|
||||
List<UsbPort> portList = new List<UsbPort>();
|
||||
@@ -744,9 +567,9 @@ namespace DiscImageChef.Devices.Windows
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The Port Class
|
||||
//
|
||||
/// <summary>
|
||||
/// Represents an USB port
|
||||
/// </summary>
|
||||
internal class UsbPort
|
||||
{
|
||||
internal int PortPortNumber;
|
||||
@@ -754,7 +577,7 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal bool PortIsHub, PortIsDeviceConnected;
|
||||
internal UsbDeviceDescriptor PortDeviceDescriptor;
|
||||
|
||||
// a simple default constructor
|
||||
/// <summary>a simple default constructor</summary>
|
||||
internal UsbPort()
|
||||
{
|
||||
PortPortNumber = 0;
|
||||
@@ -765,25 +588,28 @@ namespace DiscImageChef.Devices.Windows
|
||||
PortIsDeviceConnected = false;
|
||||
}
|
||||
|
||||
// return Port Index of the Hub
|
||||
/// <summary>return Port Index of the Hub</summary>
|
||||
internal int PortNumber => PortPortNumber;
|
||||
|
||||
// return the Device Path of the Hub
|
||||
/// <summary>return the Device Path of the Hub</summary>
|
||||
internal string HubDevicePath => PortHubDevicePath;
|
||||
|
||||
// the status (see USB_CONNECTION_STATUS above)
|
||||
/// <summary>the status (see USB_CONNECTION_STATUS above)</summary>
|
||||
internal string Status => PortStatus;
|
||||
|
||||
// the speed of the connection (see USB_DEVICE_SPEED above)
|
||||
/// <summary>the speed of the connection (see USB_DEVICE_SPEED above)</summary>
|
||||
internal string Speed => PortSpeed;
|
||||
|
||||
// is this a downstream external hub?
|
||||
/// <summary>is this a downstream external hub?</summary>
|
||||
internal bool IsHub => PortIsHub;
|
||||
|
||||
// is anybody home?
|
||||
/// <summary>is anybody home?</summary>
|
||||
internal bool IsDeviceConnected => PortIsDeviceConnected;
|
||||
|
||||
// return a down stream external hub
|
||||
/// <summary>
|
||||
/// return a down stream external hub
|
||||
/// </summary>
|
||||
/// <returns>Downstream external hub</returns>
|
||||
internal UsbDevice GetDevice()
|
||||
{
|
||||
if(!PortIsDeviceConnected) return null;
|
||||
@@ -955,7 +781,10 @@ namespace DiscImageChef.Devices.Windows
|
||||
return device;
|
||||
}
|
||||
|
||||
// return a down stream external hub
|
||||
/// <summary>
|
||||
/// return a down stream external hub
|
||||
/// </summary>
|
||||
/// <returns>Downstream external hub</returns>
|
||||
internal UsbHub GetHub()
|
||||
{
|
||||
if(!PortIsHub) return null;
|
||||
@@ -1022,9 +851,9 @@ namespace DiscImageChef.Devices.Windows
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The USB Device Class
|
||||
//
|
||||
/// <summary>
|
||||
/// Represents an USB device
|
||||
/// </summary>
|
||||
internal class UsbDevice
|
||||
{
|
||||
internal int DevicePortNumber;
|
||||
@@ -1033,7 +862,7 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal UsbDeviceDescriptor DeviceDescriptor;
|
||||
internal byte[] BinaryDeviceDescriptors;
|
||||
|
||||
// a simple default constructor
|
||||
/// <summary>a simple default constructor</summary>
|
||||
internal UsbDevice()
|
||||
{
|
||||
DevicePortNumber = 0;
|
||||
@@ -1047,19 +876,19 @@ namespace DiscImageChef.Devices.Windows
|
||||
BinaryDeviceDescriptors = null;
|
||||
}
|
||||
|
||||
// return Port Index of the Hub
|
||||
/// <summary>return Port Index of the Hub</summary>
|
||||
internal int PortNumber => DevicePortNumber;
|
||||
|
||||
// return the Device Path of the Hub (the parent device)
|
||||
/// <summary>return the Device Path of the Hub (the parent device)</summary>
|
||||
internal string HubDevicePath => DeviceHubDevicePath;
|
||||
|
||||
// useful as a search key
|
||||
/// <summary>useful as a search key</summary>
|
||||
internal string DriverKey => DeviceDriverKey;
|
||||
|
||||
// the device path of this device
|
||||
/// <summary>the device path of this device</summary>
|
||||
internal string InstanceId => DeviceInstanceId;
|
||||
|
||||
// the friendly name
|
||||
/// <summary>the friendly name</summary>
|
||||
internal string Name => DeviceName;
|
||||
|
||||
internal string Manufacturer => DeviceManufacturer;
|
||||
@@ -1071,9 +900,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal byte[] BinaryDescriptors => BinaryDeviceDescriptors;
|
||||
}
|
||||
|
||||
//
|
||||
// private function for finding a USB device's Description
|
||||
//
|
||||
/// <summary>
|
||||
/// private function for finding a USB device's Description
|
||||
/// </summary>
|
||||
/// <param name="driverKeyName">Device driver key name</param>
|
||||
/// <returns>USB device description</returns>
|
||||
static string GetDescriptionByKeyName(string driverKeyName)
|
||||
{
|
||||
string ans = "";
|
||||
@@ -1124,9 +955,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
return ans;
|
||||
}
|
||||
|
||||
//
|
||||
// private function for finding a USB device's Instance ID
|
||||
//
|
||||
/// <summary>
|
||||
/// private function for finding a USB device's Instance ID
|
||||
/// </summary>
|
||||
/// <param name="driverKeyName">Device driver key name</param>
|
||||
/// <returns>Device instance ID</returns>
|
||||
static string GetInstanceIdByKeyName(string driverKeyName)
|
||||
{
|
||||
string ans = "";
|
||||
|
||||
@@ -42,11 +42,15 @@ namespace DiscImageChef.Devices.Windows
|
||||
// You might not want to keep these in the USB class... your choice
|
||||
//
|
||||
// TODO: Even after cleaning, refactoring and xml-documenting, this code needs some love
|
||||
/// <summary>
|
||||
/// Implements functions for getting and accesing information from the USB bus
|
||||
/// </summary>
|
||||
static partial class Usb
|
||||
{
|
||||
//
|
||||
// Get a list of all connected devices
|
||||
//
|
||||
/// <summary>
|
||||
/// Get a list of all connected devices
|
||||
/// </summary>
|
||||
/// <returns>List of usb devices</returns>
|
||||
internal static List<UsbDevice> GetConnectedDevices()
|
||||
{
|
||||
List<UsbDevice> devList = new List<UsbDevice>();
|
||||
@@ -56,7 +60,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
return devList;
|
||||
}
|
||||
|
||||
// private routine for enumerating a hub
|
||||
/// <summary>
|
||||
/// private routine for enumerating a hub
|
||||
/// </summary>
|
||||
/// <param name="hub">Hub</param>
|
||||
/// <param name="devList">Device list</param>
|
||||
static void ListHub(UsbHub hub, ICollection<UsbDevice> devList)
|
||||
{
|
||||
foreach(UsbPort port in hub.GetPorts())
|
||||
@@ -64,9 +72,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
else { if(port.IsDeviceConnected) devList.Add(port.GetDevice()); }
|
||||
}
|
||||
|
||||
//
|
||||
// Find a device based upon it's DriverKeyName
|
||||
//
|
||||
/// <summary>
|
||||
/// Find a device based upon it's DriverKeyName
|
||||
/// </summary>
|
||||
/// <param name="driverKeyName">DriverKeyName</param>
|
||||
/// <returns>USB device</returns>
|
||||
internal static UsbDevice FindDeviceByDriverKeyName(string driverKeyName)
|
||||
{
|
||||
UsbDevice foundDevice = null;
|
||||
@@ -80,7 +90,12 @@ namespace DiscImageChef.Devices.Windows
|
||||
return foundDevice;
|
||||
}
|
||||
|
||||
// private routine for enumerating a hub
|
||||
/// <summary>
|
||||
/// Finds a device connected to a specified hub by it's DriverKeyName
|
||||
/// </summary>
|
||||
/// <param name="hub">Hub</param>
|
||||
/// <param name="foundDevice">UsbDevice</param>
|
||||
/// <param name="driverKeyName">DriverKeyName</param>
|
||||
static void SearchHubDriverKeyName(UsbHub hub, ref UsbDevice foundDevice, string driverKeyName)
|
||||
{
|
||||
foreach(UsbPort port in hub.GetPorts())
|
||||
@@ -97,9 +112,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Find a device based upon it's Instance ID
|
||||
//
|
||||
/// <summary>
|
||||
/// Find a device based upon it's Instance ID
|
||||
/// </summary>
|
||||
/// <param name="instanceId">Device instance ID</param>
|
||||
/// <returns>USB device</returns>
|
||||
static UsbDevice FindDeviceByInstanceId(string instanceId)
|
||||
{
|
||||
UsbDevice foundDevice = null;
|
||||
@@ -113,7 +130,12 @@ namespace DiscImageChef.Devices.Windows
|
||||
return foundDevice;
|
||||
}
|
||||
|
||||
// private routine for enumerating a hub
|
||||
/// <summary>
|
||||
/// private routine for enumerating a hub
|
||||
/// </summary>
|
||||
/// <param name="hub">Hub</param>
|
||||
/// <param name="foundDevice">USB device</param>
|
||||
/// <param name="instanceId">Device instance ID</param>
|
||||
static void SearchHubInstanceId(UsbHub hub, ref UsbDevice foundDevice, string instanceId)
|
||||
{
|
||||
foreach(UsbPort port in hub.GetPorts())
|
||||
@@ -135,11 +157,6 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal const string GuidDevinterfaceCdrom = "53f56308-b6bf-11d0-94f2-00a0c91efb8b";
|
||||
internal const string GuidDevinterfaceFloppy = "53f56311-b6bf-11d0-94f2-00a0c91efb8b";
|
||||
|
||||
//typedef struct _STORAGE_DEVICE_NUMBER {
|
||||
// DEVICE_TYPE DeviceType;
|
||||
// ULONG DeviceNumber;
|
||||
// ULONG PartitionNumber;
|
||||
//} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct StorageDeviceNumber
|
||||
{
|
||||
@@ -148,26 +165,18 @@ namespace DiscImageChef.Devices.Windows
|
||||
internal int PartitionNumber;
|
||||
}
|
||||
|
||||
//CMAPI CONFIGRET WINAPI CM_Get_Parent(
|
||||
// OUT PDEVINST pdnDevInst,
|
||||
// IN DEVINST dnDevInst,
|
||||
// IN ULONG ulFlags
|
||||
//);
|
||||
[DllImport("setupapi.dll")]
|
||||
static extern int CM_Get_Parent(out IntPtr pdnDevInst, IntPtr dnDevInst, int ulFlags);
|
||||
|
||||
//CMAPI CONFIGRET WINAPI CM_Get_Device_ID(
|
||||
// IN DEVINST dnDevInst,
|
||||
// OUT PTCHAR Buffer,
|
||||
// IN ULONG BufferLen,
|
||||
// IN ULONG ulFlags
|
||||
//);
|
||||
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
|
||||
static extern int CM_Get_Device_ID(IntPtr dnDevInst, IntPtr buffer, int bufferLen, int ulFlags);
|
||||
|
||||
//
|
||||
// Find a device based upon a Drive Letter
|
||||
//
|
||||
/// <summary>
|
||||
/// Find a device based upon a Drive Letter
|
||||
/// </summary>
|
||||
/// <param name="driveLetter">Drive letter</param>
|
||||
/// <param name="deviceGuid">Device GUID</param>
|
||||
/// <returns>USB device</returns>
|
||||
internal static UsbDevice FindDriveLetter(string driveLetter, string deviceGuid)
|
||||
{
|
||||
// We start by getting the unique DeviceNumber of the given
|
||||
@@ -177,6 +186,12 @@ namespace DiscImageChef.Devices.Windows
|
||||
return devNum < 0 ? null : FindDeviceNumber(devNum, deviceGuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a device based upon a Drive Path
|
||||
/// </summary>
|
||||
/// <param name="drivePath">Drive path</param>
|
||||
/// <param name="deviceGuid">Device GUID</param>
|
||||
/// <returns>USB device</returns>
|
||||
internal static UsbDevice FindDrivePath(string drivePath, string deviceGuid)
|
||||
{
|
||||
// We start by getting the unique DeviceNumber of the given
|
||||
@@ -186,9 +201,12 @@ namespace DiscImageChef.Devices.Windows
|
||||
return devNum < 0 ? null : FindDeviceNumber(devNum, deviceGuid);
|
||||
}
|
||||
|
||||
//
|
||||
// Find a device based upon a Drive Letter
|
||||
//
|
||||
/// <summary>
|
||||
/// Find a device based upon a Device Number
|
||||
/// </summary>
|
||||
/// <param name="devNum">Device Number</param>
|
||||
/// <param name="deviceGuid">Device GUID</param>
|
||||
/// <returns>USB device</returns>
|
||||
static UsbDevice FindDeviceNumber(int devNum, string deviceGuid)
|
||||
{
|
||||
UsbDevice foundDevice = null;
|
||||
@@ -253,7 +271,11 @@ namespace DiscImageChef.Devices.Windows
|
||||
return foundDevice;
|
||||
}
|
||||
|
||||
// return a unique device number for the given device path
|
||||
/// <summary>
|
||||
/// return a unique device number for the given device path
|
||||
/// </summary>
|
||||
/// <param name="devicePath">Device path</param>
|
||||
/// <returns>Device number</returns>
|
||||
static int GetDeviceNumber(string devicePath)
|
||||
{
|
||||
int ans = -1;
|
||||
|
||||
Reference in New Issue
Block a user