/*++ Copyright (c) 1999 Microsoft Corporation Module Name: struc.c Abstract: WinDbg Extension Api implements !_devh dumps USBD_DEVICE_HANDLE !_piph dumps USBD_PIPE_HANDLE_I !_endp dumps HCD_ENDPOINT !_cmbf dumps USBPORT_COMMON_BUFFER !_tfer dumps HCD_TRANSFER_CONTEXT !_mdl dumps MDL !_cfgh dumps Author: jd Environment: User Mode. Revision History: --*/ #include "precomp.h" #include "usbhcdkd.h" VOID DumpDeviceHandle( MEMLOC MemLoc ) { MEMLOC l, t; USB_DEVICE_DESCRIPTOR dd; ULONG f, cb; UCHAR cs[] = "_USBD_DEVICE_HANDLE"; STRUC_ENTRY DevHandle[] = { "Sig", FT_SIG, "DeviceAddress", FT_USHORT, "Tt", FT_PTR, "PendingUrbs", FT_ULONG, "PortNumber", FT_USHORT, "HubDeviceHandle", FT_PTR, "ConfigurationHandle", FT_PTR, "DeviceSpeed", FT_DEVSPEED }; FLAG_TABLE devFlags[] = { "USBPORT_DEVICEFLAG_ROOTHUB", USBPORT_DEVICEFLAG_ROOTHUB, "USBPORT_DEVICEFLAG_FREED_BY_HUB", USBPORT_DEVICEFLAG_FREED_BY_HUB }; PrintfMemLoc("*USBD_DEVICE_HANDLE ", MemLoc, "\n"); UsbDumpStruc(MemLoc, cs, &DevHandle[0], sizeof(DevHandle)/sizeof(STRUC_ENTRY)); f = UsbReadFieldUlong(MemLoc, cs, "DeviceFlags"); dprintf("DeviceFlags: %08.8x\n", f); UsbDumpFlags(f, devFlags, sizeof(devFlags)/sizeof(FLAG_TABLE)); dprintf("-pipe list-\n"); l = MemLoc + UsbFieldOffset(cs, "PipeHandleList"); PrintfMemLoc("\t(PH) PipeHandleList: ", l, ListEmpty(l)); dprintf("-tt list-\n"); l = MemLoc + UsbFieldOffset(cs, "TtList"); PrintfMemLoc("\t(TT) TtList: ", l, ListEmpty(l)); t = MemLoc + UsbFieldOffset(cs, "DeviceDescriptor"); PrintfMemLoc("DeviceDescriptor ", t, "\n"); ReadMemory(t, &dd, sizeof(dd), &cb); DumpUSBDescriptor(&dd); } VOID DumpTt( MEMLOC MemLoc ) { ULONG f, i; UCHAR cs[] = "_TRANSACTION_TRANSLATOR"; UCHAR s[64]; STRUC_ENTRY tt[] = { "Sig", FT_SIG, "DeviceAddress", FT_USHORT, "PdoDeviceObject", FT_PTR, }; PrintfMemLoc("*TRANSACTION_TRANSLATOR ", MemLoc, "\n"); UsbDumpStruc(MemLoc, cs, &tt[0], sizeof(tt)/sizeof(STRUC_ENTRY)); f = UsbReadFieldUlong(MemLoc, cs, "TotalBusBandwidth"); dprintf("TotalBusBandwidth: %d\n", f); for (i=0; i\n"); UsbDumpStruc(tmp, "_TRANSFER_PARAMETERS", &tp[0], sizeof(tp)/sizeof(STRUC_ENTRY)); } { STRUC_ENTRY sg[] = { "SgFlags", FT_ULONG, "MdlVirtualAddress", FT_PTR, "MdlSystemAddress", FT_PTR, "SgCount", FT_ULONG, }; sgList = MemLoc + UsbFieldOffset(cs, "SgList"); dprintf("\n"); UsbDumpStruc(sgList, "_TRANSFER_SG_LIST", &sg[0], sizeof(sg)/sizeof(STRUC_ENTRY)); c = UsbReadFieldUlong(sgList, "_TRANSFER_SG_LIST", "SgCount"); } dprintf("\n", c); for (i=0; i< c; i++) { UCHAR s[64]; MEMLOC tmp; STRUC_ENTRY sg[] = { "StartOffset", FT_ULONG, "Length", FT_ULONG, "LogicalAddress", FT_PTR, "SystemAddress", FT_PTR }; sprintf(s, "SgEntry[%d]", i); tmp = sgList + UsbFieldOffset("_TRANSFER_SG_LIST", s); dprintf(" [%d]\n", i); UsbDumpStruc(tmp, "TRANSFER_SG_ENTRY32", &sg[0], sizeof(sg)/sizeof(STRUC_ENTRY)); } #if 0 // dump the sg list dprintf("SGList.SgFlags: %08.8x\n", transfer->SgList.SgFlags); dprintf("SGList.MdlVirtualAddress: %08.8x\n", transfer->SgList.MdlVirtualAddress); dprintf("SGList.SgCount: %08.8x\n", transfer->SgList.SgCount); for (i=0; i< transfer->SgList.SgCount; i++) { dprintf("SGList.SgEntry[%d].StartOffset: %08.8x\n", i, transfer->SgList.SgEntry[i].StartOffset); dprintf("SGList.SgEntry[%d].Length: %08.8x\n", i, transfer->SgList.SgEntry[i].Length); dprintf("SGList.SgEntry[%d].LogicalAddress: %08.8x\n", i, transfer->SgList.SgEntry[i].LogicalAddress); } if (transfer->Flags & USBPORT_TXFLAG_ISO) { DumpIsoTransferContext((ULONG) transfer->IsoTransfer); } free(transfer); } #endif } VOID EpStatus( MP_ENDPOINT_STATUS status ) { switch(status) { case ENDPOINT_STATUS_RUN: dprintf("\t ENDPOINT_STAUS_RUN\n"); break; case ENDPOINT_STATUS_HALT: dprintf("\t ENDPOINT_STATUS_HALT\n"); break; } } VOID EpState( MP_ENDPOINT_STATE state ) { switch(state) { case ENDPOINT_TRANSITION: dprintf("\t ENDPOINT_TRANSITION\n"); break; case ENDPOINT_IDLE: dprintf("\t ENDPOINT_IDLE\n"); break; case ENDPOINT_PAUSE: dprintf("\t ENDPOINT_PAUSE\n"); break; case ENDPOINT_ACTIVE: dprintf("\t ENDPOINT_ACTIVE\n"); break; case ENDPOINT_REMOVE: dprintf("\t ENDPOINT_REMOVE\n"); break; case ENDPOINT_CLOSED: dprintf("\t ENDPOINT_CLOSED\n"); break; } } VOID EpType( ENDPOINT_TRANSFER_TYPE Typ ) { switch(Typ) { case Isochronous: dprintf("Isochronous"); break; case Control: dprintf("Control"); break; case Bulk: dprintf("Bulk"); break; case Interrupt: dprintf("Interrupt"); break; } } VOID EpDir( ENDPOINT_TRANSFER_DIRECTION Dir ) { switch(Dir) { case In: dprintf("In"); break; case Out: dprintf("Out"); break; } } VOID EpSpeed( DEVICE_SPEED Speed ) { switch(Speed) { case LowSpeed: dprintf("LowSpeed"); break; case FullSpeed: dprintf("FullSpeed"); break; case HighSpeed: dprintf("HighSpeed"); break; } } VOID DumpEndpointParameters( MEMLOC MemLoc ) { UCHAR cs[] = "_ENDPOINT_PARAMETERS"; PrintfMemLoc("-endpoint Parameters- ", MemLoc, "\n"); dprintf("\tDeviceAddress: 0x%x\n", UsbReadFieldUshort(MemLoc, cs, "DeviceAddress")); dprintf("\tEndpointAddress: 0x%x\n", UsbReadFieldUshort(MemLoc, cs, "EndpointAddress")); dprintf("\tMaxPacketSize: 0x%08.8x\n", UsbReadFieldUshort(MemLoc, cs, "MaxPacketSize")); dprintf("\tPeriod: 0x%0.2x\n", UsbReadFieldUchar(MemLoc, cs, "Period")); dprintf("\tMaxPeriod: 0x%0.2x\n", UsbReadFieldUchar(MemLoc, cs, "MaxPeriod")); dprintf("\tBandwidth: 0x%08.8x %d Bits/Sec\n", UsbReadFieldUlong(MemLoc, cs, "Bandwidth"), UsbReadFieldUlong(MemLoc, cs, "Bandwidth")); dprintf("\tSchedule Offset: %d\n", UsbReadFieldUlong(MemLoc, cs, "ScheduleOffset")); dprintf("\tType: "); EpType(UsbReadFieldUlong(MemLoc, cs, "TransferType")); dprintf("\n\tDirection: "); EpDir(UsbReadFieldUlong(MemLoc, cs, "TransferDirection")); dprintf("\n"); PrintfMemLoc("\tCommonBufferVa: ", UsbReadFieldPtr(MemLoc, cs, "CommonBufferVa"), "\n"); dprintf("\tCommonBufferPhys (32 bit): %08.8x\n", UsbReadFieldUlong(MemLoc, cs, "CommonBufferPhys")); dprintf("\tCommonBufferBytes: %08.8x\n", UsbReadFieldUlong(MemLoc, cs, "CommonBufferBytes")); dprintf("\tEndpointFlags: 0x%08.8x\n", UsbReadFieldUlong(MemLoc, cs, "EndpointFlags")); dprintf("\tMaxTransferSize: %08.8x\n", UsbReadFieldUlong(MemLoc, cs, "MaxTransferSize")); dprintf("\tDeviceSpeed: %d - ", UsbReadFieldUlong(MemLoc, cs, "DeviceSpeed")); EpSpeed(UsbReadFieldUlong(MemLoc, cs, "DeviceSpeed")); dprintf("\n"); dprintf("\tTtDeviceAddress: 0x%x - ", UsbReadFieldUlong(MemLoc, cs, "TtDeviceAddress")); dprintf("TtNumber: %d - \n", UsbReadFieldUlong(MemLoc, cs, "TtNumber")); dprintf("\tInterruptScheduleMask: x%x - \n", UsbReadFieldUchar(MemLoc, cs, "InterruptScheduleMask")); dprintf("\tSplitCompletionMask: x%x - \n", UsbReadFieldUchar(MemLoc, cs, "SplitCompletionMask")); dprintf("\tTransactionsPerMicroframe: x%x - \n", UsbReadFieldUchar(MemLoc, cs, "TransactionsPerMicroframe")); dprintf("\tMuxPacketSize: x%x - \n", UsbReadFieldUshort(MemLoc, cs, "MuxPacketSize")); dprintf("\tOrdinal: x%x - \n", UsbReadFieldUlong(MemLoc, cs, "Ordinal")); } VOID DumpEndpoint( MEMLOC MemLoc ) { UCHAR cs[] = "_HCD_ENDPOINT"; SIG s; FLAG_TABLE epFlags[] = { "EPFLAG_MAP_XFERS", EPFLAG_MAP_XFERS, "EPFLAG_ROOTHUB", EPFLAG_ROOTHUB, "EPFLAG_NUKED", EPFLAG_NUKED, "EPFLAG_VIRGIN", EPFLAG_VIRGIN, "EPFLAG_DEVICE_GONE", EPFLAG_DEVICE_GONE }; MP_ENDPOINT_STATUS epStatus; MP_ENDPOINT_STATE epState; ULONG f; MEMLOC l; PrintfMemLoc("*ENDPOINT ", MemLoc, "\n"); s.l = UsbReadFieldUlong(MemLoc, cs, "Sig"); Sig(s.l, ""); if (s.l != SIG_ENDPOINT) { BadSig(s.l, SIG_ENDPOINT); return; } f = UsbReadFieldUlong(MemLoc, cs, "Flags"); dprintf("Flags: %08.8x\n", f); UsbDumpFlags(f, epFlags, sizeof(epFlags)/sizeof(FLAG_TABLE)); dprintf("Busy: %d\n", UsbReadFieldUlong(MemLoc, cs, "Busy")); PrintfMemLoc("FdoDeviceObject:", UsbReadFieldPtr(MemLoc, cs, "DeviceDescriptor"), "\n"); epStatus = UsbReadFieldUlong(MemLoc, cs, "CurrentStatus"); dprintf("CurrentStatus: %08.8x\n", epStatus); EpStatus(epStatus); epState = UsbReadFieldUlong(MemLoc, cs, "CurrentState"); dprintf("CurrentState: %08.8x\n", epState); EpState(epState); epState = UsbReadFieldUlong(MemLoc, cs, "NewState"); dprintf("NewState: %08.8x\n", epState); EpState(epState); dprintf("StateChangeFrame: %08.8x\n", UsbReadFieldUlong(MemLoc, cs, "StateChangeFrame")); PrintfMemLoc("EpWorkerFunction:", UsbReadFieldPtr(MemLoc, cs, "EpWorkerFunction"), "\n"); PrintfMemLoc("CommonBuffer:", UsbReadFieldPtr(MemLoc, cs, "CommonBuffer"), "\n"); PrintfMemLoc("Usb2LibEpContext:", UsbReadFieldPtr(MemLoc, cs, "Usb2LibEpContext"), "\n"); PrintfMemLoc("MiniportContext: ", MemLoc + UsbFieldOffset(cs, "MiniportEndpointData"), "\n"); // dprintf("HubDeviceAddress: 0x%08.8x\n", endpoint.HubDeviceAddress); // dprintf("PortTTNumber: 0x%08.8x\n", endpoint.PortTTNumber); DumpEndpointParameters(MemLoc + UsbFieldOffset(cs, "Parameters")); dprintf("-lists-\n"); l = MemLoc + UsbFieldOffset(cs, "ActiveList"); PrintfMemLoc("\t(AL) ActiveList: ", l, ListEmpty(l)); l = MemLoc + UsbFieldOffset(cs, "PendingList"); PrintfMemLoc("\t(PL) PendingList: ", l, ListEmpty(l)); l = MemLoc + UsbFieldOffset(cs, "CancelList"); PrintfMemLoc("\t(CL) CancelList: ", l, ListEmpty(l)); l = MemLoc + UsbFieldOffset(cs, "AbortIrpList"); PrintfMemLoc("\t(AI) AbortIrpList: ", l, ListEmpty(l)); // LIST_ENTRY AbortIrpList; #if 0 // for linkage to global endpoint list dprintf("-linkage-\n"); dprintf("\tGlobalLink.Flink: %08.8x\n", endpoint.GlobalLink.Flink); dprintf("\tGlobalLink.Blink: %08.8x\n", endpoint.GlobalLink.Blink); dprintf("\tAttendLink.Flink: %08.8x\n", endpoint.AttendLink.Flink); dprintf("\tAttendLink.Blink: %08.8x\n", endpoint.AttendLink.Blink); dprintf("\tStateLink.Flink: %08.8x\n", endpoint.StateLink.Flink); dprintf("\tStateLink.Blink: %08.8x\n", endpoint.StateLink.Blink); dprintf("\tClosedLink.Flink: %08.8x\n", endpoint.ClosedLink.Flink); dprintf("\tClosedLink.Blink: %08.8x\n", endpoint.ClosedLink.Blink); #endif } VOID DumpCommonBuffer( ULONG MemLoc, ULONG Level ) { USBPORT_COMMON_BUFFER header; ULONG result; if (!ReadMemory (MemLoc, &header, sizeof (header), &result)) { BadMemLoc(MemLoc); return; } dprintf("*COMMON_BUFFER_HEADER %08.8x\n", MemLoc); Sig(header.Sig, ""); if (header.Sig != SIG_CMNBUF) { BadSig(header.Sig, SIG_CMNBUF); return; } dprintf("Flags: %08.8x\n", header.Flags); dprintf("TotalLength: %08.8x\n", header.TotalLength); dprintf("VirtualAddress: %08.8x\n", header.VirtualAddress); dprintf("BaseVa: %08.8x\n", header.BaseVa); dprintf("BasePhys: %08.8x\n", header.BasePhys); dprintf("MiniportLength: %08.8x\n", header.MiniportLength); dprintf("PadLength: %08.8x\n", header.PadLength); dprintf("MiniportVa: %08.8x\n", header.MiniportVa); dprintf("MiniportPhys: %08.8x\n", header.MiniportPhys); } VOID DumpMdl( ULONG MemLoc ) { PMDL mdl; MDL tmpMdl; PUCHAR buffer; ULONG result, count, i; PULONG pages; if (!ReadMemory (MemLoc, &tmpMdl, sizeof (tmpMdl), &result)) { BadMemLoc(MemLoc); return; } buffer = (PUCHAR) malloc(tmpMdl.Size); if (buffer != NULL) { if (!ReadMemory (MemLoc, buffer, tmpMdl.Size, &result)) { BadMemLoc(MemLoc); free(buffer); return; } mdl = (PMDL) buffer; pages = (PULONG) (buffer+sizeof(MDL)); dprintf("*MDL %08.8x\n", MemLoc); dprintf("Size: %d\n", mdl->Size); dprintf("Flags: %04.4x\n", mdl->MdlFlags); dprintf("MappedSystemVa: %08.8x\n", mdl->MappedSystemVa); dprintf("StartVa: %08.8x\n", mdl->StartVa); dprintf("ByteCount: %08.8x\n", mdl->ByteCount); dprintf("ByteOffset: %08.8x\n", mdl->ByteOffset); count = (mdl->Size - sizeof(MDL)) / sizeof(ULONG); dprintf(" %d\n", count); for (i = 0; i < count; i++) { dprintf("Page[%d]: %08.8x\n", i, *pages); pages++; } free(buffer); } } VOID DumpInterfaceHandle( MEMLOC MemLoc ) { UCHAR cs[] = "_USBD_INTERFACE_HANDLE_I"; ULONG f, cb; STRUC_ENTRY t[] = { "Sig", FT_SIG, "HasAlternateSettings", FT_UCHAR, }; UCHAR c, i; MEMLOC tmp; USB_INTERFACE_DESCRIPTOR id; dprintf("***\n"); PrintfMemLoc("*INTERFACE_HANDLE ", MemLoc, "\n"); UsbDumpStruc(MemLoc, cs, &t[0], sizeof(t)/sizeof(STRUC_ENTRY)); c = UsbReadFieldUchar(MemLoc, cs, "InterfaceDescriptor.bNumEndpoints"); tmp = MemLoc + UsbFieldOffset(cs, "InterfaceDescriptor"); PrintfMemLoc("InterfaceDescriptor ", tmp, "\n"); ReadMemory(tmp, &id, sizeof(id), &cb); DumpUSBDescriptor(&id); for (i=0; i%08.8x\n", MemLoc, cd.bLength, cd.bDescriptorType, MemLoc+cd.bLength); tmp = malloc(cd.bLength); if (tmp) { if (!ReadMemory (MemLoc, tmp, cd.bLength, &result)) { BadMemLoc(MemLoc); return; } DumpUSBDescriptor(tmp); free (tmp); } #endif } VOID DumpCfgDescriptorMemLoc( ULONG MemLoc ) { #if 0 USB_CONFIGURATION_DESCRIPTOR cf; PUSB_COMMON_DESCRIPTOR cd; ULONG result; PUCHAR tmp, tmp2; if (!ReadMemory (MemLoc, &cf, sizeof(cf), &result)) { BadMemLoc(MemLoc); return; } dprintf("*USB CONFIG DESCRIPTOR %08.8x\n", MemLoc); tmp = malloc(cf.wTotalLength); if (tmp) { if (!ReadMemory (MemLoc, tmp, cf.wTotalLength, &result)) { BadMemLoc(MemLoc); return; } tmp2 = tmp; while (tmp2-tmp < cf.wTotalLength) { cd = (PUSB_COMMON_DESCRIPTOR) tmp2; DumpUSBDescriptor(tmp2); tmp2+=cd->bLength; } free (tmp); } #endif } VOID DumpConfigHandle( MEMLOC MemLoc ) { UCHAR cs[] = "_USBD_CONFIG_HANDLE"; SIG s; MEMLOC cf, list; PrintfMemLoc("*USBD_CONFIG_HANDLE ", MemLoc, "\n"); s.l = UsbReadFieldUlong(MemLoc, cs, "Sig"); Sig(s.l, ""); if (s.l != SIG_CONFIG_HANDLE) { BadSig(s.l, SIG_ENDPOINT); return; } cf = UsbReadFieldPtr(MemLoc, cs, "ConfigurationDescriptor"); PrintfMemLoc("ConfigurationDescriptor ", cf, "\n"); list = MemLoc + UsbFieldOffset(cs, "InterfaceHandleList"); DumpInterfaceHandleList(list); } DECLARE_API( _iso ) /*++ Routine Description: dumps the extension Arguments: args - Address flags Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpIsoTransferContext (addr); return S_OK; } DECLARE_API( _tt ) /*++ Routine Description: dumps the extension Arguments: args - Address flags Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpTt (addr); return S_OK; } DECLARE_API( _devh ) /*++ Routine Description: dumps the extension Arguments: args - Address flags Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpDeviceHandle (addr); return S_OK; } DECLARE_API( _piph ) /*++ Routine Description: dumps the extension Arguments: args - Address flags Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpIPipe(addr); return S_OK; } DECLARE_API( _endp ) /*++ Routine Description: dumps the extension Arguments: args - Address flags Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpEndpoint(addr); return S_OK; } DECLARE_API( _cmbf ) /*++ Routine Description: dumps the extension Arguments: args - Address flags Return Value: None --*/ { ULONG memLoc; UCHAR buffer[256]; ULONG level = 1; //UNREFERENCED_PARAMETER (dwProcessor); //UNREFERENCED_PARAMETER (dwCurrentPc); //UNREFERENCED_PARAMETER (hCurrentThread); //UNREFERENCED_PARAMETER (hCurrentProcess); buffer[0] = '\0'; sscanf(args, "%lx, %s", &memLoc, buffer); if ('\0' != buffer[0]) { sscanf(buffer, "%lx", &level); } DumpCommonBuffer (memLoc, level); return S_OK; } DECLARE_API( _tfer ) /*++ Routine Description: dumps transfer Context for usbport Arguments: args - Address flags Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpTransferContext(addr); return S_OK; } DECLARE_API( _mdl ) /*++ Routine Description: dumps an MDL Arguments: Return Value: None --*/ { ULONG memLoc; UCHAR buffer[256]; ULONG level = 1; //UNREFERENCED_PARAMETER (dwProcessor); //UNREFERENCED_PARAMETER (dwCurrentPc); //UNREFERENCED_PARAMETER (hCurrentThread); //UNREFERENCED_PARAMETER (hCurrentProcess); buffer[0] = '\0'; sscanf(args, "%lx, %s", &memLoc, buffer); if ('\0' != buffer[0]) { sscanf(buffer, "%lx", &level); } DumpMdl (memLoc); return S_OK; } DECLARE_API( _cfgh ) /*++ Routine Description: dumps an MDL Arguments: Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpConfigHandle(addr); return S_OK; } DECLARE_API( _ifh ) /*++ Routine Description: dumps an MDL Arguments: Return Value: None --*/ { MEMLOC addr; // fetch the list head addr = GetExpression(args); DumpInterfaceHandle(addr); return S_OK; } DECLARE_API( _descusb ) /*++ Routine Description: dumps an MDL Arguments: Return Value: None --*/ { ULONG memLoc; UCHAR buffer[256]; ULONG level = 1; //UNREFERENCED_PARAMETER (dwProcessor); //UNREFERENCED_PARAMETER (dwCurrentPc); //UNREFERENCED_PARAMETER (hCurrentThread); //UNREFERENCED_PARAMETER (hCurrentProcess); buffer[0] = '\0'; sscanf(args, "%lx, %s", &memLoc, buffer); if ('\0' != buffer[0]) { sscanf(buffer, "%lx", &level); } DumpUsbDescriptorMemLoc(memLoc); return S_OK; } DECLARE_API( _desccfg ) /*++ Routine Description: dumps an MDL Arguments: Return Value: None --*/ { ULONG memLoc; UCHAR buffer[256]; ULONG level = 1; //UNREFERENCED_PARAMETER (dwProcessor); //UNREFERENCED_PARAMETER (dwCurrentPc); //UNREFERENCED_PARAMETER (hCurrentThread); //UNREFERENCED_PARAMETER (hCurrentProcess); buffer[0] = '\0'; sscanf(args, "%lx, %s", &memLoc, buffer); if ('\0' != buffer[0]) { sscanf(buffer, "%lx", &level); } DumpCfgDescriptorMemLoc(memLoc); return S_OK; }