windows-nt/Source/XPSP1/NT/base/pnp/setupapi/inflogcf.c
2020-09-26 16:20:57 +08:00

2328 lines
71 KiB
C

/*++
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 "precomp.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_CACHEABLE TEXT('H')
#define INFCHAR_MEMATTR_DWORD TEXT('D')
#define INFCHAR_MEMATTR_ATTRIBUTE TEXT('A')
#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_NARROW TEXT('N') // i.e., 8-bit
#define INFCHAR_DMAWIDTH_WORD TEXT('W') // i.e., 16-bit
#define INFCHAR_DMAWIDTH_DWORD TEXT('D') // i.e., 32-bit
#define INFCHAR_DMA_BUSMASTER TEXT('M')
#define INFCHAR_DMATYPE_A TEXT('A')
#define INFCHAR_DMATYPE_B TEXT('B')
#define INFCHAR_DMATYPE_F TEXT('F')
#define INFCHAR_IOATTR_MEMORY TEXT('M')
#define INFCHAR_PCCARD_IOATTR_WORD TEXT('W')
#define INFCHAR_PCCARD_IOATTR_BYTE TEXT('B')
#define INFCHAR_PCCARD_IOATTR_SRC TEXT('S')
#define INFCHAR_PCCARD_IOATTR_Z8 TEXT('Z')
#define INFCHAR_PCCARD_ATTR_WAIT TEXT('X')
#define INFCHAR_PCCARD_ATTR_WAITI TEXT('I')
#define INFCHAR_PCCARD_ATTR_WAITM TEXT('M')
#define INFCHAR_PCCARD_MEMATTR_WORD TEXT('M')
#define INFCHAR_PCCARD_MEM_ISATTR TEXT('A')
#define INFCHAR_PCCARD_MEM_ISCOMMON TEXT('C')
#define INFCHAR_PCCARD_SEP TEXT(':')
#define INFCHAR_PCCARD_ATTR_SEP TEXT(' ')
#define INFCHAR_MFCARD_AUDIO_ATTR TEXT('A')
#define INFLOGCONF_IOPORT_10BIT_DECODE 0x000003ff
#define INFLOGCONF_IOPORT_12BIT_DECODE 0x00000fff
#define INFLOGCONF_IOPORT_16BIT_DECODE 0x0000ffff
#define INFLOGCONF_IOPORT_POSITIVE_DECODE 0x00000000
#define DEFAULT_IOPORT_DECODE INFLOGCONF_IOPORT_10BIT_DECODE
#define DEFAULT_MEMORY_ALIGNMENT 0xfffffffffffff000 // 4K-aligned (a'la Win9x)
#define DEFAULT_IOPORT_ALIGNMENT 0xffffffffffffffff // byte-aligned
#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[] = { INFSTR_CFGPRI_HARDWIRED , LCPRI_HARDWIRED,
INFSTR_CFGPRI_DESIRED , LCPRI_DESIRED,
INFSTR_CFGPRI_NORMAL , LCPRI_NORMAL,
INFSTR_CFGPRI_SUBOPTIMAL , LCPRI_SUBOPTIMAL,
INFSTR_CFGPRI_DISABLED , LCPRI_DISABLED,
INFSTR_CFGPRI_RESTART , LCPRI_RESTART,
INFSTR_CFGPRI_REBOOT , LCPRI_REBOOT,
INFSTR_CFGPRI_POWEROFF , LCPRI_POWEROFF,
INFSTR_CFGPRI_HARDRECONFIG, LCPRI_HARDRECONFIG,
INFSTR_CFGPRI_FORCECONFIG , LCPRI_FORCECONFIG,
NULL , 0
};
STRING_TO_DATA InfConfigSpecToConfig[] = { INFSTR_CFGTYPE_BASIC , BASIC_LOG_CONF,
INFSTR_CFGTYPE_FORCED , FORCED_LOG_CONF,
INFSTR_CFGTYPE_OVERRIDE, OVERRIDE_LOG_CONF,
NULL , 0
};
//
// Declare strings used in processing INF LogConfigs.
//
// These strings are defined in infstr.h:
//
CONST TCHAR pszMemConfig[] = INFSTR_KEY_MEMCONFIG,
pszIOConfig[] = INFSTR_KEY_IOCONFIG,
pszIRQConfig[] = INFSTR_KEY_IRQCONFIG,
pszDMAConfig[] = INFSTR_KEY_DMACONFIG,
pszPcCardConfig[] = INFSTR_KEY_PCCARDCONFIG,
pszMfCardConfig[] = INFSTR_KEY_MFCARDCONFIG,
pszConfigPriority[] = INFSTR_KEY_CONFIGPRIORITY,
pszDriverVer[] = INFSTR_DRIVERVERSION_SECTION;
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 = (UINT)(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,
IN HMACHINE hMachine
)
/*++
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
C - memory is combined-write
D - memory is 32-bit, otherwise 24-bit.
F - memory is prefetchable
H - memory is cacheable
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;
INT u;
UINT Attributes;
DWORD RangeSize;
ULARGE_INTEGER Align;
DWORDLONG Start,End;
PMEM_RESOURCE MemRes;
PMEM_RANGE MemRange;
RES_DES ResDes;
PVOID q;
BOOL bReadFlag = FALSE, bWriteFlag = FALSE;
FieldCount = SetupGetFieldCount(InfLine);
if (!FieldCount && GetLastError() != NO_ERROR) {
return GetLastError();
}
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.QuadPart = 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_INF_LOGCONFIG;
}
}
//
// 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(pHexToUlonglong(Field, p, &(Align.QuadPart))) {
//
// NOTE: Since these mask values are actually stored in a WDM
// resource list (i.e., IO_RESOURCE_REQUIREMENTS_LIST), there's
// no way to specify an alignment greater than 32 bits. However,
// since the alignment value was implemented as a mask (for
// compatibility with Win9x), we must specify it as a 64-bit
// quantity, since it is applied to a 64-bit value. We will check
// below to ensure that the most significant DWORD is all ones.
//
// Also, we must handle alignment values such as 000F0000, 00FF0000,
// 0FFF0000, and FFFF0000. These 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.HighPart & (1 << u)) {
break;
}
Align.HighPart |= (1 << u);
}
//
// Make sure that all the bits in the most-significant DWORD are set,
// because we can't express this alignment otherwise (as discussed
// above). Also, make sure that if we encountered a '1' in the high
// dword, then the high bit of the low dword is '1' as well.
//
if((Align.HighPart ^ 0xffffffff) ||
((u >= 0) && !(Align.LowPart & 0x80000000))) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
//
// Do the sign extension for the low dword.
//
for(u=31; u>=0; u--) {
if(Align.LowPart & (1 << u)) {
break;
}
Align.LowPart |= (1 << u);
}
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
//
// See if we have attributes.
//
if((d == NO_ERROR) && (*p == INFCHAR_ATTR_START)) {
Field = ++p;
if(p = _tcschr(Field,INFCHAR_ATTR_END)) {
//
// C for combined-write
// D for 32-bit memory
// F for prefetchable
// H for cacheable
// 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;
case INFCHAR_MEMATTR_CACHEABLE:
Attributes |= fMD_Cacheable;
break;
default:
d = ERROR_INVALID_INF_LOGCONFIG;
break;
}
Field++;
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
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.QuadPart = 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.QuadPart;
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_Ex(
&ResDes,
LogConfig,
ResType_Mem,
MemRes,
offsetof(MEM_RESOURCE,MEM_Data) + (sizeof(MEM_RANGE) * MemRes->MEM_Header.MD_Count),
0,
hMachine);
d = MapCrToSpError(d, ERROR_INVALID_DATA);
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,
IN HMACHINE hMachine
)
/*++
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> defines the alias type, and may be one of the following combinations:
3ff 10-bit decode, IOR_Alias is 0x04
fff 12-bit decode, IOR_Alias is 0x10
ffff 16-bit decode, IOR_Alias is 0x00
0 positive decode, IOR_Alias is 0xFF
<aliasoffset> is ignored.
<attr> if 'M', specifies port is a memory address, otherwise port is an IO address.
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(3FF:8000:)
Arguments:
Return Value:
--*/
{
UINT FieldCount,i;
PCTSTR Field;
DWORD d;
PTCHAR p;
INT u;
DWORD RangeSize;
ULARGE_INTEGER Align;
DWORDLONG Decode;
DWORDLONG Start,End;
BOOL GotSize;
PIO_RESOURCE IoRes;
PIO_RANGE IoRange;
RES_DES ResDes;
PVOID q;
UINT Attributes = 0;
PTCHAR Attr;
FieldCount = SetupGetFieldCount(InfLine);
if (!FieldCount && GetLastError() != NO_ERROR) {
return GetLastError();
}
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;
Decode = DEFAULT_IOPORT_DECODE;
RangeSize = 0;
Align.QuadPart = DEFAULT_IOPORT_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_INF_LOGCONFIG;
}
}
//
// 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(pHexToUlonglong(Field, p, &(Align.QuadPart))) {
//
// NOTE: Since these mask values are actually stored in a WDM
// resource list (i.e., IO_RESOURCE_REQUIREMENTS_LIST), there's
// no way to specify an alignment greater than 32 bits. However,
// since the alignment value was implemented as a mask (for
// compatibility with Win9x), we must specify it as a 64-bit
// quantity, since it is applied to a 64-bit value. We will check
// below to ensure that the most significant DWORD is all ones.
//
// Also, we must handle alignment values such as 000F0000, 00FF0000,
// 0FFF0000, and FFFF0000. These 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.HighPart & (1 << u)) {
break;
}
Align.HighPart |= (1 << u);
}
//
// Make sure that all the bits in the most-significant DWORD are set,
// because we can't express this alignment otherwise (as discussed
// above). Also, make sure that if we encountered a '1' in the high
// dword, then the high bit of the low dword is '1' as well.
//
if((Align.HighPart ^ 0xffffffff) ||
((u >= 0) && !(Align.LowPart & 0x80000000))) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
//
// Do the sign extension for the low dword.
//
for(u=31; u>=0; u--) {
if(Align.LowPart & (1 << u)) {
break;
}
Align.LowPart |= (1 << u);
}
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
break;
case INFCHAR_DECODE_START:
//
// Get decode value (this determines the IOR_Alias that gets filled
// in for the resdes.
//
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) {
//
// Ignore alias field.
//
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_INF_LOGCONFIG;
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
break;
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
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 (i.e., the default
// byte-alignment should be specified).
//
if(RangeSize == 0) {
RangeSize = (DWORD)(End-Start)+1;
Align.QuadPart = DEFAULT_IOPORT_ALIGNMENT;
}
//
// Create an alternate decode flag
//
switch(Decode) {
case INFLOGCONF_IOPORT_10BIT_DECODE:
Attributes |= fIOD_10_BIT_DECODE;
break;
case INFLOGCONF_IOPORT_12BIT_DECODE:
Attributes |= fIOD_12_BIT_DECODE;
break;
case INFLOGCONF_IOPORT_16BIT_DECODE:
Attributes |= fIOD_16_BIT_DECODE;
break;
case INFLOGCONF_IOPORT_POSITIVE_DECODE:
Attributes |= fIOD_POSITIVE_DECODE;
break;
}
//
// 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++];
IoRange->IOR_Align = Align.QuadPart;
IoRange->IOR_nPorts = RangeSize;
IoRange->IOR_Min = Start;
IoRange->IOR_Max = End;
IoRange->IOR_RangeFlags = Attributes;
switch(Decode) {
case INFLOGCONF_IOPORT_10BIT_DECODE:
IoRange->IOR_Alias = IO_ALIAS_10_BIT_DECODE;
break;
case INFLOGCONF_IOPORT_12BIT_DECODE:
IoRange->IOR_Alias = IO_ALIAS_12_BIT_DECODE;
break;
case INFLOGCONF_IOPORT_16BIT_DECODE:
IoRange->IOR_Alias = IO_ALIAS_16_BIT_DECODE;
break;
case INFLOGCONF_IOPORT_POSITIVE_DECODE:
IoRange->IOR_Alias = IO_ALIAS_POSITIVE_DECODE;
break;
default:
d = ERROR_INVALID_INF_LOGCONFIG;
break;
}
} else {
d = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
if((d == NO_ERROR) && IoRes->IO_Header.IOD_Count) {
d = CM_Add_Res_Des_Ex(
&ResDes,
LogConfig,
ResType_IO,
IoRes,
offsetof(IO_RESOURCE,IO_Data) + (sizeof(IO_RANGE) * IoRes->IO_Header.IOD_Count),
0,
hMachine);
d = MapCrToSpError(d, ERROR_INVALID_DATA);
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,
IN HMACHINE hMachine
)
/*++
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 (!FieldCount && GetLastError() != NO_ERROR) {
return GetLastError();
}
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;
IrqRange->IRQR_Flags |= Level ? fIRQD_Level : fIRQD_Edge;
} else {
d = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
if((d == NO_ERROR) && IrqRes->IRQ_Header.IRQD_Count) {
d = CM_Add_Res_Des_Ex(
&ResDes,
LogConfig,
ResType_IRQ,
IrqRes,
offsetof(IRQ_RESOURCE,IRQ_Data) + (sizeof(IRQ_RANGE) * IrqRes->IRQ_Header.IRQD_Count),
0,
hMachine);
d = MapCrToSpError(d, ERROR_INVALID_DATA);
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,
IN HMACHINE hMachine
)
/*++
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
N - 8-bit DMA channel (default). Specify both W and N if 8- and 16-bit DMA is supported.
M - Bus Mastering
A - Type-A DMA channel
B - Type-B DMA channel
F - Type-F DMA channel
(If none of A, B, or F are specified, then standard DMA is assumed)
DMANum is the DMA channel number in decimal.
Arguments:
Return Value:
--*/
{
UINT FieldCount,i;
PCTSTR Field;
DWORD d;
DWORD Dma;
INT ChannelSize; // fDD_ xxx flags for channel width
INT DmaType; // fDD_ xxx flags for DMA type
PDMA_RESOURCE DmaRes;
PDMA_RANGE DmaRange;
RES_DES ResDes;
PVOID q;
PTCHAR p;
BOOL BusMaster;
ULONG DmaFlags;
ChannelSize = -1;
BusMaster = FALSE;
DmaType = -1;
FieldCount = SetupGetFieldCount(InfLine);
if (!FieldCount && GetLastError() != NO_ERROR) {
return GetLastError();
}
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;
}
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) {
if(p = _tcschr(Field, INFCHAR_IRQATTR_SEP)) {
for( ;((d == NO_ERROR) && (Field < p)); Field++) {
switch((TCHAR)CharUpper((PTSTR)(*Field))) {
//
// Channel size can be both 8 and 16 (i.e., both 'W' and 'N'), but
// you can't mix these with 'D'.
//
case INFCHAR_DMAWIDTH_WORD:
if(ChannelSize == fDD_DWORD) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else if(ChannelSize == fDD_BYTE) {
ChannelSize = fDD_BYTE_AND_WORD;
} else {
ChannelSize = fDD_WORD;
}
break;
case INFCHAR_DMAWIDTH_DWORD:
if((ChannelSize != -1) && (ChannelSize != fDD_DWORD)) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
ChannelSize = fDD_DWORD;
}
break;
case INFCHAR_DMAWIDTH_NARROW:
if(ChannelSize == fDD_DWORD) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else if(ChannelSize == fDD_WORD) {
ChannelSize = fDD_BYTE_AND_WORD;
} else {
ChannelSize = fDD_BYTE;
}
break;
case INFCHAR_DMA_BUSMASTER:
BusMaster = TRUE;
break;
//
// The DMA types are mutually exclusive...
//
case INFCHAR_DMATYPE_A:
if((DmaType != -1) && (DmaType != fDD_TypeA)) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
DmaType = fDD_TypeA;
}
break;
case INFCHAR_DMATYPE_B:
if((DmaType != -1) && (DmaType != fDD_TypeB)) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
DmaType = fDD_TypeB;
}
break;
case INFCHAR_DMATYPE_F:
if((DmaType != -1) && (DmaType != fDD_TypeF)) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
DmaType = fDD_TypeF;
}
break;
default:
d = ERROR_INVALID_INF_LOGCONFIG;
break;
}
}
Field++; // skip over separator character
}
if(ChannelSize == -1) {
DmaFlags = fDD_BYTE; // default is 8-bit DMA
} else {
DmaFlags = (ULONG)ChannelSize;
}
if(BusMaster) {
DmaFlags |= fDD_BusMaster;
}
if(DmaType != -1) {
DmaFlags |= DmaType;
}
}
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 = DmaFlags;
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 = DmaFlags;
} else {
d = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
}
if((d == NO_ERROR) && DmaRes->DMA_Header.DD_Count) {
d = CM_Add_Res_Des_Ex(
&ResDes,
LogConfig,
ResType_DMA,
DmaRes,
offsetof(DMA_RESOURCE,DMA_Data) + (sizeof(DMA_RANGE) * DmaRes->DMA_Header.DD_Count),
0,
hMachine);
d = MapCrToSpError(d, ERROR_INVALID_DATA);
if(d == NO_ERROR) {
CM_Free_Res_Des_Handle(ResDes);
}
}
if(DmaRes) {
MyFree(DmaRes);
}
return(d);
}
DWORD
pSetupProcessPcCardConfig(
IN LOG_CONF LogConfig,
IN PINFCONTEXT InfLine,
IN HMACHINE hMachine
)
/*++
Routine Description:
Process a PcCardConfig line in a Win95 INF. Such lines specify
PC Card (PCMCIA) configuration information necessary for a device.
Each line is expected to be in the form
PcCardConfig = <ConfigIndex>[:[<MemoryCardBase1>][:<MemoryCardBase2>]][(<attrs>)]
where
<ConfigIndex> is the 8-bit PCMCIA configuration index
<MemoryCardBase1> is the (optional) 32-bit 1st memory base address
<MemoryCardBase2> is the (optional) 32-bit 2nd memory base address
<attrs> is a combination of attribute specifiers optionally separated by
spaces. The attribute string is processed from left to right,
and an invalid attribute specifier aborts the entire PcCardConfig
directive. Attributes may be specified in any order except for the
positional attributes 'A' and 'C', which are described below.
Accepted attribute specifiers are as follows:
W - 16-bit I/O data path (default: 16-bit)
B - 8-bit I/O data path (default: 16-bit)
Sn - ~IOCS16 source. If n is zero, ~IOCS16 is based on the value of
the datasize bit. If n is one, ~IOCS16 is based on the ~IOIS16
signal from the device. (default: 1)
Zn - I/O 8-bit zero wait state. If n is one, 8-bit I/O accesses occur
with zero additional wait states. If n is zero, access will
occur with additional wait states. This flag has no meaning for
16-bit I/O. (default: 0)
XIn - I/O wait states. If n is one, 16-bit system accesses occur with
1 additional wait state. (default: 1)
M - 16-bit Memory (default: 8-bit)
M8 - 8-bit Memory (default: 8-bit)
XMn - Memory wait states, where n can be 0, 1, 2 or 3. This value
determines the number of additional wait states for 16-bit
accesses to a memory window. (default: 3)
NOTE: The following two attributes relate positionally to memory
windows resources. That is, the first 'A' or 'C' specified in the
attribute string (reading from left to right) corresponds to the
first memory resource in the device's resource list. The next
'A' or 'C' corresponds to the second memory resource. Subsequent
attribute/common memory specifiers are ignored.
A - Memory range to be mapped as Attribute memory
C - Memory range to be mapped as Common Memory (default)
Example:
(W CA M XM1 XI0) translates to:
I/O 16bit
1st memory window is common
2nd memory window is attribute
Memory 16 bit
one wait state on memory windows
zero wait states on i/o windows
All numeric values are assumed to be in hexadecimal format.
Arguments:
Return Value:
--*/
{
PCCARD_RESOURCE PcCardResource;
PCTSTR Field, p;
DWORD ConfigIndex, i, d;
DWORD MemoryCardBase[PCD_MAX_MEMORY] = {0};
DWORD Flags;
UINT memAttrIndex = 0, memWaitIndex = 0, memWidthIndex = 0;
UINT ioSourceIndex = 0, ioZeroWait8Index = 0, ioWaitState16Index = 0, ioWidthIndex = 0;
UINT index;
RES_DES ResDes;
//
// Assume failure
//
d = ERROR_INVALID_INF_LOGCONFIG;
//
// We should have one field (not counting the line's key)
//
if(SetupGetFieldCount(InfLine) != 1) {
goto clean0;
} else {
Field = pSetupGetField(InfLine, 1);
}
//
// Retrieve the ConfigIndex. It may be terminated by either a colon ':',
// an open paren '(', or eol.
//
if(!(p = _tcschr(Field, INFCHAR_PCCARD_SEP)) && !(p = _tcschr(Field, INFCHAR_ATTR_START))) {
p = Field + lstrlen(Field);
}
if(!pHexToUlong(Field, p, &ConfigIndex) || (ConfigIndex > 255)) {
goto clean0;
}
//
// Process the (optional) memory card base addresses
//
for(i = 0; i < PCD_MAX_MEMORY; i++) {
if(*p == INFCHAR_PCCARD_SEP) {
Field = p + 1;
if(!(p = _tcschr(Field, INFCHAR_PCCARD_SEP)) && !(p = _tcschr(Field, INFCHAR_ATTR_START))) {
p = Field + lstrlen(Field);
}
//
// Allow an empty field.
//
if(Field == p) {
MemoryCardBase[i] = 0;
} else if(!pHexToUlong(Field, p, &(MemoryCardBase[i]))) {
goto clean0;
}
} else {
MemoryCardBase[i] = 0;
}
}
//
// Initialize the flags
//
Flags = fPCD_ATTRIBUTES_PER_WINDOW |
fPCD_MEM1_WS_THREE | fPCD_MEM2_WS_THREE |
fPCD_IO1_SRC_16 | fPCD_IO2_SRC_16 |
fPCD_IO1_WS_16 | fPCD_IO2_WS_16;
if(*p && (*p == INFCHAR_ATTR_START)) {
//
// Read the attributes.
// W - 16-bit I/O data path
// B - 8-bit I/O data path
// Sn - ~IOCS16 source.
// Zn - I/O 8-bit zero wait state.
// XIn - I/O wait states.
// M - 16-bit Memory
// M8 - 8-bit Memory
// XMn - Memory wait states
// A - Attribute Memory
// C - Common Memory
//
Field = ++p;
if(!(p = _tcschr(Field,INFCHAR_ATTR_END))) {
goto clean0;
}
while(Field < p) {
switch((TCHAR)CharUpper((PTSTR)(*Field))) {
case INFCHAR_PCCARD_IOATTR_WORD:
if (ioWidthIndex >= PCD_MAX_IO) {
goto clean0;
}
Flags |= (ioWidthIndex++ ? fPCD_IO2_16
: (fPCD_IO1_16 | fPCD_IO2_16));
break;
case INFCHAR_PCCARD_IOATTR_BYTE:
if (ioWidthIndex >= PCD_MAX_IO) {
goto clean0;
}
Flags &= (ioWidthIndex++ ? ~fPCD_IO2_16
: ~(fPCD_IO1_16 | fPCD_IO2_16));
break;
case INFCHAR_PCCARD_MEMATTR_WORD:
if (memWidthIndex >= PCD_MAX_MEMORY) {
goto clean0;
}
if (++Field < p) {
if (*Field == TEXT('8')) {
Flags &= (memWidthIndex++ ? ~fPCD_MEM2_16
: ~(fPCD_MEM1_16 | fPCD_MEM2_16));
break;
}
// not an 8, back up 1
--Field;
}
Flags |= (memWidthIndex++ ? fPCD_MEM2_16
: (fPCD_MEM1_16 | fPCD_MEM2_16));
break;
case INFCHAR_PCCARD_MEM_ISATTR:
if (memAttrIndex >= PCD_MAX_MEMORY) {
goto clean0;
}
Flags |= (memAttrIndex++ ? fPCD_MEM2_A
: (fPCD_MEM1_A | fPCD_MEM2_A));
break;
case INFCHAR_PCCARD_MEM_ISCOMMON:
if (memAttrIndex >= PCD_MAX_MEMORY) {
goto clean0;
}
Flags &= (memAttrIndex++ ? ~fPCD_MEM2_A
: ~(fPCD_MEM1_A | fPCD_MEM2_A));
break;
case INFCHAR_PCCARD_IOATTR_SRC:
if (ioSourceIndex >= PCD_MAX_IO) {
goto clean0;
}
if (++Field < p) {
if (*Field == TEXT('0')) {
Flags &= (ioSourceIndex++ ? ~fPCD_IO2_SRC_16
: ~(fPCD_IO1_SRC_16 | fPCD_IO2_SRC_16));
} else if (*Field == TEXT('1')) {
Flags |= (ioSourceIndex++ ? fPCD_IO2_SRC_16
: (fPCD_IO1_SRC_16 | fPCD_IO2_SRC_16));
} else {
goto clean0;
}
}
break;
case INFCHAR_PCCARD_IOATTR_Z8:
if (ioZeroWait8Index >= PCD_MAX_IO) {
goto clean0;
}
if (++Field < p) {
if (*Field == TEXT('0')) {
Flags &= (ioZeroWait8Index++ ? ~fPCD_IO2_ZW_8
: ~(fPCD_IO1_ZW_8 | fPCD_IO2_ZW_8));
} else if (*Field == TEXT('1')) {
Flags |= (ioZeroWait8Index++ ? fPCD_IO2_ZW_8
: (fPCD_IO1_ZW_8 | fPCD_IO2_ZW_8));
} else {
goto clean0;
}
}
break;
case INFCHAR_PCCARD_ATTR_WAIT:
if (++Field < p) {
switch((TCHAR)CharUpper((PTSTR)(*Field))) {
case INFCHAR_PCCARD_ATTR_WAITI:
if (ioWaitState16Index >= PCD_MAX_IO) {
goto clean0;
}
if (++Field < p) {
if (*Field == TEXT('0')) {
Flags &= (ioWaitState16Index++ ? ~fPCD_IO2_WS_16
: ~(fPCD_IO1_WS_16 | fPCD_IO2_WS_16));
} else if (*Field == TEXT('1')) {
Flags |= (ioWaitState16Index++ ? fPCD_IO2_WS_16
: (fPCD_IO1_WS_16 | fPCD_IO2_WS_16));
} else {
goto clean0;
}
}
break;
case INFCHAR_PCCARD_ATTR_WAITM:
if (memWaitIndex >= PCD_MAX_MEMORY) {
goto clean0;
}
if (++Field < p) {
Flags &= (memWaitIndex ? ~mPCD_MEM2_WS
: ~(mPCD_MEM1_WS | mPCD_MEM2_WS));
if (*Field == TEXT('0')) {
memWaitIndex++;
} else if (*Field == TEXT('1')) {
Flags |= (memWaitIndex++ ? fPCD_MEM2_WS_ONE
: (fPCD_MEM1_WS_ONE | fPCD_MEM2_WS_ONE));
} else if (*Field == TEXT('2')) {
Flags |= (memWaitIndex++ ? fPCD_MEM2_WS_TWO
: (fPCD_MEM1_WS_TWO | fPCD_MEM2_WS_TWO));
} else if (*Field == TEXT('3')) {
Flags |= (memWaitIndex++ ? fPCD_MEM2_WS_THREE
: (fPCD_MEM1_WS_THREE | fPCD_MEM2_WS_THREE));
} else {
goto clean0;
}
}
break;
default:
goto clean0;
}
}
break;
case INFCHAR_PCCARD_ATTR_SEP:
break;
default:
// unknown character
goto clean0;
}
if (Field < p) {
Field++;
}
}
}
//
// If we get to here, then we've successfully retrieved all the necessary information
// needed to initialize the PC Card configuration resource descriptor.
//
ZeroMemory(&PcCardResource, sizeof(PcCardResource));
PcCardResource.PcCard_Header.PCD_Count = 1;
PcCardResource.PcCard_Header.PCD_Flags = Flags;
PcCardResource.PcCard_Header.PCD_ConfigIndex = (BYTE)ConfigIndex;
PcCardResource.PcCard_Header.PCD_MemoryCardBase1 = MemoryCardBase[0];
PcCardResource.PcCard_Header.PCD_MemoryCardBase2 = MemoryCardBase[1];
d = CM_Add_Res_Des_Ex(
&ResDes,
LogConfig,
ResType_PcCardConfig,
&PcCardResource,
sizeof(PcCardResource),
0,
hMachine);
d = MapCrToSpError(d, ERROR_INVALID_DATA);
if(d == NO_ERROR) {
CM_Free_Res_Des_Handle(ResDes);
}
clean0:
return d;
}
DWORD
pSetupProcessMfCardConfig(
IN LOG_CONF LogConfig,
IN PINFCONTEXT InfLine,
IN HMACHINE hMachine
)
/*++
Routine Description:
Process a MfCardConfig line in a Win95 INF. Such lines specify
PCMCIA Multifunction card configuration information necessary for a device.
There should normally be one MfCardConfig line per function. Each line is expected
to be in the form:
MfCardConfig = <ConfigRegBase>:<ConfigOptions>[:<IoResourceIndex>][(<attrs>)]
where
<ConfigRegBase> is the attribute offset of this function's
configuration registers
<ConfigOptions> is the 8-bit PCMCIA configuration option register
<IoResourceIndex> is the (optional) index to the Port Io resource descriptor
which will be used to program the configuration I/O base
and limit registers
<attrs> is the optional set of attribute flags which can consist of:
A - Audio enable should be set on in the configuration and status register
All numeric values are assumed to be in hexadecimal format.
Arguments:
Return Value:
--*/
{
MFCARD_RESOURCE MfCardResource;
PCTSTR Field, p;
DWORD ConfigOptions, i;
DWORD ConfigRegisterBase, IoResourceIndex;
DWORD Flags = 0;
DWORD d = NO_ERROR;
RES_DES ResDes;
//
// We should have one field (not counting the line's key)
//
if(SetupGetFieldCount(InfLine) != 1) {
d = ERROR_INVALID_INF_LOGCONFIG;
}
if (d == NO_ERROR) {
//
// Retrieve the ConfigRegisterBase. It must be terminated by a colon.
//
Field = pSetupGetField(InfLine, 1);
p = _tcschr(Field, INFCHAR_PCCARD_SEP);
if(!p || !pHexToUlong(Field, p, &ConfigRegisterBase)) {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
if (d == NO_ERROR) {
//
// Retrieve the ConfigOptions. It may be terminated by either a colon ':',
// an open paren '(', or eol.
//
Field = p + 1;
if(!(p = _tcschr(Field, INFCHAR_PCCARD_SEP)) && !(p = _tcschr(Field, INFCHAR_ATTR_START))) {
p = Field + lstrlen(Field);
}
if(!pHexToUlong(Field, p, &ConfigOptions) || (ConfigOptions > 255)) {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
if ((d == NO_ERROR) && (*p == INFCHAR_PCCARD_SEP)) {
//
// Retrieve the IoResourceIndex. It may be terminated by either
// an open paren '(', or eol.
//
Field = p + 1;
if(!(p = _tcschr(Field, INFCHAR_ATTR_START))) {
p = Field + lstrlen(Field);
}
if(!pHexToUlong(Field, p, &IoResourceIndex) || (IoResourceIndex > 255)) {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
if ((d == NO_ERROR) && (*p == INFCHAR_ATTR_START)) {
//
// Retrieve the attributes.
//
while (TRUE) {
p++;
if (!*p) {
// Didn't find a close paren
d = ERROR_INVALID_INF_LOGCONFIG;
break;
}
if (*p == INFCHAR_ATTR_END) {
if (*(p+1)) {
// found garbage after the close paren
d = ERROR_INVALID_INF_LOGCONFIG;
}
break;
}
if ((TCHAR)CharUpper((PTSTR)*p) == INFCHAR_MFCARD_AUDIO_ATTR) {
Flags |= fPMF_AUDIO_ENABLE;
} else {
// bad flag
d = ERROR_INVALID_INF_LOGCONFIG;
break;
}
}
}
if(d == NO_ERROR) {
//
// If we get to here, then we've successfully retrieved all the necessary information
// needed to initialize the multifunction PC Card configuration resource descriptor.
//
ZeroMemory(&MfCardResource, sizeof(MfCardResource));
MfCardResource.MfCard_Header.PMF_Count = 1;
MfCardResource.MfCard_Header.PMF_Flags = Flags;
MfCardResource.MfCard_Header.PMF_ConfigOptions = (BYTE)ConfigOptions;
MfCardResource.MfCard_Header.PMF_IoResourceIndex = (BYTE)IoResourceIndex;
MfCardResource.MfCard_Header.PMF_ConfigRegisterBase = ConfigRegisterBase;
d = CM_Add_Res_Des_Ex(
&ResDes,
LogConfig,
ResType_MfCardConfig,
&MfCardResource,
sizeof(MfCardResource),
0,
hMachine);
d = MapCrToSpError(d, ERROR_INVALID_DATA);
if(d == NO_ERROR) {
CM_Free_Res_Des_Handle(ResDes);
}
}
return d;
}
#if 0
DWORD
pSetupProcessLogConfigLines(
IN PVOID Inf,
IN PCTSTR SectionName,
IN PCTSTR KeyName,
IN DWORD (*CallbackFunc)(LOG_CONFIG,PINFCONTEXT,HMACHINE),
IN LOG_CONF LogConfig,
IN HMACHINE hMachine
)
{
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, hMachine);
if(d == NO_ERROR) {
b = SetupFindNextMatchLine(&InfLine,KeyName,&InfLine);
}
}
return(d);
}
#endif
DWORD
pSetupProcessConfigPriority(
IN PVOID Inf,
IN PCTSTR SectionName,
IN LOG_CONF LogConfig,
OUT PRIORITY *PriorityValue,
OUT DWORD *ConfigType,
IN DWORD Flags
)
{
INFCONTEXT InfLine;
PCTSTR PrioritySpec;
PCTSTR ConfigSpec;
DWORD d = NO_ERROR;
INT_PTR v;
//
// We only need to fetch one of these lines and look at the
// first value on it.
//
if(SetupFindFirstLine(Inf,SectionName,pszConfigPriority,&InfLine)
&& (PrioritySpec = pSetupGetField(&InfLine,1))) {
if(!LookUpStringInTable(InfPrioritySpecToPriority,PrioritySpec,&v)) {
d = ERROR_INVALID_INF_LOGCONFIG;
} else {
*PriorityValue = (PRIORITY)v;
//
// The second value is optional and specifies whether the config is forced,
// standard (i.e., basic), or override. If the value isn't specified then
// assume basic, unless the Flags tell us otherwise.
//
ConfigSpec = pSetupGetField(&InfLine,2);
if(!ConfigSpec || !*ConfigSpec) {
if(Flags & SPINST_LOGCONFIG_IS_FORCED) {
*ConfigType = FORCED_LOG_CONF;
} else if(Flags & SPINST_LOGCONFIGS_ARE_OVERRIDES) {
*ConfigType = OVERRIDE_LOG_CONF;
} else {
*ConfigType = BASIC_LOG_CONF;
}
} else {
if(LookUpStringInTable(InfConfigSpecToConfig, ConfigSpec, &v)) {
*ConfigType = (DWORD)v;
//
// A valid ConfigType was specified. Let's make sure it doesn't disagree
// with any flags that were passed in to this routine.
//
if(Flags & SPINST_LOGCONFIG_IS_FORCED) {
if(*ConfigType != FORCED_LOG_CONF) {
d = ERROR_INVALID_INF_LOGCONFIG;
}
} else if(Flags & SPINST_LOGCONFIGS_ARE_OVERRIDES) {
if(*ConfigType != OVERRIDE_LOG_CONF) {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
} else {
d = ERROR_INVALID_INF_LOGCONFIG;
}
}
}
//
// If we successfully determined the LogConfig type as FORCED_LOG_CONF, then
// set the priority to LCPRI_FORCECONFIG.
//
if((d == NO_ERROR) && (*ConfigType == FORCED_LOG_CONF)) {
*PriorityValue = LCPRI_FORCECONFIG;
}
} else {
*PriorityValue = (Flags & SPINST_LOGCONFIG_IS_FORCED) ? LCPRI_FORCECONFIG : LCPRI_NORMAL;
if(Flags & SPINST_LOGCONFIG_IS_FORCED) {
*ConfigType = FORCED_LOG_CONF;
} else if(Flags & SPINST_LOGCONFIGS_ARE_OVERRIDES) {
*ConfigType = OVERRIDE_LOG_CONF;
} else {
*ConfigType = BASIC_LOG_CONF;
}
}
return d;
}
DWORD
pSetupProcessLogConfigSection(
IN PVOID Inf,
IN PCTSTR SectionName,
IN DEVINST DevInst,
IN DWORD Flags,
IN HMACHINE hMachine
)
{
DWORD d;
LOG_CONF LogConfig;
PRIORITY Priority;
DWORD ConfigType;
CONFIGRET cr;
DWORD LineIndex = 0;
INFCONTEXT InfLine;
TCHAR Key[MAX_LOGCONFKEYSTR_LEN];
//
// Process config priority values.
//
//
// LogConfig is used before initialized in following call.
// It doesn't matter to function being called, but 6.0 compiler
// doesn't like it, so init to 0.
//
LogConfig = 0;
d = pSetupProcessConfigPriority(Inf,SectionName,LogConfig,&Priority,&ConfigType,Flags);
if(d != NO_ERROR) {
goto c0;
}
//
// Now that we know the priority we can create an empty log config.
//
d = MapCrToSpError(CM_Add_Empty_Log_Conf_Ex(&LogConfig,DevInst,Priority,ConfigType,hMachine),
ERROR_INVALID_DATA
);
if(d != NO_ERROR) {
goto c0;
}
//
// Iterate over the lines in the section adding entries to the log config in
// the same order as they are found.
//
if (SetupFindFirstLine(Inf,SectionName,NULL,&InfLine)) {
do {
//
// Get the key.
//
if (!SetupGetStringField(&InfLine,
0, // Index 0 is the key field
Key,
MAX_LOGCONFKEYSTR_LEN,
NULL
)) {
//
// Either we didn't have a key or its longer than the longest
// valid key - either way its invalid
//
d = ERROR_INVALID_INF_LOGCONFIG;
goto c1;
}
if (!lstrcmpi(Key, pszMemConfig)) {
//
// Process MemConfig lines
//
d = pSetupProcessMemConfig(LogConfig, &InfLine, hMachine);
} else if (!lstrcmpi(Key, pszIOConfig)) {
//
// Process IoConfig lines
//
d = pSetupProcessIoConfig(LogConfig, &InfLine, hMachine);
} else if (!lstrcmpi(Key, pszIRQConfig)) {
//
// Process IRQConfig lines
//
d = pSetupProcessIrqConfig(LogConfig, &InfLine, hMachine);
} else if (!lstrcmpi(Key, pszDMAConfig)) {
//
// Process DMAConfig lines
//
d = pSetupProcessDmaConfig(LogConfig, &InfLine, hMachine);
} else if (!lstrcmpi(Key, pszPcCardConfig)) {
//
// Process PcCardConfig lines
//
d = pSetupProcessPcCardConfig(LogConfig, &InfLine, hMachine);
} else if (!lstrcmpi(Key, pszMfCardConfig)) {
//
// Process MfCardConfig lines
//
d = pSetupProcessMfCardConfig(LogConfig, &InfLine, hMachine);
} else {
//
// If we don't understand the line skip it
//
d = NO_ERROR;
}
} while (d == NO_ERROR && SetupFindNextMatchLine(&InfLine,NULL,&InfLine));
}
#if 0
//
// Process MemConfig lines
//
d = pSetupProcessLogConfigLines(
Inf,
SectionName,
pszMemConfig,
pSetupProcessMemConfig,
LogConfig,
hMachine
);
if(d != NO_ERROR) {
goto c1;
}
//
// Process IOConfig lines
//
d = pSetupProcessLogConfigLines(
Inf,
SectionName,
pszIOConfig,
pSetupProcessIoConfig,
LogConfig,
hMachine
);
if(d != NO_ERROR) {
goto c1;
}
//
// Process IRQConfig lines
//
d = pSetupProcessLogConfigLines(
Inf,
SectionName,
pszIRQConfig,
pSetupProcessIrqConfig,
LogConfig,
hMachine
);
if(d != NO_ERROR) {
goto c1;
}
//
// Process DMAConfig lines
//
d = pSetupProcessLogConfigLines(
Inf,
SectionName,
pszDMAConfig,
pSetupProcessDmaConfig,
LogConfig,
hMachine
);
if(d != NO_ERROR) {
goto c1;
}
//
// Process PcCardConfig lines
//
d = pSetupProcessLogConfigLines(
Inf,
SectionName,
pszPcCardConfig,
pSetupProcessPcCardConfig,
LogConfig,
hMachine
);
#endif
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,
IN DWORD Flags,
IN HMACHINE hMachine
)
/*++
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.
Flags - supplies flags that modify the behavior of this routine. The
following flags are payed attention to, everything else is ignored:
SPINST_SINGLESECTION - if this bit is set, then the specified section
is a LogConf section, instead of an install
section containing LogConf entries.
SPINST_LOGCONFIG_IS_FORCED - if this bit is set, then the LogConfigs
to be written out are forced configs.
If the ConfigType field of the ConfigPriority
entry is present, and specifies something
other than FORCED, this routine will fail
with ERROR_INVALID_INF_LOGCONFIG.
SPINST_LOGCONFIGS_ARE_OVERRIDES - if this bit is set, then the LogConfigs
to be written out are override configs.
If the ConfigType field of the ConfigPriority
entry is present, and specifies something
other than OVERRIDE, this routine will fail
with ERROR_INVALID_INF_LOGCONFIG.
Return Value:
Win32 error code indicating outcome.
--*/
{
INFCONTEXT LineContext;
DWORD rc = NO_ERROR;
DWORD FieldCount;
DWORD Field;
PCTSTR SectionSpec;
if(Flags & SPINST_SINGLESECTION) {
//
// Process the specific LogConf section the caller specified.
//
if(SetupGetLineCount(Inf, SectionName) == -1) {
rc = ERROR_SECTION_NOT_FOUND;
} else {
rc = pSetupProcessLogConfigSection(Inf, SectionName, DevInst, Flags,hMachine);
}
} else {
//
// Find the relevant line in the given install section.
// If not present then we're done with this operation.
//
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,Flags,hMachine);
} else {
rc = ERROR_SECTION_NOT_FOUND;
}
if (rc != NO_ERROR) {
pSetupLogSectionError(Inf,NULL,NULL,NULL,SectionSpec,MSG_LOG_SECT_ERROR,rc,SZ_KEY_LOGCONFIG);
}
}
} while((rc == NO_ERROR) && SetupFindNextMatchLine(&LineContext,SZ_KEY_LOGCONFIG,&LineContext));
}
}
return rc;
}