MyRegisterPort.c

/*
    File:       MyRegisterPort.c
 
    Contains:   Contains the custom routines for registering an offlineing an OT Port
                See the PortScanner.c file for an explanation of the call
 
    Written by:     
 
    Copyright:  Copyright © 1998-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/16/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
 
#pragma export on
 
//----------------------------------------------------------------------
 
#define DEBUG                   1
//----------------------------------------------------------------------
 
#include  <OpenTptModule.h>
#include  <OpenTptLinks.h>
#include <PCCardEnablerPlugin.h>
#include <PCCardTuples.h>
#include <Gestalt.h>
#include <DriverFamilyMatching.h>
#include "EnablerSample.h"
#include "MyRegisterPort.h"
 
 
static Boolean OfflinePortExists(RegEntryID *deviceRef, DriverDescription *dd, UInt32 socketNum);
static OSStatus SetPortConfiguredProperty (RegEntryID *deviceRef);
 
/*
    The OfflinePortExists call is used to offline a port
    where the assumption is that the deviceRef for the device
    in the NameRegistry is stored in the fContext field of the
    portRecord.  This routine searches the ports for an entry which
    has a matching deviceRef value and unregisters the port.
    
    Assumes that there is an existing port that has as it's fContext
    value, the same as *deviceRef, so that the value can be matched.
*/
 
static Boolean OfflinePortExists(RegEntryID *deviceRef, DriverDescription *dd, UInt32 socketNum)
{
    DriverServiceInfo   *dsi;
    TPortRecord         *portRecord;
    UInt32              index;
    UInt32              busType;
    size_t              idx;
    OSStatus            err;
    Boolean             foundOne;
    
 
#if DEBUG
    DebugStr("\p about to check for offlined ports");
#endif
 
    index = 0;
    while (portRecord = OTGetIndexedPort(index))
    {
        index++;
            
        busType = OTGetBusTypeFromPortRef(portRecord->fRef);
        if (busType == kOTPCCardBus)
        {
#if DEBUG
            DebugStr("\p PCCard port found");                   
#endif
        
                // check if the socket numbers match
            if (((UInt8)portRecord->fSlotID[0] - '0') != socketNum)
            {
#if DEBUG
                DebugStr("\p socketNum - no match");                    
#endif
                continue;
            }
#if DEBUG
            DebugStr("\p socketNum - matches");                 
#endif
                
                // check if the port is offlined
            if (portRecord->fPortFlags && kOTPortIsOffline)
            {
                // we've found an offline port.  
                // check if the driver descriptor info matches the info in the port
                dsi = dd->driverServices.service;
 
                foundOne = false;
 
                for (idx = 0; idx < dd->driverServices.nServices; ++idx)
                {
                    if ( dsi->serviceCategory == kServiceCategoryOpenTransport )
                    {
                        foundOne = true;
                        break;
                    }
                    dsi += 1;
                }
                
                if (foundOne == true)
                {
                        // check if the driver name matches
                    if (OTMemcmp(&(dd->driverOSRuntimeInfo.driverName[1]), portRecord->fModuleName,
                                    dd->driverOSRuntimeInfo.driverName[0]) == true)
                    {
#if DEBUG
                        DebugStr("\p matching offline port found");                 
#endif
                            // restore the fPortFlags
                        portRecord->fPortFlags &= ~(kOTPortIsOffline + kOTPortIsUnavailable );
                        
                            // set the fContext field to the current deviceRef
                        *(RegEntryID *)portRecord->fContext = *deviceRef;
                        err = SetPortConfiguredProperty(deviceRef);
                        if (err)
                        {
#if DEBUG
                            DebugStr("\p RegistryPropertySet for port-configured property failed");
#endif
                        }   
                        return true;
                    }
                }
            }
        }
    }
#if DEBUG
    DebugStr("\p matching offliner port not found");
#endif
    
    return false;
 
}
 
/*
    The OfflineThePort call is used to offline a port
    where the assumption is that the deviceRef for the device
    in the NameRegistry is stored in the fContext field of the
    portRecord.  This routine searches the ports for an entry which
    has a matching deviceRef value and unregisters the port.
    
    Assumes that there is an existing port that has as it's fContext
    value, the same as *deviceRef, so that the value can be matched.
*/
extern void OfflineThePort(RegEntryID *deviceRef)
{
    RegEntryID      *portContext;
    TPortRecord     *portRecord;
    UInt32          index;
    UInt32          busType;
    
 
#if DEBUG
    DebugStr("\p about to check bus");
#endif
 
    index = 0;
    while (portRecord = OTGetIndexedPort(index))
    {
        index++;
        busType = OTGetBusTypeFromPortRef(portRecord->fRef);
        if (busType == kOTPCCardBus)
        {
                // check if the deviceRef matches
            portContext = portRecord->fContext;
            if (*((long*)deviceRef) == *((long*)portContext))
            {
                    // set the offline bit in the fPortFlags field
                portRecord->fPortFlags |= kOTPortIsOffline;
                portRecord->fPortFlags |= kOTPortIsUnavailable;
#if DEBUG
                DebugStr("\p port offlined");
#endif
                return;
            }
        }
    }
#if DEBUG
    DebugStr("\p port not found to offline");
#endif
}
 
/*
    The RegisterThePort call is used to register a network port for a 
    PC Card 3.0 device with Open Transport.  The call 
    is designed for alternate networking cards like TokenRing, and ATM
    which are not handled by the default PC Card Port Scanner.
    
    This function checks for the presence of a 
    "driver-descriptor" and the "SocketNumber" property associated with
    the device node. It uses the these properties to fill in the port information.
    
    The call looks at the "driver-descriptor" property to know how to fill out the 
    TPortRecord structure.
    
*/
void RegisterThePort( RegEntryID *deviceRef)
{
    char                buffer[sizeof(DriverDescription) + 
                                 kMaxServices*sizeof(DriverServiceInfo)];
    DriverDescription   *dd = (DriverDescription*)buffer;
    DriverServiceInfo   *dsi;
    OTPortRecord        *portRecord;
    RegEntryID          *portContext;
    OSStatus            err;
    UInt32              size;
    UInt32              framing;
    UInt32              socket;
    size_t              idx;
    size_t              sIndex = 0;
    UInt16              other;
    UInt16              otType;
    UInt16              iface;
    Boolean             foundOne;
        
#if DEBUG   
    DebugStr("\p port scanner:  RegisterThePort");      
#endif
 
    //
    // If the driver has no driver-descriptor property, or the size
    // is too small, or it is too large to fit our buffer - forget 
    // this one.
    //
    err = RegistryPropertyGetSize(deviceRef, kDescriptorProperty, &size);
    if ( err != noErr || size < sizeof(DriverDescription) ||
         size > sizeof(buffer) )
    {
#if DEBUG
        DebugStr("\p kPropertyDriverDesc not found");
#endif
        return;
    }
    
    //
    // Read the driver-descriptor property into our buffer.
    //
    err = RegistryPropertyGet(deviceRef, kDescriptorProperty, buffer, &size);
    
    if ( err != noErr )
    {
#if DEBUG
        DebugStr("\p kPropertyDriverDesc not found");
#endif
        return;
    }
    
    //
    // Read the SocketNumber property into our buffer.
    //
    size = sizeof(socket);
    err = RegistryPropertyGet(deviceRef, kSocketNumber, &socket, &size);
    
    if ( err != noErr )
    {
#if DEBUG
        DebugStr("\p socket property not found");
#endif
        return;
    }
 
    //
    // Check whether an offline port exists for this module
    //
    
    if (OfflinePortExists(deviceRef, dd, socket) == true)
    {
        return;
    }
    
    dsi = dd->driverServices.service;
    foundOne = false;
    
    for (idx = 0; idx < dd->driverServices.nServices; ++idx)
    {
        if ( dsi->serviceCategory == kServiceCategoryOpenTransport )
        {
            foundOne = true;
            break;
        }
        dsi += 1;
    }
    
    if (foundOne == false)
        return;
        
        // check if there is a driver name
    if (dd->driverOSRuntimeInfo.driverName[0] == 0 )
        return;
        
        // lets register this port - first get some memory
    portRecord = (OTPortRecord*)OTAllocPortMem(sizeof(OTPortRecord));
    if (portRecord == nil)
        return;
        
    OTMemzero(portRecord, sizeof(OTPortRecord));
        
    OTMemcpy(&portRecord->fModuleName, &dd->driverOSRuntimeInfo.driverName[1], 
                dd->driverOSRuntimeInfo.driverName[0]);
    
    otType = (UInt16)((dsi->serviceType >> 16) & 0x7ff);
    iface = (UInt16)(dsi->serviceType & 3);
    framing = (UInt32)((dsi->serviceType >> 8) & 0xff);
    
        // find a unique "other" value for this device
    other = 0;
    do
    {
        portRecord->fRef = OTCreatePortRef(kOTPCCardBus, otType, socket, other++);
    } while ( OTFindPortByRef(portRecord->fRef) != 0 );
    
        // now set the associated slot 
//  portRecord->fSlotID[0] = 0;
 
    OTMemcpy(&portRecord->fSlotID, " \0", 2);
    portRecord->fSlotID[0] = (char)('0'+ socket);
    
        // for the fInfoFlag the 0x1 indicates the module is DLPI
        // for a TPI interface, set the value to 0x2
 
    portRecord->fInfoFlags      = iface;
    portRecord->fCapabilities   = framing;
    portRecord->fNumChildPorts  = 0;
    portRecord->fPortName[0]    = 0;
    
        // allocate port context memory
    portContext = (RegEntryID*)OTAllocPortMem(sizeof(RegEntryID));
    if (portContext != nil)
    {
            // store the deviceRef in the portContext field so that
            // we can discriminate this port entry later when we for a matching 
            // port to offline.
        *portContext = *deviceRef;
        
#if DEBUG
        DebugStr("\p about to register port");
#endif
        err = OTRegisterPort(portRecord, (void*)portContext);
    
        if (err == noErr)
        {
            err = SetPortConfiguredProperty(deviceRef);
            if (err)
            {
#if DEBUG
                DebugStr("\p RegistryPropertySet for port-configured property failed");
#endif
            }   
        }
        else
        {
#if DEBUG
            DebugStr("\p OTRegisterPort failed");
#endif
        }
    }
    else
    {
#if DEBUG
            DebugStr("\p OTAllocPortMem failed");
#endif
            OTFreePortMem(portRecord);
    }
}
 
static OSStatus SetPortConfiguredProperty (RegEntryID *deviceRef)
{
    OSStatus    err;
    UInt16      portConfigProperty = 1;
 
    // modify the port-configured property to indicate that we have registered the
    // port.  Note that the presence of this property tells the default PC Card
    // Port scanner that the port has been previously registered, whatever the
    // value.  This scanner checks the value and if zero, registers the port.
    // then we set the value to 1 to indicate that we've registered it.  Later
    // we might find this port and have a way to know that we've already configured
    // this device.
    err = RegistryPropertySet(deviceRef, kPortConfigured, 
                            &portConfigProperty, sizeof(portConfigProperty));
    return err;
}
 
#pragma export off