/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.chipset.i440BX;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import javax.naming.NameNotFoundException;
import org.apache.log4j.Logger;
import org.jnode.driver.DeviceUtils;
import org.jnode.driver.DriverException;
import org.jnode.driver.bus.pci.PCIDevice;
import org.jnode.driver.bus.smbus.DIMM;
import org.jnode.driver.bus.smbus.DIMMDriver;
import org.jnode.driver.bus.smbus.SMBus;
import org.jnode.driver.bus.smbus.SMBusControler;
import org.jnode.naming.InitialNaming;
import org.jnode.system.resource.IOResource;
import org.jnode.system.resource.ResourceManager;
import org.jnode.system.resource.ResourceNotFreeException;
import org.jnode.system.resource.ResourceOwner;
import org.jnode.util.AccessControllerUtils;
import org.jnode.util.NumberUtils;
/**
* i82371AB_ACPI_SMBusControler.
* <p/>
* <p>
* Title:
* </p>
* <p>
* Description:
* </p>
* <p>
* Licence: GNU LGPL
* </p>
* <p>
* </p>
*
* @author Francois-Frederic Ozog
* @version 1.0
*/
public class i82371AB_ACPI_SMBusControler extends SMBusControler {
private static final Logger log = Logger.getLogger(i82371AB_ACPI_SMBusControler.class);
PCIDevice device;
int hostStatusIORegister = 0;
int slaveStatusIORegister = 0;
int hostControlIORegister = 0;
int hostCommandIORegister = 0;
int hostAddressIORegister = 0;
int hostData0IORegister = 0;
int hostData1IORegister = 0;
int blockDataIORegister = 0;
int slaveControlIORegister = 0;
int shadowCommandIORegister = 0;
int slaveEventIORegister = 0;
int slaveDataIORegister = 0;
public static final byte CONTROL_START = 0x40; // bit 6
public static final byte CONTROL_PROTOCOL_QUIKCOMMAND = 0x0;
public static final byte CONTROL_PROTOCOL_READWRITE_BYTE = 0x8;
public static final byte CONTROL_PROTOCOL_READWRITE_WORD = 0xC;
public static final byte CONTROL_PROTOCOL_READWRITE_BLOCK = 0x14;
public static final byte CONTROL_PROTOCOL_SENDRECEIVE_BYTE = 0x4;
private static final byte ADDRESS_READ_TAG = 1;
private static final byte ADDRESS_WRITE_TAG = 0;
public static final byte CONTROL_INTERUPT_ENABLED = 1;
public static final byte CONTROL_INTERUPT_DISABLED = 0;
IOResource ioRes = null;
public i82371AB_ACPI_SMBusControler(PCIDevice device) throws DriverException {
this.device = device;
// gets the IO registers address base from the PCI configuration register
// see paragraph 7.3 in chipset specification
int dword = device.readConfigWord(0x90);
int base = dword & 0xFFF0; // see 7.1.127 in specification for clearing the last digit
hostStatusIORegister = base++;
slaveStatusIORegister = base++;
hostControlIORegister = base++;
hostCommandIORegister = base++;
hostAddressIORegister = base++;
hostData0IORegister = base++;
hostData1IORegister = base++;
blockDataIORegister = base++;
slaveControlIORegister = base++;
shadowCommandIORegister = base++;
slaveEventIORegister = base++; // word size register
slaveDataIORegister = ++base; // word size register
// makes sure we generate IRQ9, not SMI and that the SMBus is enabled
device.writeConfigByte(0xd2, 0x9);
/*int config =*/
device.readConfigByte(0xd2);
try {
final ResourceManager rm = InitialNaming.lookup(ResourceManager.NAME);
try {
ioRes = claimPorts(rm, device, hostStatusIORegister, 14);
} catch (ResourceNotFreeException ex1) {
//todo empty?
}
} catch (NameNotFoundException ex) {
System.err.println("Cannot find ResourceManager: " + ex);
}
}
public boolean sendByte(byte address, byte value)
throws java.security.InvalidParameterException, java.lang.UnsupportedOperationException {
if (ioRes == null) {
throw new UnsupportedOperationException("IO resource not available");
}
ioRes.outPortByte(hostAddressIORegister, address | ADDRESS_WRITE_TAG);
ioRes.outPortByte(hostData0IORegister, value);
ioRes.outPortByte(hostCommandIORegister, value);
ioRes.outPortByte(hostControlIORegister,
CONTROL_START | CONTROL_PROTOCOL_READWRITE_BYTE | CONTROL_INTERUPT_DISABLED);
byte status;
try {
status = statusWait();
} catch (IOException e) {
throw new UnsupportedOperationException(e);
}
return status == 0;
}
public int processCall(byte address, byte command, int parameter)
throws java.security.InvalidParameterException, java.lang.UnsupportedOperationException {
throw new java.lang.UnsupportedOperationException("SMBus processCallI not supported by Intel 8273AB .");
}
public int readWord(byte smbaddress, byte reference)
throws java.security.InvalidParameterException, java.io.IOException {
reset();
ioRes.outPortByte(hostAddressIORegister, smbaddress | ADDRESS_READ_TAG);
ioRes.outPortByte(hostCommandIORegister, reference);
ioRes.outPortByte(hostControlIORegister,
CONTROL_START | CONTROL_PROTOCOL_READWRITE_WORD | CONTROL_INTERUPT_DISABLED);
byte status = statusWait();
if ((status & 0x10) > 0)
throw new java.io.IOException("Failed SMBus readWord transaction on bus address " +
NumberUtils.hex(smbaddress) + " and reference=" + NumberUtils.hex(reference));
else if ((status & 0x08) > 0)
throw new java.io.IOException(
"SMBus collision for readWord transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
if ((status & 0x04) > 0)
throw new java.io.IOException(
"Device error for SMBus readWord transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
return (ioRes.inPortByte(hostData0IORegister)) & 0xff + ((ioRes.inPortByte(hostData1IORegister)) & 0xff << 8);
}
public byte receiveByte(byte address)
throws java.security.InvalidParameterException, java.lang.UnsupportedOperationException {
/** @todo Implement this org.jnode.driver.smbus.SMBusControler abstract method */
throw new java.lang.UnsupportedOperationException("Method receiveByteImpl() not yet implemented.");
}
public boolean blockWrite(byte address, byte[] block)
throws java.security.InvalidParameterException, java.io.IOException, java.lang.UnsupportedOperationException {
/** @todo Implement this org.jnode.driver.smbus.SMBusControler abstract method */
throw new java.lang.UnsupportedOperationException("Method blockWriteImpl() not yet implemented.");
}
public boolean quickCommand(byte address)
throws java.security.InvalidParameterException, java.lang.UnsupportedOperationException {
/** @todo Implement this org.jnode.driver.smbus.SMBusControler abstract method */
throw new java.lang.UnsupportedOperationException("Method quickCommandImpl() not yet implemented.");
}
public byte[] blockRead(byte smbaddress, byte reference)
throws java.security.InvalidParameterException, java.io.IOException, java.lang.UnsupportedOperationException,
java.io.IOException {
reset();
ioRes.outPortByte(hostAddressIORegister, smbaddress | ADDRESS_READ_TAG);
ioRes.outPortByte(hostCommandIORegister, reference);
ioRes.outPortByte(hostControlIORegister,
CONTROL_START | CONTROL_PROTOCOL_READWRITE_BLOCK | CONTROL_INTERUPT_DISABLED);
byte status = statusWait();
if ((status & 0x10) > 0)
throw new java.io.IOException("Failed SMBus blockRead transaction on bus address " +
NumberUtils.hex(smbaddress) + " and reference=" + NumberUtils.hex(reference));
else if ((status & 0x08) > 0)
throw new java.io.IOException(
"SMBus collision for blockRead transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
if ((status & 0x04) > 0)
throw new java.io.IOException(
"Device error for SMBus blockRead transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
int size = ioRes.inPortByte(hostData0IORegister) & 0xff;
byte[] res = new byte[size];
ioRes.inPortByte(hostControlIORegister); // according to specification, reset chip internal
// index to read block data
for (int i = 0; i < size; i++) {
res[i] = (byte) ioRes.inPortByte(blockDataIORegister);
}
return res;
}
public boolean writeWord(byte smbaddress, byte reference, int value)
throws java.security.InvalidParameterException, java.lang.UnsupportedOperationException, java.io.IOException {
reset();
ioRes.outPortByte(hostAddressIORegister, smbaddress | ADDRESS_WRITE_TAG);
ioRes.outPortByte(hostCommandIORegister, reference);
ioRes.outPortByte(hostData0IORegister, value & 0xff);
ioRes.outPortByte(hostData1IORegister, (value & 0xff00) >> 8);
ioRes.outPortByte(hostControlIORegister,
CONTROL_START | CONTROL_PROTOCOL_READWRITE_WORD | CONTROL_INTERUPT_DISABLED);
byte status = statusWait();
if ((status & 0x10) > 0)
throw new java.io.IOException("Failed SMBus writeWord transaction on bus address " +
NumberUtils.hex(smbaddress) + " and reference=" + NumberUtils.hex(reference));
else if ((status & 0x08) > 0)
throw new java.io.IOException(
"SMBus collision for writeWord transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
if ((status & 0x04) > 0)
throw new java.io.IOException(
"Device error for SMBus writeWord transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
return true;
}
public boolean writeByte(byte smbaddress, byte reference, byte value)
throws java.security.InvalidParameterException, java.lang.UnsupportedOperationException, java.io.IOException {
reset();
ioRes.outPortByte(hostAddressIORegister, smbaddress | ADDRESS_WRITE_TAG);
ioRes.outPortByte(hostCommandIORegister, reference);
ioRes.outPortByte(hostData0IORegister, value);
ioRes.outPortByte(hostControlIORegister,
CONTROL_START | CONTROL_PROTOCOL_READWRITE_BYTE | CONTROL_INTERUPT_DISABLED);
byte status = statusWait();
if ((status & 0x10) > 0)
throw new java.io.IOException("Failed SMBus writeByte transaction on bus address " +
NumberUtils.hex(smbaddress) + " and reference=" + NumberUtils.hex(reference));
else if ((status & 0x08) > 0)
throw new java.io.IOException(
"SMBus collision for writeByte transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
if ((status & 0x04) > 0)
throw new java.io.IOException(
"Device error for SMBus writeByte transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
return true;
}
public boolean blockWriteProcessCall(byte address, byte[] inblock, byte[] outblock)
throws java.security.InvalidParameterException, java.io.IOException, java.lang.UnsupportedOperationException {
throw new java.lang.UnsupportedOperationException("SMBus processCall not supported by Intel 8273AB.");
}
public byte readByte(byte smbaddress, byte reference)
throws java.security.InvalidParameterException, java.io.IOException, java.lang.UnsupportedOperationException {
reset();
ioRes.outPortByte(hostAddressIORegister, smbaddress | ADDRESS_READ_TAG);
ioRes.outPortByte(hostCommandIORegister, reference);
ioRes.outPortByte(hostControlIORegister,
CONTROL_START | CONTROL_PROTOCOL_READWRITE_BYTE | CONTROL_INTERUPT_DISABLED);
byte status = statusWait();
if ((status & 0x10) > 0)
throw new java.io.IOException("Failed SMBus readByte transaction on bus address " +
NumberUtils.hex(smbaddress) + " and reference=" + NumberUtils.hex(reference));
else if ((status & 0x08) > 0)
throw new java.io.IOException(
"SMBus collision for readByte transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
if ((status & 0x04) > 0)
throw new java.io.IOException(
"Device error for SMBus readByte transaction on bus address " + NumberUtils.hex(smbaddress) +
" and reference=" + NumberUtils.hex(reference));
return (byte) ioRes.inPortByte(hostData0IORegister);
}
public void probeDevices(SMBus bus) {
// this controler is a SMBus version 1.0, so there are no dynamic discovery.
// use well known addresses and probe each address
byte res = 0;
// probes for the DIM
for (byte i = 0; i < 8; i++) {
try {
byte address = (byte) (0xa0 | (i << 1));
if (DIMMDriver.canExist(bus, address)) {
res = readByte((byte) (0xa0 | (i << 1)), (byte) 2);
log.debug("Discovered DIMM " + i + " type :" + Integer.toHexString(
(int) res));
DIMM dimmDevice = new DIMM(bus, "DIMM-" + i);
bus.addDevice(dimmDevice);
DIMMDriver dimmDriver = new DIMMDriver(bus, address);
dimmDevice.setDriver(dimmDriver);
DeviceUtils.getDeviceManager().register(dimmDevice);
log.info(dimmDevice.toString());
}
} catch (Exception ex) {
log.debug("DIMM " + i + " not present");
}
}
}
private void reset() throws IOException {
statusWait(); // just make sure it is available (may be errors due to last conditions so...
ioRes.outPortByte(hostStatusIORegister, 0x1e); // ...clears the error bits
}
private byte statusWait() throws IOException {
if (ioRes == null) {
throw new IOException("IO resource not available");
}
byte status = 0;
for (int i = 0; i < 500; i++) ; // dumb delay : see specification update
status = (byte) ioRes.inPortByte(hostStatusIORegister);
int i;
for (i = 0; (status & 0x01) == 1 && i < 2500000; i++)
status = (byte) ioRes.inPortByte(hostStatusIORegister);
if (i == 2500000) {
System.err.println("SMBus wait status timeout");
return -1;
}
return status;
}
private IOResource claimPorts(final ResourceManager rm, final ResourceOwner owner, final int low, final int length)
throws ResourceNotFreeException, DriverException {
try {
return AccessControllerUtils.doPrivileged(new PrivilegedExceptionAction<IOResource>() {
public IOResource run() throws ResourceNotFreeException {
return rm.claimIOResource(owner, low, length);
}
});
} catch (ResourceNotFreeException ex) {
throw ex;
} catch (Exception ex) {
throw new DriverException("Unknown exception", ex);
}
}
}