SYSTEM OF REUSABLE SOFTWARE PARTS FOR IMPLEMENTING CONCURRENCY AND HARDWARE ACCESS, AND METHODS OF USE

Abstract: A system of reusable software parts for designing and implementing concurrency and access to hardware in software components, applications and systems constructed by assembly. Parts for generating events in specific execution contexts, and under specific time constraints are included. Also included are innovative parts for protecting critical regions consisting of parts or structures of interconnected parts. In addition, reusable parts for handling hardware interrupts and access to registers and memory of peripheral hardware devices are also included. The system includes a number of parts for designing and implementing device drivers in a way that is independent of specific operating system and hardware architecture.

Description: SYSTEM OF REUSABLE SOFTWARE PARTS FOR IMPLEMENTING CONCURRENCY AND HARDWARE ACCESS, AND METHODS OF USE BACKGROUND OF THE INVENTION (1 ) FIELD OF THE INVENTION The present invention is related to the field of object-oriented software engineering, and, more specifically, to reusable software components for concurrency and hardware access. (2) DISCUSSION OF THE BACKGROUND ART Over the last twenty years, the object paradigm, including object-oriented analysis, design, programming and testing, has become the predominant paradigm for building software systems. A wide variety of methods, tools and techniques have been developed to support various aspects of object-oriented software construction, from formal methods for analysis and design, through a number of object-oriented languages, component object models and object-oriented databases, to a number of CASE systems and other tools that aim to automate one or more aspects of the development process. With the maturing of the object paradigm, the focus has shifted from methods for programming objects as abstract data types to methods for designing and building systems of interacting objects. As a result, methods and means for expressing and building structures of objects have become increasingly important. Object composition has emerged and is rapidly gaining acceptance as a general and efficient way to express structural relationships between objects. New analysis and design methods based on object composition have developed and most older methods have been extended to accommodate composition. Composition methods The focus of object composition is to provide methods, tools and systems that make it easy to create new objects by combining already existing objects. An excellent background explanation of analysis and design methodology based on object composition is contained in Real-time Object-Oriented Modeling (ROOM) by Bran Selic et al., John Wiley & Sons, New York, (year), in which Selic describes a method and a system for building certain specialized types of software systems using object composition. Another method for object composition is described in HOOD : Hierarchical Object- Oriented Design by Peter J. Robinson, Prentice-Hall, Hertfordshire, UK, 1992, and "Creating Architectures with Building Blocks" by Frank J. van der Linden and Jϋrgen K. Mϋller, IEEE Software, 1 2:6, November 1995, pp. 51 -60. Another method of building software components and systems by composition is described in a commonly assigned international patent application entitled "Apparatus, System and Method for Designing and Constructing Software Components and Systems as Assemblies of Independent Parts", serial number PCT/US96/19675, filed December 13, 1 996, and published June 26, 1997, which is incorporated herein by reference and referred to herein throughout as the "'675 application." Yet another method that unifies many pre-existing methods for design and analysis of object-oriented systems and has specific provisions for object composition is described in the OMG Unified Modeling Language Specification, version 1 .3, June 1 999, led by the Object Management Group, Inc., 492 Old Connecticut Path, Framingham, MA 01701 . Composition-based development Composition - building new objects out of existing objects - is the natural way in which most technical systems are made. For example, mechanical systems are built by assembling together various mechanical parts and electronic systems are built by assembling and connecting chips on printed circuit boards. But today, despite its many benefits, the use of composition to build software systems is quite limited. The reason for this is that supporting software design by composition has proven to be extremely difficult. Instead, inferior approaches, which are limited and often hard-to-use, have been taken because they were easier to support. Approaches such as single and multiple inheritance, aggregation, etc., have been widely used, resulting in fragile base classes, lack of reusability, overwhelming complexity, high rate of defects and failures. Early composition-based systems include HOOD (see earlier reference), ObjecTime Developer by ObjecTime Limited (acquired by Rational Software Corp.), Parts Workbench by Digitalk, and Parts for Java by ObjectShare, Inc. (acquired by Starbase Corp.). Each of these systems was targeted to solve a small subset of problems. None of them provided a solution applicable to a broad range of software application types without impeding severely their performance. Specifically, use of these systems was primarily in (a) graphical user interfaces for database applications and (b) high-end telecommunication equipment. One system that supports composition for a broad range of applications without performance impediments is the system described in the commonly assigned '675 application, with which it is possible to create new, custom functionality entirely by composition and without new program code. This system was commercialized in several products, including ClassMagic and DriverMagic, and has been used to create a variety of software components and applications ranging from graphical user interface property sheets, through Microsoft COM components, to various communications and device drivers. Since 1996, other composition approaches have been attempted in research projects such as Espresso SCEDE by Faison Computing, Inc., and in commercial products such as Parts for Java by ParcPlace-Digitalk (later ObjectShare, Inc.), and Rational Rose RealTime by Rational Software Corp. None of these has been widely accepted or proven to be able to create commercial systems in a broad range of application areas. The only system known to the inventors that allows effective practicing of object composition in a wide area of commercial applications is the system described in the '675 application. The system described in the '675 application and its commercial and other implementations are referred to hereinafter as the "'675 system." Concurrent software systems Unlike hardware, in which different parts of the system operate concurrently, software is fundamentally sequential: processors execute software by reading instructions from memory and interpreting them one instruction at a time. Because of this, implementing software systems that behave in a concurrent fashion always requires specialized and quite complex support. In fact, the task of building concurrent software systems is regarded as the most challenging problem of software engineering. At the same time, more and more applications of software require substantial degree of concurrency. This is true in desktop operating systems and applications, where concurrency makes it possible to share a single processor among multiple applications efficiently. It is even more true in embedded and real-time systems which, by their very nature, have to respond to multiple, usually unrelated, stimuli that originate in the physical world. The need for software systems that are capable of behaving in highly concurrent fashion is especially acute in today's high bandwidth intelligent network equipment, such as high-speed routers and switches, voice and video delivery platforms, network-attached storage devices, and hundreds of other emerging network applications. Traditionally, the primary mechanisms for supporting concurrency in software systems are provided by the operating system. The two predominant models for concurrency implemented by practically all operating systems in existence today are the process model and the thread model. In the process model, the operating system implements, in essence, virtual machines, each with its own memory space and ownership of resources. The operating system then executes multiple virtual machines by scheduling their execution on the processor using one or more scheduling disciplines, such as time-slice and others. The process model is adequate for sharing processor and other hardware resources among multiple independent applications or multiple users. However, it comes at a substantial price: supporting independent virtual machines is expensive both in terms of operating system complexity and in execution overhead. The threading model overcomes these limitations by providing a framework for sharing processor time only. In the threading model, the operating system provides support for creation, execution and synchronization of multiple threads. Each thread is associated, for the duration of its existence, with a specific function or block of code; all threads have access to one and the same memory space and set of hardware resources. The operating system divides processor time among various threads based on their priority, readiness to run and common scheduling disciplines, not unlike in the process model described above. The models described above can be applied both in the case of a single processor system and in systems that provide two or more processors executing in the same memory space (symmetric multiprocessing). The minimal support for concurrency in any software system has to provide adequate solutions to three basic types of issues: (a) creation, destruction and management of multiple threads of execution, (b) mechanisms for synchronization between different threads, and (c) mechanisms for protecting regions of code from being executed simultaneously in two or more threads which would lead to data corruption and race conditions. Concurrency models differ primarily by the approach they take to solving these three problems and the semantics of the solution they provide. Over the last 20 or so years the threading models of most general-purpose operating systems have converged to a large degree, forming a commonly understood concept of threads. In this model, a thread is created by invoking an operating system API and supplying priority and an address of a function which will execute in the new thread. When the thread is created, this function is being invoked and may continue processing by calling other functions and, generally, implement any desired software functionality. Synchronization among threads is achieved by a wide variety of so called "synchronization objects", provided by the operating system. Common synchronization objects include: semaphores, mutexes, signalable events, mailslots, etc. Most synchronization objects operate by "blocking", or suspending the execution of .one or more threads until certain condition occurs, typically as a result of the execution of another thread. Most operating system APIs, at some point or another, block the execution of the thread in which they are invoked in order to be able to operate in a synchronous fashion and return to the application code only after the desired result has been achieved. Protecting code regions from reentrancy can be achieved using some of the synchronization objects described above, such as semaphores or mutexes. However, most modern operating systems implement a special synchronization object called "critical section" for this purpose. A critical section operates in a manner similar to a mutex but with much lower overhead. Further information on the concurrency models implemented in today's most advanced operating systems is available in the following publications: • Modern Operating Systems, ISBN 0135881870, by Andrew S. Tanenbaum, 1992, Prentice Hall; • Microsoft Developers Network Library, April 1999 release, 1 999, by Microsoft Corporation, Redmond, Washington, which is incorporated herein in its entirety by reference thereto; also available online at www.microsoft.com; • VxWorks Programmer's Guide, 5.3.1 , Edition 1 , part number DOC-12067-ZD- 00, by Wind River Systems, Inc., 1 997, Alameda, California, which is incorporated herein in its entirety by reference thereto. Concurrency in object-oriented software As we have seen above, concurrency models defined and implemented by modem operating systems associate threads of execution with code. This creates a serious problem in object-oriented software, where code is typically contained in object classes, which are instantiated and used in many different, disparate subsystems and often unrelated functions of the application. In this environment, associating a thread of execution with the class means that all instances of this class will be forced to execute in that thread, thus creating massive parasitic dependencies between otherwise unrelated aspects of the application in which different instances of that class are used. For this reason, object-oriented software engineering defines a variety of new concurrency models, built on top of the standard threading models, and better applicable to the realities of object-oriented software development. The oldest and best understood of these models is the "active objects" concurrency model. In this model, a separate thread of execution is associated with each instance of each object class, hence the name "active objects". Typically, each active object also requires a separate queue on which requests coming from other objects are enqueued by other threads. The thread associated with the active object dequeues those requests and invokes methods on the objects to execute them. One of the better known implementations of the active objects model is the ObjecTime Developer toolkit which is based on the ROOM method, mentioned herein. In this manner, the active object model ensures that each object operates always in the context of one and the same execution thread - its own. Since the same thread is responsible for handling all requests for this object, requests become naturally serialized: the thread invokes the object; the object processes each request to completion before returning; the thread then takes the next request from the queue and invokes the object again. For this reason, the active object model rarely requires explicit use of synchronization mechanisms. In design terms, synchronization happens along the logical interactions between different object instances. While simple, elegant and easy to understand and use, the active objects concurrency model is extremely expensive in terms of both memory and processing time. Associating a thread, a queue and one or more synchronization objects with every instance of every object class consumes large portion of the system resources; worse, significant delays are introduced on each and every interaction between object instances. As a result, systems based on the active objects model are forced to maintain coarse granularity of objects to minimize overhead, thereby increasing implementation complexity and reducing drastically opportunities for reuse. In order to reduce the overhead related to concurrency, component object models, such as Microsoft COM and CORBA, have introduced a variety of different concurrency models. The best-known of those are the "class threading", in which all instances of a given component class share one or more worker threads, the "apartment threading" model, which extends the class threading model by allowing the developer to associate two or more classes into a group, called "apartment", which shares the same thread of worker threads, and the "free threading" model, in which any thread can enter any object at any time and which, although still better than the operating system provided concurrency model, essentially abandons most of the object-oriented aspects of the concurrency support. Detailed information on these concurrency models is available in the Microsoft Developer Network Library referenced herein. Component object models also introduce the concept of "guarding", or protecting the instance data of a component from being corrupted by simultaneous execution of code in multiple threads, as an alternative to protecting code regions from reentrancy. With guarding, a critical section is typically associated with each instance of the component, and is acquired in the beginning of each object method. As a result, the execution of different methods of the same object instance is effectively serialized, with only one method accessing the instance data structure at any given time. Finally, the Java language implements a concurrency model, in which threads are represented by a standard base class defined by the language library. To become "active" a Java class derives from the thread class; when the class is instantiated, a new thread is created automatically. In addition, Java implements guarding as described above, by defining a special "synchronized" attribute which can be attached when declaring any method of any class that requires guarding. More information on the Java concurrency model is available in the Microsoft Developer Network Library and from the JavaSoft division of Sun Microsystems at www.javasoft.com. All these concurrency models, including the threading models defined by operating systems, create a number of substantial problems in both designing and implementing concurrent software systems of above moderate complexity. The most widely spread problem related to concurrency models is a substantial increase in the size of an average object from under 100 lines of code per class, which is the typical size of a C + + class designed without concurrency considerations, to over 1000 lines of code per class, which is typical for multithreaded component based systems. In addition to the serious increase in complexity and associated development costs and longer time to market, this decrease in granularity has a crippling effect on the reusability of such classes. Another serious problem stems from the fact that an object-oriented concurrent system designed for one of the existing concurrency models effectively has to have two loosely coupled structures: the object interaction structure, which is derived from the functional requirements to the system, and the threading structure, which is determined by performance, response time and scalability requirements. The fact that these two structures interact in practically every object but the relationships between them are not obvious and not easily visible to developers is the source of large portion of the defects and performance problems that plague today's multithreaded software and are all too easily visible to each and every user of a desktop computer. This situation is aggravated additionally with concurrency models that associate threads with classes and objects. In these models, to create a new thread the designer typically has to create a new class or object instance. As a result, performance and concurrency considerations begin to affect the functional decomposition of the system; new classes are being created without sufficient functional reasons, affecting severely the cohesiveness, modularity, reusability and maintainability of the application object models. All these problems result in increased complexity of the software, creating opportunities for new defects, especially types of defects directly related to concurrency, such as deadlocks, race conditions and data corruption. As one skilled in the art to which the present invention pertains knows well, once introduced, these types of defects are extremely difficult to diagnose and correct: it is not unusual so spend a month or more in diagnosing a single reentrancy problem. But the real problem with today's concurrency models comes from the fact that they simply do not provide sufficient degree of concurrency. All of these models have been developed with single processor systems in mind, and then extended to multiprocessor hardware. The substantial costs of operating system threads, in both memory and execution time, as well as the complexity of object oriented concurrency models and the very fact that they associate threads with individual object instances, result in systems that, while adequate for desktop operation, cannot scale well beyond even four simultaneously operating processors. This fact already creates severe problems in software systems targeted toward Internet servers, which are often required to process hundreds of thousands of transactions per second. It is even more severe in software systems targeted for network infrastructure equipment where traffic flows are growing much faster than our ability to process them, and where systems with 8 and more processors are rapidly becoming mainstream. Hardware access in object-oriented software The best way to describe the current state of the art in object-oriented software as related to problems of accessing and controlling hardware is as non-existent. Under most operating systems, access to hardware is an exclusive domain of specialized system components, typically called device drivers. In modern operating systems, device drivers operate in a special, "system", or "kernel" mode of execution, where the protection, safety and even security mechanisms are simplified, circumvented or simple avoided in the name of performance. The fact that device drivers operate in a separate execution environment means that tools and technologies, normally used for application development, cannot be applied to driver development, and therefore to hardware access, without substantial porting effort. As a result, the only object-oriented technology currently available to engineers who build drivers is a C/C + + compiler. Over the last 5 years, a number of attempts, both research and commercial, to use object-oriented techniques based on C + + in device driver development have been made, but were not particularly successful. Since C + + is a very complex language, with a number of non-obvious side effects, in both functionality and performance aspects of the code, the device driver developers community is generally staying away from C + + and, consequently, object-oriented technology in most projects related to accessing and controlling hardware. Since 1997, at least two companies, Blue Water Systems of Bellevue, Washington, (currently a subsidiary of BSQUARE Corp.), and Vireo Software (currently owned by Numega, a division of Compuware Corp., of Farminton Hills, Michigan), have tried to introduce object-oriented frameworks for device drivers; both of these products failed to make a substantial difference in the way drivers are being built. To the best of inventors' knowledge, the only object-oriented technology which has been applied successfully to the problems of building device drivers, and more specifically, to the issues of controlling and accessing hardware, is DriverMagic which is based on the system described in the '675 application. SUMMARY OF THE INVENTION Advantages of the Invention 1 . It is therefore a first advantage of the present invention that it provides a set of fine- granularity, easily reusable components that implement most of the fundamental functionality needed to handle concurrency and hardware access in a wide variety of software applications and systems. 2. It is a second advantage of the present invention to provide a set of reusable components that can be parameterized extensively without modifying their implementation or requiring source code, thus achieving the ability to modify and specialize their behavior to suit many different specific purposes as required. 3. Yet another advantage of the present invention is to provide a set of reusable components that can be combined easily into different composition structures, in new and unanticipated ways, so that even entirely new application requirements and functionality can be met by combining mostly, if not only, pre-existing components. 4. One other advantage of the present invention is to provide a set of reusable components that implements fundamental software mechanisms in a way that makes these mechanisms readily available to system developers, without requiring substantial understanding of their implementation. 5. Yet another advantage of the present invention is that it provides a set of reusable parts such that each of these parts implements one well-defined mechanism or function in a way that allows this function to be combined with other functions in unanticipated ways. 6. Still another advantage of the present invention is that it provides a set of reusable parts defined so that most of these parts can be implemented in a way that is independent from any specific application, so that the parts can be reused easily in new and widely different application areas and domains. 7. Yet another advantage of the present invention is that it provides a set of reusable parts that encapsulate important interactions with hardware and operating system environments, so that components and systems built using these parts have no inherent dependencies on the execution environment and can be moved to new operating systems, environments and hardware without any modifications. 8. Yet another advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions in the context of specific threads of execution, controlled by these parts, so that other parts can perform their functions in the context of those threads. 9. One other advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions in the context of specific threads of execution, and use incoming events to control whether those threads run or remain blocked, so that the manner in which a system of parts executes can be easily controlled from the flow of events in the system. 10. Another advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions at pre-defined moments in time, or periodically, at pre-defined intervals, so that other parts can perform their functions at correct times. 1 1 Net another advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions at pre-defined moments of time, or periodically, and use incoming events to determine when the starting time for the measured periods, so that time-related functions of other parts can be initiated at the occurrence of appropriate events. 1 2. One other advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions at pre-defined moments of time, or periodically, and use incoming events to enable or disable these outgoing interactions, so that time-related functions of other parts can be enabled or disabled in accordance with the flow of events in the system. 1 3Net another advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions at pre-defined moments of time, or periodically, in the context of specific threads of execution, so that time-related functions of other parts can execute in the context of those threads. 14. Another advantage of the present invention is that it provides reusable parts that can be inserted on a connection between other parts without affecting the semantics of that connection, and allow only one thread of execution to pass through them at any given time by blocking any other threads that attempt to pass at the same time. 1 5. A yet another advantage of the present invention is that it provides reusable parts that can protect other parts or structures of parts from being entered by more than one thread at a time even when a second thread attempts to enter these other parts through a different connection. 1 6. One other advantage of the present invention is that it provides reusable parts that can protect other parts or structures of parts from being entered by more than one thread at a time and allow a second thread to enter even when the first thread leaves these other parts through a different connection. 17Net another advantage of the present invention is that it provides reusable parts that can hold requests for arbitrary periods of time until a specific event is received and complete those requests when that event occurs, so that the thread of execution in which the request is submitted does not have to be blocked. 18. Another advantage of the present invention is that it provides reusable parts that can hold requests for arbitrary periods of time and complete those requests based on the history of events received by those parts through a separate terminal, so that other parts can be notified of a given condition without the need to block any thread of execution waiting for that condition to occur. 1 9Net another advantage of the preset invention is that it provides reusable parts that store incoming events and forward them to their outputs in response to specific other events or in a given thread of execution, thereby providing an easy way to desynchronize and decouple interactions between other parts. 20. Another advantage of the present invention is that it provides reusable parts that convert incoming calls or synchronous requests into pairs of asynchronous interactions consisting of requests and replies, so that components that expect that their outgoing requests will be handled synchronously can be combined easily with components that process incoming requests asynchronously. 21 .One other advantage of the present invention is that it provides reusable parts that implement a concurrency model in which threads of execution are associated with events flowing through the system rather than with portions of code, or instances of objects, so that software systems with high degree of parallelism can be constructed easily. 22Net another advantage of the present invention is that it provides reusable parts that can initiate outgoing interactions when hardware interrupts occur, so that other parts can handle those interrupts in a manner independent of the specific operating system or hardware architecture. 23. One other advantage of the present invention is that it provides reusable parts that give other parts access to registers or memory of a peripheral hardware device through a terminal, so that those other parts can control the device in a manner independent of the specific operating system or hardware architecture. 24. Another advantage of the present invention is that it provides reusable parts that give other parts ability to handle interrupts, initiated by a peripheral hardware device, and to interact with that device through its registers or memory, in a manner independent of the specific interrupt level or register and memory address assigned to that device on a given computer system. 25Net another advantage of the present invention is that it provides reusable parts that make it possible to construct structures of parts for controlling peripheral hardware devices by combining a reusable part for receiving interrupts from the device, a reusable part for accessing the registers or memory of the device and a part or a structure of interconnected parts that implements the functionality required to control the device in a manner independent of the specific operating system or hardware architecture. 26. One other advantage of the present invention is that it provides reusable parts that make it easy to design and implement device drivers in a manner independent of the specific operating system or hardware architecture, so that peripheral hardware devices can be used with different computers and operating systems. 27. Another advantage of the present invention is that it defines reusable interfaces and events that make it easy to build reusable software parts and construct software systems by composition using such parts. Summary In providing the above-described and other advantages, the invention provides a method for designing access to a hardware component in a component-based software system, said method comprising the steps of: designating a first software component for receiving interrupts from said hardware component; designating a at least a second software component for accessing input and output ports of said hardware component; designating a third software component for handling interrupts received by said first software component; designating a fourth software component for manipulating said hardware component; connecting said first software component to said third software component; connecting said second software component to said fourth software component. Alternatively, this method can further comprise the step of connecting said third software component and said fourth software component, or said third software component and said fourth software component may comprise one component. The invention further provides a part in a software system, said part comprising: a first terminal for sending out calls; a section of program code for receiving control when an interrupt occurs and sending out a call through said first terminal. Alternatively, the part described immediately above may further comprise a property for configuring which hardware interrupt vector among a plurality of hardware interrupt vectors said part should receive., or a section of program code for registering said part to receive control when said interrupt occurs. The invention further provides a part in a software system, said part comprising: a terminal for receiving requests to access at least one port of a hardware component; a property defining the base address of said port; a section of code that accesses said port when a request is received on said first terminal. Alternatively, the part described immediately above may be further described such that said port is a memory-mapped port or is an input-output port, or wherein said requests include a read request and a write request. The invention further provides a structure of connected parts in a software system, said structure comprising: an interrupt source part for receiving interrupt from a hardware component; at least one port accessor part for accessing ports of said hardware component; at least one controller part for controlling said hardware component. Alternatively, the structure described immediately above may be characterized such that said controller part accesses said hardware component exclusively through said interrupt source part and said port accessor part, or such that said structure further comprises: a connection between said interrupt source part and one of said controller parts; a connection between one of said port accessor parts and one of said controller parts. Also in the alternative, the structures described immediately above may be contained within a composite part in a software system. The invention further provides, in a software system, a part comprising: a first terminal for sending out events in the context of a thread of execution designated by said part; a second terminal for receiving events that control the operation of said part. Alternatively, the part described immediately above may be further characterized such that said first terminal and said second terminal are one terminal, or such that said part further comprises a thread object, or such that said part further comprises a means for providing said thread of execution. The invention further provides, in a software system, a part comprising: a first terminal for sending out events upon the expiration of a time interval. Alternatively, the part described immediately above may be further characterized such that said part further comprises a second terminal for receiving events that control the operation of said part, or such that said part further comprises a timer object, or such that said part further comprises an interrupt source, or such that said part sends events out through said first terminal periodically with a specified time interval between events. The invention further provides, n a software system, a part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded. Alternatively, the part described immediately above may be further characterized such that said means are a synchronization object, or such that said means comprise a third terminal for delegating said prevention to another part, or such that the part further comprises a third terminal for accepting delegation of said prevention, or where the third terminal is included, still further comprising a fourth terminal for accepting delegation of said prevention. The invention further provides a system for protecting parts or structures of parts from being entered by more than one thread of execution at a time, said system comprising: a first part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded, wherein said means comprise a third terminal for delegating said prevention to another part; a second part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded; a third terminal for accepting delegation of said prevention; and a connection between said first part and said second part. In a software system, a part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a first means for indicating that flow of control is entering said part; a second means for indicating that flow of control is returning back from said part. Alternatively, the part described immediately above may be further characterized such that said first means and said second means are one terminal. The invention further provides a system for protecting parts or structures of parts from being entered by more than one thread of execution at a time, said system comprising: a first part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded, wherein said means comprise a third terminal for delegating said prevention to another part; a second part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a first means for indicating that flow of control is entering said part; a second means for indicating that flow of control is returning back from said part; and a connection between said first part and said second part. The invention further provides a system for protecting parts or structures of parts from being entered by more than one thread of execution at a time, said system comprising: a first and a second part, each comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a first means for indicating that flow of control is entering said part; a second means for indicating that flow of control is returning back from said part; a third part comprising a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded; a third terminal for accepting delegation of said prevention; a first connection between said first part and said third part; a second connection between said second part and said third part. In a software system, a part comprising: a first terminal for accepting a first asynchronously completeable request; a second terminal for accepting events; a memory for holding said first asynchronously completeable request; a first means for recognizing a sequence of one or more events received on said second terminal; a second means for completing said first asynchronously completeable request. Alternatively, the part described immediately above may be further characterized such that said memory can hold multiple requests. BRIEF DESCRIPTION OF THE DRAWINGS The aforementioned features and advantages of the invention as well as additional features and advantages thereof will be more clearly understood hereinafter as a result of a detailed description of a preferred embodiment of the invention when taken in conjunction with the following drawings in which: Figure 1 illustrates an event source by thread, DM_EST Figure 2 illustrates a timer event source, DM_EVT Figure 3 illustrates a stackable critical section, ZP_CRT Figure 4 illustrates a advantageous use of the inventive stackable critical section, ZP_CRT Figure 5 illustrates a stackable reverse critical section ZP UNCRT part. Figure 6 illustrates a usage of the ZP UNCRT stackable reverse critical section part Figure 7 illustrates a stackable critical section, DM CRT Figure 8 illustrates a notification to request completion, DM_N2C Figure 9 illustrates a fundamental desynchronizer, DM_FDSY Figure 10 illustrates desynchronizers with own thread, DM_DWT and DM_DOT Figure 1 1 illustrates the internal structure of the DM_DWT desynchronizer Figure 1 2 illustrates the internal structure of the DM_DOT desynchronizer Figure 13 illustrates a usage of the DM_DWT desynchronizer Figure 14 illustrates a usage of two DM_DWT desynchronizers to keep separate the order of events from two event sources Figure 1 5 illustrates a usage of the DM_DOT desynchronizers Figure 1 6 illustrates a bi-directional resynchronizer, DM_RSB Figure 17 illustrates a resynchronizer, DM_RSY Figure 1 8 illustrates the internal structure of the DM_RSY resynchronizer Figure 1 9 illustrates a usage of the DM RSY resynchronizer Figure 20 illustrates a usage of the DM_RSB resynchronizer Figure 21 illustrates a cascaded usage of resynchronizers Figure 22 illustrates an interrupt source, DMJRQ Figure 23 illustrates an I/O port accessor, DMJOP Figure 24 illustrates a device interface to life-cycle adapter, DM_DLC Figure 25 illustrates a PNP life cycle state machine, DM_PNS Figure 26 illustrates the state machine of the DM_PNS part. Figure 27 illustrates how the set of output LFC events is generated Figure 28 illustrates a recommended state transition diagram for LFC event consumers. Figure 29 illustrates a plug-n-play IRP handler, Figure 30 illustrates the internal structure of the DM_PNP plug-n-play IRP handler. Figure 31 illustrates a usage of the DM PNP plug-n-play IRP handler Figure 32 illustrates a IOCTL handler, DMJOC Figure 33 illustrates a driver gateway for IRPs, DMJRPOUT Figure 34 illustrates a plug-n-play power IRP handler, DM_PWR Figure 35 illustrates a device driver opener, DM DOPEN Figure 36 illustrates a usage of the DM_DOPEN device driver opener. Figure 37 illustrates a device driver accessor, DM_DEVACC Figure 38 illustrates the internal structure of the DM_DEVACC device driver accessor Figure 39 illustrates a exception handler/event log, DM_EXC Figure 40 illustrates a callback to 16-bit windows, DM_EDCW1 6 Figure 41 llustrates a callback to 1 6-bit windows on request completion, DM_ECNW1 6 Figure 42 llustrates a USB control pipe, DM USCTL Figure 43 llustrates a USB configurator, DM USCFG Figure 44 llustrates a usage of the DM JSCFG configurator Figure 45 llustrates a USB isochronous pipe, DM USISO Figure 46 llustrates the state machine of the DMJJSISO part Figure 47 llustrates the RQ_BLOCK structure Figure 48 llustrates an interrupt source, ZPJRQ Figure 49 llustrates a usage of the ZPJRQ interrupt source Figure 50 llustrates a usage of the ZPJRQ interrupt source Glossary The following definitions will assist the reader in comprehending the enclosed description of a preferred embodiment of the present invention. All of the following definitions are presented as they apply in the context of the present invention. Adapter a part which converts one interface, logical connection contract and/or physical connection mechanism to another. Adapters are used to establish connections between parts that cannot be connected directly because of incompatibilities. Alias an alternative name or path representing a part, terminal or property. Aliases are used primarily to provide alternative identification of an entity, usually encapsulating the exact structure of the original name or path. Assembly a composite object most of the functionality of which is provided by a contained structure of interconnected parts. In many cases assemblies can be instantiated by descriptor and do not require specific program code. Bind or binding an operation of resolving a name of an entity to a pointer, handle or other identifier that can be used to access this entity. For example, a component factory provides a bind operation that gives access to the factory interface of an individual component class by a name associated with it. Bus, part a part which provides a many-to-many type of interaction between other parts. The name "bus" comes from the analogy with network architectures such as Ethernet that are based on a common bus through which every computer can access all other computers on the network. Code, automatically generated program code, such as functions or parts of functions, the source code for which is generated by a computer program. Code, general purpose program code, such as functions and libraries, used by or on more than one class of objects. COM an abbreviation of Component Object Model, a component model defined and supported by Microsoft Corp. COM is the basis of OLE2 technologies and is supported on all members of the Windows family of operating systems. Component an instantiable object class or an instance of such class that can be manipulated by general purpose code using only information available at run-time. A Microsoft COM object is a component, a Win32 window is a component; a C + + class without run-time type information (RTTI) is not a component. Component model(s) a class of object model based on language-independent definition of objects, their attributes and mechanisms of invocation. Unlike object-oriented languages, component models promote modularity by allowing systems to be built from objects that reside in different executable modules, processes and computers. Connecting process of establishing a connection between terminals of two parts in which sufficient information is exchanged between the parts to establish that both parts can interact and to allow at least one of the parts to invoke services of the other part. Connection an association between two terminals for the purposes of transferring data, invoking operations or passing events. Connection broker an entity that drives and enforces the procedure for establishing connections between terminals. Connection brokers are used in the present invention to create connections exchanging the minimum necessary information between the objects being connected. Connection, direction of a characteristic of a connection defined by the flow of control on it. Connections can be uni-directional, such as when only one of the participants invokes operations on the other, or bidirectional, when each of the participants can invoke operations on the other one. Connection, direction of data flow a characteristic of a connection defined by the data flow on it. For example, a function call on which arguments are passed into the function but no data is returned has uni-directional data flow as opposed to a function in which some arguments are passed in and some are returned to the caller . Connection, logical contract a defined protocol of interaction on a connection recognized by more than one object. The same logical contract may be implemented using different physical mechanisms. Connection, physical mechanism a generic mechanism of invoking operations and passing data through connections. Examples of physical mechanisms include function calls, messages, v-table interfaces, RPC mechanisms, inter-process communication mechanisms, network sessions, etc. Connection point see terminal. Connection, synchronosity a characteristic of a connection which defines whether the entity that invokes an operation is required to wait until the execution of the operation is completed. If at least one of the operations defined by the logical contract of the connection must be synchronous, the connection is assumed to be synchronous. Container an object which contains other objects. A container usually provides interfaces through which the collection of multiple objects that it contains can be manipulated from outside. Control block see Data bus. CORBA Common Object Request Broker Architecture, a component model architecture maintained by Object Management Group, Inc., a consortium of many software vendors. Critical section a mechanism, object or part the function of which is to prevent concurrent invocations of the same entity. Used to protect data integrity within entities and avoid complications inherent to multiple threads of control in preemptive systems. Data bus a data structure containing all fields necessary to invoke all operations of a given interface and receive back results from them. Data buses improve understandability of interfaces and promote polymorphism. In particular interfaces based on data buses are easier to de-synchronize, convert, etc. Data flow direction in which data is being transferred through a function call, message, interface or connection. The directions are usually denoted as "in", "out" or "in-out", the latter defining a bi-directional data flow. Descriptor table an initialized data structure that can be used to describe or to direct a process. Descriptors are especially useful in conjunction with general purpose program code. Using properly designed descriptor tables, such code can be directed to perform different functions in a flexible way . De-serialization part of a persistency mechanism in object systems. A process of restoring the state of one or more objects from a persistent storage such as file, database, etc. See also serialization. De-synchronizer a category of parts used to convert synchronous operations to asynchronous. Generally, any interface with unidirectional data flow coinciding with the flow of control can be de- synchronized using such a part. Event in the context of a specific part or object, any invocation of an operation implemented by it or its subordinate parts or objects. Event-driven designs model objects as state machines which change state or perform actions in response to external events. In the context of a system of objects, a notification or request typically not directed to a single object but rather multicast to, or passed through, a structure of objects. In a context of a system in general, an occurrence. Event, external An event caused by reasons or originated outside of the scope of a given system. Execution context State of a processor and, possibly of regions of memory and of system software, which is not shared between streams of processor instructions that execute in parallel. Typically includes some but not necessarily all processor registers, a stack, and, in multithreaded operating systems, the attributes of the specific thread, such as priority, security, etc. Factory, abstract a pattern and mechanism for creating instances of objects under the control of general purpose code. The mechanism used by OLE COM to create object instances is an abstract factory; the operator "new" in C + + is not an abstract factory Factory, component or part portion of the program code of a component or part which handles creation and destruction of instances. Usually invoked by an external abstract factory in response to request(s) to create or destroy instances of the given class. Flow of control a sequence of nested function calls, operation invocations, synchronous messages, etc. Despite all abstractions of object- oriented and event-driven methods, on single-processor computer systems the actual execution happens strictly in the sequence of the flow of control. Group property a property used to represent a set of other properties for the purposes of their simultaneous manipulation. For example, an assembly containing several parts may define a group property through which similar properties of those parts can be set from outside via a single operation. Indicator a category of parts that provides human-readable representation of the data and operations that it receives. Used during the development process to monitor the behavior of a system in a given point of its structure. Input a terminal w th incoming flow of control. As related to terminals, directional attributes such as incoming and outgoing are always defined from the viewpoint of the object on which the terminal is defined. Interaction an act of transferring data, invoking an operation, passing an event, or otherwise transfer control between objects, typically on a single connection between two terminals. Interaction, incoming in a context of a given object, an interaction that transfers data, control or both data and control into this object. Whenever both control and data are being transferred in one and the same interaction, the direction is preferably determined by the direction of the transfer of control. Interaction, outgoing in a context of a given object, an interaction that transfers data, control or both data and control out of this object. Whenever both control and data are being transferred in one and the same interaction, the direction is preferably determined by the direction of the transfer of control Interface a specification for a set of related operations that are implemented together. An object given access to an implementation of an interface is guaranteed that all operations of the interface can be invoked and will behave according to the specification of that interface. Interface, message-based an interface the operations of which are invoked through messages in message-passing systems. "Message-based" pertains to a physical mechanism of access in which the actual binding of the requested operation to code that executes this operation on a given object is performed at call time. Interface, OLE COM a standard of. defining interfaces specified and enforced by COM. Based on the virtual table dispatch mechanism supported by C + + compilers. Interface, remoting a term defined by Microsoft OLE COM to denote the process of transferring operations invoked on a local implementation of an interface to some implementation running on a different computer or in a different address space, usually through an RPC mechanism. Interface, v-table a physical mechanism of implementing interfaces, similar to the one specified by OLE COM. Marshaler a category of parts used to convert an interface which is defined in the scope of a single address space to a logically equivalent interface on which the operations and related data can be transferred between address spaces. Multiplexor a category of parts used to direct a flow of operations invoked on its input through one of several outgoing connections. Multiplexors are used for conditional control of the event flows in structures of interconnected parts. Name a persistent identifier of an entity that is unique within a given scope. Most often names are human-readable character strings; however, other values can be used instead as long as they are persistent. Name space the set of all defined names in a given scope. Name space, joined a name space produced by combining the name spaces of several parts. Preferably used in the present invention to provide unique identification of properties and terminals of parts in a structure that contains those parts. Object, composite an object that includes other objects, typically interacting with each other. Composites usually encapsulate the subordinate objects. Output a terminal with outgoing flow of control. See also Input. Parameterization a mechanism and process of modifying the behavior of an object by supplying particular data values for attributes defined by the object. Part an object or a component preferably created through an abstract factory and having properties and terminals. Parts can be assembled into structures at run-time. Property a named attribute of an object exposed for manipulation from outside through a mechanism that is not specific for this attribute or object class. Property interface an interface which defines the set of operations to manipulate properties of objects that implement it. Typical operations of a property interface include: get value, set value, and enumerate properties. Property mechanism a mechanism defining particular ways of addressing and accessing properties. A single property interface may be implemented using different property mechanisms, as it happens with parts and assemblies. Alternatively, the same property mechanism can be exposed through a number of different property interfaces. Proxy program code, object or component designed to present an entity or a system in a way suitable for accessing it from a different system. Compare to a wrapper. Repeater a category of parts used to facilitate connections in cases where the number of required connections is greater than the maximum number supported by one or more of the participants. Return status a standardized type and set of values returned by operations of an interface to indicate the completion status of the requested action, such as OK, FAILED, ACCESS VIOLATION, etc. Serialization part of a persistency mechanism in object systems. A process of storing the state of one or more objects to persistent storage such as file, database, etc. See also de-serialization. Structure of parts a set of parts interconnected in a meaningful way to provide specific functionality. Structured storage a mechanism for providing persistent storage in an object system where objects can access the storage separately and independently during run-time. Terminal a named entity defined on an object for the purposes of establishing connections with other objects. Terminal, cardinality the maximum number of connections in which a given terminal can participate at the same time. The cardinality depends on the nature of the connection and the way the particular terminal is implemented. Terminal, exterior a terminal, preferably used to establish connections between the part to which it belongs and one or more objects outside of this part. Terminal, interior a terminal, of an assembly, preferably used to establish connections between the assembly to which it belongs and one or more subordinate objects of this assembly. Terminal interface an interface which defines the set of operations to manipulate terminals of objects that implement it. Terminal mechanism a mechanism defining particular ways of addressing and connecting terminals. A single terminal interface may be implemented using different terminal mechanisms, as happens with parts and assemblies. Thread of execution a unit of execution in which processor instructions are being executed sequentially in a given execution context. In the absence of a multithreaded operating system or kernel, and when interrupts are disabled, a single-processor system has only one thread of execution, while a multiprocessor system has as many threads of execution as it has processors. Under the control of a multithreaded operating system or kernel, each instance of a system thread object defines a separate thread of execution. Wrapper program code, object or component designed to present an entity or a system in a way suitable for inclusion in a different system. Compare to a proxy. DETAILED DESCRIPTION OF THE INVENTION The preferred embodiment is are software component objects (parts). The part are preferably used in conjunction with the method and system described in the '675 application. The terms ClassMagic and DriverMagic, used throughout this document, refer to commercially available products incorporating the inventive System for Constructing. Software Components and Systems as Assemblies of Independent Parts in general, and to certain implementations of that System. Moreover, an implementation of the System is described in the following product manuals: • "Reference - C Language Binding - ClassMagic™ Object Composition Engine", Object Dynamics Corporation, August 1 998, which is incorporated herein in its entirety by reference; • "User Manual - User Manual, Tutorial and Part Library Reference - DriverMagic Rapid Driver Development Kit", Object Dynamics Corporation, August 1998, which is incorporated herein in its entirety by reference; • "Advanced Part Library - Reference Manual", version 1 .32, Object Dynamics Corporation, July 1 999, which is incorporated herein in its entirety by reference; • "WDM Driver Part Library - Reference Manual", version 1 .12, Object Dynamics Corporation, July 1 999, which is incorporated herein in its entirety by reference; • "Windows NT Driver Part Library - Reference Manual", version 1 .05, Object Dynamics Corporation, April 1999, which is incorporated herein in its entirety by reference. Appendix 1 describes preferred interfaces used by the parts described herein. Appendix 2 describes the preferred events used by the parts described herein. 1. Events One inventive aspect of the present invention is the ability to represent many of the interactions between different parts in a software system in a common, preferably polymorphic, way called event objects, or events. Events provide a simple method for associating a data structure or a block of data, such as a received buffer or a network frame, with an object that identifies this structure, its contents, or an operation requested on it. Event objects can also identify the required distribution discipline for handling the event, ownership of the event object itself and the data structure associated with it, and other attributes that may simplify the processing of the event or its delivery to various parts of the system. Of particular significance is the fact that event objects defined as described above can be used to express notifications and requests that can be distributed and processed in an asynchronous fashion. The word "event" is used herein most often in reference to either an event object or the act of passing of such object into or out of a part instance. Such passing preferably is done by invoking the "raise" operation defined by the l_DRAIN interface, with an event object as the operation data bus. The IJDRAIN interface is a standard interface as interfaces are described in the '675 application, it has only one operation, "raise", and is intended for use with event objects. A large portion of the parts described in this application are designed to operate on events. Also in this sense, "sending an event" refers to a part invoking its output IJDRAIN terminal and "receiving an event" refers to a part's l_DRAIN input terminal being invoked. 1.1. Event Objects An event object is a memory object used to carry context data for requests and for notifications. An event object may also be created and destroyed in the context of a hardware interrupt and is the designated carrier for transferring data from interrupt sources into the normal flow of execution in systems based on the '675 system. An event object preferably consists of a data buffer (referred to as the event context data or event data) and the following "event fields": • event ID - an integer value that identifies the notification or the request. • size - the size (in bytes) of the event data buffer. • attributes - an integer bit-mask value that defines event attributes. Half of the bits in this field are standard attributes, which define whether the event is intended as a notification or as an asynchronous request and other characteristics related to the use of the event's memory buffer. The other half is reserved as event-specific and is defined differently for each different event (or group of events). • status - this field is used with asynchronous requests and indicates the completion status of the request (see the. Asynchronous Requests section below). The data buffer pointer identifies the event object. Note that the "event fields" do not necessarily reside in the event data buffer, but are accessible by any part that has a pointer to the event data buffer. The event objects are used as the operation data of the I DRAIN interface's single operation - raise. This interface is intended for use with events and there are many parts described in this application that operate on events. The following two sections describe the use of events for notifications and for asynchronous requests. 1.2. Notifications Notifications are "signals" that are generated by parts as an indication of a state change or the occurrence of an external event. The "recipient" of a notification is not expected to perform any specific action and is always expected to return an OK status, except if for some reason it refuses to assume responsibility for the ownership of the event object. The events objects used to carry notifications are referred to as "self-owned" events because the ownership of the event object travels with it, that is, a part that receives a notification either frees it when it is no longer needed or forwards it to one of its outputs. 1.3. Asynchronous Requests Using event objects as asynchronous requests provides a uniform way for implementing an essential mechanism of communication between parts: • the normal interface operations through which parts interact are in essence function calls and are synchronous, that is, control is not returned to the part that requests the operation until it is completed and the completion status is conveyed to it as a return status from the call. • the asynchronous requests (as the name implies) are asynchronous, control is returned immediately to the part that issues the request, regardless of whether the request is actually completed or not. The requester is notified of the completion by a "callback", which takes a form of invoking an incoming operation on one of its terminals, typically, but not necessarily, the same terminal through which the original request was issued. The "callback" operation is preferably invoked with a pointer to the original event object that contained the request itself. The "status" field of the event object conveys the completion status. Many parts are designed to work with asynchronous requests. Note, however that most events originated by parts are not asynchronous requests - they are notifications or synchronous requests. The "event recoder" (DMJΞRC herein), in combination with other parts may be used to transform notifications into asynchronous requests. The following special usage rules preferably apply to events that are used as asynchronous requests: 1 . Requests are used on a symmetrical bi-directional I DRAIN connection. 2. Requests may be completed either synchronously or asynchronously. 3. The originator of a request (the request 'owner') creates and owns the event object. No one except the 'owner' may destroy it or make any assumptions about its origin. 4. A special data field may be reserved in the request data buffer, referred to as "owner context" - this field is private to the owner of the request and may not be overwritten by recipients of the request. 5. A part that receives a request (through an IJDRAIN. raise operation) may: a) Complete the request by returning any status except ST_PENDING (synchronous completion); b) Retain a pointer to the event object and return ST_PENDING. This may be done only if the 'attr' field of the request has the CMEVT_A_ASYNC_CPLT bit set. In this case, using the retained pointer to execute l_DRAIN. raise on the back channel of the terminal through which the original request was received completes the request. The part should store the completion status in the "status" event field and set the CMEVT_A_COMPLETED bit in the "attributes" field before completing the request in this manner. 6. A part that receives a request may re-use the request's data buffer to issue one or more requests through one of its l_DRAIN terminals, as long as this does not violate the rules specified above (i.e., the event object is not destroyed or the owner context overwritten and the request is eventually completed as specified above). Since in most cases parts intended to process asynchronous requests may expect to receive any number of them and have to execute them on a first-come-first-served basis, such parts are typically assembled using desynchronizers which preferably provide a queue for the pending requests and take care of setting the "status" field in the completed requests. 1.4. The notion of event as invocation of an interface operation It is important to note that in many important cases, the act of invoking a given operation on an object interface, such as a v-table interface, can be considered an event to the large degree similar to events described above. This is especially true in the case of interfaces which are defined as bus-based interfaces; in such interfaces, data arguments provided to the operation, as well as, data returned by it, is exchanged by means of a data structure called bus. Typically, all operations of the same bus-based interface are defined to accept one and the same bus structure. Combining an identifier of the operation being requested with the bus data structure is logically equivalent to defining an event object of the type described above. And, indeed, some of the inventive reusable parts described in this application use this mechanism to convert an arbitrary interface into a set of events or vice-versa. The importance of this similarity between events and operations in bus-based interfaces becomes apparent when one considers that it allows to apply many of the parts, design patterns and mechanisms for handling, distributing, desynchronizing and otherwise processing flows of events, to any bus-based interface. In this manner, an outgoing interaction on a part that requires a specific bus-based interface can be distributed to multiple parts, desynchronized and processed in a different thread of execution, or even converted to an event object. In all such cases, the outgoing operation can be passed through an arbitrarily complex structure of parts that shape and direct the flow of events and delivered to one or more parts that actually implement the required operation of that interface, all through the use of reusable software parts. 2. Concurrency Parts 2.1. Thread Sources Thread sources are parts that generate outgoing events in the context of specific threads of execution which they control. When connected in a structure of parts, a thread source preferably serves as an originator and holder of an execution context in which other parts can operate. Thread sources preferably have a bidirectional terminal, through which they generate, or "fire", outgoing events and receive control events, preferably "enable" and "disable". In addition, thread sources preferably define properties through which their operation can be parameterized, for example, to set the priority of the thread, the size of its stack, security context, and other characteristics that may be desirable to define. When assembled in a structure with other parts, a thread source preferably remains inactive until it receives the first "enable" event from one of these parts. After becoming enabled, the thread source generates a continuous stream of outgoing events in the context of the thread it controls, which are used by other parts to perform their operations. At some point in time or another, a part other than the source may generate a "disable" event. On receiving this event, the thread source becomes disabled and does not generate outgoing events until enabled again. While practical in many cases, the ability to enable and disable the thread source from outside is not required for the advantageous operation of this type of reusable parts. Other means of controlling the operation of the thread source are possible. An example of a thread source is the inventive part DMJΞST described herein. As one skilled in the art to which the present invention pertains can easily see, many other types of the inventive thread source parts can be defined and may be desirable in different classes of applications or different operating environments. For example, in systems where no operating system exists, a thread source may implement the actual scheduling, synchronization and other mechanisms required to provide multiple threads of execution. As another example, in systems where multiple threads of execution are supported directly in hardware, a thread source would define its functionality by interactions with the appropriate hardware. In many cases, it may be beneficial to define different event sources, such as timer source and thread source, so that they have similar boundaries and interfaces, and may be interchanged in the design as required. However, this is a convenience and not necessarily a requirement. Reusable thread source parts have many advantages, among them the ability to separate the creation and management of execution contexts, such as threads, as well as the definition of their characteristics, from the parts and structures of parts that operate in these contexts. 2.2. Timers Timers are event sources that generate outgoing events spontaneously, upon expiration of a given period of time, as is the case with a watchdog timer, or periodically on some time interval, as is the case with a periodic timer. When assembled in structures with other parts, timers provide the ability to perform time-dependent functionality, such as timeouts, in response to events generated by them. Timers preferably have a bidirectional terminal, through which they generate, or "fire", outgoing events and receive control events, preferably "enable" and "disable". In addition, timers preferably define properties through which their operation can be parameterized, such as the time period, periodic versus watchdog mode of operation, and others. Other means of controlling the operation of the timer are possible. When assembled in a structure with other parts, a timer preferably remains inactive until it receives the first "enable" event from one of these parts. After becoming enabled, the timer will generate one or more outgoing events, which are used by other parts to perform their operations. At some point in time or another, even before the timer generates its first outgoing event, a part other than the timer may generate a "disable" event. On receiving this event, the timer becomes disabled and does not generate outgoing events until enabled again. An example of a timer is the inventive part DMJ≡VT described herein. As one skilled in the art to which the present invention pertains can easily see, many other types of the inventive timer parts can be defined and may be desirable in different classes of applications or different operating environments. For example, a timer may be a variation of a thread source that blocks its thread for the specified period of time and generates an outgoing event when the thread becomes unblocked again. As another example, in systems where no operating system timer service is available the timer may be assembled with an interrupt source described herein to implement the actual timer service functionality providing multiple timers for applications. Yet another example is a specialized timer implemented over a peripheral real-time clock device, which would have the ability to fire at absolute calendar times or can be set to expire months or years later, even if the systems goes through power cycles in the meantime. Reusable timers have many advantages, among them the ability to insulate the rest of the application from an important class of operating system or hardware-dependent interactions. 2.3. Critical sections Critical sections are parts that can be inserted on connections between other parts without affecting the semantics of those connections, and protect a specific part or structure of parts from being reentered by two or more threads at the same time, even when those threads attempt to enter the protected structure or region through two or more different connections. Critical sections preferably have an "in" terminal for receiving incoming interactions and an "out" terminal for forwarding those interactions to the structure of parts being protected. In addition, critical sections preferably have a synchronization object, preferably semantically equivalent to the critical section object found in operating systems like Microsoft Windows NT, for blocking threads that should be prevented from entering the protected structure. Critical sections preferably have additional "crtjn" and "crt_out" terminals for connecting more than one instances of critical sections together whenever they are used to protect more than one connection in a synchronized fashion. In these cases, a separate instance of the critical section is preferably inserted on each connection to be protected and its "crt_out" terminal preferably is connected to the "crtjn" terminal of the closest other critical section instance that guards the same region. In a chain like this, at least one of the instances of the critical section will preferably always remain with its "crt_out" terminal unconnected. Examples of critical sections include the inventive parts ZP CRT and DM_CRT. An important variation of a critical section part is a part that "unguards" the protected region when the thread which was operating inside the region leaves through an outgoing interaction to a part outside of the region. In this manner, the protected region can be reentered immediately by another thread, reducing substantially the . response time of the function implemented in the region. This type of critical sections preferably operates in a manner opposite of the normal critical sections, and are preferably included in the same chain as at least one normal critical section. An example of this type of critical sections is the inventive part ZPJJNCRT described herein. One skilled in the art to which the present invention pertains will recognize that other types of the inventive critical section parts are possible. By way of example, a critical section can be implemented as a combination of two parts: (a) the part that contains the actual synchronization object and has a "crtjn" input terminal, and (b) an "enter/leave" part that contains no synchronization objects but is inserted on the connection that requires guarding and is also connected to the "crtjn" terminal of the first part. 2.4. Notification to request completion converters Notification to request completion converters ("N2C converters" hereinafter) are parts that hold incoming requests until a particular event is received. When assembled in a structure with other parts, these converters make it possible for those other parts to wait for an occurrence of a specific event without causing a thread of execution to be blocked or to poll for this event. N2C converters preferably have a bidirectional "req" terminal for receiving incoming requests and forwarding the request completion events and an input "nfy" terminal for receiving events being monitored. In addition, N2C converters preferably have state for tracking what events have already been received, and storage for pending requests received through the "req" terminal. N2C converters preferably have properties for configuring the part instance with identifiers of events to be monitored and with the desired mode of operation. An example of N2C converter is the inventive part DM_N2C described herein. As one skilled in the art to which the present invention pertains, many other types of the inventive N2C converters can be defined and may be desirable in different classes of applications or in different operating environments. By way of example, N2C converters may also have a terminal "reset" for aborting currently pending requests. 3. Hardware Access Parts 3.1. Interrupt sources Interrupt sources are parts that generate outgoing events whenever a hardware interrupt occurs. When connected in a structure of parts, the interrupt source preferably provides the event on which other parts will begin performing their function, which is preferably related to serving the hardware that originated the interrupt or providing operating system services. Interrupt sources preferably have an output terminal "out" for sending out events whenever an interrupt occurs. Interrupt sources preferably have properties for configuring various parameters of the their operation, such as the interrupt vector number of the hardware interrupt to be used. Interrupt sources may also have an input "ctl" terminal for controlling the interrupt source, allowing other parts to enable and disable the interrupt source. When the interrupt source is disabled it does not generate an outgoing event even if the hardware interrupt occurs; alternatively, when disabled, the interrupt source preferably disables the hardware interrupt through the interrupt controller or a similar mechanism for controlling interrupts. Interrupt sources preferably have means for acknowledging the interrupt, so that further interrupts from the same and other devices may continue to come. Interrupt sources may generate an additional event on their output after they have acknowledged the interrupt, allowing parts connected to the interrupt source to complete processing of the interrupt without preventing other interrupts from being handled. Examples of interrupt sources include the inventive parts DMJRQ and ZPJRQ described herein. As one skilled in the art to which the present invention pertains can easily see, many other types of the inventive interrupts source parts can be defined and may be desirable in different classes of applications or different operating environments. For example, in systems where no operating system exists, the interrupt source may directly manipulate the interrupt controlling hardware and set the interrupt vector so that the interrupt source will receive control when the interrupt occurs. As another example, the interrupt source may include means for sharing a single hardware interrupt between different event sources, so that the hardware interrupt may be shared between two or more devices without requiring modifications in the structure of parts that controls these devices when they use separate hardware interrupts. 3.2. Port Accessors Port accessors are parts that provide access to registers or memory of peripheral hardware devices. When connected in a structure of parts, port accessors are preferably the only software that directly accesses the registers and memory of those devices, allowing the remaining parts that control the devices to be independent of the means for access used on a particular system. Port accessors preferably have an input "in" terminal for receiving requests for accessing registers or memory of the hardware devices. Port accessors preferably also have one or more properties for configuring the port accessor with the base address and other characteristics of the registers and memory to be accessed. Another benefit of using port accessors to access hardware devices is that since all other parts do not access the hardware directly, other parts may be inserted before or in place of the port accessors, allowing emulation or modification of part or the whole behavior of the hardware device being accessed. An example of a port accessor is the inventive part DMJOP described herein. As one skilled in the art to which the present invention pertains can easily see, many other types of the inventive port accessors can be easily defined and may be desirable in different classes of applications or different operating environments. For example, in systems where an operating system provides means for accessing the registers of hardware devices, the port accessor will use this means; in systems without an operating system, the port accessor will directly access the registers or memory of the device. Another example is a port accessor that can access registers of the hardware device either through input/output ports or through memory mapped registers. Yet another example, a port accessor may provide access to memory embedded on the device or shared with the processor. One other example is a port accessor that provides a different interface for accessing the hardware registers or memory, such with different word sizes, block access, and many others. 4. CONCURRENCY PARTS DETAILS 4.1. Thread Sources 4. 1. 1. DM EST - Event Source by Thread Fig. 1 illustrates the boundary of the inventive DMJΞST part. DMJΞST is an event source that generates both singular and periodic events for a part connected to its evs terminal. DMJΞST is armed and disarmed via input operations on its evs terminal and generates events by invoking the fire output operation on the same terminal. A user-defined context is passed to DMJΞST when armed and is passed back in the fire operation call when the time out period expires. DMJΞST allows itself to be armed only once. If DMJΞST has not been armed to generate periodic events, it may be re-armed successfully as soon as the event is generated; this includes being re-armed while in the context of the fire operation call. DMJΞST may be disarmed at any time. Once disarmed, DMJΞST will never invoke the fire operation on evs until it is re-armed. The context passed to DMJΞST when disarming it must match the context that was passed with the arm operation. DMJΞST may be parameterized with default values to use when generating events and flags that control the use of the -defaults and whether or not DMJΞST automatically arms itself when activated. These properties can significantly simplify the use of DMJΞST in that it is possible to simply connect to and activate DMJEST to obtain a source of events. Boundary Terminals Terminal "evs" with direction "Bidir" and contract In: l_EVS Out: l_EVS_R. Note: Synchronous, v-table, cardinality 1 Used to arm and disarm the event source on the input and also to send the event on the output when the time period expires. Events and notifications DMJΞST has no incoming or outgoing events. The "event" generated by DMJΞST is a fire operation call defined in I_EVS_R; it is not an event or notification passed via an IJDRAIN interface. Special events, frames, commands or verbs None. Properties Property "force defaults" of type "UINT32" . Note: Boolean. If TRUE, the time and continuous properties override the values passed in the IJΞVS bus. Default is FALSE. Property "auto_arm" of type "UINT32". Note: Boolean. If TRUE, DM_EST will automatically arm itself on activation. DMJΞST will return CMST_REFUSE on any evs. arm calls. The force_defaults property must be set to TRUE for this property to be valid. If not, DM_EST will fail its activation. Default is FALSE. Property "thread_priority" of type "UINT32" . Note: Thread priority of DM_EST's worker thread. Default is THREAD_PRIORITY_NORMAL. Property "time" of type "SINT32". Note: Default time period in milliseconds. Valid range is 1 - 0x7fffffff. When this time period expires (after DMJΞST is armed), DMJEST will fire an event (by calling evs. fire). Default is -1 . Property "continuous" of type "UINT32". Note: Boolean. If TRUE and DM_EST is armed, generate periodic events until disarmed. Default is TRUE. Encapsulated interactions DMJΞST uses the following NT Kernel Mode APIs to control event objects and its worker thread: KelnitializeEventf) KeSetEventO • KeClearEventO PsCreateSystemThreadO PsTerminateSystemThreadO KeDelayExecutionThreadO KeWaitForSingleObjectO • KeWaitForMultipleObjectsf) DMJΞST uses the following Windows 95 Kernel Mode APIs to control event objects and its worker thread: HeapAllocateO HeapFreef) • SignallDO BlockOnlDO Get System Time() Time_Slice_Sleep() VWIN32_CreateRingOThread() Set_Thread_Win32_Pri() Set_Async_Time_Out() Create_Semaphore() Destroy_Semaphore() Signal_Semaphore_No_Switch() Wait_Semaphore() Responsibilities When armed with a time period, generate timer events by calling evs. fire. Generate either one-shot timer events that require arming for each or periodic timer events that require a single arm operation. Allow the re-arming/disarming of the event source while in the context of a evs. fire call. Allow disarming of single or periodic timer events. No events are to be sent out evs. fire at any time while DMJΞST is disarmed (even if periodic timer events are pending). Theory of operation Mechanisms Using a separate thread for arm/disarm requests DMJΞST uses a separate thread to arm/disarm the event source. The thread waits for an arm or disarm request and acts appropriately. DM_EST uses events to synchronize the execution and termination of the thread. Each instance of DMJΞST maintains its own thread. Arming the event source When an arm request arrives (within the execution context of a part using DMJΞST) the thread created by DMJΞST is awakened and begins waiting for the specified time period to expire using KeDelayExecutionThreadO. When the time period has expired the thread will fire an event through the evs terminal. The event source may be re-armed while in the execution context of a fire event. Upon return from the fire event, the thread will re-arm the event source with the parameters passed with the arm request. Note that arm requests fail with CMST_REFUSE if DMJΞST was parameterized to generate periodic events (continuous property is TRUE). Disarming the event source When a disarm request arrives (within the execution context of a part using DMJΞST), the thread will disarm the event source (if armed). The event source will not fire again until it is re-armed. The event source may be disarmed while in the execution context of a fire event. Upon return from the fire event, the thread will disarm the event source canceling any previous arm requests. The event source will not fire again until it is re-armed. Deactivation/Destruction of DM EST When the event source is destroyed, DMJΞST waits for the worker thread to terminate. DMJΞST will then free its resources and will not fire again until it is created, activated and armed. DMJΞST may be deactivated while in the execution context of a fire event. Use Cases Using the event source as a one-shot timer 1 . DM_EST and Part A are created. 2. Part A connects its evs terminal to DMJΞST's evs terminal. 3. Both parts are activated. 4. Part A arms DMJΞST passing a time period and a context. 5. At some later point, the time period expires. 6. DMJΞST's worker thread calls Part A's fire operation through its evs terminal passing the status CMST_OK and the context associated with the event (passed with the arm request). 7. Part A does one of the following: a. re-arms the event source - the event source is armed and will fire again when appropriate b. continues execution - the event source is disarmed and will not fire again until Part A re-arms it at a later time Using the event source as a periodic timer 1 . DM_EST and Part A are created. 2. Part A connects its evs terminal to DM EST's evs terminal. 3. DMJΞST is parameterized with the following: a. force_defaults is TRUE b. auto_arm is FALSE c. time is set to some time interval for each event d. continuous is TRUE 4. Both parts are activated. 5. Part A arms DMJΞST passing a context. 6. At some later point, the time period expires. 7. DMJΞST's worker thread calls Part A's fire operation through its evs terminal passing the status CMST_OK and the context associated with the event (passed with the arm request). 8. Part A does one of the following: c. disarms the event source - the event source is disarmed and will not fire again until Part A re-arms it at a later time d. continues execution - the event source will re-arm itself and will fire again at a later time 9. If the fire_delay property is not zero, DMJΞST sleeps for fire_delay milliseconds before arming itself again for the next fire event. 10. Steps 6-8 are executed many times as long as the event source remains armed. Auto-arming the event source 1 . DMJΞST and Part A are created. 2. Part A connects its evs terminal to DMJΞST's evs terminal. 3. DMJΞST is parameterized with the following: a. force_defaults is TRUE b. auto_arm is TRUE c. time is set to some time interval for each event d. continuous is TRUE 4. Both parts are activated. 5. At some later point, the time period expires. 6. DMJΞST's worker thread calls Part A's fire operation through its evs terminal passing the status CMST OK. 7. Part A does one of the following: a. disarms the event source - the event source is disarmed and will not fire again until Part A re-arms it at a later time b. continues execution - the event source will re-arm itself and will fire again at a later time 8. Steps 5-7 are executed many times as long as the event source remains armed. Disarm event source to terminate firing 1 . DM EST and Part A are created. 2. Part A connects its evs terminal to DMJΞST's evs terminal. 3. Both parts are activated. 4. Part A arms DMJΞST passing a time period and a context. 5. At some later point before the time period expires Part A disarms the event source. 6. The event source is disarmed and will not fire again until it is rearmed. Deactivation/Destruction of DM EST while the event source is armed 1 . DMJEST and Part A are created. 2. Part A connects its evs terminal to DMJΞST's evs terminal. 3. Both parts are activated. 4. Part A arms DM EST passing a time period and a context. 5. At some later point before the time period has expired, DM EST is deactivated (not necessarily by Part A). 6. DM EST signals the worker thread to stop waiting for the specified time period to expire. 7. DMJΞST waits for its worker thread to terminate and releases all its resources. 8. DM_EST is destroyed. 4.2. Timers 4.2. 1. DM EVT - Timer Event Source Fig. 2 illustrates the boundary of the inventive DMJΞVT part. DMJΞVT is a timer event source that generates both singular and periodic timer events for a part connected to its evs terminal. DMJΞVT is armed and disarmed via input operations on its evs terminal and generates timer events by invoking the fire output operation on the same terminal. A user defined context is passed to DMJΞVT when armed and is passed back in the fire operation call when the time out period expires. DMJΞVT allows itself to be armed only once. If DMJΞVT has not been armed to generate periodic timer events, it may be re-armed successfully as soon as the timer event is generated; this includes being re-armed while in the context of the fire operation call. DMJΞVT may be disarmed at any time. Once disarmed, DMJΞVT will never invoke the fire operation on evs until it is re-armed. The context passed to DMJΞVT when disarming it must match the context that was passed with the arm operation. DMJΞVT may be parameterized with default values to use when generating events and flags that control the use of the defaults and whether or not DMJΞVT automatically arms itself when activated. These properties can significantly simplify the use of DMJΞVT in that it is possible to simply connect to and activate DMJΞVT to obtain a source of events. DMJΞVT is boundary compatible with the DMJΞVS part. This part is only available in Windows NT/95/98 Kernel Mode environments. Boundary Terminals Terminal "evs" with direction "Bidir" and contract In: l_EVS Out: l_EVS_R. Note: Used to arm and disarm the event source on the input and to send the timer event on the output when the time period expires. Events and notifications DMJΞVT has no incoming or outgoing events. The timer "event" generated by DMJEVT is a fire operation call defined in l_EVS_R; it is not an event or notification passed via an I DRAIN interface. Special events, frames, commands or verbs None. Properties Property "force_defaults" of type "UINT32". Note: Boolean. If non-zero, the time and continuous properties override the values passed in the IJΞVS bus. Default is FALSE. Property "auto_arm" of type "UINT32". Note: Boolean. If non-zero, DM EVT will automatically arm itself on activation. DMJΞVT will return CMST_REFUSE when on any call evs. arm call. The force_defaults property must be set to TRUE for this property to be valid. If not, DMJΞVT will fail its activation. Default is FALSE. Property "time" of type "SINT32". Note: Default time period in milliseconds. Valid range is 1 - 0x7fffffff. Default is 500. Property "continuous" of type "UINT32". Note: Boolean. If non-zero and DM EVT is armed, generate periodic events until disarmed. Default is FALSE. Encapsulated interactions Windows NT Kernel Mode DMJΞVT uses KelnitializeTimerExO and KelnitializeDpcO to initialize a timer object and a deferred procedure. DMJΞVT utilizes the kernel-mode services KeSetTimerExO and KeCancelTimerO to generate and cancel timer events. DMJΞVT does not create any threads. Windows 95/98 Kernel Mode DM EVT utilizes the VMM services Set_Async_Time_Out() and Cancel " TimeJDutO to generate and cancel timer events. DMJΞVT does not create any threads. 4.2.2. Specification Responsibilities When armed with a time period, generate timer events by calling evs. fire. Generate either one-shot timer events that require arming for each or periodic timer events that require a single arm operation. Allow the re-arming of the timer event source while in the context of a evs. fire call. Allow disarming of single or periodic timer events. No events are to be sent out evs. fire at any time while DMJΞVT is disarmed (even if periodic timer events are pending). Theory of operation State machine None. Data structures used in Windows 95/98 Kernel Mode environment Because the embedded timer event handler is invoked in an interrupt context, it cannot access DMJΞVT's self. To accommodate this restriction, a structure is allocated that can be shared between DM_EVT's operations and the timer event handler utilizing an interrupt level critical section for synchronization. This structure is allocated on each arm and is freed either by a disarm call or by the message handler in DMJΞVT's de-synchronization mechanism (see the following section). Access to this structure is shared between operations in DMJΞVT and the embedded timer event handler, requiring an interrupt level critical section to synchronize access to it. No specific data structures are used in Windows NT Kernel Mode implementation. Mechanisms used in Windows NT Kernel Mode environment Timer Initialization At creation time DMJΞVT initializes a kernel-mode timer object and a deferred procedure call structure (KDPC). DMJΞVT initializes the KDPC with the timer callback function and first callback parameter a pointer to self. The KDPC structure is passed as a parameter when DM_EVT set the timer object. Generating timer events DMJΞVT passes a time period and the deferred procedure structure to KeSetTimerExO. When the time period expires, the deferred procedure is invoked which posts a VM_EVT_TIMER message to DMJΞVT to de-synchronize the timer object event. Arming and disarming DM_EVT is armed and disarmed via the evs operation calls arm and disarm, respectively. When called on evs. arm, DMJΞVT sets the time period with KeSetTimerExO and returns. The timer event set by KeSetTimerExO can be periodic or single event, depend on the parameters passed. When called on evs. disarm, DMJΞVT disarmd the timer by calling KeCancelTimerO. De-synchronization The VMJΞVT " TIMER message handler checks the context against the one stored in the self (changed after each disarm operation) and, if it matches, invokes the evs. fire operation, otherwise it returns CMSTJDK. Mechanisms used in Windows 95/98 Kernel Mode environment Generating timer events DMJΞVT passes a time period to and registers a callback procedure with the VMM service Set_AsyncJ ime_Out(). When the time period expires, the callback procedure is invoked, which posts a message to DMJΞVT to de-synchronize the VMM timer event (called during interrupt). The method that receives the posted message invokes the evs. fire operation synchronously, if DMJΞVT's state allows (e.g., the timer was not disarmed before message was de-queued). Arming and disarming DMJΞVT is armed and disarmed via the evs operation calls arm and disarm, respectively. When called on evs. arm, DMJΞVT creates a critical section and allocates a context for the embedded timer and registers it with Set_AsyncJTime_Out(). DM EVT also passes Set_Async_Time_Out() a callback and a time period. The pointer to the context is saved in the self. When called on evs. disarm, DM_EVT checks the embedded timer context and, if a timer event is pending, calls Cancel " TimeJDutO and frees the context. If a timer event is not pending, the critical section is destroyed and the pointer to the context in the self is set to NULL. De-synchronization When the callback procedure registered with Set_Async_Time_Out is invoked, the state in the received context is checked to determine if a periodic timer is specified, at which a new event is registered. A VM_EVT_FIRE message is then posted to DMJΞVT. The VMJΞVT FIRE message handler checks the context pointer against the one stored in the self (by the arm operation) and, if it matches, invokes the evs. fire operation. If there are no pending timer events, DMJΞVT will free the context and move into a disarmed state. Managing the context for the embedded timer The event handler for the embedded system timer executes in an interrupt context, therefore, it cannot access the self. A context that can be shared between DMJΞVT's normal operation handlers and the timer event handler is allocated by the evs. arm operation and freed either by the evs. disarm operation or, if already referenced by a posted message, by the handler that receives the message. Reference counters are maintained inside the structure to store the necessary state to determine when the context should be freed (more than one message with the same context may be queued). Additionally, a critical section object is stored in the context and is always accessed before any other field is touched. The critical section is used for synchronization of access to this context. 4.3. Critical Regions 4.3. 1. ZP CRT - Stackable Critical Section Fig. 3 illustrates the boundary of the inventive ZP CRT part. ZP_CRT is a synchronization part used to serialize access through one or more interfaces in a multi-threaded system using a critical section. ZP_CRT may be inserted into the path of any uni-directional connection. All operation calls invoked through the in terminal are redirected through the out terminal only after a successful entry into a critical section. The critical section may be maintained by ZP_CRT or by another part connected to the crt_out terminal. If the crt_out terminal is not connected, ZP_CRT uses its own critical section; otherwise ZP CRT issues 'enter' and 'leave' calls to this terminal instead. This allows multiple instances of ZP_CRT to use the same critical section object, thus serializing operations on multiple interfaces through a common critical section. All operation calls invoked on the crtjn terminal are either redirected to crt_out (if connected) or are executed on ZP_CRT's own critical section otherwise. Boundary Terminals Terminal "in" with direction "in" and contract I POLY. Note: Infinite cardinality, floating, reconnectable, synchronous. The call from in is redirected to out after successfully entering a critical section. ZP CRT does not alter the operation bus passed with the call. Terminal "out" with direction "out" and contract l_POLY. Note: Single cardinality, floating, reconnectable, synchronous. The call from in is redirected through this terminal after successfully entering a critical section. Terminal "crtjn" with direction "in" and contract I CRT. Note: Infinite cardinality, floating, reconnectable, synchronous. If crt_out is connected, ZP_CRT passes the calls received from crtjn through crt_out. If crt_out is not connected, ZP_CRT uses its own critical section to satisfy requests on this terminal. Terminal "crt_out" with direction "out" and contract l_CRT. Note: Single cardinality, floating, synchronous. If connected, ZP_CRT uses this terminal to enter and leave critical sections. Properties Property "attr" of type "uint32". Note: Critical section attributes. This should be set to 0. All other values are reserved. Default = 0. Events and notifications None. Environmental Dependencies Encapsulated Interactions Specification Responsibilities 1 . Implement procedure for redirecting requests to enter/leave operations for critical sections to crt out if connected. 2. Protect operations invoked on the in terminal using the delegation procedure and redirect them to out. External States None. Use Cases Delegation Procedure ZP CRT decides whether to maintain its own critical section or let another part maintain it. If the crt_out terminal is not connected, ZP_CRT will use its own critical section, otherwise all critical section operations are passed through crt_out. Protecting operations on the "in" terminal and redirection All operations invoked through the in terminal are protected using the delegation procedure. If the critical section is entered successfully, the operation is redirected through the out terminal. An operation call may be blocked waiting to enter the critical section. The operation bus passed with the call is not interpreted by ZP_CRT. Typical Usage Fig. 4 illustrates an advantageous use of the inventive ZP_CRT part. This example shows how two instances of CRT can be used to synchronize access to a part that has two inputs. The diagram shows a part that produces a pair of identical events on one of its outputs in response to an event received on its 'in' terminal. The 'ctl' input is used to select the output to which the event pairs are sent ('outr or 'out2'). To make sure that output switching does not happen between the two events of an event pair, the part should not be entered through 'ctl' and 'in' at the same time. This protection is implemented by connecting two instances of CRT so that they use one and the same guard object (owned by the g2 instance) to protect both the 'in' and the 'ctl' inputs. Note that since CRT allows re-entry from the same thread, this design does not prevent a recursion from OutV or Out2' to the 'ctl' terminal to cause an "illegal" switch in the middle of an event pair. 4.3.2. ZP UNCRT - Stackable Reverse Critical Section Fig. 5 illustrates the boundary of the inventive ZP UNCRT part. ZPJJNCRT is a synchronization part that is used in pair with ZP_CRT to serialize access through one or more interfaces in a multi-threaded system. ZPJJNCRT allows for a critical section to be left during the processing of a call. ZP UNCRT may be inserted into the path of any uni-directional connection. All operation calls invoked through the in terminal are redirected through the out terminal only after a successful releasing a critical section. The critical section may be maintained by ZP UNCRT or by another part connected to the crt_out terminal. If the crt_out terminal is not connected, ZPJJNCRT uses its own critical section; if the crt out terminal is connected, ZP UNCRT issues 'enter' and 'leave' calls to this terminal instead. This allows multiple instances of ZPJJNCRT and/or ZP_CRT to use the same critical section object, thus serializing operations on multiple interfaces through a common critical section. All operation calls invoked on the crtjn terminal are either redirected to crt_out (if connected) or are executed on ZPJJNCRT's own critical section otherwise. ZPJJNCRT used with ZP_CRT provide a way to serialize the access to a certain execution region. ZP UNCRT may not be invoked at interrupt time. Boundary Terminals Terminal "in" with direction "In" and contract l_POLY. Note: Infinite cardinality, floating, activetime, synchronous. The call from in is redirected to out after successfully leaving a critical section. When the redirected call completes, ZP UNCRT re-enters the critical section. ZPJJNCRT does not alter the operation bus passed with the call. Terminal "out" with direction "Out" and contract l_POLY. Note: Single cardinality, floating, activetime, synchronous. The call from in is redirected through this terminal after successfully leaving a critical section. When the redirected call completes, ZP UNCRT re-enters the critical section. Terminal "crtjn" with direction "In" and contract l_CRT. Note: Infinite cardinality, floating, activetime, synchronous. If crt out is connected, ZPJJNCRT passes the calls received from crtjn through crt_out. If crt_out is not connected, ZPJJNCRT uses its own critical section to satisfy requests on this terminal. Terminal "crt_out" with direction "Out" and contract l_CRT. Note: Single cardinality, floating, synchronous. If connected, ZPJJNCRT uses this terminal to enter and leave critical sections. Properties Property "attr" of type "uint32" . Note: Critical section attributes. This should be set to 0. All other values are reserved. Default = 0. Events and notifications None. Environmental Dependencies Encapsulated interactions Specification Responsibilities 1 . Implement procedure for redirecting requests to enter/leave operations for critical sections to crt_out if connected. 2. Unprotect operations invoked on the in terminal using the delegation procedure and redirect them to out. External States None. Use Cases Delegation Procedure ZPJJNCRT decides whether to maintain its own critical section or let another part maintain it. If the crt_out terminal is not connected, ZPJJNCRT will use its own critical section, otherwise all critical section operations are passed through crt out. Unprotecting operations on the "in" terminal and redirection All operations invoked through the in terminal are unprotected using the delegation procedure. If the critical section is leaved successfully, the operation is redirected through the out terminal. The operation bus passed with the call is not interpreted by ZP UNCRT. When the call completes, ZPJJNCRT re-enters the critical section. An operation call may be blocked waiting to enter the critical section. Typical Usage Fig. 6 illustrates an advantageous use of the inventive ZP UNCRT part. CRT and UNCRT can be used to make a part that is guarded while it is performing some "internal processing" but allows re-entry when control leaves the part through the output terminal. This example is a part writes a record into a file upon each call to its input before forwarding the call to its output. To avoid the series of operations needed to open the file, write into it and close it from being interrupted, the part's input is guarded with CRT (g1). Once the write operation is completed, there is no need to prevent other threads from re-entering the part, even if the original call has not yet returned control - therefore the guard is "released" before forwarding the call to the outptut, using the UNCRT instance (g2). Note that the guard is entered again on the "unwind" path, when control returns from the call to 'out' and before it is returned to 'in' when it is released again. This gives the log part the chance to run in guarded context again, after it receives control back from its 'out' terminal and before it returns. Following is a possible sequence of operations that illustrates how the above assembly works: 1 . Thread A enters the assembly through 'in'. 2. Execution passes through g1 , acquiring the guard, before the sequence of writing into the file begins. 3. While the file is being written, a higher-priority thread B interrupts A and comes to the 'in' terminal. Passing through the 'g1 ' will cause it to block because A has already acquired the guard. 4. Thread A continues execution and completes the file write operation. The execution then proceeds to the assembly's 'out' terminal, passing through g2 (UNCRT). At this time the guard is released, which now allows thread B to enter log. If the UNCRT instance (g2) were omitted, thread B would remain blocked until thread A returns back from the call to the assembly's 'out' terminal and unwinds all the way back to g1 . 5. A new file transaction is executed by thread B, before it goes through 'out' and returns back. 6. Etc. 4.3.3. DM CRT - Stackable Critical Section Fig. 6 illustrates the boundary of the inventive DM_CRT part. DM_CRT is used to serialize access through one or more interfaces in a multithreaded system. DM CRT is inserted between bus-based cdecl v-table connections. All operation calls invoked through the in terminal are redirected through the out terminal only after a successful entry into a critical section. The critical section may be maintained by DM_CRT or by another part connected to the crt_out terminal. If the crt out terminal is not connected, DM_CRT will use its own critical section. If the crt_out terminal is connected, this terminal is used for the critical section. This enables the ability to create a cascaded critical section where many DM_CRT's are connected to each other; serializing operations on multiple interfaces through a common critical section. All operation calls invoked on the crtjn terminal are either redirected to crt_out (if connected) or are executed by DM CRT through its critical section. Boundary Terminals Terminal "in" with direction "In" and contract I POLY. Note: Infinite cardinality, floating, activetime, synchronous. The call from in is redirected to out after successfully entering a critical section. DM_CRT does not alter the operation bus passed with the call. Terminal "out" with direction "Out" and contract I POLY. Note: Single cardinality, floating, activetime, synchronous. The call from in is redirected through this terminal after successfully entering a critical section. Terminal "crtjn" with direction "In" and contract l_CRT. Note: Infinite cardinality, floating, activetime, synchronous. If crt_out is connected, DM_CRT passes the calls received from crtjn through crt_out. If crt_out is not connected, DM_CRT uses its own critical section to satisfy requests on this terminal. Terminal "crt_out" with direction "Out" and contract I_CRT. Note: Single cardinality, floating, synchronous. If connected, DM_CRT uses this terminal to enter and leave critical sections. Events and notifications None. Special events, frames, commands or verbs None. Properties Property "attr" of type "DWORD" . Note: Critical section attributes. May be either CMCRT_A_NONE or CMCRT_A_FAST. DM CRT does not allow named critical sections. Default = CMCRT_A_NONE Encapsulated interactions None. Specification Responsibilities 1 . Implement procedure for redirecting requests to enter/leave operations for critical sections to crt_out if connected. 2. Protect operations invoked on the in terminal using the delegation procedure and redirect them to out. Theory of operation State machine None. Main data structures None. Mechanisms Delegation Procedure DM_CRT decides whether to maintain its own critical section or let another part maintain it. If the crt_out terminal is not connected, DM_CRT will use its own critical section, otherwise all critical section operations are passed through crt_out. Protecting operations on the "in" terminal and redirection All operations invoked through the in terminal are protected using the delegation procedure. If the critical section is entered successfully, the operation is redirected through the out terminal. An operation call may be blocked waiting to enter the critical section. The operation bus passed with the call is not interpreted by DM CRT. Use Cases Protecting operation code with DM CRT's critical section DM_CRT is inserted between a v-table connection of Part A and Part B. DM_CRT's crt_out and crtjn terminals are not connected. Part A's output terminal is connected to DM CRT's in terminal. Part B's input terminal is connected to DM_CRT's out terminal. All the parts are activated. During activation, because the crt_out terminal is not connected, DM_CRT creates its own critical section for later use. Part A invokes an operation through its output terminal. DM_CRT gets a call on its in terminal from Part A and enters the critical section. DM_CRT then redirects the operation call out through its out terminal. Part B gets a call on its input terminal from DM_CRT. The operation code is executed and Part B returns control back to DM_CRT. DM_CRT leaves the critical section and then returns control back to Part A. Steps 6-9 may be executed many times. The parts are deactivated and destroyed. 4.4. N2C 4.4. 1. DM N2C - Notification to request completion Fig. 7 illustrates the boundary of the inventive DM_N2C part. DM N2C converts notification events that come on the nfy input into completion of asynchronous requests on the in terminal. DM_N2C can hold only one pending request at a time. A pending request may be cancelled by sending a cancel request to either in or ctl. The IDs of all requests and notifications recognized by DM_N2C are programmable through properties. Depending on its parameterization, DM_N2C can operate in two modes: trigger: An incoming wait request on in is always "pended" (i.e., held by DM_N2C for later completion). The trigger event received on nfy releases the pending request and DM N2C completes it by calling back the in terminal. toggle: A pair of notifications referred to as "on" and "off" are recognized by DM N2C. DM_N2C keeps track of the notifications by setting and clearing an internal flag. Based on the state of this flag an incoming wait request is either completed immediately or "pended" until the matching notification is received. For a detailed description of the two modes of operation, please refer to the Use Cases section below. All inputs of DM_N2C are guarded and it can operate only in normal thread time (PASSIVE_LEVEL). DM N2C never blocks the thread of execution that enters it. Boundary Terminals Terminal "in" with direction "Plug" and contract l_DRAIN. Note: DM_N2C expects the "wait" requests on this terminal. The requests are completed when DM N2C receives the appropriate notification on the nfy terminal. DM N2C compares the event ID to the req_wait_on, req_wait_off and req_wait_cancel properties; other data in the event bus is not interpreted by DM_N2C. Events that are not recognized return with CMST_NOT_SUPPORTED status. Since DM N2C may keep the event data bus pointer for later completion, this input should never be called with data that is on the stack (i.e., is an automatic variable). If the event sent to this input does not allow asynchronous completion (CMEVT_A_ASYNC_CPLT bit is not set in the attributes) DM_N2C will return CMST_FAILED. Event buses with the "self-owned" attribute set are not accepted by DM_N2C on this input. It will return CMSTJNVALID (the bus will be freed if the force Jree property is set). Terminal "nfy" with direction "In" and contract I DRAIN. Note: DMJM2C receives notification events on this input. Only the event ID is checked and compared to the "trigger" values nfy_on and nfy off - see Properties below. Terminal "ctl" with direction "In" and contract l_DRAIN. Note: The event ID specified by the ctl cancel property is recognized on this input and has the same effect as the req_wait_cancel request received on the in terminal. The use of the ctl terminal is optional - it is provided to allow a separate control path for the "cancel" request. Events and notifications The events recognized by DM_N2C are programmed into it as properties. The event names in the table below are given as the corresponding property name in parentheses. The following events are recognized on the in terminal: Incoming Event Bus Notes (req wait on) CMEVENT When this event is received, DM N2C checks its _HDR or internal "on" flag (the flag that tracks the (nfy_on) and extended (nfy_off) notifications) and if it is set, returns CMST_OK. Otherwise the event bus is saved and DM_N2C returns CMST PENDING. If there is an old pending request, DM_N2C returns CMST_BUSY. (req wait off) CMEVENT When this event is received, DM_N2C checks its _HDR internal "on" flag and if it is clear, returns CMSTJDK. or Otherwise the event bus is saved and DM N2C returns extended CMST_PENDING. If there is an old pending request, DM_N2C returns CMST_BUSY. (req_wait_cancel CMEVENT If there is a previously saved wait request (see ) _HDR above), DM N2C completes it with CMST CANCELLED. or This request always completes synchronously, with extended CMST OK. The following events are recognized on the ctl terminal: Incoming Event Bus Notes (ctl_cancel) CMEVENT This event has the same effect as the _HDR (req_wait_cancel) request on the in terminal (see or above). extended This request always completes synchronously, with CMST OK. The following events are recognized on the nfy terminal: Incoming Event Bus Notes (nfy_on) CMEVENT When this event is received, DMJM2C completes a _HDR pending (req_wait_on) event, if there is one. or If the nfy off property is not set to EVJMULL, extended DM_N2C also sets its internal "on" flag. If the nfy_off property is set to EVJMULL, DM_N2C operates in "trigger" mode - (req_wait_on) requests are always blocked and they are released on the (nfy_on) notification. (nfy off) CMEVENT When this event is received, DMJM2C completes a _HDR pending (req_wait_off) event, if there is one. or If the nfy_off property is set to EVJMULL, DMJM2C extended operates in "trigger" mode (see above). These events are sent out the in terminal: Outgoing Bus Notes Event (req_wait_on) CMEVENT_ If there is a pending (req_wait_on) request when HDR DM_N2C receives (nfy_on), it is sent back to the in or extended terminal with the CMEVT_A_ASYNC_CPLT flag set and the completion status filled in (see the cplt_s_offs property). (req_wait_off) CMEVENT_ If there is a pending (req_wait_off) request when HDR DM_N2C receives (nfy_off), it is sent back to the in or extended terminal with the CMEVT_A_ASYNC_CPLT flag set and the completion status filled in (see the cplt_s_offs property). Special events, frames, commands or verbs None. Properties Property "req_wait_on" of type "UINT32" . Note: Defines the event to recognize as "wait for on condition". This property is mandatory. It may not be set EVJMULL. Property "req_wait_off" of type "UINT32". Note: Defines the event to recognize as "wait for off condition". This property is optional; its default value is EVJMULL (no event will be recognized with this value). Property "req_wait_cancel" of type "UINT32". Note: Defines the event to recognize as "cancel pending waits". This property is optional; its default value is EVJMULL. Property "nfy_on" of type "UINT32". Note: Defines the event to be treated as the "on" notification on the nfy input. This property is mandatory. It may not be set EVJMULL. Property "nfy_off" of type "UINT32". Note: Defines the event to be treated as the "off" notification on the nfy input. When this property is set to EVJMULL, DMJM2C operates in "trigger" mode - its internal state is always "off" and the nfy_on event only releases a pending req_wait_on event without changing DM_N2C's state to "on". This property is optional; its default value is EVJMULL (no "off" event). Property "ctl_cancel" of type "UINT32". Note: Defines the event to recognize as "cancel" in the ctl terminal. This property is optional; its default value is EV_NULL. Property "in_cplt_s_offs" of type "UINT32". Note: The offset in the bus received on in where DMJM2C should store the completion status of requests that complete asynchronously. DM_N2C treats this as a byte offset to a field of type "cmstat" (defined in CMAGIC.H). This property is optional; its default value is -1 (this value is treated as "do not set completion status in the bus"). Property "nfy_cplt_s_offs" of type "UINT32". Note: The offset in the bus received on nfy where DM_N2C should retrieve the completion status of the completed request. DMJM2C treats this as a byte offset to a field of type "cmstat" (defined in CMAGIC.H). This property is optional; its default value is -1 (this value is treated as "do not retrieve the completion status in the bus"). The status is copied into the pending request bus upon completion (if needed). Property "force ree" of type "UINT32". Note: Defines whether buses with the "self-owned" attribute should be freed even if DMJM2C has to return a bad status. This property is optional; its default value is FALSE. Encapsulated interactions None. Specification Responsibilities 1 . Maintain an internal "on" flag changed through notifications received on the nfy terminal. The IDs for the "on" and "off" notifications are programmable through properties. 2. Based on the internal "on" flag, either complete or save the recognized "wait" requests on the in terminal. The IDs for the "wait" requests are programmable through properties. Provide storage for one pending "wait" request. 3. Upon receipt of a recognized notification, complete the pending "wait" request, if any. Also propagate the completion status if needed. 4. Recognize a "cancel" request on either the in terminal or the ctl terminal and complete any pending request. The ID for the "cancel" request is programmable through a property. Theory of operation State machine None. Mechanisms None. Use Cases Using DM N2C in "trigger" mode For this mode, the nfy_off property is set to EVJMULL (the default value). Also the req_wait_off property may be left not programmed, since it has no use in this mode. 1 . In this mode, the client connected to the in terminal will always get CMST_PENDING return status on the req_wait_on event. 2. DMJM2C will send the event back with the completion flag set when it receives the nfy_on event on the nfy input. 3. If there is no pending req_wait_on request, incoming nfy_on notifications are simply ignored. This mode can be used to convert an event-type notification (e.g., from an interrupt source or a timer) to completion of a "wait" request that uses the bi-directional asynchronous request/completion pattern (e.g., a request produced from an IOCTL by the DMJOC part). Using DM N2C in "toggle" mode In this mode, both the nfy_on and the nfy_off properties should be programmed. The optional req_wait_off property is usually programmed in this case. 1 . When activated, DM_N2C assumes the "off" state. In this state a req_wait_off request is completed immediately. 2. An incoming req_wait_on request is saved and DM_N2C returns CMST_PENDING. 3. When an nfy_on notification is received, the pending req_wait_on request is completed and DM_N2C assumes the "on" state. 4. Additional req_wait_on requests are completed immediately and req_wait_off requests are saved for later completion until an nfy_off notification is received. This mode is typically used to convert a pair of notifications signalling that something is turned on/off, inserted/removed etc. into a pair of "wait" requests. A typical example of such requests is the IOCTL_SMARTCARD IS ABSENT/ IOCTL_SMARTCARDJS_PRESENT pair from the Windows Smart Card DDK. Notes 1 . The "trigger" mode can be extended to provide counting of the incoming nfy_on events in order to have as many req_wait_on requests completed as there were nfy_on notifications received, whether or not there was a pending req_wait_on when an nfy_on is received. This functionality is similar to the operation of a "semaphore" synchronization object as opposed of the "event"-like functionality currently defined for DM N2C. In addition to in and ctl, nfy can be used as a third source of "cancel" requests. This was not included in this specification because all existing use cases are satisfied with one or two sources of "cancel" requests. 4.5. Desynch & Resynch 4.5. 1. DM FDSY - Fundamental Desynchronizer Fig. 8 illustrates the boundary of the inventive DM_FDSY part. DM_FDSY de-couples the flow of control from the operation flow, a mechanism known as desynchronization. DM FDSY desynchronizes ail operations received on its in terminal. The operation buses are not interpreted by DM_FDSY. DM_FDSY enqueues the operation and its bus; the queue keeps the operations in the same order as they are received. As EV _IDLE/EV_PULSE events are received on its ctl input, DM_FDSY dequeues all the pending operations and sends them through the out terminal (one operation is dequeued for each EV JDLE/EV PULSE event received). The size of the queue used by DM FDSY is dynamic and may be limited by a property called queue sz. DM FDSY issues EV_REQ_ENABLE and EV REQJDISABLE requests through its ctl terminal in order to control the pulse generation. The issuing of these requests can be disabled through the property disable_ctl_req. Boundary Terminals Terminal "in" with direction "In" and contract l_POLY. Note: v-table, infinite cardinality, floating, synchronous. DM_FDSY desynchronizes the operations received on this terminal. The bus passed with the operation call is not interpreted by DM_FDSY. This terminal is unguarded. DM_FDSY does not enter its guard at any time. Terminal "out" with direction "Out" and contract l_POLY. Note: v-table, cardinality 1 , synchronous. DM_FDSY sends all desynchronized queued operations out through this terminal (when it receives EVJDLE/EV_PULSE events from ctl). The bus passed with the operation call is not interpreted by DM_FDSY and is passed directly through the out terminal. The outgoing operations are in the same order as they were received from in. Terminal "ctl" with direction "Plug" and contract l_DRAIN. Note: v-table, cardinality 1 , synchronous. EVJDLE/EV PULSE events are received through this terminal so DM_FDSY can dequeue operations and send them through the out terminal (one operation is dequeued for each EVJDLE/EV_PULSE event received). DM FDSY generates pulse enable/disable requests through this terminal (unless the disable_ctl_req property is TRUE). This terminal is unguarded. DM_FDSY does not enter its guard at any time. Incoming Event Bus Notes EV_RESET CMEVENT This event is received on the ctl terminal. _HDR In response, DM FDSY flushes its operation queue. No operations are invoked through the out terminal. EV IDLE CMEVENT This event is received on the ctl terminal. _HDR In response, DM_FDSY dequeues an operation and invokes it through out. If there are no elements on the queue, DM FDSY will return CMSTJ O ACTION even if disable_ctl_req property is set to TRUE. EV PULSE CMEVENT This event is the same as EVJDLE. HDR Outgoing Event Bus Notes EV REQ ENABL CMEVENT DM_FDSY sends this request through ctl when an _HDR operation is invoked on the in terminal and the operation queue was empty. DM_FDSY sends this event only if disable_ctl_req property is FALSE. EV REQ DISAB CMEVENT DM FDSY sends this request through ctl if the LE _HDR operation queue is empty (after receiving EVJDLE/EV_PULSE and dequeueing the last operation). DM_FDSY sends this event only if disable_ctl_req property is FALSE. Special events, frames, commands or verbs None. Properties Property "queue sz" of type "UINT32". Note: This is the number of events that the operation queue can hold. If 0, the queue will extend itself when it gets full (the number of operations the queue can hold is limited only by available memory). Default is 0. Property "disable_ctl_req" of type "UINT32". Note: Boolean. If FALSE, DM_FDSY sends requests through ctl to enable/disable the pulse generation when needed. If TRUE, requests are never sent through ctl. Default is FALSE. Property "ok stat" of type "UINT32" . Note: This specifies the status that DM_FDSY returns on calls through in if the operation was successfully enqueued. This status is also used to determine if operations passed through out succeeded. Default is CMST_OK. Property "disable_diag" of type "UINT32" . Note: Boolean. This determines whether DM_FDSY prints debug output indicating that a call through ctl or out failed. A call through ctl fails if the return status is not equal to CMST_OK. A call through out fails if the return status is not equal to ok_stat. This property affects only the checked build of DM_FDSY. Default is FALSE. Specification Responsibilities 1 . Desynchronize all incoming operations received through the in terminal and return the appropriate status. 2. When an EVJDLE/EV PULSE event is received from the ctl terminal, dequeue and invoke an operation through the out terminal. 3. Do not interpret or modify the operation bus passed with operation calls received on the in terminal. 4. Depending on the value of the disable_ctl_req property, generate enable/disable requests through ctl when needed. 5. Depending on the value of disable_diag, print debug output if operations invoked through out or ctl fail (checked builds only). Theory of operation Main data structures DM_FDSY uses a DriverMagic queue to store all desynchronized operations and their buses. Mechanisms Desynchronization of incoming operations DM FDSY desynchronizes all operations invoked through the in terminal. DM FDSY enqueues the operation and its bus and returns to the caller. The return status is ok_stat (if enqueing of the operation succeeded; otherwise a failure status is returned). DM FDSY then requests pulse generation (if the disable_ctl_req property is FALSE and the queue was empty) by sending an EV_REQ_ENABLE event through the ctl terminal. For each EVJDLE/EV_PULSE event received from the ctl terminal, DM_FDSY dequeues one operation and invokes it through out. If the disable_ctl_req property is FALSE and the queue is empty, DM_FDSY requests to disable the pulse generation by sending an EV_REQ_DISABLE event through ctl. The operation bus received on the in terminal is not interpreted, modified or valchked by DM_FDSY. The operation bus passed through out is the exact same bus received with the operation invoked through the in terminal. All enable/disable pulse generation events sent through ctl are allocated on the stack and sent with the CMEVT_A_SYNC_ANY and CMEVT_A_SELF_CONTAINED attributes. Event handling on the ctl terminal All self-owned events received on the ctl terminal are freed by DM_FDSY only if the processing of that event is successful (CMST OK is returned). All unrecognized events are not processed by DM_FDSY and a CMST_NOT_SUPPORTED status is returned. If an EVJDLE or EV_PULSE event is received when the operation queue is empty, DM FDSY returns CMST_NO_ACTION. Use Cases Desynchronizing operations 1 . The counter terminal of in invokes an operation through in and the call is received by DM_FDSY. 2. Unless the disable_ctl_req property is TRUE, an EV_REQ_ENABLE event is sent through the ctl terminal. 3. The operation is enqueued and the flow of control is returned to the caller. The return status is ok stat. 4. Steps 1 and 3 may be repeated several times. 5. DM_FDSY receives an EV JDLE/EV_PULSE event from its ctl terminal. 6. DM_FDSY dequeues one operation and invokes it through the out terminal passing the same operation bus as received on the in terminal. 7. If the return status from the operation call is not equal to ok_stat and disable_diag is FALSE, DM_FDSY prints debug output indicating that the operation call failed. 8. Steps 5 through 7 are repeated many times. 9. If the disable_ctl_req property is FALSE an EV_REQ_DISABLE event is sent through the ctl terminal to stop the pulse generation (when the operation queue becomes empty). Notes 1 . DM_FDSY assumes that buses passed with operations invoked through the in terminal are not allocated on the caller's stack. 2. DM_FDSY does not interpret, modify or valchk the operation buses received on the in terminal. The bus passed through the out terminal is exactly the same as the bus received on the in terminal (it is the original bus pointer). 4.5.2. DM DWT, DM DOT - Desynchronizers With Thread Fig. 9 illustrates the boundary of the inventive DM_DWT AND DM_DOT part. DM_DWT desynchronizes and forwards events received on its in input. The input event is desynchronized only if the input event's attributes specify that it may be distributed asynchronously, otherwise DM DWT returns an error. Each instance of DM_DWT uses its own thread to de-queue the events queued through in and send them to out. Before an input event is queued, DM_DWT checks the self-owned attribute of the event (CMEVT_A_SELF_OWNED). If it is set, the event is queued as-is, otherwise a copy of the event is queued. In any case the output is called with the self-owned attribute cleared 1 . DM_DWT frees the event memory after the call to out returns. DM_DOT has the same functionality, but it provides a single bi-directional terminal to receive the input events and send the de-synchronized events. It can be used in cases when a part needs to postpone the processing of an event and/or request to be This may change in a future release. called back in a different thread of execution in order to perform operations that it cannot do in its current execution context. Note The desynchronized event may be distributed in a thread different than the one that posted it. This may impose additional limitations if thread-local storage is used. Boundary Terminals (DM_DWT) Terminal "in" with direction "In" and contract l_DRAIN. Note: v-table, infinite cardinality, synchronous This terminal receives all the incoming events for DM_DWT. Events that require synchronous distribution are rejected with CMST_REFUSE status. Such events are those that have only the CMEVT_A_SYNC attribute set. In general, all the events to be desynchronized by DM_DWT should have both the CMEVT_A_SYNC and the CMEVT A ASYNC attribute set. Terminal "out" with direction "Out" and contract I DRAIN. Note: v-table, cardinality 1 , synchronous DMJDSY sends all de-synchronized events out through this terminal. This output is called in a dedicated worker thread created by DM_DWT (a separate thread is created by each instance of DM_DWT). Terminals (DM_DOT) Terminal "dsy" with direction "I/O" and contract I DRAIN. Note: v-table, cardinality 1 , synchronous This terminal receives all the incoming events for DM_DOT. Events that require synchronous distribution are rejected with CMST_REFUSE status. Such events are those that have only the CMEVT_A_SYNC attribute set. In general, all the events to be desynchronized by DM_DWT should have both the CMEVT_A_SYNC and the CMEVT A ASYNC attribute set. The de-synchronized events are sent out through the same terminal. The output is called in a dedicated worker thread created by DM_DOT (a separate thread is created by each instance of DM DOT). Events and notifications Incoming Bus Notes Event EV XXX CMEVENT DM_DWT: All incoming events on in are de- _HDR synchronized and sent out through out. /CMEvent DM_DOT: All incoming events on dsy are de- synchronized and sent back through dsy. Outgoing Bus Notes Event EV_XXX CMEVENT All incoming events on in(dsy) are de-synch onized _HDR and sent out through out(dsy). - /CMEvent Special events, frames, commands or verbs None. Properties Property "queue_sz" of type "UINT32" . Note: This is the number of events that the event queue can hold. If 0, the queue will extend itself when it gets full (the number of events the queue can hold is limited only by available memory). This property is redirected to the EST subordinate. Default is 0. Property "thread_priority" of type "UINT32" . Note: Specifies the priority of the worker thread. The values for this property depend on the environment. It is used directly to call the environment specific function that sets the thread priority (SetThreadPriority in Win32, KeSetPriorityThread in WDM, etc.). This property is redirected to the EST subordinate. Encapsulated interactions The DMJΞST part used in the DM_DWT and DM_DOT assemblies uses the following operating system services: • Thread functions • Synchronization functions please refer to the DM EST data sheet. Specification Fig. 10 illustrates the internal structure of the inventive DM_DWT part. Fig. 1 1 illustrates the internal structure of the inventive DM_DOT part. Responsibilities 1 . Desynchronize all incoming events received from in/dsy and send them out through out/dsy. 2. Use a dedicated worker thread to call the out/dsy terminal. Theory of operation DM_DWT and DM_DOT are assemblies built entirely of DriverMagic parts. For simplicity, the description below refers to DM_DWT only. The same description is valid for DM_DOT, except that DM DWT has separate input and output while DM_DOT has a single bi-directional terminal for both input and output (see the diagrams above). An event that enters DMJDWT is enqueued by DM_DWI and control returns to the caller immediately with CMST OK (if DM_DWI fails to enqueue the event - i.e., the queue is full or the event does not qualify as de-synchronizable, an error status is returned). If this is the first event enqueued, DM_DWI sends an enable request to its idle terminal. This request is translated by DMJES to an "arm" operation sent to DMJΞST, which in turn unblocks the worker thread created by DMJΞST. When the worker thread receives control, DMJΞST calls "fire" on its output continuously, until disabled. The "fire" operations are translated by DMJES into EVJDLE events used by DM_DWI to de-queue events from its queue and send them to out. When the queue becomes empty, DM DWI sends a disable request (translated to "disarm" on DMJΞST), which causes the worker thread to be blocked until a new event is enqueued. Subordinate Parameterization Subordinate Property Value DM_EST force_defaults TRUE auto arm FALSE Use Cases De-synchronizing events with DM DWT Fig. 1 2 illustrates an advantageous use of the inventive DM_DWT part. Fig. 13 illustrates an advantageous use of the inventive DM_DWT part. If one or more event sources are connected to a single event recipient and all the event sources produce only de-synchronizable 1 events, DM DWT may be placed in front of the recipient if a direct connection is undesirable for any of the following reasons (or other similar considerations): • The event source(s) do not execute in a normal thread context, while the recipient requires normal thread context to run. • The event source(s) may not be blocked for any reason, while the recipient calls (or is expected to call) system functions that can block the thread and/or its outputs when it receives an event. • If there is a direct or indirect loopback path from the event recipient to the event source - to avoid re-entering the source and causing an infinite loop or recursion that may oveflow the call stack. Note that since an instance of DM DWT uses a single thread, the de-synchronized events are also serialized, i.e., the part connected to DM_DWT's output will receive them in sequence and will never be re-entered from this connection with a new event until it has returned from the previous one. If serialization of events from multiple sources is undesirable, a separate instance of DM_DWT may be used to de-synchronize events from each of the sources. 1 An event is de-synchronizable if it satisfies all of the following requirements: a) the event data buffer is not in any way bound to the execution context of the caller (e.g., is not allocated on the caller's stack and does not use or refer to thread- specific data) or it may be safely copied (i.e., has no references to volatile data, like automatic or heap-allocated buffers that can become unavailable when the event is de-queued); b) the event source does not need to receive a return status or data placed in the event data buffer from the processing of the event; c) the event source can continue execution whether or not the event was actually delivered. Serializing and/or postponing processing of events generated inside a part with DM DOT Fig. 14 illustrates an advantageous use of the inventive DM_DOT part. Some parts interact with sources of asynchronous events ("Asynchronous event" here does not necessarily refer to a ClassMagic event, but to any type of entry into the part that is asynchronous, e.g., a callback from the operating system or an embedded interaction), which may come in an execution context that is restricted in some way, e.g.: • the part's guard cannot be acquired; • access to some system services is restricted; • the event requires lengthy processing and the current thread of execution may not be blocked or delayed. • the execution context may not be suitable for calling the part's outputs, because parts connected to these outputs cannot enter their guard and/or cannot call system APIs at that time. In such cases the part needs to defer part or all processing of asynchronous events and request to be re-entered in a normal thread context. To do this it should have a bidirectional l_DRAIN terminal (dsy - see diagram) connected to an instance of DM_DOT. When it needs to postpone an event, it fills in a ClassMagic event structure with all the information required to process the event later and sends it through dsy. DM_DOT will later call it back through the same terminal with the posted event structure - in the context of its working thread. 4.5.3. DM RSY, DM RSB - Re-synchronizers Fig. 1 5 illustrates the boundary of the inventive DM_RSB part. Fig. 1 6 illustrates the boundary of the inventive DM_RSY part. Overview DM_RSY is an adapter that converts a Request Event that is expected to complete synchronously into a Request Event that may complete either synchronously or asynchronously. By doing this, DM_RSY provides the part connected to its out terminal with the option to either complete the request immediately or return CMST_PENDING and delay the actual completion of the request for a future time. At the same time DM_RSY ensures that the part connected to the in terminal will receive control back (DM_RSY will return from raise operation) only after the processing of the request has actually been completed. DM_RSY is parameterized with the event ID of the Request Event, which needs to be adapted for asynchronous processing. Addional properties control details of how the adapting procedure is performed. DM_RSB has the same functionality as DM_RSY, but allows bi-directional connections to its in terminal. The back channel of the in terminal is used to transparently forward all events received on the back channel of the out terminal, allowing DM_RSB to be inserted in bi-directional connections. Details DM_RSY uses a specialized protocol to accomplish the process of resynchronization. DM_RSY sets an attribute (the value of this attribute is a property) on the incoming event, indicating that the request can be completed asynchronously, and forwards the event to its out terminal. The part connected to that terminal may complete the processing immediately (synchronously) or may decide to delay the processing and return CMST PENDING. If the request was completed synchronously, DM_RSY returns immediately to the originator. If the processing was delayed (CMST_PENDING was returned) however, DM_RSY will block the originator of the event and wait for an event to come from the back channel of the out terminal (the event ID is a property) indicating that the request has been completed. After DM_RSY receives such event, it will return to the Request Event originator (restoring the original attributes). Boundary Terminals (DM_RSY) Terminal "in" with direction "Input" and contract IJDRAIN. Note: v-table, infinite cardinality, synchronous, activetime The req_evjd event is expected to be received on this terminal. If req ev id is EVJMULL, any event may be received on this terminal. Terminal "out" with direction "Bidir (plug)" and contract IJDRAIN. Note: v-table, cardinality 1 , synchronous, unguarded The cplt_ev id event is expected to be received on this terminal. Terminals (DM RSB) Terminal "in" with direction "Bidir (plug)" and contract l_DRAIN. Note: v-table, cardinality 1 , synchronous The req_ev id event is expected to be received on this terminal. If req_evjd is EVJMULL, any event may be received on this terminal. Terminal "out" with direction "Bidir (plug)" and contract IJDRAIN. Note: v-table, cardinality 1 , synchronous, unguarded The cplt evjd event is expected to be received on this terminal. Events and notifications The re-synchronizers recognize two specific events: req_evjd and cplt_ev id. The event IDs for these two events are specified as properties and are described in the tables below: Incoming Event Bus Notes req_evjd CMEVENT_ The event that requests a synchronous or HDR asynchronous operation. or extended This event ID is specified as a property on the re- synchronizers. This event is expected to be received on the in terminal. If req_ev id is EVJMULL, any event may be re- synchronized. This event may be the same as cplt evjd. cplt_evjd CMEVENT_ The event that signifies that an asynchronous HDR operation, requested by a preceding req_evjd, has or extended completed. This event ID is specified as a property on the re- synchronizers. This event is expected to be received on the out terminal. This event may be the same as req_ev id. all others CMEVENT_ All incoming events received from the in terminal are HDR forwarded through out. or extended DM_RSB: Unrecognized events received from the out terminal are forwarded through in if the resynchronizer is not expecting to receive a completion notification. Otherwise, the event is refused. DM RSY: Unrecognized events received from the out terminal are not processed by DM_RSY and CMST NOT CONNECTED is returned. Outgoing Bus Notes Event req ev id CMEVENT_ The event that requests a synchronous or HDR asynchronous operation. or extended This event ID is specified as a property on the re- synchronizers. This event, when received on the in terminal, is passed through the out terminal. all others CMEVENT_ All incoming events received from the in terminal are HDR forwarded through out. or extended Special events, frames, commands or verbs None. Properties Property "req_evjd" of type "UINT32". Note: This is the ID of the event that requests the operation that needs to be completed asynchronously. If req_evjd is EVJMULL, any event may be re-synchronized. This event is expected to be received on the in terminal. This event may be the same as cplt_evjd. Default is EVJMULL. Property "cplt_evjd" of type "UINT32". Note: This is the ID of the event that signifies the completion of the asynchronous operation. This event is expected to be received on the out terminal. If cplt_evjd is EVJMULL, the completion event must be the same as req_evjd, otherwise it may be a different event. Default is EVJMULL. Property "async cplt attr" of type "UINT32" . Note: This is the event-specific attribute to be set on the req evjd event in order to signify that the requested operation can be completed asynchronously. The attribute value may be 0. Default is CMEVT_A_ASYNC_CPLT. Property "cplt_attr" of type "UINT32" . Note: This is the event-specific attribute to be set on the cplt_evjd event in order to signify that the asynchronous operation has completed. This attribute is used only if req_evjd is the same as cplt_evjd. The attribute value may be 0. Default is CMEVT_A_COMPLETED. Property "copy_cplt_data" of type "BOOL" . Note: If TRUE, the re-synchronizer copies the completion data from the completion event bus to the event bus of the originator of the request. Default is FALSE. Property "extract_cplt_s" of type "BOOL". Note: If TRUE, the re-synchronizer extracts the completion status from the completion event bus and return it to the originator of the request. Default is FALSE. Property "cplt_s_offset" of type "UINT32" . Note: This is the offset from the beginning of the completion event bus (in bytes), where the completion status is stored. This property is ignored if extract_cplt_s is FALSE. Default is OxOC. Encapsulated interactions DM RSY uses the synchronization services (Events) of the operating system to block the thread that requests the operation which is desynchronized. Dependencies DM RSY requires DM BSP and DM RSB to be available. Specification Responsibilities 1 . Pass all events received from the in terminal through the out terminal. 2. DM RSB: Pass all unrecognized events received from the out terminal through the in terminal (only if the re-synchronizer is not expecting to receive a completion notification; otherwise the event is refused). 3. DM_RSY: Ignore unrecognized events received from the out terminal. 4. If an req_evjd event is received on the in terminal, forward the event through out and block the caller (if needed) until the cplt_evjd event is received on the out terminal. If an req_evjd is EVJMULL, allow any event to be re-synchronized. 5. When an asynchronous operation completes, return the results and control back to the caller. Theory of operation Fig. 1 7 illustrates the internal structure of the inventive DM RSY part. Interior DM_RSB is a coded part. DM_RSY is a static assembly. Mechanisms Handling operation requests from the in terminal When the re-synchronizer receives an req_evjd event (or any event if req_evjd is EVJMULL) from the in terminal, it sets the asynchronous completion attribute (specified by async_cplt_attr) and forwards the event through the out terminal. If any status other than CMST OK or CMST_PENDING is returned from the event processing, this is considered an error and the status is returned to the caller. If the return status is CMSTJDK (or any status other than CMST_PENDING) the operation completed synchronously. In this case, the re-synchronizer returns control back to the caller and does nothing else. If the return status is CMST PENDING, the operation will complete asynchronously. The re-synchronizer blocks the caller (using an event synchronization object) until it receives an cplt_evjd event on its out terminal. When an cplt_evjd event is received, the event object is signaled and control is returned back to the caller. In all cases, before the control is returned back to the caller, the event-specific attributes (possibly modified by the re-synchronizer) are restored to their original values. The re-synchronizers pass all other events from the in terminal through the out terminal without modification. Notification of asynchronous operation completion The re-synchronizer blocks the caller (as described in the mechanism above) until it receives an cplt_evjd event on its out terminal. This event indicates that the asynchronous operation is complete. If the completion event (cplt_evjd) is the same as the operation request event (req_evjd), the re-synchronizer expects that the completion attribute (cplt_attr) is set. If not, the re-synchronizer returns CMST REFUSE. When the asynchronous operation has completed, the caller is unblocked by signaling the event object. The re-synchronizer uses the values of the properties copy_cplt_data and extract_cplt_s to determine if it should copy the completion event bus and/or return the completion status to the caller. The caller receives the results of the asynchronous operation and continues execution as if the requested operation had completed synchronously. If an unrecognized event is received on the out terminal and the re-synchronizer is not expecting to receive a completion notification, it will pass the event through the in terminal. If a completion event is expected, the event is refused. Extraction of the completion status When the asynchronous operation has completed, the re-synchronizer uses the value of the extra ct_cplt_s property to determine whether the completion status is returned to the caller. If extract_cplt_s is TRUE, the re-synchronizer uses the value of cplt_s_offset to determine where the completion status is stored in the completion event bus. The status is extracted and returned to the caller. If extract_cplt_s is FALSE, the re-synchronizer returns CMST_OK to the caller. Use Cases Fig. 1 8 illustrates an advantageous use of the inventive DM_RSY part. Fig. 1 9 illustrates an advantageous use of the inventive DM_RSB part. Requested operation completes synchronously 1 . The structures in figures 3 and 4 are created, connected, and activated. 2. At some point, the re-synchronizer receives an req_ev id event on its in terminal. 3. The re-synchronizer sets the asynchronous attribute (async_cplt_attr) in the event bus to indicate that the operation can complete asynchronously if needed. 4. The event is passed through the out terminal. 5. The part connected to the re-synchronizer's out terminal receives the event and completes the operation synchronously. Control is returned back to the resynchronizer. 6. The re-synchronizer returns control back to the caller. 7. Steps 2-6 may be executed many times. 8. The re-synchronizer is deactivated, disconnected, and destroyed. Requested operation completes asynchronously 1 . The structures in figures 3 and 4 are created, connected, and activated. 2. At some point, the re-synchronizer receives an req_evjd event on its in terminal. 3. The re-synchronizer sets the asynchronous attribute (async_cplt_attr) in the event bus to indicate that the operation can complete asynchronously if needed. 4. The event is passed through the out terminal. 5. The part connected to the re-synchronizers out terminal receives the event and returns CMST_PENDING indicating that the operation will complete asynchronously. 6. The re-synchronizer blocks the caller by waiting on an event synchronization object. 7. At some later point, the re-synchronizer receives a cplt__evjd event on its out terminal. 8. If the copy_cplt_data property is TRUE, the re-synchronizer copies the completion data into the event bus of the blocked caller. 9. If the extract_cplt_s property is TRUE, the re-synchronizer extracts the completion status from the completion data and saves it in its instance data. 10. The re-synchronizer unblocks the caller by signaling the event. 1 1 . If the extract_cplt_s property is TRUE, the saved completion status is returned to the caller, otherwise CMST_OK is returned. 1 2. Steps 2-1 1 may be executed many times. 1 3. The re-synchronizer is deactivated, disconnected, and destroyed. Unrecognized events received on in terminal 1 . DM_RSB/DM_RSY is created, connected, and activated. 2. At some point, the re-synchronizer receives an unrecognized event on its in terminal (any event other than req_ev id). 3. The re-synchronizer forwards the event through the out terminal and returns the results back to the caller. 4. Steps 2-3 may be executed many times. 5. The re-synchronizer is deactivated, disconnected, and destroyed. Unrecognized events received on out terminal 1 . DM_RSB/DM_RSY is created, connected, and activated. 2. At some point, the re-synchronizer receives an unrecognized event on its out terminal (any event other than cplt_evjd). 3. If the re-synchronizer is expecting to receive a completion notification, it returns CMST REFUSE. Otherwise, DM RSB forwards the event through the in terminal and returns the results back to the caller. DM_RSY returns CMST_NOT_CONNECTED. 4. Steps 2-3 may be executed many times. 5. The re-synchronizer is deactivated, disconnected, and destroyed. Using cascaded re-synchronizers Fig. 20 illustrates an advantageous use of the inventive DM_RSB and DM RSY parts. The structure in the figure above is used if there is a need to resynchronize different operations along the same channel. In this example, 3 resynchronizers arecascaded - one for each of 3 events that can be made to complete asynchronously. 1 . The structure in figure 20 is created, parameterized, and activated. 2. Part A sends an event (e.g., the one that is parameterized on the second resynchronizer) to the first resynchronizer. The resynchronizer passes it through the out terminal. 3. The second resynchronizer receives the event and passes it through the out terminal. 4. The third resynchronizer receives the event and passes it through the out terminal. 5. Part B receives the event and returns CMST_PENDING indicating that the operation will complete asynchronously. Control is returned to the second resynchronizer. 6. The second resynchronizer blocks the caller by waiting on an event synchronization object. 7. The asynchronous operation is completed the same way as in the above use cases. 8. The second resynchronizer returns control back to Part A. Notes 1 . If any of the resynchronizers receive cplt evjd on its out terminal while it is no expecting asynchronous completion, it will return CMST_REFUSE. 2. If an event is sent to the resynchronizers in terminal while the resynchronizer is waiting for asynchronous completion, the caller will be blocked until the pending asynchronous operation completes. 3. DM_RSY does not enforce the contract ID of the in terminal. The counter terminal of in is expected to be I DRAIN. 4. If an unrecognized event is received on the resynchronizer's out terminal (while it is not waiting for an asynchronous operation to complete), different situations can occurr. DM_RSY will always return CMSTJMOT CONNECTED and DM_RSB will always pass the event through the in terminal. The asynchronous operation may be completed by sending the completion event to the resynchronizer while in the context of the operation request. 5. HARDWARE ACCESS PARTS DETAILS 5.1. Interupt Sources 5. 7. 1. DM IRQ - Interrupt Event Source Fig. 21 illustrates the boundary of the inventive DMJRQ part. DMJRQ is an interrupt event source that generates events when a hardware interrupt occurs. DMJRQ is enabled and disabled via input operations on its out terminal and generates interrupt events by invoking preview and/or submit output operation on the same terminal. DMJRQ may be enabled and disabled only at PASSIVE_LEVEL. Once enabled, DMJRQ will invoke preview and submit operations on its out terminal whenever interrupts occur. Disabling the DMJRQ will stop generation of output operations through the out terminal. If the auto_enable property is set, enabling of the DMJRQ is executed internally at activation time. A user-defined context is passed back to DMJRQ upon successful return from preview call. This context is used for the subsequent submit call, if the client returns with status CMST_SUBMIT. DMJRQ maintain statistics counters for the number of generated interrupts, the number of submit commands issued through the out terminal and the number of "missed" submits. Note: The preview operation is executed at interrupt context. The corresponding operation handler must be unguarded. The submit operation is executed at DISPATCH_LEVEL. Note DMJRQ may only be used in the NT Kernel Mode environment. Boundary Terminals Terminal "out" with direction "bi-dir" and contract in: IJRQ (vtable) out: IJRQ_R (vtable). Note: Used to enable and disable the event source on the input and to send the interrupt event on the output when the interrupt occurs. Events and notifications None. Special events, frames, commands or verbs None. Properties Property "bus" of type "DWORD". Note: number of the bus on which the device is placed (Mandatory) Property "bus_type" of type "DWORD". Note: Type of the bus (BUS TYPE xxx): BUS TYPE INTERNAL (1 ) BUSJNPEJSA (2) BUS_TYPE_EISA (3) BUS NPE MICRCHAΝΝEL (4) BUS_TYPE_TURBOCHAΝΝEL (5) BUS_TYPE_PCI (6) The default value is BUS_TYPE_PCI Property "level" of type "DWORD" . Note: IRQ level (IRQL) (Mandatory) Property "vector" of type "DWORD". Note: IRQ vector (Mandatory) Property "irq_mode" of type "DWORD". Note: IRQ_MODE_LEVEL(0) - level- sensitive interrupt. IRQ_MODE_LATCHED(1 ) - edge-sensitive The default value is IRQ_MODE_LEVEL. Property "shared" of type "DWORD". Note: Boolean TRUE if the interrupt can be shared. FALSE - IQR must claim exclusive use of this interrupt. The default value is TRUE. Property "auto_enable" of type "DWORD". Note: Boolean. If non-zero, IRQ will automatically enable itself on activation. IRQ will return REFUSE on any enable call. The default value is FALSE. Property "cnt_received" of type "DWORD read-only". Note: Count the number of received interrupts since DMJRQ was enabled. Property "cnt_submitted" of type "DWORD read-only". Note: Count the number of submitted interrupts since DMJRQ was enabled. Property "cnt_missed" of type "DWORD read-only". Note: Count the number of interrupts for which DMJRQ was not able to execute submit call. Encapsulated interactions HalGetlnterruptVector - returns a mapped system interrupt vector, interrupt level, and processor affinity mask that device drivers must pass to loConnectlnterrupt. loConnectlnterrupt - registers an ISR to be called when the interrupt occurs. loDisconnectlnterrupt - unregisters the Interrupt Service Routine (ISR) KelnsertQueueDpc - queues a DPC for execution when the IRQL of a processor drops below DISPATCHJ.EVEL - KeRemoveQueueDpc - removes a given DPC object from the system DPC queue. InterlockedCompareExchange - an atomic compare and exchange operation. Specification Responsibilities 3. Provide sufficient properties to identify the interrupt uniquely 4. Allocate and connect interrupt on enable or on activate if the property auto_enable is set. 5. Implement the actual interrupt handler. 6. Process incoming interrupts as follows: a. call preview b. depending on the returned status, create a DPC and queue it c. inform the operating system that this interrupt is recognized d. maintain the statistic counters 7. On disable, clean up properly. Cancel all outstanding DPCs. 8. Maintain a stack with free DPC structures. They are used for scheduling deferred procedure calls from which context is called submit operations. 9. Check the current IRQ level on all incoming enable and disable calls and refuse the operation if the level is not PASSIVE LEVEL 10. Guarantee that the submit comes out on IRQL equal to DISPATCHJ.EVEL 1 1 .Guarantee that the preview comes out in interrupt context. 1 2. Guarantee that there will not be any preview or submit calls after the disable operations returns or after it is deactivated. Theory of operation State machine None. Main data structures A stack of 32 KDPC structures used for issuing the deferred procedure calls. Mechanisms Servicing the interrupt When the interrupt occurs, DMJRQ generates a preview call through its out terminal. If the preview returns status CMST SUBMIT, DMJRQ schedules a DPC which sends out a submit call with the returned from preview context. Enabling and disabling interrupts DMJRQ expects client to call enable and disable at PASSIVEJ.EVEL. The same applies for activation and deactivation with property auto enable set to TRUE. On enable it allocates an interrupt and connects an interrupt handler to it. On disable it disconnects itself from the interrupt and releases all pending DPCs. There will be no outgoing calls after disabling the interrupts. Allocating memory for the DMJRQ instance The memory allocated for the DMJRQ instance is from the non-paged memory pool. Usage notes The preview operation on the part connected to the DMJRQ must be unguarded. The preview operation cannot be guarded because it is executed in interrupt context. If the clients needs to access any data during preview or submit it should be in non- paged memory. On preview the client is responsible to synchronize access to any data that is shared between the preview handler and the rest of the code, using appropriate atomic and interlocked operations. Note that no DriverMagic™ APIs may be called during preview. While a preview operation is executed it could be preempted at any time by other preview operation with higher priority or running on different processor. If the interrupt being serviced is level-sensitive, the preview operation handler should cause the device to deassert the interrupt request - otherwise the preview operation will be invoked immediately upon return. For devices that support multiple causes of interrupts, the preview operation needs to clear at least one cause on each invocation. Since the connected part is not supposed to know the type of interrupt (edge-sensitive or level-sensitive), the preview handler should always remove the cause of the interrupt before returning. There is no limitation for the implementation of submit operation on the connected part. DMJRQ could send out a submit operation at any time. It is in the connected part responsibilities to guard itself from submit reentrancy. 5. 1.2. ZPJRQ - Interrupt Event Source Fig. 48 illustrates the boundary of the inventive ZPJRQ part. ZPJRQ is a system-dependent part that acts as an interrupt event source. ZPJRQ can be enabled/disabled via EV REQ ENABLE and EV REQ DISABLE events received on its ctl terminal. Once enabled, ZPJRQ generates EV PULSE events out its irq and dsr terminals whenever an interrupt occurs. The event sent out the irq terminal is sent before ZPJRQ acknowledges recognition of the interrupt and the event that is sent out the dsr terminal is generated after the interrupt has been acknowledged. In addition, ZPJRQ maintains a count of the number of interrupts it has received and exposes it as a read-only property. ZPJRQ allows interrupt sharing - two or more instances of ZPJRQ can be created that are parameterized with the same value of the 'irqn' property. When a hardware interrupt occurs, all instances that have the matching 'irqn' property value will send an EV PULSE event to their outputs. ZPJRQ invokes the irq and dsr terminals at interrupt time. The ctl terminal of this part cannot be called at interrupt time. Boundary Terminals Terminal "irq" with direction "out" and contract l_DRAIN. Note: EV_PULSE events are sent out this terminal when an interrupt occurs and prior to acknowledging that the interrupt is being serviced. The interrupt handler may store data in the event before returning, up to the size specified by the 'evt sz' property. This data will be passed back with the event sent to the 'dsr' terminal - see below. The return status from this output is interpreted as follows: ST_OK - the handler recognized the interrupt as coming from the device that it services. If the 'dsr' terminal is connected, the EV_PULSE event will be sent to it after the interrupt has been acknowledged. ST_NO_ACTION - the handler does not recognize the interrupt as coming from its device, (other) - fatal error. Terminal "dsr" with direction "out" and contract l_DRAIN. Note: ZPJRQ generates an EV_PULSE event out this terminal after the operating system has been notified that the interrupt is being serviced. This terminal is called only if the call to the 'irq' terminal returned ST_OK. The 'dsr' output may be left unconnected. It may be used if the interrupt handler needs additional processing at interrupt time, but does not require that further interrupts from the device be held back. Terminal "ctl" with direction "in" and contract I DRAIN. Note: ZPJRQ accepts enable/disable events on this terminal. Properties Property "irqn" of type "uint32". Note: Specifies the interrupt number for which ZPJRQ is to receive interrupts. Note that this is a 0-based interrupt line number, not a vector number. ZPJRQ can be used only for hardware interrupts; it cannot trap CPU exceptions or other types of software interrupts. This property is Mandatory. Property "evt_sz" of type "uint32". Note: Size (in bytes) of the EV_PULSE event data allocated for the calls to 'irq' and 'dsr'. Default value: 0 Property "count" of type "uint32 read-only". Note: Specifies the number of interrupts received since ZPJRQ was enabled. This property is reset each time ZPJRQ is enabled (i.e., receipt of EV_REQ_ENABLE event on the ctl terminal). Note: All implementations of ZPJRQ will expose the above properties. Additional environment-specific properties may be added and should have reasonable default values so that ZPJRQ will operate without additional parameterization. Events and notifications Terminal: irq Event Dir Bus Description EV_PULSE out (any) An interrupt has occurred while ZPJRQ is in an enabled state. This event is sent to the irq terminal before ZPJRQ acknowledges that the interrupt has been processed; it may be sent while all system interrupts are disabled. The event sent to the 'irq' terminal is a synchronous request. The recipient should not free this event. The recipient may store data in the request bus, up to 'evt_sz' bytes - see the 'evt_sz' property. This data will be sent out with the EV PULSE notification sent to the 'dsr' terminal. Terminal: dsr Event Dir Bus Description EVJPULSE out (any) An interrupt has occurred while ZPJRQ is in an enabled state. The event is sent out the dsr terminal after ZPJRQ has notified the operating system that the interrupt is being serviced. The system is usually still in interrupt context when the event is sent to dsr. EV_PULSE is sent to the 'dsr' terminal as a notification and has the SELFJDWNED attribute set. The recipient should free the event if it returns ST_OK. Terminal: ctl Event Dir Bus Description EV_REQ_ENA in (void) Request to enable the event source. BLE Event Dir Bus Description EV REQ DISA in (void) Request to disable the event source. BLE Environmental Dependencies Encapsulated Interactions ZPJRQ utilizes system-specific services to receive and process interrupts. • Hooking an interrupt vector • Enabling/disabling of hardware (external interrupt controller or built-in CPU interrupt-control registers) • Enabling/disabling CPU interrupts Other Dependencies None. Specification Responsibilities 1 . When enabled, process incoming interrupts as follows: e. Send EV PULSE event out irq f. Inform the operating system that this interrupt is recognized g. If the status returned from the call to irq is ST_OK, send EV_PULSE event out dsr. 2. Maintain a counter of the number of interrupts received since the part was enabled. 3. Guarantee that no events are generated when the part is not enabled or after destruction. External States ZPJRQ has the following states: disabled this is the initial state in which the part is created. In this state it does not send any events to its outputs. enabled ZPJRQ enters this state when it receives EV_REQJΞNABLE on the 'ctl' terminal. In this state, when the hardware interrupt specified by the irqn property occurs, the part calls its 'irq' and 'dsr' outputs as specified in the terminals' description above. ZPJRQ leaves this state when it receives EV_REQ_DISABLE. None Typical Usage Fig. 49 illustrates an advantageous use of the inventive ZPJRQ part. The above diagram illustrates how ZPJRQ can be used within the context of an application. ZPJRQ is parameterized to enable itself upon creation and ZP FDSY is parameterized to NOT send enable/disable requests out its ctl terminal. The sole responsibility of the HDLR part is to obtain the state of the hardware outs its io terminal using ZPJOP and forwarding the data to ZP_FDSY. The idea is to perform as little processing as necessary while inside the interrupt because the interrupt execution path is time critical and affects the system interrupt latency. After acknowledging the processing of the interrupt, ZPJRQ sends an event out its dsr terminal so that ZP_FDSY will dequeue the hardware state and send it out its out terminal for further processing. Fig. 50 illustrates an advantageous use of the inventive ZPJRQ part. In the above example, ZPJRQ sends an event to an external thread source, which causes the processing of the hardware event to be completed within normal thread context rather than within the context of Notes Win32 In the Win32 environment, the ZPJRQ part represents a placeholder and does not implement any functionality. 5.2. Peripheral Access 5.2. 1. DMJOP - I/O Port Accessor Fig. 22 illustrates the boundary of the inventive DMJOP part. DMJOP provides generic access to device I/O ports. When an operation comes through the io terminal, DMJOP validates the relative port offset and executes the operation. DMJOP provides basic access protection. The caller can disable read or write access to the port space by setting the properties denyj-ead and deny_write. If the aligned_only property is set, DMJOP executes I/O addresses and double-word access at addresses not aligned on 4-byte boundary. DMJOP can also be used in Plug and Play and other types of drivers. To provide for this, DMJOP can be enabled/disabled through the ctl terminal (by sending specific events). The events are set as properties on DMJOP. Boundary Terminals Terminal "io" with direction "In" and contract MOP (v-table). Note: Used to receive I/O packets. Terminal "ctl" with direction "In" and contract I DRAIN (v-table). Note: Used to enable/disable DMJOP. Events and notifications IncomingEvent Bus Notes (ev_enable) CMEVENTJHD Enable DMJOP. R When DMJOP is enabled, it allows access to a port through the io terminal. (eyjdisable) " CMEVENTJHD Disable DMJOP. R When DMJOP is disabled, it denies access to a port through the io terminal. All operations invoked through the io terminal return CMST_NOT_ACTIVE. (ev_remove) CMEVENTJHD Device was removed. R DMJOP disables itself when this event is received on the ctl terminal. All operations invoked through the io terminal return CMST_NOT_ACTIVE. Special events, frames, commands or verbs None. Properties Property "base" of type "BINARY (uint64)". Note: Activetime. I/O port base. (8- byte physical address). Default is 0. is 0. Property "aligned only" of type "UINT32". Note: Activetime. Boolean. TRUE if port address must be aligned depending on the type of the data. Default is FALSE Property "deny read" of type "UINT32". Note: Activetime. Boolean. TRUE if port space is write only. Default is FALSE Property "deny_write" of type "UINT32". Note: Activetime. Boolean. TRUE if port space is read only. Default is FALSE. Property "auto_enable" of type "UINT32". Note: Activetime. If TRUE, DMJOP is enabled on activation, otherwise DMJOP remains disabled until it receives an ev_enable event through the ctl terminal (port access is not allowed while DMJOP is disabled). Default is TRUE. Property "optional" of type "UINT32". Note: Activetime. This property defines whether or not DMJOP may be used optionally in a driver framework. If TRUE, DMJOP may be activated and enabled without setting any properties. All operations invoked through the io terminal return CMST NOT ACTIVE. If FALSE, the base and length properties must be set to valid values before DMJOP activation. If not, activation of DMJOP fails. Default is FALSE. Property "ev_enable" of type "UINT32". Note: Activetime. This is the event ID of the enable event that when received on the ctl terminal, enables DMJOP. This event is provided for use with drivers where the hardware resource allocation may be dynamic. Default is EV_LFC_REQ_START. Property "ev_disable" of type "UINT32". Note: Activetime. This is the event ID of the disable event that when received on the ctl terminal, disables DMJOP. When DMJOP is disabled, all operations invoked through the io terminal return CMSTJ OT ACTIVE. This event is provided for use with drivers where the hardware resource allocation may be dynamic. Default is EV_LFC_REQ_STOP. Property "ev emove" of type "UINT32". Note: Activetime. This is the event ID of the remove device event that when received on the ctl terminal, disables DMJOP. When DMJOP is disabled, all operations invoked through the io terminal return CMST_NOT_ACTIVE. This event is provided for use with drivers where the hardware resource allocation may be dynamic. Default is EV_LFC_NFY_DEV_REMOVED. None. Specification Responsibilities 1 . Provide generic access to the I/O port address space. 2. Executes all I/O operation inside of the allocated I/O region. 3. Refuse non-aligned operations when aligned_only property is set. 4. Refuse read or write I/O port access when deny_read or deny write property is set. 5. Enable/disable port access when the ev_enable/ev_disable/ev_remove events are received from the ctl terminal. 6. If auto_enable is TRUE, enable port access on activation. 7. Optionally allow DMJOP to be used when no port properties have been specified (optional property is TRUE). Fail all port access operations with CMSTJMOT ACTIVE, Theory of operation Mechanisms I/O operations DMJOP uses the C run-time functions JnpO, JnpwO, JnpdO, _outp(), _outpw() and _outpd() in order to satisfy the user calls. In Windows NT kernel mode environment, DMJOP uses the HAL functions READ PORT xxx and WRITE_PORT_xxx. 6. DEVICE DRIVER PARTS 6. 1. 1. DM DLC - Device Interface to Life-Cycle Adapter Fig. 23 illustrates the boundary of the inventive DM_DLC part. DM_DLC is an adapter that generates life-cycle events from l_DIO requests that pass through it. It generates a EV_LFC_REQ_START life-cycle event on the first open that it receives; subsequent opens are reference-counted and passed through. When DMJDLC receives the last close or a cleanup request, it generates a EV LFC REQ STOP life- cycle event. The life-cycle events encapsulate the open/close pair. When the first open is received on in, DM_DLC sends EV_LFC_REQ START on Ifc and then open on out. through out, then EV_LFC_REQ_STOP on Ifc (which operation generates an EV_LFC_REQ_STOP request is controlled through properties). The requests and the life-cycle events can be completed either synchronously or asynchronously - DM_DLC takes care of the proper sequencing, completion and necessary cleanup. DM_DLC is typically used inside device and file object scopes in Windows NT drivers. Boundary Terminals Terminal "in" with direction "Bidir" and contract In: I DIO Out: I DIO C. Note: Incoming device requests. Requests are forwarded through out. On open and close DM_DLC also generates life-cycle events. Request completions are sent out this terminal. DM_DLC does not interpret the irpp field in the I DIO bus, B_DIO. Terminal "out" with direction "Bidir" and contract In: l_DIO_C Out: I DIO. Note: Out this terminal DMJDLC sends the device requests it received on in. On it DM_DLC receives DIO request completions. Terminal "Ifc" with direction "Plug" and contract l_DRAIN. Note: Life-cycle event output. Through this terminal, DM DLC sends EV_LFC_REQ_START event before passing l_DIO.open to out; it sends EV_LFC_REQ_STOP after passing I DIO. close to out. On this terminal DM DLC receives notifications for asynchronously completed life- cycle events. Floating. Terminal "exc" with direction "Out" and contract l_DRAIN. Note: Exception output. DM_DLC sends exceptions through this terminal whenever it receives unexpected event to which it cannot otherwise respond. Floating. Events and notifications Incoming Event Bus Notes EV_LFC_NFY_STAR B_EV_L Desynchronized start has completed. T_CPLT FC Received from the Ifc terminal. EV_LFC_NFY_STOP B EV L Desynchronized stop has completed. CPLT FC Received from the Ifc terminal. T FC This notification should have the CMEVT A COMPLETED bit set in its attributes. Received from the Ifc terminal. EV_LFC_REQ_STOP B_EV_L Desynchronized stop has completed. FC This notification should have the CMEVT_A_COMPLETED bit set in its attributes. Received from the Ifc terminal. Outgoing Event Bus Notes EV_LFC_RE Q _ST B_EV_LF Start normal operation. Always allowed to be ART C completed asynchronously. Sent out of the ifc terminal. EV_LFC_REQ_ST B_EV_LF Stop normal operation. Always allowed to be OP C completed asynchronously. Sent out of the ifc terminal. EV EXCEPTION B_EV_EX An exception has been detected in DM DLC. C Sent out of the exc terminal. Special events, frames, commands or verbs None. Properties Property "exclusive" of type "BOOL". Note: If TRUE, DM_DLC enforces that there are no nested opens (only one file object may be open at any time). If FALSE, DM DLC allows nested and intersected opens; EV_LFC_REQ_START and EV_LFC_REQ_STOP are generated on the first open and on the last close, respectively (reference counted). Default is FALSE. Property "stop on close" of type "BOOL" . Note: If TRUE, DM_DLC will generate EV_LFC_REQ_STOP on the last close (reference counted). If FALSE, DM_DLC will generate EV_LFC_REQ_STOP on I DIO. cleanup. Default is FALSE. None. Specification Responsibilities For all I DIO operations coming on in except for the first open and the last close, pass all incoming requests out the out terminal; pass any asynchronous completions of these operations back out in. On the I DIO first open operation coming on in, generate a EV_LFC_REQ_START event out Ifc terminal. Upon successful completion, synchronous or asynchronous, pass the open request to the out terminal. On successful completion of the open, complete the open operation that came on in. If the out. open failed, generate a EV_LFC_REQ_STOP through Ifc and wait until it completes before failing in. open. On either the l_DIO last close or first cleanup operation coming on in, pass the operation through the out terminal. Upon completion, successful or not, synchronous or asynchronous, generate EV_LFC_REQ_STOP event out the Ifc terminal. Upon completion, complete the in. close. During the first open and last close, allow both synchronous and asynchronous completion of the life-cycle events DM_DLC generates, as well as for the open and close requests that is passes to out. Track events and their sequences, ignoring events that come out-of-sequence (e.g., completion coming back through a terminal on which DM DLC did not initiate an operation; or, getting a new request through in while open or close are in progress. DM DLC raises exception when it receives out-of-sequence events. DM DLC does not allow overlapped requests, even if they are for different files (different open handles). If so configured, enforce exclusive access to the device. If an open has succeeded, reject further opens with "access denied" until the device is closed. Fail any new requests while the first open or the last close request (or any of the life-cycle events generated for it) is pending. Theory of operation State machine None. None. Mechanisms Reference Counting DM_DLC keeps a counter of nested opens. The counter is incremented on successful open and decremented on close. Synchronous and Asynchronous Sequencing DMJDLC does a two-way split on the first open and the last close requests. The second step is performed only after the first step has completed. Each step may be completed either synchronously (getting any status other than CMST PENDING) or asynchronously (getting a CMST_PENDING status).. DMJDLC uses a sequencer to execute each of the steps, including any cleanups. As long as steps complete synchronously, DM DLC feeds events automatically into the sequencer to advance to the next step; when an operation gets desynchronized (returns CMST_PENDING), DM DLC uses the respective completion event to resume feeding the sequencer. Preventing Reentrancy When DMJDLC receives a completion indication (IJDIO. completed or start/stop completion event), it posts a message to itself and processes the indication asynchronously. This prevents recursion into the part that sent the completion indication. Handling Failures on First Open The first open may fail in any of the two requests: lfc.EV_LFC_REQ_START - DM DLC completes the in. open with failure; out. open - DMJDLC sends lfc.EV_LFC_REQ_STOP, and when it completes, DMJDLC completes the in. open with failure; The cleanup step may also be desynchronized. DMJDLC tracks the sequence, and after the last cleanup step completes, it completes the in. open with the first failure status. If out. close fails, DMJDLC completes in. close with its failure status. If lfc.EV_LFC_REQ_STOP fails, DM DLC completes in. close with the respective failure status. Recognizing Out-of-Sequence Events DMJDLC keeps in its state what was the last event or request it sent out and through which terminal it sent it (out or Ifc). When it gets a completion indication, DMJDLC asserts that the terminal is the same and the completed operation was the one DMJDLC sent. If they match, DMJDLC proceeds with the next step in the sequence. Otherwise, it raises exception and ignores the indication. DMJDLC handles out-of-order requests on in differently: if it receives a new request on in while it is processing a first open or last close (at any stage), DMJDLC fails that new request without raising exception. 6. 1.2. DM PNS - PnP Life Cycle State Machine DM_PNS is a state machine that when fed with life-cycle related PnP IRPs (in the form of EV REQJRP) generates life cycle events on its output. DM_PNS assumes particular (partial) order of events coming on the in terminal. This order is described further in this document. The life cycle events are allowed to complete asynchronously. DM_PNS will wait until completion of these events or for a timeout, whichever comes first. If a timeout occurs, DM_PNS will complete the incoming IRP with a status CMST_TIMEOUT. DM PNS uses an external timer event source connected to its tout terminal. While DM_PNS awaits completion, it expects that no other IRPs will come on in. To synchronize the flow of control on its in terminal, DM_PNS uses EV_REQ_ENABLE/DISABLE events sent through flw terminal. DM_PNS expects that the part connected to this terminal can control the event flow on arriving at the in terminal. Boundary Terminals Terminal "in" with direction "Plug" and contract IJDRAIN. Note: v-table, synchronous, cardinality 1 Incoming (IRP) events are received here. Terminal "out" with direction "Plug" and contract I DRAIN. Note: v-table, synchronous, cardinality 1 Outgoing (life-cycle) events are sent through here. Terminal "flw" with direction "Output" and contract IJDRAIN. Note: v-table, synchronous, cardinality 1 Event flow control terminal. The part connected to this terminal is expected to control the flow of events coming on in. Terminal "tout" with direction "Bidir" and contract Out:l_EVS In :I_EVS_R. Note: v-table, synchronous, cardinality 1 , floating Terminal for timer events. Used to wait for a timeout Events and notifications received on the "in" terminal Incoming Event Bus Notes EV_REQ_IRP BJΞVJR Indicates that IRP needs processing. P Events and notifications sent through the "in" terminal Incoming Event Bus Notes EV REQ IRP BJΞVJR Completion events. P Events and notifications sent through the "out" terminal Incoming Event Bus Notes EV_LFC_REQ_START B EV L Request driver to commence normal operation. FC EV LFC REQ STOP BJΞVJ. Request driver to stop normal operation. FC EV_LFC_REQ_DEV_PAU BJΞVJ. Request driver to temporarily stop interaction with SE FC the device. EV_LFC_REQ_DEV_RES B_EV_L Request driver to resume operation with the UME FC device. EV_LFC_NFY_DEV_REM B_EV_L Notification that the device has been removed. OVED FC Events and notifications received on the "out" terminal Incoming Event Bus Notes EV_LFC_REQ_START B_EV_L Completion event. This is the same life-cycle FC event previously sent to out with CMEVT_A_COMPLETED attribute set. EV_LFC_REQ_STOP B_EV_L Same as above. FC EV_LFC_REQ_DEV_PAU B_EV_L Same as above. SE FC EV_LFC_REQ_DEV_RES B_EV_L Same as above. UME FC EV_LFC_NFY_DEV_REM B_EV_L Same as above. OVED FC Events and notifications sent through the "flw" terminal Incoming Event Bus Notes EV REQ DISABLE CMEVE Request to temporarily disable feeding events to NT the in terminal. EV REQ ENABLE CMEVE Request to enable events feed at the in terminal. NT Special events, frames, commands or verbs EV REQJRP events coming on "in" terminal One such event is sent for each IRP fed into DM PNS. DM PNS is responsible to retrieve from the current stack location the respective major and minor function codes. The only major function code accepted by DM PNS is IRP_MJ_PNP. All other are refused (CMST_REFUSE is returned as distribution status). The minor codes accepted are listed in the following table: Incoming Event Notes IRP_MN_START_DEVICE Request to start device. IRP MN STOP DEVICE Request to stop device. IRP MN REMOVE DEVICE Notification that device has been removed. Incoming Event Notes IRP MN QUERY REMOVE Inquiry about whether the device can be removed. _DEVICE IRP_MN_QUERY_STOP_D Inquiry about whether the device can be stopped. EVICE IRP_MN_CANCEL_REMOV Cancellation of device removal. E D EVICE IRP_MN_CANCEL_STOP_ Cancellation of device stopping. DEVICE All other minor codes are completed asynchronously with completion status CMSTJDK. Properties None. Encapsulated interactions DM_PNS retrieves the IRP current stack location using OS API (loGetCurrentStackLocation). Specification Responsibilities Translate life-cycle related IRP events to LFC events using internal state. Wait in a timeout for LFC event completion and if timeout expires, complete the IRP generating this LFC event with an error. Theory of operation Fig. 25 illustrates the state machine of the DM_PNS part. The following is a legend for fig. 25: Legend: E_START = IRPJv1N_START_DEVICE E_QRY_STOP = IRP_MN_QUERY_STOP_DEVICE E_STOP = IRPJvlN_STOPJDEVICE E_CANCEL_STOP = IRPJvlN CANCEL STOPJDEVICE E_QRY_REMOVE = IRP_MN_QUERY_REMOVE_DEVICE E REMOVE = IRP MN REMOVE DEVICE EJNT STOP = < internal self-generated event > The set of output LFC events is generated according to Fig. 26 Main data structures DM_PNS uses the following OS-defined data structures: IRP IO_STACK_LOCATION Mechanisms None. Use Cases Typical Usage Normally DM_PNS is to be used on the boundary between the IRP and driver LFC event channels. The IRP event channel (or one flow of it at least) stopd at DM_PNS and new event set is generated: the driver LFC events. Although the two flows are dependent, there is no one-to-one correspondence between incoming and outgoing events. One IRP event may cause zero or more LFC events to be generated. This generally means, that parts consumers of the LFC events generates by DM_PNS, may need to implement and run a state machine as illustrated by Fig 27. 6. 1.3. DM PNP - Plug-n-Play IRP handler Fig. 28 illustrates the boundary of the inventive DM PNP part. DM_PNP translates the Plug-n-Play IRP events (EV_REQ IRP) coming on its in terminal into life-cycle events (EV_LFC_xxx) and forwards these through its Ifc terminal. DM_PNP forwards all PnP-related IRPs through its pnp and all other through out before or after the life-cycle event is generated depending on the particular IRP being processed. Life-cycle events can be completed asynchronously. DM PNP will complete the IRP event whenever the respective life-cycle event completes. To complete the IRP event, DM_PRP will send the EV_REQJRP event with CMEVT_A_COMPLETED attribute set back to in. Boundary Terminals Terminal "in" with direction "Plug" and contract I DRAIN. Note: IRP events (EV_REQJRP). All events that are not processed are forwarded synchronously to out with no modification. The back channel of this terminal is used for completion events only. Can be connected at Active Time. Terminal "out" with direction "Plug" and contract IJDRAIN. Note: All events that are not processed are passed through here. The back channel passes all events through to in terminal. Floating. Terminal "Ifc" with direction "Plug" and contract IJDRAIN. Note: This terminal is used to send out the life-cycle events generated by DM_PNP. The back channel of this terminal is used for completion events only. Terminal "pnp" with direction "Plug" and contract IJDRAIN. Note: All PnP IRP events are forwarded through here. The back channel of this terminal is used for completion events only. Floating. Events and notifications passed through the "in" terminal Incoming Event Bus Notes EV REQ IRP B_EVJR Indicates that IRP needs processing. DM PNP P may process the request asynchronously - it will keep the event bus pointer until the request is completed. For this reason the caller should not use an automatic (stack) variable for the event bus. Outgoing Event Bus Notes EV REQ IRP BJΞVJR Indicates that IRP processing has completed. P The event bus is that of the original EV REQJRP event that entered DM_PNP, with the CMEVT A COMPLETED attribute set. Events and notifications passed through the "pnp" terminal Outgoing Event Bus Notes EV REQJRP BJΞV IR Indicates that IRP needs processing. P Incoming Event Bus Notes EV_REQJRP B_EVJR Indicates that IRP processing has completed. P DM PNP expects to receive the the same bus pointer as the one used to send the request out the pnp terminal. It should have the CMEVT A COMPLETED attribute set. Events and notifications passed through the "out" terminal Outgoing Event Bus Notes <any> < any> All non-PnP events received at the in terminal. Incoming Event Bus Notes < any > < any > These events are sent to in terminal. DM PNP does not interpret them. Events and notifications passed through the "Ifc" terminal Outgoing Event Bus Notes EV_LFC_REQ_START B_EV_L Request to start normal operation. FC EV_LFC_REQ_STOP B_EV_L Request to stop normal operation. FC EV_LFC_REQ_DEV_PAU B EV L Request to put the device in a "paused" state. SE FC EV_LFC_REQ_DEV_RES B_EV_L Request to revert the device from "paused" state UME FC to normal. EV_LFC_NFY_DEV_REM B EV L Notification that the device has been removed. OVED FC Special events, frames, commands or verbs Upon receiving EV_REQJRP event on its in terminal, DM_PNP performs a secondary dispatch by IRPs minor function code for PnP IRPs (IRP MJ PNP). The processing for most of the minor function codes is generating a life-cycle (LFC) event and sending it through the Ifc terminal. The following table provides details about the relative order between the LFC and the original IRP events sent by DM_PNP through its output terminals. IRP MJ PNP Notes minor functions IRP_MN_START_DEVICE LFC event is generated after the IRP event is forwarded out. IRP_MN_CANCEL_REMOVE_DEVICE Same as above. IRP MN CANCEL STOPJDEVICE Same as above. IRP_MN_QUERY_STOP_DEVICE LFC event is generated before the IRP event is forwarded out. IRP_MN_STOP_DEVICE Same as above. IRP_MN_QUERY_REMOVE_DEVICE Same as above. IRP_MN_REMOVE_DEVICE Same as above. IRP MNJDEVICEJJSAGE NOTIFICA No LFC event is generated. The IRP event TION is forwarded out. IRP_MNJRP_MN_QUERY_DEVICE_R Same as above. ELATIONS IRP MN QUERY RESOURCES Same as above. IRP_MN_QUERY_RESOURCE_REQUI Same as above. REMENTS IRP MN QUERY ID Same as above. The particular LFC event being generated in response to an IRP depends on the internal state of DM PNP. Property "cplt_tout" of type "UINT32". Note: LFC events completion timeout in miliseconds. Redirected to subordinate PLT, property cplt_out. Default: as provided by DM_PLT (3000) Encapsulated interactions DM_PNP is an assembly and does not utilize such interactions. Its subordinates, however, may do so, depending on their implementation. For more information on the subordinates, please refer to the data sheets of: DMJRPFLT DM RSL DM_BSP DM_SEQ DM_PLT 6. 1.4. Internal Definition Fig. 29 illustrates the internal structure of the inventive DM PNP part. Theory of operation DM_PNP is an assembly, its internal structure is shown on the previous page. The main flow of events is received on the in terminal input in the form of EV_REQ IRP. The IRP flow is split by SPL into IRP_MJ_PNP IRPs (events of interest), which are passed through its aux terminal further and events that are forwared immediately out of DM_PNP through the out terminal. The PnP IRP events arrive at the in terminal of the RSL (request serializer). ESL is basically a "valve" for events. It ensures that only one IRP event at a time is pending processing in Area B (including the outside scope of DM_PNP). All new events are enqueued. When the event being processed in is completed, RSL will dequeue the next event (in the order in which was received) and repeat the same procedure. The IRP event arriving at the in terminal of S1 is distributed to three channels: Ch1 , Ch2 and Ch3 in this order by the cascaded set of DM_SEQ instances - S1 and S2. The three event channels appear as follows: Ch2 - Part S2, terminal outl Ch3 - Part S2, terminal out2 Ch1 and Ch3 are connected to IRP filters (F pre and Fpost) parameterized to filter in respectively the pre and post-LFC IRP events. The filters are mutually exclusive: IRP events filtered in by one of them is filtered out by the other. Ch2 is connected to PLT - the part responsible to generate LFC events on its out terminal from the IRP events arriving at its in terminal. The output of this part is wired directly to the Ifc terminal. Finally the outputs of Fpre and Fpost filters (pre and post-LFC IRP events) are combined together and wired out to the pnp terminal. Subordinate Parameterization Subordinat Property Value SPL irp nj IRPJVU PNP Fpre irp_mj IRPJVU PNP irp_mn[0] IRPJvlN _START_DEVICE irp_mn[1 ] IRP_MN CANCEL_STOP_DEVICE irp_mn[2] IRPJvlN _CANCEL_REMOVE_DEVICE Fpost irp_mj IRPJVU PNP irp_mn[0] IRP_MN DEVICE USAGE NOTIFICATION irp_mn[1 ] IRP_MN _EJECT irp_mn[2] IRP_MN _FILTER_RESOURCE_REQUIREMENTS irp_mn[3] IRPJvlN _QUERY_BUSJN FORMATION irp_mn[4] IRPJvlN _QUERY_CAPABILITIES irp_mn[5] IRPJvlN _QUERY_DEVICE_RELATIONS irp_mn[6] IRPJvlN _QUERY_DEVICE_TEXT irp_mn[7] IRPJvlN QUERY ID irp_mn[8] IRPJvlN .QUERYJNTERFACE irp_mn[9] IRPJvlN QUERY J 3 NP_DEVICE_ST ATE irp_mn[1 0] IRPJvlN _QUERY_REMOVE_DEVICE irp mn[1 1 ] IRP MN QUERY RESOURCES irp_mn[1 2] IRP_MN_QUERY_RESOURCE_REQUIREMENTS irp_mn[1 3] IRP_MN_QUERY_STOP_DEVICE irp_mn[14] IRP_MN_READ_CONFIG irp_mn[1 5] IRPJV1N _REMOVEJDEVICE irp_mn[1 6] IRP_MN_SET_LOCK irp_mn[1 7] IRP_MN_STOP_DEVICE irp_mn[1 8] IRP_MN_SURPRISE_REMOVAL irp_mn[1 9] IRP MN WRITE CONFIG Fback < same as Fpost _> S1 ev[0].evjd EV_REQJRP ev[0].disc "fwd_cleanup" ev[0].cleanu EV NULL pjd async_cplt_a CMEVT A_ASYNC_CPLT ttr cplt_attr CMEVT_A_COMPLETED cplt_s_offs offsetof (B_EV IRP, cplt_s) S2 < same as S 1 > se Cases Typical Usage Fig. 30 illustrates an advantageous use of the inventive DM_PNP part. DM FAC instantiates the device assembly (DEV) for each hardware device. This, in turn instantiates DM_PNP and connects it to the ext terminal of the factory (DM_FAC). The outputs of DM_PNP are connected as shown on the diagram. When the factory is called on its PnP IRP dispatch routine, it generates event EV_REQJRP and sends it through its ext terminal. event must be generated first. DM_PNP generates and sends the life cycle event through its Ifc terminal, which ends up in the CTL part for processing. The recipient of the life-cycle event indicates asynchronous completion and will send a completion event back later. The control returns to DM_PNP and it attempts to forward the IRP event through its pnp terminal, which is left unconnected in this case and it will be simply ignored. DM_PNP returns control to its caller indicating that the event processing is still pending and waits for completion event sent back through its Ifc terminal. When the CTL finishes the processing of the life-cycle event, it sends completion event back to DM_PNP. This causes DM_PNP to send a completion event back to through its in terminal, which ends up in the factory (DM_FAC). The factory after receiving this completion event will finally complete the IRP. Notes The recipient of the IRP_MN_REMOVE_DEVICE IRP event (received from the pnp terminal) must return the removal completion status from the lower driver to DM_PNP, not its own removal status. The life-cycle events received from the Ifc terminal are sent in the execution context of the DriverMagic's pump thread - not the thread that caused DM_PNP to generate these events. 6. 1.5. DM IOC - IOCTL Handler Fig. 31 illustrates the boundary of the inventive DMJOCTL part. DMJOC is an I/O control handler that accepts either single I/O controls or a consecutive range of I/O controls (through IJDIO.ioctl) and translates them into corresponding events, which it then sends out its evt terminal. The structure of the event-specific data portion of the event bus must be identical to the structure of the incoming I/O control data. The I/O controls that DMJOC processes must all be accompanied by the same or similar data (bus). On preview, DMJOC accepts ioctl operations (only for recognized I/O controls) for exclusive processing and passes all other I DIO operations through out. events on its evt terminal and forwards all operations received on its out terminal to in. IJDIO operations invoked through in other then ioctl are passed through out without modification. Unrecognized I/O controls received with ioctl (preview or no preview) are passed through out as well. Boundary Terminals Terminal "in" with direction "Bidir" and contract in: I DIO out: MDIO C. Note: Synchronous, v-table, cardinality 1 Receive IJDIO commands and send out completions. This terminal is unguarded. Terminal "out" with direction "Bidir" and contract in: l_DIO_C out: I DIO. Note: Synchronous, v-table, cardinality 1 , floating I DIO operations invoked through in (not preview) and unrecognized I/O controls (received with IJDIO. ioctl) are passed out through this terminal, complete operations invoked through this terminal are passed out in. This terminal is unguarded. Terminal "evt" with direction "Plug" and contract IJDRAIN. Note: Synchronous, v- table, cardinality 1 Send/receive recognized events. This terminal is unguarded. Events and notifications DMJOC is parameterized with the event IDs of the events it generates from the I/O controls received from in.ioctl. DMJOC requires that the event bus contains storage for a completion status and a context value. These fields are usually in addition (outside) of the data coming/returning on the I/O control. The size of the data buffer supplied with the incoming request must be large enough to hold the return data from the I/O control operation. Also, the size of the input data must be equal to the length of the output data for the request. Special events, frames, commands or verbs None. Properties Property "ioctl_base" of type "UINT32". Note: Base ID for incoming I/O controls. This property is mandatory Property "event_base" of type "UINT32". Note: Base ID for outgoing events. This property is mandatory controls/events) to support, starting from xxx_base. This property is mandatory. Property "async cplt attr" of type "UINT32". Note: Value of the attribute that signifies an I/O control operation can be completed asynchronously. The default is: CMEVT_A_ASYNC_CPLT Property "cplt_attr" of type "UINT32". Note: Value of the attribute that signifies that an I/O control operation has been completed. This attribute is expected to be set in the completion event received on evt when a previously issued asynchronous I/O control operation has completed. The default is: CMEVT_A_COMPLETED Property "cplt_s_offs" of type "UINT32". Note: Offset in event bus for storage for the operation completion status. The size of the storage must be at least sizeof (cmstat). The default is: OxOC (first field in event bus after standard fields id, sz and attr) Property "ctx_offs" of type "UINT32". Note: Offset in event bus where DMJOC's context is to be stored. The size of the storage must be at least sizeof (_ctx). The default is: 0x10 (after completion status storage) Property "data_offs" of type "UINT32". Note: Offset in event bus where data received with I/O control is to be stored. The default is: 0x14 (data is at the end of the event bus) Property "copyjn" of type "UINT32". Note: Boolean. If TRUE, DMJOC copies the I/O control input data received with the I/O control into the I/O control event sent through the evt terminal. Default is TRUE. Property "copy_out" of type "UINT32". Note: Boolean. If TRUE, DMJOC copies the output data in the I/O control event (received from the evt terminal) into the output data buffer received with the original I/O control. Default is TRUE. Property "force Jree" of type "UINT32". Note: Set to TRUE to free self-owned events received from the evt terminal. Default: FALSE. Encapsulated interactions None. Responsibilities Accept ioctl operations on in (preview) and claim as exclusive; do not forward preview to out. Reject all other I DIO operations on preview; do not forward preview. Forward unrecognized I/O controls to out without modification. Forward all incoming calls on out to in without modification. Forward all incoming calls on in to out without modification (excluding ioctl). Process recognized I/O control requests by translating the request into an event and forward the event out evt (note: DMJOC must satisfy the IJDIO completion requirements). Generate events for asynchronous completion only if the I/O control request requires it. Check completion attribute for recognized events received on evt and invoke in. complete if applicable. Refuse recognized events received on evt whose completion attribute is not set. Refuse all events coming on evt whose event ID is outside of the range recognized by DMJOC. Theory of operation State machine None. Main data structures None. Mechanisms Recognizing IOCTL requests The recognized I/O control requests are specified by setting the ioctl base and n_ops properties. The request is handled by DMJOC if the I/O control ID received on preview falls in the range of ioctl_base...ioctl_base + n_ops - 1 . For all recognized requests, DMJOC generates an event through its evt terminal. The event ID is calculated by using the event base and ioctl_base properties. The formula for calculating the event ID is: event base + (I/O control request - and the event IDs generated by DMJOC. Processing recognized I/O control requests (preview) When DMJOC receives a call on in.ioctl (preview), it checks if the I/O control is recognized using the mechanism described above. If it is recognized, DMJOC claims it as exclusive by returning CMST_SUBMIT. If the I/O control is not recognized, DMJOC forwards the request through out and returns the status from the operation. Submitting the I/O control request When DMJOC recognizes an I/O control request, the following steps are performed: Allocates an event bus with size B DIO.Ien + 8 + sizeof (CMEVENT HDR). The extra 8 bytes are used for the completion status and the context value. Sets up the event header using the associated event ID, sets the attributes to CMEVT_A_SYNC_ANY | CMEVT_A_SELF_CONTAINED. Add the async_cplt_attr attribute to the event if the operation is allowed to complete asynchronously (specified in BJDIO). Transfers the data stored in BJDIO. p at data_offs in the event bus (if copyjn is TRUE). Initializes the context and completion status to their respective values. (The context is set to point to a copy of the incoming bus and the completion status is initialized to CMSTJDK). Sends the event out the evt terminal. Handles possible asynchronous completion (see Handling asynchronous completion mechanism below); frees the saved copy of the incoming bus if the operation has completed synchronously. Handling asynchronous completion α When DMJOC is invoked on its evt terminal and the cplt_at.tr is present in the event attributes, it retrieves the saved copy of the BJDIO bus. DMJOC then sets the completion status from the I/O control operation. If copy out is TRUE, DMJOC then copies the data (BJDIO. len bytes) into the bus (BJDIO. p). DMJOC then invokes in. complete to complete the asynchronous operation. it frees the event bus and refuses the event by returning CMSTJREFUSE. Usage Notes The I/O control codes and event IDs DMJOC recognizes must be consecutive starting from their respective bases (ioctl_base and event Jsase). The length of the output data for an I/O control request must be equal to the length of the input data. On evt. raise, DMJOC will always free the event bus (for recognized events) without reguard to the event attributes (i.e., the event should not be allocated on the stack). Normally the client should use the same event bus that it received from DMJOC. DMJOC does not expect the completion event received on evt. raise to be the same event it generated for a specific IOCTL. If the client uses a copy of the event, it should free the original event. DMJOC only supports buffered I/O controls. 6. 1.6. DMJRPOUT - Driver Gateway for IRPs Fig. 32 illustrates the boundary of the inventive DMJRPOUT part. DMJRPOUT is an IRP gateway to drivers. This part provides the functionality necessary to submit an IRP to any driver 2 . The IRP event is received on the in terminal. DMJRPOUT can be parameterized to specially handle Power Management IRPs, as the procedure for these is somewhat different than all the rest. DMJRPOUT provides an event for IRP completion back to the part that originally submitted the IRP. DMJRPOUT may optionally (property-based) condition the execution context from which the completion event is sent. DMJRPOUT will block the sender until the IRP is completed in case the incoming event does not allow asynchronous completion. 2 The IRP must have enough stack locations, so that the driver it is sent to can complete its processing. Boundary Terminals Terminal "in" with direction "Plug" and contract I DRAIN. Note: Terminal for IRP events. The input receives IRP events (EV REQJRP) and fails all other with CMSTJMOT_SUPPORTED. DMJRPOUT registers an IO completion routine, which when executed will cause a completion event to be sent through the back channel. DMJRPOUT may optionally condition the execution context for the completion event by ensuring that the completion event is sent within a thread context (PASSIVE IRQL). Based on the attributes of the incomming event, DMJRPOUT may block the caller's thread until the IRP is completed. Events and notifications Incoming Event Bus Notes EV_REQJRP B EVJR Indicates that IRP needs processing. P The attributes of the event define whether asynchronous completion is allowed: if (CMEVT_A_ASYNC_CPLT) Received on in terminal. Outgoing Event Bus Notes EV REQ IRP B EVJR Notification that IRP has completed. This P event is a copy of the original event with CMEVT_A_COMPLETED attribute set. Sent through the back channel of in terminal. Special events, frames, commands or verbs None. Properties Property "pwr" of type "UINT32". Note: Boolean. If TRUE DMJRPOUT uses Power Management API for passing to lower-level drivers. Default: FALSE Property "cond_cplt" of type "UINT32". Note: Boolean. If TRUE DMJRPOUT enforces that the completion events are sent in thread context (IRQL PASSIVE). Default: TRUE driver, which to forward the IRPs to. Activetime. Property "force ree" of type "UINT32". Note: Boolean. If TRUE DMJRPOUT will free event buses even if error occurs. Encapsulated interactions DMJRPOUT calls the Windows I/O manager to retrieve IRP stack location and pass IRPs to lower level drivers. DM_ IRPOUT registers completion routines called by the I/O manager when it completes the IRPs (in all cases: OK, ERROR and CANCEL). If necessary, DMJRPOUT allocates OS event for synchronization of the completion procedure. DMJRPOUT uses asynchronous message dispatch service provided by DriverMagic. Specification Responsibilities Call the driver (device) for further processing of the IRP. Register IO completion routine with each IRP. Send completion event back when the IRP is completed asyncronously by the driver (device). If needed, condition the execution context when sending the completion event back. When conditioned is performed, ensure that the event is sent back in PASSIVE IRQL. Block the event sender until the driver completes the IRP when the incoming event does not allow asynchronous completion. Use PoCallDriver API for passing the IRP to the driver when pwr property is TRUE. Theory of operation State machine None. Main data structures DeviceObject (system-defined) The OS maintains a DeviceObject structure for each device created. This structure is used by the I/O Manager to pass the arguments for all driver functions (IRPJVU_xxx). Mechanisms Generating Completion Events for IRPs DMJRPOUT sends completion event back to the part that submitted the IRP event. In order to do this, DMJRPOUT registers an IO completion routine with the IRP in question. When the lower-level driver completes that IRP this routine is invoked. DMJRPOUT associates the original IRP event with the completion routine as context. This context is passed to that routine. If cond_cplt property is TRUE and the IRQL is DISPATCH, DMJRPOUT will post a message to itself and await for a thread (PASSIVE IRQL) to dispatch that message. When the message is dispatched, DMJRPOUT will send the completion event through the in back channel. Use Cases Sync. Completion IRP event comes on in. DMJRPOUT registers completion routine with a copy of the incoming event. DMJRPOUT submits the IRP to the driver. The driver completes it synchronously which invokes the completion routine. DMJRPOUT returns the status of the IRP back to the sender Async. Completion w/blocking IRP event comes on in. DMJRPOUT registers completion routine with a copy of the incoming event. DMJRPOUT submits it to the driver. The driver returns STATUS_PENDING. DMJRPOUT blocks the calling thread on OS sync, object. When the driver completes the IRP, the completion routine is invoked, DMJRPOUT signals the sync, object. The thread waiting on the sync, object unblocks and returns the completion status as returned by the driver. Async. Completion w/o blocking IRP event comes on in. DMJRPOUT submits it to the driver. The driver returns STATUS_PENDING. DMJRPOUT returns CMST_PENDING When the driver completes the IRP, the completion routine is invoked, DMJRPOUT generates the completion event and sends it back to in. Async. Completion with conditioning IRP event comes on in. DMJRPOUT registers IO completion routine DMJRPOUT submits it to the driver. The driver returns STATUS_PENDING. DMJRPOUT returns CMST_PENDING When the routine is invoked DMJRPOUT posts a message to itself. When the message is dispatched (in thread context) DMJRPOUT generates the respective completion event and returns it back to in. 6. 1.7. DM PWR - Plug-n-Play Power IRP handler Fig. 33 illustrates the boundary of the inventive DM_PWR part. DM_PWR handles Plug-n-Play Power Management IRPs for drivers that are not concerned with power management. DM_PWR satisfies the PnP specification requirements for power management so these drivers can be used (Note that a driver can request not to handle power management IRPs - please see the Windows 98 DDK documentation for more information). IRPs are received by DM PWR as EV_REQJRP events (from the irp terminal). All unrecognized events received from irp are passed to aux with no modification. All events received on aux are passed out irp. This enables DM_PWR to be used in any event flow. DM_PWR can be configured for a filter or a function driver. When using DM PWR in a filter driver, all power IRPs are passed out through pwr to be submitted to the next lower driver. When using DM_PWR in a function driver, DM_PWR completes all power IRPs itself. See the Mechanism section below for more details. Boundary Terminals Terminal "irp" with direction "Plug" and contract IJDRAIN. Note: v-table, synchronous, cardinality 1 IRP events (EV_REQJRP) with IRPJVIJ POWER. All other modification. Terminal "pwr" with direction "Plug" and contract IJDRAIN. Note: v-table, synchronous, cardinality 1 This terminal is used to pass the power IRPs to a lower-level driver. The back channel is used only for completion events. Terminal "aux" with direction "Plug" and contract IJDRAIN. Note: v-table, synchronous, cardinality 1 , floating Used to send out all unrecognized events received on irp. All events received here are passed out through irp with no modification. Events and notifications "irp" terminal Incoming Event Bus Notes EV REQ IRP BJΞVJRP Indicates that IRP needs processing. The attributes of the event define whether asynchronous completion is allowed: if CMEVT_A ASYNC CPLT is specified. 'pwr" terminal Incoming Event Bus Notes EV_REQJRP B EV IRP Notification that a power IRP has completed. This event is a copy of the original event with CMEVT A COMPLETED attribute set. Outgoing Bus Notes Event EV_REQJRP B_EVJRP Original IRP event. Sent through pwr terminal to be passed to the next lower-level driver. Special events, frames, commands or verbs The following minor IRP codes are processed by DM_PWR (in conjunction with IRP_MJ_POWER): IRP_MN_QUERY_POWER IRP_MN_SET_POWER IRP_MN_POWER_SEQUENCE Properties Property "filter" of type "UINT32" . Note: Boolean. If TRUE DM_PWR passes all power IRPs down to the next driver in the stack. If FALSE, DM PWR completes the power IRPs as expected by the operating system refusing transitions to lower power modes. Default is FALSE. Encapsulated interactions DM_PWR calls the Windows Power Manager to request the next power IRP. Specification Responsibilities Forward all power IRPs to irp if DM_PWR is being used in a filter driver. Complete all power IRPs (as expected by the PnP specification) if DM_PWR is being used in a function driver. Refuse transitions to any power mode other then full power. Pass all unrecognized events (events other than EV_REQJRP or IRPs with major code other than IRP_MJ_POWER) received from irp and aux out through the opposite terminal. Theory of operation State machine None. Main data structures IRP (system-defined) This structure is used by the I/O Manager to pass requests and their arguments for all driver functions (IRP_MJ_xxx). Mechanisms Handling Power IRPs for a filter driver If the filter property is TRUE, DM_PWR behaves like a filter driver. Filter drivers pass all IRPs down to the next lower-level driver. DM_PWR forwards all power IRPs out through the pwr terminal without modification. It is up to the final driver in the stack to complete the power IRP. to pass it to the next lower-level driver using PoCallDriverO. If the IRP is completed asynchronously, DM_PWR expects to receive a completion event (from pwr) when the IRP has completed. The completion event is the same event passed through pwr with the CMEVT_A_COMPLETED attribute set. After the IRP is completed by a lower-level driver and DM PWR receives the completion event, DM_PWR calls PoStartNextPowerlrpO to tell the Power Manager that DM_PWR is ready to accept new power IRPs. If the IRP is completed synchronously, it is up to the part connected to pwr to call PoStartNextPowerlrpO to receive the next IRP. Handling Power IRPs for a function driver If the filter property is FALSE, DM PWR behaves like a function driver. In this case, DM_PWR behaves like the filter mechanism described above. The only difference is DM PWR fails particular power IRPs. In addition, DM_PWR will refuse any request to change to a power mode other then full power. Here is a description of how each IRP is handled when DM PWR behaves like a function driver: IRP_MN_QUERY_POWER - Required to be handled by all drivers. If transition is to any power mode other then full power, fail the IRP with STATUS NOT SUPPORTED. Otherwise the IRP is passed to the next lower- level driver. IRP MNJ5ET POWER - Required to be handled by all drivers and must always succeed. The IRP is passed to the next lower-level driver. IRP_MN_WAIT_WAKE - Not required, it is completed with STATUS_NOT_SUPPORTED. IRP_MN_POWER_SEQUENCE - Not required, it is completed with STATUS NOTJMPLEMENTED. Please refer to the Windows 98 DDK documentation for descriptions of the power management IRPs. Use Cases Using DM PWR in a filter driver DM_PWR is parameterized with a device object pointer and as a filter driver (filter_drv property is TRUE). All power IRPs received by DM_PWR from this point forward are passed out the pwr terminal. A lower-level driver completes the power IRPs. The driver continues to run until unloaded by the operating system. Using DM PWR in a function driver DM_PWR is parameterized with a device object pointer and as a function driver (filter_drv property is FALSE). The driver is loaded, created, and activated. All power IRPs received by DM PWR from this point forward are completed according to the mechanism described above. The driver continues to run until unloaded by the operating system. Notes DM_PWR expects that incoming IRPs will have their next stack location set with a copy of the current (using loCopyCurrentlrpStackLocationToNextO) DM_PWR expects that when it passes an IRP through its pwr terminal, if the recipient does not set a completion routine for the IRP, PoStartNextPowerlrpO should be called before passing the IRP to the next lower-level driver. Otherwise, it is expected that a completion routine is set for the IRP and when the completion routine is called, a completion event is sent back to DM_PWR. 6. 1.8. DM DOPEN - Device Driver Opener Fig. 34 illustrates the boundary of the inventive DMJDOPEN part. DMJDOPEN is used by device drivers to communicate with other device drivers. Since in the Windows NT/WDM environments a device driver can't be opened or closed by submitting requests to it, DMJDOPEN must be used to open/close a device driver using the ZwCreateFile and ZwClose APIs. All other device driver operations are passed through DMJDOPEN so they can be handled elsewhere. When an EV_DIO_RQ_OPEN event is received on the in terminal, DMJDOPEN opens the specified driver using ZwCreateFileO. The driver is closed when a through out without modification. After a device driver is opened, DMJDOPEN sets device object and file object properties through the prp terminal. This allows DMJDOPEN to be used in an assembly with the DI02IRP and IRPOUT parts - DMJDOPEN should never be used by itself (see the use case below). DMJDOPEN is made to be used inside an assembly to allow full communication with another device driver. Only one device driver may be open at any time; subsequent open atempts fail with CMST REFUSE. Boundary Terminals Terminal "in" with direction "Plug" and contract I DRAIN. Note: v-table, synchronous, infinite cardinality IJDIO event terminal. If EV_DIO_RQ_OPEN or EV_DIO_RQ_CLOSE are received through this terminal they are translated into ZwCreateFile and ZwClose operations respectively. All unrecognized events are passed through out without modificaiton. Terminal "out" with direction "Plug" and contract IJDRAIN. Note: v-table, -synchronous, cardinality 1 All unrecognized events received from in are passed out this terminal without modificaiton. All events received on this terminal are passed through the in terminal without modification. Terminal "prp" with direction "Out" and contract l_A_PROP. Note: v-table, synchronous, cardinality 1 After a device driver is opened by DMJDOPEN, the device object (dev_objp) and file object (file_objp) properties are set through this terminal. Events and notifications Incoming Event Bus Notes EV DIO RQJD B_EV_D This event is translated into a ZwCreateFile PEN IO operation. EV_DIp_RQ_C BJΞVJD This event is translated into a ZwClose operation. LOSE IO Special events, frames, commands or verbs None. Property "share_access" of type "UINT32". Note: Type of share access for the device driver being opened. Can be one or a combination of the following values: Property of type . Note: FILE SHARE READ Read access by other threads. Property of type . Note: FILE_SHARE_WRITE Write access by other threads. Property of type . Note: FILE SHARE DELETE Delete access by other threads. Property of type . Note: Default is 0 (no file sharing). Properties set through prp The following properties are set through the prp terminal after a device driver has been successfully opened: Property "dev objp" of type "UINT32" . Note: Device object corresponding to device driver opened by DMJDOPEN. Property "file_objp" of type "UINT32". Note: File object corresponding to device driver opened by DMJDOPEN. Encapsulated interactions DMJDOPEN is designed to operate within the Windows NT/WDM kernel mode environments. It uses the following system services to open and close a device driver: ZwCreateFileO ZwCloseO Specification Responsibilities 1 . If an EV_DIO_RQ_OPEN event is received on in, open the specified device driver using ZwCreateFileO . 2. If an EV_DIO_RQ_CLOSE event is received on in, close the device driver using ZwCloseO. 3. Pass all unrecognized events received on in through out without modification. 4. Pass all events received on out through in without modification. Theory of operation Mechanisms Opening/closing a device driver DMJDOPEN translates the following events into open/close file operations: EV DIO RQ OPEN → ZwCreateFile The driver that DMJDOPEN opens is specified in the B_EV_DIO bus passed with the EV_DIO_RQ_OPEN event. DMJDOPEN passes back a file handle representing the opened device driver. After DMJDOPEN opens the device driver, it retrieves the device object and the file object corresponding to the driver. DMJDOPEN sets these two values as properties through its prp terminal. All unrecognized events are passed directly through out without modification. Use Cases Fig. 35 illustrates the internal structure of the inventive DMJDOPEN part. The assembly in the above figure is created and activated. A Part connected to the in terminal sends an EV_DIO_RQ_OPEN event to DM_DEVACC. DOPEN opens the specified device driver using ZwCreateFileO and receives the file handle. DOPEN sets the dev_objp and file_objp properties through the prp terminal. The PEX sets these properties on the DMJDEVACC assembly and they are propagated to the DI02IRP and IRPOUT subordinates (group properties). Read, write and ioctl operations are received on in as I DIO events (EV_DIO_RQ_xxx) and are passed directly to DI02IRP. DI02IRP converts these events to IRP events and sends them to IRPOUT. IRPOUT sends the IRP to the previously opened device driver and returns. When the part connected to DMJDEVACC is finished using the device driver, it closes it by sending an EV DIO RQ CLOSE event to DMJDEVACC. DOPEN closes the device driver using ZwCloseO. Notes DMJDOPEN expects that a fully qualified device driver path (i.e. \Device\xxx) is specified in the B_EV_DIO bus passed with the EV_DIO_RQ_OPEN event. DMJDOPEN passes the device driver path directly to ZwCreateFileO. Below is a list of the parameters DMJDOPEN passes to ZwCreateFileO: DesiredAccess = GENERIC_READ and GENERIC_WRITE FileAttribues = O CreateDisposition = FILE OPEN CreateOptions = 0 6. 1.9. DM DEVACC - Device Driver Accessor Fig. 36 illustrates the boundary of the inventive DM DEVACC part. DMJDEVACC is used by device drivers to communicate with other device drivers. DMJDEVACC supports all the I DIO events as defined by e dio.h. When an EVJDIO RQ OPEN event is received on the in terminal, DM DEVACC opens the specified driver using ZwCreateFileO. The driver is closed when a EV_DIO_RQ_CLOSE event is received (using ZwCloseO). All other IJDIO events (besides open and close) are converted into IRPs and are passed to the device driver. The IJDIO operations passed through in may complete synchronously or asynchronously. Only one device driver may be open at any time; subsequent open atempts fail with CMST_REFUSE. Boundary Terminals Terminal "in" with direction "Plug" and contract I DRAIN. Note: v-table, synchronous, infinite cardinality I DIO events (EV DIO RQ xxx) are received through this terminal. These events are used by a device driver to communicate with another device driver. The back channel of this terminal is used for notifications of the completion of asynchornous operations. Events and notifications Incoming Event Bus Notes EVJDIO RQ OPEN B_EV _D Open device driver using ZwCreateFileO. IO EV_DIO_RQ_CLEANUP B_EVJD Not supported. IO EV_DIO_RQ_CLOSE B_EVJD Close device driver using ZwCloseO. IO EV DIO RQ READ BJΞVJD Issues a read operation to device driver. IO EV_DIO_RQ_WRITE B_EV_D Issues a write operation to device driver. IO EVJDIO RQJOCTL BJΞVJD Issues an I/O control operation to device driver. IO EV DIO RQJNTERNAL BJΞVJD Issues an internal I/O control operation to device IOCTL IO driver. Special events, frames, commands or verbs None. Properties Property Type Notes name share access UINT32 Type of share access for the device driver being opened. Can be one or a combination of the following values: FILE_SHARE_R Read access by other threads. EAD FILE_SHARE_ Write access by other threads. WRITE FILE_SHARE_D Delete access by other threads. ELETE ' Default is 0 (no file sharing). This property is redirected to DMJDOPEN. Encapsulated interactions DMJDEVACC is designed to operate within the Windows NT/WDM kernel mode environments. It uses the following system services to open/close device drivers, manage IRPs and completion routines: ZwCreateFileO ZwCloseO loAIIocatelrpO loGetNextlrpStackLocationO loFreelrpf) loCallDriverO loSetCompletionRoutineO KeWaitForSingleObjectO KeSetEventO Internal Definition Fig. 37 illustrates the internal structure of the inventive DM DEVACC part. DMJDEVACC is an assembly that is built entirely out of DriverMagic library parts. It is comprised of a "Device Driver Opener" (DOPEN), which opens and closes a device driver; a "Property Exposer" (PEX) that gives DOPEN access to DMJDEVACC's properties; an "I DIO Event to IRP Adapter" (DI02IRP), which converts I DIO events into IRP events; and an "IRP Gateway" (IRPOUT) which takes an IRP event and sends the IRP to the appropriate device driver. When an IJDIO event is received on the in terminal it is passed to DOPEN. If the event is EVJDIO RQ OPEN, DOPEN opens the device driver using ZwCreateFileO. If the event is EVJDIO RQ CLOSE, DOPEN closes the device driver using ZwCloseO. All other events are passed through out and arrive in DI02IRP. After the device is successfully opened, DOPEN sets the dev_objp and file_objp properties through the prp terminal. The PEX sets these properties on the DMJDEVACC assembly and they are propagated to the appropriate parts. This mechanism allows DOPEN to parameterize the other parts so the IJDIO operations are passed to the appropriate device driver. DI02IRP converts all other I DIO events into IRP events and passes them through out. The IRP events are received by IRPOUT and are submitted to the appropriate driver. Note that the open and close events are handled entirely by DOPEN and are not passed to DI02IRP or IRPOUT. The I DIO operations passed through in may complete synchronously or asynchronously. Subordinate's Responsibilities DOPEN - Device Driver Opener Open a device driver using ZwCreateFileO if an EV_DIO_RQ_OPEN event is received on its in terminal. Close a device driver using ZwCloseO if an EV_DIO_RQ_CLOSE event is received on its in terminal. Pass all unrecognized events through the out terminal. PEX - Property Exposer Allow access to the dominant's properties from its subordinates. DI02IRP - I DIO Event to IRP Adapter Convert EV_DIO_RQ_xxx events into IRP events that can be submitted to a device driver. IRPOUT - IRP Gateway Send an IRP to the specified device driver. Dominant's Responsibilities Hard parameterization of subordinates Part Property Value Dio2irp n_stk_loc 0 (Default) Dio2irp force_newJr FALSE (Default) P Irpout cond_cplt TRUE (Default) Irpout force ree FALSE (Default) Distribution of Properties to the Subordinates Property Name Type Dist To Share access UINT32 redir dopen.share_access Dev objp UINT32 group dio2irp.dev_objp Dev_objp UINT32 group irpout. dey_objp file objp UINT32 redir dio2irp.file_objp 6. 1. 10. DM EXC - Exception Handler/Event Log Fig. 38 illustrates the boundary of the inventive DMJΞXC part. DMJΞXC listens for exception events (EVJΞXCEPION) on its exc input and saves them in the Windows NT system event log. The nfy input of DMJΞXC is unguarded and can be called at any time as long as the processor interrupt level is at or below DISPATCH. This part is available only in Windows NT Kernel Mode environment. Terminals Terminal "Exc" with direction "In" and contract IJDRAIN. Note: DM EXC formats the data coming with EV EXCEPTION events on this input and saves it in the system event log. All other events are ignored. The exc input terminal is not guarded. Events and notifications Incoming Event Bus Notes EV_EXCEPTION B_EV_EX Exception notification. C No outgoing events. Special events, frames, commands or verbs None. Properties Property "io_objectp" of type "UINT32". Note: Pointer to an I/O Manager object (either DEVICE OBJECT or DRIVERJDBJECT). If the EV_EXCEPTION event does not specify a device object for the source of the exception, this property is used to identify the source of the logged message. This property is mandatory and should be set to a valid I/O Manager object. Property "debug_output" of type "UINT32" . Note: Enables dumping the exception data to the system debug console. The default value for this property is 1 (enabled). Property "eventjog" of type "UINT32" . Note: Enables writing the exception data in the system event log. The default value for this property is 1 (enabled). Encapsulated interactions DMJΞXC uses the I/O Manager services to log events in the system event log. It uses the following kernel-mode services: • loGetCurrentlrpStackLocation • loAllocateErrorLogEntry • loWriteErrorLogEntry Responsibilities 1 . If the eventjog property is set to a non-zero value: write the data coming with EVJΞXCEPTION events as entries in the system event log. 2. If the debug_output property is set to a non-zero value: dump the data coming with EVJΞXCEPTION events to the system debug console. Theory of operation Mapping of EV EXCEPTION to Windows NT Event Log The table below describes the binary data as seen in the event log (same as the Windows NT IO ERROR LOG PACKET structure): Offset Type Field name (IO ERROR LOG PACKET) 0 BYTE MajorFunctionCode 1 BYTE RetryCount 2 WORD DumpDataSize 4 WORD NumberOfStrings 6 WORD StringOffset 8 WORD EventCategory A WORD (compiler-generated alignment to DWORD: not used) C DWORD ErrorCode 10 DWORD UniqueErrorValue 14 DWORD FinalStatus 18 DWORD SequenceNumber 1 C DWORD loControlCode 20 QWORD DeviceOffset 28 BINARY DumpDatafO..] The following fields are interpreted by the I/O Manager to format the log entry: Field Description size of attached binary data NumberOfStrin used to get the insert strings gs StringOffset used to get the insert strings EventCategory shown as category in the event log ErrorCode message ID to look for in the message DLL Mapping IO ERRORJ.OG PACKET and B_EV_EXC IO ERRORJ-OG PACKE B EV EXC ( + IRP's IO STACK LOCATION) T MajorFunctionCode IO_STACK_LOCATION.MajorFunction RetryCount 0 DumpDataSize < calculated from data in BJΞVJΞXC, see below > NumberOfStrings < calculated from inserts > StringOffset < calculated: DumpDataSize + sizeof(IO_ERROR_LOG_PACKET) > EventCategory (exc_severity) < < 8 + exc_class; ErrorCode exc id UniqueErrorValue cm_stat FinalStatus os stat SequenceNumber 0 loControlCode IO_STACK_LOCATION. Parameters. DeviceloControl. loControlCode DeviceOffset IO STACK LOCATION. Parameters. Read. ByteOff set DumpData[0..x] file_name line# - — cutoff line - see note below path (empty) class name term_name oper_name < insert strings (made from 'format' & 'data' fields) follow DumpData > The fields EventCategory and ErrorCode are also shown on the event log summary as Category and Event respectively. The icon displayed with each event is determined by bits 31 and 30 of ErrorCode. When formatting DumpData and the insert strings and the buffer is too small to fit all data, the priority of the data is as follows (high to low, lower priority data is discarded first): 1 . file name 2. Iine# 3. insert strings 4. path 5. class_name 6. term_name 7. oper name State machine None. IO ERROR LOG PA CKET (system-defined) DMJΞXC packs the data from the incoming EVJΞXCEPTION events into this structure and passes it to the operating system. Windows NT I/O Manager saves the contents of this structure as binary data in the system event log. Mechanisms None Use Cases Logging Driver-related Exceptions A driver-related exception is one that is not related to any device instance or any specific I/O operation. In this case the caller provides only an exception ID and optional insert strings with the EV_EXCEPTION event. In this case DMJΞXC uses the value of the io_objectp property as the event source identifier. The I/O operation data in the event log entry is left empty (all zeros). Logging Device-related Exceptions In this case DMJΞXC receives a device object pointer with the EVJΞXCEPTION event and uses it as the event source identifier. The I/O operation data in the event log entry is left empty (all zeros). Alternatively, if the instance of DMJΞXC is used to receive exception events for a single device, the device object pointer can be set as the io_objectp property instead of the driver object. Logging l/O-related Exceptions In this case DMJΞXC receives a pointer to an IRP object (I/O request packet) and uses the data in it to fill in the I/O operation data in the event log entry. DMJΞXC determines the event source by trying the following options (in this order): 1 . A device object pointer provided with the EVJΞXCEPTION data. 2. If the provided IRP has a current stack location - the device object associated with it. The value of the io_objectp property. 6. 1. 11. DM EDCW16 - Callback to 16-bit Windows Fig. 39 illustrates the boundary of the inventive DMJΞDCW1 6 part. arguments as follows: _loadds CALLBACK cbk(uint32 ctx, uint32 msg, uint32 arg); The callback address, the ctx and msg arguments are programmable as properties. The last argument (arg) is taken from the trigger event bus. The argument is taken from a programmable offset in the bus of the trigger event. The callback is invoked in the system virtual machine (the VM in which all 16- and 32-bit Windows applications execute), using VxD nested execution services. Since the callback can be invoked in any thread and at any time, the user-mode code that is called faces the same restrictions that apply to a hardware interrupt that is reflected into user-mode code (for example, see the restrictions that apply to the multimedia timer callbacks). This part is for use in Windows 95 or Windows 98 VxD drivers. It may be used in a WDM driver for Windows 95 or Windows 98. It may also be linked into a driver that is used in Windows NT, but it should not be enabled in this environment. Boundary Terminals Terminal "in" with direction "In" and contract IJDRAIN. Note: DM EDCW1 6 expects a trigger event on this input The ID of the trigger event is programmable as a property. All other events are ignored. This input is unguarded and may be called at any time (including interrupt context). Events and notifications This part recognizes a single event, programmed as a property (trigger_ev). This "trigger" event is converted to a callback to 1 6-bit user mode. Note that, depending on the execution context at the time of the call, the call to in may return before the callback is actually invoked. Special events, frames, commands or verbs None. Properties Property "trigger_ev" of type "UINT32". Note: Trigger event, default = EV_PULSE Setting this property to NULL disables the callback - the trigger event is ignored. This property may be set at active time. Default value: NULL. Property "ctx " of type "UINT32". Note: Context to pass to callback This property may be set at active time. Default value: 0 Property "msgjd " of type "UINT32". Note: Message ID to pass to callback. Default value: 0 Property "arg offs" of type "UINT32". Note: Offset in the trigger event bus of a uint32 argument to pass to callback. Setting this property to -1 is treated as "don't use argument" - no data is taken from the event bus and the 3-rd argument of the callback is set to 0. Default value: -1 Property "enable" of type "UINT32". Note: Enables (1 ) or disables (0) the callback. This property may be set at active time. Default value: 1 (enabled) Encapsulated interactions Uses the following nested execution VxD services: • BeginJMestedJΞxec • EndJMestedJΞxec • ResumeJΞxec • Simulate Far Call • Save_Client_State • Restore_Client_State Other VxD services used: • Get_System_VM_Handle • Call_Priority_VM_Event Note: no VxD services are called if the callback is disabled (addr is set to NULL or enable is set to 0). This allows the part to be embedded into a WDM driver that operates in NT, as long as the design ensures that the callback will be enabled only in Windows 95/98 and not in NT. Responsibilities 1 . Convert a "trigger" event into a callback into 16-bit user-mode code. Ensure the 16-bit code is invoked in the system virtual machine (the normal Windows execution environment) and only if the user-mode code is running with interrupts enabled (i.e., the callback behaves like a hardware interrupt as it would be generated by the VPICD service). Theory of operation State machine No state machine. " Main data structures None. Mechanisms Getting The Correct Execution Context for 16-bit Callback The Call Priority VMJΞvent service is used to ensure,the callback is invoked in the system virtual machine and only when the interrupts are enabled: Call_Priority_VM_Event( High_Pri_Device_Boost, // priority boost Get_System_VM_Handle(), // VM to schedule the event for PEF_Wait_For_STI, // flags (wait for enabled interrupts) ctx, // event callback evtjidlr, // event context 0) // timeout (not used) Invoking the User-Mode Callback DM EDCW1 6 uses the "nested execution" services to invoke the callback. To ensure the correct execution context for the callback, it is invoked from an event handler scheduled to execute as described above. The callback invocation is performed in several steps, as desribed in the Windows 95 DDK: Push_Client_State ; Save client state on stack BeginJMestJΞxec ; Prepare to execute app-mode code ("push" arguments on client's stack here) ; "call far" instruction ResumeJΞxec ; Run the procedure until it returns EndJMestJΞxec ; Finished with nested execution Pop_Client_State ; Restore client state from stack 6. 1. 12. DM ECNW16 - Callback to 16-bit Windows On Request Completion Fig. 40 illustrates the boundary of the inventive DMJΞCNW1 6 part. This part converts an event on its in terminal to a 16-bit user-mode callback, with arguments as follows: __loadds CALLBACK cbk(uint32 ctx, uint32 msg, uint32 arg); The callback address, the ctx and msg arguments are programmable as properties. The last argument (arg) is taken from the trigger event bus. The argument is taken from a programmable offset in the bus of the trigger event. The callback is invoked in the system virtual machine (the VM in which all 16- and 32-bit Windows applications execute), using VxD nested execution services. Since the callback can be invoked in any thread and at any time, the user-mode code that is called faces the same restrictions that apply to a hardware interrupt that is reflected into user-mode code (for example, see the restrictions that apply to the multimedia timer callbacks). This part is for use in Windows 95 or Windows 98 VxD drivers. It may be used in a WDM driver for Windows 95 or Windows 98. It may also be linked into a driver that is used in Windows NT, but it should not be enabled in this environment. DM_ECNW1 6 has the same functionality as DM EDCW1 6, except that DMJΞCNW16 is a transparent filter for asyncronous requests and executes the callback upon completion of the specified trigger event, while DMJΞDCW16 "consumes" the trigger event as an input. A side effect of the DMJΞCNW16 operation is that the trigger event always completes asynchronously for the client connected to in. DMJΞCNW1 6 is an assembly built using DM_EDCW16 (see diagram above). Terminals Terminal "in" with direction "Plug" and contract IJDRAIN. Note: All events from this input are forwarded to out. The "trigger" event is forced to complete asynchronously, even if the part connected to out completes it synchronously. Terminal "out" with direction "Plug" and contract IJDRAIN. Note: Requests from in are forwarded to this terminal. Request completions are forwarded back to in. When completion for the "trigger" request is received, the 1 6-bit callback is invoked after the request is forwarded to in. Events and notifications This part recognizes a single event, programmed as a property (trigger_ev). This "trigger" event generates a callback to 16-bit user mode when received on out. All other events are forwarded transparently between in and out. Special events, frames, commands or verbs None. Properties Property "trigger_ev" of type "UINT32". Note: Trigger event, default = EV_PULSE. This property is forwarded to both instances of DM BFL as "ev_min" and as "evjnax" to make them send the "trigger" event along the "aux" path (the lower part of the diagram). The property is also forwaded to DMJΞDCW1 6 (as trigger_ev). Property "addr" of type "UINT32". Note: Address of callback to invoke (seg:offs). Setting this property to NULL disables the callback - the trigger event is ignored. This property may be set at active time. Default value: NULL. Forwaded to DM EDCW16. Property "ctx " of type "UINT32". Note: Context to pass to callback This property may be set at active time. Default value: 0 Forwaded to DMJΞDCW1 6. Property "msgjd " of type "UINT32". Note: Message ID to pass to callback. Default value: 0 Forwaded to DM EDCW1 6. Property "arg_offs" of type "UINT32". Note: Offset in the trigger event bus of a uint32 argument to pass to callback. Setting this property to -1 is treated as "don't use is set to 0. Default value: -1 Forwaded to DM_EDCW1 6. Property "enable" of type "UINT32" . Note: Enables ( 1 ) or disables (0) the callback. This property may be set at active time. Default value: 1 (enabled) Forwaded to DM_EDCW1 6. Encapsulated interactions The DM EDCW1 6 subordinate uses VxD nested execution services. Refer to the DM EDCW16 data sheet for details. Note: no VxD services are called if the callback is disabled (addr is set to NULL or enable is set to 0). This allows the part to be embedded into a WDM driver that operates in NT, as long as the design ensures that the callback will be enabled only in Windows 95/98 and not in NT. Specification Subordinates DM BFL - Event Filter DMJ3FL is used to direct the "trigger" event along the alternate path where the callback is generated (see the lower part of the diagram). Two instances of DMJ3FL are used - one for the "forward" direction and one for the "back" (completion) direction. DM BSP - Bi-Directional Splitter Two instances of DMJ3SP are used to allow the insertion of DM_RPL (which is unidirectional) into the path of the trigger event completion (out to in). DM RPL - Event Replicator DMJRPL is used to make a copy of the completion event and send it to DM EDCW16 after the original event has been forwarded to in. DM_ACT - Asynchronous Completer This part is used to force the "trigger" event to complete asynchronously, so that even if the part connected to out completes synchronously, a completion event is generated that can be "trapped" by the event replicator (DM_RPL) and sent to DM_EDCW1 6 to generate the 1 6-bit callback. DM EDCW16 - Event to 16-bit Callback This part implements the main functionality of the DMJΞCNW1 6 assembly. It generates the user-mode 1 6-bit callback when it receives the "trigger" event. Hard parameterization of subordinates Part Property Value DM_BFL ev mm EV PULSE (both) ev max EV PULSE 6. 1. 13. DM USCTL - USB Control Pipe Fig. 41 illustrates the boundary of the inventive DM_USCTL part. DMJJSCTL handles command transaction through a USB control pipe. It supports only the default control pipe. Only URB_FUNCTION_VENDOR_xxx and URB FUNCTION CLASS xxx requests are accepted. DMJJSCTL receives control requests on its cmd terminal, converts them into IRPs and sends them out through the irp terminal. DMJJSCTL provides synchronous and asynchronous request completion. DMJJSCTL accepts on its irp terminal only completion report for previously issued IRP requests. DMJJSCTL is typically used inside device and file object scopes in Windows WDM drivers (Windows 98/NT5.0). Boundary Terminals Terminal "cmd" with direction "Plug" and contract IJDRAIN. Note: Accept commands and send out their completions. Terminal "irq" with direction "Plug" and contract IJDRAIN. Note: Submit EV REQ IRP events to the USB driver. Receive EV_REQJRP completions as input. Events and notifications Incoming Event Bus Notes EV USBCTL REQ BJ≡VJJSBCTL Control request command. REQ Received from the cmd terminal. EVJRP_NFY_PROC B EVJRP Notify that the I/O request is completed. _CPLT Received from the irp terminal. EV REQ IRP B EV IRP Notify that the I/O request is completed. CMEVT_A_COMPLETED must be set. Received through the irp terminal. Outgoing Event Bus Notes EV_REQJRP B_EV IRP Sends out an I/O request. Sent out of the irq terminal. EV_USBCTL_REQ B_EVJRP Notify compleion of the control request. Sent out of the cmd terminal. Special events, frames, commands or verbs None. Properties Property "usbd_dev_objp" of type "UINT32". Note: Pointer to the device object of the driver to which to send USB requests. Mandatory. Property "force free" of type "UINT32". Note: Boolean. Set to TRUE to free self- owned events without regard of what the returned sratus is. The default value is FALSE. Encapsulated interactions DMJJSCTL relies on following services from the WDM kernel mode support routines: UsbBuildVendorRequest - formats an URB to send a vendor or class-specific command to a USB device loAllocatelrp - allocates an IRP, given the number of I/O stack locations for each driver layered under the caller, and, optionally, for the caller. loFreelrp - releases a caller-allocated IRP from the caller's loCompletion routine. loSetNextlrpStackLocation - sets the IRP stack location in a driver-allocated IRP to that of the caller. loGetCurrentlrpStackLocation - returns a pointer to the caller's stack location in the given IRP. driver's I/O stack location in an IRP so the caller can set it up for the lower driver. Specification Responsibilities Receive command transaction requests on its cmd terminal. Convert command requests received on cmd into one or several EVJRP requests and send them out through irp terminal. Provide synchronous or asynchronous completions of commands received on the cmd terminal. Accept all incoming request completions on irp terminal. Generate a response for asynchronous completion and send it back through cmd terminal. Theory of operation State machine None. Main data structures None. Mechanisms None 6. 1. 14. DM USCFG - USB Configurator Fig. 42 illustrates the boundary of the inventive DMJJSCFG part. DMJJSCFG provides a simplified interface for enumerating the possible configurations and selecting a configuration for USB devices that support no more than one \JSB interface(*) per configuration^). (* these words are used here in the 'USB' sense. To avoid confusion, terms that are used as defined in the USB specification will be printed in bold italic typeface). The client of DMJJSCFG uses the IJJSBCFG interface to enumerate the available configurations and to select a configuration. Note that selecting a configuration through IJJSBCFG may or may not involve changing the USB configuration of the device. DMJJSCFG sends USBDI requests through its irp terminal in the form of EV_REQJRP events. This output is expected to be connected to a part that services driver. DMJJSCFG is intended to be used in an assembly with other parts from the USB kit. To facilitate this, it provides the parameters of the currently selected configuration as a set of properties by issuing a series of "set" operations to its prp output whenever a request to set an new configuration is successfully completed. Please refer to the Use Cases section later in this document for an example. DMJJSCFG is typically used inside device and file object scopes in WDM USB drivers for Windows 98/NT5. Boundary Terminals Terminal "ctl" with direction "In" and contract IJJSBCFG. Note: Receive configuration requests. Terminal "irp" with direction "Plug " and contract IJDRAIN. Note: Submit EV_REQ IRP events to the lower level USB driver. Since DMJJSCFG always requests EV REQJRP events to be completed synchronously, no callbacks are expected on this terminal. This terminal is unguarded. Terminal "prp" with direction "Out" and contract l_A_PROP. Note: Send out property settings. This output may be left unconnected. Events and notifications Outgoing Event Bus Notes EV_REQJRP BJΞVJRP I/O request. Sent out of the irq terminal. Special events, frames, commands or verbs DMJJSCFG uses the USB-defined tag-length-value structures for configuration, interface and endpoint descriptors. For compatibility with future USB specifications, DMJJSCFG ignores descriptors of other types that are found in the USB configuration data, provided that they are coded the same way as the standard USB descriptors, i.e.: 1 byte length followed by 1 byte descriptor type followed by descriptor data. For details on the USB descriptor structures refer to the USB specification (Universal Serial Bus Specification Revision 1 .0). Property "dev objp" of type "UINT32". Note: Pointer to USBDI device instance structure. This property is mandatory. Properties exported through eprp terminal. Property "config no" of type. Note: "UINT32" Device defined number of the configuration selected by DMJJSCFG. Property "alt_no" of type. Note: "UINT32" Device defined number of the alternate setting selected. Property "endpt[n]. *". Note: Endpoint properties, n in the property name is a 0- based sequence number assigned by DMJJSCFG. DMJJSCFG sets as many of these properties as there are endpoints in the selected configuration and alternate setting. See the descriptions below for each of the endpoint properties. Property "endpt[n].pipe_h". Note: UINT32 Pipe handle. Property "endpt[n].pkt_sz". Note: UINT32 Data packet size. Property "endpt[n].pipe ype". Note: UINT32 Pipe type (UsbdPipeTypexxx). Property "endpt[n]. interval". Note: UINT32 Poll interval. This property has meaning only for interrupt endpoints. Encapsulated interactions DMJJSCFG uses the following services from the USB library: - UsbBuildGetDescriptorRequest - formats an URB with the parameters necessary to obtain descriptor information from the host controller driver (HCD). UsbBuildSelectConfigurationRequest - formats an URB with the parameters necessary to select a configuration on a USB device. USBD_CreateConfigurationRequestEx - allocates and formats an URB to select a configuration for a USB device. DMJJSCFG uses the following WDM kernel mode support routines: loAllocatelrp loFreelrp loGetNextlrpStackLocation Responsibilities Read USB configuration descriptors from device, provide enumeration of available configurations through IJJSBCFG. (Skip any device configurations that have more than one interface). When requested through IJJSBCFG. set: configure the device by selecting the appropriate USB configuration and alternate setting. On successful completion of a IJJSBCFG. set operation: pass USB configuration parameters out as properties to prp output (l_A_PROP interface). Communicate with the USB driver through the irp terminal. Theory of operation State machine None. Main data structures None. Mechanisms Sending USBDI requests DMJJSCFG uses USBDI (USB Device Interface) commands to read configuration descriptors from the device and to set the device configuration. As required by the USBDI it prepares the requests in the form of USB Request Blocks (URBs). These blocks are sent with IOCTL JNTERNAL_USB_SUBMITJJRB requests to the irp output (as EV_REQ IRP events). DMJJSCFG always requests synchronous completion for the EV_REQJRP events. For details on USBDI refer to the Windows 98 DDK documentation. The use of EV REQJRP for sending IRPs is described in the DMJRPOUT data sheet. Also see the EV REQJRP event definition in EJRP.H. Use Cases Using DM USCFG in an assembly with DM USISO. The diagram below shows a sample assembly that includes the DMJJSCFG and DMJJSISO parts as well as parts from the DriverMagic WDM kit. Fig. 43 illustrates an advantageous use of the inventive DMJJSCFG part. the parts of the assembly are: 1 ) Client enumerates available configurations by calling qry_open, qry_first, qry next, etc. on the cfg terminal. DMJJSCFG will read the USB configuration on the qry_open operation by sending the appropriate USBDI requests to irp (connected to an instance of the IRPOUT part). 2) Client selects a configuration suitable for its needs and calls set on the cfg terminal. DMJJSCFG configures the device using USBDI requests. Upon successful completion of the configuration requests, the properties of the selected configuration are sent as properties to the prp output of DMJJSCFG. The PEX part connected to this output converts these calls to standard ClassMagic properties set on on its parent (USBA). USBA in turn is expected to redirect them to the DMJJSISO part. - 3) Client can now enable the data channel by sending EV_REQ_ENABLE to ctl terminal. 4) When done receiving data, client disables the data channel by sending EV REQJDISABLE to ctl. 5) Finally, the USB configuration may be disabled by executing a set operation on cfg, with the cfgjd field set to NOJJSBCFG. 6. . 15. DM USISO - USB Isochronous Pipe Fig. 44 illustrates the boundary of the inventive DMJJSISO part. DMJJSISO handles data transfer through an isochronous USB pipe. It is enabled and disabled through the ctl terminal. The disable and enable operations could be completed asynchronously. DMJJSISO is parameterized with a pipe handle and settings through active time properties. This parameterization takes effect next time when DMJJSISO is enabled. DMJJSISO manages a pool of buffers. When it is enabled, DMJJSISO submits all of them as EV REQJRP events out through irp terminal. On every competed EV_REQ IRP event, USB sends an EV_STM_DATA event through its dat terminal. When this event is completed, synchronously or asynchronously, DMJJSISO resub its EV REQJRP event to the USBDI driver. DMJJSISO accepts on its irp and dat terminals only completion reports for previously issued EV_REQJRP and EV STM DATA requests, respectively. Both terminals are unguarded and could receive events at IRQL less or equal to DISPATCH LEVEL. The EV STMJDATA event is sent usually in the same thread context as its corresponding EV_REQJRP response is received. DMJJSISO is typically used inside device and file object scopes in WDM USB drivers for Windows 98/NT5. Note 1 : DMJJSISO expects completions on its dat terminal to come with the same bus instance as DMJJSISO sent them (and with CMEVT_A_COMPLETED attribute set) Note 2: DMJJSISO supports only Device-to-host data transfers. Boundary Terminals Terminal "ctl" with direction "Plug" and contract I DRAIN. Note: Control terminal. Enable/disable DMJJSISO part. Sends out completion events for these control requests. Can be entered at dispatch IRQL. Terminal "dat" with direction "Plug" and contract IJDRAIN. Note: Submits stream of data EV_STM_xxx events and receive their responses. Unguarded input; can be entered at dispatch IRQL Terminal "irp" with direction "Plug" and contract I DRAIN. Note: Submits EV_REQJRP events to the USB driver. Receives EV REQJRP completions as input. Unguarded input; can be entered at dispatch IRQL Events and notifications Incoming Event . Bus Notes EV JSB ENABLE BJΞVJJSB Enable DMJJSISO part. CTL Received through the cmd terminal. EVJJSBJDISABLE B EV USB Disable DMJJSISO part. CTL Received through the cmd terminal. ATA DMJJSISO can reuse the buffer. CMEVT_A_COMLETED must be set. Received through the dat terminal. EV REQ IRP BJΞVJ RP Notify that the I/O request is completed. CMEVT_A_COMPLETED must be set. Received through the irp terminal. Outgoing Event Bus Notes EV STM DATA void Contains data received through the USB pipe, reception status and USB frame number on which data was received. CMEVT_A_ASYNC_CPLT is always set. Sent out of the dat terminal. EV REQJRP B EVJRP Sends out a USB request. Sent out of the irp terminal. Special events, frames, commands or verbs DMJJSISO sends out USBDI requests as IRPs. The Major IRP function used in the request is IRP_MJJNTERNAL_DEVICE_CONTROL. I/O control code is IOCTLJNTERNAL_USB_SUBMIT_URB. A pointer to the URB is send as part of the next stack location (Parameters. Others. Argumentl ). DMJJSISO sends out only three types of USBDI requests: - URB_FUNCTION_GET_CURRENT_FRAME_NUMBER - used for obtaining the current frame number. - URB_FUNCTION_ABORT_PIPE - cancel all outstanding URB requests for a specified pipe - URB_FUNCTIONJSOCH_TRANSFER - used for getting framed data from the USB device Status translation table This status translation table is used only in the scope of DMJJSISO component. USB status DriverMagic™ status USBD STATUS SUCCESS CMST OK USBD_STATUS_PENDING CMST_UNEXPECTE D USBD STATUSJHALTED CMST UNEXPECTE D USBD_STATUS_ERROR CMSTJOERR USBD STATUS CRC CMST_BAD_CHKSU M USBD_STATUS_BTSTUFF CMSTJOERR USBD_STATUS_DATA_TOGGLE_MI CMSTJOERR SMATCH USBD_STATUS_STALL_PID CMSTJJNEXPECTE D USBD_STATUS_DEV_NOT_RESPON CMST_TIMEOUT DING USBD_STATUS_PID_CHECK_FAILU CMSTJOERR RE USBD_STATUS_UNEXPECTED_PID CMSTJOERR USBD_STATUS_DATA_OVERRUN CMST OVERFLOW USBD_STATUS_DATA_UNDERRUN CMST JNDERFLOW USBD STATUS RESERVED 1 CMST UNEXPECTE D USBD_STATUS_RESERVED2 CMSTJJNEXPECTE D USBD_STATUS_BUFFER_OVERRUN CMST_OVERFLOW USBD_STATUS_BUFFER_UNDERRU CMST_UNDERFLOW N USBD_STATUS_NOT_ACCESSED CMST_NO_ACTION USBD_STATUS_FIFO CMSTJJNEXPECTE D USBD_STATUS_ENDPOINT_HALTE CMSTJJNEXPECTE D D USBD_STATUSJMO_MEMORY CMST_ALLOC USBD_STATUSJNVALID_URB_FUN CMST NOT SUPPO CTION RTED USBD_STATUSJNVALID_PARAME CMSTJNVALID TER USBD_STATUS_ERROR_BUSY CMST BUSY USBD_STATUS_REQUEST_FAILED CMST_FAILED USBD STATUSJNVALID PIPE HAD CMSTJNVALID LE USBD_STATUS_NO_BANDWIDTH CMST UNEXPECTE D USBD STATUS JNTERNALJHC ERR CMSTJOERR OR USBD_STATUS_ERROR_SHORT_TR CMST_UNDERFLOW ANSFER USBD_STATUS_BAD_START_FRA CMSTJNVALID ME USBD STATDMJJSISOCH REQUES CMST_FAILED T_FAILED USBD_STATUS_FRAME_CONTROL_ CMST ACCESSJDE OWNED NIED USBD_STATUS_FRAME_CONTROL_ CMST_ACCESS_DE NOT_OWNED NIED USBD_STATUS_CANCELED CMST CANCELED USBD STATUS CANCELING CMST_CLEANUP USBD_STATUS_SUCCESS is treated as no error. All errors for which USBD_HALTED(s) returns TRUE are treated as data errors. All other errors and USBD_STATUS_BAD_START_FRAME are treated as valcheck errors. Valcheck error indicate fatal condition, which can be recovered only by disabling and re-enabling DMJJSISO. Property "endpt_addr" of type "UINT32" . Note: Endpoint address (1 -255). This property is mandatory. Property "n_bufs" of type "UINT32". Note: Number of buffers to keep for this pipe. Default value is 30. Property "bufs_per_req" of type "UINT32" . Note: Number of buffers per USBDI request. ( 1 -255) Default value is 10. Property "buf_sz" of type " UINT32". Note: Specifies buffer size to be used with data transfer, in bytes. Must be at least as large as the max pkt_sz. This property is mandatory. Property "short_xfer_ok" of type "UINT32" . Note: TRUE if is allowed to DMJJSISO to receive data packet with shorter size than configured in the pipe. Affects only EV_STM_DATA status report. The default value is TRUE. Property "asap_offset" of type "UINT32" . Note: The offset in frames, relative to the current frame from which to start submitting USB requests. The default value is 3. Property "usbd_dev_objp" of type "UINT32" . Note: Pointer to the device object of the driver to which to send USB requests. Mandatory. Property "max_xfer_sz" of type "UINT32". Note: The maximum URB request size. Must be at least as big as total size of the EV_STM_DATA events in the request. It is calculated at activation. This property is read-only. Property "force ree" of type "UINT32". Note: Set to TRUE to free self-owned events without regard of what the returned status is. This is used for backward compatibility with older parts. The default value is FALSE. Property "pipe i" of type "UINT32" . Note: Pipe Handle. Takes effect the next time UJSO is enabled. This property is active-time. The default value is 0. Property "pkt_sz" of type "UINT32" . Note: Data packet size. Must match the configured packet size for the pipe specified by pipe h. Must be less than buf_sz (otherwise 'enable' will fail). This property is active-time. The default value is 0. Property "pipe ype" of type "UINT32". Note: Pipe type (UsbdPipeTypexxx). Pipe type is validated at the next "enable" operation. This property is active-time. The default value is -1 . DMJJSISO relies on following services from the WDM kernel mode support routines: lolnitializelrp - initializes the IRP allocated by the DMJJSISO loGetCurrentlrpStackLocation - returns a pointer to the caller's stack location in the given IRP loSetNextlrpStackLocation -sets the IRP stack location in a driver-allocated IRP to that of the caller loGetNextlrpStackLocation - gives access to the next driver's I/O stack location in an IRP so the caller can set it up for the next driver Specification Responsibilities Keep a copy of all active time properties while DMJJSISO is enabled. Update the copy every time when DMJJSISO is enabled. Manage a pool of buffers to be submitted to the USBDI driver with EV REQJRP events. When receive EV_REQJRP completions on the irp terminal, submit the data received out through dat terminal with EV_STM_DATA events. When receive EV_STM_DATA completion events on dat terminal, submit a USB request through irp terminal as with EV_REQJRP events. Keep track of the EV REQ IRP events pending on irp and EV_STM_DATA events pending on dat. Cancel all EV_REQJRP events on disable. Complete disable request when all IRP and data responses are collected back. Theory of operation State machine Type: (state, event) - (action) Fig. 45 illustrates the state machine of the DMJJSISO part State Machine states State name Notes DISABLED Start/End state of the state machine. GETTING FRMNO Waiting for 'get current frame number' response. ENABLING The DMJJSISO is in the process of enabling. ENABLED Main working state. In this state DMJJSISO generates EV_REQ IRP and EV_STM_DATA events through its irp and dat terminals respectively. DISABLING The DMJJSISO is in the process of disabling. ERROR Error state. DMJJSISO does not generate outgoing events. State Machine events Event name Notes ENABLE ASAP Enable generation of the EV_STM_DATA events starting from the 'current frame' + asap_offset. ENABLE ON FRAM Enable generation of the EVJ3TM DATA events starting from the specified frame number. The starting frame number must be within a system-defined range from the current USBDI frame number. DISABLE Disable DMJJSISO ENABLE FAILED (internal) The enable procedure failed. ENABLE_CPLT (internal) Indicates successful end of enable procedure. ALL_REQ_CPLT (internal) There are no more pending EV_REQJRP or EV_STM_DATA events. IRP CPLT OK Received when EV REQJRP completes without valcheck error. IRP_CPLT_ERR Received when EV_REQJRP completes with valceck error. DAT_CPLT Received when EV_STM_DATA completes. Main data structures RQ BLOCK structure Used to keep track of all structures associated with the request. A pointer to it is placed in the top-level stack location of the IRP associated with it. Fig. 46 illustrates the RQ_BLOCK structure The solid arrows represent the direct connection between the REQ HEADER and associated structures. Note that there is only one connection between the header and EV_STM DATA array. the REQ HEADER. The 'strip -dot' arrow represents the connection between the IRP request and the URB. REQUEST QUEUE DMJJSISO keeps an internal queue with pointers to the requests not submitted to the dat or irp terminal. It is used in 'enabling' when all request pointers are obtained from the queue and requests are submitted to the USBDI driver. In case of error or while DMJJSISO is disabled, a pointer to the completed requests are stored back in the queue. Mechanisms Allocating & de-allocating request blocks At activation time DMJJSISO allocates a buffer pool of n_bufs request blocks. It initializes all structures of this block. If at deactivation there are no any outstanding (pending) requests, this buffer pool is freed, otherwise it is not freed. Notes 1 . The EV_REQJRP submitted through irp terminal is expected not to return OK nor send completion with CMSTJDK status nested in the call. This could cause recursion. 2. In the event URB completes with error other than a data error, DMJJSISO issues only one EV_STM_DATA event with completion status CMSTJFAILED and length of the data equal to zero. It enters ERROR state with no more EV_STM_DATA events generated. In order to restore the proper working state DMJJSISO must be 'disabled' and 'enabled' again. 3. Whenever URB completes with data error, DMJJSISO passes the error as data status with EV_STM_DATA event and continues normal operation. If at deactivation there are any outstanding (pending) requests, the buffer pool is not freed. The caller must ensure that the deactivation request will come only after successfully completed 'disable' request. Appendix 1 - Interfaces This appendix describes preferred definition of interfaces used by parts described herein. I DRAIN - Event Drain Overview The Event Drain interface is used for event transportation and channeling. The events are carried with event ID, size, attributes and any event-specific data. Implementers of this interface usually need to perform a dispatch on the event ID (if they care). Events are the most flexible way of communication between parts; their usage is highly justified in many cases, especially in weak interactions. Examples of usage include notification distribution, remote execution of services, etc. Events can be classified in three groups: requests, notifications and general-purpose events. The events sent through this interface can be distributed synchronously or asynchronously. This is indicated by two bits in the attr member of the bus. Additional attributes specified within the same member indicate whether the data is constant (that is, no recipient is supposed to modify the contents), or whether the ownership of the memory is transferred with the event (self-ownership). For detailed description of all attributes, see the next section. There are two categories of parts that implement IJDRAIN: transporters and consumers. Transporters are parts that deliver events for other parts, without interpreting any data except id and, possibly, sz. They may duplicate the event, desynchronize it, marshal it, etc. In contrast, consumers expect specific events, process them by taking appropriate actions and using any event-specific data that arrives with the event. In this case the event is effectively "consumed". If the event is self-owned, consumers need to release it after they are done processing. This is necessary, as there will be no other recipient that will receive the same event instance after the consumer. Transporters do not need to do that, they generally pass events through to other parts. Eventually, all events reach consumers and get released. Implementations that are mixtures between transporters and consumers need to take about proper resource handling whenever the event is consumed. to a CMEvent-derived class. List of Operations Name Description raise Raise an event, such as request, notification, etc. Attribute Definitions Name Description CMEVT_A_NONE No attributes specified. CMEVT_A_AUTO Leave it to the implementation to determine the best attributes. CMEVT_A_CONST Data in the event bus is constant. CMEVT A SYNC Event can be distributed synchronously. CMEVT A ASYNC Event can be distributed asynchronously. All events that are asynchronous must have self-owned event buses. See the description of the CMEVT_A_SELF_OWNED attribute below. CMEVT_A_SYNC_AN Event can be distributed either synchronously or Y asynchronously. This is a convenience attribute that combines CMEVT_A_SYNC and CMEVT_A_ASYNC. If no synchronicity is specified, it is assumed the event is both synchronous and asynchronous. CMEVT_A_SELF_OW Event bus was allocated from heap. Recipient of events with NED this attribute set are supposed to free the event. CMEVT_A_SELF_CO Data in the bus structure is self contained. The event bus NTAINED contains no external references. CMEVT A DFLT Default attributes for an event bus (CMEVT A CONST and CMEVT A SYNC). Bus Definition II event header typedef struct CMEVENTJHDR { uint32 sz; // size of the event data Jd id; // event id flg32 attr; // event attributes } CMEVENT HDR; Note Use the EVENT and/or EVENTX macro to conveniently define event structures. raise Description: Raise an event (such as request, notification, etc.) In: sz Size of event bus, incl. event-specific data, in bytes id Event ID attr Event attributes [CMEVT_A_XXX] (any other) Depends on id Out: void Return Varies with the event Status: Example: /* define my event */ EVENTX (MY_EVENT, MY VENTJD, CMEVT_A_ AUTO, CMEVT JJNGUARDED) dword my_event_data; END_EVENTX MY_EVENT *eventp; cmstat status; /* create a new event */ status = evt_alloc (MY_EVENT, δieventp); if (status ! = CMST JDK) . . . /* set event data */ eventp- > my_event_data = 1 28; /* raise event through IJDRAIN output */ out (drain, raise, eventp); Remarks: The IJDRAIN interface is used to send events, requests or notifications. It only has one operation called raise. An event is generated by initializing an event bus and invoking the raise operation. The event bus describes the event. The minimum information needed is the size of the bus, event ID, and event attributes. The binary structure of the event bus may be extended to include event-specific information. Extending the event bus structure is done by using the EVENT and EVENTX macros. Parts that don't recognize the ID of a given event should interpret only the common header: the members of CMEVENT_HDR. The event attributes are divided into two categories: generic and event- specific. The first 1 6 bits (low word) of the attribute bit area is reserved for event-specific attributes. The last 1 6 bits (high word) of the attribute bit area is reserved for generic attributes. These are defined by CMAGIC.H (CMEVT_A_XXX). The generic attributes include the synchronicity of the event, whether the event data is constant, and if the event bus is self-owned or self-contained. If the event bus is self-owned, this means that it was allocated by the generator of the event and it is the responsibility of the recipient to free it (if the event is consumed). If the event is self-contained, this means the event bus contains no external references. For the event to be distributed asynchronously, the event bus must be self-owned and self-contained. See also: EVENT, EVENTX I ITEM - Single Data Item Access Overview This interface is dedicated to a single item access based on a data path - a string that uniquely identifies the piece of data that is being accessed. This data can be stored in any type of container; how the data is stored is unimportant for the interface. The set of operations is pretty basic: set, get and remove. The only detail that deserves attention is the fact that there is no need to "add" the data. This is implied by the set operation. If the container does not have data under given data path, this data will get there when set operation (with that path) is executed successfully. In contrast, if the container already had data under the path, the existing data will get replaced. There is no explicit type information supported by the interface. However, for each piece of data, there is a double word that is associated with that data. Implementations that need type information can use this context for indication of the data type. Typical implementation of this interface is by a container part that allows addressing the data by a string name. The syntax of that string is not defined by the interface. List of Operations Name Description get Get an item specified by data path set Set an item specified by data path remove Remove an item specified by data path Bus Definition BUS (BJTEM) dword qry idl; // query handle char *pathp; // data path void *stgp; // pointer to storage uint32 valjen; // length of value in storage uint32 stg_sz; // size of storage dword ctx; // external data item context dword attr; // attributes END BUS Notes There are no attributes defined for this interface. The member attr in the BJTEM bus is reserved and must be set to zero. get Description: Get an item specified by data path In: qryjidl Handle to query or 0 to use absolute path pathp Data path (zero-terminated) If qryjidl ! = 0 then the data path starts from the current query position. If qryjidl = = 0 then data path starts from the root. stgp Pointer to buffer for data or NULL to get only the size of the item stg_sz Size of buffer pointed to by stgp attr Reserved, must be zero Out: (*stgp) Data for specified data path (if stgp ! = NULL) valjen data size (even if stgp = = NULL) ctx data context (even if stgp = = NULL) Return CMST OK The operation was successful. Status: CMST_BAD_SY The data path is invalid. NTAX CMSTJNVALID The query handle is invalid. CMSTJMOT O No data found at specified data path or the path was UND not found. CMST OVERFLO Storage buffer too small W Example: BJTEM itembus; char buffer [256]; cmstat status; /* initialize item bus */ itembus. qryjidl = 0; itembus.pathp = "customer[0].name"; itembus.stgp = buffer; itembus.stg_sz = sizeof (buffer); itembus.attr = 0; /* get item data for 'customer[0].name' */ status = out (item, get, &itembus); if (status I = CMSTJDK) return; /* print customers name */ printf ("The first customers name is %s\n", buffer); See Also: DM_REP, l_QUERY, EV_REP_NFY_DATA_CHANGE set Description: Set an item specified by data path In: qryjidl Handle to query or 0 to use absolute path pathp Data path (ASCIIZ zero-terminated) If qryjidl ! = 0 then data path starts from the current query position. If qryjidl = = 0 then data path starts from the root, stgp Pointer to buffer with data or NULL for no data valjen Length of data ctx Data context attr Reserved, must be zero Out: void Return CMST OK The operation was successful Status: CMSTJNVALI The query handle is invalid. D CMST_BAD_S The data path is improperly formed. YNTAX CMST NO RO Too many names and/or too many entries OM Example: BJTEM itembus; char buffer [256]; cmstat status /* initialize buffer with first customers name */ strcpy (buffer, "John Stewart"); /* initialize item bus */ itembus. qryjidl = 0; itembus. pathp = "customer[0].name"; itembus. stgp = buffer; itembus. valjen = strlen (buffer) + 1 ; // include \0 itembus. ctx = MY_STRING_TYPE; // used as type itembus. attr = 0; /* set item data for 'customer[0].name' */ status = out (item, set, δiitembus); Remarks: If an item is set by using the set operation and the data path specified does not exist, it will be created. It is possible and valid to have a data path with item size 0. In this case the context value is still present. To delete an item, use the remove operation. Sα feo: DM REP, IJDUERY, EV_REP_NFY_DATA_CHANGE remove Description: Remove an item specified by data path In: qryjidl Handle to query or 0 pathp Data path (ASCIIZ zero-terminated) If qryjidl ! = 0 then data path starts from the current query position. If qry dl = = 0 then data path starts from the root. attr Reserved, must be zero Out: void Return CMST JDK The operation was successful Status: CMSTJNVALID The query handle is invalid. CMST_BAD_SY The specified path is invalid or improperly specified. NTAX CMSTJMOT FO No data found at specified path UND Example: BJTEM itembus; cmstat status; /* initialize item bus */ itembus. qryjdl = 0; itembus. pathp = "customer[0].name"; itembus. attr = 0; /* remove path 'customer[0].name' */ status = out (item, remove, Siitembus); See Also: DM REP, I QUERY, EV REP NFY DATA CHANGE I LIST - Data List Access Overview I LIST interface is devised to maintain lists. A list in this context is a collection of data objects with a notion of "previous" and "next" given an object. For all elements of the list this notion defines which element is preceding the current and which element is next. Naturally, the first and the last elements do not have previous and next, respectively. A 0-terminated string uniquely identifies each list element. The implementer defines the syntax of this string. The basic set of operations defined in this interface allows to simply add or remove elements from the list or to insert element at a particular position in the list. This position is identified by a reference element and the interface allows insertion before/after the reference or at beginning/ end of the list. The interface supports both dynamic and static lists, thus allowing implementers to choose their best complexity/performance trade-off level. One typical implementation of a list is an array. In this case is important to understand that recycling of deleted elements is almost always necessary for reasonable behavior. This is a typical scenario in static list implementations. For dynamic lists, the best-suited implementation model is dynamically allocated array with pointers to previous and next in the list elements (a double-linked list). More sophisticated implementers may choose to carry pointers to last element and/or "recycle list" - a list of deleted array elements. The examples below assume hierarchical data implementation but this is only for illustration purposes. The nature of data is not defined by the interface. List of Operations Name Description add Add a new element to a list remove Remove an element from a list Bus Definition BUS (B LIST) dword qryjidl; // query handle char *pathp; // data path char *bufp; // pointer to storage sizej buf_sz; // size of storage dword attr; // attributes END BUS Notes When adding a new element to the list, the implementation of I LIST should choose the next index for the data path which will be the next available sequential index in the array. The data path is constructed and returned to the caller for later reference. It is possible for a data path array to have missing elements (e.g., deleted entries). The maximum number of elements in an array is determined by the implementer of IJIST. add Description: Add a new element to a list In: qryjidl Handle to query or 0 to use absolute path pathp Subpath of list to add to. If qryjidl = = 0 then pathp starts from the root and ends before the index (e.g., company[1 ]. phone if you want to add a new phone entry under company[1 ]). If qryjidl I = 0 then pathp starts from the current query position. bufp Pointer to buffer for new path of element or NULL buf_sz Size of the buffer pointed to by bufp attr Reserved, must be zero Out: (*bufp) New path for list element (e.g., company[1 ].phone[3]) Return CMST_OK The operation was successful Status: CMSTJNVALI The query handle is invalid. D CMSTJ3AD S The data path is improperly formed. YNTAX CMST_NO_RO Too many entries, names or list elements OM CMSTJDVERFL Too many levels in the path OW Example: BJ-IST listbus; char path [256]; cmstat status; /* initialize list bus */ listbus. qry hdl = 0; listbus. pathp = "customer"; listbus. bufp = path; listbus. buf_sz = sizeof (path); listbus. attr = 0; /* add new element to customer list */ status = out (list, add, &listbus); if (status ! = CMSTJDK) return; /* print new element */ printf ("New list element added is %s\n", path); Remarks Add operates on a single data path which is either explicitly provided or is the current data path of a query. To operate on the current data path of a query, a query handle needs to be supplied. See the I QUERY interface for more information about queries. See Also: DM REP, I QUERY, EV REP NFY DATA CHANGE remove Description: Remove an element from a list In: qryjidl Handle to query or 0 pathp Subpath of element root to remove (e.g., company [1 ].forms[4]) Out: void Return CMST OK The operation was successful Status: CMSTJNVALI The query handle is invalid. D CMST_BAD_S The data path is improperly formed. YNTAX CMST_NOT_F No such list element (this status will be returned if and OUND only if there is no such element; CMSTJDK will be returned if the element existed, even if there were no data below it). Example: BJIST listbus; cmstat status; /* initialize list bus */ listbus. qry dl = 0; listbus. pathp = "customerfO]"; /* remove first element from customer list */ status = out (list, remove, &listbus); Remarks: Remove operates on a single data path or the current data path of a query. To operate on the current data path of a query, a query handle needs to be supplied. See the l_QUERY interface for more information about queries. In hierarchical data spaces, when this operation succeeds, it is expected that the whole subtree of the specified path was removed, too. See Also: DM_REP, IJDUERY, EV_REP_NFY_DATA_CHANGE I QUERY - Data Queries Overview The I QUERY interface is designed for performing queries among string elements. A query string is specified when opening a query; matching items can be enumerated. This interface does not define the query string syntax, nor the possible syntax of the items themselves; this is left to the part that implements the interface. A few examples are: query is a SQL string, items are comma-separated values matching the query; query is a file path with wildcards, items are file names that match the wildcard. When a query is opened, the open operation returns two values: a query handle and an enumeration context. The handle should be provided on all subsequent operations, including close. The enumeration context is slightly different; again, it should be provided to all operations. The difference is that the enumeration operations can modify the context value; the next time an operation is called, the caller must provide the new value. This mechanism allows for two principally different implementations of the interface; provided that callers comply with the interface specification, they don't need to know which mechanism is implemented. The first mechanism, identifying the query by handle, is used when the implementation can and needs to keep state of the query; on each operation, the handle identifies the query among the currently opened queries. The second mechanism, via enumeration context that is modified by each enumeration operation is used by simple implementations. For example, the context may be the index of last item retrieved; this way, when asked for the next item, the implementation just needs to return the item at the next index. Note that each operation leaves the context in the interface bus, so callers don't have to take special actions to pass the context on every operation. List of Operations Name Description open Open a query close Close a query get irst Find first match get_next Find next match get_prev Find previous match getjast Find last match get_curr Get current match Bus Definition BUS (B_QUERY) char *stgp; // storage buffer size stg_sz; // storage buffer size dword qryjidl; // query handle dword attr; // query attributes dword qry_ctx; // query context END BUS Notes Every open query has a query context represented and accessed by a query handle. This context may just be the position in the enumeration or may contain other implementation specific data. Implementations may support different numbers of simultaneously open queries. This number ranges from 1 to unlimited. open Description: Open a new query In: stgp Query syntax string The syntax of the query is not defined by this interface; it is defined by the implementation. attr Attributes, must be 0 The enumeration criteria is not defined by this interface; it's defined by the implementation. Out: qryjidl Query handle Return CMST OK The operation was successful Status: CMST BAD SYN Invalid query syntax TAX CMST NO ROO Too many open queries M Example: BJDUERY qrybus; cmstat status; /* initialize query bus */ qrybus. stgp = "* "; // enumerate everything qrybus. attr = 0; /* open query */ status = out (query, open, &qrybus); if (status ! = CMST OK) return; /* execute other query operations. . . */ See Also: DM REP close Description: Close a query In: qryjidl Query handle returned from a previous call to open attr Reserved, must be zero Out: qryjidl 0 Return none Status: Example B_QUERY qrybus; cmstat status; /* initialize query bus-*/ qrybus. stgp = "* "; // enumerate everything qrybus. attr = 0; /* open query */ status = out (query, open, &qrybus); if (status I = CMSTJDK) return; /* execute other query operations. . . */ /* close query */ out (query, close, &qrybus); See Also: DM REP get first Description: Find the first match in the given query In: qryjidl Query handle returned from a previous call to open stgp Pointer to buffer for the match found or NULL stg_sz Size of the buffer pointed to by stgp attr Reserved, must be zero Out: (*stgp) Result (if stgp ! = NULL), in ASCIIZ form qry_ctx Query context Return CMST OK The operation was successful. Status: CMSTJNVALID The query handle is invalid. CMSTJDVERFLO Buffer is too small to hold match, (if stgp ! = NULL) W CMSTJMOT FO No match was found. UND Example: B_QUERY qrybus; char buffer [256]; cmstat status; /* initialize query bus */ qrybus. stgp = "*"; // enumerate everything qrybus. attr = 0; /* open query */ status = out (query, open, &qrybus); if (status I = CMSTJDK) return; /* get first match */ qrybus. stgp = buffer; qrybus. stg sz = sizeof (buffer); status = out (query, get irst, δiqrybus); iffstatus = = CMSTJDK) /* print match (assuming match syntax is a string) */ printf ("The first match of the query is %s\n", buffer); /* close query */ out (query, close, δiqrybus); See Also: DM REP get next Description: Find the next match in the given query In: qry dl Query handle returned from a previous call to open stgp Pointer to buffer for the match found or NULL stg_sz Size of the buffer pointed to by stgp qry ctx Query context returned from a previous call to get_xxx attr Reserved, must be zero Out: (*stgp) Result (if stgp ! = NULL) qry ctx Query context Return Status: CMSTJDK The operation was successful. CMST JNVALI The query handle is invalid. D CMSTJDVERF The buffer is too small to hold the match, (if stgp ! = LOW NULL) CMST_NOT_F No match found OUND Example: BJDUERY qrybus; char buffer [256]; cmstat status; /* initialize query bus */ qrybus. stgp = "* "; // enumerate everything qrybus. attr = 0; /* open query */ status = out (query, open, &qrybus); if (status ! = CMSTJDK) return; /* initialize bus get first match */ qrybus. stgp = buffer; qrybus. stg_sz = sizeof (buffer); /* enumerate matching entries */ for (status = out (query, get irst, δiqrybus); status = = CMSTJDK; status = out (query, get_next, δiqrybus)) { /* print matching entries */ printf ("The next match is %s\n", buffer); } if (status ! = CMSTJMOTJOUND) /* print error. . . */ /* close query */ out (query, close, δiqrybus); See Also: DM REP get prev Description: Find the previous match in the given query In: qryjidl Query handle returned from a previous call to open stgp Pointer to buffer for the match found or NULL stg_sz Size of the buffer pointed to by stgp qry_ctx Query context returned from a previous call to get xxx attr Reserved, must be zero Out: (*stgp) Result (if stgp ! = NULL) qry_ctx Query context Return Status: CMSTJDK The operation was successful CMSTJNVALI The query handle is invalid. D CMSTJDVERF The buffer is too small to hold the match, (if stgp ! = LOW NULL) CMST_NOT_F No match found OUND Example: See get_next example See Also: DMJ-EP get last Description: FFiinndd tthhee last match in the given query In: qryjidl Query handle returned from a previous call to open stgp Pointer to buffer for the match found or NULL stg sz Size of the buffer pointed to by stgp attr Reserved, must be zero Out: (*stgp) Result (if stgp ! = NULL) qry_ctx Query context Return Status: CCMMSSTTJ 0DK The operation was successful CMSTJNVALI The query handle is invalid. D CMSTJDVERF The buffer is too small to hold the match, (if stgp h LOW NULL) CMST NOT F No match found OUND Example: See get irst example See Also DM REP get_curr Description: Get curren In: qryjidl Query handle returned from a previous call to open stgp Pointer to buffer for the match found or NULL stg_sz Size of the buffer pointed to by stgp qry_ctx Query context returned from a previous call to get_xxx attr Reserved, must be zero Out: (*stgp) Result (if stgp ! = NULL) qry ctx Query context Return CMST OK The operation was successful Status: CMSTJNVALID The query handle is invalid. CMSTJDVERFLOW The buffer is too small to hold the match, (if stgp NULL) CMSTJ OTJOUN No match found D Example: B QUERY qrybus; char buffer [256]; cmstat status; /* initialize query bus */ qrybus. stgp = "*"; // enumerate everything qrybus. attr = 0; /* open query */ status = out (query, open, δiqrybus); if (status ! = CMST OK) return; /* get first match */ qrybus. stgp = buffer; qrybus. stg_sz = sizeof (buffer); status = out (query, get irst, δiqrybus); if (status ! = CMSTJDK) { /* close query */ out (query, close, δiqrybus); return; } /* get current match */ status = out (query, get_curr, δiqrybus); if (status = = CMSTJDK) /* print current match */ printf ("The current match is %s\n", buffer); /* close query */ out (query, close, δiqrybus); See Also: DM_REP I DPATH - Hierarchical Data Path Arithmetic Overview The IJDPATH interface is designed for manipulation of data paths. A data path is a string, with a specific syntax, that identifies a data item in some type of data storage. The syntax of data paths manipulated by this interface is virtually identical to the syntax of accessing data structures in most high level programming languages, including C and C + + . Here are a few examples of data path manipulated by this interface: customer[1 ].name Sensor. Value matrix[1 ][2][3] This interface provides for parsing and constructing data paths. The smallest unit of the path we call pel, or path element. This interface defines the following types of path elements: • names (e.g., Sensor) • indices (e.g., [3]) • single pel wildcard (e.g., ? or [?]) • wildcard for any number of pels (e.g., *) List of Operations Name Description join Construct a path from up to three elements, inserting the appropriate delimiters split Split a path at the specified level in up to three parts split2 Split a path at the specified level in up to two parts getjnfo Parse the path and count the number of levels Pel Type Definition Name Description IJDPATH PELTYPE NON No pel specified E IJDPATH PELTYPE NA Name pel (ASCII string) ME l_DPATH_PELTYPEJNDE Index pel X l_DPATH_PELTYPE_WIL Wildcard for one pel D J l_DPATH_PELTYPE_WIL Wildcard for any number of pels D_ANY Bus Definition BUS (BJDPATH) char *pathp; // full path size path_sz; // size of buffer for full path, [bytes] char *pre_pathp; // path prefix (up to δι excluding the // pel) size pre_path_sz; // size of buffer for prefix, [bytes] uint peljype; // path element (pel) uint32 pel_val; // value of index pel (when // PELTYPEJNDEX) char *pelp; // pel in string form (any type) sizej pel_sz; // size of pel string buffer, [bytes] char *post_pathp; // suffix (after the pel) sizej post_path_sz; // size of buffer for suffix, [bytes] dword attr; // attributes (none defined) int level; // level to split at // ( < 0: count backwards) uint num levels; // number of levels in the full path END BUS Notes The data paths are strings of up to 256 characters, which are constructed using identifiers and array indices. Both identifiers and indices are referred to as "pels" - short for " ath element". The data path syntax is very similar to the syntax for specifying data structures in programming languages like C. Here are a few examples of typical data paths: customer[1 ].name Sensor. Value matrix[1 ][2][3] join Description: Construct a path of up to three elements (prefix + pel + suffix), inserting the appropriate delimiters (path punctuation) In: Pathp Buffer for resulting path or NULL Path_sz Size of buffer pointed to by pathp in bytes Pre pathp Path prefix or NULL for none Peljype Type of pel to insert [I_DPATH_PELTYPE_XXX] Pelp Pel name to insert between the prefix and suffix This argument is supplied only when peljype = = l_DPATH_PELTYPE_NAME. Any type of single-level pel can be provided in pelp: wildcard, name, or [index] (index must have the brackets, otherwise it is interpreted as a name). Pel val Pel value to insert between the prefix and suffix This argument is supplied only when peljype = = IJDPATH PELTYPEJNDEX. Post pathp Path suffix or NULL for none Attr Reserved, must be zero Out: (*pathp) Resulting path (if pathp ! = NULL) Numjevels Number of levels in resulting path Return CMST_OK The operation was successful Status: CMST_BAD_SY Incorrect path syntax in one or more elements NTAX CMST_OUT_OF_ Invalid pel index value (for RANGE I DPATH PELTYPE INDEX only) CMST_BAD_VAL Resulting path is not a valid path (e.g., too UE long) Example: BJDPATH dpathbus; Char path [256]; Cmstat status; /* initialize bus to join: customer[1 ].name */ dpathbus. pathp = path; dpathbus. path sz = sizeof (path); dpathbus. pre pathp = "customer"; dpathbus. pel ype = l_DPATH_PELTYPEJNDEX; dpathbus. pel_val = 1 ; dpathbus. post_pathp = "name"; dpathbus. attr = 0; /* join path elements */ status = out (dpath, join, δidpathbus); if (status = = CMSTJDK) /* print result (customer[1 ].name) */ printf ("The resulting path is %s\n", path); Remarks: All elements (pre_pathp, pelp, and post pathp) are optional. The path is to be assembled in a local buffer before being copied into *pathp; therefore in and out buffers can overlap, e.g., pathp can be the same as pre_pathp. See Also: DM REP split Description: Divide a path at the specified level in up to three parts In: Pathp Path to split Refer to the notes section act the beginning of this interface for a further description of the syntax of paths and pels. Pre_pathp Buffer for path prefix or NULL, may overlap pathp pre_path_sz Size of prefix buffer in bytes Pelp Buffer for pel name or NULL, may overlap pathp pel_sz Size of pel name buffer in bytes post_pathp Buffer for path suffix or NULL, may overlap pathp post path sz Size of suffix buffer in bytes level Level at which to split When level is negative, the split position is counted from the end of the path. If the path has n levels, the valid values for level are [-n..n-1 ]. If level < 0, level becomes n-level. attr Reserved, must be zero Out: (*pre_pathp) Path prefix (if pre pathp ! = NULL ), may be an empty string pel ype Type of pel [l_DPATH_PEL_TYPE_XXX] Refer to the notes section act the beginning of this interface for a further description of the syntax of paths and pels. (*pelp) Pel name or value (if pelp ! = NULL) pel val Pel value (0 if pel ype ! = l_DPATH_PELTYPEJNDEX) (*post_pathp) Path suffix (if post_pathp I = NULL) , may be an empty string level Level at which path was split, ( > = 0) Return CMST OK The operation was successful. Status: CMST_BAD_S Incorrect path syntax. YNTAX CMST_BAD_V The source path has less than level levels. ALUE Example: B DPATH dpathbus; char prepath [256]; char postpath [256]; char pel [256]; cmstat status; /* initialize bus to split: customer[1 ].name */ dpathbus. pathp = "customer[1 ].name"; dpathbus. pre_pathp = prepath; dpathbus. pre_path_sz = sizeof (prepath); dpathbus. pelp = pel; dpathbus. pel sz = sizeof (pel); dpathbus. post pathp = postpath; dpathbus. post_path_sz = sizeof (postpath); dpathbus. level = 1 ; dpathbus. attr = 0; /* split path */ status = out (dpath, split, δidpathbus); if (status = = CMSTJDK) { /* print results */ printf ("path prefix = %s\n", prepath); // 'customer' printf ("path pel = %s\n", pel); // '[1]' printf ("path suffix = %s\n", postpath); // 'name' } Remarks: pelp will contain the path element at the position specified by level. pre_pathp will contain any part of the path before this position, and post_pathp will contain any part after this position. See Also: DM REP split2 Description: Divide a path at the specified level into two parts In: pathp Path to split Refer to the notes section act the beginning of this interface for a further description of the syntax of paths and pels. pre_pathp Buffer for path prefix or NULL, may overlap pathp pre_path_sz Size of prefix buffer in bytes post pathp Buffer for path suffix or NULL, may overlap pathp post_path_sz Size of suffix buffer in bytes level Level at which to split When level is negative, the split position is counted from the end of the path. If the path has n levels, the valid values for level are [~n..n-1 ]. If level < 0, level becomes n-level. attr Reserved, must be zero Out: (*pre_pathp) Path prefix (if pre_pathp ! = NULL ), may be an empty string (*post_pathp) Path suffix (if post_pathp ! = NULL) , may be an empty string level Level at which path was split, ( > = 0) Return CMST OK The operation was successful Status: CMST BAD S Incorrect path syntax in source path. YNTAX CMST_BADJ/ Source path has less than level levels ALUE Example: BJDPATH dpathbus; char prepath [256]; char postpath [256]; cmstat status; /* initialize bus to split: 'customer[1 ].name' */ dpathbus. pathp = "customer[1 ].name"; dpathbus. pre_pathp = prepath; dpathbus. pre_path_sz = sizeof (prepath); dpathbus. post_pathp = postpath; dpathbus. post_path_sz = sizeof (postpath); dpathbus. level = 2; dpathbus. attr = 0; /* split path */ status = out (dpath, split2, δidpathbus); if (status = = CMSTJDK) { /* print results */ printf ("path prefix = %s\n", prepath); // 'customer[1 ]' printf ("path suffix = %s\n", postpath); // 'name' } See Also: DM REP get info Description: Parse the path and count the number of levels the path contains In: pathp Path to check or NULL Refer to the notes section at the beginning of this interface for a further description of the syntax of paths and pels. attr Reserved, must be zero Out: numjevels Number of levels in the path, if pathp = = NULL 0 is returned Return CMSTJDK The operation was successful Status: CMST_BAD_S Incorrect path syntax YNTAX Example: B DPATH dpathbus; cmstat status; /* initialize bus */ dpathbus. pathp = "customer[0].name"; dpathbus. attr = 0; /* get information on path */ status = out (dpath, getjnfo, δidpathbus); if (status = = CMSTJDK) { /* print results */ printf ("Path has %u levels. \n", dpathbus. numjevels); // displays 3 } See Also: DM REP . SERIAL - Data Serialization Overview The l_SERIAL interface provides for performing transfers between a primary data store and a secondary data store. For example, it can be used to serialize and deserialize the state of a given object to file. The definition of the interface does not define the type of data that is being serialized, nor the format in which the data is maintained in either store. It does define the possible types of secondary data store: disk file, registry entry and Windows INI file; it defines where and how the data is placed in the secondary store. List of Operations Name Description clear Clear the state of the primary store load Load the primary store from the specified secondary store (deserialize) save Save the primary store into the specified secondary store (serialize) Storage Type Definitions Name Description I SERIAL STGJNI Windows INI file I SERIAL STG SPEC File by supplied file path l_SERIAL_STG_FHANDLE File by supplied file handle (file is open) l_SERIAL STGJ-EGISTRY Windows Registry Bus Definition BUS (B SERIAL) uint stg type; // storage type dword attr; // attributes char *nmp; // depends on storage type char *sect_nmp; // section name dword hdl; // depends on storage type END BUS Notes The implementation of these operations may not support all storage types. It can return CMST_NOT_SUPPORTED for the storage types not supported. When using the l_SERIAL_STG_FHANDLE storage type, the file handle should contain a handle to an open file. The file should be at the position of where the data is to be saved. After a save operation, the file position will be at the next byte following the data. The file handle type used with the I SERIAL STG HANDLE storage type is defined by the implementer (Win32, DOS, etc.). The file handle type must remain consistent with all the I SERIALIZE operations. clear Description: Clear the state of the primary store (empty data) In: void Out: void Return CMST OK The operation was successful Status: (any other) An intermittent error has occurred Example: B SERIAL serbus; /* clear data */ out (ser, clear, δiserbus); See Also: DM REP load Description: Load primary store from persistent storage In: stgjype Storage type, [I_SERIAL_STG_xxx] attr Reserved, must be zero nmp Depends on storage type: I SERIAL STGJNI Name of INI file to load data from l_SERIAL_STG_FSPE Full path of file C to load l_SERIAL_STG_REGI Key name in STRY registry to load data from (other) set to NULL sect_nmp Depends on storage type: l_SERIAL_STG INI Name of INI section to load data from (other) set to NULL hdl Depends on storage type: I_SERIAL_STG JHA File handle NDLE l_SERIAL_STG_REGI Registry Key STRY handle (other) set to 0 If the storage type is l_SERIAL_STG_FHANDLE, the file position is expected to be set at the beginning of the serialized repository data; after the load is complete it will leave the file position at the byte after the last byte of the repository data. Out: void Return CMST OK The operation was successful Status: CMSTJMOT FOUN The source from which to load D could not be located. CMSTJOERR Could not read data from storage medium CMST_NOT_SUPP Specified storage type is not ORTED supported Example: B SERIAL serbus; cmstat status; /* initialize serialization bus */ serbus. stg ype = I SERIAL STG FSPEC; serbus. attr = 0; serbus.nmp = "C:\\DOS\\MYDATA.BIN"; /* load repository from my binary file */ status = out (ser, load, δiserbus); See Also: DM REP save Description: Save primary store to persistent storage In: stgjype Storage type [l_SERIAL_STG_XXX] attr Reserved, must be zero nmp Depends on storage type: l_SERIAL_STGJNI Name of INI section to save data to l_SERIAL_STG_FSPE Full path of file C to save data to l_SERIAL_STG_REGI Key name in STRY registry to save data to (other) set to NULL sect nmp Depends on storage type: l_SERIAL_STGJNI Name of INI section to save data to (other) set to NULL hdl Depends on storage type: l_SERIAL_STGJHA File handle NDLE I_SERIAL_STG_REGI Registry Key STRY handle (other) set to 0 When this argument is l_SERIAL_STG HANDLE, the data will be saved starting from the current file position; after save is complete, it will leave the position at the next byte after the last byte of the saved data. Out: void Return CMSTJDK The operation was successful Status: CMST NOT OUN The source to which to save the D data could not be located. CMSTJOERR Could not write data to storage medium CMST NOT SUPP Specified storage type is not ORTED supported Example: B SERIAL serbus; cmstat status; /* initialize serialization bus */ serbus. stgjype = l_SERIAL_STG_FSPEC; serbus. attr = 0; serbus.nmp = "C:\\DOS\\MYDATA.BIN"; /* save repository to a binary file */ status = out (ser, save, δiserbus); See Also: DM_REP l_A_FACT - Part Array Factory Services Overview This interface is used to control the life cycle and enumerate the parts in a part array. The parts are identified by an ID either generated by the array or supplied by the user on creation of a new part. This interface is typically used by a controlling part in a dynamic assembly. The controlling part is responsible for maintaining the container of part instances for the assembly. This interface is implemented by DM_ARR. List of Operations Name Description create Create a part instance in the array, destroy Destroy a part instance in the array, activate Activate a part instance in the array, deactivate Deactivate a part instance in the array, get irst Get the first part in the part array. get_next Get the next part in the part array. Bus Definition BUS (B A FACT) flg32 attr ; // attributes [A_FACT_A_XXX] char *namep ; // class name for part to create uint32 id ; // part instance id ctx ctx ; // enumeration context END BUS create Description: Create a part instance in the array. In: attr Creation attributes: A_FACT_A_NONE Not specified. A_FACT_A_USEJ Use the ID D supplied in id to identify the created part. namep Class name of the part to create or NULL to use the default class name. id ID to use if the attribute A_FACT_A_USEJD is specified. Out: id ID of the created part (only if the attribute A FACT A USE ID is not specified). Return CMST OK The operation was successful. Status: CMST_CANT_BI The part class was not found. ND CMST_ALLOC Not enough memory. CMST NO ROO No more parts can be created. M CMSTJDUPLICA The specified ID already exists (only if TE the A FACT A USE ID attribute is specifed). (all others) Specific error occurred during object creation. Example: B_A_FACT bus; CMSTAT s; /* create a new part in the part array */ bus. attr = A_FACT_A_NONE; bus.namep = "MyPartClass"; s = out (i_a act, create, δibus); if (s ! = CMST OK) . . . See Also: DM ARR destroy Description: Destroy a part instance in the array. In: id ID of part to destroy. Out: void Return CMST OK The operation was successful. Status: CMST_NOT_FO A part with the specified ID was not UND found. (all others) An intermittent error occurred during destruction. Example: B_A_FACT bus; CMSTAT s; /* create a new part in the part array */ bus.attr = A ACT A NONE; bus.namep = "MyPartClass"; s = out (i_a act, create, δibus); if (s ! = CMST OK) . . . /* destroy created part */ s = out (i_a act, destroy, δibus); if (s ! = CMST OK) . . . See Also: DM ARR activate Description: Activate a part instance in the array. In: id ID of part to activate. Out: void Return CMST OK The operation was successful. Status: CMSTJMOT O A part with the specified ID was not UND found. CMST NO ACTI The part is already active. ON CMST_REFUSE Mandatory properties have not been set or terminals not connected on the part. (all others) An intermittent error occurred during activation. Example: B_A_FACT bus; CMSTAT s; /* create a new part in the part array */ bus.attr = A_FACT_A_NONE; bus.namep = "MyPartClass"; s = out (i_a act, create, δibus); if (s 1 = CMSTJDK) . . . /* activate part */ s = out (i_a act, activate, δibus); if (s ! = CMST OK) . . . See Also: DM ARR deactivate Description: Deactivate a part instance in the array. In: id ID of part to deactivate. Out: void Return CMSTJDK The operation was successful. Status: CMSTJMOT FO A part with the specified ID was not UND found. (all others) An intermittent error occurred during deactivation. Example: B_A_FACT bus; CMSTAT s; /* create a new part in the part array */ bus.attr = AJACT_A_NONE; bus.namep = "MyPartClass"; s = out (i_ajact, create, δibus); if (s ! = CMSTJDK) . . . /* activate part */ s = out (i_a act, activate, δibus); if (s ! = CMST OK) . . . /* deactivate part */ s = out (i_a act, deactivate, δibus); if (s ! = CMST OK) . . . See Also: DM ARR get irst Description: Get the first part in the array. In: void Out: id ID of the first part in the array. ctx Enumeration context for subsequent get next calls. Return CMST OK The operation was successful. Status: CMST NOT FO The array has no parts. UND Example: B_A_FACT bus; CMSTAT s; /* enumerate all parts in part array */ s = out (i_a act, get irst, δibus); while (s = = CMSTJDK) { /* * print id */ printf ("Part ID = %x\n", bus.id); /* * get next part */ s = out (i_a act, get_next, δibus); } See Also: DM ARR get next Description: Get the next part in the array. ctx Enumeration context from previous get_xxx calls. Out: id ID of next part in the array. ctx Enumeration context for subsequent get_xxx calls. Return CMST OK The operation was successful. Status: CMST_NOT_FO The array has no more parts. UND Example: B A FACT bus; CMSTAT s; /* enumerate all parts in part array */ s = out (i_a act, get first, δibus); while (s = = CMSTJDK) { /* * print id */ printf ("Part ID = %x\n", bus. id); /* * get next part */ s = out (i_a act, get_next, δibus); } See Also: DM ARR l_A_CONN - Part Array Connection Services Overview This interface is used to connect and disconnect terminals of parts maintained in a part array. This interface is typically used by a controlling part in a dynamic assembly. The controlling part is responsible for maintaining the container of part instances for the assembly. This interface is implemented by DM_ARR. List of Operations Name Description connect_ Connect two terminals between parts in the array, disconnect Disconnect two terminals between parts in the array. Bus Definition BUS (B_A_CONN) uint32 id 1 ; // id of part 1 char *term1 _namep ; // terminal name of part 1 uint32 id2 ; // id of part 2 char *term2_namep ; // terminal name of part 2 Jd connjd ; // connection id END BUS Notes When connecting and disconnecting terminals, id 1 and id2 may be the same to connect two terminals on the same part. connect_ Description: Connect two terminals between parts in the array. In: id l ID of first part. term1_namep Terminal name of first part. id2 ID of second part. term2_namep Terminal name of second part. conn id Connection ID to represent this connection. Out: void Return CMST OK The operation was successful. Status: CMST REFUSE There has been an interface or direction mismatch or an attempt has been made to connect a non-activetime terminal when the part is in an active state. CMSTJMOT O At least one of the terminals could not UND be found or one of the ids is invalid. CMSTJDVERFLO An implementation imposed restriction W in the number of connections has been exceeded. Example: B A CONN bus; CMSTAT s; /* connect "in" on first part to "out" on second part */ bus. id 1 = partjdl ; bus.term1_namep = "in"; bus.id2 = partjd2; bus.term2_namep = "out"; bus. connjd = 1 ; s = out (i_a_conn, connect_, δibus); if (s ! = CMST OK) . . . See Also: DM ARR disconnect Description: Disconnect two terminals between parts in the array. In: idl ID of first part. term1_namep Terminal name of first part. id2 ID of second part. term2_namep Terminal name of second part. conn id Connection ID to represent this connection. Out: void Return CMSTJDK The operation was successful. Status: Example: B A CONN bus; CMSTAT s; /* connect "in" on first part to "out" on second part */ bus. id 1 = partjd l ; bus.term1 _namep = "in"; bus.id2 = part id2; bus.term2_namep = "out"; bus. connjd = 1 ; s = out (i_a_conn, connect_, δibus); if (s ! = CMST OK) . . . /* disconnect terminals */ out (i_a_conn, disconnect, δibus); See Also: DM ARR I A PROP - Part Array Property Services Overview This interface is used to access properties of parts maintained by a part array. The interface includes all the standard property operations including enumeration. This interface is typically used by a controlling part in a dynamic assembly. The controlling part is responsible for maintaining the container of part instances for the assembly. This interface is implemented by DM_ARR. List of Operations Name Description get Get the value of a property from a part in the array. set Set the value of a property of a part in the array. chk Check if a property can be set to the specified value. get info Retrieve the type and attributes of the specified property. qry open Open a query to enumerate properties on a part in the array based upon the specified attribute mask and values. qry_close Close a query. qry irst Retrieve the first property in a query, qryjiext Retrieve the next property in a query. qry_curr Retrieve the current property in a query. Bus Definition BUS (B_A_PROP) uint32 id ; // id of the instance that is the // operation target char *namep ; // property name [ASCIZ] uintl 6 type ; // property type [CMPRP_T_XXX] flg32 attr ; // attributes [CMPRP_A_XXX] flg32 attrjriask; // attribute mask for queries // [CMPRP_A_XXX] void *bufp ; // pointer to input buffer uint32 buf_sz ; // size of *bufp in bytes uint32 valjen ; // length of value in *bufp in bytes hdl qryh ; // query handle END_BUS Notes When opening a new query using qry_open, specifiy the set of attributes in attrjnask and their desired values in attr. During the enumeration, a bit-wise AND is performed between the actual attributes of each property and the value of attrjnask; the result is then compared to attr. If there is an exact match, the property will be enumerated. To enumerate all properties of a part, specifiy the query string as " * " and attrjnask and attr as 0. get Description: Get the value of a property from a part in the array. In: id Part instance ID. namep Null-terminated property name. type Type of the property to retrieve or CMPRPJJNONE for any. bufp Pointer to buffer to receive property or NULL. buf sz Size in bytes of *bufp. Out: (*bufp) Property value. valjen Length in bytes of property value Return CMSTJDK The operation was successful. Status: CMSTJMOTJO The property could not be found or the UND ID is invalid. CMST_REFUSE The data type does not match the expected type. CMST OVERFLO The buffer is too small to hold the W property value. Example: B_A_PROP bus; char buffer [256]; CMSTAT s; /* get the value of property "MyProp" */ bus. id = partjd; bus. namep = "MyProp"; bus.type = CMPRPJJASCIZ; bus. bufp = buffer; bus.buf sz = sizeof (buffer); s = out (ijaj rop, get, δibus); if (s I = CMSTJDK) . . . /* * print property information */ printf ("The value of property MyProp is %s\n", buffer); printf ("The value is %ld bytes long.", bus. valjen); See Also: DM ARR set Description: Set the value of a property from a part in the array. In: id Part instance ID. namep Null-terminated property name. type Type of the property to set. bufp Pointer to buffer containing property value or NULL (reset the property value to its default). val len Size in bytes of property value (for string properties this must include the terminating zero). Out: void Return CMSTJDK The operation was successful. Status: CMST NOT FO The property could not be found or the UND ID is invalid. CMST REFUSE The property type is incorrect or the property cannot be changed while the part is in an active state. CMST OUT OF The property value is not within the RANGE range of allowed values for this property. CMST BAD AC There has been an attempt to set a CESS read-only property. CMSTJDVERFLO The property value is too large. W CMSTj ULL_PT The property name pointer is NULL or R an attempt was made to set default value for a property that does not have a default value. Example: B_A_PROP bus; CMSTAT s; /* set the value of property "MyProp" */ bus. id = part id; bus. namep = "MyProp"; bus.type = CMPRPJJASCIZ; bus. bufp = "MyStringValue"; bus. valjen = strien ("MyStringValue") + 1 ; // include NULL // terminator s = out (i ajprop, set, δibus); if (s ! = CMST OK) . . . See Also: DM_ARR chk Description: CChheecckk iiff ι a property can be set to the specified value. In: id Part instance ID. namep Null-terminated property name. type Type of the property to check. bufp Pointer to buffer containing property value. val len Size in bytes of property value. Out: void Return CMSTJDK The operation was successful. Status: CMSTJMOT FO The property could not be found or the UND ID is invalid. CMST REFUSE The property type is incorrect or the property cannot be changed while the part is in an active state. CMST DUTJDF_ The property value is not within the RANGE range of allowed values for this property. CMST_BAD_AC There has been an attempt to set a CESS read-only property. CMST OVERFLO The property value is too large. W CMST NULL PT The property name pointer is NULL or R an attempt was made to set default value for a property that does not have a default value. Example: B A PROP bus; CMSTAT s; /* check setting the value of property "MyProp" */ bus. id = part id; bus. namep = "MyProp"; bus.type = CMPRPJJASCIZ; bus. bufp = "MyStringValue"; bus. valjen = strien ("MyStringValue") + 1 ; // include NULL // terminator s = out (ijajprop, chk, δibus); if (s ! = CMST OK) . . . See Also: DM ARR getjnfo Description: Retrieve the type and attributes of the specified property. In: id Part instance ID. namep Null-terminated property name. Out: type Type of property [CMPRP_T_XXX] . attr Property attributes [CMPRP_A_XXX]. Return CMSTJDK The operation was successful. Status: CMSTJMOTJ^O The property could not be found or the UND ID is invalid. Example: B_A_PROP bus; CMSTAT s; /* set the value of property "MyProp" */ bus. id = partjd; bus. namep = "MyProp"; s = out (ijajprop, getjnfo, δibus); if (s ! = CMSTJDK) . . . /* print property information */ printf ("The property type is %u.\n", bus. type); printf ("The property attributes are %x.\n", bus. attr); See Also: DM ARR qry open Description: Open a query to enumerate properties on a part in the array based upon the specified attribute mask and values or CMPRP_A_NONE to enumerate all properties. In: id Part instance ID. namep Query string (must be " * "). attr Attribute values of properties to include. attr mask Attribute mask of properties to include. Can be one or more of the following values: CMPRP_A_NONE Not specified. CMPRP A PERSIS Persistent T property. CMPRP_A_ACTIV Property can be ETIME modified while active. CMPRP_A_MAND Property must be ATORY set before activation. CMPRP_A_RDONL Read-Only Y property. CMPRP_A_UPCAS Force uppercase. E CMPRP_A_ARRA Property is an Y array. Out: qryh Query handle. Return CMST OK The operation was successful. Status: CMST_NOT_FOU The ID could not be found or is invalid. ND CMST NOT SUP The specified part does not support PORTED property enumeration or does not support nested or concurrent property enumeration. Example: B A PROP bus; char buffer [256]; CMSTAT s; /* open query for all properties that are mandatory */ bus. id = partjd; bus. namep = "*"; bus. attr = CMPRP_A_MANDATORY; bus. attrjnask = CMPRP_A_MANDATORY; bus. bufp = buffer; bus.buf sz = sizeof (buffer); s = out (ijajprop, qry φen, δibus); if (s ! = CMSTJDK) . . . /* enumerate and print all mandatory properties */ s = out (ijajprop, qry irst, δibus); while (s = = CMSTJDK) { /* print property name */ printf ("Property name is %s\n", buffer); /* get current property */ s = out (ijajprop, qry_curr, δibus); if (s ! = CMSTJDK) . . . /* get next mandatory property */ s = out (ijajprop, qry next, δibus); } /* * close query */ out (i ajprop, qry_close, δibus); See Also: DM ARR qry close Description: Close a query. In: qryh Handle to open query. Out: void Return CMST OK The operation was successful. Status: CMST_NOT_FOU Query handle was not found or is ND invalid. CMST NOT BUS The object can not be entered from Y this execution context at this time. Example: See qry open example. See Also: DM ARR qry first Description: Retrieve the first property in a query. In: qryh Query handle returned on qry φen. bufp Storage for the returned property name or NULL. buf sz Size in bytes of *bufp. Out: 'bufp) Property name (if bufp not NULL). Return CMST OK The operation was successful. Status: CMST NOT FOU No properties found matching current ND query. CMST OVERFLO Buffer is too small for property name. W Example: See qry open example. See Also: DM_ARR qry iext Description: RReettrriieevvee 1 the next property in a query. In: qryh Query handle returned on qryjapen. bufp Storage for the returned property name or NULL. buf sz Size in bytes of *bufp. Out: (*bufp) Property name (if bufp not NULL). Return CMST OK The operation was successful. Status: CMSTjNOTJOU No more properties found matching ND the current query. CMST OVERFLO Buffer is too small for property name. W Example: See qry open example. See Also: DM ARR qry curr Description: Retrieve the current property in a query. In: qryh Query handle returned on qry open. bufp Storage for the returned property name or NULL. buf sz Size in bytes of *bufp. Out: (*bufp) Property name (if bufp not NULL). Return CMST OK The operation was successful. Status: CMSTjMOTJOU No current property (e.g. after a call to ND qryjDpen). CMSTJDVERFLO Buffer is too small for property name. W Example: See qry open example. See Also: DM ARR I EVS, I EVS R - Event Source Interfaces Overview These two interfaces are for manipulating and using event sources. I EVS and I EVS R are conjoint interfaces; they are always used together. Events generated by an event source can be periodic or singular. Periodic events will be generated in equal intervals of time. Singular events will be generated when a synchronization object gets signaled or when a timeout expires. The interface also allows "preview" of the events being generated and cancellation. The l_EVS_R interface has one operation: fire. This operation is invoked when the event source generates an event. List of Operations Name Description arm Arm the event source (IJΞVS) disarm Disarm the event source (IJΞVS) fire Trigger event occurred (IjΞVS R) Operation Bus BUS (BjΞVS) flg32 attr ; // attributes [EVS_A_xxx] ctx ctx ; // trigger context uint32 time ; // trigger timeout or period cmstat stat ; // trigger status _hdl h ; // synchronization object handle END BUS arm Description: Arm the event source Direction: Input In: attr Arm attributes, can be any one of the following: EVS_AJMONE Not specified. EVS_A_ONETIM Arm for a one-time E firing (disarm upon fire) EVS_A CONTIN Arm for multiple UOUS firing (remain armed upon fire) EVS A PREVIE Fire a preview W before the actual firing ctx User-supplied context to provide when firing time Timeout or fire period in milliseconds, this can also be one of the following values: EVS T INFINIT Infinite time EVSJTJDEFAUL Implementor-defined T default Handle to a synchronization object (or NO HDL for none) Out: void Return CMST OK The operation was successful. Status: CMSTJM0J.00 Can not arm any more events in the M event source. CMSTj O ACTI Already armed (possibly with different ON arguments). CMST REFUSE Event source cannot be armed manually. CMSTJMOTJSUP The particular combination of PORTED attributes and fields is not supported by the implementor. Example: BjΞVS eb; cmstat s; // arm event source for a one-shot timer with no preview eb.attr = EVS_AJDNETIME; eb.time = 10000; // 10 seconds eb.ctx = 0x500; if (s != CMST OK) ... Remarks: The fields attr (not all combinations) and ctx must be supported by all implementors. Support for all other fields is optional. Both implementors and users of this interface must describe their support/requirements in the appropriate documentation. Implementors may honor the field time as a timeout or period between firings. Implementors may honor the field h as a handle to a synchronization object. Typically, the source will fire either when h is signaled or when the timeout expires. It is also possible to use h with EVS Aj ONTINUOUS. Implementors may accept a NULL bus or invalid arguments if the implementor has sufficient defaults. If the bus is NULL, ctx will be 0 on fire. Implementors may ignore most or all of the supplied arguments (if so configured). As long as the bus is not NULL, ctx should be honored. Exactly one of EVS AJDNETIME and EVS A CONTINUOUS must be specified; if none is specified, the implementor may use its default (usually with auto-arm). Implementors may support only one of these two attributes. If the implementor auto-arms the event source, calling arm/disarm may return CMST REFUSE, indicating that the event source cannot be controlled manually. If EVS_A_PREVIEW is specified, the terminal on which fire is received must be unguarded. Preview is invoked in non- thread context (interrupt or event time in Windows 95/98 Kernel Mode; DISPATCH IRQL in Windows NT kernel mode). Not all implementors support the preview feature. See Also: disarm, fire disarm Description: Arm the event source Direction: Input In: ctx User context - as supplied on arm attr Disarm attributes, must be EVS A NONE Out: void Return CMST OK The operation was successful. Status: CMST NOT FOU An armed event associated with ctx ND cannot be found. CMSTjMO ACTI The event source is not armed. ON CMST REFUSE The event source cannot be disarmed manually. Example: B_EVS eb; cmstat s; // disarm event source eb.attr = EVS_A_NONE; eb.ctx = 0x500; s = out (evs, disarm, δieb); if (s ! = CMSTJDK) . . . Remarks: Upon successful return, the event source guarantees that it will not fire unless it is re-armed. See Also: arm, fire fire Description: Trigger event occurred Direction: Output > In: attr Fire attributes, can be one of the following: EVS Aj ON Not specified. E EVS_A_PREV This is a fire preview. IEW ctx User supplied context provided on arm. stat Trigger status, can be one of the following: CMSTJDK Event triggered normally. CMSTJTΪME Event triggered due to OUT timeout. This status can only appear if event source was armed to wait on a synchronous object with a timeout period. CMST ABOR Event source was TED disarmed due to external reason (e.g., deactivation). This status can only appear if event source was armed to wait on a synchronous object with a timeout period. Out: ctx User supplied context to provide on the final fire. This is only used if in the context of a fire preview (attr = = EVS_A_PREVIEW). See the Remarks section below. Return CMST OK The event is accepted - to be sent Status: again without the EVS_A_PREVIEW attribute (ignored if not in the context of a fire preview). (any other) The event is refused - do not send the event again (ignored if not in the context of a fire preview). Example: B_EVS eb; cmstat s; // arm event source for a one-shot timer with no preview eb.attr = EVS_A_ONETIME; eb.time = 10000; // 10 seconds eb.ctx = 0x500; if (s ! = CMSTJDK) . . . // fire callback OPERATION (evsj\ fire, BjΞVS) { // nb: bp- > ctx should be 0x500 - supplied on arm printf ("Event source fired!\n"); return (CMSTJDK); } END OPERATION Remarks: If the event source was armed as a one-time event, the event source is disarmed before fire is called (before preview also). If the event source was armed as a continuous event, the event source remains armed until disarmed, arm and disarm can be called from within fire (provided that fire came without the EVS_A_PREVIEW attribute). If EVS_A_PREVIEW is set, the fire call may not be at thread time. Interrupts may be disabled (Windows 95/98 Kernel Mode), the CPU may be running at DISPATCH IRQL (Windows NT Kernel Mode), etc. arm and disarm (and any thread-level guarded code) should not be called from within fire preview. If a recipient expects fire previews, the terminal on which fire is received should be unguarded (or guarded at the appropriate level depending on the event source). Upon return from fire preview, if a recipient modified ctx, the modified ctx will be provided on the final fire. This change affects only the final fire that corresponds to this preview. Subsequent firings (if the event source was armed as continuous) will come with the original ctx provided on arm. If EVS_A_PREVIEW is not set, the return status from a fire call is generally ignored. Some event sources may expect CMSTJDK for accepted events, and any other for refused events (i.e., event not processed by the recipient). In both cases, the returned status does not affect the armed/disarmed state of the event source for future firings. See Also: arm, disarm I CRT - Critical Section Overview This is an interface to a critical section synchronization object. It provides operations for entering and leaving the critical section. No support for conditional entering is provided (a.k.a. try-enter) by this interface. List of Operations Name Description enter Enter a critical section (cumulative, blocking) leave Leave a critical section (cumulative) enter Description: Enter a critical section (cumulative, blocking) In: void Out: void Return CMST OK The operation was successful. Status: STJDVERFLOW Critical section entered too many times Example: cmstat s; // enter critical section s = out (crt, enter, NULL); if (s ! = CMSTJDK) . . . Remarks: The calling thread is blocked until the critical section is available. leave Description: Leave a critical section (cumulative) In: void Out: void Return CMST OK The operation was successful. Status: Example: cmstat s; // enter critical section s = out (crt, enter, NULL); if (s ! = CMST OK) . . . // leave critical section s = out (crt, leave, NULL); if (s ! = CMSTJDK) . . . Remarks: If another thread was waiting for this critical section, the calling thread may be pre-empted before it returns from this call. I PRPFAC - Property Factory Interface Overview The property factory interface is used to handle virtual (dynamic) properties. Such operations include the creation, destruction, initialization and enumeration of the properties. List of Operations Name Description create Create a new virtual property destroy Destroy a virtual property clear Re-initialize the property value to empty get irst Retrieve first virtual property getjiext Retrieve next virtual property Operation Bus BUS (B PRPFAC) char *namep ; // property name [ASCIZ] uintl 6 type ; // property type [CMPRP T XXX] flg32 attr ; // attributes [CMPRP_A_XXX] byte *bufp ; // pointer to buffer to receive // property name uint32 sz ; // size of *bufp in bytes uint32 ctx ; // enumeration context END BUS create Description: Create a new virtual property In: namep null-terminated property name type type of the property to retrieve [CMPRPJJxxx] attr attributes to be associated with property [CMPRP_A_xxx] Out: void Return CMST OK successful Status: CMSTJNVALID namep is empty or "*" CMSTJDUPLICA the property already exists TE CMST NULL PT namep is NULL R CMST_REFUSE no data type provided CMST NO ROO no room to store property M CMST ALLOC failed to allocate memory for property Example: B_PRPFAC bus; cmstat s; // create a new virtual property bus. namep = "MyProp"; bus.type = CMPRPJT ASCIZ; bus.attr = CMPRP_A_NONE; s = out (prpfac, create, δibus); if (s ! = CMSTJDK) . . . // other property operations here // destroy property s = out (prpfac, destroy, δibus); if (s ! = CMSTJDK) . . . destroy Description: Destroy a virtual property In: namep null-terminated property name to destroy Out: void Return CMST OK successful Status: CMSTJMOT_FO the property could not be found if UND namep not NULL CMSTJNVALID namep is NULL and all is TRUE CMST_NULL_PT namep is NULL R Example: See create example. Remarks: if namep is " * " then all properties will be destroyed clear Description: Re-initialize the property value to empty In: namep null-terminated property name Out: void Return CMST OK successful Status: CMSTjMOTJO the property could not be found if UND namep not NULL CMSTJNVALID namep is NULL and all is TRUE Example: B PRPFAC bus; cmstat s; // clear virtual property bus. namep = "MyProp"; s = out (prpfac, clear, δibus); if (s I = CMST OK) . . . Remarks: if namep is " * " then all properties will be re-initialized empty infers zero-initialized value get first Description: Retrieve first property In: bufp buffer to receive property name sz size of *bufp Out: (*bufp ) null-terminated property name type property type [CMPRP T xxx] attr property attributes ctx enumeration context Return CMSTJDK successful Status: CMSTJMOTJO no properties to enumerate UND CMST DVERFLO buffer too small W Example: B_PRPFAC bus; char buf [256]; cmstat s; // enumerate all virtual properties in container bus. namep = buf; bus.sz = sizeof (buf); s = out (prpfac, get irst, δibus); while (s = = CMSTJDK) { // print property name printf ("Property name is %s\n", buf); // get next property s = out (prpfac, getj ext, δibus); getjiext Description: Retrieve next property In: bufp buffer to receive property name sz size of *bufp ctx enumeration context Out: (*bufp ) null-terminated property name type property type [CMPRP_T_xxx] attr property attributes ctx enumeration context Return CMSTJDK successful Status: CMSTjMOT_FO no properties to enumerate UND CMSTJDVERFLO buffer too small W Example: See get irst example. I BYTEARR - Byte-Array Interface Overview This interface provides access to a byte-array. It provides read and write operations for manipulation of the array. It also allows control over the byte-array metrics (size). The byte array may be fixed length or it may be dynamic - depending on the implementation. List of Operations Name Description read read block of bytes starting at specified offset write write block of bytes starting at specified offset getjnetrics get size of the array set metrics set size of the array Operation Bus BUS (B BYTEARR) void *p ; // buffer pointer uint32 offs ; // offset uint32 len ; // length of data in *p, [bytes] uint32 sz ; // size of buffer pointed to by p, // [bytes] flg32 attr ; // attributes, [BYTEARR A xxx] END BUS read Description: read block of bytes starting at specified offset In: P buffer pointer sz size of buffer offs offset len how many bytes to read attr 0 to read < = len bytes, or BYTEARR_A_EXACT to read exactly len bytes Out: *P data len bytes actually read Return CMST OK successful Status: CMSTJΞOF cannot read requested len bytes (when BYTEARR A EXACT) Example: BjBYTEARR bus; char buf [256]; cmstat s; // read 5 bytes starting at offset 10 bus.p = buf; bus.sz = sizeof (buf); bus. offs = 10; bus. len = 5; bus. attr = BYTEARR_A_EXACT; s = out (arr, read, δibus); if (s ! = CMST OK) . . . Remarks: If BYTEARR_A_EXACT is not specified, an attempt to read beyond the limits of supported space returns CMSTJDK with len = = 0. write Description: write block of bytes starting at specified offset In: P pointer to data to be written offs offset len number of bytes to write attr 0 to BYTEARR_A_GROW to grow automatically Out: void Return CMST OK successful Status: CMSTJDVERFLO offs + len is beyond the current size W of the array and BYTEARR_A 3ROW was not specified CMSTjMOT SUP specified attribute is not supported PORTED Example: B BYTEARR bus; char buf [256]; cmstat s; // write 5 bytes starting at offset 10 strcpy (buf, "1 2345"); bus.p = buf; bus. offs = 10; bus. len = 5; bus. attr = 0; s = out (arr, write, δibus); if (s ! = CMST OK) . . . getjmetrics Description: get size of the array In: void Out: len number of bytes available for reading from offset 0 sz number of bytes available for writing from offset 0 Return CMST OK successful Status: Example: B BYTEARR bus; cmstat s; // get size of the array s = out (arr, getjnetrics, δibus); if (s ! = CMSTJDK) . . . // print size printf ("available for reading: %ld\n", bus. len); printf ("available for writing: %ld\n", bus.sz ); setjmetrics Description: set size of the array In: len number of bytes to become available for reading from offset 0 sz number of bytes to become available for writing from offset 0 Out: void Return CMST OK successful Status: CMST_REFUSE if specified sz < specified len CMST ALLOC specified size cannot be reached (i.e., out of memory) CMST NOT SUP operation is not supported PORTED Example: BJ3YTEARR bus; cmstat s; // set size of the array bus.sz = 10; bus. len = 10; s = out (arr, setjnetrics, δibus); if (s ! = CMSTJDK) . . . Remarks: if len < current length, elements are removed if len > current length, elements are filled with 0 I DEN - Device Enumeration Interface Overview This is a device class enumeration interface. Supports multiple queries (if implementation allows it) on the device class name space. The interface supports multiple class name identifications. Uses UNICODE strings. List of Operations Name Description qryjapen Open a query to enumerate devices qry close Close a query qry irst Get the first device qryjiext Get the next device Operation Bus BUS (BJDEN) char classjiame [1 6]; // CMagic class name WCHAR devicejιame[64]; // name to use for registering // the device WCHAR symjinkl [64]; // Win32 alias (does not include // the \??\ prefix) WCHAR symjink2 [64]; // Win32 alias (does not include // the \??\ prefix) uint32 id; // device ID (valid while qry is // open) hdl qryji; // query handle ENDJ3US qryjαpen Description: Open a query to enumerate devices In: void Out: qry h query handle; must be passed on subsequent calls qry irst, qry iext, qryj_:lose Return CMSTJDK The operation was successful. Status: ST NO ROOM no more queries can be open Example: B DEN bus; // open query s = out (den, qryjopen, δibus); if (s I = CMSTJDK) . . . // query all devices s = out (den, qryjirst, δibus); while (s -= = CMSTJDK) { // print information printf ("Class name = %s\n" , bus.classjiame ); printf ("ID = %ld\n", bus.id ); // get next s = out (den, qryjiext, δibus); } // close query out (den, qryjilose, δibus); qry close Description: Close a query In: qry h query handle from qryjopen Out: void Return CMST OK The operation was successful. Status: Example: See qryjDpen example. qry first/qryjiext Description: Get the first/next device In: qryj Query handle from qry open Out: class name ClassMagic class name of the part that implements the driver for this device (may be empty) device name device name to use when registering the device symjinkl DOS/Win32 alias for the device (base name only, no DOS/Win32 alias for the device (base name only, no NT or Win32 prefixes like \??\ or \\.\) sym Iink2 DOS/Win32 alias for the device (base name) id device ID (see remarks below) Return CMST NOT FO no more devices Status: UND Example: See qry open example. Remarks: Any of the string output fields in the bus (except devicejiame) may be empty: an empty classjiame field means that the default name should be used an empty symjink fields means that the symbolic link is not needed id is a value defined by the implementor and uniquely identifies this device. This value is valid as long as the part that implements IJDEN is active and can be used to identify the device in calls to other terminals of the same part. I DIO, I DIO C - Device I/O Interface Overview This is a device I/O interface. Supports bi-directional data transfer and asynchronous operation. The interface also supports special I/O control operation for the purposes of device control. I DIO C is a conjugate interface used to receive notifications for completion; it has exactly one operation: complete. This interface depends on data structures defined by the Windows NT DDK. List of Operations Name Description Open Open a device object Cleanup Cancel all pending operations, prepare for close Close Cancel all pending operations, prepare for close Read Read data Write Write data Ioctl Execute the IOCTL operation specified by 'ioctl'. The definition of IOCTL operations is outside the scope of this interface complete Report completion of an operation Operation Bus BUS (BJDIO) // attributes flg32 attr; // attributes (DIO A xxx) uint32 buf mapping; // DIO_MAP_xxx uint32 id; // device instance // identification hdl h; // handle (returned on open) // I/O operation data void *p; // pointer to data uint32 sz; // size of buffer pointed to by II uint32 len; // length of data in *p LARGEJNTEGER ofs; // file offset (for block // devices) uint32 ioctl; // function code // asynchronous completion void *irpp; // NT only: original I/O Request // Packet cmstat cplt_s; // completion status (for // complete operation only) END BUS Notes 1 . The term 'object' is used below to refer to the entity on which the I/O operations are performed. This can be a file, a device, a pipe or any similar entity. 2. This interface can be used for asynchronous operations if there is a back channel provided (e.g. the I DIO connection is bi-directional). See the notes at the 'complete' operation description 3. The DIO_A_PREVIEW is used for dispatching IJDIO operations to multiple parts. If this attribute is set, the caller should interpret the status as follows: a. CMSTJDK - the operation is acceptable, the part will process it synchronously (i.e. will not return CMST_PENDING status). b. CMST SUBMIT - the operation is acceptable, the part claims the exclusive right to execute the operation. The operation may be processed synchronously. c. Other - the operation is not implemented. Note that the return statuses listed for the operations below assume that this flag is not set. 4. The id field in the BJDIO bus is used to identify the instance that should handle the operation. The use of this field is optional. It is intended as storage for a part array index in one-to-many connections, but its use is not fixed by this interface. open Description: Open a device object. In: id Device instance identification (see note #4 in the overview) attr Attributes, can be any one of the following: DIO AJPREVIE "preview" operation W DIO_A_ASYNC_ operation may CPLT complete asynchronously (WCHAR *) name of object to open (may be NULL) len Length of data pointed to by p (without terminating 0) irpp (see complete operation) Out: Handle to pass on subsequent operations Return CMST OK The operation was successful. Status: CMSTJMOT FOU Specified object not found ND CMST_ACCESS_ Object already open (if multiple opens DENIED are not supported) CMST PENDING See notes for complete operation Example: B DIO bus; // open device memset (δibus, 0, sizeof (bus)); bus.p = L"MyDevice"; bus. len = sizeof (L"MyDevice"); s = out (dio, open, δibus); if (s ! = CMSTJDK) . . . // device operations . . . // cancel any pending operations out (dio, cleanup, δibus); // close device out (dio, close, δibus); Remarks: Named object support and the naming conventions are outside the scope of this interface cleanup Description: Cancel all pending operations, prepare for close In: id Device instance identification (see note #4 in the overview) attr Attributes, can be any one of the following: DIO_A_PREVIE "preview" operation W DIO_A_ASYNC_ operation may CPLT complete asynchronously h Handle from open irpp (see complete operation) Out: void Return CMST OK The operation was successful. Status: CMSTjNOTJDPE Object is not open. N CMST PENDING Operation is asynchronous, see notes for complete operation. Example: See example for open. Remarks: No operations except close should be called after cleanup close Description: Close a device object In: id Device instance identification (see note #4 in the overview) attr Attributes, can be any one of the following: DIO_A_PREVIE "preview" operation W DIO_A_ASYNC_ operation may CPLT complete asynchronously h Handle from open irpp (see complete operation) Out: void Return CMST OK The operation was successful. Status: CMST NOT OPE Object is not open N CMSTJOERR I/O error (nb: object is closed anyway) CMST PENDING See notes for complete operation Example: See example for open. read Description: Read data In: id Device instance identification (see note #4 in the overview) attr Attributes, can be any one of the following: DIO_A_PREVIE "preview" operation W DIO_A_ASYNC operation may CPLT complete asynchronously buf jnapping Buffering attributes, can be one of the following: DIOJv1AP_BUFF buffering is handled ERED by caller, p is a valid virtual memory address DIO MAP DIRE no buffering, p value CT is system-dependent P Buffer pointer sz Size of buffer ofs File offset (for block devices) h Handle from open irpp See complete operation Out: len Number of bytes read *P Data read Return CMSTJDK The operation was successfu Status: CMSTJMOTJOPE Object is not open N CMSTJOERR I/O error CMST PENDING See notes for complete operation Example: B DIO bus; char buffer [256]; // open device memset (δibus, 0, sizeof (bus)); bus.p = L"MyDevice"; bus. len = sizeof (L"MyDevice"); s = out (dio, open, δibus); if (s ! = CMSTJDK) . . . // read from device bus.bufjnapping = DIO BUFJDIRECT; bus.p = buffer; bus.sz = sizeof (buffer); bus.ofs = 1000; bus.irpp = δiirp; // NT request packet s = out (dio, read, δibus); if (s I = CMSTJDK) . . . // cancel any pending operations out (dio, cleanup, δibus); // close device out (dio, close, δibus); write Description: Write data In: id Device instance identification (see note #4 in the overview) attr Attributes, can be any one of the following: DIO_A_PREVIE "preview" operation W DIO_A_ASYNC_ operation may CPLT complete asynchronously bufjnapping Buffering attributes, can be one of the following: DIO MAP BUFF buffering is handled ERED by caller, p is a valid virtual memory address DIOJV1AP DIRE no buffering, p value CT is system-dependent P Pointer to data to be written sz Number of bytes to write ofs File offset (for block devices) h Handle from open irpp See complete operation Out: len Number of bytes written Return CMST OK The operation was successful. Status: CMSTJMOTJDPE Object is not open N CMSTJOERR I/O error CMST_FULL Media full (for block devices only) CMST PENDING See notes for complete operation Example: B DIO bus; // open device memset (δibus, 0, sizeof (bus)); bus.p = L"MyDevice"; bus. len = sizeof (L"MyDevice"); s = out (dio, open, δibus); if (s ! = CMSTJDK) . . . // write to device bus.bufjnapping = DIO BUF DIRECT; bus.p = "MyString"; bus.sz = strien ("MyString") + 1 ; bus.ofs = 1000; bus.irpp = δiirp; // NT request packet s = out (dio, write, δibus); if (s ! = CMSTJDK) . . . // cancel any pending operations out (dio, cleanup, δibus); // close device out (dio, close, δibus); ioctl Description: Execute the IOCTL operation specified by ioctl. The definition of IOCTL operations is outside the scope of this interface. For more information see the Windows NT DDK documentation. In: id Device instance identification (see note #4 in the overview) attr Attributes, can be any one of the following: DIO_A_PREVIE "preview" operation W DIO A ASYNC operation may CPLT complete asynchronously bufjnapping Buffering attributes, can be one of the following: DIO MAP BUFF buffering is handled ERED by caller, p is a valid virtual memory address DIOJVIAPJDIRE no buffering, p value CT is system-dependent Pointer to input data and buffer for output data sz Size of output buffer len Length of input data ioctl IOCTL function code h Handle from open irpp See complete operation Out: len Length of output data (never more than sz) Output data (depending on function code ioctl) Return CMST OK The operation was successful. Status: CMST NOT OPE Object is not open N CMSTJOERR I/O error CMST PENDING See notes for complete operation CMSTjMOT SUP The specified IOCTL code is not PORTED implemented Example: BJDIO bus; char buffer [256]; // open device memset (δibus, 0, sizeof (bus)); bus.p = L"MyDevice"; bus. len = sizeof (L"MyDevice"); s = out (dio, open, δibus); if (s ! = CMSTJDK) . . . // write to device strcpy (buffer, "MyData"); bus.buf mapping = DIOjBUF DIRECT; bus.p = buffer; bus.sz = sizeof (buffer); bus. len = strien (buffer) + 1 ; bus.ioctl = IOCTL_SMARTCARDJ3ET_ATTRIBUTE; bus.irpp = δiirp; // NT request packet s = out (dio, write, δibus); if (s ! = CMSTJDK) . . . // cancel any pending operations out (dio, cleanup, δibus); // close device out (dio, close, δibus); complete Description: Report completion of an operation In: Handle to pass to subsequent operations (when completing open) len Length of output data (if applicable, see I DIO above) other See the 'out' fields for each I DIO operation irpp Must be as received with the operation being completed cpltjs Completion status Out: void Return CMST OK The operation was successful. Status: CMSTJNVALID irpp does not correspond to a valid pending operation Example: BJDIO bus; char buffer [256]; // open device memset (δibus, 0, sizeof (bus)); bus.p = L"MyDevice"; bus. len = sizeof (L"MyDevice"); s = out (dio, open, δibus); if (s ! = CMSTJDK) . . . // read from device asynchronously bus.attr = DIO_A_ASYNC_CPLT; bus.bufjnapping = DIOjBUFJDIRECT; bus.p = buffer; bus.sz = sizeof (buffer); bus.ofs = 1000; bus. irpp = δiirp; // NT request packet s = out (dio, read, δibus); if (s ! = CMSTJDK) . . . // . . . OPERATION (dio_c, complete, BJDIO) { // this is called when the read operation completes return (CMSTJDK); } ENDJDPERATION Remarks: This operation is intended to be used in the client-to-server direction of a bi-directional IJDIO/IJDIOjC terminal. If the server has to complete any of the IJDIO operations described above asynchronously it should copy the bus and return CMST PENDING. When the operation completes it fills in the required 'out' fields in the bus and calls through the back channel with the saved copy of the bus. I IRQ, I JRQ R - Interrupt Source Interface Overview This is an interrupt source interface. It is used for enabling and disabling the event source and for receiving events when an interrupt occurs. List of Operations Name Description enable Enable interrupt handling disable Disable interrupt handling preview Preview interrupt event at device IRQL submit Interrupt event occurred (preview returned CMST SUBMIT) Operation Bus uint32 attr ; // attributes ctx ctx ; // context END BUS Notes 1 . The enable and disable operations must be invoked only at PASSIVE IRQL 2. The preview operation is always sent at device IRQL (in interrupt context). The operation implementation must be unguarded. 3. The submit operation is always sent at DISPATCH IRQL. enable Description: Enable interrupt handling. In: void Out: void Return CMST OK Interrupt handling is enabled. Status: CMSTj O_ACTI The interrupt handling is already ON enabled. CMST_REFUSE Interrupt source cannot be enabled manually CMSTJNVALID Failed to register ISR because of invalid properties. STJ3USY The Interrupt is used exscluzivly from sombody else Example: s = out (irq, enable, NULL); if (s ! = CMST OK) . . . // enable interrupt generation // . . . // disable interrupt generation s = out (irq, disable, NULL); if (s ! = CMST OK) . . . Remarks: The enable operation must be invoked only at PASSIVE IRQL disable Description: Disable interrupt handling In: void Out: void Return CMST OK The operation was successful. Status: CMSTJMO_ACTI Interrupt event source is not enabled ON CMST REFUSE Interrupt event source cannot be disabled manually Example: See example for enable. Remarks: The disable operation must be invoked only at PASSIVE IRQL. Upon successful return, the event source guarantees that it will not preview or submit unless it is re-enabled. preview Description: Preview an interrupt at device IRQL In: void Out: ctx context for the subsequent submit operation Return CMSTJDK Interrupt handling completed, no need Status: for sending submit operation CMSTJ3UBMIT Interrupt event accepted. Send submit operation at lower IRQL other error Interrupt not recognized, don't send status submit. Example: None. Remarks: preview operation is always sent at device IRQL (in interrupt context) Note that if the interrupt is level-sensitive (as opposed to edge-sensitive), this operation should clear at least one reason for the interrupt; if the the device does not deassert the interrupt, the preview operation will be invoked again upon return. submit Description: Process interrupt. In: ctx context returned from preview Out: void Return CMST OK Event accepted. Status: Example: None. Remarks: submit operation is always sent at DISPATCH IRQL HOP - I/O Port Interface Overview This is a generic I/O port interface. List of Operations Name Description in Read a byte (8-bits) from the I/O port inw Read a word (1 6-bits) from the I/O port indw Read a double word (32-bits) from the I/O port inbuf read sequence of bytes, words or double words from the I/O port out Output a byte (8-bits) to the I/O port outw Output a word (1 6-bits) to the I/O port outdw Output a dword (32-bits) to the I/O port outbuf Output sequence of bytes, words or double words to the I/O port Operation Bus None Notes All operations can be invoked at any interrupt level. in {CMIFCP ( iface), uint32 offs, byte *bp) Description: Read a byte (8-bits) from the I/O port In: offs base relative I/O port offset bp pointer to a storage for 8-bit value Out: f bp 8-bit value read from the port Return CMSTJDK operation finished successfully Status: Example: byte b; s = outX (io, in) ((Jface * const)top (io), 0, δib); if (s ! = CMSTJDK) . . . printf ("byte received 0x%02x\n", b); inw (CMIFCP ( iface), uint32 offs, word *wp) Description: Read a word ( 1 6-bits) from the I/O port In: offs base relative I/O port offset wp pointer to a storage for 1 6-bit value Out: e wp 1 6-bit value read from the port Return CMST OK operation finished successfully Status: Example: word w; s = outX (io, inw) ((Jface * const)top (io), 0, δiw); if (s ! = CMSTJDK) . . . printf ("word received 0x%04x\n", w); indw (CMIFCP ( iface), uint32 offs, dword *dp) Description: Read a double word (32-bits) from the I/O port In: offs base relative I/O port offset dp pointer to a storage for 32-bit value Out: f dp 32-bit value read from the port Return CMST OK operation finished successfully Status: Example: word dw; s = outX (io, indw) ((Jface * const)top (io), 0, δid); if (s I = CMSTJDK) . . . printf ("dword received 0x%08lx\n", d); inbuf (CMIFCP ( iface), uint32 offs, uint32 unit sz, uint32 nj nits, void *bufp) Description: read sequence of bytes, words or double words from the I/O port In: offs base relative I/O port offset unitjsz port size (in bytes) or size of the units. Must be 1 ,2 or 4 n unit number of the units to be read from the port bufp output data buffer. The size of the buffer must be at least unitjsz * n units (in bytes) Out: f bufp n units read from the port Return CMSTJDK operation finished successfully Status: Example: byte b; word w; dword dw[10]; s = outX (io, inbuf) ( (Jface * const)top (io), 0, sizeof(b), 1 , &b); if (s ! = CMST OK) . . . printf ("byte received Ox%02x\n", b); s = outX (io, inbuf) ( (Jface * const)top (io), 0, sizeof(w), 1 , if (s I = CMSTJDK) . . . printf ("word received 0x%04x\n", w); s = outX (io, inbuf) ( (Jface * const)top (io), 0, sizeof(dw[0]), sizeof (dw)/sizeof(dw[0]), if (s I = CMSTJDK) . . . printf ("1 -st dword received = 0x%08lx\n", dw[0]); out (CMIFCP ( iface), uint32 offs, byte b) Description: Output a byte (8-bits) to the I/O port In: offs base relative I/O port offset 8-bit output value Out: void Return CMST OK operation finished successfully Status: Example: s = outX (io, out) ((Jface * const)top (io), 0, 0x1 2); if (s ! = CMST OK) . . . outw (CMIFCP ( iface), uint32 offs, word w) Description: Output a word (1 6-bits) to the I/O port In: offs base relative I/O port offset w 1 6-bit output value Out: void Return CMST OK operation finished successfully Status: Example: word w; s = outX (io, outw) ((Jface * const)top (io), 0, 0x1 234); if (s ! = CMST OK) . . . outdw (CMIFCP ( iface), uint32 offs, dword dw) Description: Output a dword (32-bits) to the I/O port In: offs base relative I/O port offset dw 32-bit output value Out: void Return CMST OK operation finished successfully Status: Example: word dw; s = outX (io, outdw) ((Jface * const) top (io), 0, 0x1 2345678); if (s ! = CMSTJDK) . . . inbuf (CMIFCP ( iface), uint32 offs, uint32 unit sz, uint32 n units, void *bufp) Description: Output sequence of bytes, words or double words to the I/O port In: offs base relative I/O port offset unitjsz port size (in bytes) or size of the units. Must be 1 ,2 or 4 n unit number of the units to be outputed to the port bufp data buffer. The length of the data is equal to unit sz * n units (in bytes) Out: void Return CMSTJDK operation finished successfully Status: word w = 12345; dword dw[10] = {1 , 2, 3, 4, 5, 6, 7, 8, 9, 10}; s = outX (io, out) ( (Jface * const)top (io), 0, sizeof(b), 1 , if (s I = CMSTJDK) . . . s = outX (io, outbuf) ( (Jface * const)top (io), 1 234, sizeof(w), 1 , if (s ! = CMSTJDK) . . . s = outX (io, outbuf) ( (Jface * const)top (io), 333, sizeof(dw[0]), sizeof (dw)/sizeof(dw[0]), if (s I = CMSTJDK) . . . I BYTEARR - Byte-Array Interface Overview This interface provides access to a byte-array. It provides read and write operations for manipulation of the array. It also allows control over the byte-array metrics (size). The byte array may be fixed length or it may be dynamic - depending on the implementation. List of Operations Name Description read read block of bytes starting at specified offset write write block of bytes starting at specified offset set metrics set size of the array Operation Bus BUS (BJ3YTEARR) void *p ; // buffer pointer uint32 offs ; // offset uint32 len ; // length of data in *p, [bytes] uint32 sz ; // size of buffer pointed to by p, // [bytes] flg32 attr ; // attributes, [BYTEARR_A_xxx] ENDJ3US read Description: read block of bytes starting at specified offset In: P buffer pointer sz size of buffer offs offset len how many bytes to read attr 0 to read < = len bytes, or BYTEARR A EXACT to read exactly len bytes Out: *P data len bytes actually read Return CMST OK successful Status: CMST EOF cannot read requested len bytes (when BYTEARR A EXACT) Example: B BYTEARR bus; char buf [256]; cmstat s; // read 5 bytes starting at offset 10 bus.p = buf; bus.sz = sizeof (buf); bus. offs = 10; bus. len = 5; bus. attr = BYTEARR_A_EXACT; s = out (arr, read, δibus); if (s ! = CMST OK) . . . Remarks: If BYTEARR_A_EXACT is not specified, an attempt to read beyond the limits of supported space returns CMSTJDK with len = = 0. write Description: write block of bytes starting at specified offset In: P pointer to data to be written offs offset len number of bytes to write attr 0 to BYTEARR_Aj3ROW to grow automatically Out: void Return CMST OK successful Status: CMSTJDVERFLO offs + len is beyond the current size W of the array and BYTEARR_AJ3R0W was not specified CMST NOT SUP specified attribute is not supported PORTED Example: BjBYTEARR bus; char buf [256]; cmstat s; // write 5 bytes starting at offset 10 strcpy (buf, "1 2345"); bus.p = buf; bus.offs = 10; bus. len = 5; bus. attr = 0; s = out (arr, write, δibus); if (s ! = CMST OK) . . . get metrics Description: get size of the array In: void Out: len number of bytes available for reading from offset 0 sz number of bytes available for writing from offset 0 Return CMST OK successful Status: Example: B BYTEARR bus; cmstat s; // get size of the array s = out (arr, getjnetrics, δibus); if (s ! = CMSTJDK) . . . // print size printf ("available for reading: %ld\n", bus. len); printf ("available for writing: %ld\n", bus.sz ); setjTietrics Description: set size of the array In: len number of bytes to become available for reading from offset 0 sz number of bytes to become available for writing from offset 0 Out: void Return CMST OK successful Status: CMST_REFUSE if specified sz < specified len CMST ALLOC specified size cannot be reached (i.e., out of memory) CMSTj OT SUP operation is not supported PORTED Example: B BYTEARR bus; cmstat s; // set size of the array bus.sz = 10; bus. len = 10; s = out (arr, setjnetrics, δibus); if (s l = CMST OK) . . . Remarks: if len < current length, elements are removed if len > current length, elements are filled with 0 IJJSBCFG - USB Configuration Interface Overview This interface is used to enumerate the set of available USB configurations on the current system. After enumeration, a configuration can be set to the current configuration used by a USB driver. The configuration list may be refreshed at any time. List of Operations Name Description refresh Refresh the list of available configurations set Set a configuration or set to unconfigured state (id = NO USBCFG) get Get currently selected configuration getjnfo Get information for specified configuration ID ('id' does not have to be the current configuration) qryjopen Open a query for enumerating configurations qry_close Close a query for enumerating configurations q ry i rst/q ry n ext Get first/next configuration reset Reset the USB device Operation Bus BUS( B USBCFG // primary identification uint32 id; // configuration ID // USB identification byte cfgjd; // configuration number byte ifcjd; // interface number byte alt id; // alternate setting number // configuration data word cfg attr; // USBCFG_A_xxx word cfgjpwr; // 0-500 [ma] byte cfgjdescjdx; // index of configuration // description string byte ifc class; // (values are defined by the USB // standard) byte ifc subclass; // (values are defined by the USB // standard) byte ifcjprotocol; // (values are defined by the USB // standard) uint32 njandpts; // number of entries in endpt[] // array ENDPT endpt[MAX ENDPTS]; // endpoint data END BUS refresh Description: Refresh the list of available configurations In: void Out: void Return CMSTJDK configuration was read successfully Status: (other) failed to read configuration Remarks: Use of this operation is not required in order to use other operations of the IJJSBCFG interface This operation may invalidate configuration IDs obtained with prior qry first/qryjiext operations set Description: Set a configuration or set to unconfigured state (id = NO USBCFG) In: id config ID from qry irst/qry_next or NO USBCFG Out: void Return CMST OK configuration was selected successfully Status: CMST FAILED configuration was not selected Remarks: It is recommended that all activity on USB endpoints except endpoint 0 is suspended when calling the 'set' operation. Implementation may not guarantee that device state will be preserved if the operation fails. Upon successful return from 'set' the device is configured and ready and all the endpoints are ready for data transfer. get Description: Get currently selected configuration In: void Out: id current configuration ID Return CMST OK always (except fatal failures) Status: getjnfo Description: Get information for specified configuration ID ('id' does not have to be the current configuration) In: id value returned by qryjirst, qryjiext or get Out: (all fields - see notes at qry irst/qryjiext) Return CMSTJNVALID id is not valid (use only values returned Status: by qryjirst/qryjiext) qry open Description: Open a query for enumerating configurations In: void Out: void Return CMSTjNO JJOO a query is already open Status: M qry close Description: Close a query for enumerating configurations In: void Out: void Return CMSTjMO_ACTI no query is open Status: ON q ry f i rst/qryjiext Description: Get first/next configuration In: id (for qryjiext only) value from previous call to qry first/qryjiext Out: (all B USBCFG fields are set) Return CMSTjMOTJO there are no more configurations Status: UND reset Description: Reset the USB device; this operation executes the reset sequence on the USB port and returns the device to its unconfigured state. In: void Out: void Return CMST_ACCESS_ device is disconnected Status: DENIED Appendix 2 - Events This appendix describes preferred definition of events used by parts described herein. EV IDLE Overview: The EVJDLE is a generic event used to signal that idle processing can take place. Recipients of this event perform processing that was postponed or desynchronized. Description: Signifies that a system is idle and that idle processing can take place. Event Bus CMEVENT_HDR/CMEvent Definition: Return Depends on the consumer of the event. Usually, the Status: following values are interpreted CMSTJDK processing was performed; there is need for more idle-time processing, waiting for another idle event CMSTj O AC there was nothing to do on this event TION Example: /* my idle event definition - equivalent to CMEVENT HDR */ EVENT (MYJDLEjΞVENT) // no event data END_EVENT MYJDLEjΕVENT idlejavent; /* initialize idle event */ idlejevent.sz = sizeof (idlejavent); idlejavent.attr = CMEVT_A_DFLT; idle event.id = EVJDLE; /* raise event through a IJDRAIN output */ out (drain, raise, δiidle event); Remarks: This event uses the CMEVENT HDR/CMEvent directly; it does not have any event-specific data. There are no event-specific attributes defined for this event. This event is typically distributed synchronously. See the overview of the IJDRAIN interface for a description of the generic event attributes. See Also: I DRAIN, DMJDWI, DMJEV, CMEVENT HDR, CMEvent EV REQ ENABLE Overview: EV REQ ENABLE is a generic request to enable a particular procedure or processing. The nature of this procedure depends on the context and environment in which it is used. Description: Generic request to enable a particular procedure. Event Bus CMEVENT JHDR/CMEvent Definition: Return Depends on the consumer of the event Status: Example: EVENTX (MY_ENABLE_EVENT, EVJ.EQ ENABLE, CMEVT_A_AUTO, CMEVT JJNGUARDED) char data[32]; ENDjΞVENTX /* allocate enable event */ if (evtjalloc (MY_ENABLE_EVENT, δienablejaventp) I : CMSTJDK) return; /* raise event through a IJDRAIN output */ memset (διenablej3ventp- >data[0], OxAA, sizeof (enablejaventp->data)); out (drain, raise, enablejaventp); Remarks: This event does not have any event-specific data or attributes. If this event is distributed asynchronously, then the event bus must be self-owned. See the overview of the IJDRAIN interface for a description of the generic event attributes. See Also: IJDRAIN, DM DWI, DMJEV, CMEVENTJHDR/CMEvent EV REQ DISABLE Overview: EV REQJDISABLE is a generic request to disable a particular procedure or processing. The nature of this procedure depends on the context and environment in which it is used. Description: Generic request to disable a particular procedure. Event Bus CMEVENTJHDR/CMEvent Definition: Return Depends on the consumer of the event Status: Example: EVENTX (MY_DISABLE_EVENT, EV_REQ_DISABLE, CMEVT_A_AUTO, CMEVT JJNGUARDED) char data[32]; ENDjΞVENTX /* allocate disable event */ if (evtjalloc (MYJDISABLEjΞVENT, &disable_eventp) ! = CMSTJDK) return; /* raise event through a IJDRAIN output */ memset (διdisablejaventp- >data[0], OxAA, sizeof (disable_eventp->data)); /* raise event through a IJDRAIN output */ out (drain, raise, disablejaventp); Remarks: This event does not have any event-specific data or attributes. If this event is asynchronous, then the event bus must be self-owned. See the overview of the IJDRAIN interface for a description of the generic event attributes. See Also: IJDRAIN, DM DWI, DMJEV, CMEVENT HDR, CMEvent EV REP NFY DATA CHANGE Overview: This event is generated when a repository data item or a subtree changes. The change may be that a value has been modified, added or deleted. The originator of the event may use the event with an indication that a whole subtree has been changed in order to avoid notifying for each item separately. Description: Notification that a repository data item has been modified, added, or deleted Event Bus EVENTX (EV_REP, EV_REP_NFY_DATA_CHANGE, Definition: CMEVT A AUTO, CMEVT JJNGUARDED) // repository event specific data char path[IJTEM_MAX_PATH]; // full path to affected // entity bool32 isjsubtree ; // TRUE if the whole // subtree is affected END EVENTX Data: path Full data path to affected data item or subtree root is subtree TRUE the if whole subtree below the path specified by path has changed. If this member is FALSE, only the item at the specified path has changed. Return Since this is a notification of an action that has already Status: occurred and does not depend on processing by the recipient, originators of this event can safely ignore the returned status. Example: OPERATION (nfy, raise, EV_REP) { /* valchk */ if (bp = = NULL) return (CMSTj ULL_PTR); if (bp-> id ! = EV_REPj FY_DATA_CHANGE) t ■ . • /* free bus if self-owned */ if (bp->attr δι CMEVT A SELF OWNED) evt free (bp); return (CMSTJDK); } /* find out which path changed */ if (stricmp (bp- > path, "customers[1 ].name") = = 0) printf ("customer #1 name has changed. \n"); if (stricmp (bp- > path, "customers[2].name") = = 0) printf ("customer #2 name has changed. \n"); /* find out if the whole subtree was affected */ if (bp- > is_subtree) printf ("The whole subtree was affected\n"); /* free bus if self-owned */ if (bp- > attr δι CMEVT_A_SELFJDWNED) evt ree (bp); return (CMSTJDK); } ENDJDPERATION Remarks: The EV_REP_NFY_DATA_CHANGE event is generated by DMj EP when a repository data item changes (added, changed, deleted). There are no event-specific attributes defined for this event. The event bus contains all the information about the affected entity. It contains the affected data path and whether or not the whole subtree under that path was affected. If this event is distributed asynchronously, then the event bus must be self-owned. Note that, since the event contains the storage for the path and not only a pointer to it, the event is self-contained and can be distributed asynchronously. See the overview of the I DRAIN interface for a description of the generic event attributes. See Also: IJDRAIN, DM_REP EV RESET Overview: This event is a generic request for reset. Recipients of this event should immediately reset their state and get ready to operate again as if they were just activated. Description: Reset the internal state of a part. Event Bus CMEVENTJHDR/CMEvent Definition: Return Depends oh the consumer of the event Status: Remarks: This event does not have any event-specific data or attributes. If this event is asynchronous, then the event bus must be self-owned. See the overview of the IJDRAIN interface for a description of the generic event attributes. See Also: IJDRAIN, DM DWI, CMEVENTjHDR, CMEvent EV MESSAGE Overview: This event contains a message received or to be transmitted through some communication channel. The event contains the actual data and its length. The event also contains an indication of whether the data is corrupted or not. Description: Send a string of bytes Event Bus EVENTX (BjΞV MSG, EV NULL, Definition: CMEVT_A_SYNC | CMEVT_A_SELFJDWNED CMEVT_A_SELF_CONTAINED, CMEVT JJNGUARDED) uint len ; // length of the data char data[1 ]; // variable size data END EVENT Data: attr MSG_AjMONE no attrubutes MSG AJ3AD DAT message consists A of bad data len length of message data data beginning of message data Return CMST OK event processed successfully Status: Remarks: This message must be sent with the EV A SYNC attribute set. EV EXCEPTION Overview: This event signifies that an exception has occurred which requires special processing. More than one recipient can process this event. Description: Raise exception. Event Bus EVENTX (B EV EXC, EV EXCEPTION, Definition: CMEVT_Aj3YNC | CMEVT_A_SELF_CONTAINED, CMEVT UNGUARDED) // exception identification dword exc id ; // exception ID byte exc_class ; // type of exception byte exc severity ; // severity, [CMERR XXX] // source identification cmoid oid ; // oid of original issuer cmoid oid2 ; // current oid char path[48] ; // path along the assembly // hierarchy (dot-separated // names as in the SUBORDINATES // tables) char classjιame[24]; // class name char file_name[24] ; // file name dword line ; // line number in file // context char termjιame[1 6] ; // terminal name char operjιame[16] ; // operation name cmstat cm stat ; // ClassMagic status (optional) dword os stat ; // OS-dependent status _ctx ctxl ; // optional context (see // EXC_A_xxx) ctx ctx2 ; // optional context (see // EXC_A_xxx) // inserts char format[16] ; // defines format of data[] byte data[128] ; // packed insert data, as // specified by the // format 'field' Data: attr Attributes, can be any one of the following: EXC_A_CTX1 IRP ctxl is a pointer to IRP EXC_A_CTX2_IO ctx2 is an I/O M manager object excjd exception ID excj-;lass type of exception, reserved excjseverity severity, [CMERR_XXX] oid oid of original issuer oid2 current oid - used to trace assembly path path path along the assembly hierarchy (dot- separated names as in the SUBORDINATES tables) classjiame ClassMagic class name filejiame source file name line line number in file termjiame terminal name operjiame operation name cmjstat ClassMagic status (CMST xxx) osjstat system status (NT status, Win32 error, etc.) ctxl optional context (see EXC_A <xx) ctx2 optional context (see EXC A xxx) format defines format of the 'data' field, one char defines one data field as follows: b, w, d - byte, word, dword (to be printed in hex) i, u - signed integer, unsigned integer (dword, decimal) c - byte (to be printed as a character) s - asciiz string S - unicodez string 1 ..9 - 1 to 9 dwords of binary data data packed insert data, as specified by format 'field' Return CMST OK The event was processed successfully Status: Remarks: All fields except exc cxx, classjiame, filejiame and line are optional, set them to binary Os if not used Use guidelines: 1 ) original issuer should: - - initialize all mandatory fields - set 'oid' and Oid2' to the same value (sp- > self) - zero-init the following fields, they are for use only by exception processing parts: path 2) all unused fields should be zero-initialized EV LFC REQ START Overview: This life cycle event is used to signal that normal operation can begin. Recipients may commence operation immediately (the usual practice) and return after they have started. Recipient can postpone the starting for asynchronous completion and raise EV_LFC_NFY_START CPLT event when ready. Description: Start normal operation Event Bus EVENT (BjΞVJFC) Definition: cmstat cpltjs; // completion status (asynchronous completion) END EVENT Data: attr standard event attributes, optionally LFC A ASYNC CPLT Return CMST OK started OK Status: CMST_PENDING postponed for asynchronous completion (allowed if LFC_A_ASYNC_CPLT is specified; otherwise treated as failure) any other start failed Remarks: If LFC A ASYNC PLT is specified, the recipient may return CMST PENDING and complete the start later by sending EVJFC_NFY 3TART_CPLT. EV LFC REQ STOP Overview: This life cycle event is used to signal that normal operation should end. Typically recipients initiate the stopping procedure immediately and return after this procedure is complete. Recipient can postpone the starting for asynchronous completion and raise EV_LFCj FY_STOP_CPLT event when ready. Description: Stop normal operation Event Bus EVENT (BjΞVJFC) Definition: cmstat cpltjs; // completion status (asynchronous completion) END EVENT Data: attr standard event attributes, optionally LFC A ASYNC CPLT Return CMST OK Stop completed Status: CMST PENDING postponed for asynchronous completion (allowed if LFC_A_ASYNC_CPLT is specified; otherwise treated as failure) any other stop failed Remarks: If LFC_A_ASYNC_CPLT is specified, the recipient may return CMST_PENDING and complete the stop later by sending EVJFCjMFY STOP CPLT. In case stop fails, the recipient should still clean up as much as possible -- in many cases, stop failures are ignored (e.g., NT kernel mode drivers are unloaded, even if they fail to stop properly). EV LFC NFY START CPLT Overview: This event indicates that the starting procedure has completed. The event is used when an asynchronous completion is needed and complements EV_LFC_REQ_START event. Description: Start has completed Event Bus EVENT (BjΞVJFC) Definition: cmstat cpltjs; // completion status // (asynchronous completion) END EVENT Data: cplt s completion status Return The return status is ignored Status: Remarks: Start has completed successfully if cplt_s is CMSTJDK, failed otherwise this event is sent in response to EV_LFC_REQ_START on which CMST_PENDING was returned; it goes in the opposite direction of EV_LFC_REQ_START EV LFC NFY STOP CPLT Overview: This event indicates that the stopping procedure has completed. The event is used when an asynchronous completion is needed and complements EV_LFC_REQ 3TOP event. Description: Stop has completed Event Bus EVENT (B_EV_LFC) Definition: cmstat cplt s; // completion status // (asynchronous completion) END EVENT Data: cpltjs completion status Return The return status is ignored Status: Remarks: Stop has completed successfully if cpltjs is CMSTJDK, failed otherwise this event is sent in response to EV_LFC_REQ_STOP on which CMST_PENDING was returned; it goes in the opposite direction of EV_LFC_REQ_STOP In case stop fails, the sender should still clean up as much as possible — in many cases, stop failures are ignored (e.g., a file handle becomes invalid even if close failed). EV PRP REQ Overview This event is used to request a part to execute a property operation. All of the standard DriverMagic property operations are supported and are specified in the event as an op-code. The input and output parameters for each operation is dependent upon the op-code. Each property operation is described below. Event Bus EVENTX (B_EV_PRP, EV_PRP_REQ, CMEVT_A_DFLT, CMEVT UNGUARDED) uint32 cplt_s ; // completion status, [CMST_xxx] _ctx context ; // IOCTL context uint32 opcode ; // property operation code, // [PROPJDP_xxx] Jidl qryh ; // query handle char name[64] ; // property name uint1 6 type ; // property type, [CMPRP T XXX] flg32 prpjattr ; // property attributes, [CMPRP A XXX] flg32 attrjnask; // property attribute mask, // [CMPRP_A_XXX] uint32 size ; // size of data in bytes uint32 len ; // length of data in bytes byte data[1 ] ; // buffer for property value ENDjΞVENTX PROPJDPJ3ET Description: Get a property In: context 32-bit context opcode operation id, [PROPJDPJ3ET] name null-terminated property name type type of the property to retrieve or CMPRPJJNONE for any size size of data, [bytes] data[] buffer to receive property value Out: cplt_s completion status, [CMSTJKXX] len length of data returned in data[] data property value Return CMST OK success Status: CMST_REFUSE the data type does not match the expected type CMST NOT FO unknown property UND CMSTJDVERFLO the buffer is too small to hold the W property value PROP_OP_SET Description: Set a property In: context 32-bit context opcode operation id, [PROP OP SET] name null-terminated property name type property type, [CMPRP_T_XXX] len length [in bytes] of data stored in data data[] property value Out: cpltjs completion status, [CMST xxx] Return CMST OK success Status: CMST_NOT_FO unknown property UND CMSTJDVERFLO the property value is too large W CMST_REFUSE the property type is incorrect or the property cannot be changed while the part is in an active state CMST_OUT_OF_ the property value is not within the RANGE range of allowed values for this property CMST_BAD_AC there has been an attempt to set a CESS read-only property PROP OP CHK Description: Check if a property can be set to the specified value In: context 32-bit context opcode operation id, [PROP OP CHK] name null-terminated property name type type of the property value to check len size in bytes of property value data[] buffer containing property value Out: cpltjs completion status, [CMST <xx] Return CMST OK successful Status: CMST NOT FO the property could not be found or the UND id is invalid CMSTJDVERFLO the property value is too large W CMST REFUSE the property type is incorrect or the property cannot be changed while the part is in an active state CMST DUTJDF the property value is not within the RANGE range of allowed values for this property CMSTJ3AD AC there has been an attempt to set a CESS read-only property PROP OP GET INFO Description: Retrieve the type and attributes of the specified property In: context 32-bit context opcode operation id, [PROP OPJ3ETJNFO] name null-terminated property name Out: cpltjs completion status, [CMST xxx] type type of property, [CMPRP_T_XXX] prpjattr property attributes, [CMPRP_A_XXX] Return CMST OK successful Status: CMSTjMOT FO the property could not be found UND PROPJDP_ QRY OPEN Description: Open a query to enumerate properties on a part based upon the specified attribute mask and values or CMPRP A NONE to enumerate all properties In: context 32-bit context opcode operation id, [PROPJDP QRYJDPEN] name query string (must be " * ") prpjattr attribute values of properties to include attr mask attribute mask of properties to include Out: cpltjs completion status, [CMST xxx] qryh query handle Return CMST OK successful Status: CMSTjMOT SUP the specified part does not support PORTED property enumeration or does not support nested or concurrent property enumeration Remarks: To filter by atrributes, specifiy the set of attributes in attrjnask and their desired values in prpjattr. During the enumeration, a bit-wise AND is performed between the actual attributes of each property and the value of attrjnask; the result is then compared to prpjattr. If there is an exact match, the property will be enumerated. To enumerate all properties of a part, specifiy the query string as " *", and attrjnask and prpjattr as 0. The attribute mask can be one or more of the following: CMPRP_A_NONE - not specified CMPRP_A_PERSIST - persistent property CMPRP_A_ACTIVETIME - property can be modified while active CMPRP AJV1ANDATORY - property must be set before activation CMPRP AJ.DONLY - read-only property CMPRP A UPCASE - force uppercase CMPRP_A_ARRAY - property is an array PROP OP QRY CLOSE Description: Close a query In: context 32-bit context opcode operation id, [PROPJDPJDRYJDLOSE] qryh query handle Out: cpltjs completion status, [CMST xxx] Return CMSTJDK successful Status: CMST_NOT_FOU query handle was not found or is ND invalid CMSTJ3USY the object can not be entered from this execution context at this time PROP OP QRY FIRST Description: Retrieve the first property in a query In: context 32-bit context opcode operation id, [PROP OP QRY IRST] qryh query handle returned on PROPJDPjQRYJDPEN size size in bytes of data data[] storage for the returned property name Out: cpltjs completion status, [CMST xxx] data property name if size is not 0 len length of data (including null terminator) Return CMSTJDK successful Status: CMSTjNIOT FOU no properties found matching current ND query CMSTJDVERFLO buffer is too small for property name W PROP OP QRY_ NEXT Description: Retrieve the next property in a query In: context 32-bit context opcode operation id, [PROPJDP QRY NEXT] qryh query handle returned on PROPJDP QRY OPEN size size in bytes of data data[] storage for the returned property name Out: cpltjs completion status, [CMST_xxx] data property name if size is not 0 len length of value (including null terminator) Return CMST OK successful Status: CMST NOTJOU there are no more properties that ND match the query criteria CMSTJDVERFLO buffer is too small for property name W PROP OP QRY CURR Description: Retrieve the current property in a query In: context 32-bit context opcode operation id, [PROP OPJDRYj URR] qryh query handle returned on PROPJDP QRYJDPEN size size in bytes of data data[] storage for the returned property name Out: cpltjs completion status, [CMST xxx] data property name if size is not 0 len length of value (including null terminator) Return CMST OK successful Status: CMSTJMOT FOU no current property (e.g. after a call to ND PROPJDPJD-RYJDPEN) CMSTJDVERFLO buffer is too small for property name W EV PULSE Overview: EV_PULSE is a generic event that gives a recipient an opportunity to execute in the sender's execution context. Description: Gives recipient an opportunity to execute in sender's execution context. Event Bus uses CMEVENT HDR/CMEvent Definition: Return CMST OK recipient executed OK Status: CMST NO ACTI recipient didn't have any action to be ON performed Remarks: This event is typically distributed only synchronously. A sender of this event may re-send the event until CMST NO ACTION is returned, allowing the receipient to complete all pending actions'. This chapter provides details on the events used by WDK. The first three events are extensions to the standard life-cycle event set provided by DriverMagic. These operate on the same bus and their event IDs are binary compatible with the standard life-cycle event IDs. The third event EV_REQJRP is a request to process IRP. This event is the fundamental carrier of request packets entering the driver. The ownership of the IRP travels with the event. The next seven events are used to request operations on device drivers. Each event corresponds to an operation on the I DIO interface. These events are mainly used for communication with other device drivers. The last three events are used for keyboard interaction. Only the DM A2K part uses these events. All requests can be completed synchronously or asynchronously (default). Some parts may refuse operation if asynchronous completion is not allowed. If this creates a problem, use DMJ^SB part from the Advanced Part Library. For more information, consult the DM_RSB data sheet in the Advanced Part Library documentation. In case of asynchronous completion, the same event is sent back with CMEVT A COMPLETED attribute set, to indicate that the processing of the event is complete. EV LFC REQ DEV PAUSE Overview: This is a request to pause the operation with the device. Recipients of this event may process it synchronously or asynchronously. In the later case they have to issue the same event with CMEVT A COMPLETED attribute set. Description: Request to pause the device Event Bus EVENT (BjΞVJFC) Definition: cmstat cpltjs; // completion status // (asynchronous completion) END EVENT Data: cpltjs Completion status attr CMEVT_A_ASYNC_CPLT - if asynchronous completion is allowed CMEVT_A_COMPLETED - if the event is a completion event. Return CMST PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back the same event with CMEVT_A_COMPLETED set) Remarks This event is defined in ejfcjax.h. EV LFC REQ DEV RESUME Overview: This is a request to resume the operation with the device. Recipients of this event may process it synchronously or asynchronously. In the later case they have to issue the same event with CMEVT A COMPLETED attribute set. Description: Request to resume the device Event Bus EVENT (B EVJFC) Definition: cmstat cpltjs; // completion status // (asynchronous completion) END EVENT Data: cpltjs Completion status attr CMEVT_A_ASYNC_CPLT - if asynchronous completion is allowed CMEVT_A_COMPLETED - if the event is a completion event. Return CMST PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back the same event with CMEVT A COMPLETED set) Remarks This event is defined in ejfc ex.h. EV LFC NFY DEV REMOVED Overview: This is a post-notification that the device has been removed. Recipients of this event may process it only synchronously. In no event recipients of this event can access the hardware device - at the time this event is sent, the hardware device may have been unplugged. Description: Notification that the device has been removed. Event Bus EVENT (BjΞVJFC) Definition: cmstat cpltjs; // completion status // (asynchronous completion) END EVENT Remarks This event is defined in ejfc ex.h. This event is a notification and cannot be completed asynchronously. EV REQ IRP Overview: This event indicates that an IRP (I/O request packet) needs processing. Recipients of this event may process it synchronously or asynchronously. In the later case they have to issue the same event with CMEVT A COMPLETED attribute set. Description: Process the I/O request Event Bus EVENTX (B_EV IRP, EV REQJRP, CMEVT_A_NONE, Definition: CMEVT JJNGUARDED) dword devid ; // instance ID void *irpp ; // pointer to IRP cmstat cplt s; // completion status END EVENTX Data: devid ID of the instance that should process the request irpp pointer to IRP (NT I/O request packet) Return CMST_PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back an EV REQJRP event with CMEVT A COMPLETED set) Remarks: The value of devid is implementation-specific. This event is defined in ejrp.h. EV KBD EVENT Overview: This event is sent when keyboard data is present either from the user pressing a key or another part emulating keystrokes. Description: Notifies that the specified keyboard event has occurred. Event Bus EVENTX (BjΞV KBD, EV KBD EVENT, Definition: CMEVT_A 3ELF_CONTAINED | CMEVT_A 3YNC, CMEVTjJNGUARDED) uintl 6 data; // keyboard event data (raw data // or shift state) uintl 6 flags; // KBD_F_xxx uint32 timejdelta; // time since the previous event // (msec) uint32 dev_data[4]; // originator-specific data, do // not modify END EVENTX Data: attr event attributes - CMEVT_A_CONST and/or KBD_A_DEVICE_KBD (indicates event is generated by actual device) data keyboard data (device-specific) flags keyboard flags, may be one or more of the following: KBD Fj3R indicates that the event is EAK a "key release" event KBD_F_E0 OxeO prefix was sent with key (AT-keyboard specific and may be ignored if not needed) KBD_F_E1 0xe1 prefix was sent with key (AT-keyboard specific and may be ignored if not needed) time delta time [in msec] since the previous event. If there was no previous event or the time since the previous event exceeds the size of a 32-bit integer, time delta is set to Oxffffffff . This field is optional and not all event sources have to support it. dev data[] originator context data, must be preserved by recipients of this event. Event filters that process EV_KBD_EVENTs should pass this data on unchanged. Return CMST OK event was processed successfully Status: CMST NOT SUP the recipient does not support new PORTED event insertion (may be returned if KBD_A_DEVICE_EVT attribute is not set) (other) other (valchk/fatal) errors may be returned if receiver cannot process event Remarks: if a "fake" keyboard event is initiated by a non-keyboard part, it should set the dev_data[] fields to 0. The "fake" event is recognized by the KBD_A J E VI CEJΞVT flag in the attr field - it is 0 for such events and 1 for actual device events. Support for "fake" events may be limited by operating system (or other) restrictions. EV KBD STATE NFY Overview: This event is sent when the state of the shift, control, alt or lock (scroll, num and caps) keys of the keyboard has changed. Description: Notifies that the keyboard's shift keys are in the specified state. Event Bus EVENTX (B EV KBD, EV_KBD_EVENT, Definition: CMEVT_A_SELF_CONTAINED | CMEVT_A_SYNC, CMEVT UNGUARDED) uintl 6 data; // keyboard event data (raw data // or shift state) uintl 6 flags; // KBD _F_xxx uint32 timejdelta; // time since the previous event // (msec) uint32 devjdata[4]; // originator-specific data, do // not modify END EVENTX Data: attr event attributes - CMEVT_A_CONST and/or KBD A DEVICE KBD (indicates event is generated by actual device) data bit flag specifying current shift and lock state, may be one or more of the following: KBD SFJ.SHIF Right shift pressed T KBD SF LSHIF Left shift pressed KBD 3F_CTRL Control pressed KBD SF ALT Alt pressed KBD_SF_SCRO Scroll lock on LL KBD SFjMUM Num lock on KBD SF CAPS Caps lock on flags bit mask specifying which of the bits in data are valid (if a bit is '0' in flags, the corresponding bit in data should be ignored) EV KBD GET STATE Overview: This event is sent to find out the current state of the shift, control, alt and lock state (scroll, num and caps) of the keyboard. Description: Request current shift and lock state. Event Bus EVENTX (B EV KBD, EVjXBD EVENT, Definition: CMEVT_A_SELF_CONTAINED | CMEVT_A_SYNC, CMEVT JJNGUARDED) uintl 6 data; // keyboard event data (raw data // or shift state) uintl 6 flags; // KBD F xxx uint32 timejde.ta; // time since the previous event // (msec) uint32 devjdata[4]; // originator-specific data, do // not modify END EVENTX Data: data bit flag specifying current shift and lock state, may be one or more of the following: KBD 3F_RSHIF Right shift pressed T KBD_SF LSHIF Left shift pressed T KBD 3F_CTRL Control pressed KBD_SF_ALT Alt pressed KBD_SF_SCRO Scroll lock on LL KBD_SFJMUM Num lock on KBDj3F_CAPS Caps lock on flags bit mask specifying which of the bits in data are valid (if a bit is '0' in flags, the corresponding bit in data should be ignored) Return CMST OK event was processed successfully Status: CMST NOT SUP the recipient does not support the PORTED request (other) other (valchk/fatal) errors may be returned Device I/O Events - Notes The following notes apply to all the device I/O events defined below: 1 . The term 'object' is used below to refer to the entity on which the I/O operations are performed. This can be a file, a device, a pipe or any similar entity. 2. The devjd field in the BJΞVJDIO bus can be used to identify the instance that should handle the operation. The use of this field is optional. It is intended as storage for a part or connection ID in one- to-many connections. Its use is not explicitly defined here. 3. The devj field in the BJΞVJDIO bus is usually a handle of a device or of a file opened on the device. 4. All EVj3IO_RQ_xxx requests can be completed asynchronously, provided that the originator has set the CMEVT _A_ASYNCjCPLT attribute. To complete a request asynchronously, recipient should perform the following actions: a) save the event bus pointer b) return CMST_PENDING c) if necessary, use the event bus during processing (the event bus is exclusively available to the part that is processing the request) d) when request is completed, use the saved bus pointer and fill in the completion status (cpltjs) fill in all fields specified as 'out' for the request - set the CMEVT_A_COMPLETED attribute (all other fields, esp. ctx, must be preserved) send the completion event (typically out the terminal through which the request was received). If the CMEVT A ASYNC CPLT attribute is not set, the request must be completed synchronously. 5. The ctx field is used by the request originator to store its context. This value is not to be interpreted or modified by any part that processes the event, unless the originator has set the DIO_A_NTJRP attribute to indicate that ctx contains a pointer to a NT driver IRP (I/O request packet) associated with the event. The DIO_A_NTJRP attribute shall be clear if ctx does not contain pointer to a valid IRP. 6. (Note specific to Windows NT kernel mode and WDM environments) If ctx contains pointer to NT driver IRP, the rules for intermediate drivers apply to the processors of the EV_DIO_RQ cxx request: they can use the next and lower stack locations. In no case the IRP should be completed. If the IRP's next stack location is used to call a lower- level driver in the device's stack, the caller must set a completion routine and prevent full completion of the IRP -- the request should be completed according to note #4 above. 7. The DIO_A_UNICODE attribute can be set on EV_DI0_RQ 3PEN to indicate that the object name pointed by buf jp is a Unicode string. Note that in Windows NT kernel mode and WDM environments, the string may not be zero-terminated; the length is always correctly specified in buf Jen (in bytes, excluding any zero terminator). If the DIO A UNICODE attribute is not set, buf p on EV DIO RQ OPEN is either NULL or points to a valid O-terminated ASCII string. If buf p is NULL, DIO_A_UNICODE should not be set. EV DIO RQ OPEN Overview: This event is used to open a specific device driver or file. The entity being opened is identified by a path specified with the event. The format of the path is defined by the operating system. Description: Open a device or file object. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 dev id ; // device instance // identification Jdl devj ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 buf sz ; // size of buffer pointed to // by p, [bytes] uint32 bufjen ; // length of data in *buf jp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) buf p name of object to open (may be NULL) (see note #7) buf len length of data pointed to by ' buf jp' (without the terminating 0), [bytes] buf h device handle to pass on subsequent operations (out) Return CMSTJMOT OU specified object not found Status: ND CMST_ACCESS_ object already open (if multiple opens DENIED are not supported) Remarks: Named object support and the naming conventions are outside the scope of this interface. If DIO A UNICODE is specified, buf p is to be interpreted as WCHAR * and the string may not be O-terminated. EV DIO RQ CLEANUP Overview: This request is sent to cancel all pending operations on a specific device driver and to prepare it for closing. Description: Cancel all pending operations, prepare for close. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 devjd ; // device instance // identification Jidl dev ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 buf j3z ; // size of buffer pointed to // by p, [bytes] uint32 buf Jen ; // length of data in * buf jp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) dev h device handle from 'open' Return CMSTjNOT OPE object is not open Status: N Remarks: No operations exc. 3pt 'close' should be 'cleanup' . EV DIO RQ CLOSE Overview: This request is sent to close a specific deivce driver or file. Description: Close a device object. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 devjd ; // device instance // identification Jdl devji ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 buf J3Z ; // size of buffer pointed to // by p, [bytes] uint32 buf Jen ; // length of data in * buf jp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) dev h device handle from 'open' Return CMSTJMOTJDPE object is not open Status: N CMSTJOERR I/O error (object is closed anyway) EV DIO_RQ_READ Overview: This request is sent to read data from a specific device driver or file. Description: Read data from device. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 devjd ; // device instance // identification Jidl devj ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 buf _sz ; // size of buffer pointed to // by p, [bytes] uint32 bufjen ; // length of data in *bufjp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) dev h device handle from 'open' offs file offset (for block devices) bufjp buffer pointer buf sz size of buffer, bytes buf Jen number of bytes read (out) * buf jp data read (out) Return CMSTjMOT OPE object is not open Status: N CMSTJOERR I/O error Remarks: Reading at end of a stream is usually not considered an error; in this case the request is completed with buf Jen 0 (or any value less than bufjsz). EV DIO RQ WRITE Overview: This request is sent to write data to a specific device driver or file. Description: Write data to device. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 devjd ; // device instance // identification Jdl dev ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 buf _sz ; // size of buffer pointed to // by p, [bytes] uint32 buf Jen ; // length of data in * buf jp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) dev h device handle from 'open' offs file offset (for block devices) buf jp pointer to data to be written buf sz number of bytes to write buf Jen number of bytes written (out) Return CMSTJMOT OPE object is not open Status: N CMSTJOERR I/O error CMST_FULL media full (for block devices only) EV DIO RQJOCTL Overview: This request is sent to execute a specific operation on a device driver. The operation is defined by the driver. This type of I/O control can be sent to a driver by another driver or an application (user-mode). Description: Execute an I/O control operation on a device. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 devjd ; // device instance // identification Jidl devji ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 buf jsz ; // size of buffer pointed to // by p, [bytes] uint32 buf Jen ; // length of data in * buf jp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) devji device handle from 'open' func I/O control function code buf p pointer to input data and buffer for output data buf sz size of output buffer, bytes buf len length of input and output data in bytes Return CMSTjNOTJDPE object is not open Status: N CMSTJOERR I/O error CMST NOT SUPP the specified I/O control code is not ORTED supported Remarks: The definition of the I/O control operations is outside the scope of this definition. EV DIO RQJNTERNAL IOCTL Overview: This request is sent to execute a specific internal operation on a device driver. The operation is defined by the driver. This type of I/O control can only be sent to a driver from another driver, not by an application (user-mode). Description: Execute an internal I/O control operation on a device. Event Bus EVENT (B EV DIO) Definition: cmstat cpltjs ; // completion status // (asynchronous completion) dword ctx ; // originator's context value // (may be IRP) uint32 devjd ; // device instance // identification Jdl dev ; // device handle uint32 func ; // function code (for IOCTL) LARGEJNTEGER offs ; // file offset (for block // devices) void * buf jp ; // pointer to data uint32 bufjsz ; // size of buffer pointed to // by p, [bytes] uint32 buf Jen ; // length of data in * buf jp, // [bytes] END EVENT Data: dev id device instance identification (see note #2 above) dev _h device handle from 'open' func internal I/O control function code buf_ _P pointer to input data and buffer for output data buf_ sz size of output buffer, bytes buf len length of input and output data in bytes Return CMSTjMOTJDPE object is not open Status: N CMSTJOERR I/O error CMSTjMOTjSUPP the specified I/O control code is not ORTED supported Remarks: The definition of the I/O control operations is outside the scope of this definition. "internal IOCTL" is a Windows NT driver term. Device lOCTL's can be submitted to drivers by an application or by another driver. Internal lOCTL's can be submitted only by other drivers. The main implication is that, for internal lOCTL's, the buffers are always mapped properly in system address space (i.e., the buffer pointed by bufjp is accessible in arbitrary thread context). EV USBCTL REQ Overview: This event is used to send vender or class-specific command requests to a USB device. This request can complete synchronously or asynchronously. This event should never be sent with the CMEVT_A_SELFJDWNED attribute set. Description: Send a vendor or class-specific command to a USB device. Event Bus EVENTX (B_EV_USB_CTLREQ, Definition: EVJJSBCTLJ-EQ, CMEVT_A_SELF_CONTAINED, CMEVT UNGUARDED) cmstat cpltjs ; // completion status uint32 func ; // request type // (USB_REQ_xxx) uint32 njOsv bits; // additional function bits // (not used - must be 0) uint32 code ; // Specifies the USB or // vendor- defined request // code for the device uint32 value ; // Is a value, specific to // Request, that becomes // part of the USB-defined // setup packet for the // device uint32 index ; // Specifies the device- // defined identifier for // the request uint32 datajen ; // length of the data in the // buffer uint32 datajsz ; // data buffer size byte data[1] ; // data buffer END EVENTX In: attr USB A XFER TO xxx specifies the control request direction func function number (must be one of URB_FUNCTION_VENDOR_xxx or URB FUNCTION CLASS xxx) code Specifies the USB or vendor-defined request code for the device value specific to code value index specifies the device-defined identifier for the request data len length of the data in the buffer (only for USB_A_XFER_TOJDEVICE requests) datajsz data buffer size data data buffer variable size Out: cpltjs completion status len datajen data returned from USB_A_XFER_TO_HOST requests data Return CMST_PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back an EV_USBCTL_REQ event) EV USB ENABLE Overview: This event is sent to enable the isochronous USB stream. This request can complete synchronously or asynchronously. This event should never be sent with the CMEVT A SELF OWNED attribute set. Description: Enable isochronous USB stream. Event Bus EVENTX (B EV USBCTL, Definition: EV USBjΞNABLE, CMEVT_A_ASYNC_CPLT | CMEVT_A_SELF_CONTAINED | CMEVT_Aj3YNC, CMEVT JNGUARDED) cmstat cpltjs ; // completion status uint32 frame_no ; // isochronous frame number to // start from bool32 asap ; // TRUE - start ASAP. FALSE - // use O.framejio to start from uint32 cfgjio ; // configuration number. Not // used. // (must be -1 undefined) END EVENTX In: frame no isochronous frame number to start from, (only if asap is FALSE) asap TRUE - enable ASAP, ignoring the frame number. Out: cplt s enable completion status Return CMST PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back an EV USB ENABLE event) EVJJSB DISABLE Overview: This event is sent to disable the isochronous USB stream. This request can complete synchronously or asynchronously. This event should never be sent with the CMEVT A SELF OWNED attribute set. Description: Disable isochronous USB stream. Event Bus EVENTX (B EV USBCTL, Definition: EVJJSBJDISABLE, CMEVT A ASYNCjCPLT | CMEVT_A 3ELF_CONTAINED | CMEVT_A_SYNC, CMEVT JJNGUARDED) cmstat cpltjs ; // completion status uint32 framejio ; // isochronous frame number to // start from bool32 asap ; // TRUE - start ASAP. FALSE - // use O.framejio to start from uint32 cfg no ; // configuration number. Not // used. // (must be -1 undefined) END EVENTX In: void Out: cpltjs disable completion status Return CMST_PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back an EVJJSB DISABLE event) EVjSTM DATA Overview: This event is sent to submit an isochronous USB data frame. This request can complete synchronously or asynchronously. This event should never be sent with the CMEVT_A_SELFJDWNED attribute set. Description: Submit an isochronous USB data frame. Event Bus EVENTX (B_EV_STM_DATA, Definition: EV_STM_DATA, CMEVT_A_ASYNC_CPLT | CMEVT_Aj3ELF_CONTAINED | CMEVT A SYNC, CMEVT JJNGUARDED) cmstat cpltjs ; // data completion status uint32 framejio ; // current isochronous frame // number uint32 datajen ; // data length uint32 datajsz ; // data buffer size _ctx ownerjDtx; // owner context byte data[1 ] ; // data buffer (variable size) END EVENTX In: framejio current isochronous frame number owner_ctx owner context datajen data length datajsz data buffer size data submitted out data data data buffer (variable size) Out: cpltjs current status owner ctx owner context (caller supplied) Return CMST PENDING callee assumes responsibility to Status: complete the request later (either directly or by sending back an EVJJSBJDISABLE event) EV VXD JNIT Overview: This packaging event is used to signal that the virtual device was loaded by the system and can perform its initialization tasks. Description: Initialize virtual device Event Bus EVENT ( BjΞV VXD ) Definition: dword msg; // control message (value of EAX register) dword ebx; // value of EBX register dword ecx; // value of ECX register dword edx; // value of EDX register dword esi; // value of ESI register dword edi; // value of EDI register dword retval; // value to return // (also affects carry flag) END EVENT Data: void Return CMST OK initialized OK Status: any other initialization failed Remarks: This event is issued at thread time, before SYSJDYNAMICJDEVICEJNIT (for dynamic VxDs) or DEVICEJNIT (for static VxDs). Some EV VXD MESSAGE events may be sent before this event. See Also: EV VXD CLEANUP EV VXD CLEANUP Overview: This packaging event is used to signal that the virtual device is about to be unloaded by the system and should perform its cleanup tasks. Description: Cleanup virtual device Event Bus EVENT ( BjΞVJ XD ) Definition: dword msg; // control message (value of EAX register) dword ebx; // value of EBX register dword ecx; // value of ECX register dword edx; // value of EDX register dword esi; // value of ESI register dword edi; // value of EDI register dword retval; // value to return // (also affects carry flag) END EVENT Data: void Return CMST OK cleanup completed, OK to unload Status: any other cleanup failed - don't unload Remarks: This event is issued at thread time, after the SYSJDYNAMIC DEVICE EXIT. It is not sent for static VxDs. See Also: EV VXDJNIT EV VXD MESSAGE Overview: This packaging event is used to distribute raw VxD messages as they are sent by the system. Description: Raw message needs processing Event Bus EVENT ( B_EV_VXD ) Definition: dword msg; // control message (value of EAX register) dword ebx; // value of EBX register dword ecx; // value of ECX register dword edx; // value of EDX register dword esi; // value of ESI register dword edi; // value of EDI register dword retval; // value to return // (also affects carry flag) END EVENT Data: void Return < see Remarks > cleanup completed, OK to unload Status: Remarks: This event may come in any context, including on disabled interrupts. Upon return, the status and retval are interpreted the following way: for all control messages except PNPJMEWJDEVNODE and W32JDEVICEIOCONTROL: If returned status is not CMST OK: EAX is set to 0, carry set If returned status is CMST OK, EAX is set to retval and If retval is non-zero (VXD SUCCESS), carry is cleared If retval is zero (VXD FAILURE), carry is set to indicate error for the PNPJMEWJDEVNODE and W32JDEVICEIOCONTROL control messages If returned status is not CMST OK: EAX is set to -1 , carry set If returned status is CMSTJDK, EAX is set to retval and If retval is zero (CR SUCCESS/DEVIOCTLj OERROR), carry clear If retval is non-zero, carry is set to indicate error Note that, on W32JDEVICEIOCONTROL, retval has the following meanings: 0 - success -1 - operation accepted for asynchronous processing any other - error EV DRV JNIT Overview: This packaging event is used to signal that the driver was loaded by the system and can perform its initialization tasks. Description: Initialize driver Event Bus EVENT (B_EV_DRV) Definition: NTSTATUS ns; END EVENT Data: ns status that DriverEntry will return on failure Return CMST OK initialized OK Status: any other initialization failed Remarks: This event is issued at thread time, IRQ level passive The value returned from DriverEntry is determined as follows: if event returned CMSTJDK, DriverEntry returns STATUS SUCCESS, regardless of ns if event returned CMST JAILED, DriverEntry returns ns (unless ns is STATUS SUCCESS, in which case DriverEntry returns STATUS JINSUCCESSFUL) if event returned any other status, DriverEntry returns STATUS UNSUCCESSFUL. See Also: EV_DRV_CLEANUP EV DRV CLEANUP Overview: This packaging event is used to signal that the driver is about to be unloaded by the system and should perform its cleanup tasks. Description: Cleanup driver Event Bus EVENT (BjΞVJDRV) Definition: NTSTATUS ns; END EVENT Data: void Return CMST OK cleanup OK Status: any other cleanup failed Remarks: This event is issued at thread time, IRQ level passive Regardless of the returned status, the driver will be unloaded. See Also: EV DRV INIT The present invention therefore provides a novel system of reusable software parts for implementing concurrency and hardware access, and methods of use for same. Although the present invention has been shown and described with respect to preferred embodiments, various changes and modifications lie within the spirit and scope of the claimed invention. Thus, the corresponding structures, materials, acts, and equivalents of all means or step plus function elements in the claims are intended to include any structure, material, or acts for performing the functions in combination with other elements as specifically claimed.

Claims: CLAIMS What is claimed is: 1 . A method for designing access to a hardware component in a component-based software system, said method comprising the steps of: designating a first software component for receiving interrupts from said hardware component; designating a at least a second software component for accessing input and output ports of said hardware component; designating a third software component for handling interrupts received by said first software component; designating a fourth software component for manipulating said hardware component; connecting said first software component to said third software component; connecting said second software component to said fourth software component. 2. The method in claim 1 wherein said method further comprises the step of connecting said third software component and said fourth software component. 3. The method in claim 1 wherein said third software component and said fourth software component are one component. 4. A part in a software system, said part comprising: a first terminal for sending out calls; a section of program code for receiving control when an interrupt occurs and sending out a call through said first terminal. 5. The part of claim 4 wherein said part further comprises a property for configuring which hardware interrupt vector among a plurality of hardware interrupt vectors said part should receive. 6. The part of claim 4 wherein said part further comprises a section of program code for registering said part to receive control when said interrupt occurs. 7. A part in a software system, said part comprising: a terminal for receiving requests to access at least one port of a hardware component; a property defining the base address of said port; a section of code that accesses said port when a request is received on said first terminal. 8. The part of claim 7 wherein said port is a memory-mapped port. 9. The part of claim 7 wherein said port is a input-output port. 10. The part of claim 7 wherein said requests include a read request and a write request. 1 1 . A structure of connected parts in a software system, said structure comprising: an interrupt source part for receiving interrupt from a hardware component; at least one port accessor part for accessing ports of said hardware component; at least one controller part for controlling said hardware component. 1 2. The structure of claim 1 1 wherein said controller part accesses said hardware component exclusively through said interrupt source part and said port accessor part. 1 3. The structure of claim 1 1 wherein said structure further comprises: a connection between said interrupt source part and one of said controller parts; a connection between one of said port accessor parts and one of said controller parts. 14. A composite part in a software system, said composite part containing the structure of claim 1 1 . 1 5. A composite part in a software system, said composite part containing the structure of claim 1 2. 1 6. In a software system, a part comprising: a first terminal for sending out events in the context of a thread of execution designated by said part; a second terminal for receiving events that control the operation of said part. 17. The part in claim 1 6 wherein said first terminal and said second terminal are one terminal. 18. The part in claim 1 6 wherein said part further comprises a thread object. 19. The part in claim 16 wherein said part further comprises a means for providing said thread of execution. 20. In a software system, a part comprising: a first terminal for sending out events upon the expiration of a time interval. 21 . The part in claim 20 wherein said part further comprises a second terminal for receiving events that control the operation of said part. 22. The part in claim 20 wherein said part further comprises a timer object. 23. The part in claim 20 wherein said part further comprises an interrupt source. 24. The part in claim 20 wherein said part sends events out through said first terminal periodically with a specified time interval between events. 25. In a software system, a part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded. 26. The part in claim 25 wherein said means are a synchronization object. 27. The part in claim 25 wherein said means comprise a third terminal for delegating said prevention to another part. 28. The part in claim 25 further comprising a third terminal for accepting delegation of said prevention. 29. The part in claim 27 further comprising a fourth terminal for accepting delegation of said prevention. 30. A system for protecting parts or structures of parts from being entered by more than one thread of execution at a time, said system comprising: a first part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded, wherein said means comprise a third terminal for delegating said prevention to another part; a second part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded; a third terminal for accepting delegation of said prevention; and a connection between said first part and said second part. 31 . In a software system, a part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a first means for indicating that flow of control is entering said part; a second means for indicating that flow of control is returning back from said part. 32. The part in claim 31 wherein said first means and said second means are one terminal. 33. A system for protecting parts or structures of parts from being entered by more than one thread of execution at a time, said system comprising: a first part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded, wherein said means comprise a third terminal for delegating said prevention to another part; a second part comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a first means for indicating that flow of control is entering said part; a second means for indicating that flow of control is returning back from said part; and a connection between said first part and said second part. 34. A system for protecting parts or structures of parts from being entered by more than one thread of execution at a time, said system comprising: a first and a second part, each comprising: a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a first means for indicating that flow of control is entering said part; a second means for indicating that flow of control is returning back from said part; a third part comprising a first terminal for receiving incoming interactions; a second terminal for forwarding interactions received on said first terminal; a means for preventing interactions received in a first thread of execution from being forwarded to said second terminal while an interaction received in a second thread of execution is being forwarded; a third terminal for accepting delegation of said prevention; a first connection between said first part and said third part; a second connection between said second part and said third part. 35. In a software system, a part comprising: a first terminal for accepting a first asynchronously completeable request; a second terminal for accepting events; a memory for holding said first asynchronously completeable request; a first means for recognizing a sequence of one or more events received on said second terminal; a second means for completing said first asynchronously completeable request. 36. The part in claim 35 wherein said memory can hold multiple requests.

Inventors: MILOUSHEV VLADIMIR I, NICKOLOV PETER A, MILOUSHEV, VLADIMIR, I., NICKOLOV, PETER, A.
Applicants: FORCE CORP Z, MILOUSHEV VLADIMIR I, NICKOLOV PETER A, MILOUSHEV, VLADIMIR, I., NICKOLOV, PETER, A., Z-FORCE CORPORATION
Application year: 2000
Main classification: G06F9
IPC codes: G06F9