summaryrefslogtreecommitdiff
path: root/serial/serenum/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'serial/serenum/string.c')
-rw-r--r--serial/serenum/string.c1029
1 files changed, 1029 insertions, 0 deletions
diff --git a/serial/serenum/string.c b/serial/serenum/string.c
new file mode 100644
index 00000000..bf54ca8e
--- /dev/null
+++ b/serial/serenum/string.c
@@ -0,0 +1,1029 @@
+/*++
+Copyright (c) 1998 Microsoft Corporation
+
+Module Name:
+
+ STRING.C
+
+Abstract:
+
+ This module contains the functions used to parse the PNP COM ID
+ and save it in the appropriate UNICODE STRINGS. The main function
+ that is called is Serenum_ParseData. All other functions are called
+ by this main function.
+
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+
+
+--*/
+
+#include "pch.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, Serenum_ParseData)
+
+// Called by ParseData:
+#pragma alloc_text (PAGE, Serenum_GetDevDesc)
+#pragma alloc_text (PAGE, Serenum_GetDevCompId)
+#pragma alloc_text (PAGE, Serenum_GetDevClass)
+#pragma alloc_text (PAGE, Serenum_GetDevSerialNo)
+#pragma alloc_text (PAGE, Serenum_GetDevName)
+#pragma alloc_text (PAGE, Serenum_GetDevPnPRev)
+#pragma alloc_text (PAGE, Serenum_GetDevOtherID)
+
+#pragma alloc_text (PAGE, Serenum_InitMultiString)
+#pragma alloc_text (PAGE, Serenum_SzCopy)
+#pragma alloc_text (PAGE, Serenum_StrLen)
+
+// Called by the above functions:
+#pragma alloc_text (PAGE, Serenum_FixptToAscii)
+#pragma alloc_text (PAGE, Serenum_HToI)
+
+#endif
+
+NTSTATUS
+Serenum_ParseData( PFDO_DEVICE_DATA FdoData,
+ _In_reads_(BufferLen) PCHAR ReadBuffer, ULONG BufferLen,
+ PUNICODE_STRING hardwareIDs, PUNICODE_STRING compIDs,
+ PUNICODE_STRING deviceIDs, PUNICODE_STRING PDeviceDesc,
+ PUNICODE_STRING serialNo, PUNICODE_STRING pnpRev
+ )
+/*++
+
+Routine Description:
+ Parses the PNP COM ID out of the buffer which is passed as the
+ first parameter and then saves the appropriate IDs as
+ UNICODE_STRINGS in the other passed parameters.
+
+Return value:
+ NTSTATUS
+
+--*/
+
+{
+ LPSTR pOtherId = NULL;
+ LPSTR pPnpRev = NULL;
+ LPSTR pDevNodeName = NULL;
+ LPSTR pSerNo = NULL;
+ LPSTR pClass = NULL;
+ LPSTR pCompIdStar = NULL;
+ LPSTR pDesc = NULL;
+ PCHAR pStrBuffer = NULL;
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ LPSTR pDevName = NULL;
+ LPSTR pCompId = NULL;
+
+ int start;
+
+ BOOLEAN isMouse = FALSE;
+ PCHAR pMouseID = NULL;
+ ULONG mouseIDLen;
+
+ UNREFERENCED_PARAMETER(BufferLen);
+ PAGED_CODE();
+
+ //
+ // Allocate the string buffers
+ //
+
+ pStrBuffer = ExAllocatePoolWithTag(PagedPool, MAX_DEVNODE_NAME * 7 + 1,SERENUM_POOL_TAG);
+
+ if (pStrBuffer == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto DoneParsingErr;
+ } else {
+ PCHAR pCurBuffer = pStrBuffer;
+
+ pOtherId = pCurBuffer;
+ *pOtherId = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME;
+
+ pPnpRev = pCurBuffer;
+ *pPnpRev = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME;
+
+ pDevNodeName = pCurBuffer;
+ *pDevNodeName = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME;
+
+ pSerNo = pCurBuffer;
+ *pSerNo = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME;
+
+ pClass = pCurBuffer;
+ *pClass = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME;
+
+ pCompIdStar = pCurBuffer;
+ pCompId = pCompIdStar + 1;
+ *pCompIdStar = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME + 1;
+
+ pDesc = pCurBuffer;
+ *pDesc = '\0';
+ pCurBuffer += MAX_DEVNODE_NAME;
+ }
+
+ start = Serenum_SzCopy ( NAME_SERENUM, pDevNodeName, MAX_DEVNODE_NAME);
+ pDevName = pDevNodeName + start;
+
+ start = 0;
+
+ RtlInitUnicodeString(hardwareIDs, NULL);
+ RtlInitUnicodeString(compIDs, NULL);
+ RtlInitUnicodeString(deviceIDs, NULL);
+ RtlInitUnicodeString(pnpRev, NULL);
+ RtlInitUnicodeString(serialNo, NULL);
+
+
+ //
+ // OtherID
+ //
+
+ if(ReadBuffer!=NULL&&BufferLen>=MAX_DEVNODE_NAME){
+ start = Serenum_GetDevOtherID(ReadBuffer, BufferLen, pOtherId);
+ }
+
+ if (start > 16||start==0) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("Other ID string too long\n"));
+ status = STATUS_UNSUCCESSFUL;
+ goto DoneParsingErr;
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Other ID: %s\n", pOtherId));
+
+ //
+ // See if this is a mouse
+ //
+
+ SerenumScanOtherIdForMouse(ReadBuffer, BufferLen, &pMouseID, &mouseIDLen );
+
+ if (pMouseID != NULL && (*pMouseID == 'M' || *pMouseID == 'B')) {
+ isMouse = TRUE;
+ }
+
+ //
+ // PNP revision number
+ //
+
+ status = Serenum_GetDevPnPRev(FdoData, ReadBuffer, BufferLen, pPnpRev, &start);
+
+ if (!NT_SUCCESS(status)) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR, ("PNP ID string bad\n"));
+ goto DoneParsingErr;
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("PNP Revision: %s\n", pPnpRev));
+
+ //
+ // PNP device node name
+ // EISA ID followed by Product ID
+ //
+
+ Serenum_GetDevName(ReadBuffer, BufferLen, pDevName, &start);
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Device Node name: %s\n",
+ pDevNodeName));
+
+ //
+ // Device serial number
+ //
+ if(ReadBuffer!=NULL){
+ Serenum_GetDevSerialNo(ReadBuffer, BufferLen, pSerNo, &start);
+ }
+
+ if (Serenum_StrLen(pSerNo)) {
+ //
+ // This field exists - Make sure it is correct length.
+ //
+
+ if (Serenum_StrLen(pSerNo) != 8) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR, ("Serial number wrong"
+ " length\n"));
+ *pSerNo = '\0';
+ status = STATUS_UNSUCCESSFUL;
+ goto DoneParsingErr;
+ }
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Serial Number: %s\n", pSerNo));
+
+ //
+ // PNP class identifier
+ //
+ if(ReadBuffer!=NULL){
+ Serenum_GetDevClass(ReadBuffer, BufferLen, pClass, &start);
+ }
+
+ if (Serenum_StrLen(pClass) > 32) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR, ("Class ID string too long\n"
+ ));
+ status = STATUS_UNSUCCESSFUL;
+ goto DoneParsingErr;
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Class: %s\n", pClass));
+
+ if (_stricmp(pClass, "MOUSE") == 0) {
+ RtlStringCchCopyA(pClass, MAX_DEVNODE_NAME, "SERIAL_MOUSE");
+ }
+
+ //
+ // Compatible device ID
+ //
+ *pCompIdStar = '*';
+ if(ReadBuffer!=NULL&&pCompId!=NULL){
+ Serenum_GetDevCompId(ReadBuffer, BufferLen, pCompId, &start);
+ }
+
+ if (Serenum_StrLen(pCompId) > 40) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR, ("Compatible driver ID"
+ " string too long\n"));
+ status = STATUS_UNSUCCESSFUL;
+ goto DoneParsingErr;
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Compatible driver ID: %s\n",
+ pCompId));
+
+ //
+ // End-user legible Product Description
+ //
+ if(ReadBuffer!=NULL){
+ Serenum_GetDevDesc (ReadBuffer, BufferLen, pDesc, &start);
+ }
+
+ if (Serenum_StrLen(pDesc) > 40) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR, ("Device Description too"
+ " long\n"));
+ status = STATUS_UNSUCCESSFUL;
+ goto DoneParsingErr;
+ }
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Device Description: %s\n",
+ pDesc));
+
+ DoneParsingErr:
+ if (pStrBuffer != NULL) {
+ //
+ // send back the good bits so that routine knows what driver to load
+ //
+
+ Serenum_InitMultiString (FdoData, hardwareIDs, pDevNodeName, pDevName,
+ NULL);
+
+ if (Serenum_StrLen(pCompId) > 0) {
+ if (!isMouse) {
+ Serenum_InitMultiString(FdoData, compIDs, pCompIdStar, pClass,
+ NULL);
+ } else {
+ Serenum_InitMultiString(FdoData, compIDs, pCompIdStar, pClass,
+ "SERIAL_MOUSE", NULL);
+ }
+ } else {
+ if (isMouse) {
+ Serenum_InitMultiString(FdoData, compIDs, "SERIAL_MOUSE", NULL);
+ }
+ }
+
+ Serenum_InitMultiString(FdoData, deviceIDs, pDevNodeName, NULL);
+
+ Serenum_InitMultiString(FdoData, PDeviceDesc, pDesc, NULL);
+
+ if (Serenum_StrLen(pSerNo)) {
+ Serenum_InitMultiString(FdoData, serialNo, pSerNo, NULL);
+ }
+ if (Serenum_StrLen(pPnpRev)) {
+ Serenum_InitMultiString(FdoData, pnpRev, pPnpRev, NULL);
+ }
+
+ ExFreePoolWithTag(pStrBuffer,SERENUM_POOL_TAG);
+ }
+
+ return status;
+}
+
+NTSTATUS
+Serenum_InitMultiString(PFDO_DEVICE_DATA FdoData, PUNICODE_STRING MultiString,
+ ...)
+/*++
+
+ This routine will take a null terminated list of ascii strings and combine
+ them together to generate a unicode multi-string block
+
+Arguments:
+
+ MultiString - a unicode structure in which a multi-string will be built
+ ... - a null terminated list of narrow strings which will be
+ combined together. This list must contain at least a
+ trailing NULL
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ ANSI_STRING ansiString;
+ NTSTATUS status;
+ PCSTR rawString;
+ ULONG multiLength = 0;
+ UNICODE_STRING unicodeString;
+ va_list ap;
+ ULONG i;
+
+ PAGED_CODE();
+
+#if !DBG
+ UNREFERENCED_PARAMETER(FdoData);
+#endif
+
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("Entering Serenum_InitMultiString\n"));
+
+ va_start(ap,MultiString);
+
+ //
+ // Make sure that we won't leak memory
+ //
+
+ ASSERT(MultiString->Buffer == NULL);
+
+ rawString = va_arg(ap, PCSTR);
+
+ while (rawString != NULL) {
+ RtlInitAnsiString(&ansiString, rawString);
+ multiLength += RtlAnsiStringToUnicodeSize(&(ansiString));
+ rawString = va_arg(ap, PCSTR);
+ }
+
+ va_end( ap );
+
+ if (multiLength == 0) {
+ //
+ // Done
+ //
+ RtlInitUnicodeString(MultiString, NULL);
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("Leaving Serenum_InitMultiString (1)\n"));
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // We need an extra null
+ //
+ multiLength += sizeof(WCHAR);
+
+ MultiString->MaximumLength = (USHORT)multiLength;
+ MultiString->Buffer = ExAllocatePoolWithTag(PagedPool, multiLength,SERENUM_POOL_TAG);
+ MultiString->Length = 0;
+
+ if (MultiString->Buffer == NULL) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("Leaving Serenum_InitMultiString (2)\n"));
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("Allocated %lu bytes for buffer\n", multiLength));
+
+#if DBG
+ RtlFillMemory(MultiString->Buffer, multiLength, 0xff);
+#endif
+
+ unicodeString.Buffer = MultiString->Buffer;
+ unicodeString.MaximumLength = (USHORT) multiLength;
+ unicodeString.Length = 0;
+
+ va_start(ap, MultiString);
+ rawString = va_arg(ap, PCSTR);
+
+ while (rawString != NULL) {
+
+ RtlInitAnsiString(&ansiString,rawString);
+ status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
+ if (!NT_SUCCESS(status)) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR, ("Serenum_InitMultiString: Call to RtlAnsiStringToUnicodeString Failed.\n"));
+ return status;
+ }
+
+ //
+ // We don't allocate memory, so if something goes wrong here,
+ // its the function that's at fault
+ //
+ ASSERT(NT_SUCCESS(status));
+
+ //
+ // Check for any commas and replace them with NULLs
+ //
+
+ ASSERT(unicodeString.Length % sizeof(WCHAR) == 0);
+
+ for (i = 0; i < (unicodeString.Length / sizeof(WCHAR)); i++) {
+ if (unicodeString.Buffer[i] == L'\x2C' ||
+ unicodeString.Buffer[i] == L'\x0C' ) {
+ unicodeString.Buffer[i] = L'\0';
+ }
+ }
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("unicode buffer: %ws\n",
+ unicodeString.Buffer));
+
+ //
+ // Move the buffers along
+ //
+ unicodeString.Buffer += ((unicodeString.Length / sizeof(WCHAR)) + 1);
+ unicodeString.MaximumLength -= (unicodeString.Length + sizeof(WCHAR));
+ unicodeString.Length = 0;
+
+ //
+ // Next
+ //
+
+ rawString = va_arg(ap, PCSTR);
+ } // while
+
+ va_end(ap);
+
+ ASSERT(unicodeString.MaximumLength == sizeof(WCHAR));
+
+ //
+ // Stick the final null there
+ //
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("unicode buffer last addr: "
+ "%p\n", unicodeString.Buffer));
+
+ unicodeString.Buffer[0] = L'\0';
+
+ //
+ // Include the nulls in the length of the string
+ //
+
+ MultiString->Length = (USHORT)multiLength;
+ MultiString->MaximumLength = MultiString->Length;
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("Leaving Serenum_InitMultiString (3)\n"));
+
+ return STATUS_SUCCESS;
+}
+
+int
+Serenum_StrLen (
+ _In_ LPSTR string)
+// Measures the length of a string
+{
+ int i;
+ PAGED_CODE();
+
+ if (string == NULL) {
+ return 0;
+ }
+ for (i=0; string[i] != '\0'; i++) {
+ }
+ return i;
+}
+
+int
+Serenum_SzCopy (
+ _In_ LPSTR source,
+ _Out_writes_(len) PCHAR dest,
+ int len
+ )
+// Copies a string
+// Assumes the buffer is already allocated to be copied into
+{
+ int i;
+
+ PAGED_CODE();
+
+ ASSERT (source);
+ ASSERT (dest);
+
+ for (i=0; source[i] != '\0' && i < len; i++) {
+ *dest++ = source[i];
+ }
+ return i;
+}
+
+//
+// String extraction functions:
+//
+int
+Serenum_GetDevOtherID(
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNODE_NAME)LPSTR output
+ )
+{
+ int tail;
+ CHAR c;
+
+ PAGED_CODE();
+
+ tail = 0;
+ c = input[tail++];
+ while((tail < 17 ) && (c != '(') && (c != '(' - 0x20) && tail < len ) {
+ *output++ = c;
+#pragma warning(suppress: 6385)
+ c = input[tail++];
+ }
+ *output = '\0';
+ return(tail-1);
+}
+
+
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+int
+Serenum_HToI(char c)
+{
+ PAGED_CODE();
+
+ if('0' <= c && c <= '9')
+ return(c - '0');
+
+ if('A' <= c && c <= 'F')
+ return(c - 'A' + 10);
+
+ if('a' <= c && c <= 'f')
+ return(c - 'a' + 10);
+
+ return(-1);
+}
+
+void
+Serenum_FixptToAscii(
+ int n,
+ _Out_writes_(MAX_DEVNODE_NAME) LPSTR output)
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+{
+ int tmp;
+
+ PAGED_CODE();
+
+ tmp = n / 100;
+
+ if(tmp >= 10)
+ *output++ = (CHAR)('0' + (tmp / 10));
+
+ *output++ = (CHAR)('0' + (tmp % 10));
+ *output++ = '.';
+
+ tmp = n % 100;
+
+ *output++ = (CHAR)('0' + (tmp / 10));
+ *output++ = (CHAR)('0' + (tmp % 10));
+
+ *output = '\0';
+}
+
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+NTSTATUS
+Serenum_GetDevPnPRev(
+ PFDO_DEVICE_DATA FdoData,
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNODE_NAME) LPSTR output,
+ _Inout_ int *start
+ )
+{
+ int tail;
+ int i;
+ char delta;
+ char c, begin_PnP, end_PnP_pos;
+ int sum, chk_sum, msd, lsd;
+
+ UNREFERENCED_PARAMETER(FdoData);
+ PAGED_CODE();
+
+ if (output == NULL || input == NULL) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, NULL pointer!\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+ __analysis_assume(len>=MAX_DEVNODE_NAME);
+ *output = '\0';
+
+ tail = *start;
+
+ if ( tail >= len ) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, insufficient input buffer\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (input[tail] == 0) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, input buffer empty!\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ c = input[tail++];
+
+ while ((tail < 256) && (c != '(') && (c != '(' - 0x20) && tail < len) {
+ c = input[tail++];
+ }
+
+ if (c != '(' && c != '(' - 0x20) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, no Begin PnP char!\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ begin_PnP = c;
+ delta = '(' - begin_PnP;
+
+ if ( tail+9 >= len ) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, insufficient input buffer\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#pragma warning(suppress: 6385)
+ if ( input[tail + 9] != ')' - delta) {
+
+ //
+ // compute checksum
+ //
+
+ sum = c;
+ i = tail;
+ while ( (i < 256) && (c != ( ')' - delta)) && i < len ) {
+ c = input[i++];
+ sum += c;
+ }
+
+ if ( i < 3 || i-2 >= len) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, insufficient input buffer\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ msd = input[i-3];
+ lsd = input[i-2];
+
+ sum -= msd;
+ sum -= lsd;
+
+ msd += delta;
+ lsd += delta;
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("checksum from device (chars) = %c%c\n", (char)msd,
+ (char)lsd));
+
+ msd = Serenum_HToI((char)msd);
+ if (msd < 0) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("Bad msd checksum digit\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ lsd = Serenum_HToI((char)lsd);
+ if (lsd < 0) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("Bad lsd checksum digit\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ chk_sum = (msd << 4) + lsd;
+
+ sum &= 0xff;
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("checksum read from device = %0x\n", chk_sum));
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
+ ("Computed checksum = %0x\n", sum));
+
+ end_PnP_pos = (char)i;
+
+ if ( c - begin_PnP != ')' - '(' ) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed,BeginPnP didn't match "
+ "EndPnP\n"));
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("begin_PnP = %02x end_PnP = %02x\n", begin_PnP, c));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // check the checksum
+ //
+
+ if (chk_sum != sum) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("checksum Failed! Continuing...\n"));
+ // return STATUS_UNSUCCESSFUL; // Commented out in Memphis
+ }
+
+ i = end_PnP_pos;
+
+ if ( i < 3 || i-2 >= len) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, insufficient input buffer\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+ input[i-3] = ')' - delta; // trash the checksum
+ input[i-2] = '\0'; // since we are done with it
+ }
+
+ if ( tail+1 >= len ) {
+ Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
+ ("GetDevPnPRev Failed, insufficient input buffer\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (input[tail] > 0x3f ||
+ input[tail+1] > 0x3f) {
+
+ Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Bad PnP Rev digits\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ i = (input[tail++] & 0x3f) << 6;
+ i |= (input[tail++]) & 0x3f;
+
+ Serenum_FixptToAscii(i, output);
+
+ i = tail;
+
+ //
+ // get ride of Mouse'output 0x20 bias in the string
+ //
+ while ( (i < 256) && delta && i < len ) {
+ input[i] += delta;
+ c = input[i++];
+ if ( c == ')' ) {
+ delta = 0; // indicate we are done
+ }
+ }
+
+ *start = tail;
+
+ return STATUS_SUCCESS;
+}
+
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+void Serenum_GetDevName(
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNAME) PCHAR output,
+ _Inout_ int *start
+ )
+{
+
+ int tail;
+ char c;
+
+ PAGED_CODE();
+
+ if(output == NULL || input == NULL)
+ return;
+
+ tail = *start;
+
+ // EISA ID
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ *output++ = input[tail++];
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ *output++ = input[tail++];
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ *output++ = input[tail++];
+
+ // Product ID
+
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ c = input[tail++];
+ if(Serenum_HToI(c) >= 0)
+ *output++ = c;
+
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ c = input[tail++];
+ if(Serenum_HToI(c) >= 0)
+ *output++ = c;
+
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ c = input[tail++];
+ if(Serenum_HToI(c) >= 0)
+ *output++ = c;
+
+ if ( tail >= len ) { *start = tail; goto Exit; }
+ c = input[tail++];
+ if(Serenum_HToI(c) >= 0)
+ *output++ = c;
+
+ Exit:
+ *output = '\0';
+
+ *start = tail;
+
+ return;
+}
+
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+void Serenum_GetDevSerialNo(
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNODE_NAME) LPSTR output,
+ _Inout_ int *start
+ )
+{
+
+ int tail, cnt;
+ char c;
+
+ PAGED_CODE();
+
+ *output = '\0';
+
+ tail = *start;
+
+ if ( tail >= len ) { return; }
+
+ if( input[tail++] != '\\')
+ return;
+
+ if ( tail >= len ) { *start = tail-1; return; }
+ c = input[tail++];
+
+ cnt = 0;
+
+ while(cnt < 8 && tail < 256 && ( c != '\\') && ( c != ')') && tail < len ) {
+ cnt++;
+ if(Serenum_HToI(c) < 0)
+ break;
+
+ *output++ = c;
+ c = input[tail++];
+ }
+
+ *output = '\0';
+
+ *start = tail - 1;
+
+ return;
+}
+
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+void Serenum_GetDevClass(
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNODE_NAME) LPSTR output,
+ _Inout_ int *start
+ )
+{
+
+ int tail, cnt;
+ char c;
+
+ PAGED_CODE();
+
+ *output = '\0';
+
+ tail = *start;
+
+ if ( tail >= len ) { return; }
+
+ if( input[tail++] != '\\')
+ return;
+
+ if ( tail >= len ) { *start = tail-1; return; }
+ c = input[tail++];
+
+ cnt = 0;
+
+ while(tail < 256 && ( c != '\\') && ( c != ')') && tail < len && cnt < MAX_DEVNODE_NAME - 1) {
+ cnt++;
+ *output++ = c;
+ c = input[tail++];
+ }
+ *output = '\0';
+
+ *start = tail - 1;
+
+ return;
+}
+
+
+void Serenum_GetDevCompId(
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNODE_NAME) LPSTR output,
+ _Inout_ int *start
+ )
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+{
+
+ int tail, cnt;
+ char c;
+
+ PAGED_CODE();
+
+ *output = '\0';
+
+ tail = *start;
+
+ if ( tail >= len ) { return; }
+
+ if( input[tail++] != '\\')
+ return;
+
+ if ( tail >= len ) { *start = tail-1; return; }
+ c = input[tail++];
+
+ cnt = 0;
+
+ while(tail < 256 && ( c != '\\') && ( c != ')') && tail < len && cnt < MAX_DEVNODE_NAME - 2 ) {
+ cnt++;
+ *output++ = c;
+ //
+ // Put a * after every comma
+ //
+ if ('\x0C' == c || '\x2C' == c) {
+ cnt++;
+ *output++ = '*';
+ }
+ c = input[tail++];
+ }
+
+ *output = '\0';
+
+ *start = tail - 1;
+}
+
+void
+Serenum_GetDevDesc(
+ _In_reads_(len) PCHAR input,
+ int len,
+ _Out_writes_(MAX_DEVNODE_NAME) LPSTR output,
+ _Inout_ int *start
+ )
+/****************************************************************************
+ *
+ *
+ ***************************************************************************/
+{
+
+ int tail, cnt;
+ char c;
+
+ PAGED_CODE();
+
+ *output = '\0';
+
+ tail = *start;
+
+ if ( tail >= len ) { return; }
+
+ if( input[tail++] != '\\')
+ return;
+
+ if ( tail >= len ) { *start = tail-1; return; }
+ c = input[tail++];
+
+ cnt = 0;
+
+ while(tail < 256 && ( c != '\\') && ( c != ')') && tail < len && cnt < MAX_DEVNODE_NAME - 1) {
+ cnt++;
+ *output++ = c;
+ c = input[tail++];
+ }
+
+ *output = '\0';
+
+ *start = tail - 1;
+}
+
+