123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- intrface.c
- Abstract:
- This module implements support for device interfaces.
- Author:
- Evan Green 19-Sep-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include "iop.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines an interface directory, which contains device
- interface instances and listeners.
- Members:
- Header - Supplies the standard object manager header.
- Uuid - Supplies the UUID of the interface.
- --*/
- typedef struct _INTERFACE_DIRECTORY {
- OBJECT_HEADER Header;
- UUID Uuid;
- } INTERFACE_DIRECTORY, *PINTERFACE_DIRECTORY;
- /*++
- Structure Description:
- This structure defines a device interface instance.
- Members:
- Header - Stores the object manager header.
- Device - Stores a pointer to the device this interface is attached to.
- InterfaceBuffer - Stores a pointer to the interface buffer.
- InterfaceBufferSize - Stores the size of the interface buffer.
- --*/
- typedef struct _DEVICE_INTERFACE_INSTANCE {
- OBJECT_HEADER Header;
- PDEVICE Device;
- PVOID InterfaceBuffer;
- ULONG InterfaceBufferSize;
- } DEVICE_INTERFACE_INSTANCE, *PDEVICE_INTERFACE_INSTANCE;
- /*++
- Structure Description:
- This structure defines an interface listener.
- Members:
- Header - Stores the standard object manager header.
- CallbackRoutine - Stores a pointer to the listener's callback routine.
- Device - Stores an optional pointer to a specific device to listen to.
- Context - Stores a pointer supplied by and passed back to the interface
- listener during notifications.
- --*/
- typedef struct _INTERFACE_LISTENER {
- OBJECT_HEADER Header;
- PINTERFACE_NOTIFICATION_CALLBACK CallbackRoutine;
- PDEVICE Device;
- PVOID Context;
- } INTERFACE_LISTENER, *PINTERFACE_LISTENER;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- IopNotifyInterfaceListeners (
- PINTERFACE_DIRECTORY InterfaceDirectory,
- PDEVICE_INTERFACE_INSTANCE InterfaceInstance,
- PDEVICE Device,
- BOOL Arrival
- );
- VOID
- IopPrintUuidToString (
- PSTR String,
- ULONG StringSize,
- PUUID Uuid
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store a pointer to the directory of all exposed interfaces.
- //
- POBJECT_HEADER IoInterfaceDirectory = NULL;
- PQUEUED_LOCK IoInterfaceLock = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- KERNEL_API
- KSTATUS
- IoCreateInterface (
- PUUID InterfaceUuid,
- PDEVICE Device,
- PVOID InterfaceBuffer,
- ULONG InterfaceBufferSize
- )
- /*++
- Routine Description:
- This routine creates a device interface. Interfaces start out disabled. The
- Interface/device pair must be unique, there cannot be two interfaces for
- the same UUID and device.
- Arguments:
- InterfaceUuid - Supplies a pointer to the UUID identifying the interface.
- Device - Supplies a pointer to the device exposing the interface.
- InterfaceBuffer - Supplies a pointer to the interface buffer.
- InterfaceBufferSize - Supplies the size of the interface buffer, in bytes.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if the interface or device were not specified.
- STATUS_NO_MEMORY if allocations could not be made.
- STATUS_DUPLICATE_ENTRY if an interface already exists for this device.
- --*/
- {
- PINTERFACE_DIRECTORY InterfaceDirectory;
- PDEVICE_INTERFACE_INSTANCE InterfaceInstance;
- CHAR Name[UUID_STRING_LENGTH + 1];
- ULONG NameLength;
- KSTATUS Status;
- if ((InterfaceUuid == NULL) || (Device == NULL)) {
- return STATUS_INVALID_PARAMETER;
- }
- IopPrintUuidToString(Name, UUID_STRING_LENGTH + 1, InterfaceUuid);
- KeAcquireQueuedLock(IoInterfaceLock);
- //
- // Look up the interface directory. Create it if it does not exist.
- //
- InterfaceDirectory = ObFindObject(Name,
- UUID_STRING_LENGTH + 1,
- IoInterfaceDirectory);
- if (InterfaceDirectory == NULL) {
- InterfaceDirectory = ObCreateObject(ObjectInterface,
- IoInterfaceDirectory,
- Name,
- sizeof(Name),
- sizeof(INTERFACE_DIRECTORY),
- NULL,
- 0,
- DEVICE_INTERFACE_ALLOCATION_TAG);
- if (InterfaceDirectory == NULL) {
- Status = STATUS_NO_MEMORY;
- goto CreateInterfaceEnd;
- }
- InterfaceDirectory->Uuid = *InterfaceUuid;
- }
- ASSERT(UUID_STRING_LENGTH + 1 > ((sizeof(UINTN) * 2) + 1));
- //
- // Attempt to open the interface instance for this device. If this succeeds,
- // fail this function.
- //
- NameLength = RtlPrintToString(Name,
- UUID_STRING_LENGTH + 1,
- CharacterEncodingDefault,
- "%08x",
- Device);
- if (NameLength > UUID_STRING_LENGTH + 1) {
- NameLength = UUID_STRING_LENGTH + 1;
- }
- InterfaceInstance = ObFindObject(Name,
- NameLength,
- (POBJECT_HEADER)InterfaceDirectory);
- if (InterfaceInstance != NULL) {
- ObReleaseReference(InterfaceInstance);
- Status = STATUS_DUPLICATE_ENTRY;
- goto CreateInterfaceEnd;
- }
- InterfaceInstance = ObCreateObject(ObjectInterfaceInstance,
- InterfaceDirectory,
- Name,
- sizeof(Name),
- sizeof(DEVICE_INTERFACE_INSTANCE),
- NULL,
- 0,
- DEVICE_INTERFACE_ALLOCATION_TAG);
- if (InterfaceInstance == NULL) {
- Status = STATUS_NO_MEMORY;
- }
- InterfaceInstance->Device = Device;
- InterfaceInstance->InterfaceBuffer = InterfaceBuffer;
- InterfaceInstance->InterfaceBufferSize = InterfaceBufferSize;
- //
- // Notify listeners of the interface arrival.
- //
- IopNotifyInterfaceListeners(InterfaceDirectory,
- InterfaceInstance,
- Device,
- TRUE);
- Status = STATUS_SUCCESS;
- CreateInterfaceEnd:
- KeReleaseQueuedLock(IoInterfaceLock);
- if (InterfaceDirectory != NULL) {
- ObReleaseReference(InterfaceDirectory);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoDestroyInterface (
- PUUID InterfaceUuid,
- PDEVICE Device,
- PVOID InterfaceBuffer
- )
- /*++
- Routine Description:
- This routine destroys a previously created interface. All parties
- registered for notifications on this interface will be notified that the
- interface is going down.
- Arguments:
- InterfaceUuid - Supplies a pointer to the UUID identifying the interface.
- Device - Supplies a pointer to the device supplied on registration.
- InterfaceBuffer - Supplies a pointer to the interface buffer for the
- specific interface to tear down. This needs to match the interface
- buffer used when the interface was created.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if the interface or device is invalid.
- STATUS_NOT_FOUND if the interface could not be found.
- --*/
- {
- PINTERFACE_DIRECTORY InterfaceDirectory;
- PDEVICE_INTERFACE_INSTANCE InterfaceInstance;
- CHAR Name[UUID_STRING_LENGTH + 1];
- ULONG NameLength;
- KSTATUS Status;
- if (InterfaceUuid == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- IopPrintUuidToString(Name, UUID_STRING_LENGTH + 1, InterfaceUuid);
- KeAcquireQueuedLock(IoInterfaceLock);
- //
- // Look up the interface directory.
- //
- InterfaceDirectory = ObFindObject(Name,
- UUID_STRING_LENGTH + 1,
- IoInterfaceDirectory);
- if (InterfaceDirectory == NULL) {
- Status = STATUS_NOT_FOUND;
- goto DeleteInterfaceEnd;
- }
- //
- // Look up the interface instance.
- //
- NameLength = RtlPrintToString(Name,
- UUID_STRING_LENGTH + 1,
- CharacterEncodingDefault,
- "%08x",
- Device);
- if (NameLength > UUID_STRING_LENGTH + 1) {
- NameLength = UUID_STRING_LENGTH + 1;
- }
- InterfaceInstance = ObFindObject(Name,
- NameLength,
- (POBJECT_HEADER)InterfaceDirectory);
- if (InterfaceInstance == NULL) {
- Status = STATUS_NOT_FOUND;
- goto DeleteInterfaceEnd;
- }
- //
- // TODO: Rework the data structures for interfaces. There's no need to
- // use the object manager.
- //
- ASSERT(InterfaceInstance->InterfaceBuffer == InterfaceBuffer);
- //
- // Notify listeners that the interface is going down.
- //
- IopNotifyInterfaceListeners(InterfaceDirectory,
- InterfaceInstance,
- Device,
- FALSE);
- //
- // Remove the reference from the interface, once because of the find and
- // another because of the initial creation.
- //
- ObReleaseReference(InterfaceInstance);
- ObReleaseReference(InterfaceInstance);
- Status = STATUS_SUCCESS;
- DeleteInterfaceEnd:
- //
- // If necessary, release the pointer to the interface directory added by
- // finding it.
- //
- if (InterfaceDirectory != NULL) {
- ObReleaseReference(InterfaceDirectory);
- }
- KeReleaseQueuedLock(IoInterfaceLock);
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoRegisterForInterfaceNotifications (
- PUUID Interface,
- PINTERFACE_NOTIFICATION_CALLBACK CallbackRoutine,
- PDEVICE Device,
- PVOID Context,
- BOOL NotifyForExisting
- )
- /*++
- Routine Description:
- This routine registers the given handler to be notified when the given
- interface arrives or disappears. Callers are notified of both events.
- Callers will be notified for all interface arrivals and removals of the
- given interface.
- Arguments:
- Interface - Supplies a pointer to the UUID identifying the interface.
- CallbackRoutine - Supplies a pointer to the callback routine to notify
- when an interface arrives or is removed.
- Device - Supplies an optional pointer to a device. If this device is
- non-NULL, then interface notifications will be restricted to the given
- device.
- Context - Supplies an optional pointer to a context that will be passed
- back to the caller during notifications.
- NotifyForExisting - Supplies TRUE if the caller would like an arrival
- notification for every pre-existing interface, or FALSE if the caller
- only wants to be notified about future arrivals. The caller will be
- notified about ALL removals no matter the state of this flag.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if an invalid interface or callback routine was
- supplied.
- STATUS_NO_MEMORY if memory could not be allocated to satisfy the request.
- STATUS_INSUFFICIENT_RESOURCES if general resources could not be allocated to
- satisfy the request.
- STATUS_DUPLICATE_ENTRY if the given routine is already registered for
- notification on the device.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PDEVICE_INTERFACE_INSTANCE CurrentInterface;
- PINTERFACE_DIRECTORY InterfaceDirectory;
- PINTERFACE_LISTENER InterfaceListener;
- CHAR Name[UUID_STRING_LENGTH + 1];
- KSTATUS Status;
- if ((Interface == NULL) || (CallbackRoutine == NULL)) {
- return STATUS_INVALID_PARAMETER;
- }
- IopPrintUuidToString(Name, UUID_STRING_LENGTH + 1, Interface);
- KeAcquireQueuedLock(IoInterfaceLock);
- //
- // Look up the interface directory. Create it if it doesn't exist.
- //
- InterfaceDirectory = ObFindObject(Name,
- UUID_STRING_LENGTH + 1,
- IoInterfaceDirectory);
- if (InterfaceDirectory == NULL) {
- InterfaceDirectory = ObCreateObject(ObjectInterface,
- IoInterfaceDirectory,
- Name,
- sizeof(Name),
- sizeof(INTERFACE_DIRECTORY),
- NULL,
- 0,
- DEVICE_INTERFACE_ALLOCATION_TAG);
- if (InterfaceDirectory == NULL) {
- Status = STATUS_NO_MEMORY;
- goto RegisterForInterfaceNotificationsEnd;
- }
- }
- ASSERT(InterfaceDirectory != NULL);
- //
- // Create the interface listener object.
- //
- InterfaceListener = ObCreateObject(ObjectInterfaceListener,
- InterfaceDirectory,
- NULL,
- 0,
- sizeof(INTERFACE_LISTENER),
- NULL,
- 0,
- DEVICE_INTERFACE_ALLOCATION_TAG);
- if (InterfaceListener == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto RegisterForInterfaceNotificationsEnd;
- }
- InterfaceListener->CallbackRoutine = CallbackRoutine;
- InterfaceListener->Device = Device;
- InterfaceListener->Context = Context;
- //
- // If the caller would like to be notified about existing interfaces,
- // notify them now.
- //
- if (NotifyForExisting != FALSE) {
- CurrentEntry = InterfaceDirectory->Header.ChildListHead.Next;
- while (CurrentEntry != &(InterfaceDirectory->Header.ChildListHead)) {
- CurrentInterface =
- (PDEVICE_INTERFACE_INSTANCE)LIST_VALUE(CurrentEntry,
- OBJECT_HEADER,
- SiblingEntry);
- CurrentEntry = CurrentEntry->Next;
- if (CurrentInterface->Header.Type != ObjectInterfaceInstance) {
- continue;
- }
- //
- // Notify the listener.
- //
- if ((Device == NULL) || (CurrentInterface->Device == Device)) {
- CallbackRoutine(InterfaceListener->Context,
- CurrentInterface->Device,
- CurrentInterface->InterfaceBuffer,
- CurrentInterface->InterfaceBufferSize,
- TRUE);
- }
- }
- }
- Status = STATUS_SUCCESS;
- RegisterForInterfaceNotificationsEnd:
- KeReleaseQueuedLock(IoInterfaceLock);
- if (InterfaceDirectory != NULL) {
- ObReleaseReference(InterfaceDirectory);
- }
- return Status;
- }
- KERNEL_API
- KSTATUS
- IoUnregisterForInterfaceNotifications (
- PUUID Interface,
- PINTERFACE_NOTIFICATION_CALLBACK CallbackRoutine,
- PDEVICE Device,
- PVOID Context
- )
- /*++
- Routine Description:
- This routine de-registers the given handler from receiving device interface
- notifications. Once this routine returns, the given handler will not
- receive notifications for the given interface.
- Arguments:
- Interface - Supplies a pointer to the UUID identifying the interface.
- CallbackRoutine - Supplies a pointer to the callback routine supplied on
- registration for notifications.
- Device - Supplies a pointer to the device supplied upon registration.
- Context - Supplies a pointer to the context supplied upon registration.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INVALID_PARAMETER if an invalid interface or callback routine was
- supplied.
- STATUS_NOT_FOUND if no interface listener was found for the given callback
- routine on the given UUID.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PINTERFACE_LISTENER CurrentListener;
- PINTERFACE_DIRECTORY InterfaceDirectory;
- CHAR Name[UUID_STRING_LENGTH + 1];
- KSTATUS Status;
- if ((Interface == NULL) || (CallbackRoutine == NULL)) {
- return STATUS_INVALID_PARAMETER;
- }
- IopPrintUuidToString(Name, UUID_STRING_LENGTH + 1, Interface);
- KeAcquireQueuedLock(IoInterfaceLock);
- //
- // Look up the interface directory. Create it if it doesn't exist.
- //
- InterfaceDirectory = ObFindObject(Name,
- UUID_STRING_LENGTH + 1,
- IoInterfaceDirectory);
- if (InterfaceDirectory == NULL) {
- Status = STATUS_NOT_FOUND;
- goto UnregisterForInterfaceNotificationsEnd;
- }
- //
- // Loop through the interface listeners searching for the one matching the
- // given callback routine.
- //
- Status = STATUS_NOT_FOUND;
- CurrentEntry = InterfaceDirectory->Header.ChildListHead.Next;
- while (CurrentEntry != &(InterfaceDirectory->Header.ChildListHead)) {
- CurrentListener = (PINTERFACE_LISTENER)LIST_VALUE(CurrentEntry,
- OBJECT_HEADER,
- SiblingEntry);
- CurrentEntry = CurrentEntry->Next;
- if (CurrentListener->Header.Type != ObjectInterfaceListener) {
- continue;
- }
- if ((CurrentListener->CallbackRoutine == CallbackRoutine) &&
- (CurrentListener->Device == Device) &&
- (CurrentListener->Context == Context)) {
- ObReleaseReference(CurrentListener);
- Status = STATUS_SUCCESS;
- break;
- }
- }
- UnregisterForInterfaceNotificationsEnd:
- if (InterfaceDirectory != NULL) {
- ObReleaseReference(InterfaceDirectory);
- }
- KeReleaseQueuedLock(IoInterfaceLock);
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- IopNotifyInterfaceListeners (
- PINTERFACE_DIRECTORY InterfaceDirectory,
- PDEVICE_INTERFACE_INSTANCE InterfaceInstance,
- PDEVICE Device,
- BOOL Arrival
- )
- /*++
- Routine Description:
- This routine notifies all parties registered to receive device interface
- notifications. This routine MUST be called with the interface lock held.
- Arguments:
- InterfaceDirectory - Supplies a pointer to the interface undergoing the
- transition.
- InterfaceInstance - Supplies a pointer to the interface instance undergoing
- transition.
- Device - Supplies a pointer to the device changing its interface.
- Arrival - Supplies TRUE if the interface is arriving, or FALSE if it is
- departing.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PINTERFACE_LISTENER CurrentListener;
- CurrentEntry = InterfaceDirectory->Header.ChildListHead.Next;
- while (CurrentEntry != &(InterfaceDirectory->Header.ChildListHead)) {
- CurrentListener = (PINTERFACE_LISTENER)LIST_VALUE(CurrentEntry,
- OBJECT_HEADER,
- SiblingEntry);
- CurrentEntry = CurrentEntry->Next;
- if (CurrentListener->Header.Type != ObjectInterfaceListener) {
- continue;
- }
- ASSERT(CurrentListener->CallbackRoutine != NULL);
- if ((CurrentListener->Device == NULL) ||
- (Device == CurrentListener->Device)) {
- CurrentListener->CallbackRoutine(
- CurrentListener->Context,
- Device,
- InterfaceInstance->InterfaceBuffer,
- InterfaceInstance->InterfaceBufferSize,
- Arrival);
- }
- }
- return;
- }
- VOID
- IopPrintUuidToString (
- PSTR String,
- ULONG StringSize,
- PUUID Uuid
- )
- /*++
- Routine Description:
- This routine prints the given UUID out to a string.
- Arguments:
- String - Supplies a pointer to the string where the UUID will be written.
- StringSize - Supplies the size of the supplied string buffer.
- Uuid - Supplies a pointer to the UUID to print.
- Return Value:
- None.
- --*/
- {
- RtlPrintToString(String,
- StringSize,
- CharacterEncodingDefault,
- "%08X-%08X-%08X-%08X",
- Uuid->Data[0],
- Uuid->Data[1],
- Uuid->Data[2],
- Uuid->Data[3]);
- return;
- }
|