ApplePCCardSample.cpp [plain text]
#include <IOKit/IOService.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/pccard/IOPCCard.h>
#define NEEDS_A_ENABLER
#ifdef NEEDS_A_ENABLER
class ApplePCCardSampleEnabler : public IOPCCard16Enabler
{
OSDeclareDefaultStructors(ApplePCCardSampleEnabler);
public:
static ApplePCCardSampleEnabler * withDevice(IOPCCard16Device *provider);
virtual bool sortConfigurations(void);
};
#undef super
#define super IOPCCard16Enabler
OSDefineMetaClassAndStructors(ApplePCCardSampleEnabler, IOPCCard16Enabler);
ApplePCCardSampleEnabler *
ApplePCCardSampleEnabler::withDevice(IOPCCard16Device *provider)
{
ApplePCCardSampleEnabler *me = new ApplePCCardSampleEnabler;
if (me && !me->init(provider)) {
me->free();
return 0;
}
return me;
}
bool
ApplePCCardSampleEnabler::sortConfigurations(void)
{
IOLog("ApplePCCardSampleEnabler::sortConfigurations entered\n");
IOSleep(500);
for (unsigned i=0; i < tableEntryCount; i++) {
cistpl_cftable_entry_t *cfg = configTable[i];
IOLog("sortConfig index=0x%x, vcc %d vpp %d vpp1 %d", cfg->index,
(cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) ? (int)cfg->vcc.param[CISTPL_POWER_VNOM] : 0,
(cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) ? (int)cfg->vpp1.param[CISTPL_POWER_VNOM] : 0,
(cfg->vpp2.present & (1<<CISTPL_POWER_VNOM)) ? (int)cfg->vpp2.param[CISTPL_POWER_VNOM] : 0);
if (cfg->io.nwin) {
IOLog(" io (desc=0x%x)", cfg->io.flags);
for (unsigned j=0; j < cfg->io.nwin; j++) {
IOLog(", 0x%x-0x%x", cfg->io.win[j].base, cfg->io.win[j].base + cfg->io.win[j].len - 1);
}
}
if (cfg->mem.nwin) {
IOLog(" mem sizes");
for (unsigned j=0; j < cfg->mem.nwin; j++) {
IOLog(" 0x%x", cfg->mem.win[j].len);
}
}
IOLog("\n");
}
IOSleep(500);
return super::sortConfigurations();
}
#endif NEEDS_A_ENABLER
class ApplePCCardSample : public IOService
{
OSDeclareDefaultStructors(ApplePCCardSample)
IOPCCard16Device * nub;
IOInterruptEventSource * interruptSource;
IOWorkLoop * workLoop;
unsigned windowCount;
IOMemoryMap * windowMap[10];
bool cardPresent;
public:
virtual IOService * probe(IOService *provider, SInt32 *score);
virtual bool start(IOService * provider);
virtual void stop(IOService * provider);
virtual IOReturn setPowerState(unsigned long powerState, IOService * whatDevice);
virtual IOReturn message(UInt32 type, IOService * provider, void * argument = 0);
void interruptOccurred(IOInterruptEventSource * src, int i);
void dumpWindows();
void dumpConfigRegisters();
};
#define CardServices nub->cardServices
#undef super
#define super IOService
OSDefineMetaClassAndStructors(ApplePCCardSample, IOService);
IOService*
ApplePCCardSample::probe(IOService * provider, SInt32 * score)
{
IOLog("ApplePCCardSample::probe(provider=%p, score=0x%x) starting\n", provider, (int)*score);
nub = OSDynamicCast(IOPCCard16Device, provider);
if (!nub) return NULL;
cardPresent = true;
if (!super::probe(provider, score)) return NULL;
cisinfo_t cisinfo;
int ret = CardServices(ValidateCIS, nub->getCardServicesHandle(), &cisinfo);
if (ret != CS_SUCCESS) {
IOLog("ApplePCCardSample: ValidateCIS failed %d.\n", ret);
stop(provider);
return false;
}
IOLog("ApplePCCardSample: ValidateCIS Chains=%d.\n", cisinfo.Chains);
return this;
}
bool
ApplePCCardSample::start(IOService * provider)
{
IOLog("ApplePCCardSample::start(provider=%p, this=%p) starting\n", provider, this);
nub = OSDynamicCast(IOPCCard16Device, provider);
if (!nub) {
IOLog("%s: provider is not of class IOPCCard16Device?\n", getName());
return false;
}
#ifdef CHANGE_VERSION_ONE
OSArray *vers1 = OSArray::withCapacity(2);
if (vers1) {
const OSSymbol *str = OSSymbol::withCString("test vendor");
if (str) {
vers1->setObject((OSSymbol *)str);
str->release();
}
str = OSSymbol::withCString("test card type");
if (str) {
vers1->setObject((OSSymbol *)str);
str->release();
}
provider->setProperty("VersionOneInfo", vers1);
vers1->release();
}
#endif
cardPresent = true;
static const IOPMPowerState myPowerStates[ kIOPCCard16DevicePowerStateCount ] =
{
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, IOPMSoftSleep, IOPMSoftSleep, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, IOPMPowerOn, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};
PMinit();
registerPowerDriver(this, (IOPMPowerState *)myPowerStates, kIOPCCard16DevicePowerStateCount);
provider->joinPMtree( this);
changePowerStateTo(kIOPCCard16DeviceOnState);
workLoop = getWorkLoop();
if (!workLoop) {
IOLog("%s: could not get the workLoop.\n", getName());
return false;
}
interruptSource = IOInterruptEventSource::interruptEventSource(this,
(IOInterruptEventAction)&ApplePCCardSample::interruptOccurred,
provider,
0);
if (!interruptSource) {
IOLog("%s: Failed to create interrupt event source.\n", getName());
return false;
}
if (workLoop->addEventSource(interruptSource) != kIOReturnSuccess) {
IOLog("%s: Failed to add interrupt event to workLoop.\n", getName());
interruptSource->release();
interruptSource = NULL;
workLoop->release();
workLoop = NULL;
return false;
}
workLoop->enableAllInterrupts();
#ifdef NEEDS_A_ENABLER
ApplePCCardSampleEnabler *customEnabler = ApplePCCardSampleEnabler::withDevice(nub);
if (!customEnabler) IOLog("%s: ApplePCCardSampleEnabler::withDevice(nub) failed\n", getName());
bool success = nub->installEnabler(customEnabler);
if (!success) IOLog("%s: nub->installEnabler(customEnabler) failed\n", getName());
customEnabler->release();
#endif
if (!nub->configure()) {
stop(provider);
return false;
}
config_info_t config;
if (!nub->getConfigurationInfo(&config)) IOLog("%s: getConfigurationInfo failed\n", getName());
IOLog("%s: the client is %svalid, ConfigBase=0x%x, BasePort1=0x%x(0x%x), BasePort2=0x%x(0x%x)\n",
getName(), (config.Attributes & CONF_VALID_CLIENT) ? "" : "not ", config.ConfigBase,
config.BasePort1, config.NumPorts1, config.BasePort2, config.NumPorts2);
windowCount = nub->getWindowCount();
for (unsigned i=0; i < windowCount; i++) {
UInt32 attributes;
if (!nub->getWindowAttributes(i, &attributes)) IOLog("%s: getWindowAttributes failed\n", getName());
IOLog("%s: mapping window index %d, size = 0x%x, attributes = 0x%x\n", getName(), i, (int)nub->getWindowSize(i), (int)attributes);
windowMap[i] = nub->mapDeviceMemoryWithIndex(i);
if (!windowMap[i]) {
IOLog("%s: Failed to map device memory index %d.\n", getName(), i);
stop(provider);
return false;
}
}
dumpWindows();
dumpConfigRegisters();
IOLog("ApplePCCardSample::start(provider=%p, this=%p) ending\n", provider, this);
return true;
}
void
ApplePCCardSample::stop(IOService * provider)
{
IOLog("ApplePCCardSample::stop(provider=%p, this=%p) stopping\n", provider, this);
if (nub != provider) {
IOLog("%s: nub != provider\n", getName());
return;
}
for (unsigned i=0; i < windowCount; i++) {
IOLog("%s: unmapping window index %d, size = 0x%x\n", getName(), i, (int)nub->getWindowSize(i));
if (windowMap[i]) windowMap[i]->release();
}
nub->unconfigure();
PMstop();
if (workLoop && interruptSource) {
workLoop->removeEventSource(interruptSource);
interruptSource->release();
interruptSource = NULL;
workLoop = NULL;
}
super::stop(provider);
}
IOReturn
ApplePCCardSample::setPowerState(unsigned long powerState, IOService * whatDevice)
{
switch (powerState) {
case kIOPCCard16DeviceOnState:
case kIOPCCard16DeviceDozeState:
IOLog("ApplePCCardSample::setPowerState setting power state to on\n");
if (workLoop) workLoop->enableAllInterrupts();
dumpWindows();
break;
case kIOPCCard16DeviceOffState:
if (workLoop) workLoop->disableAllInterrupts();
IOLog("ApplePCCardSample::setPowerState setting power state to off\n");
break;
default:
IOLog("ApplePCCardSample::setPowerState unknown state=%d?\n", (int)powerState);
break;
}
return IOPMAckImplied;
}
IOReturn
ApplePCCardSample::message(UInt32 type, IOService * provider, void * argument)
{
switch(type) {
case kIOPCCardCSEventMessage: {
UInt32 cs_event = (UInt32) argument;
switch (cs_event) {
case CS_EVENT_CARD_INSERTION:
IOLog("ApplePCCardSample::message, nub=%p, card services event CS_EVENT_CARD_INSERTION.\n", nub);
break;
case CS_EVENT_CARD_REMOVAL:
IOLog("ApplePCCardSample::message, nub=%p, card services event CS_EVENT_CARD_REMOVAL.\n", nub);
cardPresent = false;
break;
case CS_EVENT_EJECTION_REQUEST:
IOLog("ApplePCCardSample::message, nub=%p, card services event CS_EVENT_EJECTION_REQUEST.\n", nub);
break;
case CS_EVENT_RESET_REQUEST:
IOLog("ApplePCCardSample::message, nub=%p, card services event CS_EVENT_RESET_REQUEST.\n", nub);
break;
case CS_EVENT_RESET_PHYSICAL:
IOLog("ApplePCCardSample::message, nub=%p, card services event CS_EVENT_RESET_PHYSICAL.\n", nub);
break;
case CS_EVENT_CARD_RESET:
IOLog("ApplePCCardSample::message, nub=%p, card services event CS_EVENT_CARD_RESET.\n", nub);
break;
default:
IOLog("ApplePCCardSample::message, nub=%p, card services event type=0x%x.\n", nub, (int)cs_event);
break;
}
}
break;
default:
return super::message(type, provider, argument);
break;
}
return kIOReturnSuccess;
}
void
ApplePCCardSample::interruptOccurred(IOInterruptEventSource * src, int i)
{
IOLog("ApplePCCardSample::interruptOccurred, nub=%p, src=%p, i=0x%x.\n", nub, src, i);
if (!cardPresent) {
IOLog("%s::interruptOccurred, ignoring interrupt, the card is not present\n", getName());
return;
}
}
void
ApplePCCardSample::dumpWindows()
{
if (!cardPresent) {
IOLog("%s::dumpWindows, aborting, the card is not present\n", getName());
return;
}
for (unsigned i=0; i < windowCount; i++) {
if (nub->getWindowType(i) == IOPCCARD16_MEMORY_WINDOW) {
UInt32 offset;
if (!nub->getWindowOffset(i, &offset)) IOLog("%s: getWindowOffset failed\n", getName());
IOLog("%s: window %d physical 0x%x virtual 0x%x offset 0x%x length 0x%x (memory)\n",
getName(), i, (int)windowMap[i]->getPhysicalAddress(), windowMap[i]->getVirtualAddress(), (int)offset, (int)windowMap[i]->getLength());
IOLog("%x %x %x %x %x %x %x %x\n",
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 0), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 4),
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 8), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 12),
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 16), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 20),
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 24), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 28));
#if 1
if (!nub->setWindowOffset(i, 0x1000)) IOLog("%s: setWindowOffset failed\n", getName());
if (!nub->getWindowOffset(i, &offset)) IOLog("%s: getWindowOffset failed (case 2)\n", getName());
IOLog("%s: window %d physical 0x%x virtual 0x%x offset 0x%x length 0x%x (memory)\n",
getName(), i, (int)windowMap[i]->getPhysicalAddress(), windowMap[i]->getVirtualAddress(), (int)offset, (int)windowMap[i]->getLength());
IOLog("%x %x %x %x %x %x %x %x\n",
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 0), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 4),
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 8), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 12),
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 16), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 20),
(int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 24), (int)OSReadSwapInt32((void *)windowMap[i]->getVirtualAddress(), 28));
#endif
} else {
IOLog("%s: window %d physical 0x%x virtual 0x%x length 0x%x (io)\n",
getName(), i, (int)windowMap[i]->getPhysicalAddress(), windowMap[i]->getVirtualAddress(), (int)windowMap[i]->getLength());
UInt32 attributes;
if (!nub->getWindowAttributes(i, &attributes)) {
IOLog("%s: getWindowAttributes failed\n", getName());
return;
}
if (attributes & IO_DATA_PATH_WIDTH == IO_DATA_PATH_WIDTH_16) {
int l = windowMap[i]->getLength(); l = l > 0x10 ? 0x10 : l;
for (int j=0; j < l; j++,j++) {
IOLog("%x ", nub->ioRead16(j, windowMap[i]));
}
} else {
int l = windowMap[i]->getLength(); l = l > 0x10 ? 0x10 : l;
for (int j=0; j < l; j++) {
IOLog("%x ", nub->ioRead8(j, windowMap[i]));
}
}
IOLog("\n");
}
}
}
#define ATTRIBUTE_SIZE 0x1000
void
ApplePCCardSample::dumpConfigRegisters()
{
if (!cardPresent) {
IOLog("%s::dumpConfigRegisters, the card is not present\n", getName());
return;
}
config_info_t config;
if (!nub->getConfigurationInfo(&config)) {
IOLog("%s:dumpConfigRegisters, getConfigurationInfo failed\n", getName());
return;
}
OSData * temp = OSData::withCapacity(ATTRIBUTE_SIZE >> 1);
conf_reg_t reg;
reg.Function = 0; reg.Action = CS_READ; reg.Offset = 0; reg.Value = 0;
for (int i=0; i < (ATTRIBUTE_SIZE - (int)config.ConfigBase); i += 2) {
reg.Offset = i;
int ret = CardServices(AccessConfigurationRegister, nub->getCardServicesHandle(), ®);
if (ret != CS_SUCCESS) {
IOLog("%s::dumpConfigRegisters failed %d.\n", getName(), ret);
break;
}
UInt8 byte = (UInt8)reg.Value;
temp->appendBytes(&byte, 1);
}
registerService();
setProperty("Configuration Registers Base Address", config.ConfigBase, 32);
setProperty("Configuration Registers Present Mask", config.Present, 32);
setProperty("Attribute Memory", temp);
temp->release();
}