EnablerSmpl.c

/*
    File:       EnablerSmpl.c
 
    Contains:   This is a sample enabler for an ethernet PC Card, which demonstrates how to
                create a port module
                registration item and set a custom module name that will be used to
                identify the device driver. 
 
    Written by: Carl Fallis - writer of the original sample on which this sample is based
                Hiroko Nishimura - modified the sample to support the Ratoc REX-5589 Ethernet 
                    PC Card.
                Rich Kubota - modified to demonstrate handling of custom port registration  
 
    Copyright:  Copyright © 1996-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
                
 
*/
 
#include <Types.h>
#include <Errors.h>
#include <Devices.h>
#include <Gestalt.h>
#include <CodeFragments.h>
//#include <DriverServices.h>
#include <PCCardEnablerPlugin.h>
#include <PCCardTuples.h>
#include <OpenTptModule.h>
#include <OpenTptPCISupport.h>
#include <OpenTptDevLinks.h>
#include "EnablerSample.h"
#include "MyPortCalls.h"
 
// use the TupleDumper PPC utility which comes with the PC Card DDK to display the data
// associated with the following Tuples.  The following are used with the _IdentifyCard call
// to verify that the proper card is being supported.
 
const unsigned char kCISTPL_VERS_1_Data[] = "\4\1PCMCIA LAN MBH10304  ES\0  01\0\xff";
 
const unsigned char kCISTPL_CONFIG_Data[] = {0x05,0x20,0xF0,0x03,0x03,0x00,0xFF};
 
const unsigned char kCISTPL_CFTABLE_ENTRY_Data[] = {0xE0,0xC1,0x99,0x5F,0x55,0xC5,0x4B,0xD5,
                                        0x19,0x86,0x10,0x26,0x45,0x65,0x30,0xFF,
                                        0xFF,0x20,0xFF};
 
//----------------------------------------------------------------------
//  Local Prototypes
 
typedef PCCardTupleIterator PCCardTupleIteratorPtr;
 
OSStatus MyValidateHardware(const RegEntryID * lpCardEntry);
OSStatus MyHandleCardEvent(const RegEntryID *cardRef, PCCardEvent theEvent);
OSStatus MyGetFirstTuple(UInt32 socket, UInt32 device, PCCardTupleIteratorPtr lpTupleIterator,
            Byte desiredTuple, void *lptupleData, UInt32 *lpTupleBufferSize, Byte *lpFoundTuple);
OSStatus MyGetNextTuple(PCCardTupleIteratorPtr tupleIterator, Byte desiredTuple, void *tupleData, ByteCount *tupleBufferSize, Byte *foundTuple);
 
 
OSStatus _IdentifyCard(const RegEntryID *   lpCardEntry);
Boolean  CheckVers1Tuple(unsigned char * data, char * manufacturerName, char * cardName);
OSStatus CreatePortProperties(const RegEntryID *cardRef);
OSStatus MyAddDeviceProperties(const RegEntryID *cardRef, UInt32 device);
OSStatus MyFinalizeDevice(UInt32 socket, UInt32 device, const RegEntryID *deviceRef);
void    CallPortScanner(void);
void    EnablerOfflinePort(const RegEntryID *cardRef);
//----------------------------------------------------------------------
// Globals
 
 
#pragma export on 
 
// --------------------
// Here's the exported Driver Descriptor
DriverDescription TheDriverDescription = {
    /*
     * Signature info
     */
    kTheDescriptionSignature,               /* OSType driverDescSignature           */
    kInitialDriverDescriptor,               /* DriverDescVersion driverDescVersion  */
    /*
     * DriverType driverType - these are defined in
     */
    kPluginNamePString,                     /* Name of hardware */
    kVersionMajor, kVersionMinor,           /* NumVersion version */
    kVersionStage, kVersionNonRel,
 
    /*
     * DriverOSRuntime driverOSRuntimeInfo
     */
    kDriverIsLoadedUponDiscovery    |   /* Loader runtime options               */
    kDriverIsUnderExpertControl,        /* I/O expert handles loads/opens       */
    kPluginNamePString,                 /* Str31 driverName (OpenDriver param)  */
    0, 0, 0, 0, 0, 0, 0, 0,             /* UInt32 driverDescReserved[8]         */
 
    /*
     * DriverOSService Information. This section contains a vector count followed by
     * a vector of structures, each defining a driver service.
     */
    1,                                      /*  ServiceCount nServices              */
 
    /*
     * DriverServiceInfo service[0]
     */
    kServiceCategoryPCCard,                 /* OSType serviceCategory               */
    kServiceTypePCCardEnabler,              /* OSType serviceType                   */
 
    1, 0,developStage, 1
    };
 
 
 
// --------------------
// Here's the exported Plugin Function TableÉ
PCCardEnablerPluginDispatchTable ThePluginDispatchTable =
{
    /* PCCardEnablerPluginHeader */
    { kPCCardEnablerPluginCurrentVersion, 0, 0, 0 },
 
    /* CEValidateHardwareProc           */  MyValidateHardware,
    /* CEInitializeProc                 */  CEInitializeCard,
    /* CECleanupProc                    */  CEFinalizeCard,
    /* CEPowerManagementProc            */  CEPowerManagement,
 
    /* CEHandleEventProc                */  CEHandleCardEvent,
    /* CEGetCardInfoProc                */  CEGetCardInfo,
    /* CEAddCardPropertiesProc          */  CEAddCardProperties,
    /* CEGetDeviceCountProc             */  CEGetDeviceCount,
 
    /* CEGetDeviceNameProc              */  CEGetDeviceName,
    /* CEGetDeviceCompatibleNameProc    */  CEGetDeviceCompatibleNames,
    /* CEGetDeviceTypeProc              */  CEGetDeviceType,
    /* CEGetDeviceTypeNameProc          */  CEGetDeviceTypeName,
    /* CEAddDevicePropertiesProc        */  MyAddDeviceProperties,
    /* CEConfigureDeviceProc            */  CEConfigureDevice,
    /* CEFinalizeDeviceProc             */  MyFinalizeDevice,
 
    /* CEValidateCISProc                */  CEValidateCIS,
    /* CEGetFirstTupleProc              */  MyGetFirstTuple,
    /* CEGetNextTupleProc               */  MyGetNextTuple,
 
    /* InterruptHandler                 */  CEDefaultInterruptHandler,
    /* InterruptEnabler                 */  NULL,
    /* InterruptDisabler                */  NULL
};
 
 
//----------------------------------------------------------------------
//  Determine whether the plugin can support this card. 
//  Returning noErr means that the card is supported
OSStatus MyValidateHardware(const RegEntryID *lpCardEntry)
{
    OSStatus            err;
    
#if DEBUG   
    DebugStr("\pCustomCardEnabler:  MyValidateHardware");
#endif
    if (!(lpCardEntry)) return(paramErr);
 
    // see if we are supposed to handle this card, set global card id
    err = _IdentifyCard(lpCardEntry);
 
#if DEBUG1  
    if (err == noErr) DebugStr("\p Enabler will handle this card!;g");
#endif
    return(err);
}
 
 
//----------------------------------------------------------------------
//  Look to see if this is a card we are supposed to handle
//  If it is return noErr, other wise return kUnsupportedCardErr
// 
// Identification of the IBM OEM Ethernet card 
//  1) check the manufacturer's ID
//  2) check the vers 1 for IBM Corp Ethernet
//  3) check for the config table entry for the bad entry so that we are sure that 
//     this is the correct card we say it is our card
OSStatus _IdentifyCard(const RegEntryID *lpCardEntry)
{
    PCCardTupleIteratorPtr  iter;
    OSStatus                err = noErr;
    UInt32                  size=MAX_TUPLE_SIZE, socket, device;
    Boolean                 match = false; 
    int                     i=0;
    
    
#if DEBUG   
    DebugStr("\pCustomCardEnabler:  _IdentifyCard");
#endif
 
    if(!(lpCardEntry)  ) return(paramErr);
 
    err =  CEGetSocketAndDeviceFromRegEntry(lpCardEntry, &socket, &device);
    if (err != noErr)
        return(err);                            
 
    iter = PCCardNewTupleIterator();
    if (iter == NULL)
        return memFullErr;
 
    err = CECompareCISTPL_MANFID(lpCardEntry, 
                                    kManifID,
                                    kManifInfo,
                                    &match); 
        
    if ((err == noErr) && (match == true))
    {
        // do other checking if required like calling CSGetFirstTuple
        // to get more tuple info to compare against
    }
    else
        err = kUnsupportedCardErr;
        
        // dispose of the tuple iterator    
    PCCardDisposeTupleIterator(iter);
    
    return(err);
}
 
//----------------------------------------------------------------------
//   Look for the kPCCardInsertionMessage as the event
OSStatus MyHandleCardEvent(const RegEntryID *cardRef, PCCardEvent theEvent)
{
    OSStatus    err = noErr;
    
#if DEBUG   
 
    DebugStr("\pMyHandleCardEvent called");
#endif
 
    switch (theEvent)
    {
        case kPCCardInsertionMessage:
#if DEBUG1  
            DebugStr("\pkPCCardInsertionMessage event passed to MyHandleCardEvent;g");
#endif
            break;
    
        case kPCCardEjectionRequestMessage:
        case kPCCardRemovalMessage:
#if DEBUG   
            DebugStr("\p kPCCardRemovalMessage called");
#endif
//          EnablerOfflinePort(cardRef);
            break;
    }
            
    if (err == noErr)
            // call the default HandleEventProc to complete processing of the event.
        err = CEHandleCardEvent(cardRef, theEvent);
    
    return err;
}
 
 
//----------------------------------------------------------------------
OSStatus MyGetFirstTuple(UInt32 socket, UInt32 device,          
                                PCCardTupleIteratorPtr lpTupleIterator,
                                Byte desiredTuple,          
                                void *lpTupleData,
                                UInt32 *lpTupleBufferSize,
                                Byte *lpFoundTuple)
{
    OSStatus                err = noErr;
    unsigned char           *dataPtr = (unsigned char *)lpTupleData;
    UInt32                  i=0;
 
 
#if DEBUG   
//  DebugStr("\pCustomCardEnabler:  MyGetFirstTuple");      
#endif
    if(!(lpTupleIterator && lpFoundTuple && lpTupleData && *lpTupleBufferSize))
        return(paramErr);
    
    
    
    err = CSGetFirstTuple(socket, device,lpTupleIterator,desiredTuple,
                                lpTupleData,lpTupleBufferSize,lpFoundTuple);
    if (err != noErr)
        return(err);                            
 
    if (*lpTupleBufferSize == 0)
        return(err);
        
    if (*lpFoundTuple == CISTPL_VERS_1)
    {
#if DEBUG1
//      DebugStr("\pCISTPL_VERS_1");
#endif
        for( i = 0; i < sizeof(kCISTPL_VERS_1_Data); i++)
            dataPtr[i] = kCISTPL_VERS_1_Data[i];
                
        *lpTupleBufferSize = sizeof(kCISTPL_VERS_1_Data);
        
    }
            
    if (*lpFoundTuple == CISTPL_CONFIG)
    {
#if DEBUG1
        DebugStr("\pCISTPL_CONFIG");
#endif
        for( i = 0; i < sizeof(kCISTPL_CONFIG_Data); i++)
            dataPtr[i] = kCISTPL_CONFIG_Data[i];    
        *lpTupleBufferSize = sizeof(kCISTPL_CONFIG_Data);
    }
    if (*lpFoundTuple == CISTPL_CFTABLE_ENTRY)
    {
#if DEBUG1
        DebugStr("\pCISTPL_CFTABLE_ENTRY");
#endif
        for( i = 0; i < sizeof(kCISTPL_CFTABLE_ENTRY_Data); i++)
            dataPtr[i] = kCISTPL_CFTABLE_ENTRY_Data[i]; 
        *lpTupleBufferSize = sizeof(kCISTPL_CFTABLE_ENTRY_Data);
    }
 
    return(err);
}           
 
//
// MyGetNextTuple 
//          
OSStatus MyGetNextTuple(PCCardTupleIteratorPtr lpTupleIterator, 
                        Byte desiredTuple, 
                        void *lpTupleData, 
                        ByteCount *lpTupleBufferSize, 
                        Byte *lpFoundTuple)
{
    OSStatus                err = noErr;
    unsigned char           *dataPtr = (unsigned char *)lpTupleData;
    UInt32                  i=0;
    
    
#if DEBUG   
//  DebugStr("\pCustomCardEnabler:  MyGetNextTuple");       
#endif
    if(!(lpTupleIterator && lpFoundTuple && lpTupleData && *lpTupleBufferSize))
        return(paramErr);
    
    
    
    err = CSGetNextTuple(lpTupleIterator, desiredTuple,lpTupleData,lpTupleBufferSize,
                                lpFoundTuple);
    if (err != noErr)
        return(err);                            
    
    
    if (*lpTupleBufferSize == 0)
        return(err);
        
    if (*lpFoundTuple == CISTPL_VERS_1)
    {
#if DEBUG1
//      DebugStr("\pCISTPL_VERS_1");
#endif
        for( i = 0; i < sizeof(kCISTPL_VERS_1_Data); i++)
            dataPtr[i] = kCISTPL_VERS_1_Data[i];    
        *lpTupleBufferSize = sizeof(kCISTPL_VERS_1_Data);
    }       
    if (*lpFoundTuple == CISTPL_CONFIG)
    {
#if DEBUG1
        DebugStr("\pCISTPL_CONFIG");
#endif
        for( i = 0; i < sizeof(kCISTPL_CONFIG_Data); i++)
            dataPtr[i] = kCISTPL_CONFIG_Data[i];    
        *lpTupleBufferSize = sizeof(kCISTPL_CONFIG_Data);
    }
    
    if (*lpFoundTuple == CISTPL_CFTABLE_ENTRY)
    {
#if DEBUG1
        DebugStr("\pCISTPL_CFTABLE_ENTRY");
#endif
        for( i = 0; i < sizeof(kCISTPL_CFTABLE_ENTRY_Data); i++)
            dataPtr[i] = kCISTPL_CFTABLE_ENTRY_Data[i]; 
        *lpTupleBufferSize = sizeof(kCISTPL_CFTABLE_ENTRY_Data);
    }
 
    return(err);
}                       
 
 
//----------------------------------------------------------------------
//  Pass in a VERS1 tuple and check that the manufacturer name and card name are
// the the same as the ones passed in
Boolean CheckVers1Tuple(unsigned char * data, char * manufacturerName, char * cardName)
{
    unsigned char        *ptr;
    
    
#if DEBUG   
//  DebugStr("\pCustomCardEnabler:  CheckVers1Tuple");
#endif
    // the manufacturer name is a null terminated string starting in byte three
    ptr = &(data[2]);
    if(CStrCmp((const char *) ptr, manufacturerName) == 0)
    { 
        // the card name is a null terminated string that starts after the manufacturer name
        while(*ptr++)
            ;
        if(CStrCmp((const char *) ptr, cardName) != 0)
            return(false);
    }
    else
        return(false);                          
    
    // if we make it to here, both names match
    return(true);
}
 
 
OSStatus MyFinalizeDevice(UInt32 socket, UInt32 device, const RegEntryID *deviceRef)
{
    OSStatus    err;
#if DEBUG   
    DebugStr("\p MyFinalizeDevice called");
#endif
    EnablerOfflinePort(deviceRef);
    err = CEFinalizeDevice(socket, device, deviceRef);
    return err;
}
 
OSStatus MyAddDeviceProperties(const RegEntryID *cardRef, UInt32 device)
{
#pragma unused ( device )
    OSStatus    err;
 
#if DEBUG   
    DebugStr("\pCustomCardEnabler:  MyAddDeviceProperties");        
#endif
    
    //  This would be a great place to register a port, however, this creates a problem for 
    //  the shared library since this code could be called at start up time prior to
    //  the availability of Open Transport.  While I could weak link with OT, if the library
    // is not present, then even when the library becomes available, CFM will not relink
    //  with the OT libraries.  To handle this case, we implement a port scanner.
    
    err = CreatePortProperties(cardRef);
        CallPortScanner();
    
    return err;
}