1 line
No EOL
4.1 KiB
C
1 line
No EOL
4.1 KiB
C
/*
|
|
* Various utilities for writing a MacOS "ndrv" driver, such as device-tree
|
|
* helpers. These replace the various Apple sample codes whose licences
|
|
* are dubious and probably not suitable for GPL code
|
|
*/
|
|
|
|
//#include "VideoDriverPrivate.h"
|
|
//#include "VideoDriverPrototypes.h"
|
|
#include "logger.h"
|
|
#include "MacDriverUtils.h"
|
|
|
|
/* Simplified DT properties accessors */
|
|
void *DTGetProp(RegEntryIDPtr dtNode,
|
|
RegPropertyNamePtr name,
|
|
RegPropertyValueSize *outSize)
|
|
{
|
|
OSStatus err;
|
|
RegPropertyValue *v;
|
|
|
|
if (!outSize)
|
|
return NULL;
|
|
|
|
/* Grab size so we can allocate some memory */
|
|
err = RegistryPropertyGetSize(dtNode, name, outSize);
|
|
if (err)
|
|
return NULL;
|
|
|
|
/* Allocate */
|
|
v = PoolAllocateResident(*outSize, FALSE);
|
|
if (!v)
|
|
return NULL;
|
|
|
|
err = RegistryPropertyGet(dtNode, name, v, outSize);
|
|
if (err)
|
|
return NULL;
|
|
|
|
return v;
|
|
}
|
|
|
|
void DTFreeProp(void *v)
|
|
{
|
|
if (v)
|
|
PoolDeallocate(v);
|
|
}
|
|
|
|
/* Find a BAR logical address and size */
|
|
LogicalAddress GetDeviceBARAddress(RegEntryIDPtr dtNode,
|
|
PCIRegisterNumber barOffset,
|
|
ByteCount *size,
|
|
Boolean *isIO)
|
|
{
|
|
RegPropertyValueSize aasize, lasize;
|
|
LogicalAddress *las = NULL;
|
|
PCIAssignedAddress *aas = NULL;
|
|
LogicalAddress result = 0;
|
|
UInt32 i;
|
|
|
|
/* First grab assigned-addresses to find the BAR */
|
|
aas = DTGetProp(dtNode, kPCIAssignedAddressProperty, &aasize);
|
|
if (!aas)
|
|
return NULL;
|
|
aasize /= sizeof(*aas);
|
|
|
|
/* Then grab AAPL,addresses to get the corresponding logical addresses */
|
|
las = DTGetProp(dtNode, kAAPLDeviceLogicalAddress, &lasize);
|
|
if (!las)
|
|
goto bail;
|
|
lasize /= sizeof(LogicalAddress);
|
|
|
|
/* Lookup BAR */
|
|
for (i = 0; i < aasize; i++) {
|
|
struct PCIAssignedAddress *aa = aas + i;
|
|
|
|
/* Skip config space */
|
|
if (GetPCIAddressSpaceType(aa) == kPCIConfigSpace)
|
|
continue;
|
|
|
|
/* Check BAR offset */
|
|
if (GetPCIRegisterNumber(aa) != barOffset)
|
|
continue;
|
|
|
|
/* Found it, check that it was assigned */
|
|
if (aa->size.hi == 0 && aa->size.lo == 0) {
|
|
lprintf("BAR %02x not assigned !\n");
|
|
goto bail;
|
|
}
|
|
|
|
/* Check we have a logical for it */
|
|
if (i >= lasize) {
|
|
lprintf("BAR %02x missing AAPL,address property !\n");
|
|
goto bail;
|
|
}
|
|
|
|
/* We don't do 64-bit, sorry... */
|
|
if (aa->size.hi) {
|
|
lprintf("BAR %02x too big !\n");
|
|
goto bail;
|
|
}
|
|
|
|
/* Gotcha ! */
|
|
if (size)
|
|
*size = aa->size.lo;
|
|
if (isIO)
|
|
*isIO = GetPCIAddressSpaceType(aa) == kPCIIOSpace;
|
|
result = las[i];
|
|
break;
|
|
}
|
|
|
|
bail:
|
|
DTFreeProp(aas);
|
|
DTFreeProp(las);
|
|
return result;
|
|
}
|
|
|
|
|
|
/* PCI "Command" config register address */
|
|
#define kPCIConfigCommandAddress 0x04
|
|
#define cwCommandEnableMemorySpace 0x0002
|
|
|
|
/* Enable access to PCI memory space */
|
|
OSStatus EnablePCIMemorySpace(RegEntryIDPtr dtNode)
|
|
{
|
|
OSStatus status;
|
|
UInt16 cmd;
|
|
|
|
lprintf("Reading cmd word...\n");
|
|
status = ExpMgrConfigReadWord(dtNode, (LogicalAddress)kPCIConfigCommandAddress, &cmd);
|
|
if( status )
|
|
return status;
|
|
|
|
lprintf("cmad word is: %04x, writing update...\n", cmd);
|
|
cmd |= cwCommandEnableMemorySpace;
|
|
|
|
return ExpMgrConfigWriteWord(dtNode, (LogicalAddress)kPCIConfigCommandAddress, cmd);
|
|
}
|
|
|
|
OSStatus SetupPCIInterrupt(RegEntryID *dtNode, IRQInfo *info,
|
|
InterruptHandler handler, void *refCon)
|
|
{
|
|
ISTProperty *ist;
|
|
RegPropertyValueSize istSize;
|
|
OSStatus err;
|
|
|
|
ist = DTGetProp(dtNode, kISTPropertyName, &istSize);
|
|
if (!ist) {
|
|
lprintf("SetupPCIInterrupt: No %s property\n", kISTPropertyName);
|
|
return paramErr;
|
|
}
|
|
info->interruptSetMember = (*ist)[kISTChipInterruptSource];
|
|
DTFreeProp(ist);
|
|
|
|
err = GetInterruptFunctions(info->interruptSetMember.setID,
|
|
info->interruptSetMember.member,
|
|
&info->refCon,
|
|
&info->handlerFunction,
|
|
&info->enableFunction,
|
|
&info->disableFunction);
|
|
if (err) {
|
|
lprintf("SetupPCIInterrupt: Error %d getting interrupt functions\n");
|
|
return err;
|
|
}
|
|
err = InstallInterruptFunctions(info->interruptSetMember.setID,
|
|
info->interruptSetMember.member,
|
|
refCon, handler, NULL, NULL);
|
|
if (err) {
|
|
lprintf("SetupPCIInterrupt: Error %d setting interrupt functions\n");
|
|
return err;
|
|
}
|
|
return noErr;
|
|
} |