#include "Apple16X50PCI.h"
#include <IOKit/serial/IOSerialKeys.h>
#define BAR_OFFSET_TO_REFCON(bar, off) ( (void *)( ((bar)&0x07)|((off)&0x18) ) )
#define REFCON_TO_OFFSET(ref) ( (UInt32)( ((UInt32)ref) & 0x18 ) )
#define REFCON_TO_BAR(ref) ( (UInt32)( ((UInt32)ref) & 0x07 ) )
#define super Apple16X50BusInterface
OSDefineMetaClassAndStructors(com_apple_driver_16X50PCI, com_apple_driver_16X50BusInterface)
IOService *Apple16X50PCI::
probe(IOService *provider, SInt32 *score)
{
Provider = OSDynamicCast(IOPCIDevice, provider);
if (!Provider) {
IOLog ("Apple16X50PCI: Attached to non-IOPCIDevice provider! Failing probe()\n");
return NULL;
}
if (!super::probe(provider, score)) return NULL;
char buf[80];
UInt8 dev = Provider->getDeviceNumber();
UInt8 func = Provider->getFunctionNumber();
UInt8 bus = Provider->getBusNumber();
OSData *propData = OSDynamicCast(OSData, Provider->getProperty("AAPL,slot-name"));
if (propData && (propData->getLength()) < 16)
sprintf(buf, "PCI %s Bus=%d Dev=%d Func=%d", (char *)(propData->getBytesNoCopy()), bus, dev, func);
else
sprintf(buf, "PCI Bus=%d Dev=%d Func=%d", bus, dev, func);
setProperty(kLocationKey, buf);
Location = (OSDynamicCast(OSString, getProperty(kLocationKey))->getCStringNoCopy());
setProperty(kIOTTYBaseNameKey, "pci-serial"); InterfaceBaseName="PCI Serial Adapter";
InterfaceInstance=Provider->dev;
sprintf(buf, "Apple16X50PCI%d", (int)InterfaceInstance);
setName(buf);
Provider->setMemoryEnable(false);
Provider->setIOEnable(false);
Provider->setBusMasterEnable(false);
return this;
}
Apple16X50UARTSync *Apple16X50PCI::
probeUART(void* refCon, Apple16X50UARTSync *uart, OSDictionary *properties)
{
char buf[80];
uart = super::probeUART(refCon, uart, properties);
if (!uart) return false;
sprintf(buf, "%s BAR=%d Offset=%d", Location, (int)REFCON_TO_BAR(refCon), (int)REFCON_TO_OFFSET(refCon));
uart->setProperty(kLocationKey, buf);
return uart;
}
bool Apple16X50PCI::
setupBAR (UInt32 bar, UInt32 maxUARTs)
{
register UInt32 barsize, implemented;
UInt32 barbase, addr=kIOPCIConfigBaseAddress0+(bar<<2);
barbase = Provider->configRead32(addr);
Provider->configWrite32(addr, ~barbase);
implemented = barbase ^ (Provider->configRead32(addr)); if ((barbase & implemented) == 0)
goto skip; Provider->configWrite32(addr, barbase);
for (barsize=1; barsize; barsize<<=1)
if (barsize & implemented) break;
DEBUG_IOLog("%s: BAR[%d]=0x%08x:0x%08x (len=%d bytes)\n", Name,
(int)bar, (int)barbase, (int)implemented, (int)barsize);
if ((barbase & 0x01) != 0x01) goto skip; if (barsize > (maxUARTs*kREG_Size)) goto skip; if (barsize < (kREG_Size)) goto skip; Map[bar] = Provider->mapDeviceMemoryWithRegister(addr);
if (!(Map[bar])) goto skip;
Len[bar]=barsize;
return true;
skip:
RELEASE(Map[bar]);
Len[bar]=0;
return false;
}
UInt32 Apple16X50PCI::
scanBARforUARTs (UInt32 bar, UInt32 maxUARTs)
{
register UInt32 count=0, offset;
if (Map[bar] && Len[bar]) {
for (offset=0; offset<Len[bar]; offset+=kREG_Size) {
if (probeUART(BAR_OFFSET_TO_REFCON(bar,offset)))
count++;
else break; }
if (!count) { RELEASE(Map[bar])
Len[bar]=0;
}
}
return count;
}
bool Apple16X50PCI::
start(IOService *provider)
{
UInt32 bar;
DEBUG_IOLog("%s: %s ID=%04x:%04x SID=%04x:%04x Class=%02x:%02x:%02x Int=%d\n",
Name, Location,
(int)(Provider->configRead16(kIOPCIConfigVendorID)),
(int)(Provider->configRead16(kIOPCIConfigDeviceID)),
(int)(Provider->configRead16(kIOPCIConfigSubSystemVendorID)),
(int)(Provider->configRead16(kIOPCIConfigSubSystemID)),
(int)(Provider->configRead8(kIOPCIConfigClassCode+2)),
(int)(Provider->configRead8(kIOPCIConfigClassCode+1)),
(int)(Provider->configRead8(kIOPCIConfigClassCode+0)),
(int)(Provider->configRead8(kIOPCIConfigInterruptPin))
);
for (bar=0; bar<MAX_BARS; bar++)
setupBAR(bar, bar?1:4);
Provider->setIOEnable(true);
for (bar=0; bar<MAX_BARS; bar++) {
UInt32 count = scanBARforUARTs(bar, bar?1:4);
if (count != 1) break;
}
if (UARTInstance==0) goto fail;
if (!super::start(provider)) goto fail;
IOLog("%s: Identified %d Serial channels at %s\n", Name, (int)UARTInstance, Location);
startUARTs();
return true;
fail:
Provider->setIOEnable(false);
return false;
}
void Apple16X50PCI::
stop(IOService *provider)
{
DEBUG_IOLog("%s: stop(%p)\n", Name, provider);
super::stop(provider);
DEBUG_IOLog("%s::stop() releasing UARTs\n", Name);
for (UInt32 i=0; i<UARTInstance; i++)
RELEASE(UART[i]);
Provider->setIOEnable(false);
}
void Apple16X50PCI::
free()
{
UInt32 i;
DEBUG_IOLog("%s: free()\n", Name);
for (i=0; i<MAX_BARS; i++) RELEASE(Map[i]);
super::free();
}
UInt8 Apple16X50PCI::
getReg(UInt32 reg, void *refCon)
{
return (Provider->ioRead8(reg+REFCON_TO_OFFSET(refCon), Map[REFCON_TO_BAR(refCon)]));
}
void Apple16X50PCI::
setReg(UInt32 reg, UInt8 val, void *refCon)
{
Provider->ioWrite8(reg+REFCON_TO_OFFSET(refCon), val, Map[REFCON_TO_BAR(refCon)]);
}