bool SMBIOSResolver::start(IOService * provider)
{
	if( super::start(provider) != true ) return false;	// Oh no	
	if( IOService::getResourceService()->getProperty("SMBIOS-Resolver") ) return false;	// We should exist only once	
	if( !IOService::getResourceService()->getProperty("SMBIOS") ) return false;	// AppleSMBIOS.kext didn´t start we bail out
	
	IOService * iosRoot = getServiceRoot();
	if( !iosRoot ) return false;	// Unable to get IOServiceRoot
	
	int doVerbose = 0;
	// PE_parse_boot_arg("smbios", &doVerbose);	// bootarg SMBIOS=1 will give a verbose output to log (when I find something verbose worth outputting)
	
	// Dictionary from plist
	OSDictionary * hwDict = OSDynamicCast( OSDictionary, getProperty("Override"));
	
	//	/rom/version
	IORegistryEntry * dtROMNode = fromPath("/rom", gIODTPlane);
	if( dtROMNode )
	{
		OSString * romVersion = OSDynamicCast( OSString, hwDict->getObject("rom-version"));
		if(romVersion->getLength() > 0) dtROMNode->setProperty("version", OSData::withBytes(romVersion->getCStringNoCopy(), romVersion->getLength() + 1) );
		dtROMNode->release();
	}
	else
	{
		return false;	// No /rom node in IODeviceTree plane
	}
	
	// root entries
	OSObject * dictString = 0;
	
	dictString = hwDict->getObject("manufacturer");
	if(dictString)
	{
		OSString * rootManufacturer = OSDynamicCast( OSString, dictString);
		if(rootManufacturer->getLength() > 1) iosRoot->setProperty("manufacturer", OSData::withBytes(rootManufacturer->getCStringNoCopy(), rootManufacturer->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("system-type");
	if(dictString)
	{
		OSData * systemType = OSDynamicCast( OSData, dictString);
		if(systemType) iosRoot->setProperty("system-type", systemType );
	}
	
	dictString = hwDict->getObject("compatible");
	if(dictString) 
	{
		OSString * rootCompatible = OSDynamicCast( OSString, dictString);
		if(rootCompatible->getLength() > 1) iosRoot->setProperty("compatible", OSData::withBytes(rootCompatible->getCStringNoCopy(), rootCompatible->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("product-name");
	if(dictString) 
	{
		OSString * rootProductName = OSDynamicCast( OSString, dictString);
		if(rootProductName->getLength() > 1) iosRoot->setProperty("product-name", OSData::withBytes(rootProductName->getCStringNoCopy(), rootProductName->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("model");
	if(dictString) 
	{
		OSString * rootModel = OSDynamicCast( OSString, dictString);
		if(rootModel->getLength() > 1)
		{
			iosRoot->setProperty("model", OSData::withBytes(rootModel->getCStringNoCopy(), rootModel->getLength() + 1) );
			iosRoot->setName(rootModel->getCStringNoCopy());
		}
	}
	
	dictString = hwDict->getObject("version");
	if(dictString) 
	{
		OSString * rootVersion = OSDynamicCast( OSString, dictString);
		if(rootVersion->getLength() > 1) iosRoot->setProperty("version", OSData::withBytes(rootVersion->getCStringNoCopy(), rootVersion->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("board-id");
	if(dictString) 
	{
		OSString * rootBoardId = OSDynamicCast( OSString, dictString);
		if(rootBoardId->getLength() > 1) iosRoot->setProperty("board-id", OSData::withBytes(rootBoardId->getCStringNoCopy(), rootBoardId->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("serial-number");
	if(dictString) 
	{
		OSString * rootSerial = OSDynamicCast( OSString, dictString);
		if(rootSerial->getLength() > 1)
		{
			UInt8 length = rootSerial->getLength();
			const char *serialNumberString = rootSerial->getCStringNoCopy();
			
			// The serial-number property in the IORegistry is a 43-byte data object.
			// Bytes 0 through 2 are the last three bytes of the serial number string.
			// Bytes 11 through 20, inclusive, are the serial number string itself.
			// All other bytes are '\0'.
			OSData * data = OSData::withCapacity(43);
			if (data)
			{
				data->appendBytes(serialNumberString + (length - 3), 3);
				data->appendBytes(NULL, 10);
				data->appendBytes(serialNumberString, length);
				data->appendBytes(NULL, 43 - length - 10 - 3);
				iosRoot->setProperty("serial-number", data);
				data->release();
			}
			
			iosRoot->setProperty(kIOPlatformSerialNumberKey, rootSerial);
		}
	}
	
	dictString = hwDict->getObject("UUID-key");
	if(dictString) 
	{
		OSString * rootUUIDKey = OSDynamicCast( OSString, hwDict->getObject("UUID-key"));
		iosRoot->setProperty(kIOPlatformUUIDKey, rootUUIDKey);
		publishResource(kIOPlatformUUIDKey, rootUUIDKey);
	}
	
	bool useEfiBus = false;
	UInt64 fsbFrequency = 0;
	UInt64 msr;
	dictString = hwDict->getObject("use-efi-bus");
	if (dictString) useEfiBus = (OSDynamicCast(OSBoolean, dictString))->getValue(); 
	IORegistryEntry * efiPlatform = fromPath("/efi/platform", gIODTPlane);
	if (efiPlatform && useEfiBus)
	{
		OSData * efiFSBFreq = OSDynamicCast(OSData, efiPlatform->getProperty("FSBFrequency"));
		bcopy(efiFSBFreq->getBytesNoCopy(), &fsbFrequency, efiFSBFreq->getLength());
		efiPlatform->release();
	}
	else
	{	// No /efi/platform found
		fsbFrequency = gPEClockFrequencyInfo.bus_frequency_hz;	// Value previously set by AppleSMBIOS 
		if (!strncmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)) && (cpuid_info()->cpuid_features & CPUID_FEATURE_SSE2)) fsbFrequency /= 4;
	}

	dictString = hwDict->getObject("hardcode-bus");
	if(dictString) 
	{
		fsbFrequency = (OSDynamicCast(OSNumber, dictString))->unsigned64BitValue();
		if (fsbFrequency)
		{
			if (fsbFrequency <= 10000) fsbFrequency *= 1000000;
		}
		else
		{
			if (!strncmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)))
			{
				if ((cpuid_info()->cpuid_family == 0x0f) && (cpuid_info()->cpuid_model >= 2))
				{
					msr = rdmsr64(0x0000002C);
					switch ((msr >> 16) & 0x7) {
						case 0:
							if (cpuid_info()->cpuid_model == 2) fsbFrequency = 100 * 1000000;
							else 
							{
								fsbFrequency = (800 * 1000000) / 3;	// 266
								fsbFrequency++;
							}
							break;
						case 1:
							fsbFrequency = (400 * 1000000) / 3;	//	133
							break;
						case 2:
							fsbFrequency = (600 * 1000000) / 3;	// 200
							break;
						case 3:
							fsbFrequency = (500 * 1000000) / 3;	//	166
							fsbFrequency++;
							break;
						case 4:
							fsbFrequency = (1000 * 1000000) / 3;	//	333
							break;
						default:
							break;
					}
				}
				else
				{
					fsbFrequency = 100 * 1000000;
				}
				
				if (cpuid_info()->cpuid_family == 0x06)
				{
					msr = rdmsr64(0x000000CD);
					switch (msr & 0x7) {
						case 0:
							fsbFrequency = (800 * 1000000) / 3;	//	266
							fsbFrequency++;
							break;
						case 1:
							fsbFrequency = (400 * 1000000) / 3;	//	133
							break;
						case 2:
							fsbFrequency = (600 * 1000000) / 3;	//	200
							break;
						case 3:
							fsbFrequency = (500 * 1000000) / 3;	//	166
							fsbFrequency++;
							break;
						case 4:
							fsbFrequency = (1000 * 1000000) / 3;//	333
							break;
						case 5:
							fsbFrequency = (300 * 1000000) / 3;	//	100
							break;
						case 6:
							fsbFrequency = (1200 * 1000000) / 3;//	400
							break;
						case 7:		// should check
							fsbFrequency = (1400 * 1000000) / 3;//	466
							fsbFrequency++;
							break;
						default:
							break;
					}
				}
				 
			}
		}
Exemple #2
0
bool IT87x::startPlugin()
{
	DebugLog("starting...");

	
	InfoLog("found ITE %s", getModelName());
    OSDictionary* list = OSDynamicCast(OSDictionary, getProperty("Sensors Configuration"));
    IOService * fRoot = getServiceRoot();
    OSString *vendor=NULL, *product=NULL;
    OSDictionary *configuration=NULL; 
    
    
    if(fRoot)
    {
        vendor = vendorID( OSDynamicCast(OSString, fRoot->getProperty("oem-mb-manufacturer") ? fRoot->getProperty("oem-mb-manufacturer") :  (fRoot->getProperty("oem-manufacturer") ? fRoot->getProperty("oem-manufacturer") : NULL)));
        product = OSDynamicCast(OSString, fRoot->getProperty("oem-mb-product") ? fRoot->getProperty("oem-mb-product") :  (fRoot->getProperty("oem-product-name") ? fRoot->getProperty("oem-product-name") : NULL));
        
    }
    if (vendor)
        if (OSDictionary *link = OSDynamicCast(OSDictionary, list->getObject(vendor)))
            if(product)
                configuration = OSDynamicCast(OSDictionary, link->getObject(product));

    
    if (list && !configuration) 
        configuration = OSDynamicCast(OSDictionary, list->getObject("Default"));
    
    if(configuration)
        this->setProperty("Current Configuration", configuration);
	
	// Temperature Sensors
	if (configuration) {
		for (int i = 0; i < 3; i++) 
		{				
			char key[8];
			
			snprintf(key, 8, "TEMPIN%X", i);
            if(readTemperature(i)<MAX_TEMP_THRESHOLD)  // Need to check if temperature sensor valid
    			if (OSString* name = OSDynamicCast(OSString, configuration->getObject(key)))
                    if (name->isEqualTo("CPU")) {
                        if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, i))
                            WarningLog("error adding heatsink temperature sensor");
                    }
                    else if (name->isEqualTo("System")) {				
                        if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor,i))
                            WarningLog("error adding system temperature sensor");
                    }
                    else if (name->isEqualTo("Ambient")) {				
                        if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor,i))
                            WarningLog("error adding Ambient temperature sensor");
				}
		}
	}
	else {
        if(readTemperature(0)<MAX_TEMP_THRESHOLD)  // Need to check if temperature sensor valid
             if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 0))
                 WarningLog("error adding heatsink temperature sensor");
        if(readTemperature(1)<MAX_TEMP_THRESHOLD)  // Need to check if temperature sensor valid
            if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 1))
                WarningLog("error adding Ambient temperature sensor");
        if(readTemperature(2)<MAX_TEMP_THRESHOLD)  // Need to check if temperature sensor valid
            if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 2))
                WarningLog("error adding system temperature sensor");
	}
	
	
	// Voltage
    UInt8 tmp = readByte(address, ITE_ADC_CHANNEL_ENABLE);
    DebugLog("ADC Enable register = %X",tmp);
    
    vbat_updates=false;
    if(configuration)
    {
        if(OSBoolean* smartGuard=OSDynamicCast(OSBoolean, configuration->getObject("VBATNeedUpdates")))
            if(smartGuard->isTrue())
                vbat_updates=true;
        
    }
    // Refresh VBAT reading on each access to the key
    if(vbat_updates)
        writeByte(address, ITE_CONFIGURATION_REGISTER, readByte(address, ITE_CONFIGURATION_REGISTER) | 0x40);
    
	if (configuration) {
		for (int i = 0; i < 9; i++) 
		{				
			char key[5];
            OSString * name;
            long Ri=0;
            long Rf=1;
            long Vf=0;
			
			snprintf(key, 5, "VIN%X", i);
			
			if (process_sensor_entry(configuration->getObject(key), &name, &Ri, &Rf, &Vf)) {
				if (name->isEqualTo("CPU")) {
					if (!addSensor(KEY_CPU_VRM_SUPPLY0, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf))
						WarningLog("error adding CPU voltage sensor");
				}
				else if (name->isEqualTo("Memory")) {
					if (!addSensor(KEY_MEMORY_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf))
						WarningLog("error adding memory voltage sensor");
				}
                else if (name->isEqualTo("+5VC")) {  
                    if (!addSensor(KEY_5VC_VOLTAGE, TYPE_FP4C, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding AVCC Voltage Sensor!");
                    }
                }
                else if (name->isEqualTo("+5VSB")) {  
                    if (!addSensor(KEY_5VSB_VOLTAGE, TYPE_FP4C, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding AVCC Voltage Sensor!");
                    }
                }                
                else if (name->isEqualTo("+12VC")) {
                    if (!addSensor(KEY_12V_VOLTAGE, TYPE_FP4C, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding 12V Voltage Sensor!");
                    }
                }
                else if (name->isEqualTo("-12VC")) {
                    if (!addSensor(KEY_N12VC_VOLTAGE, TYPE_FP4C, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding 12V Voltage Sensor!");
                    }
                }
                else if (name->isEqualTo("3VCC")) {
                    if (!addSensor(KEY_3VCC_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding 3VCC Voltage Sensor!");
                    }
                }
                
                else if (name->isEqualTo("3VSB")) {
                    if (!addSensor(KEY_3VSB_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding 3VSB Voltage Sensor!");
                    }
                }
                else if (name->isEqualTo("VBAT")) {
                    if (!addSensor(KEY_VBAT_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) {
                        WarningLog("ERROR Adding VBAT Voltage Sensor!");
                    }
                }
			}
		}
	}
	
	// Tachometers
	for (int i = 0; i < 5; i++) {
		OSString* name = NULL;
		char key[5];
		if (configuration) {
			char key_temp[7];
			
			snprintf(key_temp, 7, "FANIN%X", i);
			
			name = OSDynamicCast(OSString, configuration->getObject(key_temp));
		}
		
		UInt32 nameLength = name ? (UInt32)strlen(name->getCStringNoCopy()) : 0;
		
		if (readTachometer(i) > 10 || nameLength > 0)
            // Pff WTF ??? Add tachometer if it doesn't exist in a system but only the name defined in the config???   
        {
            
			if (!addTachometer(i, (nameLength > 0 ? name->getCStringNoCopy() : 0)))
                // Need to look at this a bit later
				WarningLog("error adding tachometer sensor %d", i);
            
            
            
        }
        
        // Check if this chip support SmartGuardian feature  
        
        hasSmartGuardian=false;
        if(configuration)
        {
            if(OSBoolean* smartGuard=OSDynamicCast(OSBoolean, configuration->getObject("SmartGuardian")))
                if(smartGuard->isTrue())
                    hasSmartGuardian=true;
            
        }
        
        if(hasSmartGuardian)
        {
            // Ugly development hack started for (SuperIOSensorGroup)
            snprintf(key,5,KEY_FORMAT_FAN_TARGET_SPEED,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardPWMControl, i))
                WarningLog("error adding PWM fan control");
            
            snprintf(key,5,KEY_FORMAT_FAN_START_TEMP,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanStart, i))
                WarningLog("error adding start temp fan control");
            
            snprintf(key,5,KEY_FORMAT_FAN_OFF_TEMP,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanStop, i))
                WarningLog("error adding stop temp fan control");
            
            snprintf(key,5,KEY_FORMAT_FAN_FULL_TEMP,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanFullOn, i))
                WarningLog("error adding full speed temp fan control");
            
            snprintf(key,5,KEY_FORMAT_FAN_START_PWM,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardPWMStart, i))
                WarningLog("error adding start PWM fan control");
            
            snprintf(key,5,KEY_FORMAT_FAN_TEMP_DELTA,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanFullOff, i))
                WarningLog("error adding temp full off fan control");
            
            snprintf(key,5,KEY_FORMAT_FAN_CONTROL,i);
            if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanControl, i))
                WarningLog("error adding register fan control");
        }
	}
     if(hasSmartGuardian)
     {
         
         if (!addSensor(KEY_FORMAT_FAN_MAIN_CONTROL, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardMainControl, 0))
             WarningLog("error adding Main fan control"); 
         if (!addSensor(KEY_FORMAT_FAN_REG_CONTROL, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardRegControl, 0))
             WarningLog("error adding Main fan control"); 
     }
	
	return true;	
}
Exemple #3
0
bool Andigilog::start(IOService *provider)
{
    int i;
    bool res;
    UInt8 cmd, data, addrs[] = ASC7621_ADDRS;
    /* Mapping common for Intel boards */
    struct MList list[] = {
        { ASC7621_TEMP1H, ASC7621_TEMP1L, {"TC0D",TYPE_SP78,2,-1}, -1, 0, true },
        { ASC7621_TEMP2H, ASC7621_TEMP2L, {KEY_AMBIENT_TEMPERATURE,TYPE_SP78,2,-1}, -1, 0, true },
        { ASC7621_TEMP3H, ASC7621_TEMP3L, {KEY_DIMM_TEMPERATURE,TYPE_SP78,2,-1}, -1, 0, true },
        { ASC7621_TEMP4H, ASC7621_TEMP4L, {KEY_CPU_HEATSINK_TEMPERATURE,TYPE_SP78,2,-1}, -1, 0, true },
        
        { ASC7621_TACH1L, ASC7621_TACH1H, {"Fan 1",TYPE_FPE2,2,0}, true, 0, true },
        { ASC7621_TACH2L, ASC7621_TACH2H, {"Fan 2",TYPE_FPE2,2,1}, true, 0, true },
        { ASC7621_TACH3L, ASC7621_TACH3H, {"Fan 3",TYPE_FPE2,2,2}, true, 0, true },
        { ASC7621_TACH4L, ASC7621_TACH4H, {"Fan 4",TYPE_FPE2,2,2}, true, 0, true }
    };
    struct PList pwm[] = {
        { ASC7621_PWM1R, 0, -2 },
        { ASC7621_PWM2R, 0, -2 },
        { ASC7621_PWM3R, 0, -2 },
    };

    OSDictionary *conf = NULL, *sconf = OSDynamicCast(OSDictionary, getProperty("Sensors Configuration")), *dict;
    IOService *fRoot = getServiceRoot();
    OSString *str, *vendor = NULL;
    char *key;
    char tempkey[] = "_temp ", /* Ugly hack to keep keys in order for auto-generated plist */
    fankey[] = "tach ";

    
    res = super::start(provider);
    DbgPrint("start\n");
    
    if (!(i2cNub = OSDynamicCast(I2CDevice, provider))) {
        IOPrint("Failed to cast provider\n");
        return false;
    }
    
    i2cNub->retain();
    i2cNub->open(this);
    
    for (i = 0; i < sizeof(addrs) / sizeof(addrs[0]); i++)
        if (!i2cNub->ReadI2CBus(addrs[i], &(cmd = ASC7621_VID_REG), sizeof(cmd), &data,
                            sizeof(data)) && data == ASC7621_VID &&
            !i2cNub->ReadI2CBus(addrs[i], &(cmd = ASC7621_PID_REG), sizeof(cmd), &data,
                            sizeof(data)) && (data == ASC7621_PID || data == ASC7621A_PID)) {
                Asc7621_addr = addrs[i];
                IOPrint("aSC7621 attached at 0x%x.\n", Asc7621_addr);
                break;
            }
    if (!Asc7621_addr) {
        IOPrint("Device matching failed.\n");
        return false;
    }
    
    memcpy(&Measures, &list, sizeof(Measures));
    memcpy(&Pwm, &pwm, sizeof(Pwm));
    
    if (fRoot) {
        vendor = vendorID(OSDynamicCast(OSString, fRoot->getProperty("oem-mb-manufacturer") ?
                                        fRoot->getProperty("oem-mb-manufacturer") :
                                        (fRoot->getProperty("oem-manufacturer") ?
                                         fRoot->getProperty("oem-manufacturer") : NULL)));
        str = OSDynamicCast(OSString, fRoot->getProperty("oem-mb-product") ?
                            fRoot->getProperty("oem-mb-product") :
                            (fRoot->getProperty("oem-product-name") ?
                             fRoot->getProperty("oem-product-name") : NULL));
    }
    if (vendor)
        if (OSDictionary *link = OSDynamicCast(OSDictionary, sconf->getObject(vendor)))
            if(str)
                conf = OSDynamicCast(OSDictionary, link->getObject(str));
    if (sconf && !conf)
        conf = OSDynamicCast(OSDictionary, sconf->getObject("Active"));
    i = 0;
    for (int s = 0, j = 0, k = 0; i < NUM_SENSORS; i++) {
        if (conf) {
                if (Measures[i].fan < 0) {
                    snprintf(&tempkey[5], 2, "%d", j++);
                    key = tempkey;
                } else {
                    snprintf(&fankey[4], 2, "%d", k++);
                    key = fankey;
                }
                if ((dict = OSDynamicCast(OSDictionary, conf->getObject(key)))) {
                    str = OSDynamicCast(OSString, dict->getObject("id"));
                    memcpy(Measures[i].hwsensor.key, str->getCStringNoCopy(), str->getLength()+1);
                    if (Measures[i].fan > -1)
                        Measures[i].hwsensor.pwm = ((OSNumber *)OSDynamicCast(OSNumber, dict->getObject("pwm")))->
                        unsigned8BitValue();
                    Measures[i].hwsensor.size = ((OSNumber *)OSDynamicCast(OSNumber, dict->getObject("size")))->
                    unsigned8BitValue();
                    str = OSDynamicCast(OSString, dict->getObject("type"));
                    memcpy(Measures[i].hwsensor.type, str->getCStringNoCopy(), str->getLength()+1);
                }
        }
        if (Measures[i].hwsensor.key[0]) {
            if (Measures[i].fan < 0) {
                addSensor(Measures[i].hwsensor.key, Measures[i].hwsensor.type,
                          Measures[i].hwsensor.size, s);
                s++;
            } else {
                if (!config.start_fan)
                    config.start_fan = i;
                addTachometer(&Measures[i], Measures[i].fan = config.num_fan);
                config.num_fan++;
            }
        }
    }
    config.num_fan++;
    addKey(KEY_FAN_FORCE, TYPE_UI16, 2, 0);
  
    GetConf();
        
    return res;
}