mirror of
https://github.com/aaru-dps/aaruremote.git
synced 2025-12-16 19:24:37 +00:00
312 lines
11 KiB
C
312 lines
11 KiB
C
/*
|
|
* This file is part of the Aaru Remote Server.
|
|
* Copyright (c) 2019-2025 Natalia Portillo.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
|
|
#include "win32.h"
|
|
#include "../aaruremote.h"
|
|
#include "ntioctl.h"
|
|
|
|
int32_t SendSdhciCommand(void* device_ctx,
|
|
uint8_t command,
|
|
uint8_t write,
|
|
uint8_t application,
|
|
uint32_t flags,
|
|
uint32_t argument,
|
|
uint32_t block_size,
|
|
uint32_t blocks,
|
|
char* buffer,
|
|
uint32_t buf_len,
|
|
uint32_t timeout,
|
|
uint32_t* response,
|
|
uint32_t* duration,
|
|
uint32_t* sense)
|
|
{
|
|
DeviceContext* ctx = device_ctx;
|
|
DWORD cmdbuf_len;
|
|
PCHAR cmdbuf;
|
|
PSFFDISK_DEVICE_COMMAND_DATA cmd_data;
|
|
PSDCMD_DESCRIPTOR cmd_descriptor;
|
|
PCHAR data_buf;
|
|
DWORD error = 0;
|
|
DWORD k = 0;
|
|
LARGE_INTEGER frequency;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER end;
|
|
DOUBLE interval;
|
|
|
|
if(!ctx) return -1;
|
|
|
|
cmdbuf_len = sizeof(SFFDISK_DEVICE_COMMAND_DATA) + sizeof(SDCMD_DESCRIPTOR) + buf_len;
|
|
|
|
cmdbuf = malloc(cmdbuf_len);
|
|
|
|
if(!cmdbuf) return -1;
|
|
|
|
memset(cmdbuf, 0, cmdbuf_len);
|
|
cmd_data = (PSFFDISK_DEVICE_COMMAND_DATA)cmdbuf;
|
|
cmd_descriptor = (PSDCMD_DESCRIPTOR)(cmdbuf + sizeof(SFFDISK_DEVICE_COMMAND_DATA));
|
|
data_buf = cmdbuf + sizeof(SFFDISK_DEVICE_COMMAND_DATA) + sizeof(SDCMD_DESCRIPTOR);
|
|
|
|
memcpy(data_buf, buffer, buf_len);
|
|
|
|
cmd_data->HeaderSize = sizeof(SFFDISK_DEVICE_COMMAND_DATA);
|
|
cmd_data->Command = SFFDISK_DC_DEVICE_COMMAND;
|
|
cmd_data->ProtocolArgumentSize = sizeof(SDCMD_DESCRIPTOR);
|
|
cmd_data->DeviceDataBufferSize = buf_len;
|
|
cmd_descriptor->Cmd = command;
|
|
cmd_descriptor->CmdClass = application ? SDCC_APP_CMD : SDCC_STANDARD;
|
|
cmd_descriptor->TransferDirection = write ? SDTD_WRITE : SDTD_READ;
|
|
cmd_descriptor->ResponseType = 0;
|
|
cmd_descriptor->TransferType =
|
|
(flags & AARUREMOTE_MMC_COMMAND_ADTC) ? (command == 18) ? SDTT_MULTI_BLOCK : SDTT_SINGLE_BLOCK : SDTT_CMD_ONLY;
|
|
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R1) || (flags & AARUREMOTE_MMC_RESPONSE_SPI_R1))
|
|
cmd_descriptor->ResponseType = SDRT_1;
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R1B) || (flags & AARUREMOTE_MMC_RESPONSE_SPI_R1B))
|
|
cmd_descriptor->ResponseType = SDRT_1B;
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R2) || (flags & AARUREMOTE_MMC_RESPONSE_SPI_R2))
|
|
cmd_descriptor->ResponseType = SDRT_2;
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R3) || (flags & AARUREMOTE_MMC_RESPONSE_SPI_R3))
|
|
cmd_descriptor->ResponseType = SDRT_3;
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R4) || (flags & AARUREMOTE_MMC_RESPONSE_SPI_R4))
|
|
cmd_descriptor->ResponseType = SDRT_4;
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R5) || (flags & AARUREMOTE_MMC_RESPONSE_SPI_R5))
|
|
cmd_descriptor->ResponseType = SDRT_5;
|
|
if((flags & AARUREMOTE_MMC_RESPONSE_R6)) cmd_descriptor->ResponseType = SDRT_6;
|
|
|
|
QueryPerformanceFrequency(&frequency);
|
|
QueryPerformanceCounter(&start);
|
|
*sense =
|
|
!DeviceIoControl(ctx->handle, IOCTL_SFFDISK_DEVICE_COMMAND, cmdbuf, cmdbuf_len, cmdbuf, cmdbuf_len, &k, NULL);
|
|
QueryPerformanceCounter(&end);
|
|
|
|
interval = (DOUBLE)(end.QuadPart - start.QuadPart) / frequency.QuadPart;
|
|
*duration = (uint32_t)(interval * 1000.0);
|
|
|
|
if(*sense) error = GetLastError();
|
|
|
|
memcpy(buffer, data_buf, buf_len);
|
|
|
|
free(cmdbuf);
|
|
return error;
|
|
}
|
|
|
|
BOOL GuidEquals(GUID a, GUID b) { return memcmp(&a, &b, 16) == 0; }
|
|
|
|
BOOL IsSdhci(HANDLE handle)
|
|
{
|
|
SFFDISK_QUERY_DEVICE_PROTOCOL_DATA query;
|
|
DWORD k = 0;
|
|
GUID sdGuid = GUID_SFF_PROTOCOL_SD;
|
|
GUID mmcGuid = GUID_SFF_PROTOCOL_MMC;
|
|
|
|
DeviceIoControl(handle,
|
|
IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL,
|
|
NULL,
|
|
0,
|
|
&query,
|
|
sizeof(SFFDISK_QUERY_DEVICE_PROTOCOL_DATA),
|
|
&k,
|
|
NULL);
|
|
|
|
return GuidEquals(query.ProtocolGUID, sdGuid) || GuidEquals(query.ProtocolGUID, mmcGuid);
|
|
}
|
|
|
|
int32_t GetSdhciRegisters(void* device_ctx,
|
|
char** csd,
|
|
char** cid,
|
|
char** ocr,
|
|
char** scr,
|
|
uint32_t* csd_len,
|
|
uint32_t* cid_len,
|
|
uint32_t* ocr_len,
|
|
uint32_t* scr_len)
|
|
{
|
|
DeviceContext* ctx = device_ctx;
|
|
uint32_t duration;
|
|
uint32_t sense;
|
|
|
|
if(!ctx) return -1;
|
|
|
|
if(!IsSdhci(ctx->handle)) return -1;
|
|
|
|
*csd = malloc(16);
|
|
if(*csd)
|
|
{
|
|
*csd_len = 16;
|
|
SendSdhciCommand(device_ctx,
|
|
9,
|
|
0,
|
|
0,
|
|
AARUREMOTE_MMC_RESPONSE_SPI_R2 | AARUREMOTE_MMC_RESPONSE_R2 | AARUREMOTE_MMC_COMMAND_AC,
|
|
0,
|
|
16,
|
|
1,
|
|
*csd,
|
|
*csd_len,
|
|
1000,
|
|
NULL,
|
|
&duration,
|
|
&sense);
|
|
|
|
if(sense)
|
|
{
|
|
*csd_len = 0;
|
|
free(*csd);
|
|
}
|
|
}
|
|
|
|
*cid = malloc(16);
|
|
if(*cid)
|
|
{
|
|
*cid_len = 16;
|
|
SendSdhciCommand(device_ctx,
|
|
10,
|
|
0,
|
|
0,
|
|
AARUREMOTE_MMC_RESPONSE_SPI_R2 | AARUREMOTE_MMC_RESPONSE_R2 | AARUREMOTE_MMC_COMMAND_AC,
|
|
0,
|
|
16,
|
|
1,
|
|
*cid,
|
|
*cid_len,
|
|
1000,
|
|
NULL,
|
|
&duration,
|
|
&sense);
|
|
|
|
if(sense)
|
|
{
|
|
*cid_len = 0;
|
|
free(*cid);
|
|
}
|
|
}
|
|
|
|
*scr = malloc(8);
|
|
if(*scr)
|
|
{
|
|
*scr_len = 8;
|
|
SendSdhciCommand(device_ctx,
|
|
10,
|
|
0,
|
|
0,
|
|
AARUREMOTE_MMC_RESPONSE_SPI_R1 | AARUREMOTE_MMC_RESPONSE_R1 | AARUREMOTE_MMC_COMMAND_ADTC,
|
|
0,
|
|
8,
|
|
1,
|
|
*scr,
|
|
*scr_len,
|
|
1000,
|
|
NULL,
|
|
&duration,
|
|
&sense);
|
|
|
|
if(sense)
|
|
{
|
|
*scr_len = 0;
|
|
free(*scr);
|
|
}
|
|
}
|
|
|
|
*ocr = malloc(4);
|
|
if(*ocr)
|
|
{
|
|
*ocr_len = 4;
|
|
SendSdhciCommand(device_ctx,
|
|
*scr_len > 0 ? 41 : 1,
|
|
0,
|
|
0,
|
|
AARUREMOTE_MMC_RESPONSE_SPI_R1 | AARUREMOTE_MMC_RESPONSE_R1 | AARUREMOTE_MMC_COMMAND_ADTC,
|
|
0,
|
|
4,
|
|
1,
|
|
*ocr,
|
|
*ocr_len,
|
|
1000,
|
|
NULL,
|
|
&duration,
|
|
&sense);
|
|
|
|
if(sense)
|
|
{
|
|
*ocr_len = 0;
|
|
free(*ocr);
|
|
}
|
|
}
|
|
|
|
return *csd_len > 0 || *cid_len > 0 || *scr_len > 0 || *ocr_len > 0;
|
|
}
|
|
|
|
int32_t SendMultiSdhciCommand(void* device_ctx,
|
|
uint64_t count,
|
|
MmcSingleCommand commands[],
|
|
uint32_t* duration,
|
|
uint32_t* sense)
|
|
{
|
|
DeviceContext* ctx = device_ctx;
|
|
*duration = 0;
|
|
*sense = 0;
|
|
uint64_t i;
|
|
int32_t error = 0, single_error;
|
|
uint32_t single_sense, single_duration;
|
|
|
|
if(!ctx) return -1;
|
|
|
|
if(count == 3 && commands[0].command == 16 && // SET_BLOCK_LEN
|
|
commands[1].command == 18 && // READ_MULTIPLE_BLOCK
|
|
commands[2].command == 12) // STOP_TRANSMISSION
|
|
return SendSdhciCommand(device_ctx,
|
|
commands[1].command,
|
|
commands[1].write,
|
|
commands[1].application,
|
|
commands[1].flags,
|
|
commands[1].argument,
|
|
commands[1].block_size,
|
|
commands[1].blocks,
|
|
commands[1].buffer,
|
|
commands[1].buf_len,
|
|
0,
|
|
commands[1].response,
|
|
duration,
|
|
sense);
|
|
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
single_error = SendSdhciCommand(device_ctx,
|
|
commands[i].command,
|
|
commands[i].write,
|
|
commands[i].application,
|
|
commands[i].flags,
|
|
commands[i].argument,
|
|
commands[i].block_size,
|
|
commands[i].blocks,
|
|
commands[i].buffer,
|
|
commands[i].buf_len,
|
|
0,
|
|
commands[i].response,
|
|
&single_duration,
|
|
&single_sense);
|
|
if(error == 0 && single_error != 0) error = single_error;
|
|
|
|
*duration += single_duration;
|
|
|
|
if(single_sense) *sense = TRUE;
|
|
}
|
|
|
|
return error;
|
|
} |