BSOne.SFC/Tocsg.Module/Bs1Flt/bs1flt/bs1flt_usb_desc.c

464 lines
16 KiB
C

#include "precomp.h"
NTSTATUS UDF_CallUSBDI(IN PDEVICE_OBJECT pDevObj, IN PVOID UrbEtc)
{
IO_STATUS_BLOCK IoStatus;
KEVENT event;
NTSTATUS status;
PIRP Irp = NULL;
PIO_STACK_LOCATION NextIrpStack = NULL;
//g_Temp = pDevObj;
//g_Temp2 = UrbEtc;
// Initialise IRP completion event
KeInitializeEvent(&event, NotificationEvent, FALSE);
// Build Internal IOCTL IRP
Irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB, pDevObj,
NULL, 0, // Input buffer
NULL, 0, // Output buffer
TRUE, &event, &IoStatus);
// Get IRP stack location for next driver down (already set up)
NextIrpStack = IoGetNextIrpStackLocation(Irp);
// Store pointer to the URB etc
NextIrpStack->Parameters.Others.Argument1 = UrbEtc;
NextIrpStack->Parameters.Others.Argument2 = (PVOID)0;
// Call the driver and wait for completion if necessary
status = IoCallDriver(pDevObj, Irp);
if (status == STATUS_PENDING)
{
KLogEx(DEBUG_TRACE_ERROR, "waiting for URB completion\n");
status = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
status = IoStatus.Status;
}
// return IRP completion status
KLogEx(DEBUG_TRACE_ERROR, "returned %x\n", status);
return status;
}
PURB AllocUrb(USHORT Size)
{
PURB urb = ExAllocatePoolWithTag(NonPagedPool, Size, 'PURB');
if (urb) RtlZeroMemory(urb, Size);
return urb;
}
VOID FreeUsbDeviceInfo(IN PUSB_PARSED_INFO pInfo)
{
if (!pInfo) return;
// 문자열 메모리 해제
if (pInfo->ManufacturerStr) ExFreePool(pInfo->ManufacturerStr);
if (pInfo->ProductStr) ExFreePool(pInfo->ProductStr);
if (pInfo->SerialNumberStr) ExFreePool(pInfo->SerialNumberStr);
// Configuration Descriptor 해제
if (pInfo->ConfigDesc) ExFreePool(pInfo->ConfigDesc);
// 구조체 자체 해제
ExFreePool(pInfo);
}
// ---------------------------------------------------------------------------
// 1. Device Descriptor 가져오기
// ---------------------------------------------------------------------------
NTSTATUS GetUsbDeviceDescriptor(
IN PDEVICE_OBJECT DeviceObject,
OUT PUSB_DEVICE_DESCRIPTOR* ppDescriptor
)
{
PURB urb = NULL;
PUSB_DEVICE_DESCRIPTOR descriptor = NULL;
NTSTATUS status;
urb = AllocUrb(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (!urb) return STATUS_INSUFFICIENT_RESOURCES;
descriptor = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_DEVICE_DESCRIPTOR), 'DST');
if (!descriptor) {
ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(descriptor, sizeof(USB_DEVICE_DESCRIPTOR));
UsbBuildGetDescriptorRequest(
urb,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0, 0,
descriptor, NULL,
sizeof(USB_DEVICE_DESCRIPTOR), NULL
);
status = UDF_CallUSBDI(DeviceObject, urb);
if (!NT_SUCCESS(status)) {
ExFreePool(descriptor);
*ppDescriptor = NULL;
}
else {
*ppDescriptor = descriptor;
}
ExFreePool(urb);
return status;
}
// ---------------------------------------------------------------------------
// 2. String Descriptor 가져오기 (특정 Index, Language ID)
// ---------------------------------------------------------------------------
NTSTATUS GetUsbStringDescriptor(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Index,
IN USHORT LangId,
OUT PWCHAR* ppStringData
)
{
PURB urb = NULL;
PUSB_STRING_DESCRIPTOR pStrDesc = NULL;
NTSTATUS status;
ULONG size = 256; // 넉넉하게 잡음
if (Index == 0) return STATUS_INVALID_PARAMETER;
urb = AllocUrb(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (!urb) return STATUS_INSUFFICIENT_RESOURCES;
pStrDesc = ExAllocatePoolWithTag(NonPagedPool, size, 'STR');
if (!pStrDesc) {
ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(pStrDesc, size);
UsbBuildGetDescriptorRequest(
urb,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_STRING_DESCRIPTOR_TYPE,
Index,
LangId,
pStrDesc, NULL,
size, NULL
);
status = UDF_CallUSBDI(DeviceObject, urb);
if (NT_SUCCESS(status) && pStrDesc->bLength > 2) {
// bString은 WCHAR 배열입니다. NULL Termination을 위해 별도 버퍼에 복사
ULONG strLenBytes = pStrDesc->bLength - 2;
PWCHAR outBuf = ExAllocatePoolWithTag(NonPagedPool, strLenBytes + sizeof(WCHAR), 'STR2');
if (outBuf) {
RtlZeroMemory(outBuf, strLenBytes + sizeof(WCHAR));
RtlCopyMemory(outBuf, pStrDesc->bString, strLenBytes);
*ppStringData = outBuf;
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else {
*ppStringData = NULL;
status = STATUS_UNSUCCESSFUL;
}
ExFreePool(pStrDesc);
ExFreePool(urb);
return status;
}
// ---------------------------------------------------------------------------
// 3. Configuration Descriptor 전체 가져오기 (Interface, Endpoint 포함)
// ---------------------------------------------------------------------------
NTSTATUS GetUsbFullConfigDescriptor(
IN PDEVICE_OBJECT DeviceObject,
OUT PUSB_CONFIGURATION_DESCRIPTOR* ppConfigDesc
)
{
PURB urb = NULL;
PUSB_CONFIGURATION_DESCRIPTOR pHeader = NULL;
PUSB_CONFIGURATION_DESCRIPTOR pFullDesc = NULL;
NTSTATUS status;
ULONG fullSize = 0;
// 1단계: 헤더(9바이트)만 먼저 읽어서 전체 크기(wTotalLength) 파악
urb = AllocUrb(sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (!urb) return STATUS_INSUFFICIENT_RESOURCES;
pHeader = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_CONFIGURATION_DESCRIPTOR), 'CFG');
if (!pHeader) {
ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
UsbBuildGetDescriptorRequest(
urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0,
pHeader, NULL, sizeof(USB_CONFIGURATION_DESCRIPTOR), NULL
);
status = UDF_CallUSBDI(DeviceObject, urb);
if (!NT_SUCCESS(status)) {
ExFreePool(pHeader);
ExFreePool(urb);
return status;
}
fullSize = pHeader->wTotalLength;
ExFreePool(pHeader); // 헤더는 이제 필요 없음 (크기 알았으므로)
// 2단계: 전체 크기만큼 할당 후 다시 요청
pFullDesc = ExAllocatePoolWithTag(NonPagedPool, fullSize, 'CFG');
if (!pFullDesc) {
ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
// URB 재사용을 위해 ZeroMemory (버퍼 포인터 등이 바뀌므로)
RtlZeroMemory(urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
UsbBuildGetDescriptorRequest(
urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0,
pFullDesc, NULL, fullSize, NULL
);
status = UDF_CallUSBDI(DeviceObject, urb);
if (NT_SUCCESS(status)) {
*ppConfigDesc = pFullDesc;
}
else {
ExFreePool(pFullDesc);
*ppConfigDesc = NULL;
}
ExFreePool(urb);
return status;
}
// ---------------------------------------------------------------------------
// Main Logic: 모든 정보를 수집하고 출력(Logging)하는 함수
// ---------------------------------------------------------------------------
VOID GetAllUsbDeviceInfo(PDEVICE_OBJECT DeviceObject)
{
NTSTATUS status;
PUSB_DEVICE_DESCRIPTOR pDevDesc = NULL;
PUSB_CONFIGURATION_DESCRIPTOR pConfigDesc = NULL;
USHORT LangId = 0x0409; // Default English
KLogEx(DEBUG_TRACE_INFO, "===== START USB INFO COLLECTION =====\n");
// 1. Device Descriptor 수집
status = GetUsbDeviceDescriptor(DeviceObject, &pDevDesc);
if (NT_SUCCESS(status) && pDevDesc)
{
KLogEx(DEBUG_TRACE_INFO, "[Device Descriptor]\n");
KLogEx(DEBUG_TRACE_INFO, " bLength: 0x%X\n", pDevDesc->bLength);
KLogEx(DEBUG_TRACE_INFO, " bDescriptorType: 0x%X\n", pDevDesc->bDescriptorType);
KLogEx(DEBUG_TRACE_INFO, " bcdUSB: 0x%X\n", pDevDesc->bcdUSB);
KLogEx(DEBUG_TRACE_INFO, " idVendor: 0x%04X\n", pDevDesc->idVendor);
KLogEx(DEBUG_TRACE_INFO, " idProduct: 0x%04X\n", pDevDesc->idProduct);
KLogEx(DEBUG_TRACE_INFO, " bcdDevice: 0x%X\n", pDevDesc->bcdDevice);
KLogEx(DEBUG_TRACE_INFO, " bNumConfigurations: 0x%X\n", pDevDesc->bNumConfigurations);
// String Descriptor 수집 (Manufacturer, Product, Serial)
// 실제로는 String Index 0을 먼저 호출하여 지원 언어를 확인해야 하지만,
// 여기서는 편의상 0x0409(English)를 시도합니다.
if (pDevDesc->iManufacturer)
{
PWCHAR pStr = NULL;
if (NT_SUCCESS(GetUsbStringDescriptor(DeviceObject, pDevDesc->iManufacturer, LangId, &pStr)) && pStr) {
KLogEx(DEBUG_TRACE_INFO, " Manufacturer: %ws\n", pStr);
ExFreePool(pStr);
}
}
if (pDevDesc->iProduct)
{
PWCHAR pStr = NULL;
if (NT_SUCCESS(GetUsbStringDescriptor(DeviceObject, pDevDesc->iProduct, LangId, &pStr)) && pStr) {
KLogEx(DEBUG_TRACE_INFO, " Product: %ws\n", pStr);
ExFreePool(pStr);
}
}
if (pDevDesc->iSerialNumber)
{
PWCHAR pStr = NULL;
if (NT_SUCCESS(GetUsbStringDescriptor(DeviceObject, pDevDesc->iSerialNumber, LangId, &pStr)) && pStr) {
KLogEx(DEBUG_TRACE_INFO, " SerialNumber: %ws\n", pStr);
ExFreePool(pStr);
}
}
}
// 2. Configuration Descriptor (Full) 수집 및 파싱
status = GetUsbFullConfigDescriptor(DeviceObject, &pConfigDesc);
if (NT_SUCCESS(status) && pConfigDesc)
{
PUCHAR pCurr = (PUCHAR)pConfigDesc;
PUCHAR pEnd = pCurr + pConfigDesc->wTotalLength;
KLogEx(DEBUG_TRACE_INFO, "[Configuration Descriptor]\n");
KLogEx(DEBUG_TRACE_INFO, " wTotalLength: 0x%X\n", pConfigDesc->wTotalLength);
KLogEx(DEBUG_TRACE_INFO, " bNumInterfaces: 0x%X\n", pConfigDesc->bNumInterfaces);
KLogEx(DEBUG_TRACE_INFO, " bConfigurationValue: 0x%X\n", pConfigDesc->bConfigurationValue);
KLogEx(DEBUG_TRACE_INFO, " MaxPower: 0x%X", pConfigDesc->MaxPower);
// Loop를 돌면서 Interface 및 Endpoint 파싱
// 첫 번째 Descriptor는 Configuration이므로 건너뜀
pCurr += pConfigDesc->bLength;
while (pCurr < pEnd)
{
PUSB_COMMON_DESCRIPTOR pCommon = (PUSB_COMMON_DESCRIPTOR)pCurr;
if (pCommon->bLength == 0) break; // 에러 방지
if (pCommon->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
{
PUSB_INTERFACE_DESCRIPTOR pIntf = (PUSB_INTERFACE_DESCRIPTOR)pCommon;
KLogEx(DEBUG_TRACE_INFO, "[Interface Descriptor]\n");
KLogEx(DEBUG_TRACE_INFO, " bInterfaceNumber: 0x%X\n", pIntf->bInterfaceNumber);
KLogEx(DEBUG_TRACE_INFO, " bAlternateSetting: 0x%X\n", pIntf->bAlternateSetting);
KLogEx(DEBUG_TRACE_INFO, " bNumEndpoints: 0x%X\n", pIntf->bNumEndpoints);
KLogEx(DEBUG_TRACE_INFO, " bInterfaceClass: 0x%X\n", pIntf->bInterfaceClass);
KLogEx(DEBUG_TRACE_INFO, " bInterfaceSubClass: 0x%X\n", pIntf->bInterfaceSubClass);
KLogEx(DEBUG_TRACE_INFO, " bInterfaceProtocol: 0x%X\n", pIntf->bInterfaceProtocol);
}
else if (pCommon->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
{
PUSB_ENDPOINT_DESCRIPTOR pEp = (PUSB_ENDPOINT_DESCRIPTOR)pCommon;
KLogEx(DEBUG_TRACE_INFO, "[Endpoint Descriptor]\n");
KLogEx(DEBUG_TRACE_INFO, " bEndpointAddress: 0x%X\n", pEp->bEndpointAddress);
KLogEx(DEBUG_TRACE_INFO, " bmAttributes: 0x%X\n", pEp->bmAttributes);
KLogEx(DEBUG_TRACE_INFO, " wMaxPacketSize: 0x%X\n", pEp->wMaxPacketSize);
KLogEx(DEBUG_TRACE_INFO, " bInterval: 0x%X\n", pEp->bInterval);
}
pCurr += pCommon->bLength;
}
}
// 메모리 정리
if (pDevDesc) ExFreePool(pDevDesc);
if (pConfigDesc) ExFreePool(pConfigDesc);
KLogEx(DEBUG_TRACE_INFO, "===== END USB INFO COLLECTION =====\n");
}
NTSTATUS CollectUsbDeviceInfo(
IN PDEVICE_OBJECT DeviceObject,
OUT PUSB_PARSED_INFO* ppInfo
)
{
NTSTATUS status;
PUSB_PARSED_INFO pInfo = NULL;
PUSB_DEVICE_DESCRIPTOR pDevDesc = NULL;
USHORT LangId = 0x0409; // English (US)
*ppInfo = NULL;
if (KeGetCurrentIrql() > APC_LEVEL)
{
KLogEx(DEBUG_TRACE_ERROR, "not APC_LEVEL\n");
return STATUS_INVALID_DEVICE_STATE;
}
// 1. 구조체 할당
pInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_PARSED_INFO), 'INFO');
if (!pInfo) return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(pInfo, sizeof(USB_PARSED_INFO));
// 2. Device Descriptor 수집
status = GetUsbDeviceDescriptor(DeviceObject, &pDevDesc);
if (!NT_SUCCESS(status) || !pDevDesc) {
FreeUsbDeviceInfo(pInfo);
return status;
}
// 구조체에 복사 후 임시 버퍼 해제
RtlCopyMemory(&pInfo->DeviceDesc, pDevDesc, sizeof(USB_DEVICE_DESCRIPTOR));
ExFreePool(pDevDesc);
// 3. String Descriptor 수집 (Manufacturer, Product, Serial)
if (pInfo->DeviceDesc.iManufacturer) {
GetUsbStringDescriptor(DeviceObject, pInfo->DeviceDesc.iManufacturer, LangId, &pInfo->ManufacturerStr);
}
if (pInfo->DeviceDesc.iProduct) {
GetUsbStringDescriptor(DeviceObject, pInfo->DeviceDesc.iProduct, LangId, &pInfo->ProductStr);
}
if (pInfo->DeviceDesc.iSerialNumber) {
GetUsbStringDescriptor(DeviceObject, pInfo->DeviceDesc.iSerialNumber, LangId, &pInfo->SerialNumberStr);
}
// 4. Configuration Descriptor (Full) 수집
// ConfigDesc는 내부적으로 할당된 메모리를 그대로 포인터로 연결
status = GetUsbFullConfigDescriptor(DeviceObject, &pInfo->ConfigDesc);
if (NT_SUCCESS(status) && pInfo->ConfigDesc)
{
pInfo->ConfigDescSize = pInfo->ConfigDesc->wTotalLength;
PUCHAR pCurr = (PUCHAR)pInfo->ConfigDesc;
PUCHAR pEnd = pCurr + pInfo->ConfigDescSize;
LONG currentInterfaceIndex = -1; // 현재 파싱 중인 인터페이스 번호
if (pCurr + sizeof(USB_CONFIGURATION_DESCRIPTOR) < pEnd)
pCurr += ((PUSB_COMMON_DESCRIPTOR)pCurr)->bLength;
while (pCurr < pEnd)
{
PUSB_COMMON_DESCRIPTOR pCommon = (PUSB_COMMON_DESCRIPTOR)pCurr;
// 유효성 체크
if (pCommon->bLength == 0 || pCurr + pCommon->bLength > pEnd)
break;
// Interface Descriptor 확인
if (pCommon->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) {
PUSB_INTERFACE_DESCRIPTOR pIntf = (PUSB_INTERFACE_DESCRIPTOR)pCommon;
currentInterfaceIndex = pIntf->bInterfaceNumber;
}
// [B] HID Descriptor 발견 (0x21)
else if (pCommon->bDescriptorType == USB_DESCRIPTOR_TYPE_HID)
{
PUSB_HID_DESCRIPTOR pHid = (PUSB_HID_DESCRIPTOR)pCommon;
// 저장 공간이 있고, 유효한 인터페이스 내부에 있는 경우
if (pInfo->HidInterfaceCount < MAX_HID_INTERFACES && currentInterfaceIndex >= 0)
{
ULONG idx = pInfo->HidInterfaceCount;
pInfo->HidEntries[idx].InterfaceNumber = (UCHAR)currentInterfaceIndex;
pInfo->HidEntries[idx].HidDesc = pHid;
pInfo->HidInterfaceCount++;
KLogEx(DEBUG_TRACE_INFO, " Found HID Desc at Interface %d (Count: %d)\n",
currentInterfaceIndex, pInfo->HidInterfaceCount);
}
}
pCurr += pCommon->bLength;
}
}
else
{
pInfo->ConfigDesc = NULL;
pInfo->ConfigDescSize = 0;
}
// 성공 시 포인터 반환
*ppInfo = pInfo;
return STATUS_SUCCESS;
}