Esempio n. 1
0
CNdasUnitDevice::CNdasUnitDevice(
	CNdasDevicePtr pParentDevice, 
	DWORD dwUnitNo, 
	NDAS_UNITDEVICE_TYPE type,
	NDAS_UNITDEVICE_SUBTYPE subType,
	const NDAS_UNITDEVICE_HARDWARE_INFO& unitDeviceInfo,
	const NDAS_LOGICALDEVICE_GROUP& ldGroup,
	DWORD ldSequence) :
	CStringizerA<32>("%s.%02d", pParentDevice->ToStringA(), dwUnitNo),
	m_pParentDevice(pParentDevice),
	m_unitDeviceId(pCreateUnitDeviceId(pParentDevice,dwUnitNo)),
	m_type(type),
	m_subType(subType),
	m_status(NDAS_UNITDEVICE_STATUS_NOT_MOUNTED),
	m_lastError(NDAS_UNITDEVICE_ERROR_NONE),
	m_udinfo(unitDeviceInfo),
	m_ldGroup(ldGroup),
	m_ldSequence(ldSequence),
	m_bSupposeFault(FALSE)
{
	XTLTRACE2(NDASSVC_NDASUNITDEVICE, TRACE_LEVEL_INFORMATION,
		__FUNCTION__ " %s\n", ToStringA());

	::ZeroMemory(
		&m_PrimaryHostInfo, 
		sizeof(NDAS_UNITDEVICE_PRIMARY_HOST_INFO));

	COMVERIFY( StringCchPrintf(
		m_szRegContainer,
		30,
		_T("Devices\\%04d\\%04d"),
		pParentDevice->GetSlotNo(),
		m_unitDeviceId.UnitNo));
}
Esempio n. 2
0
CNdasUnitDevicePtr
pGetNdasUnitDevice(const NDAS_DEVICE_ID_EX& device, DWORD unitNo)
{
	CNdasDevicePtr pDevice = pGetNdasDevice(device);
	if (CNdasDeviceNullPtr == pDevice) 
	{
		return CNdasUnitDeviceNullPtr;
	}
	return pDevice->GetUnitDevice(unitNo);
}
Esempio n. 3
0
CNdasUnitDevicePtr 
pGetNdasUnitDevice(DWORD SlotNo, DWORD UnitNo)
{
	CNdasDevicePtr pDevice = pGetNdasDevice(SlotNo);
	if (CNdasDeviceNullPtr == pDevice) 
	{
		return CNdasUnitDeviceNullPtr;
	}
	return pDevice->GetUnitDevice(UnitNo);
}
Esempio n. 4
0
BOOL
CNdasDeviceRegistrar::Unregister(DWORD SlotNo)
{
	InstanceAutoLock autolock(this);

	DeviceSlotMap::iterator slot_itr = m_deviceSlotMap.find(SlotNo);

	if (m_deviceSlotMap.end() == slot_itr) 
	{
		// TODO: Make more specific error code
		::SetLastError(NDASSVC_ERROR_DEVICE_ENTRY_NOT_FOUND);
		return FALSE;
	}

	CNdasDevicePtr pDevice = slot_itr->second;

	if (NDAS_DEVICE_STATUS_DISABLED != pDevice->GetStatus()) 
	{
		// TODO: ::SetLastError(NDAS_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE);
		// TODO: Make more specific error code
		::SetLastError(NDASSVC_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE);
		return FALSE;
	}

	DeviceIdMap::iterator id_itr = m_deviceIdMap.find(pDevice->GetDeviceId());

	XTLASSERT(m_deviceIdMap.end() != id_itr);

	m_deviceIdMap.erase(id_itr);
	m_deviceSlotMap.erase(slot_itr);
	m_slotbit[SlotNo] = FALSE;

	XTL::CStaticStringBuffer<30> containerName(_T("Devices\\%04d"), SlotNo);
	BOOL fSuccess = _NdasSystemCfg.DeleteContainer(containerName, FALSE);
	
	if (!fSuccess) 
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_WARNING,
			"Deleting registration entry from the registry failed at %ls, error=0x%X\n", 
			containerName, GetLastError());
	}

	(void) m_service.GetEventPublisher().DeviceEntryChanged();

	return TRUE;

}
Esempio n. 5
0
VOID 
CNdasAutoRegister::Update(ximeta::CSubject* pChangedSubject)
{
	const CNdasDeviceHeartbeatListener& listener = m_service.GetDeviceHeartbeatListener();
	const CNdasDeviceHeartbeatListener* pListener = &listener;

	//
	// Ignore other than subscribed heartbeat listener
	//

	if (pListener == pChangedSubject) {

		NDAS_DEVICE_HEARTBEAT_DATA hbData;

		pListener->GetHeartbeatData(&hbData);

		NDAS_DEVICE_ID deviceId = {0};
		::CopyMemory(&deviceId, hbData.remoteAddr.Node, sizeof(deviceId));

		ACCESS_MASK autoRegAccess = m_data.GetAutoRegAccess(deviceId);
		if (!autoRegAccess) 
		{
			return;
		}

		//
		// If already registered, do nothing
		//
		CNdasDevicePtr pDevice = pGetNdasDevice(deviceId);
		if (0 != pDevice.get()) 
		{
			return;
		}

		::NdasLogEventInformation(
			EVT_NDASSVC_INFO_AUTOREG_NDAS_DEVICE_FOUND,
			NULL, 
			0, 
			sizeof(deviceId), 
			NULL, 
			&deviceId);
		
		(VOID) AddToQueue(deviceId, autoRegAccess);
	}
}
Esempio n. 6
0
BOOL 
CNdasDeviceRegistrar::Unregister(const NDAS_DEVICE_ID& DeviceId)
{
	InstanceAutoLock autolock(this);

	XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_INFORMATION,
		"Unregister device %s\n", CNdasDeviceId(DeviceId).ToStringA());

	DeviceIdMap::iterator itrId = m_deviceIdMap.find(DeviceId);
	if (m_deviceIdMap.end() == itrId) 
	{
		::SetLastError(NDASSVC_ERROR_DEVICE_ENTRY_NOT_FOUND);
	}

	CNdasDevicePtr pDevice = itrId->second;
	
	if (pDevice->GetStatus() != NDAS_DEVICE_STATUS_DISABLED) 
	{
		::SetLastError(NDASSVC_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE);
		return FALSE;
	}

	DWORD SlotNo = pDevice->GetSlotNo();
	XTLASSERT(0 != SlotNo);

	DeviceSlotMap::iterator itrSlot = m_deviceSlotMap.find(SlotNo);

	m_deviceIdMap.erase(itrId);
	m_deviceSlotMap.erase(itrSlot);
	m_slotbit[SlotNo] = false;

	XTL::CStaticStringBuffer<30> containerName(_T("Devices\\%04d"), SlotNo);
	BOOL fSuccess = _NdasSystemCfg.DeleteContainer(containerName, TRUE);
	if (!fSuccess) 
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_WARNING,
			"Deleting registration entry from the registry failed at %ls, error=0x%X\n", 
			containerName, GetLastError());
	}

	(void) m_service.GetEventPublisher().DeviceEntryChanged();

	return TRUE;
}
Esempio n. 7
0
BOOL
CNdasAutoRegister::ProcessRegister(
	const NDAS_DEVICE_ID& deviceId, 
	ACCESS_MASK autoRegAccess)
{
	CNdasDeviceRegistrar& registrar = m_service.GetDeviceRegistrar();

	CNdasDevicePtr pExistingDevice = registrar.Find(deviceId);
	if (CNdasDeviceNullPtr != pExistingDevice) 
	{
		return TRUE;
	}

	DWORD dwRegFlags = 
		NDAS_DEVICE_REG_FLAG_AUTO_REGISTERED |
		NDAS_DEVICE_REG_FLAG_VOLATILE;

	CNdasDevicePtr pDevice = 
		registrar.Register(deviceId, dwRegFlags);
	if (0 == pDevice.get()) {
		return FALSE;
	}

	pDevice->SetGrantedAccess(autoRegAccess);

	BOOL fSuccess = pDevice->Enable(TRUE);
	if (!fSuccess) {
		DBGPRT_ERR(_FT("Enable failed: "));
	}

	TCHAR szName[MAX_NDAS_DEVICE_NAME_LEN + 1];
	HRESULT hr = ::StringCchPrintf(szName, MAX_NDAS_DEVICE_NAME_LEN + 1,
		_T("NDAS Device A%04d"), pDevice->GetSlotNo());
	XTLASSERT(SUCCEEDED(hr));

	pDevice->SetName(szName);

	return TRUE;
}
Esempio n. 8
0
CNdasDevicePtr
CNdasDeviceRegistrar::Register(
	__in_opt DWORD SlotNo,
	__in const NDAS_DEVICE_ID& DeviceId,
	__in DWORD RegFlags,
	__in_opt const NDASID_EXT_DATA* NdasIdExtension)
{
	//
	// this will lock this class from here
	// and releases the lock when the function returns;
	//
	InstanceAutoLock autolock(this);
	
	XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_INFORMATION,
		"Registering device %s at slot %d\n",
		CNdasDeviceId(DeviceId).ToStringA(), SlotNo);

	if (NULL == NdasIdExtension)
	{
		NdasIdExtension = &NDAS_ID_EXTENSION_DEFAULT;
	}

	//
	// Only DEFAULT and SEAGATE are currently implemented
	//
	if (NDAS_VID_SEAGATE != NdasIdExtension->VID &&
		NDAS_VID_DEFAULT != NdasIdExtension->VID)
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_ERROR,
			"Unknown Vendor ID=0x%02X\n",
			NdasIdExtension->VID);

		::SetLastError(NDASSVC_ERROR_UNKNOWN_VENDOR_ID);
		return CNdasDevicePtr();
	}

	// If SlotNo is zero, automatically assign it.
	// check slot number
	if (0 == SlotNo)
	{
		SlotNo = LookupEmptySlot();
		if (0 == SlotNo)
		{
			return CNdasDevicePtr();
		}
	}
	else if (SlotNo > m_dwMaxSlotNo)
	{
		::SetLastError(NDASSVC_ERROR_INVALID_SLOT_NUMBER);
		return CNdasDevicePtr();
	}

	// check and see if the slot is occupied
	if (m_slotbit[SlotNo])
	{
		::SetLastError(NDASSVC_ERROR_SLOT_ALREADY_OCCUPIED);
		return CNdasDevicePtr();
	}

	// find an duplicate address
	{
		CNdasDevicePtr pExistingDevice = Find(DeviceId);
		if (0 != pExistingDevice.get()) 
		{
			::SetLastError(NDASSVC_ERROR_DUPLICATE_DEVICE_ENTRY);
			return CNdasDevicePtr();
		}
	}

	// register 
	CNdasDevicePtr pDevice(new CNdasDevice(SlotNo, DeviceId, RegFlags, NdasIdExtension));
	if (0 == pDevice.get()) 
	{
		// memory allocation failed
		// No need to set error here!
		return CNdasDevicePtr();
	}

	BOOL fSuccess = pDevice->Initialize();
	if (!fSuccess) 
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_ERROR,
			"Device initialization failed, error=0x%X\n", GetLastError());
		return CNdasDevicePtr();
	}

	m_slotbit[SlotNo] = true;

	bool insertResult;

	XTLVERIFY( m_deviceSlotMap.insert(std::make_pair(SlotNo, pDevice)).second );
	//DeviceSlotMap::value_type(SlotNo, pDevice)).second;

	XTLVERIFY( m_deviceIdMap.insert(std::make_pair(DeviceId, pDevice)).second );
	//DeviceIdMap::value_type(DeviceId, pDevice)).second;

	XTLASSERT(m_deviceSlotMap.size() == m_deviceIdMap.size());

	//
	// When NdasIdExtension is NULL, NDAS_ID_EXTENSION_DEFAULT is assigned already
	//

	if (RegFlags & NDAS_DEVICE_REG_FLAG_VOLATILE)
	{
	}
	else
	{
		XTL::CStaticStringBuffer<30> containerName(_T("Devices\\%04d"), SlotNo);

		if (0 != memcmp(&NDAS_ID_EXTENSION_DEFAULT, NdasIdExtension, sizeof(NDASID_EXT_DATA)))
		{
			NDAS_DEVICE_ID_REG_DATA regData = {0};
			regData.DeviceId = DeviceId;
			regData.NdasIdExtension = *NdasIdExtension;

			fSuccess = _NdasSystemCfg.SetSecureValueEx(
				containerName, 
				_T("DeviceID2"), 
				&regData, 
				sizeof(regData));
		}
		else
		{
			fSuccess = _NdasSystemCfg.SetSecureValueEx(
				containerName, 
				_T("DeviceID"), 
				&DeviceId, 
				sizeof(DeviceId));
		}

		if (!fSuccess) 
		{
			XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_WARNING,
				"Writing registration entry to the registry failed at %ls, error=0x%X\n", 
				containerName.ToString(), GetLastError());
		}

		fSuccess = _NdasSystemCfg.SetSecureValueEx(
			containerName,
			_T("RegFlags"),
			&RegFlags,
			sizeof(RegFlags));

		if (!fSuccess) 
		{
			XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_WARNING,
				"Writing registration entry to the registry failed at %ls, error=0x%X\n", 
				containerName.ToString(), GetLastError());
		}
	}

	//
	// During bootstrapping, we do not publish this event
	// Bootstrap process will publish an event later
	//
	if (!m_fBootstrapping) 
	{
		(void) m_service.GetEventPublisher().DeviceEntryChanged();
	}

	return pDevice;
}
Esempio n. 9
0
BOOL
CNdasDeviceRegistrar::Bootstrap()
{
	BOOL fSuccess = FALSE;
	BOOL fMigrated = FALSE;

	//
	// Set bootstrapping flag to prevent multiple events 
	// for DeviceSetChange Events
	//

	m_fBootstrapping = TRUE;

	TCHAR szSubcontainer[30] = {0};
	for (DWORD i = 0; i < MAX_SLOT_NUMBER; ++i) 
	{
		COMVERIFY(StringCchPrintf(
			szSubcontainer, 30, _T("%s\\%04d"), CFG_CONTAINER, i));

		BOOL fAutoRegistered = FALSE;
		fSuccess = _NdasSystemCfg.GetValueEx(
			szSubcontainer,
			_T("AutoRegistered"),
			&fAutoRegistered);

		if (fSuccess && fAutoRegistered)
		{
			XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_INFORMATION,
				"Deleting %ls\n", szSubcontainer);
			// Auto registered devices are not persistent
			// it is an error to show up here.
			// We just ignore those entries
			fSuccess = _NdasSystemCfg.DeleteContainer(szSubcontainer, TRUE);
			if (!fSuccess)
			{
				XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_INFORMATION,
					"Deleting a RegKey=%ls failed, error=0x%X\n", 
					szSubcontainer, GetLastError());
			}
			continue;
		}

		DWORD cbUsed;

		NDAS_DEVICE_ID_REG_DATA regData = {0};
		const NDASID_EXT_DATA* ndasIdExtension = NULL;

		fSuccess = _NdasSystemCfg.GetSecureValueEx(
			szSubcontainer, 
			_T("DeviceID2"),
			&regData,
			sizeof(NDAS_DEVICE_ID_REG_DATA),
			&cbUsed);

		if (!fSuccess) 
		{
			//
			// Non-extension data
			//
			fSuccess = _NdasSystemCfg.GetSecureValueEx(
				szSubcontainer, 
				_T("DeviceID"),
				&regData.DeviceId,
				sizeof(regData.DeviceId),
				&cbUsed);

			//
			// ignore read fault - tampered or not exists
			//
			if (!fSuccess || cbUsed != sizeof(NDAS_DEVICE_ID))
			{
				continue;
			}
			if (regData.DeviceId.VID == 0) {
				// Assume VID 0 is VID 1 to support registry entry created by older software(~3.11)
				regData.DeviceId.VID = 1;
			}
		}
		else
		{
			if (cbUsed != sizeof(NDAS_DEVICE_ID_REG_DATA))
			{
				//
				// maybe more recent versions, unrecognized, ignore
				//
				continue;
			}
			ndasIdExtension = &regData.NdasIdExtension;
		}

		DWORD regFlags;
		fSuccess = _NdasSystemCfg.GetSecureValueEx(
			szSubcontainer,
			_T("RegFlags"),
			&regFlags,
			sizeof(regFlags));

		if (!fSuccess)
		{
			regFlags = NDAS_DEVICE_REG_FLAG_NONE;
		}

		CNdasDevicePtr pDevice = Register(
			i, 
			regData.DeviceId, 
			regFlags,
			ndasIdExtension);

		// This may happen due to auto-register feature!
		if (CNdasDeviceNullPtr == pDevice) 
		{
			XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_ERROR,
				"Registration failed for %s, error=0x%X\n",
				CNdasDeviceId(regData.DeviceId).ToStringA(),
				GetLastError());
			//
			// During bootstrapping register may fail for unsupported VID.
			// In that case, we should retain this slot number to avoid
			// overwriting the existing data which may be created by
			// the higher version.
			//
			m_slotbit[i] = true;
			continue;
		}

		NDAS_OEM_CODE oemCode;
		fSuccess = _NdasSystemCfg.GetSecureValueEx(
			szSubcontainer,
			_T("OEMCode"),
			&oemCode,
			sizeof(NDAS_OEM_CODE),
			&cbUsed);

		if (fSuccess && cbUsed == sizeof(NDAS_OEM_CODE))
		{
			pDevice->SetOemCode(oemCode);
		}

		ACCESS_MASK grantedAccess = GENERIC_READ;
		const DWORD cbBuffer = sizeof(ACCESS_MASK) + sizeof(NDAS_DEVICE_ID);
		BYTE pbBuffer[cbBuffer];
		
		fSuccess = _NdasSystemCfg.GetSecureValueEx(
			szSubcontainer,
			_T("GrantedAccess"),
			pbBuffer,
			cbBuffer);

		if (fSuccess) 
		{
			grantedAccess = *((ACCESS_MASK*)(pbBuffer));
		}
		grantedAccess |= GENERIC_READ; // to prevent invalid access mask configuration
		// XTLASSERT(grantedAccess & GENERIC_READ); // invalid configuration?
		pDevice->SetGrantedAccess(grantedAccess);

		TCHAR szDeviceName[MAX_NDAS_DEVICE_NAME_LEN + 1];
		fSuccess = _NdasSystemCfg.GetValueEx(
			szSubcontainer, 
			_T("DeviceName"),
			szDeviceName,
			sizeof(TCHAR)*(MAX_NDAS_DEVICE_NAME_LEN + 1));

		if (fSuccess) 
		{
			pDevice->SetName(szDeviceName);
		}

		BOOL fEnabled = FALSE;
		fSuccess = _NdasSystemCfg.GetValueEx(
			szSubcontainer,
			_T("Enabled"),
			&fEnabled);

		if (fSuccess && fEnabled) 
		{
			pDevice->Enable(fEnabled);
		}
	}

	//
	// Migration will be done only once 
	// if there is no registered devices in the current configurations
	// and if the migration flag (Install\Migrate = 1) is set
	//
	if (m_deviceSlotMap.size() == 0) 
	{
		fSuccess = _NdasSystemCfg.GetValueEx(_T("Install"), _T("Migrated"), &fMigrated);
		if (!fSuccess || !fMigrated) 
		{
			fMigrated = TRUE;
			ImportLegacySettings();
			_NdasSystemCfg.SetValueEx(_T("Install"), _T("Migrated"), fMigrated);
		}
	}

	//
	// Clear bootstrapping state
	//
	m_fBootstrapping = FALSE;

	return TRUE;
}
Esempio n. 10
0
BOOL
CNdasDeviceRegistrar::ImportLegacyEntry(DWORD SlotNo, HKEY hEntryKey)
{
	static CONST size_t CB_ADDR = sizeof(TCHAR) * 18;

	HRESULT hr = E_FAIL;
	TCHAR szAddrVal[CB_ADDR + 1];
	DWORD cbAddrVal = sizeof(szAddrVal);
	DWORD dwValueType;

	LONG lResult = ::RegQueryValueEx(
		hEntryKey, 
		_T("Address"), 
		0, 
		&dwValueType, 
		(LPBYTE)szAddrVal,
		&cbAddrVal);

	if (ERROR_SUCCESS != lResult) 
	{
		// Ignore invalid values
		return FALSE;
	}

	if (cbAddrVal != CB_ADDR) 
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_ERROR,
			"Invalid Entry(A): %ls, ignored\n", szAddrVal);
		return FALSE;
	}

	//
	// 00:0B:D0:00:D4:2F to NDAS_DEVICE_ID
	//

	NDAS_DEVICE_ID deviceId = {0};
	BOOL fSuccess = pConvertStringToDeviceId(szAddrVal, &deviceId);
	if (!fSuccess) 
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_ERROR,
			"Invalid Entry(D): %ls, ignored\n", szAddrVal);
		return FALSE;
	}

	XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_INFORMATION,
		"Importing an entry: %s\n", 
		CNdasDeviceId(deviceId).ToStringA());

	TCHAR szNameVal[MAX_NDAS_DEVICE_NAME_LEN + 1] = {0};
	DWORD cbNameVal = sizeof(szNameVal);
	lResult = ::RegQueryValueEx(
		hEntryKey,
		_T("Name"),
		0,
		&dwValueType,
		(LPBYTE)szNameVal,
		&cbNameVal);

	if (ERROR_SUCCESS != lResult || _T('\0') == szNameVal[0]) 
	{
		TCHAR szDefaultName[MAX_NDAS_DEVICE_NAME_LEN + 1] = {0};
		fSuccess = _NdasSystemCfg.GetValueEx(
			_T("Devices"), 
			_T("DefaultPrefix"),
			szDefaultName,
			sizeof(szDefaultName));

		if (!fSuccess) 
		{
			COMVERIFY( StringCchCopy(
				szDefaultName, 
				MAX_NDAS_DEVICE_NAME_LEN + 1,
				_T("NDAS Device ")) );
		}

		hr = ::StringCchPrintf(
			szNameVal,
			MAX_NDAS_DEVICE_NAME_LEN,
			_T("%s %d"), 
			szDefaultName, 
			SlotNo);
	}


	BYTE pbSerialKeyVal[9];
	DWORD cbSerialKeyVal = sizeof(pbSerialKeyVal);
	lResult = ::RegQueryValueEx(
		hEntryKey,
		_T("SerialKey"),
		0,
		&dwValueType,
		(LPBYTE)pbSerialKeyVal,
		&cbSerialKeyVal);

	if (ERROR_SUCCESS != lResult) 
	{
		return FALSE;
	}

	if (cbSerialKeyVal != sizeof(pbSerialKeyVal)) 
	{
		return FALSE;
	}

	ACCESS_MASK fAccessMode = GENERIC_READ;
	if (0xFF == pbSerialKeyVal[8]) 
	{
		// Registered as RW
		fAccessMode |= GENERIC_WRITE;
	}
	else if (0x00 == pbSerialKeyVal[8]) 
	{
		// Registered as RO
	}
	else 
	{
		// Invalid value
		return FALSE;
	}

	CNdasDevicePtr pDevice = Register(SlotNo, deviceId, 0, NULL);
	if (0 == pDevice.get()) 
	{
		XTLTRACE2(NDASSVC_NDASDEVICEREGISTRAR, TRACE_LEVEL_ERROR,
			"Failed to register %s at %d during import, error=0x%X",
			CNdasDeviceId(deviceId).ToStringA(), SlotNo, GetLastError());
		return FALSE;
	}

	// Always enable this!
	XTLVERIFY( pDevice->Enable(TRUE) );
	pDevice->SetName(szNameVal);
	pDevice->SetGrantedAccess(fAccessMode);

	return TRUE;
}