423 lines
11 KiB
C
423 lines
11 KiB
C
#define DRIVER
|
|
|
|
#include "wdm.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "deviceid.h"
|
|
#include <usb.h>
|
|
#include <usbdrivr.h>
|
|
#include "usbdlib.h"
|
|
|
|
|
|
|
|
#include "usbprint.h"
|
|
|
|
|
|
VOID StringSubst
|
|
(
|
|
PUCHAR lpS,
|
|
UCHAR chTargetChar,
|
|
UCHAR chReplacementChar,
|
|
USHORT cbS
|
|
)
|
|
{
|
|
USHORT iCnt = 0;
|
|
|
|
while ((lpS != '\0') && (iCnt++ < cbS))
|
|
if (*lpS == chTargetChar)
|
|
*lpS++ = chReplacementChar;
|
|
else
|
|
++lpS;
|
|
}
|
|
|
|
VOID
|
|
FixupDeviceId(
|
|
IN OUT PUCHAR DeviceId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses the NULL terminated string and replaces any invalid
|
|
characters with an underscore character.
|
|
|
|
Invalid characters are:
|
|
c <= 0x20 (' ')
|
|
c > 0x7F
|
|
c == 0x2C (',')
|
|
|
|
Arguments:
|
|
|
|
DeviceId - specifies a device id string (or part of one), must be
|
|
null-terminated.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR p;
|
|
for( p = DeviceId; *p; ++p ) {
|
|
if( (*p <= ' ') || (*p > (UCHAR)0x7F) || (*p == ',') ) {
|
|
*p = '_';
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ParPnpGetId
|
|
(
|
|
IN PUCHAR DeviceIdString,
|
|
IN ULONG Type,
|
|
OUT PUCHAR resultString
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
Creates Id's from the device id retrieved from the printer
|
|
|
|
Parameters:
|
|
|
|
DeviceId - String with raw device id
|
|
Type - What of id we want as a result
|
|
Id - requested id
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
*/
|
|
{
|
|
NTSTATUS status;
|
|
USHORT checkSum=0; // A 16 bit check sum
|
|
// The following are used to generate sub-strings from the Device ID string
|
|
// to get the DevNode name, and to update the registry
|
|
PUCHAR MFG = NULL; // Manufature name
|
|
PUCHAR MDL = NULL; // Model name
|
|
PUCHAR CLS = NULL; // Class name
|
|
PUCHAR AID = NULL; // Hardare ID
|
|
PUCHAR CID = NULL; // Compatible IDs
|
|
PUCHAR DES = NULL; // Device Description
|
|
|
|
USBPRINT_KdPrint2 (("'USBPRINT.SYS: Enter ParPnpGetId\n"));
|
|
status = STATUS_SUCCESS;
|
|
|
|
switch(Type) {
|
|
|
|
case BusQueryDeviceID:
|
|
USBPRINT_KdPrint3 (("'USBPRINT.SYS: Inside case BusQueryID, DeviceIdString==%s\n",DeviceIdString));
|
|
// Extract the usefull fields from the DeviceID string. We want
|
|
// MANUFACTURE (MFG):
|
|
// MODEL (MDL):
|
|
// AUTOMATIC ID (AID):
|
|
// COMPATIBLE ID (CID):
|
|
// DESCRIPTION (DES):
|
|
// CLASS (CLS):
|
|
|
|
ParPnpFindDeviceIdKeys(&MFG, &MDL, &CLS, &DES, &AID, &CID, DeviceIdString);
|
|
USBPRINT_KdPrint3 (("'USBPRINT.SYS: After FindDeviceIdKeys\n"));
|
|
|
|
// Check to make sure we got MFG and MDL as absolute minimum fields. If not
|
|
// we cannot continue.
|
|
if (!MFG || !MDL)
|
|
{
|
|
status = STATUS_NOT_FOUND;
|
|
USBPRINT_KdPrint2 (("'USBPRINT.SYS: STATUS_NOT_FOUND\n"));
|
|
goto ParPnpGetId_Cleanup;
|
|
}
|
|
//
|
|
// Concatenate the provided MFG and MDL P1284 fields
|
|
// Checksum the entire MFG+MDL string
|
|
//
|
|
sprintf(resultString, "%s%s\0",MFG,MDL);
|
|
break;
|
|
|
|
case BusQueryHardwareIDs:
|
|
|
|
GetCheckSum(DeviceIdString, (USHORT)strlen(DeviceIdString), &checkSum);
|
|
sprintf(resultString,"%.20s%04X",DeviceIdString,checkSum);
|
|
break;
|
|
|
|
case BusQueryCompatibleIDs:
|
|
|
|
//
|
|
// return only 1 id
|
|
//
|
|
GetCheckSum(DeviceIdString, (USHORT)strlen(DeviceIdString), &checkSum);
|
|
sprintf(resultString,"%.20s%04X",DeviceIdString,checkSum);
|
|
|
|
break;
|
|
}
|
|
|
|
if (Type!=BusQueryDeviceID) {
|
|
//
|
|
// Convert and spaces in the Hardware ID to underscores
|
|
//
|
|
StringSubst ((PUCHAR) resultString, ' ', '_', (USHORT)strlen(resultString));
|
|
}
|
|
|
|
ParPnpGetId_Cleanup:
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
VOID
|
|
ParPnpFindDeviceIdKeys
|
|
(
|
|
PUCHAR *lppMFG,
|
|
PUCHAR *lppMDL,
|
|
PUCHAR *lppCLS,
|
|
PUCHAR *lppDES,
|
|
PUCHAR *lppAID,
|
|
PUCHAR *lppCID,
|
|
PUCHAR lpDeviceID
|
|
)
|
|
/*
|
|
|
|
Description:
|
|
This function will parse a P1284 Device ID string looking for keys
|
|
of interest to the LPT enumerator. Got it from win95 lptenum
|
|
|
|
Parameters:
|
|
lppMFG Pointer to MFG string pointer
|
|
lppMDL Pointer to MDL string pointer
|
|
lppMDL Pointer to CLS string pointer
|
|
lppDES Pointer to DES string pointer
|
|
lppCIC Pointer to CID string pointer
|
|
lppAID Pointer to AID string pointer
|
|
lpDeviceID Pointer to the Device ID string
|
|
|
|
Return Value:
|
|
no return VALUE.
|
|
If found the lpp parameters are set to the approprate portions
|
|
of the DeviceID string, and they are NULL terminated.
|
|
The actual DeviceID string is used, and the lpp Parameters just
|
|
reference sections, with appropriate null thrown in.
|
|
|
|
*/
|
|
|
|
{
|
|
PUCHAR lpKey = lpDeviceID; // Pointer to the Key to look at
|
|
PUCHAR lpValue; // Pointer to the Key's value
|
|
USHORT wKeyLength; // Length for the Key (for stringcmps)
|
|
|
|
// While there are still keys to look at.
|
|
|
|
while (lpKey!=NULL)
|
|
{
|
|
while (*lpKey == ' ')
|
|
++lpKey;
|
|
|
|
// Is there a terminating COLON character for the current key?
|
|
|
|
if (!(lpValue = StringChr(lpKey, ':')) )
|
|
{
|
|
// N: OOPS, somthing wrong with the Device ID
|
|
return;
|
|
}
|
|
|
|
// The actual start of the Key value is one past the COLON
|
|
|
|
++lpValue;
|
|
|
|
//
|
|
// Compute the Key length for Comparison, including the COLON
|
|
// which will serve as a terminator
|
|
//
|
|
|
|
wKeyLength = (USHORT)(lpValue - lpKey);
|
|
|
|
//
|
|
// Compare the Key to the Know quantities. To speed up the comparison
|
|
// a Check is made on the first character first, to reduce the number
|
|
// of strings to compare against.
|
|
// If a match is found, the appropriate lpp parameter is set to the
|
|
// key's value, and the terminating SEMICOLON is converted to a NULL
|
|
// In all cases lpKey is advanced to the next key if there is one.
|
|
//
|
|
|
|
switch (*lpKey)
|
|
{
|
|
case 'M':
|
|
// Look for MANUFACTURE (MFG) or MODEL (MDL)
|
|
if ((RtlCompareMemory(lpKey, "MANUFACTURER", wKeyLength)>5) ||
|
|
(RtlCompareMemory(lpKey, "MFG", wKeyLength)==3) )
|
|
{
|
|
*lppMFG = lpValue;
|
|
if ((lpKey = StringChr(lpValue, ';'))!=NULL)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
else if ((RtlCompareMemory(lpKey, "MODEL", wKeyLength)==5) ||
|
|
(RtlCompareMemory(lpKey, "MDL", wKeyLength)==3) )
|
|
{
|
|
*lppMDL = lpValue;
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
// Look for CLASS (CLS)
|
|
if ((RtlCompareMemory(lpKey, "CLASS", wKeyLength)==5) ||
|
|
(RtlCompareMemory(lpKey, "CLS", wKeyLength)==3) )
|
|
{
|
|
*lppCLS = lpValue;
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
else if ((RtlCompareMemory(lpKey, "COMPATIBLEID", wKeyLength)>5) ||
|
|
(RtlCompareMemory(lpKey, "CID", wKeyLength)==3) )
|
|
{
|
|
*lppCID = lpValue;
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((lpKey = StringChr(lpValue,';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
// Look for DESCRIPTION (DES)
|
|
if (RtlCompareMemory(lpKey, "DESCRIPTION", wKeyLength) ||
|
|
RtlCompareMemory(lpKey, "DES", wKeyLength) )
|
|
{
|
|
*lppDES = lpValue;
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'A':
|
|
// Look for AUTOMATIC ID (AID)
|
|
if (RtlCompareMemory(lpKey, "AUTOMATICID", wKeyLength) ||
|
|
RtlCompareMemory(lpKey, "AID", wKeyLength) )
|
|
{
|
|
*lppAID = lpValue;
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// The key is uninteresting. Go to the next Key
|
|
if ((lpKey = StringChr(lpValue, ';'))!=0)
|
|
{
|
|
*lpKey = '\0';
|
|
++lpKey;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
GetCheckSum(
|
|
PUCHAR Block,
|
|
USHORT Len,
|
|
PUSHORT CheckSum
|
|
)
|
|
{
|
|
USHORT i;
|
|
USHORT crc = 0;
|
|
|
|
unsigned short crc16a[] = {
|
|
0000000, 0140301, 0140601, 0000500,
|
|
0141401, 0001700, 0001200, 0141101,
|
|
0143001, 0003300, 0003600, 0143501,
|
|
0002400, 0142701, 0142201, 0002100,
|
|
};
|
|
unsigned short crc16b[] = {
|
|
0000000, 0146001, 0154001, 0012000,
|
|
0170001, 0036000, 0024000, 0162001,
|
|
0120001, 0066000, 0074000, 0132001,
|
|
0050000, 0116001, 0104001, 0043000,
|
|
};
|
|
|
|
//
|
|
// Calculate CRC using tables.
|
|
//
|
|
|
|
UCHAR tmp;
|
|
for ( i=0; i<Len; i++) {
|
|
tmp = Block[i] ^ (UCHAR)crc;
|
|
crc = (crc >> 8) ^ crc16a[tmp & 0x0f] ^ crc16b[tmp >> 4];
|
|
}
|
|
|
|
*CheckSum = crc;
|
|
|
|
}
|
|
|
|
PUCHAR
|
|
StringChr(PCHAR string, CHAR c)
|
|
{
|
|
ULONG i=0;
|
|
|
|
if (!string)
|
|
return(NULL);
|
|
|
|
while (*string) {
|
|
if (*string==c)
|
|
return(string);
|
|
string++;
|
|
i++;
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|