mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1356 lines
36 KiB
1356 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
inflogcf.c
|
|
|
|
Abstract:
|
|
|
|
Routines to parse logical configuration sections in
|
|
win95-style INF files, and place the output in the registry.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 8-Mar-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "setupntp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
PCTSTR pszHexDigits = TEXT("0123456789ABCDEF");
|
|
|
|
#define INFCHAR_SIZE_SEP TEXT('@')
|
|
#define INFCHAR_RANGE_SEP TEXT('-')
|
|
#define INFCHAR_ALIGN_SEP TEXT('%')
|
|
#define INFCHAR_ATTR_START TEXT('(')
|
|
#define INFCHAR_ATTR_END TEXT(')')
|
|
#define INFCHAR_MEMATTR_READ TEXT('R')
|
|
#define INFCHAR_MEMATTR_WRITE TEXT('W')
|
|
#define INFCHAR_MEMATTR_PREFETCH TEXT('F')
|
|
#define INFCHAR_MEMATTR_COMBINEDWRITE TEXT('C')
|
|
#define INFCHAR_MEMATTR_DWORD TEXT('D')
|
|
#define INFCHAR_DECODE_START TEXT('(')
|
|
#define INFCHAR_DECODE_END TEXT(')')
|
|
#define INFCHAR_DECODE_SEP TEXT(':')
|
|
#define INFCHAR_IRQATTR_SEP TEXT(':')
|
|
#define INFCHAR_IRQATTR_SHARE TEXT('S')
|
|
#define INFCHAR_IRQATTR_LEVEL TEXT('L')
|
|
#define INFCHAR_DMAWIDTH_WORD TEXT('W')
|
|
#define INFCHAR_DMAWIDTH_DWORD TEXT('D')
|
|
#define INFCHAR_IOATTR_MEMORY TEXT('M')
|
|
|
|
|
|
#define DEFAULT_MEMORY_ALIGNMENT 0xffffffff // 4K-aligned
|
|
#define DEFAULT_IOPORT_ALIGNMENT 0xffffffff // byte-aligned
|
|
#define DEFAULT_IOPORT_DECODE 0x000003ff // 10 bits
|
|
#define DEFAULT_IOPORT_ALIAS 0x00000000 // no aliases
|
|
#define DEFAULT_IRQ_AFFINITY 0xffffffff // use any processor
|
|
|
|
|
|
//
|
|
// Mapping between registry key specs in an inf file
|
|
// and predefined registry handles.
|
|
//
|
|
STRING_TO_DATA InfPrioritySpecToPriority[] = { TEXT("HARDWIRED") , LCPRI_HARDWIRED,
|
|
TEXT("DESIRED") , LCPRI_DESIRED,
|
|
TEXT("NORMAL") , LCPRI_NORMAL,
|
|
TEXT("SUBOPTIMAL") , LCPRI_SUBOPTIMAL,
|
|
TEXT("DISABLED") , LCPRI_DISABLED,
|
|
TEXT("RESTART") , LCPRI_RESTART,
|
|
TEXT("REBOOT") , LCPRI_REBOOT,
|
|
TEXT("POWEROFF") , LCPRI_POWEROFF,
|
|
TEXT("HARDRECONFIG"), LCPRI_HARDRECONFIG,
|
|
NULL , 0
|
|
};
|
|
|
|
|
|
STRING_TO_DATA InfConfigSpecToConfig[] = { TEXT("BASIC") , BASIC_LOG_CONF,
|
|
TEXT("FORCED"), FORCED_LOG_CONF,
|
|
NULL , 0
|
|
};
|
|
|
|
|
|
DWORD
|
|
pConfigErrorToWin32Error(
|
|
IN DWORD ConfigError
|
|
)
|
|
{
|
|
DWORD d;
|
|
|
|
switch(ConfigError) {
|
|
|
|
case CR_SUCCESS:
|
|
|
|
d = NO_ERROR;
|
|
break;
|
|
|
|
case CR_OUT_OF_MEMORY:
|
|
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
|
|
default:
|
|
|
|
d = ERROR_INVALID_DATA;
|
|
break;
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pHexToScalar(
|
|
IN PCTSTR FieldStart,
|
|
IN PCTSTR FieldEnd,
|
|
OUT PDWORDLONG Value,
|
|
IN BOOL Want64Bits
|
|
)
|
|
{
|
|
UINT DigitCount;
|
|
UINT i;
|
|
DWORDLONG Accum;
|
|
WORD Types[16];
|
|
|
|
//
|
|
// Make sure the number is in range by checking the number
|
|
// of hex digits.
|
|
//
|
|
DigitCount = FieldEnd - FieldStart;
|
|
if((DigitCount == 0)
|
|
|| (DigitCount > (UINT)(Want64Bits ? 16 : 8))
|
|
|| !GetStringTypeEx(LOCALE_SYSTEM_DEFAULT,CT_CTYPE1,FieldStart,DigitCount,Types)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
Accum = 0;
|
|
for(i=0; i<DigitCount; i++) {
|
|
if(!(Types[i] & C1_XDIGIT)) {
|
|
return(FALSE);
|
|
}
|
|
Accum *= 16;
|
|
Accum += _tcschr(pszHexDigits,(TCHAR)CharUpper((PTSTR)FieldStart[i])) - pszHexDigits;
|
|
}
|
|
|
|
*Value = Accum;
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pHexToUlong(
|
|
IN PCTSTR FieldStart,
|
|
IN PCTSTR FieldEnd,
|
|
OUT PDWORD Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a sequence of unicode hex digits into an
|
|
unsigned 32-bit number. Digits are validated.
|
|
|
|
Arguments:
|
|
|
|
FieldStart - supplies pointer to unicode digit sequence.
|
|
|
|
FieldEnd - supplies pointer to first character beyond the
|
|
digit sequence.
|
|
|
|
Value - receives 32-bit number
|
|
|
|
Return Value:
|
|
|
|
TRUE if the number is in range and valid. FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORDLONG x;
|
|
BOOL b;
|
|
|
|
if(b = pHexToScalar(FieldStart,FieldEnd,&x,FALSE)) {
|
|
*Value = (DWORD)x;
|
|
}
|
|
return(b);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pHexToUlonglong(
|
|
IN PCTSTR FieldStart,
|
|
IN PCTSTR FieldEnd,
|
|
OUT PDWORDLONG Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a sequence of unicode hex digits into an
|
|
unsigned 64-bit number. Digits are validated.
|
|
|
|
Arguments:
|
|
|
|
FieldStart - supplies pointer to unicode digit sequence.
|
|
|
|
FieldEnd - supplies pointer to first character beyond the
|
|
digit sequence.
|
|
|
|
Value - receives 64-bit number
|
|
|
|
Return Value:
|
|
|
|
TRUE if the number is in range and valid. FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
return(pHexToScalar(FieldStart,FieldEnd,Value,TRUE));
|
|
}
|
|
|
|
|
|
BOOL
|
|
pDecimalToUlong(
|
|
IN PCTSTR Field,
|
|
OUT PDWORD Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a nul-terminated sequence of unicode decimal digits into an
|
|
unsigned 32-bit number. Digits are validated.
|
|
|
|
Arguments:
|
|
|
|
Field - supplies pointer to unicode digit sequence.
|
|
|
|
Value - receives DWORD number
|
|
|
|
Return Value:
|
|
|
|
TRUE if the number is in range and valid. FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT DigitCount;
|
|
UINT i;
|
|
DWORDLONG Accum;
|
|
WORD Types[10];
|
|
|
|
DigitCount = lstrlen(Field);
|
|
if((DigitCount == 0) || (DigitCount > 10)
|
|
|| !GetStringTypeEx(LOCALE_SYSTEM_DEFAULT,CT_CTYPE1,Field,DigitCount,Types)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
Accum = 0;
|
|
for(i=0; i<DigitCount; i++) {
|
|
if(!(Types[i] & C1_DIGIT)) {
|
|
return(FALSE);
|
|
}
|
|
Accum *= 10;
|
|
Accum += _tcschr(pszHexDigits,(TCHAR)CharUpper((PTSTR)Field[i])) - pszHexDigits;
|
|
|
|
//
|
|
// Check overflow
|
|
//
|
|
if(Accum > 0xffffffff) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
*Value = (DWORD)Accum;
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessMemConfig(
|
|
IN LOG_CONF LogConfig,
|
|
IN PINFCONTEXT InfLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a MemConfig line in a Win95 INF. Such lines specify
|
|
memory requirements for a device. Each line is expected to be
|
|
in the form
|
|
|
|
MemConfig = <start>-<end>[(<attr>)],<start>-<end>[(<attr>)],...
|
|
|
|
<start> is the start of a memory range (64-bit hex)
|
|
<end> is the end of a memory range (64-bit hex)
|
|
<attr> if present is a string of 0 or more chars from
|
|
F - memory is prefetachable
|
|
R - memory is read-only
|
|
W - memory is write-only
|
|
(If R and W are specified or neither is specified the memory
|
|
is read/write)
|
|
|
|
or
|
|
|
|
MemConfig = <size>@<min>-<max>[%align][(<attr>)],...
|
|
|
|
<size> is the size of a memory range (32-bit hex)
|
|
<min> is the minimum address where the memory range can be (64-bit hex)
|
|
<max> is the maximum address where the memory range can be (64-bit hex)
|
|
<align> (if specified) is the alignment mask for the addresses (32-bit hex)
|
|
<attr> as above.
|
|
|
|
ie, 8000@C0000-D7FFF%F0000 says the device needs a 32K memory window
|
|
starting at any 64K-aligned address between C0000 and D7FFF.
|
|
|
|
The default memory alignment is 4K (FFFFF000).
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT FieldCount,i;
|
|
PCTSTR Field;
|
|
DWORD d;
|
|
PTCHAR p;
|
|
unsigned u;
|
|
UINT Attributes;
|
|
DWORD RangeSize;
|
|
DWORD Align;
|
|
DWORDLONG Start,End;
|
|
PMEM_RESOURCE MemRes;
|
|
PMEM_RANGE MemRange;
|
|
RES_DES ResDes;
|
|
PVOID q;
|
|
BOOL bReadFlag = FALSE, bWriteFlag = FALSE;
|
|
|
|
FieldCount = SetupGetFieldCount(InfLine);
|
|
|
|
if(MemRes = MyMalloc(offsetof(MEM_RESOURCE,MEM_Data))) {
|
|
|
|
ZeroMemory(MemRes,offsetof(MEM_RESOURCE,MEM_Data));
|
|
MemRes->MEM_Header.MD_Type = MType_Range;
|
|
|
|
d = NO_ERROR;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
for(i=1; (d==NO_ERROR) && (i<=FieldCount); i++) {
|
|
|
|
Field = pSetupGetField(InfLine,i);
|
|
|
|
Attributes = 0;
|
|
RangeSize = 0;
|
|
Align = DEFAULT_MEMORY_ALIGNMENT;
|
|
|
|
//
|
|
// See if this is in the start-end or size@min-max format.
|
|
// If we have a size, use it.
|
|
//
|
|
if(p = _tcschr(Field,INFCHAR_SIZE_SEP)) {
|
|
if(pHexToUlong(Field,p,&RangeSize)) {
|
|
Field = ++p;
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We should now have a x-y which is either start/end or min/max.
|
|
//
|
|
if((d == NO_ERROR) // no err so far
|
|
&& (p = _tcschr(Field,INFCHAR_RANGE_SEP)) // Field: start of min; p: end of min
|
|
&& pHexToUlonglong(Field,p,&Start) // get min
|
|
&& (Field = p+1) // Field: start of max
|
|
&& ( (p = _tcschr(Field,INFCHAR_ALIGN_SEP))
|
|
|| (p = _tcschr(Field,INFCHAR_ATTR_START))
|
|
|| (p = _tcschr(Field,0))) // p: end of max
|
|
&& pHexToUlonglong(Field,p,&End)) { // get max
|
|
//
|
|
// If we get here Field is pointing either at the end of the field,
|
|
// at the % that starts the alignment mask spec, or at the
|
|
// ( that starts the attributes spec.
|
|
//
|
|
Field = p;
|
|
if(*Field == INFCHAR_ALIGN_SEP) {
|
|
Field++;
|
|
p = _tcschr(Field,INFCHAR_ATTR_START);
|
|
if(!p) {
|
|
p = _tcschr(Field,0);
|
|
}
|
|
if(pHexToUlong(Field,p,&Align)) {
|
|
//
|
|
// For example, 000F0000, 00FF0000, 0FFF0000, and FFFF0000
|
|
// all specify 64K alignment (depending on the min and
|
|
// max addresses, the INF writer might not need to specify
|
|
// all the 1 bits in the 32-bit value).
|
|
// Thus we perform an ersatz sign extension of sorts -- we
|
|
// find the highest 1 bit and replicate it into all the
|
|
// more significant bits in the value.
|
|
//
|
|
for(u=31; u>=0; u--) {
|
|
if(Align & (1 << u)) {
|
|
break;
|
|
}
|
|
Align |= (1 << u);
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if we have attributes.
|
|
//
|
|
if((d == NO_ERROR) && (*p == INFCHAR_ATTR_START)) {
|
|
Field = ++p;
|
|
if(p = _tcschr(Field,INFCHAR_ATTR_END)) {
|
|
//
|
|
// F for prefetachable
|
|
// R for readable
|
|
// W for writeable
|
|
// RW (or neither) means read/write
|
|
//
|
|
while((d == NO_ERROR) && (Field < p)) {
|
|
|
|
switch((TCHAR)CharUpper((PTSTR)(*Field))) {
|
|
case INFCHAR_MEMATTR_READ:
|
|
bReadFlag = TRUE;
|
|
break;
|
|
case INFCHAR_MEMATTR_WRITE:
|
|
bWriteFlag = TRUE;
|
|
break;
|
|
case INFCHAR_MEMATTR_PREFETCH:
|
|
Attributes |= fMD_PrefetchAllowed;
|
|
break;
|
|
case INFCHAR_MEMATTR_COMBINEDWRITE:
|
|
Attributes |= fMD_CombinedWriteAllowed;
|
|
break;
|
|
case INFCHAR_MEMATTR_DWORD:
|
|
Attributes |= fMD_32;
|
|
break;
|
|
default:
|
|
d = ERROR_INVALID_DATA;
|
|
break;
|
|
}
|
|
|
|
Field++;
|
|
}
|
|
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
//
|
|
// If no range size was specified, then calculate it from
|
|
// the given start and end addresses. Since this happens
|
|
// when the memory requirement was an absolute start/end,
|
|
// there is no alignment requirement.
|
|
//
|
|
if(RangeSize == 0) {
|
|
RangeSize = (DWORD)(End-Start)+1;
|
|
Align = DEFAULT_MEMORY_ALIGNMENT;
|
|
}
|
|
|
|
//
|
|
// Slam values into the header part of the memory descriptor.
|
|
// These will be ignored unless we're setting a forced config.
|
|
// Note that the inf had better have specified forced mem configs
|
|
// in a 'simple' form, since we throw away alignment, etc.
|
|
//
|
|
if (bWriteFlag && bReadFlag) {
|
|
Attributes |= fMD_ReadAllowed | fMD_RAM; // read-write
|
|
} else if (bWriteFlag && !bReadFlag) {
|
|
Attributes |= fMD_ReadDisallowed | fMD_RAM; // write only
|
|
} else if (!bWriteFlag && bReadFlag) {
|
|
Attributes |= fMD_ReadAllowed | fMD_ROM; // read-only
|
|
} else {
|
|
Attributes |= fMD_ReadAllowed | fMD_RAM; // read-write
|
|
}
|
|
|
|
MemRes->MEM_Header.MD_Alloc_Base = Start;
|
|
MemRes->MEM_Header.MD_Alloc_End = Start + RangeSize - 1;
|
|
MemRes->MEM_Header.MD_Flags = Attributes;
|
|
|
|
//
|
|
// Add this guy into the descriptor we're building up.
|
|
//
|
|
q = MyRealloc(
|
|
MemRes,
|
|
offsetof(MEM_RESOURCE,MEM_Data)
|
|
+ (sizeof(MEM_RANGE)*(MemRes->MEM_Header.MD_Count+1))
|
|
);
|
|
|
|
if(q) {
|
|
MemRes = q;
|
|
MemRange = &MemRes->MEM_Data[MemRes->MEM_Header.MD_Count++];
|
|
|
|
MemRange->MR_Align = Align;
|
|
MemRange->MR_nBytes = RangeSize;
|
|
MemRange->MR_Min = Start;
|
|
MemRange->MR_Max = End;
|
|
MemRange->MR_Flags = Attributes;
|
|
MemRange->MR_Reserved = 0;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if((d == NO_ERROR) && MemRes->MEM_Header.MD_Count) {
|
|
|
|
d = CM_Add_Res_Des(
|
|
&ResDes,
|
|
LogConfig,
|
|
ResType_Mem,
|
|
MemRes,
|
|
offsetof(MEM_RESOURCE,MEM_Data) + (sizeof(MEM_RANGE) * MemRes->MEM_Header.MD_Count),
|
|
0
|
|
);
|
|
|
|
d = pConfigErrorToWin32Error(d);
|
|
|
|
if(d == NO_ERROR) {
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
}
|
|
}
|
|
|
|
if(MemRes) {
|
|
MyFree(MemRes);
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessIoConfig(
|
|
IN LOG_CONF LogConfig,
|
|
IN PINFCONTEXT InfLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an IOConfig line in a Win95 INF. Such lines specify
|
|
IO port requirements for a device. Each line is expected to be
|
|
in the form
|
|
|
|
IOConfig = <start>-<end>[(<decodemask>:<aliasoffset>:<attr>)],...
|
|
|
|
<start> is the start of a port range (64-bit hex)
|
|
<end> is the end of a port range (64-bit hex)
|
|
<decodemask> if specified is a mask indicating which bits are decoded
|
|
by the device (64-bit hex)
|
|
<aliasoffset> if specified is the alias multiple (32-bit hex)
|
|
<attr> is ignored.
|
|
|
|
or
|
|
|
|
IOConfig = <size>@<min>-<max>[%align][(<decodemask>:<aliasoffset>:<attr>)],...
|
|
|
|
<size> is the size of a port range (32-bit hex)
|
|
<min> is the minimum port where the memory range can be (64-bit hex)
|
|
<max> is the maximum port where the memory range can be (64-bit hex)
|
|
<align> (if specified) is the alignment mask for the ports (32-bit hex)
|
|
<decodemask>, <aliasoffset>,<attr> as above
|
|
|
|
ie, IOConfig = 1F8-1FF(3FF::),2F8-2FF(3FF::),3F8-3FF(3FF::)
|
|
IOConfig = 8@300-32F%FF8(3FF::)
|
|
IOConfig = 2E8-2E8(FFFF:4:)
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT FieldCount,i;
|
|
PCTSTR Field;
|
|
DWORD d;
|
|
PTCHAR p;
|
|
unsigned u;
|
|
DWORD RangeSize;
|
|
DWORD Align;
|
|
DWORDLONG Decode;
|
|
DWORD Alias;
|
|
DWORDLONG Start,End;
|
|
BOOL GotSize;
|
|
PIO_RESOURCE IoRes;
|
|
PIO_RANGE IoRange;
|
|
RES_DES ResDes;
|
|
PVOID q;
|
|
UINT Attributes;
|
|
PTCHAR Attr;
|
|
|
|
FieldCount = SetupGetFieldCount(InfLine);
|
|
|
|
if(IoRes = MyMalloc(offsetof(IO_RESOURCE,IO_Data))) {
|
|
|
|
ZeroMemory(IoRes,offsetof(IO_RESOURCE,IO_Data));
|
|
IoRes->IO_Header.IOD_Type = IOType_Range;
|
|
|
|
d = NO_ERROR;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
for(i=1; (d==NO_ERROR) && (i<=FieldCount); i++) {
|
|
|
|
Field = pSetupGetField(InfLine,i);
|
|
|
|
Attributes = fIOD_IO;
|
|
Alias = DEFAULT_IOPORT_ALIAS;
|
|
Decode = DEFAULT_IOPORT_DECODE;
|
|
RangeSize = 0;
|
|
Align = DEFAULT_MEMORY_ALIGNMENT;
|
|
|
|
//
|
|
// See if this is in the start-end or size@min-max format.
|
|
// If we have a size, use it.
|
|
//
|
|
if(p = _tcschr(Field,INFCHAR_SIZE_SEP)) {
|
|
if(pHexToUlong(Field,p,&RangeSize)) {
|
|
Field = ++p;
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We should now have a x-y which is either start/end or min/max.
|
|
//
|
|
if((d == NO_ERROR) // no err so far
|
|
&& (p = _tcschr(Field,INFCHAR_RANGE_SEP)) // Field: start of min; p: end of min
|
|
&& pHexToUlonglong(Field,p,&Start) // get min
|
|
&& (Field = p+1) // Field: start of max
|
|
&& ( (p = _tcschr(Field,INFCHAR_ALIGN_SEP))
|
|
|| (p = _tcschr(Field,INFCHAR_DECODE_START))
|
|
|| (p = _tcschr(Field,0))) // p: end of max
|
|
&& pHexToUlonglong(Field,p,&End)) { // get max
|
|
//
|
|
// If we get here Field is pointing either at the end of the field,
|
|
// or at the % that starts the alignment mask spec,
|
|
// or at the ( that starts the decode stuff.
|
|
//
|
|
Field = p;
|
|
switch(*Field) {
|
|
case INFCHAR_ALIGN_SEP:
|
|
Field++;
|
|
|
|
|
|
p = _tcschr(Field,INFCHAR_ATTR_START);
|
|
if(!p) {
|
|
p = _tcschr(Field,0);
|
|
}
|
|
if(pHexToUlong(Field,p,&Align)) {
|
|
//
|
|
// For example, 000F0000, 00FF0000, 0FFF0000, and FFFF0000
|
|
// all specify 64K alignment (depending on the min and
|
|
// max addresses, the INF writer might not need to specify
|
|
// all the 1 bits in the 32-bit value).
|
|
// Thus we perform an ersatz sign extension of sorts -- we
|
|
// find the highest 1 bit and replicate it into all the
|
|
// more significant bits in the value.
|
|
//
|
|
for(u=31; u>=0; u--) {
|
|
if(Align & (1 << u)) {
|
|
break;
|
|
}
|
|
Align |= (1 << u);
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
break;
|
|
|
|
case INFCHAR_DECODE_START:
|
|
//
|
|
// Get (decode:alias:). Alias can be empty, in which case we
|
|
// want to use the default (Alias is already filled in, above).
|
|
//
|
|
Field++;
|
|
p = _tcschr(Field,INFCHAR_DECODE_SEP);
|
|
if (p) {
|
|
if (Field != p) {
|
|
pHexToUlonglong(Field,p,&Decode); // got decode value
|
|
}
|
|
Field = p+1;
|
|
p = _tcschr(Field,INFCHAR_DECODE_SEP);
|
|
if (p) {
|
|
if (Field != p) {
|
|
pHexToUlong(Field,p,&Alias); // got alias value
|
|
}
|
|
Field = p+1;
|
|
p = _tcschr(Field,INFCHAR_DECODE_END);
|
|
if (p) {
|
|
if (Field != p) {
|
|
if (*Field == INFCHAR_IOATTR_MEMORY) {
|
|
Attributes = fIOD_Memory; // got attribute value
|
|
}
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
//
|
|
// If no range size was specified, then calculate it from
|
|
// the given start and end addresses. Since this happens
|
|
// when the port requirement was an absolute start/end,
|
|
// there is no alignment requirement.
|
|
//
|
|
if(RangeSize == 0) {
|
|
RangeSize = (DWORD)(End-Start)+1;
|
|
Align = DEFAULT_MEMORY_ALIGNMENT;
|
|
}
|
|
|
|
//
|
|
// Slam values into the header part of the i/o descriptor.
|
|
// These will be ignored unless we're setting a forced config.
|
|
// Note that the inf had better have specified forced i/o configs
|
|
// in a 'simple' form, since we throw away alignment, etc.
|
|
//
|
|
IoRes->IO_Header.IOD_Alloc_Base = Start;
|
|
IoRes->IO_Header.IOD_Alloc_End = Start + RangeSize - 1;
|
|
IoRes->IO_Header.IOD_DesFlags = Attributes;
|
|
|
|
//
|
|
// Add this guy into the descriptor we're building up.
|
|
//
|
|
q = MyRealloc(
|
|
IoRes,
|
|
offsetof(IO_RESOURCE,IO_Data)
|
|
+ (sizeof(IO_RANGE)*(IoRes->IO_Header.IOD_Count+1))
|
|
);
|
|
|
|
if(q) {
|
|
IoRes = q;
|
|
IoRange = &IoRes->IO_Data[IoRes->IO_Header.IOD_Count++];
|
|
|
|
//
|
|
// BUGBUG no decode mask is available in the IO_RANGE structure!
|
|
//
|
|
IoRange->IOR_Align = Align;
|
|
IoRange->IOR_nPorts = RangeSize;
|
|
IoRange->IOR_Min = Start;
|
|
IoRange->IOR_Max = End;
|
|
IoRange->IOR_RangeFlags = Attributes;
|
|
IoRange->IOR_Alias = Alias;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if((d == NO_ERROR) && IoRes->IO_Header.IOD_Count) {
|
|
|
|
d = CM_Add_Res_Des(
|
|
&ResDes,
|
|
LogConfig,
|
|
ResType_IO,
|
|
IoRes,
|
|
offsetof(IO_RESOURCE,IO_Data) + (sizeof(IO_RANGE) * IoRes->IO_Header.IOD_Count),
|
|
0
|
|
);
|
|
|
|
d = pConfigErrorToWin32Error(d);
|
|
|
|
if(d == NO_ERROR) {
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
}
|
|
}
|
|
|
|
if(IoRes) {
|
|
MyFree(IoRes);
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessIrqConfig(
|
|
IN LOG_CONF LogConfig,
|
|
IN PINFCONTEXT InfLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an IRQConfig line in a Win95 INF. Such lines specify
|
|
IRQ requirements for a device. Each line is expected to be
|
|
in the form
|
|
|
|
IRQConfig = [[S][L]:]<IRQNum>,...
|
|
|
|
S: if present indicates that the interrupt is shareable
|
|
L: if present indicates that the interrupt is Level sensitive,
|
|
otherwise it is assumed to be edge sensitive.
|
|
IRQNum is the IRQ number in decimal.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT FieldCount,i;
|
|
PCTSTR Field;
|
|
DWORD d;
|
|
BOOL Shareable;
|
|
BOOL Level;
|
|
DWORD Irq;
|
|
PIRQ_RESOURCE IrqRes;
|
|
PIRQ_RANGE IrqRange;
|
|
RES_DES ResDes;
|
|
PVOID q;
|
|
|
|
FieldCount = SetupGetFieldCount(InfLine);
|
|
|
|
if(IrqRes = MyMalloc(offsetof(IRQ_RESOURCE,IRQ_Data))) {
|
|
|
|
ZeroMemory(IrqRes,offsetof(IRQ_RESOURCE,IRQ_Data));
|
|
IrqRes->IRQ_Header.IRQD_Type = IRQType_Range;
|
|
|
|
d = NO_ERROR;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Shareable = FALSE;
|
|
Level = FALSE;
|
|
for(i=1; (d==NO_ERROR) && (i<=FieldCount); i++) {
|
|
|
|
Field = pSetupGetField(InfLine,i);
|
|
|
|
//
|
|
// For first field, see if we have S: by itself...
|
|
//
|
|
if((i == 1)
|
|
&&((TCHAR)CharUpper((PTSTR)Field[0]) == INFCHAR_IRQATTR_SHARE)
|
|
&& (Field[1] == INFCHAR_IRQATTR_SEP)) {
|
|
|
|
Shareable = TRUE;
|
|
Field+=2;
|
|
}
|
|
|
|
//
|
|
// ... see if we have an L: by itself...
|
|
//
|
|
if((i == 1)
|
|
&&((TCHAR)CharUpper((PTSTR)Field[0]) == INFCHAR_IRQATTR_LEVEL)
|
|
&& (Field[1] == INFCHAR_IRQATTR_SEP)) {
|
|
|
|
Level = TRUE;
|
|
Field+=2;
|
|
}
|
|
|
|
//
|
|
// ... see if we have both attributes.
|
|
//
|
|
if((i == 1)
|
|
&& (Field[2] == INFCHAR_IRQATTR_SEP)) {
|
|
|
|
if (((TCHAR)CharUpper((PTSTR)Field[0]) == INFCHAR_IRQATTR_SHARE)
|
|
|| (TCHAR)CharUpper((PTSTR)Field[1]) == INFCHAR_IRQATTR_SHARE) {
|
|
|
|
Shareable = TRUE;
|
|
}
|
|
|
|
if (((TCHAR)CharUpper((PTSTR)Field[0]) == INFCHAR_IRQATTR_LEVEL)
|
|
|| (TCHAR)CharUpper((PTSTR)Field[1]) == INFCHAR_IRQATTR_LEVEL) {
|
|
|
|
Level = TRUE;
|
|
}
|
|
Field+=3;
|
|
}
|
|
|
|
if(pDecimalToUlong(Field,&Irq)) {
|
|
|
|
//
|
|
// Slam values into the header part of the irq descriptor.
|
|
// These will be ignored unless we're setting a forced config.
|
|
//
|
|
IrqRes->IRQ_Header.IRQD_Flags = Shareable ? fIRQD_Share : fIRQD_Exclusive;
|
|
IrqRes->IRQ_Header.IRQD_Flags |= Level ? fIRQD_Level : fIRQD_Edge;
|
|
IrqRes->IRQ_Header.IRQD_Alloc_Num = Irq;
|
|
IrqRes->IRQ_Header.IRQD_Affinity = DEFAULT_IRQ_AFFINITY;
|
|
|
|
//
|
|
// Add this guy into the descriptor we're building up.
|
|
//
|
|
q = MyRealloc(
|
|
IrqRes,
|
|
offsetof(IRQ_RESOURCE,IRQ_Data)
|
|
+ (sizeof(IRQ_RANGE)*(IrqRes->IRQ_Header.IRQD_Count+1))
|
|
);
|
|
|
|
if(q) {
|
|
IrqRes = q;
|
|
IrqRange = &IrqRes->IRQ_Data[IrqRes->IRQ_Header.IRQD_Count++];
|
|
|
|
IrqRange->IRQR_Min = Irq;
|
|
IrqRange->IRQR_Max = Irq;
|
|
IrqRange->IRQR_Flags = Shareable ? fIRQD_Share : fIRQD_Exclusive;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
if((d == NO_ERROR) && IrqRes->IRQ_Header.IRQD_Count) {
|
|
|
|
d = CM_Add_Res_Des(
|
|
&ResDes,
|
|
LogConfig,
|
|
ResType_IRQ,
|
|
IrqRes,
|
|
offsetof(IRQ_RESOURCE,IRQ_Data) + (sizeof(IRQ_RANGE) * IrqRes->IRQ_Header.IRQD_Count),
|
|
0
|
|
);
|
|
|
|
d = pConfigErrorToWin32Error(d);
|
|
|
|
if(d == NO_ERROR) {
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
}
|
|
}
|
|
|
|
if(IrqRes) {
|
|
MyFree(IrqRes);
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessDmaConfig(
|
|
IN LOG_CONF LogConfig,
|
|
IN PINFCONTEXT InfLine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a DMAConfig line in a Win95 INF. Such lines specify
|
|
DMA requirements for a device. Each line is expected to be
|
|
in the form
|
|
|
|
DMAConfig = [<attrs>:]<DMANum>,...
|
|
|
|
if <attrs> is present it can be
|
|
D - 32-bit DMA channel
|
|
W - 16-bit DMA channel
|
|
if not present, 8-bit DMA channel
|
|
DMANum is the DMA channel number in decimal.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT FieldCount,i;
|
|
PCTSTR Field;
|
|
DWORD d;
|
|
DWORD Dma;
|
|
UINT ChannelSize; // fDD_ xxx flags
|
|
PDMA_RESOURCE DmaRes;
|
|
PDMA_RANGE DmaRange;
|
|
RES_DES ResDes;
|
|
PVOID q;
|
|
|
|
ChannelSize = fDD_BYTE;
|
|
|
|
if(DmaRes = MyMalloc(offsetof(DMA_RESOURCE,DMA_Data))) {
|
|
|
|
ZeroMemory(DmaRes,offsetof(DMA_RESOURCE,DMA_Data));
|
|
DmaRes->DMA_Header.DD_Type = DType_Range;
|
|
|
|
d = NO_ERROR;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
FieldCount = SetupGetFieldCount(InfLine);
|
|
for(i=1; (d==NO_ERROR) && (i<=FieldCount); i++) {
|
|
|
|
Field = pSetupGetField(InfLine,i);
|
|
|
|
//
|
|
// For first field, see if we have attribute spec.
|
|
//
|
|
if((i == 1) && (lstrlen(Field) > 2) && (Field[1] == INFCHAR_IRQATTR_SEP)) {
|
|
|
|
switch((TCHAR)CharUpper((PTSTR)Field[0])) {
|
|
|
|
case INFCHAR_DMAWIDTH_WORD:
|
|
Field += 2;
|
|
ChannelSize = fDD_WORD;
|
|
break;
|
|
|
|
case INFCHAR_DMAWIDTH_DWORD:
|
|
Field += 2;
|
|
ChannelSize = fDD_DWORD;
|
|
break;
|
|
|
|
default:
|
|
d = ERROR_INVALID_DATA;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
if(pDecimalToUlong(Field,&Dma)) {
|
|
|
|
//
|
|
// Slam values into the header part of the dma descriptor.
|
|
// These will be ignored unless we're setting a forced config.
|
|
//
|
|
DmaRes->DMA_Header.DD_Flags = ChannelSize;
|
|
DmaRes->DMA_Header.DD_Alloc_Chan = Dma;
|
|
|
|
//
|
|
// Add this guy into the descriptor we're building up.
|
|
//
|
|
q = MyRealloc(
|
|
DmaRes,
|
|
offsetof(DMA_RESOURCE,DMA_Data)
|
|
+ (sizeof(DMA_RANGE)*(DmaRes->DMA_Header.DD_Count+1))
|
|
);
|
|
|
|
if(q) {
|
|
DmaRes = q;
|
|
DmaRange = &DmaRes->DMA_Data[DmaRes->DMA_Header.DD_Count++];
|
|
|
|
DmaRange->DR_Min = Dma;
|
|
DmaRange->DR_Max = Dma;
|
|
DmaRange->DR_Flags = ChannelSize;
|
|
|
|
} else {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
}
|
|
|
|
if((d == NO_ERROR) && DmaRes->DMA_Header.DD_Count) {
|
|
|
|
d = CM_Add_Res_Des(
|
|
&ResDes,
|
|
LogConfig,
|
|
ResType_DMA,
|
|
DmaRes,
|
|
offsetof(DMA_RESOURCE,DMA_Data) + (sizeof(DMA_RANGE) * DmaRes->DMA_Header.DD_Count),
|
|
0
|
|
);
|
|
|
|
d = pConfigErrorToWin32Error(d);
|
|
|
|
if(d == NO_ERROR) {
|
|
CM_Free_Res_Des_Handle(ResDes);
|
|
}
|
|
}
|
|
|
|
if(DmaRes) {
|
|
MyFree(DmaRes);
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessLogConfigLines(
|
|
IN PVOID Inf,
|
|
IN PCTSTR SectionName,
|
|
IN PCTSTR KeyName,
|
|
IN DWORD (*CallbackFunc)(LOG_CONFIG,PINFCONTEXT),
|
|
IN LOG_CONF LogConfig
|
|
)
|
|
{
|
|
BOOL b;
|
|
DWORD d;
|
|
INFCONTEXT InfLine;
|
|
|
|
b = SetupFindFirstLine(Inf,SectionName,KeyName,&InfLine);
|
|
d = NO_ERROR;
|
|
//
|
|
// Process each line with a key that matches.
|
|
//
|
|
while(b && (d == NO_ERROR)) {
|
|
|
|
d = CallbackFunc(LogConfig,&InfLine);
|
|
|
|
if(d == NO_ERROR) {
|
|
b = SetupFindNextMatchLine(&InfLine,KeyName,&InfLine);
|
|
}
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessConfigPriority(
|
|
IN PVOID Inf,
|
|
IN PCTSTR SectionName,
|
|
IN LOG_CONF LogConfig,
|
|
OUT PRIORITY *PriorityValue,
|
|
OUT DWORD *ConfigType
|
|
)
|
|
{
|
|
INFCONTEXT InfLine;
|
|
PCTSTR PrioritySpec;
|
|
PCTSTR ConfigSpec;
|
|
DWORD d;
|
|
|
|
//
|
|
// Make sure that the section exists.
|
|
//
|
|
if(SetupGetLineCount(Inf, SectionName) == -1) {
|
|
return ERROR_SECTION_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// We only need to fetch one of these lines and look at the
|
|
// first value on it.
|
|
//
|
|
if(SetupFindFirstLine(Inf,SectionName,TEXT("ConfigPriority"),&InfLine)
|
|
&& (PrioritySpec = pSetupGetField(&InfLine,1))) {
|
|
if(LookUpStringInTable(InfPrioritySpecToPriority,PrioritySpec,PriorityValue)) {
|
|
d = NO_ERROR;
|
|
} else {
|
|
d = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
//
|
|
// The second value is optional and specifies whether the config is forced
|
|
// or standard. If we don't recognize the value then assume basic.
|
|
//
|
|
ConfigSpec = pSetupGetField(&InfLine,2);
|
|
if(!ConfigSpec || !LookUpStringInTable(InfConfigSpecToConfig,ConfigSpec,ConfigType)) {
|
|
|
|
*ConfigType = BASIC_LOG_CONF;
|
|
}
|
|
|
|
} else {
|
|
d = NO_ERROR;
|
|
*PriorityValue = LCPRI_NORMAL;
|
|
}
|
|
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupProcessLogConfigSection(
|
|
IN PVOID Inf,
|
|
IN PCTSTR SectionName,
|
|
IN DEVINST DevInst
|
|
)
|
|
{
|
|
DWORD d;
|
|
LOG_CONF LogConfig;
|
|
PRIORITY Priority;
|
|
DWORD ConfigType;
|
|
CONFIGRET cr;
|
|
|
|
//
|
|
// Process config priority values.
|
|
//
|
|
d = pSetupProcessConfigPriority(Inf,SectionName,LogConfig,&Priority,&ConfigType);
|
|
if(d != NO_ERROR) {
|
|
goto c0;
|
|
}
|
|
|
|
//
|
|
// Now that we know the priority we can create an empty log config.
|
|
//
|
|
d = pConfigErrorToWin32Error(CM_Add_Empty_Log_Conf(&LogConfig,DevInst,Priority,ConfigType));
|
|
if(d != NO_ERROR) {
|
|
goto c0;
|
|
}
|
|
|
|
//
|
|
// Process MemConfig lines
|
|
//
|
|
d = pSetupProcessLogConfigLines(
|
|
Inf,
|
|
SectionName,
|
|
TEXT("MemConfig"),
|
|
pSetupProcessMemConfig,
|
|
LogConfig
|
|
);
|
|
|
|
if(d != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
//
|
|
// Process IOConfig lines
|
|
//
|
|
d = pSetupProcessLogConfigLines(
|
|
Inf,
|
|
SectionName,
|
|
TEXT("IOConfig"),
|
|
pSetupProcessIoConfig,
|
|
LogConfig
|
|
);
|
|
|
|
if(d != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
//
|
|
// Process IRQConfig lines
|
|
//
|
|
d = pSetupProcessLogConfigLines(
|
|
Inf,
|
|
SectionName,
|
|
TEXT("IRQConfig"),
|
|
pSetupProcessIrqConfig,
|
|
LogConfig
|
|
);
|
|
|
|
if(d != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
//
|
|
// Process DMAConfig lines
|
|
//
|
|
d = pSetupProcessLogConfigLines(
|
|
Inf,
|
|
SectionName,
|
|
TEXT("DMAConfig"),
|
|
pSetupProcessDmaConfig,
|
|
LogConfig
|
|
);
|
|
|
|
if(d != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
c1:
|
|
if(d != NO_ERROR) {
|
|
CM_Free_Log_Conf(LogConfig,0);
|
|
}
|
|
CM_Free_Log_Conf_Handle(LogConfig);
|
|
c0:
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupInstallLogConfig(
|
|
IN HINF Inf,
|
|
IN PCTSTR SectionName,
|
|
IN DEVINST DevInst
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look for logical configuration directives within an inf section
|
|
and parse them. Each value on the LogConf= line is taken to be
|
|
the name of a logical config section.
|
|
|
|
Arguments:
|
|
|
|
Inf - supplies inf handle for inf containing the section indicated
|
|
by SectionName.
|
|
|
|
SectionName - supplies name of install section.
|
|
|
|
DevInst - device instance handle for log configs.
|
|
|
|
Return Value:
|
|
|
|
Win32 error code indicating outcome.
|
|
|
|
--*/
|
|
|
|
{
|
|
INFCONTEXT LineContext;
|
|
DWORD rc;
|
|
DWORD FieldCount;
|
|
DWORD Field;
|
|
PCTSTR SectionSpec;
|
|
|
|
//
|
|
// Find the relevent line in the given install section.
|
|
// If not present then we're done with this operation.
|
|
//
|
|
rc = NO_ERROR;
|
|
if(SetupFindFirstLine(Inf,SectionName,SZ_KEY_LOGCONFIG,&LineContext)) {
|
|
|
|
do {
|
|
//
|
|
// Each value on the line in the given install section
|
|
// is the name of a logical config section.
|
|
//
|
|
FieldCount = SetupGetFieldCount(&LineContext);
|
|
for(Field=1; (rc==NO_ERROR) && (Field<=FieldCount); Field++) {
|
|
|
|
if((SectionSpec = pSetupGetField(&LineContext,Field))
|
|
&& (SetupGetLineCount(Inf,SectionSpec) > 0)) {
|
|
|
|
rc = pSetupProcessLogConfigSection(Inf,SectionSpec,DevInst);
|
|
}
|
|
}
|
|
} while(SetupFindNextMatchLine(&LineContext,SZ_KEY_LOGCONFIG,&LineContext));
|
|
}
|
|
|
|
return(rc);
|
|
}
|