/ duct-tape / xnu / iokit / IOKit / IOKernelReporters.h
IOKernelReporters.h
   1  /*
   2   * Copyright (c) 2012-2016 Apple Inc.  All Rights Reserved.
   3   *
   4   * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
   5   *
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. The rights granted to you under the License
  10   * may not be used to create, or enable the creation or redistribution of,
  11   * unlawful or unlicensed copies of an Apple operating system, or to
  12   * circumvent, violate, or enable the circumvention or violation of, any
  13   * terms of an Apple operating system software license agreement.
  14   *
  15   * Please obtain a copy of the License at
  16   * http://www.opensource.apple.com/apsl/ and read it before using this file.
  17   *
  18   * The Original Code and all software distributed under the License are
  19   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  20   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  21   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  22   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  23   * Please see the License for the specific language governing rights and
  24   * limitations under the License.
  25   *
  26   * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  27   */
  28  
  29  /*
  30   * FILE: IOReporter.h
  31   * AUTH: Cyril & Soren (Core OS)
  32   * DATE: 2012-2013 (Copyright Apple Inc.)
  33   * DESC: IOReporting interfaces for I/O Kit drivers
  34   *
  35   */
  36  
  37  #ifndef _IOKERNEL_REPORTERS_H_
  38  #define _IOKERNEL_REPORTERS_H_
  39  
  40  #include <machine/limits.h>
  41  
  42  #include <libkern/c++/OSPtr.h>
  43  #include <IOKit/IOLib.h>
  44  #include <IOKit/IOService.h>
  45  #include <IOKit/IOLocks.h>
  46  #include <IOKit/IOBufferMemoryDescriptor.h>
  47  
  48  #include <IOKit/IOReportTypes.h>
  49  #include <IOKit/IOKernelReportStructs.h>
  50  
  51  #include <libkern/c++/OSPtr.h>
  52  
  53  typedef OSDictionary IOReportLegendEntry;
  54  
  55  /*******************************
  56  *   TOC: this file contains
  57  *    1. Introduction
  58  *    2a. IOReporter class declaration (public & non-public members)
  59  *    2b. static IOReporter methods unrelated to the class
  60  *    3. IOReporter subclass declarations (public & non-public members)
  61  *    4. IOReportLegend class declaration
  62  *******************************/
  63  
  64  /*!
  65   *  1. Introduction
  66   *
  67   *  IOReporting is a mechanism for I/O Kit drivers to gather statistics
  68   *  (or other information) and make it available to various "observers,"
  69   *  which are generally in user space. Requests for information come
  70   *  through two new IOService methods: ::configureReport(...) and
  71   *  ::updateReport(...). While not required (see IOReportTypes.h), drivers
  72   *  will generally use IOReporter subclass instances to track the requested
  73   *  information and respond to IOReporting requests. Drivers can use these
  74   *  classes to track information, either all the time or between "enable"
  75   *  and "disable" calls to IOService::configureReport().
  76   *
  77   *  Available information is organized into "channels." A channel is
  78   *  uniquely identified by both driver (registry) ID and a 64-bit channel
  79   *  ID. One way drivers can advertise their channels is by publishing
  80   *  "legends" in the I/O Kit registry. In addition to collecting
  81   *  information and responding to queries, IOReporter objects can produce
  82   *  legend entries describing their channels. The IOReportLegend class
  83   *  helps manage legend entries from multiple reporter objects as well
  84   *  as with grouping channels logically for observers.
  85   *
  86   *  An important basic constraint of the current implementation is that
  87   *  all channels reported by a particular reporter instance must share all
  88   *  traits except channel ID and name.  Specifically, the channel type
  89   *  (including report class, categories, & size) and units.  Additionally,
  90   *  IOHistogramReporter currently only supports one channel at a time.
  91   *
  92   *  Currently, ::{configure/update}Report() can be called any time between
  93   *  when a driver calls registerService() and when free() is called on
  94   *  your driver. 12960947 tracks improvements / recommendations for
  95   *  correctly handling these calls during termination.
  96   *
  97   * Locking
  98   *  IOReporting only imposes concurrent access constraints when multiple
  99   *  threads are accessing the same object.  Three levels of constraint apply
 100   *  depending on a method's purpose:
 101   *  1. Allocation/Teardown - same-instance concurrency UNSAFE, MAY BLOCK
 102   *  2. Configuration - same-instance concurrency SAFE, MAY BLOCK
 103   *  3. Update - same-instance concurrency SAFE, WILL NOT BLOCK
 104   *
 105   *  Configuration requires memory management which can block and must
 106   *  be invoked with interrupts ENABLED (for example, NOT in the interrupt
 107   *  context NOR with a spin lock -- like IOSimpleLock -- held).
 108   *
 109   *  Updates can be performed with interrupts disabled, but clients should
 110   *  take into account that IOReporters' non-blocking currenency is achieved
 111   *  with IOSimpleLockLockDisable/UnlockEnableInterrupts(): that is, by
 112   *  disabling interrupts and taking a spin lock.  While IOReporting will
 113   *  never hold a lock beyond a call into it, some time may be spent within
 114   *  the call spin-waiting for the lock.  Clients holding their own
 115   *  spin locks should carefully consider the impact of IOReporting's
 116   *  (small) additional latency before calling it while holding a spin lock.
 117   *
 118   *  The documentation for each method indicates any concurrency guarantees.
 119   */
 120  
 121  
 122  /*********************************/
 123  /*** 2a. IOReporter Base Class ***/
 124  /*********************************/
 125  
 126  class IOReporter : public OSObject
 127  {
 128  	OSDeclareDefaultStructors(IOReporter);
 129  
 130  protected:
 131  /*! @function   IOReporter::init
 132   *   @abstract   base init() method, called by subclass initWith() methods
 133   *
 134   *   @param  reportingService - IOService associated with all channels
 135   *   @param  channelType - type info for all channels (element_idx = 0)
 136   *   @param  unit - description applied for all channels
 137   *   @result     true on success, false otherwise
 138   *
 139   *   @discussion
 140   *       init() establishes the parameters of all channels for this reporter
 141   *       instance. Any channels added via addChannel() will be of this type
 142   *       and have this unit.
 143   *
 144   *       IOReporter clients should use the static <subclass>::with() methods
 145   *       below to obtain fully-initialized reporter instances.  ::free()
 146   *       expects ::init() to have completed successfully.  On failure, any
 147   *       allocations are cleaned up.
 148   *
 149   *   Locking: same-instance concurrency UNSAFE
 150   */
 151  	virtual bool init(IOService *reportingService,
 152  	    IOReportChannelType channelType,
 153  	    IOReportUnit unit);
 154  
 155  public:
 156  
 157  /*! @function   IOReporter::addChannel
 158   *   @abstract   add an additional, similar channel to the reporter
 159   *
 160   *   @param  channelID - identifier for the channel to be added
 161   *   @param  channelName - an optional human-readble name for the channel
 162   *   @result     appropriate IOReturn code
 163   *
 164   *   @discussion
 165   *       The reporter will allocate memory to track a new channel with the
 166   *       provided ID and name (if any).  Its other traits (type, etc) will
 167   *       be those provided when the reporter was initialized.  If no channel
 168   *       name is provided and the channelID consists solely of ASCII bytes,
 169   *       those bytes (ignoring any NUL bytes) will be used as the
 170   *       human-readable channel name in user space.  The IOREPORT_MAKEID()
 171   *       macro in IOReportTypes.h can be used to create ASCII channel IDs.
 172   *
 173   *   Locking: same-instance concurrency SAFE, MAY BLOCK
 174   */
 175  	IOReturn addChannel(uint64_t channelID, const char *channelName = NULL);
 176  
 177  /*! @function   IOReporter::createLegend
 178   *   @abstract   create a legend entry represending this reporter's channels
 179   *   @result     An IOReportLegendEntry object or NULL on failure.
 180   *   @discussion
 181   *       All channels added to the reporter will be represented
 182   *       in the resulting legend entry.
 183   *
 184   *       Legends must be published togethar as an array under the
 185   *       kIOReportLegendKey in the I/O Kit registry.  The IOReportLegend
 186   *       class can be used to properly combine legend entries from multiple
 187   *       reporters as well as to put channels into groups of interest to
 188   *       observers.  When published, individual legend entries share
 189   *       characteristics such as group and sub-group.  Multiple IOReporter
 190   *       instances are required to produce independent legend entries which
 191   *       can then be published with different characteristics.
 192   *
 193   *       Drivers wishing to publish legends should do so as part of their
 194   *       ::start() routine.  As superclasses *may* have installed legend
 195   *       entries, any existing existing legend should be retrieved and
 196   *       IOReportLegend used to merge it with the new entries.
 197   *
 198   *       Recommendations for best practices are forthcoming.
 199   *
 200   *       Instead of calling createLegend on your reporter object and then
 201   *       appending it manually to IOReportLegend, one may prefer to call
 202   *       IOReportLegend::appendReporterLegend which creates and appends a
 203   *       reporter's IOReportLegendEntry in a single call.
 204   *
 205   *   Locking: same-instance concurrency SAFE, MAY BLOCK
 206   */
 207  	OSPtr<IOReportLegendEntry> createLegend(void);
 208  
 209  /*! @function   IOReporter::configureReport
 210   *   @abstract   track IOService::configureReport(), provide sizing info
 211   *
 212   *   @param  channelList - channels to configure
 213   *   @param  action - enable/disable/size, etc (see IOReportTypes.h)
 214   *   @param  result - *incremented* for kIOReportGetDimensions
 215   *   @param  destination - action-specific default destination
 216   *   @result     appropriate IOReturn code
 217   *
 218   *   @discussion
 219   *       Any time a reporting driver's ::configureReport method is invoked,
 220   *       this method should be invoked on each IOReporter that is being
 221   *       used by that driver to report channels in channelList.
 222   *
 223   *       Any channels in channelList which are not tracked by this reporter
 224   *       are ignored.  ::configureReport(kIOReportGetDimensions) expects
 225   *       the full size of all channels, including any reported by
 226   *       superclasses.  It is valid to call this routine on multiple
 227   *       reporter objects in succession and they will increment 'result'
 228   *       to provide the correct total.
 229   *
 230   *       In the initial release, this routine is only required to calculate
 231   *       the response to kIOReportGetDimensions, but in the future it will
 232   *       will enable functionality like "triggered polling" via
 233   *       kIOReportNotifyHubOnChange.  Internally, it is already keeping
 234   *       track of the number of times each channel has been enabled and
 235   *       disabled.  13073064 tracks adding a method to see whether any
 236   *       channels are currently being observed.
 237   *
 238   *       The static IOReporter::configureAllReports() will call this method
 239   *       on multiple reporters grouped in an OSSet.
 240   *
 241   *   Locking: same-instance concurrency SAFE, MAY BLOCK
 242   */
 243  	IOReturn configureReport(IOReportChannelList *channelList,
 244  	    IOReportConfigureAction action,
 245  	    void *result,
 246  	    void *destination);
 247  
 248  /*! @function   IOReporter::updateReport
 249   *   @abstract   Produce standard reply to IOService::updateReport()
 250   *
 251   *   @param  channelList - channels to update
 252   *   @param  action - copy/trace data (see IOReportTypes.h)
 253   *   @param  result - action-specific return value (e.g. size of data)
 254   *   @param  destination - destination for this update (action-specific)
 255   *   @result     appropriate IOReturn code
 256   *
 257   *   @discussion
 258   *       This method searches channelList for channels tracked by this
 259   *       reporter, writes the corresponding data into 'destination', and
 260   *       updates 'result'.  It should be possible to pass a given set of
 261   *       IOService::updateReport() arguments to any and all reporters as
 262   *       well as to super::updateReport() and get the right result.
 263   *
 264   *       The static IOReporter::updateAllReports() will call this method
 265   *       on an OSSet of reporters.
 266   *
 267   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
 268   */
 269  	IOReturn updateReport(IOReportChannelList *channelList,
 270  	    IOReportConfigureAction action,
 271  	    void *result,
 272  	    void *destination);
 273  
 274  /*! @function   IOReporter::free
 275   *   @abstract   Releases the object and all its resources.
 276   *
 277   *   @discussion
 278   *       ::free() [called on last ->release()] assumes that init() [called
 279   *       by static ::with() methods] has completed successfully.
 280   *
 281   *   Locking: same-instance concurrency UNSAFE
 282   */
 283  	virtual void free(void) APPLE_KEXT_OVERRIDE;
 284  
 285  /*! @function	IOReporter::init
 286   *   @abstract	Initialize global state
 287   *
 288   *   @discussion
 289   *	::initialize() [called during IOStartIOKit] initializes all global
 290   *	state for IOReporter objects.
 291   *
 292   */
 293  	static void initialize(void);
 294  
 295  
 296  /*********************************/
 297  /*** 2b. Useful Static Methods ***/
 298  /*********************************/
 299  
 300  /* The following static functions are intended to simplify the management
 301   * of multiple reporters.  They may be superseded in the future by an
 302   * IOReportManager class.
 303   */
 304  
 305  /*! @function   IOReporter::configureAllReports
 306   *   @abstract   call configureReport() on multiple IOReporter objects
 307   *
 308   *   @param  reporters - OSSet of IOReporter objects
 309   *   @param  channelList - full list of channels to configure
 310   *   @param  action - enable/disable/size, etc
 311   *   @param  result - action-specific returned value
 312   *   @param  destination - action-specific default destination
 313   *   @result     success if all objects successfully complete
 314   *               IOReporter::configureReport()
 315   *
 316   *   @discussion
 317   *       The OSSet must only contain IOReporter instances.  The presence
 318   *       of non-IOReporter instances will cause this function to return
 319   *       kIOReturnBadArgument.  If any reporter returns an error, the
 320   *       function will immediately return that error.
 321   *
 322   *       Per the IOReporter::configureReport() documentation, each
 323   *       reporter will search channelList for channels it is reporting
 324   *       and provide a partial response.
 325   */
 326  	static IOReturn configureAllReports(OSSet *reporters,
 327  	    IOReportChannelList *channelList,
 328  	    IOReportConfigureAction action,
 329  	    void *result,
 330  	    void *destination);
 331  // FIXME: just put the function (inline-ish) here?
 332  
 333  /*! @function   IOReporter::updateAllReports
 334   *   @abstract   call updateReport() on multiple IOReporter objects
 335   *
 336   *   @param  reporters - OSSet of IOReporter objects
 337   *   @param  channelList - full list of channels to update
 338   *   @param  action - type/style of update
 339   *   @param  result - returned details about what was updated
 340   *   @param  destination - destination for this update (action-specific)
 341   *   @result     IOReturn code
 342   *   @discussion
 343   *       The OSSet must only contain IOReporter instances.  The presence
 344   *       of non-IOReporter instances will cause this function to return
 345   *       kIOReturnBadArgument.  If any reporter returns an error, the
 346   *       function will immediately return that error.
 347   *
 348   *       Per the IOReporter::configureReport() documentation, each
 349   *       reporter will search channelList for channels it is reporting
 350   *       and provide a partial response.
 351   */
 352  	static IOReturn updateAllReports(OSSet *reporters,
 353  	    IOReportChannelList *channelList,
 354  	    IOReportConfigureAction action,
 355  	    void *result,
 356  	    void *destination);
 357  // FIXME: just put the function (inline-ish) here?
 358  
 359  
 360  /*  Protected (subclass-only) Methods
 361   *
 362   *   General subclassing is not encouraged as we intend to improve
 363   *   internal interfaces.  If you need something that might require
 364   *   a subclass, please file a bug against IOReporting/X and we will
 365   *   help you.
 366   *
 367   *   One important concept for sub-classes (not clients) is that report
 368   *   data is stored in IOReportElement structures (see IOReportTypes.h).
 369   */
 370  protected:
 371  
 372  /*! @function   IOReporter::lockReporterConfig
 373   *   @function   IOReporter::unlockReporterConfig
 374   *   @abstract   prevent concurrent reconfiguration of a reporter
 375   *
 376   *   @discussion
 377   *       lockReporterConfig() takes a mutex-based lock intended to prevent
 378   *       concurrent access to the reporter's configuration.  It is not
 379   *       intended to prevent updates to the reporter's data.  As long as
 380   *       all other requirements are met, it is safe to simultaneously hold
 381   *       both the configuration and data locks on a single reporter.
 382   *
 383   *       lockReporterConfig() is used by routines such as addChannel().
 384   *       See also lockReporter() and ::handle*Swap*() below.
 385   */
 386  	void lockReporterConfig(void);
 387  	void unlockReporterConfig(void);
 388  
 389  /*! @function   IOReporter::lockReporter
 390   *   @function   IOReporter::unlockReporter
 391   *   @abstract   prevent concurrent access to a reporter's data
 392   *
 393   *   @discussion
 394   *       This method grabs a lock intended to control access the reporter's
 395   *       reporting data.  Sub-classes maninupating internal report values
 396   *       must make sure the reporter is locked (usually by the most generic
 397   *       public interface) before calling getElementValues(),
 398   *       copyElementValues(), or setElementValues().
 399   *
 400   *       Subclasses should ensure that this lock is taken exactly once
 401   *       before directly accessing reporter data.  For example,
 402   *       [virtual] IOFooReporter::handleSetFoo(.) {
 403   *           // assert(lock_held)
 404   *           getElementValues(1..)
 405   *           getElementValues(3..)
 406   *           getElementValues(5..)
 407   *           [calculate]
 408   *           setElementValues(6..)
 409   *       }
 410   *       IOFooReporter::setFoo(.) {      // not virtual
 411   *           lockReporter()
 412   *           handleSetFoo(.)
 413   *           unlockReporter()
 414   *       }
 415   *
 416   *       IOReporter::handle*() use lockReporter() similarly.  For example,
 417   *       the lock is taken by IOReporter::updateReport() and is already
 418   *       held by the time any ::updateChannelValues() methods are called.
 419   *
 420   *       Subclasses cannot call this routine if the lock is already held.
 421   *       That's why IOReporting generally only calls it from non-virtual
 422   *       public methods.  In particular, this method should not be called
 423   *       it from ::handle*() methods which exist to allow override after
 424   *       the lock is taken.
 425   *
 426   *       Because lockReporter() uses a spin lock, it is SAFE to use in the
 427   *       interrupt context.  For the same reason, however, it is UNSAFE
 428   *       to perform any blocking blocking operations (including memory
 429   *       allocations) while holding this lock.
 430   */
 431  	void lockReporter(void);
 432  	void unlockReporter(void);
 433  
 434  /*!
 435   *   @discussion
 436   *       The ::handle*Swap* functions allow subclasses to safely reconfigure
 437   *       their internal state.  A non-virtual function handles locking
 438   *       and invokes the functions in order:
 439   *       - lockReporterConfig()  // protecting instance vars but not content
 440   *       - prepare / allocate buffers of the new size
 441   *       - if error, bail (unlocking, of course)
 442   *
 443   *       - lockReporter()        // protecting data / blocking updates
 444   *       - swap: preserve continuing data / install new buffers
 445   *       - unlockReporter()
 446   *
 447   *       - deallocate now-unused buffers
 448   *       - unlockReporterConfig()
 449   */
 450  /*! @function   IOReporter::handleSwapPrepare
 451   *   @abstract   allocate memory in preparation for an instance variable swap
 452   *
 453   *   @param newNChannels   target number of channels
 454   *   @result     IOReturn code
 455   *
 456   *   @discussion
 457   *       ::handleSwapPrepare() is responsible for allocating appropriately-
 458   *       sized buffers (based on the new number of channels) and storing
 459   *       them in _swap* instance variables.  If returning and error, it
 460   *       must deallocate any buffers and set to NULL any _swap* variables.
 461   *
 462   *   Locking: The caller must ensure that the *config* lock is HELD but
 463   *            that the reporter (data) lock is *NOT HELD*.
 464   */
 465  	virtual IOReturn handleSwapPrepare(int newNChannels);
 466  
 467  /*! @function   IOReporter::handleAddChannelSwap
 468   *   @abstract   update primary instance variables with new buffers
 469   *
 470   *   @param channel_id   ID of channel being added
 471   *   @param symChannelName   optional channel name, in an allocated object
 472   *   @result     IOReturn code
 473   *
 474   *   @discussion
 475   *       handlAddChannelSwap() replaces the primary instance variables
 476   *       with buffers allocated in handlePrepareSwap().  It copies the the
 477   *       existing data into the appropriate portion of the new buffers.
 478   *       Because it is specific to adding one channel, it assumes that the
 479   *       target number of channels is one greater than the current value
 480   *       of _nChannels.
 481   *
 482   *       IOReporter::handleAddChannelSwap() increments _nElements and
 483   *       _nChannels.  To ensure that these variables describe the current
 484   *       buffers throughout ::handle*Swap(), subclasses overriding this
 485   *       method should call super::handleAddChannelSwap() after swapping
 486   *       their own instance variables.
 487   *
 488   *       If returning an error, all implementations should leave their
 489   *       instance variables as they found them (*unswapped*).  That ensures
 490   *       handleSwapCleanup() cleans up the unused buffers regardless of
 491   *       whether the swap was complete.
 492   *
 493   *       Pseudo-code incorporating these suggestions:
 494   *       res = <err>; swapComplete = false;
 495   *       if (<unexpected>)       goto finish
 496   *       tmpBuf = _primaryBuf; _primaryBuf = _swapBuf; _swapBuf = _primaryBuf;
 497   *       ...
 498   *       swapComplete = true;
 499   *       res = super::handle*Swap()
 500   *       ...
 501   *       finish:
 502   *       if (res && swapComplete)    // unswap
 503   *
 504   *   Locking: The caller must ensure that BOTH the configuration and
 505   *            reporter (data) locks are HELD.
 506   */
 507  	virtual IOReturn handleAddChannelSwap(uint64_t channel_id,
 508  	    const OSSymbol *symChannelName);
 509  
 510  /*! @function   IOReporter::handleSwapCleanup
 511   *   @abstract   release and forget unused buffers
 512   *
 513   *   @param swapNChannels   channel-relative size of the _swap buffers
 514   *
 515   *   @discussion
 516   *       ::handleSwapCleanup() is responsible for deallocating the buffers
 517   *       no longer used after a swap.  It must always be called if
 518   *       SwapPrepare() completes successfully.  Because bufers may be
 519   *       swapped in and out of existance, the _swap* variables may be
 520   *       NULL and should be set to NULL when complete.
 521   *
 522   *   Locking: The caller must ensure that the *config* lock is HELD but
 523   *            that the reporter (data) lock is *NOT HELD*.
 524   */
 525  	virtual void handleSwapCleanup(int swapNChannels);
 526  
 527  /*! @function   IOReporter::handleConfigureReport
 528   *   @abstract   override vector for IOReporter::configureReport()
 529   *               [parameters and result should exactly match]
 530   *
 531   *   @discussion
 532   *       The public base class method takes the reporter lock, calls this
 533   *       function, and then drops the lock.  Subclasses should not call
 534   *       this function directly.
 535   */
 536  	virtual IOReturn handleConfigureReport(IOReportChannelList *channelList,
 537  	    IOReportConfigureAction action,
 538  	    void *result,
 539  	    void *destination);
 540  
 541  /*! @function   IOReporter::handleUpdateReport
 542   *   @abstract   override vector for IOReporter::updateReport()
 543   *               [parameters and result should exactly match]
 544   *
 545   *   @discussion
 546   *       The public base class method takes the reporter lock, calls this
 547   *       function, and then drops the lock.  Subclasses should not call
 548   *       this function directly.
 549   *
 550   *       This function may be overriden but the common case should be to
 551   *       simply update reporter's specific values by overriding
 552   *       IOReporter::updateChannelValues().
 553   */
 554  	virtual IOReturn handleUpdateReport(IOReportChannelList *channelList,
 555  	    IOReportConfigureAction action,
 556  	    void *result,
 557  	    void *destination);
 558  
 559  /*  @function   IOReporter::handleCreateLegend
 560   *   @abstract   override vector for IOReporter::createLegend()
 561   *               [parameters and result should exactly match]
 562   *
 563   *   @discussion
 564   *       The public base class method takes the reporter lock, calls this
 565   *       function, and then drops the lock.  Subclasses should not call
 566   *       this function directly.
 567   */
 568  	virtual OSPtr<IOReportLegendEntry> handleCreateLegend(void);
 569  
 570  /*! @function   IOReporter::updateChannelValues
 571   *   @abstract   update channel values for IOReporter::updateReport()
 572   *
 573   *   @param  channel_index - logical (internal) index of the channel
 574   *   @result     appropriate IOReturn code
 575   *
 576   *   @discussion
 577   *       Internal reporter method to allow a subclass to update channel
 578   *       data when updateReport() is called.  This routine handles the
 579   *       common case of a subclass needing to refresh state in response
 580   *       to IOReporter::updateReport().  It saves the complexity of
 581   *       parsing the full parameters to IOReporter::updateReport().
 582   *
 583   *       The IOReporter base class implementation does not do anything
 584   *       except return success.
 585   *
 586   *   Locking: IOReporter::updateReport() takes the reporter lock,
 587   *            determines the indices involved, calls this function, and
 588   *            then proceeds to provide values to the caller.  If subclasses
 589   *            need to call this routine directly, they must ensure that
 590   *            the reporter (data) lock is held: see
 591   *            IOReporter::lockReporter().
 592   */
 593  	virtual IOReturn updateChannelValues(int channel_index);
 594  
 595  
 596  /*! @function   IOReporter::updateReportChannel
 597   *   @abstract   Internal method to extract channel data to a destination
 598   *
 599   *   @param  channel_index - offset into internal elements array
 600   *   @param  nElements - incremented by the number of IOReportElements added
 601   *   @param  destination - pointer to the destination buffer
 602   *   @result     IOReturn code
 603   *
 604   *   @discussion
 605   *       updateReportChannel() is used to extract a single channel's
 606   *       data to the updateReport() destination.
 607   *
 608   *   Locking: Caller must ensure that the reporter (data) lock is held.
 609   */
 610  	IOReturn updateReportChannel(int channel_index,
 611  	    int *nElements,
 612  	    IOBufferMemoryDescriptor *destination);
 613  
 614  
 615  /*! @function   IOReporter::setElementValues
 616   *   @abstract   Atomically update a specific member of _elements[].
 617   *
 618   *   @param  element_index - index of the _element in internal array
 619   *   @param  values - IORepoterElementValues to replace those at _elements[idx]
 620   *   @param  record_time - optional mach_absolute_time to be used for metadata
 621   *   @result     IOReturn code
 622   *
 623   *   @discussion
 624   *       element_index can be obtained from getFirstElementIndex().  If
 625   *       record_time is not provided, IOReporter::setElementValues() will
 626   *       fetch the current mach_absolute_time.  If the current time is
 627   *       already known, it is more efficient to pass it along.
 628   *
 629   *   Locking: Caller must ensure that the reporter (data) lock is held.
 630   */
 631  	virtual IOReturn setElementValues(int element_index,
 632  	    IOReportElementValues *values,
 633  	    uint64_t record_time = 0);
 634  
 635  /*! @function   IOReporter::getElementValues
 636   *   @abstract   Internal method to directly access the values of an element
 637   *
 638   *   @param  element_index - index of the _element in internal array
 639   *   @result     A pointer to the element values requested or NULL on failure
 640   *
 641   *   @discussion Locking: Caller must ensure that the reporter (data) lock is held.
 642   *   The returned pointer is only valid until unlockReporter() is called.
 643   */
 644  	virtual const IOReportElementValues* getElementValues(int element_index);
 645  
 646  /*! @function   IOReporter::getFirstElementIndex
 647   *   @abstract   Returns the first element index for a channel
 648   *
 649   *   @param  channel_id - ID of the channel
 650   *   @param  element_index - pointer to the returned element_index
 651   *   @result     appropriate IOReturn code
 652   *
 653   *   @discussion
 654   *       For efficiently and thread-safely reading _elements
 655   *
 656   *   Locking: Caller must ensure that the reporter (data) lock is held.
 657   */
 658  	virtual IOReturn getFirstElementIndex(uint64_t channel_id,
 659  	    int *element_index);
 660  
 661  /*! @function   IOReporter::getChannelIndex
 662   *   @abstract   Returns the index of a channel from internal data structures
 663   *
 664   *   @param  channel_id - ID of the channel
 665   *   @param  channel_index - pointer to the returned element_index
 666   *   @result     appropriate IOReturn code
 667   *
 668   *   @discussion
 669   *       For efficiently and thread-safely reading channels
 670   *
 671   *   Locking: Caller must ensure that the reporter (data) lock is held.
 672   */
 673  	virtual IOReturn getChannelIndex(uint64_t channel_id,
 674  	    int *channel_index);
 675  
 676  /*! @function   IOReporter::getChannelIndices
 677   *   @abstract   Returns the index of a channel and its corresponding
 678   *               first element index from internal data structure
 679   *
 680   *    @param  channel_id - ID of the channel
 681   *    @param  channel_index - pointer to the returned channel_index
 682   *    @param  element_index - pointer to the returned element_index
 683   *    @result     appropriate IOReturn code
 684   *
 685   *    @discussion
 686   *       For efficiently and thread-safely reading channel elements.
 687   *       It is commonly useful to get access to both channel and element
 688   *       indices togther.  This convenience method allows sub-classes to
 689   *       get both indices simultaneously.
 690   *
 691   *   Locking: Caller must ensure that the reporter (data) lock is held.
 692   */
 693  	virtual IOReturn getChannelIndices(uint64_t channel_id,
 694  	    int *channel_index,
 695  	    int *element_index);
 696  
 697  /*! @function   IOReporter::copyElementValues
 698   *   @abstract   Copies the values of an internal element to *elementValues
 699   *
 700   *   @param  element_index - Index of the element to return values from
 701   *   @param  elementValues - For returning the content of element values
 702   *   @result     Returns the content of an element
 703   *
 704   *   @discussion
 705   *       For efficiently and thread-safely reading _elements.
 706   *       May need to find the index of the element first.
 707   *
 708   *   Locking: Caller must ensure that the reporter (data) lock is held.
 709   */
 710  	virtual IOReturn copyElementValues(int element_index,
 711  	    IOReportElementValues *elementValues);
 712  
 713  // private methods
 714  private:
 715  /*! @function   IOReporter::copyChannelIDs
 716   *   @abstract   return an an OSArray of the reporter's
 717   *               channel IDs
 718   *
 719   *   @result     An OSArray of the repoter's channel ID's as OSNumbers
 720   *
 721   *   @discussion
 722   *       This method is an internal helper function used to prepare a
 723   *       legend entry.  It encapsulates the channel IDs in OSNumbers and
 724   *       aggregates them in an OSArray used when building the IOReportLegend
 725   *
 726   *   Locking: Caller must ensure that the reporter (data) lock is held.
 727   */
 728  	OSPtr<OSArray> copyChannelIDs(void);
 729  
 730  /*! @function   IOReporter::legendWith
 731   *   @abstract   Internal method to help create legend entries
 732   *
 733   *   @param  channelIDs - OSArray of OSNumber(uint64_t) channels IDs.
 734   *   @param  channelNames - parrallel OSArray of OSSymbol(rich names)
 735   *   @param  channelType - the type of all channels in this legend
 736   *   @param  unit - The unit for the quantity recorded by this reporter object
 737   *
 738   *   @result     An IOReportLegendEntry object or NULL on failure
 739   *
 740   *   @discussion
 741   *       This static method is the main legend creation function. It is called by
 742   *       IOReporter sub-classes and is responsible for building an
 743   *       IOReportLegendEntry corresponding to this reporter object.
 744   *       This legend entry may be extended by the sub-class of IOReporter if
 745   *       required.
 746   *
 747   *   Locking: SAFE to call concurrently (no static globals), MAY BLOCK
 748   */
 749  	static OSPtr<IOReportLegendEntry> legendWith(OSArray *channelIDs,
 750  	    OSArray *channelNames,
 751  	    IOReportChannelType channelType,
 752  	    IOReportUnit unit);
 753  
 754  // protected instance variables (want to get rid of these)
 755  protected:
 756  	IOReportChannelType _channelType;
 757  	uint64_t            _driver_id;     // driver reporting data
 758  
 759  // IOHistogramReporter accesses these; need to re-do its instantiation
 760  	IOReportElement    *_elements;
 761  	int                *_enableCounts;  // refcount kIOReportEnable/Disable
 762  	uint16_t            _channelDimension;// Max channel size
 763  	int                 _nElements;
 764  	int                 _nChannels;     // Total Channels in this reporter
 765  	OSPtr<OSArray>      _channelNames;
 766  
 767  // MUST be protected because check is a macro!
 768  	bool                _reporterIsLocked;
 769  	bool                _reporterConfigIsLocked;
 770  
 771  // Required for swapping inside addChannel
 772  	IOReportElement    *_swapElements;
 773  	int                *_swapEnableCounts;
 774  
 775  // private instance variables
 776  private:
 777  	IOReportUnit       _unit;
 778  
 779  	int                 _enabled;// 'enabled' if _enabled > 0
 780  
 781  	IOLock             *_configLock;
 782  	IOInterruptState    _interruptState;
 783  	IOSimpleLock       *_reporterLock;
 784  };
 785  
 786  
 787  /************************************/
 788  /***** 3. IOReporter Subclasses *****/
 789  /************************************/
 790  
 791  /*!
 792   *   @class      IOSimpleReporter
 793   *   @abstract   Report simple integers
 794   *   @discussion
 795   *       Each IOSimpleReporter can have an arbitrary number of channels,
 796   *       each publishing a single integer value at any given time.
 797   */
 798  
 799  class IOSimpleReporter : public IOReporter
 800  {
 801  	OSDeclareDefaultStructors(IOSimpleReporter);
 802  
 803  public:
 804  
 805  /*! @function   IOSimpleReporter::with
 806   *   @abstract   create an initialized simple reporter
 807   *
 808   *   @param  reportingService - IOService associated with all channels
 809   *   @param  categories - The category in which the report should be classified
 810   *   @param  unit - The unit for the quantity recorded by the reporter object
 811   *   @result     On success, an instance of IOSimpleReporter, else NULL
 812   *
 813   *   @discussion
 814   *       Creates an instance of IOSimpleReporter object
 815   *
 816   *   Locking: SAFE to call concurrently (no static globals), MAY BLOCK.
 817   */
 818  	static OSPtr<IOSimpleReporter> with(IOService *reportingService,
 819  	    IOReportCategories categories,
 820  	    IOReportUnit unit);
 821  
 822  /*! @function   IOSimpleReporter::setValue
 823   *   @abstract   Thread safely set a channel's value
 824   *
 825   *   @param  channel_id - ID of the channel for which the value needs to be set
 826   *   @param  value - New channel value
 827   *   @result     Appropriate IOReturn code
 828   *
 829   *   @discussion
 830   *       Updates the value of a channel to the provided value.
 831   *
 832   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
 833   */
 834  	IOReturn setValue(uint64_t channel_id,
 835  	    int64_t value);
 836  
 837  /*! @function   IOSimpleReporter::incrementValue
 838   *   @abstract   Thread safely increment a channel's value by a given amount
 839   *
 840   *   @param  channel_id - ID of the channel for which the value needs to be incremented
 841   *   @param  increment - Amount to be added to the current channel value
 842   *   @result     Appropriate IOReturn code
 843   *   @discussion
 844   *       Increments the value of the channel ID by the provided amount.
 845   *
 846   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
 847   */
 848  	IOReturn incrementValue(uint64_t channel_id,
 849  	    int64_t increment);
 850  
 851  /*! @function   IOSimpleReporter::getValue
 852   *   @abstract   Thread safely access a channel value
 853   *
 854   *   @param  channel_id - ID of the channel to get a value from
 855   *   @result     Returns the current value stored in the channel
 856   *   @discussion
 857   *       Accessor method to a channel's current stored value
 858   *
 859   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
 860   */
 861  	int64_t getValue(uint64_t channel_id);
 862  
 863  protected:
 864  
 865  /*! @function   IOSimpleReporter::initWith
 866   *   @abstract   instance method implementation called by IOSimpleReporter::with
 867   *
 868   *   @discussion
 869   *       See description of parameters above
 870   *
 871   *   Locking: same-instance concurrency UNSAFE
 872   */
 873  	virtual bool initWith(IOService *reportingService,
 874  	    IOReportCategories categories,
 875  	    IOReportUnit unit);
 876  
 877  private:
 878  };
 879  
 880  
 881  
 882  /*!
 883   *   @class      IOStateReporter
 884   *   @abstract   Report state machine data
 885   *   @discussion
 886   *       Each IOStateReporter can report information for an arbitrary number
 887   *       of similar state machines.  All must have the same number of states.
 888   */
 889  class IOStateReporter : public IOReporter
 890  {
 891  	OSDeclareDefaultStructors(IOStateReporter);
 892  
 893  public:
 894  
 895  /*! @function   IOStateReporter::with
 896   *   @abstract   State reporter static creation method
 897   *
 898   *   @param  reportingService - The I/O Kit service for this reporter's channels
 899   *   @param  categories - The categories for this reporter's channels
 900   *   @param  nstates - Maximum number of states for this reporter's channels
 901   *   @param  unit - optional parameter if using override/increment...()
 902   *   @result     on success, an IOStateReporter instance, else NULL
 903   *
 904   *   @discussion
 905   *       Creates an instance of IOStateReporter.  The default time scale
 906   *       is the current system's notion of mach_absolute_time().  Using a
 907   *       non-default time scale requires the use of
 908   *       override/incrementChannelState() instead of setState().
 909   *       setState() always updates using mach_absolute_time().
 910   *
 911   *   Locking: SAFE to call concurrently (no static globals), MAY BLOCK
 912   */
 913  	static OSPtr<IOStateReporter> with(IOService *reportingService,
 914  	    IOReportCategories categories,
 915  	    int nstates,
 916  	    IOReportUnit unit = kIOReportUnitHWTicks);
 917  
 918  /*! @function   IOStateReporter::setStateID
 919   *   @abstract   Assign a non-default ID to a state
 920   *
 921   *   @param  channel_id - ID of channel containing the state in question
 922   *   @param  state_index - index of state to give an ID: [0..(nstates-1)]
 923   *   @param  state_id - 64-bit state ID, for ASCII, use IOREPORT_MAKEID
 924   *
 925   *   @result     Appropriate IOReturn code
 926   *
 927   *   @discussion
 928   *       By default, IOStateReporter identifies its channel states by
 929   *       numbering them from 0 to <nstates - 1>.  If setStateID is not
 930   *       called to customize the state IDs, the numbered states will be
 931   *       kept throughout the life of the object and it is safe to reference
 932   *       those states by their indices.  Otherwise, after setStateID() has
 933   *       been called, the ordering of states is no longer guaranteed and
 934   *       the client must reference states by their assigned state ID.
 935   *
 936   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
 937   */
 938  	IOReturn setStateID(uint64_t channel_id,
 939  	    int state_index,
 940  	    uint64_t state_id);
 941  
 942  /*! @function   IOStateReporter::setChannelState
 943   *   @abstract   Updates the current state of a channel to a new state
 944   *
 945   *   @param  channel_id - ID of the channel which is updated to a new state
 946   *   @param  new_state_id - ID of the target state for this channel
 947   *   @param  last_intransition - deprecated: time of most recent entry
 948   *   @param  prev_state_residency - deprecated: time spent in previous state
 949   *   @result     Appropriate IOReturn code
 950   *
 951   *   @discussion
 952   *       setChannelState() updates the amount of time spent in the previous
 953   *       state (if any) and increments the number of transitions into the
 954   *       new state.  It also sets the target state's last transition time to
 955   *       the current time and enables internal time-keeping for the channel.
 956   *       In this mode, calls like getStateResidencyTime() and updateReport()
 957   *       automatically update a channel's time in state.
 958   *
 959   *       new_state_id identifies the target state as initialized
 960   *       (0..<nstates-1>) or as configured by setStateID().
 961   *
 962   *       Drivers wishing to compute and report their own time in state
 963   *       should use incrementChannelState() or overrideChannelState().  It
 964   *       is not currently possible for a driver to synchronize with the
 965   *       automatic time-keeping enabled by setChannelState().  The
 966   *       4-argument version of setChannelState() is thus impossible to
 967   *       use correctly.  In the future, there may be a setChannelState()
 968   *       which accepts a last_intransition parameter and uses it to
 969   *       automatically calculate time in state (ERs -> IOReporting / X).
 970   *
 971   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
 972   */
 973  	IOReturn setChannelState(uint64_t channel_id,
 974  	    uint64_t new_state_id,
 975  	    uint64_t last_intransition,
 976  	    uint64_t prev_state_residency) __deprecated;
 977  
 978  /*! @function   IOStateReporter::setChannelState
 979   *   @abstract   Updates the current state of a channel to a new state
 980   *
 981   *   @param  channel_id - ID of the channel which is updated to a new state
 982   *   @param  new_state_id - ID of the target state for this channel
 983   *   @result     Appropriate IOReturn code
 984   *
 985   *   @discussion
 986   *       setChannelState() updates the amount of time spent in the previous
 987   *       state (if any) and increments the number of transitions into the
 988   *       new state.  It also sets the target state's last transition time to
 989   *       the current time and enables internal time-keeping for the channel.
 990   *       In this mode, calls like getStateResidencyTime() and updateReport()
 991   *       automatically update a channel's time in state.
 992   *
 993   *       new_state_id identifies the target state as initialized
 994   *       (0..<nstates-1>) or as configured by setStateID().
 995   *
 996   *       Drivers wishing to compute and report their own time in state
 997   *       should use incrementChannelState() or overrideChannelState().  It
 998   *       is not currently possible for a driver to synchronize with the
 999   *       automatic time-keeping enabled by setChannelState().  The
1000   *       4-argument version of setChannelState() is thus impossible to
1001   *       use correctly.  In the future, there may be a setChannelState()
1002   *       which accepts a last_intransition parameter and uses it to
1003   *       automatically calculate time in state (ERs -> IOReporting / X).
1004   *
1005   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1006   */
1007  	IOReturn setChannelState(uint64_t channel_id,
1008  	    uint64_t new_state_id);
1009  
1010  
1011  /*! @function   IOStateReporter::setState
1012   *   @abstract   Updates state for single channel reporters
1013   *
1014   *   @param  new_state_id - New state for the channel
1015   *   @result     Appropriate IOReturn code.
1016   *
1017   *   @discussion
1018   *       setState() is a convenience method for single-channel state
1019   *       reporter instances.  An error will be returned if the reporter
1020   *       in question has more than one channel.
1021   *
1022   *       See further discussion at setChannelState().
1023   *
1024   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1025   */
1026  	IOReturn setState(uint64_t new_state_id);
1027  
1028  /*! @function   IOStateReporter::setState
1029   *   @abstract   Updates state for single channel reporters
1030   *
1031   *   @param  new_state_id - New state for the channel
1032   *   @param  last_intransition - deprecated: time of most recent entry
1033   *   @param  prev_state_residency - deprecated: spent in previous state
1034   *   @result     Appropriate IOReturn code.
1035   *
1036   *   @discussion
1037   *       setState() is a convenience method for single-channel state
1038   *       reporter instances.  An error will be returned if the reporter
1039   *       in question has more than one channel.
1040   *
1041   *       See further discussion at setChannelState().
1042   *
1043   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1044   */
1045  	IOReturn setState(uint64_t new_state_id,
1046  	    uint64_t last_intransition,
1047  	    uint64_t prev_state_residency) __deprecated;
1048  
1049  /*! @function   IOStateReporter::overrideChannelState
1050   *   @abstract   Overrides state data for a channel with passed arguments
1051   *
1052   *   @param  channel_id - ID of the channel which state is to be updated
1053   *   @param  state_id - state id for the channel
1054   *   @param  time_in_state - time used as new total time in state
1055   *   @param  intransitions - total number of transitions into state
1056   *   @param  last_intransition - mach_absolute_time of most recent entry (opt)
1057   *   @result     Appropriate IOReturn code
1058   *
1059   *   @discussion
1060   *       overrideChannelState() sets a particular state's time in state
1061   *       and transition count to the values provided.  The optional
1062   *       last_intransition records the last time the channel transitioned
1063   *       into the given state.  Passing 0 for time_in_state and
1064   *       intransitions will force the current values to 0.  Passing 0
1065   *       for last_intransition for all states will disable the notion
1066   *       of a channel's "current state."
1067   *
1068   *       The most recent last_intransition (amongst all states in a channel)
1069   *       logically determines the current state.  If last_intransition is
1070   *       not provided for any state, the channel will not report a current
1071   *       For consistent results, it is important to either never specify
1072   *       last_intransition or to always specify it.
1073   *
1074   *       There is currently a bug in determining current state (13423273).
1075   *       The IOReportMacros.h macros only update the state's metadata
1076   *       timestamp and libIOReport only looks at the metadata timestamps
1077   *       to determine the current state.  Until that bug is fixed, whichever
1078   *       state is updated most recently will be considered the "current"
1079   *       state by libIOReport.
1080   *
1081   *       ::setState()'s automatic "time in state" updates are not supported
1082   *       when using overrideChannelState().  Clients must not use
1083   *       overrideChannelState() on any channel that has ::setState() called
1084   *       on it.  Unlike with ::setState(), clients using
1085   *       overrideChannelState() are responsible for ensuring that data is
1086   *       up to date for updateReport() calls.  The correct way to do this
1087   *       is for a driver's ::updateReport() method to push the most up to
1088   *       date values into the reporters before calling
1089   *       super::updateReport().
1090   *
1091   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1092   */
1093  	IOReturn overrideChannelState(uint64_t channel_id,
1094  	    uint64_t state_id,
1095  	    uint64_t time_in_state,
1096  	    uint64_t intransitions,
1097  	    uint64_t last_intransition = 0);
1098  
1099  /*! @function   IOStateReporter::incrementChannelState
1100   *   @abstract   Updates state data for a channel with passed arguments
1101   *
1102   *   @param  channel_id - ID of the channel which state is to be updated
1103   *   @param  state_id - state id for the channel
1104   *   @param  time_in_state - time to be accumulated for time in state
1105   *   @param  intransitions - number of transitions into state to be added
1106   *   @param  last_intransition - mach_absolute_time of most recent entry (opt)
1107   *   @result     Appropriate IOReturn code
1108   *
1109   *   @discussion
1110   *       incrementChannelState() adds time_in_state and intransitions
1111   *       to the current values stored for a particular state.  If provided,
1112   *       last_intransition overwrites the time the state was most recently
1113   *       entered.  Passing 0 for time_in_state and intransitions will have
1114   *       no effect.  Passing 0 for last_intransition for all states will
1115   *       disable the notion of a channel's "current state."
1116   *
1117   *       The most recent last_intransition (amongst all states in a channel)
1118   *       logically determines the current state.  If last_intransition is
1119   *       not provided for any state, the channel will not report a current
1120   *       For consistent results, it is important to either never specify
1121   *       last_intransition or to always specify it.
1122   *
1123   *       There is currently a bug in determining current state (13423273).
1124   *       The IOReportMacros.h macros only update the state's metadata
1125   *       timestamp and libIOReport only looks at the metadata timestamps
1126   *       to determine the current state.  Until that bug is fixed, whichever
1127   *       state is updated most recently will be considered the "current"
1128   *       state by libIOReport.
1129   *
1130   *       ::setState()'s automatic "time in state" updates are not supported
1131   *       when using incrementChannelState().  Clients must not use
1132   *       incrementChannelState() on any channel that has ::setState()
1133   *       called on it.  Unlike with ::setState(), clients using
1134   *       incrementChannelState() are responsible for ensuring that data
1135   *       is up to date for updateReport() calls.  The correct way to do
1136   *       this is for a driver's ::updateReport() method to push the most
1137   *       up to date values into the reporters before calling
1138   *       super::updateReport().
1139   *
1140   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1141   */
1142  	IOReturn incrementChannelState(uint64_t channel_id,
1143  	    uint64_t state_id,
1144  	    uint64_t time_in_state,
1145  	    uint64_t intransitions,
1146  	    uint64_t last_intransition = 0);
1147  
1148  /*! @function   IOStateReporter::setStateByIndices
1149   *   @abstract   update a channel state without validating channel_id
1150   *
1151   *   @param  channel_index - 0..<nChannels>, available from getChannelIndex()
1152   *   @param  new_state_index - New state (by index) for the channel
1153   *   @result     Appropriate IOReturn code
1154   *
1155   *   @discussion
1156   *       Similar to setState(), setStateByIndices() sets a channel's state
1157   *       without searching for the channel or state IDs.  It will perform
1158   *       bounds checking, but relies on the caller to properly indicate
1159   *       the indices of the channel and state.  Clients can rely on channels
1160   *       being added to IOStateReporter in order: the first channel will
1161   *       have index 0, the second index 1, etc.  Like ::setState(),
1162   *       "time in state" calculations are handled automatically.
1163   *
1164   *       setStateByIndices() is faster than than setChannelState(), but
1165   *       it should only be used where the latter's performance overhead
1166   *       might be a problem.  For example, many channels in a single
1167   *       reporter and high-frequency state changes.
1168   *
1169   *       Drivers wishing to compute and report their own time in state
1170   *       should use incrementChannelState() or overrideChannelState().  It
1171   *       is not currently possible for a driver to synchronize with the
1172   *       automatic time-keeping enabled by setStateByIndices().  The
1173   *       4-argument version of setChannelState() is thus impossible to
1174   *       use correctly.  In the future, there may be a setChannelState()
1175   *       which accepts a last_intransition parameter and uses it to
1176   *       automatically calculate time in state (ERs -> IOReporting / X).
1177   *
1178   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1179   */
1180  	IOReturn setStateByIndices(int channel_index,
1181  	    int new_state_index);
1182  
1183  /*! @function   IOStateReporter::setStateByIndices
1184   *   @abstract   update a channel state without validating channel_id
1185   *
1186   *   @param  channel_index - 0..<nChannels>, available from getChannelIndex()
1187   *   @param  new_state_index - New state (by index) for the channel
1188   *   @param  last_intransition - deprecated: time of most recent entry
1189   *   @param  prev_state_residency - deprecated: time spent in previous state
1190   *   @result     Appropriate IOReturn code
1191   *
1192   *   @discussion
1193   *       Similar to setState(), setStateByIndices() sets a channel's state
1194   *       without searching for the channel or state IDs.  It will perform
1195   *       bounds checking, but relies on the caller to properly indicate
1196   *       the indices of the channel and state.  Clients can rely on channels
1197   *       being added to IOStateReporter in order: the first channel will
1198   *       have index 0, the second index 1, etc.  Like ::setState(),
1199   *       "time in state" calculations are handled automatically.
1200   *
1201   *       setStateByIndices() is faster than than setChannelState(), but
1202   *       it should only be used where the latter's performance overhead
1203   *       might be a problem.  For example, many channels in a single
1204   *       reporter and high-frequency state changes.
1205   *
1206   *       Drivers wishing to compute and report their own time in state
1207   *       should use incrementChannelState() or overrideChannelState().  It
1208   *       is not currently possible for a driver to synchronize with the
1209   *       automatic time-keeping enabled by setStateByIndices().  The
1210   *       4-argument version of setChannelState() is thus impossible to
1211   *       use correctly.  In the future, there may be a setChannelState()
1212   *       which accepts a last_intransition parameter and uses it to
1213   *       automatically calculate time in state (ERs -> IOReporting / X).
1214   *
1215   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1216   */
1217  	IOReturn setStateByIndices(int channel_index,
1218  	    int new_state_index,
1219  	    uint64_t last_intransition,
1220  	    uint64_t prev_state_residency) __deprecated;
1221  
1222  /*! @function   IOStateReporter::getStateInTransitions
1223   *   @abstract   Accessor method for count of transitions into state
1224   *
1225   *   @param  channel_id - ID of the channel
1226   *   @param  state_id - State of the channel
1227   *   @result     Count of transitions into the requested state.
1228   *
1229   *   @discussion
1230   *       Some clients may need to consume internally the data aggregated by the
1231   *       reporter object. This method allows a client to retrieve the count of
1232   *       transitions into the requested state for the channel_id.
1233   *
1234   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1235   */
1236  	uint64_t getStateInTransitions(uint64_t channel_id,
1237  	    uint64_t state_id);
1238  
1239  /*! @function   IOStateReporter::getStateResidencyTime
1240   *   @abstract   Accessor method for time spent in a given state
1241   *
1242   *   @param  channel_id - ID of the channel
1243   *   @param  state_id - State of the channel
1244   *   @result     Absolute time spent in specified state
1245   *
1246   *   @discussion
1247   *       Some clients may need to consume internally the data aggregated
1248   *       by the by the reporter object.  This method allows a client to
1249   *       retrieve the absolute time a particular channel recorded as spent
1250   *       in a specified state.
1251   *
1252   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1253   */
1254  	uint64_t getStateResidencyTime(uint64_t channel_id,
1255  	    uint64_t state_id);
1256  
1257  /*! @function   IOStateReporter::getStateLastTransitionTime
1258   *   @abstract   Accessor method for last time a transition occured
1259   *
1260   *   @param  channel_id - ID of the channel
1261   *   @param  state_id - State of the channel
1262   *   @result     Absolute time for when the last transition occured
1263   *
1264   *   @discussion
1265   *       Some clients may need to consume internally the data aggregated
1266   *       by the by the reporter object.  This method allows a client to
1267   *       retrieve the absolute time stamp for when the last transition into
1268   *       a specific state was recorded.
1269   *
1270   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1271   */
1272  	uint64_t getStateLastTransitionTime(uint64_t channel_id, uint64_t state_id);
1273  
1274  /*! @function   [DEPRECATED] IOStateReporter::getStateLastChannelUpdateTime
1275   *   @abstract   Deprecated accessor for last time a channel was auto-updated
1276   *
1277   *   @param  channel_id - ID of the channel
1278   *   @result     Absolute time for last time the channel was updated
1279   *
1280   *   @discussion
1281   *       If a channel has had ::setState() called on it, calls such as
1282   *       getStateResidencyTime() or updateReport() will update time in the
1283   *       current state and update an internal "last channel update time."
1284   *       Because clients have no way to interlock with those methods, there
1285   *       is no sensible way to use this method and it will be removed in
1286   *       a future release.
1287   *
1288   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1289   */
1290  	uint64_t getStateLastChannelUpdateTime(uint64_t channel_id) __deprecated;
1291  
1292  /*! @function   IOStateReporter::free
1293   *   @abstract   Releases the object and all its resources.
1294   *
1295   *   @discussion
1296   *       ::free() assumes that init() has completed.  Clients should use
1297   *       the static ::with() methods to obtain fully-initialized reporter
1298   *       instances.
1299   *
1300   *   Locking: same-instance concurrency UNSAFE
1301   */
1302  	virtual void free(void) APPLE_KEXT_OVERRIDE;
1303  
1304  protected:
1305  
1306  /*! @function   IOStateReporter::initWith
1307   *   @abstract   Instance method implementation called by ::with
1308   *
1309   *   @discussion
1310   *       See description of parameters above
1311   */
1312  	virtual bool initWith(IOService *reportingService,
1313  	    IOReportCategories categories,
1314  	    int16_t nstates, IOReportUnit unit);
1315  
1316  
1317  /*! @function   IOStateReporter::handleSwapPrepare
1318   *   @abstract   _swap* = <IOStateReporter-specific per-channel buffers>
1319   *   [see IOReporter::handle*Swap* for more info]
1320   */
1321  	virtual IOReturn handleSwapPrepare(int newNChannels) APPLE_KEXT_OVERRIDE;
1322  
1323  /*!
1324   *   @function   IOStateReporter::handleAddChannelSwap
1325   *   @abstract   swap in IOStateReporter's variables
1326   */
1327  	virtual IOReturn handleAddChannelSwap(uint64_t channel_id,
1328  	    const OSSymbol *symChannelName) APPLE_KEXT_OVERRIDE;
1329  
1330  /*!
1331   *   @function   IOStateReporter::handleSwapCleanup
1332   *   @abstract   clean up unused buffers in _swap*
1333   */
1334  	virtual void handleSwapCleanup(int swapNChannels) APPLE_KEXT_OVERRIDE;
1335  
1336  /*! @function   IOStateReporter::updateChannelValues
1337   *   @abstract   Update accounting of time spent in current state
1338   *
1339   *   @param  channel_index - internal index of the channel
1340   *   @result     appropriate IOReturn code
1341   *
1342   *   @discussion
1343   *       Internal State reporter method to account for the time spent in
1344   *       the current state when updateReport() is called on the reporter's
1345   *       channels.
1346   *
1347   *   Locking: Caller must ensure that the reporter (data) lock is held.
1348   */
1349  	virtual IOReturn updateChannelValues(int channel_index) APPLE_KEXT_OVERRIDE;
1350  
1351  /*! @function   IOStateReporter::setStateByIndices
1352   *   @abstract   update a channel state without validating channel_id
1353   *
1354   *   @param  channel_index - 0..<nChannels>, available from getChannelIndex()
1355   *   @param  new_state_index - New state for the channel
1356   *   @param  last_intransition - to remove: time of most recent entry
1357   *   @param  prev_state_residency - to remove: time spent in previous state
1358   *   @result     Appropriate IOReturn code
1359   *
1360   *   @discussion
1361   *       Locked version of IOReporter::setStateByIndices().  This method may be
1362   *       overriden by sub-classes.
1363   *
1364   *   Locking: Caller must ensure that the reporter (data) lock is held.
1365   */
1366  	virtual IOReturn handleSetStateByIndices(int channel_index,
1367  	    int new_state_index,
1368  	    uint64_t last_intransition,
1369  	    uint64_t prev_state_residency);
1370  
1371  /*! @function   IOStateReporter::setStateID
1372   *   @abstract   Assign a non-default ID to a state
1373   *
1374   *   @param  channel_id - ID of channel containing the state in question
1375   *   @param  state_index - index of state to give an ID: [0..(nstates-1)]
1376   *   @param  state_id - 64-bit state ID, for ASCII, use IOREPORT_MAKEID
1377   *
1378   *   @result     Appropriate IOReturn code
1379   *
1380   *   @discussion
1381   *       Locked version of IOReporter::setStateID(). This method may be
1382   *       overriden by sub-classes
1383   *
1384   *   Locking: Caller must ensure that the reporter (data) lock is held.
1385   */
1386  	virtual IOReturn handleSetStateID(uint64_t channel_id,
1387  	    int state_index,
1388  	    uint64_t state_id);
1389  
1390  /*! @function   IOStateReporter::handleOverrideChannelStateByIndices
1391   *   @abstract   Overrides state data for a channel with passed arguments
1392   *
1393   *   @param  channel_index - index of the channel which state is to be updated
1394   *   @param  state_index - index of the state id for the channel
1395   *   @param  time_in_state - time used as new total time in state
1396   *   @param  intransitions - total number of transitions into state
1397   *   @param  last_intransition - mach_absolute_time of most recent entry (opt)
1398   *   @result     Appropriate IOReturn code
1399   *
1400   *   @discussion
1401   *       Locked version of IOReporter::overrideChannelState().  This method
1402   *       may be overriden by sub-classes.
1403   *
1404   *   Locking: Caller must ensure that the reporter (data) lock is held.
1405   */
1406  	virtual IOReturn handleOverrideChannelStateByIndices(int channel_index,
1407  	    int state_index,
1408  	    uint64_t time_in_state,
1409  	    uint64_t intransitions,
1410  	    uint64_t last_intransition = 0);
1411  
1412  /*! @function   IOStateReporter::handleIncrementChannelStateByIndices
1413   *   @abstract   Updates state data for a channel with passed arguments
1414   *
1415   *   @param  channel_index - index of the channel which state is to be updated
1416   *   @param  state_index - index of the state id for the channel
1417   *   @param  time_in_state - time used as new total time in state
1418   *   @param  intransitions - total number of transitions into state
1419   *   @param  last_intransition - mach_absolute_time of most recent entry (opt)
1420   *   @result     Appropriate IOReturn code
1421   *
1422   *   @discussion
1423   *       Locked version of IOReporter::incrementChannelState(). This method
1424   *       may be overriden by sub-classes.
1425   *
1426   *   Locking: Caller must ensure that the reporter (data) lock is held.
1427   */
1428  	virtual IOReturn handleIncrementChannelStateByIndices(int channel_index,
1429  	    int state_index,
1430  	    uint64_t time_in_state,
1431  	    uint64_t intransitions,
1432  	    uint64_t last_intransition = 0);
1433  private:
1434  
1435  	int            *_currentStates;     // current states (per chonnel)
1436  	uint64_t       *_lastUpdateTimes;   // most recent auto-update
1437  
1438  // Required for swapping inside addChannel
1439  	int            *_swapCurrentStates;
1440  	uint64_t       *_swapLastUpdateTimes;
1441  
1442  	enum valueSelector {
1443  		kInTransitions,
1444  		kResidencyTime,
1445  		kLastTransitionTime
1446  	};
1447  	uint64_t _getStateValue(uint64_t channel_id,
1448  	    uint64_t state_id,
1449  	    enum valueSelector value);
1450  
1451  	IOReturn _getStateIndices(uint64_t channel_id,
1452  	    uint64_t state_id,
1453  	    int *channel_index,
1454  	    int *state_index);
1455  };
1456  
1457  
1458  /*!
1459   *   @class      IOHistogramReporter
1460   *   @abstract   Report histograms of values
1461   *   @discussion
1462   *       Each IOHistogramReporter can report one histogram representing
1463   *       how a given value has changed over time.
1464   */
1465  class IOHistogramReporter : public IOReporter
1466  {
1467  	OSDeclareDefaultStructors(IOHistogramReporter);
1468  
1469  public:
1470  /*! @function   IOHistogramReporter::with
1471   *   @abstract   Initializes the IOHistogramReporter instance variables and data structures
1472   *
1473   *   @param  reportingService - The I/O Kit service for this reporter's channels
1474   *   @param  categories - The categories in which the report should be classified
1475   *   @param  channelID - uint64_t channel identifier
1476   *   @param  channelName - rich channel name as char*
1477   *   @param  unit - The unit for the quantity recorded by the reporter object
1478   *   @param  nSegments - Number of segments to be extracted from the config data structure
1479   *   @param  config - Histograms require the caller to pass a configuration by segments
1480   *   @result     an instance of the IOSimpleReporter object or NULL on error
1481   *
1482   *   @discussion
1483   *       Creates an instance of histogram reporter object.
1484   *
1485   *  FIXME: need more explanation of the config
1486   *
1487   *       IOHistogramReporter currently only supports a single channel.
1488   *
1489   *
1490   */
1491  	static OSPtr<IOHistogramReporter> with(IOService *reportingService,
1492  	    IOReportCategories categories,
1493  	    uint64_t channelID,
1494  	    const char *channelName,
1495  	    IOReportUnit unit,
1496  	    int nSegments,
1497  	    IOHistogramSegmentConfig *config);
1498  
1499  /*! @function   IOHistogramReporter::addChannel
1500   *   @abstract   Override IOReporter::addChannel(*) to return an error
1501   *
1502   *   @result     kIOReturnUnsupported - doesn't support adding channels
1503   */
1504  	IOReturn
1505  	addChannel(__unused uint64_t channelID, __unused const char *channelName = NULL)
1506  	{
1507  		return kIOReturnUnsupported;
1508  	}
1509  
1510  /*! @function   IOHistogramReporter::overrideBucketValues
1511   *   @abstract   Override values of a bucket at specified index
1512   *
1513   *   @param  index - index of bucket to override
1514   *   @param  bucket_hits - new bucket hits count
1515   *   @param  bucket_min - new bucket minimum value
1516   *   @param  bucket_max - new bucket maximum value
1517   *   @param  bucket_sum - new bucket sum
1518   *   @result     Appropriate IOReturn code
1519   *
1520   *   @discussion
1521   *       Replaces data in the bucket at the specified index with the data pointed
1522   *       to by bucket. No sanity check is performed on the data. If the index
1523   *       is out of bounds, kIOReturnBadArgument is returned.
1524   *
1525   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1526   */
1527  
1528  	IOReturn overrideBucketValues(unsigned int index,
1529  	    uint64_t bucket_hits,
1530  	    int64_t bucket_min,
1531  	    int64_t bucket_max,
1532  	    int64_t bucket_sum);
1533  
1534  /*! @function   IOHistogramReporter::tallyValue
1535   *   @abstract   Add a new value to the histogram
1536   *
1537   *   @param  value - new value to add to the histogram
1538   *   @result     the index of the affected bucket, or -1 on error
1539   *
1540   *   @discussion
1541   *       The histogram reporter determines in which bucket the value
1542   *       falls and increments it.  The lowest and highest buckets
1543   *       extend to negative and positive infinity, respectively.
1544   *
1545   *   Locking: same-instance concurrency SAFE, WILL NOT BLOCK
1546   */
1547  	int tallyValue(int64_t value);
1548  
1549  /*! @function   IOHistogramReporter::free
1550   *   @abstract   Releases the object and all its resources.
1551   *
1552   *   @discussion
1553   *      ::free() assumes that init() has completed.  Clients should use
1554   *      the static ::with() methods to obtain fully-initialized reporter
1555   *      instances.
1556   *
1557   *   Locking: same-instance concurrency UNSAFE
1558   */
1559  	virtual void free(void) APPLE_KEXT_OVERRIDE;
1560  
1561  protected:
1562  
1563  /*! @function   IOHistogramReporter::initWith
1564   *   @abstract   instance method implementation called by ::with
1565   *
1566   *   @discussion
1567   *       See description of parameters above
1568   */
1569  	virtual bool initWith(IOService *reportingService,
1570  	    IOReportCategories categories,
1571  	    uint64_t channelID,
1572  	    const OSSymbol *channelName,
1573  	    IOReportUnit unit,
1574  	    int nSegments,
1575  	    IOHistogramSegmentConfig  *config);
1576  
1577  /*! @function   IOHistogramReporter::handleCreateLegend
1578   *   @abstract   Builds an IOReporting legend entry representing the channels of this reporter.
1579   *
1580   *   @result     An IOReportLegendEntry or NULL on failure
1581   *
1582   *   @discussion
1583   *       The returned legend entry may be appended to kIOReportLegendKey
1584   *       to be published by the caller in the IORegistry.  See the
1585   *       IOReportLegend class for more details.
1586   *
1587   *   Locking: same-instance concurrency SAFE, MAY BLOCK
1588   */
1589  	OSPtr<IOReportLegendEntry> handleCreateLegend(void) APPLE_KEXT_OVERRIDE;
1590  
1591  
1592  private:
1593  
1594  	int                         _segmentCount;
1595  	int64_t                    *_bucketBounds;
1596  	int                         _bucketCount;
1597  	IOHistogramSegmentConfig   *_histogramSegmentsConfig;
1598  };
1599  
1600  
1601  /***********************************/
1602  /***** 4. IOReportLegend Class *****/
1603  /***********************************/
1604  
1605  /*!
1606   *   @class      IOReportLegend
1607   *   @abstract   combine legend entries into a complete legend
1608   *   @discussion
1609   *       IOReportLegend adds metadata to legend entries and combines them
1610   *       into a single OSArray that can be published under the
1611   *       kIOReportLegendKey property in the I/O Kit registry.
1612   */
1613  class IOReportLegend : public OSObject
1614  {
1615  	OSDeclareDefaultStructors(IOReportLegend);
1616  
1617  public:
1618  /*! @function   IOReportLegend::with
1619   *   @abstract   Create an instance of IOReportLegend
1620   *
1621   *   @param  legend - OSArray of the legend possibly already present in registry
1622   *   @result     an instance of IOReportLegend, or NULL on failure
1623   *
1624   *   @discussion
1625   *       An IOReporting legend (an OSArray of legend entries) may be already
1626   *       present in the IORegistry.  Thus the recommended way to publish
1627   *       new entries is to append to any existing array as follows:
1628   *       1. call getProperty(kIOReportLegendKey) to get an existing legend.
1629   *
1630   *       2a. If it exists
1631   *       - OSDynamicCast to OSArray
1632   *       - and pass it to ::with()
1633   *       IOReportLegend *legendMaker = IOReportLegend::with(legend);
1634   *       The provided array is retained by IOReportLegend.
1635   *
1636   *       2b. If no legend already exists in the registry, pass NULL
1637   *       IOReportLegend *legend = IOReportLegend::with(NULL);
1638   *       This latter invocation will cause IOReportLegend to create a new
1639   *       array internally (also holding one reference).
1640   *
1641   *       At the cost of some registry churn, the static
1642   *       IOReportLegend::addReporterLegend() will handle the above, removing
1643   *       the need for any direct use of the IOReportLegend class.
1644   */
1645  	static OSPtr<IOReportLegend> with(OSArray *legend);
1646  
1647  /*! @function   IOReportLegend::addLegendEntry
1648   *   @abstract   Add a new legend entry
1649   *
1650   *   @param  legendEntry - entry to be added to the internal legend array
1651   *   @param  groupName - primary group name for this entry
1652   *   @param  subGroupName - secondary group name for this entry
1653   *   @result     appropriate IOReturn code
1654   *
1655   *   @discussion
1656   *       The entry will be retained as an element of the internal array.
1657   *       Legend entries are available from reporter objects.  Entries
1658   *       represent some number of channels with similar properties (such
1659   *       as group and sub-group).  Multiple legend entries with the same
1660   *       group names will be aggregated in user space.
1661   *
1662   *       Drivers that instantiate their reporter objects in response to
1663   *       IOService::configureReport(kIOReportDisable) will need to create
1664   *       temporary reporter objects for the purpose of creating their
1665   *       legend entries.  User-space legends are tracked by 12836893.
1666   */
1667  	IOReturn addLegendEntry(IOReportLegendEntry *legendEntry,
1668  	    const char *groupName,
1669  	    const char *subGroupName);
1670  
1671  /*! @function   IOReportLegend::addReporterLegend
1672   *   @abstract   Add a legend entry from a reporter object
1673   *
1674   *   @param  reporter - IOReporter to use to extract and append the legend
1675   *   @param  groupName - primary group name for this entry
1676   *   @param  subGroupName - secondary group name for this entry
1677   *   @result     appropriate IOReturn code
1678   *
1679   *   @discussion
1680   *       An IOReportLegendEntry will be created internally to this method from
1681   *       the IOReporter object passed in argument. The entry will be released
1682   *       internally after being appended to the IOReportLegend object.
1683   *       Legend entries are available from reporter objects.  Entries
1684   *       represent some number of channels with similar properties (such
1685   *       as group and sub-group).  Multiple legend entries with the same
1686   *       group names will be aggregated in user space.
1687   *
1688   *       Drivers that instantiate their reporter objects in response to
1689   *       IOService::configureReport(kIOReportDisable) will need to create
1690   *       temporary reporter objects for the purpose of creating their
1691   *       legend entries.  User-space legends are tracked by 12836893.
1692   *
1693   *       Locking: same-reportingService and same-IORLegend concurrency UNSAFE
1694   */
1695  	IOReturn addReporterLegend(IOReporter *reporter,
1696  	    const char *groupName,
1697  	    const char *subGroupName);
1698  
1699  /*! @function   IOReportLegend::addReporterLegend
1700   *   @abstract   Add a legend entry from a reporter object
1701   *
1702   *   @param  reportingService - IOService data provider into the reporter object
1703   *   @param  reporter - IOReporter to use to extract and append the legend
1704   *   @param  groupName - primary group name for this entry
1705   *   @param  subGroupName - secondary group name for this entry
1706   *   @result     appropriate IOReturn code
1707   *
1708   *   @discussion
1709   *       An IOReportLegendEntry will be created internally to this method from
1710   *       the IOReporter object passed in argument. The entry will be released
1711   *       internally after being appended to the IOReportLegend object.
1712   *       Legend entries are available from reporter objects.  Entries
1713   *       represent some number of channels with similar properties (such
1714   *       as group and sub-group).  Multiple legend entries with the same
1715   *       group names will be aggregated in user space.
1716   *
1717   *       Drivers that instantiate their reporter objects in response to
1718   *       IOService::configureReport(kIOReportDisable) will need to create
1719   *       temporary reporter objects for the purpose of creating their
1720   *       legend entries.  User-space legends are tracked by 12836893.
1721   *
1722   *       The static version of addReporterLegend adds the reporter's legend
1723   *       directly to reportingService's kIOReportLegendKey.  It is not
1724   *       possible to safely update kIOReportLegendKey from multiple threads.
1725   *
1726   *       Locking: same-reportingService and same-IORLegend concurrency UNSAFE
1727   */
1728  	static  IOReturn addReporterLegend(IOService *reportingService,
1729  	    IOReporter *reporter,
1730  	    const char *groupName,
1731  	    const char *subGroupName);
1732  
1733  /*! @function   IOReportLegend::getLegend
1734   *   @abstract   Accessor method to get the legend array
1735   *
1736   *   @result     Returns the OSObject holding the legend to be published by the driver
1737   *   @discussion
1738   *       This array will include all legend entries added to the object.
1739   */
1740  	OSArray* getLegend(void);
1741  
1742  /*! @function   IOReportLegend::free
1743   *   @abstract   Frees the IOReportLegend object
1744   *
1745   *   @discussion
1746   *       ::free() cleans up the reporter and anything it allocated.
1747   *
1748   *       ::free() releases the internal array (which was either passed
1749   *       to ::with() or created as a result of ::with(NULL)).  Assuming
1750   *       the caller extracted the array with getLegend() and published it
1751   *       in the I/O Kit registry, its ownership will now be with the
1752   *       registry.
1753   */
1754  	void free(void) APPLE_KEXT_OVERRIDE;
1755  
1756  
1757  
1758  protected:
1759  
1760  private:
1761  
1762  	OSPtr<OSArray>     _reportLegend;
1763  
1764  	IOReturn initWith(OSArray *legend);
1765  
1766  /*! @function   IOReportLegend::organizeLegend
1767   *   @abstract   Sets up the legend entry, organizing it with group and sub-group names
1768   *
1769   *   @param  groupName - Primary group name
1770   *   @param  subGroupName - Secondary group name
1771   *   @result     IOReturn code
1772   */
1773  	IOReturn organizeLegend(IOReportLegendEntry *legendEntry,
1774  	    const OSSymbol *groupName,
1775  	    const OSSymbol *subGroupName);
1776  
1777  // FUTURE POSSIBILITY (NOT IMPLEMENTED!)
1778  /*! @function   IOReportLegend::createReporters
1779   *   @abstract   Creates as many IOReporter objects as the legend contains
1780   *
1781   *   @param  legend - OSArray legend object containing the description of all reporters
1782   *           the driver is able to address
1783   *   @param  reporter - OSSet of reporter objects created by this call
1784   *   @result     IOReturn code kIOReturnSuccess if successful
1785   *
1786   *   @discussion
1787   *       NOT SUPPORTED at the time of writing
1788   *       Convenience method to create all the driver's reporter objects from a legend.
1789   *       Can be used when a legend is made public through the IORegistry but IOReporter
1790   *       objects have not yet been created to save memory, waiting for observers.
1791   *       Upon a call to configureReport via the IOService method, a driver could
1792   *       create all reporter objects on the fly using this function.
1793   */
1794  // For Future IOReporterManager...
1795  // static IOReturn createReporters(requestedChannels, legend);
1796  };
1797  
1798  #endif  /* ! _IOKERNEL_REPORTERS_H_ */