Maemo patchset 20101501+0m5
[h-e-n] / drivers / dsp / bridge / services / ntfy.c
diff --git a/drivers/dsp/bridge/services/ntfy.c b/drivers/dsp/bridge/services/ntfy.c
new file mode 100644 (file)
index 0000000..2eff3eb
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * ntfy.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/*
+ *  ======== ntfyce.c ========
+ *  Purpose:
+ *      Manage lists of notification events.
+ *
+ *  Public Functions:
+ *      NTFY_Create
+ *      NTFY_Delete
+ *      NTFY_Exit
+ *      NTFY_Init
+ *      NTFY_Notify
+ *      NTFY_Register
+ *
+ *! Revision History:
+ *! =================
+ *! 06-Feb-2003 kc      Removed DSP_POSTMESSAGE related code.
+ *! 05-Nov-2001 kc      Updated DSP_HNOTIFICATION structure.
+ *! 10-May-2001 jeh     Removed SERVICES module init/exit from NTFY_Init/Exit.
+ *!                     NTFY_Register() returns DSP_ENOTIMPL for all but
+ *!                     DSP_SIGNALEVENT.
+ *! 12-Oct-2000 jeh     Use MEM_IsValidHandle().
+ *! 07-Sep-2000 jeh     Created.
+ */
+
+/*  ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/*  ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/std.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/errbase.h>
+
+/*  ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gt.h>
+
+/*  ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/csl.h>
+#include <dspbridge/list.h>
+#include <dspbridge/mem.h>
+#include <dspbridge/sync.h>
+
+/*  ----------------------------------- This */
+#include <dspbridge/ntfy.h>
+
+/*  ----------------------------------- Defines, Data Structures, Typedefs */
+#define NTFY_SIGNATURE      0x5946544e /* "YFTN" */
+
+/*
+ *  ======== NTFY_OBJECT ========
+ */
+struct NTFY_OBJECT {
+       u32 dwSignature;        /* For object validation */
+       struct LST_LIST *notifyList;    /* List of NOTIFICATION objects */
+       struct SYNC_CSOBJECT *hSync;    /* For critical sections */
+};
+
+/*
+ *  ======== NOTIFICATION ========
+ *  This object will be created when a client registers for events.
+ */
+struct NOTIFICATION {
+       struct LST_ELEM listElem;
+       u32 uEventMask; /* Events to be notified about */
+       u32 uNotifyType;        /* Type of notification to be sent */
+
+       /*
+        *  We keep a copy of the event name to check if the event has
+        *  already been registered. (SYNC also keeps a copy of the name).
+        */
+       char *pstrName;         /* Name of event */
+       HANDLE hEvent;          /* Handle for notification */
+       struct SYNC_OBJECT *hSync;
+};
+
+/*  ----------------------------------- Globals */
+#if GT_TRACE
+static struct GT_Mask NTFY_debugMask = { NULL, NULL };  /* GT trace variable */
+#endif
+
+/*  ----------------------------------- Function Prototypes */
+static void DeleteNotify(struct NOTIFICATION *pNotify);
+
+/*
+ *  ======== NTFY_Create ========
+ *  Purpose:
+ *      Create an empty list of notifications.
+ */
+DSP_STATUS NTFY_Create(struct NTFY_OBJECT **phNtfy)
+{
+       struct NTFY_OBJECT *pNtfy;
+       DSP_STATUS status = DSP_SOK;
+
+       DBC_Require(phNtfy != NULL);
+
+       *phNtfy = NULL;
+       MEM_AllocObject(pNtfy, struct NTFY_OBJECT, NTFY_SIGNATURE);
+
+       if (pNtfy) {
+
+               status = SYNC_InitializeDPCCS(&pNtfy->hSync);
+               if (DSP_SUCCEEDED(status)) {
+                       pNtfy->notifyList = LST_Create();
+                       if (pNtfy->notifyList == NULL) {
+                               (void) SYNC_DeleteCS(pNtfy->hSync);
+                               MEM_FreeObject(pNtfy);
+                               status = DSP_EMEMORY;
+                       } else {
+                               *phNtfy = pNtfy;
+                       }
+               }
+       } else {
+               status = DSP_EMEMORY;
+       }
+
+       DBC_Ensure((DSP_FAILED(status) && *phNtfy == NULL) ||
+                 (DSP_SUCCEEDED(status) && MEM_IsValidHandle((*phNtfy),
+                 NTFY_SIGNATURE)));
+
+       return status;
+}
+
+/*
+ *  ======== NTFY_Delete ========
+ *  Purpose:
+ *      Free resources allocated in NTFY_Create.
+ */
+void NTFY_Delete(struct NTFY_OBJECT *hNtfy)
+{
+       struct NOTIFICATION *pNotify;
+
+       DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE));
+
+       /* Remove any elements remaining in list */
+       if (hNtfy->notifyList) {
+               while ((pNotify = (struct NOTIFICATION *)LST_GetHead(hNtfy->
+                                                               notifyList))) {
+                       DeleteNotify(pNotify);
+               }
+               DBC_Assert(LST_IsEmpty(hNtfy->notifyList));
+               LST_Delete(hNtfy->notifyList);
+       }
+       if (hNtfy->hSync)
+               (void)SYNC_DeleteCS(hNtfy->hSync);
+
+       MEM_FreeObject(hNtfy);
+}
+
+/*
+ *  ======== NTFY_Exit ========
+ *  Purpose:
+ *      Discontinue usage of NTFY module.
+ */
+void NTFY_Exit(void)
+{
+       GT_0trace(NTFY_debugMask, GT_5CLASS, "Entered NTFY_Exit\n");
+}
+
+/*
+ *  ======== NTFY_Init ========
+ *  Purpose:
+ *      Initialize the NTFY module.
+ */
+bool NTFY_Init(void)
+{
+       GT_create(&NTFY_debugMask, "NY");       /* "NY" for NtfY */
+
+       GT_0trace(NTFY_debugMask, GT_5CLASS, "NTFY_Init()\n");
+
+       return true;
+}
+
+/*
+ *  ======== NTFY_Notify ========
+ *  Purpose:
+ *      Execute notify function (signal event) for every
+ *      element in the notification list that is to be notified about the
+ *      event specified in uEventMask.
+ */
+void NTFY_Notify(struct NTFY_OBJECT *hNtfy, u32 uEventMask)
+{
+       struct NOTIFICATION *pNotify;
+
+       DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE));
+
+       /*
+        *  Go through notifyList and notify all clients registered for
+        *  uEventMask events.
+        */
+
+       (void) SYNC_EnterCS(hNtfy->hSync);
+
+       pNotify = (struct NOTIFICATION *)LST_First(hNtfy->notifyList);
+       while (pNotify != NULL) {
+               if (pNotify->uEventMask & uEventMask) {
+                       /* Notify */
+                       if (pNotify->uNotifyType == DSP_SIGNALEVENT)
+                               (void)SYNC_SetEvent(pNotify->hSync);
+
+               }
+               pNotify = (struct NOTIFICATION *)LST_Next(hNtfy->notifyList,
+                         (struct LST_ELEM *)pNotify);
+       }
+
+       (void) SYNC_LeaveCS(hNtfy->hSync);
+}
+
+/*
+ *  ======== NTFY_Register ========
+ *  Purpose:
+ *      Add a notification element to the list. If the notification is already
+ *      registered, and uEventMask != 0, the notification will get posted for
+ *      events specified in the new event mask. If the notification is already
+ *      registered and uEventMask == 0, the notification will be unregistered.
+ */
+DSP_STATUS NTFY_Register(struct NTFY_OBJECT *hNtfy,
+                        struct DSP_NOTIFICATION *hNotification,
+                        u32 uEventMask, u32 uNotifyType)
+{
+       struct NOTIFICATION *pNotify;
+       struct SYNC_ATTRS syncAttrs;
+       DSP_STATUS status = DSP_SOK;
+
+       DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE));
+
+       if (hNotification == NULL)
+               status = DSP_EHANDLE;
+
+       /* Return DSP_ENOTIMPL if uNotifyType is not supported */
+       if (DSP_SUCCEEDED(status)) {
+               if (!IsValidNotifyMask(uNotifyType))
+                       status = DSP_ENOTIMPL;
+
+       }
+
+       if (DSP_FAILED(status))
+               return status;
+
+       (void)SYNC_EnterCS(hNtfy->hSync);
+
+       pNotify = (struct NOTIFICATION *)LST_First(hNtfy->notifyList);
+       while (pNotify != NULL) {
+               /* If there is more than one notification type, each
+                * type may require its own handler code.  */
+
+               if (hNotification->handle == pNotify->hSync) {
+                       /* found */
+                       break;
+               }
+               pNotify = (struct NOTIFICATION *)LST_Next(hNtfy->notifyList,
+                         (struct LST_ELEM *)pNotify);
+       }
+       if (pNotify == NULL) {
+               /* Not registered */
+               if (uEventMask == 0) {
+                       status = DSP_EVALUE;
+               } else {
+                       /* Allocate NOTIFICATION object, add to list */
+                       pNotify = MEM_Calloc(sizeof(struct NOTIFICATION),
+                                            MEM_PAGED);
+                       if (pNotify == NULL)
+                               status = DSP_EMEMORY;
+
+               }
+               if (DSP_SUCCEEDED(status)) {
+                       LST_InitElem((struct LST_ELEM *) pNotify);
+                        /* If there is more than one notification type, each
+                        * type may require its own handler code. */
+                       status = SYNC_OpenEvent(&pNotify->hSync, &syncAttrs);
+                       hNotification->handle = pNotify->hSync;
+
+                       if (DSP_SUCCEEDED(status)) {
+                               pNotify->uEventMask = uEventMask;
+                               pNotify->uNotifyType = uNotifyType;
+                               LST_PutTail(hNtfy->notifyList,
+                                          (struct LST_ELEM *)pNotify);
+                       } else {
+                               DeleteNotify(pNotify);
+                       }
+               }
+       } else {
+               /* Found in list */
+               if (uEventMask == 0) {
+                       /* Remove from list and free */
+                       LST_RemoveElem(hNtfy->notifyList,
+                                     (struct LST_ELEM *)pNotify);
+                       DeleteNotify(pNotify);
+               } else {
+                       /* Update notification mask (type shouldn't change) */
+                       pNotify->uEventMask = uEventMask;
+               }
+       }
+       (void)SYNC_LeaveCS(hNtfy->hSync);
+       return status;
+}
+
+/*
+ *  ======== DeleteNotify ========
+ *  Purpose:
+ *      Free the notification object.
+ */
+static void DeleteNotify(struct NOTIFICATION *pNotify)
+{
+       if (pNotify->hSync)
+               (void) SYNC_CloseEvent(pNotify->hSync);
+
+       if (pNotify->pstrName)
+               MEM_Free(pNotify->pstrName);
+
+       MEM_Free(pNotify);
+}
+