Source to iokit/IOKit/network/IONetworkController.h


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved. 
 *
 * IONetworkController.h
 *
 * Network controller driver superclass.
 *
 * HISTORY
 * 9-Dec-1998       Joe Liu (jliu) created.
 *
 */

#ifndef _IONETWORKCONTROLLER_H
#define _IONETWORKCONTROLLER_H

#include <IOKit/IOService.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOKernelDebugger.h>

struct mbuf;            // forward declarations
class  IOCommandGate;
class  IOOutputQueue;
class  IONetworkMedium;

// Keys for property table entries.
//
#define kIOVendor                "IOVendor"                // OSString
#define kIOModel                 "IOModel"                 // OSString
#define kIORevision              "IORevision"              // OSString
#define kIOInfo                  "IOInfo"                  // OSString
#define kIOControllerIndex       "IOControllerIndex"       // OSNumber:32
#define kIOFeatureSet            "IOFeatureSet"            // OSNumber:32
#define kIOFamilyFeatureSet      "IOFamilyFeatureSet"      // OSNumber:32
#define kIOMediumDictionary      "IOMediumDictionary"      // OSDictionary
#define kIODefaultMedium         "IODefaultMedium"         // OSString
#define kIOCurrentMedium         "IOCurrentMedium"         // OSSymbol
#define kIOActiveMedium          "IOActiveMedium"          // OSSymbol
#define kIOEnableDebugger        "IOEnableDebugger"        // OSString (Yes/No)
#define kIOLinkSpeed             "IOLinkSpeed"             // OSNumber:64
#define kIOLinkStatus            "IOLinkStatus"            // OSNumber:32
#define kIOLinkData              "IOLinkData"              // OSData
#define kIOPacketFilters         "IOPacketFilters"         // OSNumber:32
#define kIOActivePacketFilters   "IOActivePacketFilters"   // OSNumber:32

/*! @typedef IOPacketBufferConstraints
    @discussion Constraint parameters used by allocatePacket() to
    align the memory buffer associated with a mbuf.
    @field alignStart Alignment for the buffer's starting address.
    @field alignLength Buffer length alignment.
    @field maxLength Maximum buffer size (not implemented).
    */

typedef struct {
    UInt32 alignStart;
    UInt32 alignLength;
    UInt32 maxLength;
} IOPacketBufferConstraints;

// Some frequently used alignment constants.
//
enum {
    kIOPacketBufferAlign1   = 1,
    kIOPacketBufferAlign2   = 2,
    kIOPacketBufferAlign4   = 4,
    kIOPacketBufferAlign8   = 8,
    kIOPacketBufferAlign16  = 16,
    kIOPacketBufferAlign32  = 32,
};

// Packet filters. Upper 16-bits are family specific.
//
enum {
    kIOPacketFilterUnicast          = 0x1,
    kIOPacketFilterBroadcast        = 0x2,
    kIOPacketFilterMulticast        = 0x10,
    kIOPacketFilterMulticastAll     = 0x20,
    kIOPacketFilterPromiscuous      = 0x100,
    kIOPacketFilterPromiscuousAll   = 0x200,
    kIOPacketFilterFamilyMask       = 0xffff0000,
};

// Generic controller features.
//
enum {
    kIONetworkFeatureNoBSDWait = 0x01,  // start() should not wait for BSD.
};

    
/*! @class IONetworkController
    @abstract IONetworkController implements the framework for a generic 
    network controller. A subclass of IONetworkController must provide
    additional functionality specific for a particular network family.
    In addition, the driver must implement (override) a basic set of 
    hardware dependent methods to create a working driver.
    
    IONetworkController attaches itself to the network layer via an
    IONetworkInterface object. A controller object without a companion
    interface is not known to the networking system. The controller
    interacts with the network layer by calling methods defined by
    the interface object. And conversely, the network layer issues
    command and packets to the controller through its interface object.
    
    IONetworkController allocates an IOWorkLoop and an IOCommandGate object.
    Most commands (requests) sent from the interface object are handled
    by instructing the IOCommandGate instance to call one or more methods,
    usually implemented by the driver, that may require hardware access.
    Thus interface requests are always serialized. Outbound packets sent
    from the interface to the controller have no implicit serialization. 
    Drivers must implement an output function that is thread safe, or use
    an IOOutputQueue object which will provide a serialization model.
    */

class IONetworkController : public IOService
{
    OSDeclareAbstractStructors(IONetworkController)

public:

/*! @typedef RequestAction
    @discussion Prototype for an action to be called through syncRequest().
    See syncRequest().
    @param arg0 Action argument.
    @param arg1 Action argument.
    @param arg2 Action argument.
    @param arg3 Action argument.
    */

    typedef UInt32 (OSObject::*RequestAction)(void * arg0,
                                              void * arg1,
                                              void * arg2,
                                              void * arg3);

private:

    IOWorkLoop *             _workLoop;
    IOCommandGate *          _cmdGate;
    IOOutputQueue *          _outputQueue;
    OSSet *                  _clientSet;
    OSObject *               _reqClient;
    UInt32                   _alignStart;
    UInt32                   _alignLength;
    UInt32                   _alignPadding;
    bool                     _handleReady;
    bool                     _requestEnabled;
    IOLock *                 _mediumLock;
    IODebuggerLockState      _debugLockState;
    UInt32                   _linkStatus;
    UInt64                   _linkSpeed;
    OSData *                 _linkData;
    const IONetworkMedium *  _activeMedium;
    const IONetworkMedium *  _currentMedium;

    bool     _controllerIsReady();
    IOReturn _enable(IOService * client);
    IOReturn _disable(IOService * client);
    void     commandHandler(void *, void *, void *, void *);
    IOReturn selectMediumWithName(const OSSymbol * mediumName);

    bool setMediumProperty(const OSSymbol *         key,
                           const IONetworkMedium *  medium,
                           const IONetworkMedium ** cache,
                           bool                     force = false,
                           bool *                   changed = 0);

    bool setLink64Property(const char * key,
                           UInt64       value,
                           UInt64 *     cache,
                           bool         force = false,
                           bool *       changed = 0);

    bool setLink32Property(const char * key,
                           UInt32       value,
                           UInt32 *     cache,
                           bool         force = false,
                           bool *       changed = 0);

    bool verifyMediumDictionary(const OSDictionary * mediumDict);

    static void _logMbuf(struct mbuf * m);

    static void _enableSyncRequestFilter(IONetworkController *, bool);

    static void debugRxHandler(IOService * handler,
                               void *      buffer,
                               UInt *      length,
                               UInt        timeout);

    static void debugTxHandler(IOService * handler,
                               void *      buffer,
                               UInt        length);

public:

/*! @function initialize
    @abstract IONetworkController class initializer.
    @discussion Create often used OSSymbol objects that are used as keys.
    This method is called explicitly by a line in IOStartIOKit.cpp and not
    by the OSDefineMetaClassAndInit() mechanism, since the OSSymbol class
    is not guaranteed to be initialized first, and likewise for the
    OSSymbol pool. */

    static void initialize();

/*! @function init
    @abstract Initialize the IONetworkController instance.
    @discussion Instance variables are initialized to their default values,
    then super::init() is called.
    @param properties A dictionary object containing a property table.
    @result true on success, false otherwise. */ 

    virtual bool init(OSDictionary * properties);

/*! @function start
    @abstract Start the controller driver.
    @discussion Called when the controller was matched to a provider and
    has been selected to start running. IONetworkController will allocate
    resources and gather the controller's properties. No I/O will be
    triggered until the subclass attaches a client object from its own
    start method. Subclasses must override this method and call
    super::start() at the beginning of its implementation. They should
    also check the return value to make sure their superclass was
    started successfully. The resources allocated by IONetworkController
    include: An IOWorkLoop object, an IOCommandGate object to handle 
    synchronous requests, an OSSet to track our clients, and an optional
    IOOutputQueue object for output queueing.

    Tasks that are usually performed by a driver's start method are;
    resource allocation, hardware initialization, allocation of 
    IOEventSources and attaching them to an IOWorkLoop object,
    publishing a medium dictionary, and finally, attaching an
    interface object when the driver is ready to handle client
    requests.
    @param provider The provider that the controller was matched
    (and attached) to.
    @result true on success, false otherwise. */

    virtual bool start(IOService * provider);

/*! @function stop
    @abstract Stop the controller driver.
    @discussion The opposite of start(). The controller has been
    instructed to stop running. This method is called when the
    driver has been terminated. The stop() method should release
    resources and undo actions performed by start(). Subclasses
    must override this method and call super::stop() at the end
    of its implementation.
    @param provider The provider that the controller was matched
    (and attached) to. */

    void stop(IOService * provider);

/*! @function outputPacket
    @abstract Transmit a packet mbuf.
    @discussion If an IOOutputQueue was allocated and returned by 
    createOutputQueue(), then this method will be called by the queue object.
    Otherwise, an interface object will call this method directly upon 
    receiving an output packet from the network layer. When a queue object
    is not present, this method must be safe from multiple client threads,
    each pushing a packet to be sent on the wire.
    
    There is no upper limit on the number of mbufs, hence the number of
    memory fragments, in the mbuf chain provided. Drivers must be able to
    handle cases when the chain might exceed the limit supported by their
    DMA engines, and perform coalescing to copy the various memory fragments
    into a lesser number of fragments. This complexity can be hidden from
    a driver when an IOMBufMemoryCursor is used, which is able to convert
    a mbuf chain into a physical address scatter-gather list that will not
    exceed a specified number of physically contiguous memory segments.
    See IOMBufMemoryCursor.

    Packets may also be chained to form a packet chain. Although the
    network layer, through the interface object, will currently only
    send a single mbuf packet to the controller for each outputPacket()
    call, it is possible for this to change. When a queue object is used,
    the queue will automatically accept a single packet or a packet chain,
    but it will call outputPacket() for each packet removed from the queue.

    The implementation in IONetworkController performs no useful action
    and will drop all packets. A driver must always override this method.

    @param m The packet mbuf.
    @result A return code defined by the caller. */

    virtual UInt32 outputPacket(struct mbuf * m);

/*! @function getFeatureSet
    @discussion Report features supported by the controller.
    @result Returns 0. Drivers may override this method and return a mask
    containing all supported feature bits. */

    virtual UInt32 getFeatureSet() const;

/*! @function getFamilyFeatureSet
    @discussion Report family specific features supported by the controller.
    @result Drivers may override this method and return a mask containing
    all supported family feature bits. */

    virtual UInt32 getFamilyFeatureSet() const = 0;

/*! @function getVendorString
    @result Return a vendor string. i.e. "Apple" */

    virtual const char * getVendorString() const = 0;

/*! @function getModelString
    @result Return a string describing the model of the network controller.
    i.e. "BMac Ethernet" */

    virtual const char * getModelString() const = 0;

/*! @function getRevisionString
    @result Return a string describing the revision level of the 
    controller. */

    virtual const char * getRevisionString() const;

/*! @function getInfoString
    @result Return a string containing any additional information about
    the controller and/or driver. */

    virtual const char * getInfoString() const;

/*! @function getCurrentMedium
    @abstract Get the currently selected medium.
    @discussion Returns the currently selected medium object. If the driver
    has yet to assign an entry in its medium dictionary as the current medium 
    using the setCurrentMedium() method, then the driver's property table is 
    consulted and a default medium property (can be set by the user), is
    looked up and the corresponding entry in the medium dictionary is returned.
    Therefore, drivers can always call getCurrentMedium() to either get
    the current medium selected by the driver, or the default
    medium chosen by the user.
    @result The current medium entry from the medium dictionary, or 0
    if a matching entry was not found. */

    virtual const IONetworkMedium * getCurrentMedium() const;

/*! @function getMediumDictionary
    @abstract Returns the medium dictionary published by the driver.
    @discussion Returns the medium dictionary published by the driver
    through publishMediumDictionary(). Use copyMediumDictionary() to
    get a copy of the medium dictionary.
    @result The published medium dictionary, or 0 if the driver has not
    yet published a medium dictionary using publishMediumDictionary(). */

    virtual const OSDictionary * getMediumDictionary() const;

/*! @function copyMediumDictionary
    @abstract Returns a copy of the medium dictionary published by the driver.
    @discussion The caller is responsible for releasing the dictionary
    object returned. Use getMediumDictionary() to get a reference to the
    published medium dictionary instead of creating a copy.
    @result A copy of the medium dictionary, or 0 if the driver has not
    published a medium dictionary using publishMediumDictionary(). */

    virtual OSDictionary * copyMediumDictionary() const;

/*! @function syncRequest
    @abstract Perform a request action synchronously.
    @discussion Used both internally and also by clients to execute an
    arbitrary request action using the IOCommandGate's runAction()
    method. For client requests, where the client field is not equal to
    'this', the request is filtered by calling syncRequestFilter() to
    qualify the client request. This filter function must return true
    in order for the request to be accepted and the request action called.
    @param client The client (caller) of the synchronous request.
    @param target The target object that implements the request action.
    @param action The action to perform.
    @param ret    The return value from the action is written to the
                  integer with the provided address. The result is
                  not written if the request was rejected by the request
                  filter.
    @param arg0 Optional action argument.
    @param arg1 Optional action argument.
    @param arg2 Optional action argument.
    @param arg3 Optional action argument.
    @result kIOReturnNotReady if the client request was rejected by the filter.
    Otherwise kIOReturnSuccess is returned. */

    virtual IOReturn syncRequest(OSObject *     client,
                                 OSObject *     target,
                                 RequestAction  action,
                                 UInt32 *       ret  = 0,
                                 void *         arg0 = 0,
                                 void *         arg1 = 0,
                                 void *         arg2 = 0,
                                 void *         arg3 = 0);

/*! @function getOutputHandler
    @abstract Get the address of the method designated to handle output 
    packets.
    @result the address of the outputPacket() method. */

    virtual IOOutputAction getOutputHandler() const;

/*! @function doEnablePacketFilters
    @discussion Call enablePacketFilters() through syncRequest().
    See enablePacketFilters(). */

    virtual IOReturn doEnablePacketFilters(IOService * client,
                                           UInt32      filters,
                                           UInt32 *    activeFiltersP = 0);

/*! @function doGetPacketFilters
    @discussion Call getPacketFilters() through syncRequest().
    See getPacketFilters(). */

    virtual IOReturn doGetPacketFilters(IOService * client, UInt32 * filtersP);

/*! @function doEnable
    @discussion Call enable(IOService *) through syncRequest().
    See enable(). */

    virtual IOReturn doEnable(IOService * client);

/*! @function doDisable
    @discussion Call disable(IOService *) through syncRequest().
    See disable(). */

    virtual IOReturn doDisable(IOService * client);

/*! @function doGetControllerIndex
    @discussion Call getControllerIndex(IOService *) through syncRequest().
    See getControllerIndex(). */

    virtual IOReturn doGetControllerIndex(IOService * client,
                                          UInt32 *    index);

/*! @function doSetMaxTransferUnit
    @discussion Call setMaxTransferUnit() through syncRequest().
    See setMaxTransferUnit(). */

    virtual IOReturn doSetMaxTransferUnit(IOService * client, UInt32 mtu);

/*! @function doSelectMedium
    @discussion Call selectMedium() through syncRequest().
    See selectMedium(). */

    virtual IOReturn doSelectMedium(IOService *      client,
                                    const OSSymbol * mediumName);

/*! @function doSetOutputQueueCapacity
    @discussion Call setOutputQueueCapacity() through syncRequest().
    See setOutputQueueCapacity(). */

    virtual IOReturn doSetOutputQueueCapacity(IOService * client,
                                              UInt32      capacity);

/*! @function doGetOutputQueueCapacity
    @discussion Call getOutputQueueCapacity() through syncRequest().
    See getOutputQueueCapacity(). */

    virtual IOReturn doGetOutputQueueCapacity(IOService * client,
                                              UInt32 *    capacityP);

/*! @function doGetOutputQueueSize
    @discussion Call getOutputQueueSize() through syncRequest().
    See getOutputQueueSize(). */

    virtual IOReturn doGetOutputQueueSize(IOService * client,
                                          UInt32 *    sizeP);

/*! @function doFlushOutputQueue
    @discussion Call flushOutputQueue() through syncRequest().
    See flushOutputQueue(). */

    virtual IOReturn doFlushOutputQueue(IOService * client,
                                        UInt32 *    flushCountP);

/*! @function doPerformDiagnostics
    @discussion Call performDiagnostics() through syncRequest().
    See performDiagnostics(). */

    virtual IOReturn doPerformDiagnostics(IOService * client,
                                          UInt32 *    failureCode);

protected:

/*! @function free
    @abstract Free the IONetworkController instance.
    @discussion Free the IONetworkController instance and all allocated
    resources, then call super::free(). */

    virtual void free();

/*! @function setOutputQueueCapacity
    @abstract Adjust the capacity of the output queue.
    @discussion A client request to adjust the capacity of the driver's
    output queue (number of packets the queue can hold). If a driver does
    not override this method, then the default action is to forward the
    request to an IOOutputQueue object if it was created. Otherwise return
    kIOReturnUnsupported.
    @param capacity The new capacity of the output queue.
    @result kIOReturnSuccess on success, kIOReturnBadArgument if the
    specified capacity is invalid, or kIOReturnUnsupported if the
    function is not supported. */

    virtual IOReturn setOutputQueueCapacity(UInt32 capacity);

/*! @function getOutputQueueCapacity
    @abstract Get the capacity of the output queue.
    @discussion A client request to get the capacity of the driver's
    output queue. If a driver does not override this method, then the
    default action is to forward the request to an IOOutputQueue object
    if it was created. Otherwise return kIOReturnUnsupported.
    @param capacityP Address of an integer where the capacity
    shall be written to.
    @result kIOReturnSuccess on success, or kIOReturnUnsupported if an
    IOOutputQueue object was not created. */

    virtual IOReturn getOutputQueueCapacity(UInt32 * capacityP) const;

/*! @function getOutputQueueSize
    @abstract Get the number of packets in the output queue.
    @discussion A client request to get the number of packets currently held
    by the queue. If a driver does not override this method, then the default
    action is to forward the request to an IOOutputQueue object if it was 
    created. Otherwise return kIOReturnUnsupported.
    @param sizeP Address of an integer where the queue size shall be
           written to.
    @result kIOReturnSuccess on success, or kIOReturnUnsupported if an
    IOOutputQueue object was not created. */

    virtual IOReturn getOutputQueueSize(UInt32 * sizeP) const;

/*! @function flushOutputQueue
    @abstract Discard all packets in the output queue.
    @discussion A client request to flush all packets currently held by the
    queue, and return the number of packets discarded. If a driver does not
    override this method, then the default action is to forward the request
    to an IOOutputQueue object if it was created. Otherwise return
    kIOReturnUnsupported.
    @param flushCountP Address of an integer where the number of
    discarded packets shall be written to.
    @result kIOReturnSuccess on success, or kIOReturnUnsupported if an
    IOOutputQueue object was not created. */

    virtual IOReturn flushOutputQueue(UInt32 * flushCountP);

/*! @function ready
    @abstract An indication that the controller is ready to service
    clients.
    @discussion This method is called the first time that a controller
    driver calls attachInterface() or attachDebuggerClient(), which is
    an indication that the driver has been started and is ready to
    service client requests. IONetworkController uses this method to
    complete its initialization before any client objects are attached.
    @param provider The controller's provider.
    @result true on success, false otherwise. */

    virtual bool ready(IOService * provider);

/*! @function enable
    @abstract An enable request from an interface client.
    @discussion Called by an interface client to enable the controller.
    This method must bring up the hardware and enable event sources
    to prepare for packet transmission and reception. A driver should
    delay the allocation of most runtime resources until this method is
    called to conserve shared system resources.
    @param interface The interface client object that requested the enable.
    @result kIOReturnUnsupported. Driver may override this method and
    return kIOReturnSuccess on success, or an error code otherwise. */

    virtual IOReturn enable(IONetworkInterface * interface);

/*! @function disable
    @abstract A disable request from an interface client.
    @discussion Called by an interface object to disable the controller.
    This method should quiesce the hardware and disable event sources.
    Any resources allocated in enable() should also be deallocated.
    @param interface The interface object that requested the disable.
    @result kIOReturnUnsupported. Driver may override this method and
    return kIOReturnSuccess on success, or an error code otherwise. */

    virtual IOReturn disable(IONetworkInterface * interface);

/*! @function enable
    @abstract An enable request from a client.
    @discussion Handle an enable request from a client. The client
    object is typecasted using OSDynamicCast, and if the client is an
    IOKernelDebugger or an IONetworkInterface, then an overloaded enable
    method that takes a more specific argument is called. If the client
    matches neither type, a kIOReturnBadArgument is returned.
    A driver has the option of override this generic enable method,
    or the derived version.
    @param client The client object requesting the enable.
    @result The return value from the derived enable method, or
    kIOReturnBadArgument if the client's type is unknown. */

    virtual IOReturn enable(IOService * client);

/*! @function disable
    @abstract A disable request from a client.
    @discussion Handle an enable request from a client. The client
    object is typecasted using OSDynamicCast, and if the client is an
    IOKernelDebugger or an IONetworkInterface, then an overloaded disable
    method that takes a more specific argument is called. If the client
    matches neither type, a kIOReturnBadArgument is returned.
    A driver has the option of override this generic enable method,
    or the derived version.
    @param client The client object requesting the disable.
    @result The return from the derived disable method, or
    kIOReturnBadArgument if the client's type is unknown. */
    
    virtual IOReturn disable(IOService * client);

/*! @function getControllerIndex
    @abstract Return an ordinal number for multiport adapters.
    @discussion Return an ordinal number for multiport network adapters.
    The implementation in IONetworkController will work for PCI controllers
    behind a PCI-PCI bridge. This method exists solely to support the
    current interface naming scheme, and is likely to
    undergo changes or may disappear in the future.
    @param indexP The oridinal number should be written to the
           integer at this address.
    @result kIOReturnSuccess. */

    virtual IOReturn getControllerIndex(UInt32 * indexP) const;

/*! @function setMaxTransferUnit
    @abstract Change the controller's MTU size.
    @discussion A client request for the controller to change to
    a new MTU size.
    @param mtu The new MTU size requested.
    @result kIOReturnUnsupported. Drivers may override this method
    and return either kIOReturnSuccess to indicate that the new MTU size
    was accepted and is in effect, or an error to indicate failure. */

    virtual IOReturn setMaxTransferUnit(UInt32 mtu);

/*! @function performDiagnostics
    @abstract A request for the driver to perform hardware diagnostics.
    @discussion A client request for the driver to perform hardware 
    diagnostics and return the test result after completion.
    @param resultCodeP In addition to the return code, drivers may
    write a hardware specific result code to the integer at this
    address.
    
    @result kIOReturnSuccess if hardware passed all test, otherwise
    an appropriate error code should be returned. The default return
    is always kIOReturnUnsupported. */

    virtual IOReturn performDiagnostics(UInt32 * resultCodeP);

/*! @function publishCapabilities
    @abstract Publish controller's properties and capabilities.
    @discussion Discover and publish controller capabilities to the
    property table. This method is called by ready().
    @result true if all capabilities were discovered and published
    successfully, false otherwise. Returning false will prevent client
    objects from attaching to the controller since a property that
    a client depends on may be missing. */

    virtual bool publishCapabilities();

/*! @function publishMediumDictionary
    @abstract Publish a medium dictionary.
    @discussion Called by drivers to publish their medium dictionary.
    The dictionary consist of IONetworkMedium entries that represent
    the entire media selection supported by the hardware. This method
    will make a copy of the provided dictionary, then add the copy to
    the driver's property table. The dictionary provided can be
    released after this call returns. It is permissible to call
    this method multiple times, which may be necessary if the hardware's
    media capability changes dynamically. However, if this were not
    so, then drivers will typically call this method from its start() 
    implementation, after the hardware capability is discovered.

    Several methods depends on the presence of a medium dictionary.
    They should be called after the dictionary has been published.
    Those are:
        selectMedium()
        setCurrentMedium()
        getCurrentMedium()
        getMediumDictionary()
        copyMediumDictionary()
    
    Calling publishMediumDictionary() will cause a media change event
    to be delivered to all attached interface clients.
    @param mediumDict A dictionary containing IONetworkMedium objects.
    @result true if the dictionary is valid, and was successfully
    added to the property table, false otherwise. */

    virtual bool publishMediumDictionary(const OSDictionary * mediumDict);

/*! @function setCurrentMedium
    @abstract Designate an entry in the published medium dictionary as
    the currently selected medium.
    @discussion From the set of medium objects in the medium dictionary
    published by the driver, one of them can be designated as the
    currently selected medium. Drivers should call this method whenever
    their media selection changes. An entry in the driver's property
    table is updated to advertise the current medium.
    
    A media change event will be broadcasted to all attached interface
    clients when the current medium property changes.
    
    @param medium A medium object to promote as the current medium.
    @result true if the medium dictionary exists, the medium object
    provided matches an entry in this dictionary, and the property
    table update was successful, false otherwise. */

    virtual bool setCurrentMedium(const IONetworkMedium * medium);

/*! @function selectMedium
    @abstract Change the controller's medium selection.
    @discussion A client request for the controller to change the
    selected medium. Drivers may override this method and provide
    an implementation appropriate for its hardware, then call
    setCurrentMedium() to update the current medium property if
    a change occurred.
    @param medium An entry in the published medium dictionary.
    @result kIOReturnUnsupported. Drivers may override this method and
    return kIOReturnSuccess if the selected medium was activated,
    or an error code otherwise. */

    virtual IOReturn selectMedium(const IONetworkMedium * medium);

/*! @function setLinkStatus
    @abstract Report the link status and the active medium.
    @discussion Update the link status parameters published by the
    controller. Drivers should call this method whenever the link
    status changes. Never call this method from interrupt context
    since this method may block. An event will be sent to all
    attached interface objects when a change is detected.
    @param status Link status bits.
           See IONetworkMedium.h for defined link status bits.
    @param speed Link speed in units of bits per second.
    @param activeMedium A medium entry in the published medium dictionary
           where the link was established. This may not be the same as the
           current medium. See setCurrentMedium().
    @param data An OSData containing any additional link information.
    @result true if all link properties were successfully updated,
    false otherwise. */

    virtual bool setLinkStatus(UInt32                  status,
                               UInt64                  speed,
                               const IONetworkMedium * activeMedium,
                               OSData *                data = 0);

/*! @function syncRequestFilter
    @abstract Filter client requests sent to syncRequest().
    @discussion This method is called to qualify all client requests
    sent to syncRequest(). This implementation will either allow or
    refuse all requests, and this behavior is set by calling the 
    enableSyncRequest() or disableSyncRequest() methods. By default,
    all requests are allowed.
    @param client The client of the synchronous request.
    @param target The target object that implements the request action.
    @param action The action to perform.
    @param arg0 Action argument.
    @param arg1 Action argument.
    @param arg2 Action argument.
    @param arg3 Action argument.
    @result true to accept the request and allow the request action to be
    called, or false to refuse it. */

    virtual bool syncRequestFilter(OSObject *     client,
                                   OSObject *     target,
                                   RequestAction  action,
                                   void *         arg0,
                                   void *         arg1,
                                   void *         arg2,
                                   void *         arg3);

/*! @function enableSyncRequest
    @abstract Set syncRequestFilter() to accept all client requests.
    @discussion Enable all client requests sent to the syncRequest() method.
    Don't use this method if the driver overrides syncRequestFilter(). */

    virtual void enableSyncRequest();

/*! @function disableSyncRequest
    @abstract Set syncRequestFilter() to refuse all client requests.
    @discussion Disable all client requests sent to the syncRequest() method.
    Don't use this method if the driver overrides syncRequestFilter(). */

    virtual void disableSyncRequest();  

/*! @function getSyncRequestClient
    @abstract Get request client.
    @discussion Methods that are called by syncRequest() can call this
    to get the client object which initiated the request.
    @result The request client. If the caller's context does not indicate
    that it is running through syncRequest(), then 0 is returned. */

    virtual OSObject * getSyncRequestClient() const;

/*! @function handleOpen
    @abstract Handle a client open.
    @discussion Handle a client open on the controller object. IOService
    calls this method with the arbitration lock held. Subclasses
    should not override this method.
    @param client The client that is trying to open the controller.
    @param options Not used. See IOService.
    @param argument Not used. See IOService.
    @result true to accept the client open, false to refuse the open. */

    virtual bool handleOpen(IOService *  client,
                            IOOptionBits options,
                            void *       argument);

/*! @function handleClose
    @abstract Handle a client close.
    @discussion Handle a close from one of our client objects. IOService
    calls this method with the arbitration lock held. Subclasses
    should not override this method.
    @param client The client that has closed the controller.
    @param options Not used. See IOService. */

    virtual void handleClose(IOService * client, IOOptionBits options);

/*! @function handleIsOpen
    @abstract Query a client that has an open on the controller.
    @discussion This method is always called by IOService with the
    arbitration lock held. Subclasses should not override this method.
    @result true if the specified client, or any client if none is
    specified, presently has an open on this object. */

    virtual bool handleIsOpen(const IOService * client) const;

/*! @function attachInterface
    @abstract Attach a new interface client object.
    @discussion Create a new interface client object and attach it
    to the controller. The createInterface() method is called to
    perform the allocation and initialization, followed by a call to 
    configureInterface() to configure the interface. Both of these
    methods can be overridden by subclasses to customize the
    interface client attached. Drivers must call attachInterface()
    from its start() method, after it is ready to service client requests.
    @param interfaceP If successful (return value is true), then the
    interface object will be written to the handle provided.
    @param doRegister If true, then registerService() is called to register
    the interface, which will trigger the matching process, and cause the 
    interface to become registered with the network layer. For drivers that
    wish to delay the registration, and hold off servicing requests and data
    packets from the network layer, set doRegister to false and call 
    registerService() on the interface client when the controller becomes
    ready.
    @result true on success, false otherwise. */

    virtual bool attachInterface(IONetworkInterface ** interface,
                                 bool  doRegister = true);

    virtual bool attachNetworkInterface(IONetworkInterface ** interface,
                                        bool  doRegister = true);  // obsolete

/*! @function detachInterface
    @abstract Detach an interface client object.
    @discussion This method will check that the object provided is indeed
    an IONetworkInterface, and if so its terminate() method is called.
    The interface object will close and detach from its controller only
    after the network layer has removed all references to the data
    structures exposed by the interface.
    @param interface An interface object to be detached.
    @param sync If true, the interface is terminated synchronously.
           Note that this may cause detachInterface() to block
           for an indefinite period of time. */

    virtual void detachInterface(IONetworkInterface * interface,
                                 bool                 sync = false);

/*! @function getPacketBufferConstraints
    @abstract Get controller's packet buffer constraints.
    @discussion Called by start() to obtain the constraints on the
    memory buffer associated with each mbuf allocated through
    allocatePacket(). Drivers can override this method to specify
    their buffer constraints imposed by their bus master hardware.
    Note that outbound packets, those that originate from the
    network stack, are not subject to the constraints reported here.
    @param constraintsP A pointer to an IOPacketBufferConstraints
    structure that that this method is expected to initialize.
    See IOPacketBufferConstraints structure definition.
    */

    virtual void getPacketBufferConstraints(
                    IOPacketBufferConstraints * constraintsP) const;

/*! @function allocatePacket
    @discussion Allocate a mbuf packet with the given size. This method
    will always return a single mbuf unless the size requested (plus the
    alignment padding) is greater than MCLBYTES. The mbuf (or a mbuf
    chain) returned is aligned according to the constraints reported
    by getPacketBufferConstraints().
    
    The m_len and pkthdr.len fields in the mbuf is updated by this
    method, thus allowing the packet to be passed directly to an
    IOMbufMemoryCursor object in order to convert the mbuf to a
    scatter-gather list.

    @param size The desired size of the mbuf packet.
    @result The allocated mbuf packet, or 0 if allocation failed. */

    virtual struct mbuf * allocatePacket(UInt size);

/*! @function copyPacket
    @discussion Make a copy of a mbuf, and return the copy.
    The source mbuf is not modified.
    @param m The source mbuf.
    @param size The number of bytes to copy. If set to 0, then the entire
    source mbuf is copied (source length is taken from the m_pkthdr.len).
    @result A new mbuf created from the source packet. */

    virtual struct mbuf * copyPacket(const struct mbuf * m, UInt size = 0);

/*! @function replacePacket
    @discussion Replace the mbuf pointed by the given pointer with
    another mbuf. Drivers can call this method to replace a mbuf before
    passing the original mbuf, which contains a received frame, to the
    network layer.
    @param mp A pointer to the original mbuf that shall be updated by this
    method to point to the new mbuf.
    @param size If size is 0, then the new mbuf shall have the same size
    as the original mbuf that is being replaced. Otherwise, the new
    mbuf shall have the size specified here.
    @result If mbuf allocation was successful, then the replacement will
    take place and the original mbuf will be returned. Otherwise, a NULL
    is returned. */

    virtual struct mbuf * replacePacket(struct mbuf ** mp, UInt size = 0);

/*! @function replaceOrCopyPacket
    @discussion Either replace or copy the source mbuf given depending
    on the amount of data in the source mbuf. This method will either
    perform a copy or replace the source mbuf, whichever is more
    time efficient. If replaced, then the original mbuf is returned, and
    a new mbuf is allocated to take its place. If copied, the source mbuf is
    left intact, while a copy is returned that is just big enough to hold
    all the data from the source mbuf.
    @param mp A pointer to the source mbuf that may be updated by this
    method to point to the new mbuf if replaced.
    @param rcvlen The number of data bytes in the source mbuf.
    @param replacedP Pointer to a bool that is set to true if the
           source mbuf was replaced, or set to false if the
           source mbuf was copied.
    @result A replacement or a copy of the source mbuf, 0 if mbuf
    allocation failed. */

    virtual struct mbuf * replaceOrCopyPacket(struct mbuf ** mp,
                                              UInt           rcvlen,
                                              bool *         replacedP);

/*! @function freePacket
    @discussion Release the mbuf back to the free pool.
    @param m The mbuf to be freed. */

    virtual void freePacket(struct mbuf * m);

/*! @function createInterface
    @abstract Create an interface client object.
    @discussion Create a new IONetworkInterface instance.
    This method is called by attachInterface() to perform the
    allocation and initialization of a new interface client object.
    A family specific subclass of IONetworkController must implement
    this method and return a matching interface instance. For example,
    IOEthernetController implements this method and returns an
    IOEthernetInterface instance.
    @result The allocated interface object. */

    virtual IONetworkInterface * createInterface() = 0;

/*! @function configureInterface
    @abstract Configure an interface client object.
    @discussion Configure an interface object created through
    createInterface(). IONetworkController will register
    its output handler with the interface object provided.
    Subclasses may override this method to customize the interface object.
    Once the interface is registered and opened by a client, it will
    refuse changes to its properties. And since this method is called
    before the interface has become registered, this is a final
    opportunity for the controller to configure the interface.
    @param interface The interface object to be configured.
    @result true if configuration was successful, false otherwise
    (this will cause attachInterface() to fail). */

    virtual bool configureInterface(IONetworkInterface * interface);

    // obsolete
    virtual bool configureNetworkInterface(IONetworkInterface * interface);

/*! @function createOutputQueue
    @abstract Create an IOOutputQueue to handle output queueing.
    @discussion Called by start() to create an IOOutputQueue instance
    to handle output queueing. The default implementation will always
    return 0, hence no output queue will be created. A driver may override
    this method and return a subclass of IOOutputQueue. IONetworkController
    will keep a reference to the queue created, and will release the 
    object when IONetworkController is freed. Also see getOutputQueue().
    @result A newly allocated and initialized IOOutputQueue instance. */

    virtual IOOutputQueue * createOutputQueue();
    virtual IOOutputQueue * allocateOutputQueue();  // obsolete

/*! @function getOutputQueue
    @abstract Get the IOOutputQueue object created by createOutputQueue().
    @result Return the output queue created by createOutputQueue(). */

    virtual IOOutputQueue * getOutputQueue() const;

/*! @function getWorkLoop
    @abstract Get the IOWorkLoop object created by IONetworkController.
    @discussion An IOWorkLoop object is created by the start() method.
    Drivers can call getWorkLoop() to obtain a reference to the
    IOWorkLoop object, and attach their event sources, such
    as IOTimerEventSource or IOInterruptEventSource.
    See IOWorkLoop.
    @result The IOWorkLoop object created by IONetworkController. */

    virtual IOWorkLoop * getWorkLoop() const;

/*! @function getCommandGate
    @abstract Get the IOCommandGate object created by IONetworkController.
    @discussion An IOCommandGate is created and attached to an
    IOWorkLoop by the start() method. This IOCommandGate object is used
    to handle client requests issued through the syncRequest() method.
    Subclasses that need an IOCommandGate should try to use the object
    returned by this method, rather than creating a new instance.
    See IOCommandGate.
    @result The IOCommandGate object created by IONetworkController. */

    virtual IOCommandGate * getCommandGate() const;

/*! @function broadcastEvent
    @abstract Send an event to all interface client objects.
    @discussion Broadcast an event to all attached interface objects.
    This is equivalent to calling the IONetworkInterface::inputEvent()
    method for all interfaces.
    
    IONetworkController uses this method to broadcast link and media
    events. Drivers will usually call the inputEvent() method directly
    since it is more efficient, and most drivers will only attach a
    single interface client.
    
    @param type Event type.
    @param arg Event argument.
    @result true if the event was delivered, false if an error occurred
    (unable to perform object allocation) and the event was not delivered. */

    virtual bool broadcastEvent(UInt32 type, void * arg = 0);

/*! @function getPacketFilters
    @abstract Get the set of packet filters supported by the controller.
    @discussion A subclass must implement this method and report its
    supported filter set. See IOPacketFilter enum for the list of defined
    packet filters.
    @param filtersP A mask of supported filters should be written to the
    integer with this address.
    @result kIOReturnSuccess on success, or an error to indicate
    failure to discover the hardware supported filters. */

    virtual IOReturn getPacketFilters(UInt32 * filtersP) = 0;

/*! @function enablePacketFilters
    @abstract Enable a set of packet filters supported by the controller.
    @discussion After calling getPacketFilters() to gather the set of
    supported packet filters, a client may issue a request to enable a
    (sub)set of filters from the supported set.
    @param filters Each bit that is set indicates a particular filter that
           should be enabled. Filter bits that cleared should be disabled.
    @param activeFiltersP Must be updated by this method to contain the filter
           set that was activated. Ideally, it should be the same as the filter 
           set specified by the first argument.
    @result kIOReturnSuccess on success, otherwise an error code is
    returned. If (*activeFiltersP != filters), then an error is expected. */

    virtual IOReturn enablePacketFilters(UInt32   filters,
                                         UInt32 * activeFiltersP) = 0;

/*! @function attachDebuggerClient
    @abstract Attach a new IOKernelDebugger client object. Attaching
    a debugger client implies that the driver supports the kernel
    debugging interface, and must implement the two polled-mode entry
    points. See sendPacket() and receivePacket().
    @discussion Allocate and attach a new IOKernelDebugger client object.
    @param debuggerP An IOKernelDebugger handle that is updated by this
           method to contain the allocated IOKernelDebugger instance.
    @result true on success, false otherwise. */

    virtual bool attachDebuggerClient(IOKernelDebugger ** debuggerP);

/*! @function detachDebuggerClient
    @abstract Detach an IOKernelDebugger client object.
    @discussion Detach and terminate the IOKernelDebugger client object
    provided. A synchronous termination is issued, and this method returns
    after the client has been terminated.
    @param debugger The IOKernelDebugger instance to be detached and
           terminated. If the argument provided is NULL or is not an
           IOKernelDebugger, this method will return immediately. */

    virtual void detachDebuggerClient(IOKernelDebugger * debugger);

/*! @function enable
    @abstract An enable request from an IOKernelDebugger client.
    @discussion This method is called when an open is received from an
    IOKernelDebugger client. Drivers that wish to provide debugging
    services must override this method and setup the hardware to
    support the polled-mode send and receive methods; receivePacket()
    and sendPacket(). Debug capable drivers may also override the
    more generic enable/disable calls that take an IOService argument.
    @param debugger The IOKernelDebugger client that issued the open.
    @result kIOReturnSuccess. The driver method must return kIOReturnSuccess
    to allow the debugger open, anything else will cause the debugger open
    to fail and the attachDebuggerClient() method will return false. */

    virtual IOReturn enable(IOKernelDebugger * debugger);
    virtual IOReturn handleDebuggerOpen(IOKernelDebugger * debugger);

/*! @function disable
    @abstract A disable request from an IOKernelDebugger client.
    @discussion This method is called when a close is received from an
    IOKernelDebugger client. A driver which implements
    enable(IOKernelDebugger *) should also implement this method to
    disable hardware support for the polled-mode send and receive methods.
    @param debugger The IOKernelDebugger client that issued the close.
    @result kIOReturnSuccess. The driver method should return a status
    from the disable operation. */

    virtual IOReturn disable(IOKernelDebugger * debugger);
    virtual IOReturn handleDebuggerClose(IOKernelDebugger * debugger);

/*! @function reserveDebuggerLock
    @abstract Take the global debugger lock.
    @discussion This method should not be used. Call the
    lock() method provided by IOKernelDebugger instead. */
    
    void reserveDebuggerLock();

/*! @function releaseDebuggerLock
    @abstract Release the global debugger lock.
    @discussion This method should not be used. Call the
    unlock() method provided by IOKernelDebugger instead. */

    void releaseDebuggerLock();

/*! @function receivePacket
    @abstract Debugger polled-mode receive handler.
    @discussion This method must be implemented by a driver that supports
    kernel debugging. After a debugger client is attached through
    attachDebuggerClient(), this method will be called by the debugger
    object to poll for a incoming packet when the debugger is active.
    This method can be called from an interrupt context, and the
    driver must never block or perform any memory allocation. The
    receivePacket() method in IONetworkController is used as a placeholder
    and should never be called. A driver that attaches a debugger client
    must override this method.
    @param pkt Pointer to a receive buffer where the received packet should
           be stored to. The buffer has room for 1518 bytes.
    @param pkt_len The length of the received packet must be written to the
           integer pointed by pkt_len.
    @param timeout The maximum amount of time in milliseconds to poll for
           a packet to arrive before this method must return. */ 

    virtual void receivePacket(void * pkt, UInt * pkt_len, UInt timeout);

/*! @function sendPacket
    @abstract Debugger polled-mode transmit handler.
    @discussion This method must be implemented by a driver that supports
    kernel debugging. After a debugger client is attached through
    attachDebuggerClient(), this method will be called by the debugger
    object to send an outbound packet generated by the debugger.
    This method can be called from an interrupt context, and the
    driver must never block or perform any memory allocation. The
    sendPacket() method in IONetworkController is used as a placeholder
    and should never be called. A driver that attaches a debugger client
    must override this method.
    @param pkt Pointer to a transmit buffer containing the packet to be sent.
    @param pkt_len The amount of data in the transmit buffer. */

    virtual void sendPacket(void * pkt, UInt pkt_len);
};

#define IONetworkAction IONetworkController::RequestAction

inline bool
IONetworkController::attachNetworkInterface(IONetworkInterface ** interface,
                                            bool  doRegister = true)
{
    return attachInterface(interface, doRegister);
}

#endif /* !_IONETWORKCONTROLLER_H */