[bus] Add custom work items to WvBusProcessWorkItems
authorShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Thu, 30 Dec 2010 14:58:21 +0000 (09:58 -0500)
committerShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Thu, 30 Dec 2010 15:15:54 +0000 (10:15 -0500)
To be honest, a bus probably shouldn't be particularly
concerned with providing a default thread; it should be
up to the driver using the bus to ensure a single,
controlling thread for those operations which deal with
subjects such as the list of child nodes on the bus.

But for now, since there's already a mechanism in place
to enqueue work items for execution in a bus'
controlling thread, we abuse it to allow a driver to
enqueue their own driver-specific work item.  Use the
new WvBusEnqueueCustomWorkItem() function and the new
WV_S_BUS_CUSTOM_WORK_ITEM type.

This might change at some point, such as if thread
subject matter is removed from the bus library.

src/include/bus.h
src/winvblock/bus/bus.c

index bea6fed..1e3d956 100644 (file)
@@ -92,6 +92,23 @@ typedef struct WV_BUS_NODE {
       } BusPrivate_;
   } WV_S_BUS_NODE, * WV_SP_BUS_NODE;
 
+/**
+ * A custom work-item function.
+ *
+ * @v context           Function-specific data.
+ *
+ * If a driver needs to enqueue a work item which should execute in the
+ * context of the bus' controlling thread (this is the thread which calls
+ * WvBusProcessWorkItems()), then this is the function prototype to be
+ * used.
+ */
+typedef void STDCALL WV_F_BUS_WORK_ITEM(void *);
+typedef WV_F_BUS_WORK_ITEM * WV_FP_BUS_WORK_ITEM;
+typedef struct WV_BUS_CUSTOM_WORK_ITEM {
+    WV_FP_BUS_WORK_ITEM Func;
+    void * Context;
+  } WV_S_BUS_CUSTOM_WORK_ITEM, * WV_SP_BUS_CUSTOM_WORK_ITEM;
+
 /* Exports. */
 extern winvblock__lib_func void WvBusInit(WV_SP_BUS_T);
 extern winvblock__lib_func WV_SP_BUS_T WvBusCreate(void);
@@ -108,6 +125,10 @@ extern winvblock__lib_func NTSTATUS STDCALL WvBusAddNode(
   );
 extern winvblock__lib_func NTSTATUS STDCALL WvBusRemoveNode(WV_SP_BUS_NODE);
 extern winvblock__lib_func NTSTATUS STDCALL WvBusEnqueueIrp(WV_SP_BUS_T, PIRP);
+extern winvblock__lib_func NTSTATUS STDCALL WvBusEnqueueCustomWorkItem(
+    WV_SP_BUS_T,
+    WV_SP_BUS_CUSTOM_WORK_ITEM
+  );
 extern winvblock__lib_func NTSTATUS STDCALL WvBusSysCtl(
     IN WV_SP_BUS_T,
     IN PIRP
index 43b5a17..9e73cf7 100644 (file)
@@ -39,6 +39,7 @@ typedef enum WV_BUS_WORK_ITEM_CMD_ {
     WvBusWorkItemCmdAddPdo_,
     WvBusWorkItemCmdRemovePdo_,
     WvBusWorkItemCmdProcessIrp_,
+    WvBusWorkItemCmdCustom_,
     WvBusWorkItemCmds_
   } WV_E_BUS_WORK_ITEM_CMD_, * WV_EP_BUS_WORK_ITEM_CMD_;
 
@@ -48,6 +49,7 @@ typedef struct WV_BUS_WORK_ITEM_ {
     union {
         WV_SP_BUS_NODE Node;
         PIRP Irp;
+        WV_SP_BUS_CUSTOM_WORK_ITEM Custom;
       } Context;
   } WV_S_BUS_WORK_ITEM_, * WV_SP_BUS_WORK_ITEM_;
 
@@ -283,6 +285,13 @@ winvblock__lib_func void WvBusProcessWorkItems(WV_SP_BUS_T Bus) {
                 );
               break;
 
+            case WvBusWorkItemCmdCustom_:
+              DBG("Custom work item.\n");
+              work_item->Context.Custom->Func(
+                  work_item->Context.Custom->Context
+                );
+              break;
+
             default:
               DBG("Unknown work item type!\n");
           }
@@ -545,6 +554,39 @@ winvblock__lib_func NTSTATUS STDCALL WvBusEnqueueIrp(
     return STATUS_PENDING;
   }
 
+/**
+ * Enqueue a custom work item for a bus' thread to process.
+ *
+ * @v Bus               The bus for the IRP.
+ * @v CustomWorkItem    The custom work item for the bus' thread to process.
+ * @ret NTSTATUS        The status of the operation.
+ */
+winvblock__lib_func NTSTATUS STDCALL WvBusEnqueueCustomWorkItem(
+    WV_SP_BUS_T Bus,
+    WV_SP_BUS_CUSTOM_WORK_ITEM CustomWorkItem
+  ) {
+    WV_SP_BUS_WORK_ITEM_ work_item;
+
+    if (!Bus || !CustomWorkItem)
+      return STATUS_INVALID_PARAMETER;
+
+    if (Bus->Stop)
+      return STATUS_NO_SUCH_DEVICE;
+
+    if (!(work_item = wv_malloc(sizeof *work_item)))
+      return STATUS_INSUFFICIENT_RESOURCES;
+
+    work_item->Cmd = WvBusWorkItemCmdCustom_;
+    work_item->Context.Custom = CustomWorkItem;
+    if (!WvBusAddWorkItem_(Bus, work_item)) {
+        wv_free(work_item);
+        return STATUS_UNSUCCESSFUL;
+      }
+    /* Fire and forget. */
+    KeSetEvent(&Bus->ThreadSignal, 0, FALSE);
+    return STATUS_SUCCESS;
+  }
+
 /**
  * Get the unit number for a child node on a bus.
  *