win-pvdrivers

view xenpci/xenbus.c @ 89:5f69bcb9090c

exec xenbus_interrupt at dispatch because it calls KeSetEvent
author Andy Grover <andy.grover@oracle.com>
date Wed Jan 02 14:10:35 2008 -0800 (2008-01-02)
parents b1f7c8a9eb17
children 2a2f98373c9a
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
21 #include "io/xs_wire.h"
22 #include <stdlib.h>
24 #pragma warning( disable : 4204 )
25 #pragma warning( disable : 4221 )
27 struct write_req {
28 const void *data;
29 unsigned len;
30 };
32 static void
33 XenBus_ReadThreadProc(PVOID StartContext);
34 static void
35 XenBus_WatchThreadProc(PVOID StartContext);
36 static BOOLEAN
37 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext);
39 static int allocate_xenbus_id(WDFDEVICE Device)
40 {
41 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
43 static int probe;
44 int o_probe;
46 //KdPrint((__DRIVER_NAME " --> allocate_xenbus_id\n"));
48 for (;;)
49 {
50 // spin_lock(&req_lock);
51 if (xpdd->nr_live_reqs < NR_XB_REQS)
52 break;
53 // spin_unlock(&req_lock);
54 // wait_event(req_wq, (nr_live_reqs < NR_REQS));
55 }
57 o_probe = probe;
59 for (;;)
60 {
61 if (!xpdd->req_info[o_probe].In_Use)
62 break;
63 o_probe = (o_probe + 1) % NR_XB_REQS;
64 // BUG_ON(o_probe == probe);
65 }
66 xpdd->nr_live_reqs++;
67 xpdd->req_info[o_probe].In_Use = 1;
68 probe = (o_probe + 1) % NR_XB_REQS;
69 //spin_unlock(&req_lock);
70 //init_waitqueue_head(&req_info[o_probe].waitq);
71 KeInitializeEvent(&xpdd->req_info[o_probe].WaitEvent, SynchronizationEvent, FALSE);
73 //KdPrint((__DRIVER_NAME " <-- allocate_xenbus_id\n"));
75 return o_probe;
76 }
78 static void release_xenbus_id(WDFDEVICE Device, int id)
79 {
80 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
82 // BUG_ON(!req_info[id].in_use);
83 // spin_lock(&req_lock);
84 xpdd->req_info[id].In_Use = 0;
85 xpdd->nr_live_reqs--;
86 xpdd->req_info[id].In_Use = 0;
87 // if (nr_live_reqs == NR_REQS - 1)
88 // wake_up(&req_wq);
89 // spin_unlock(&req_lock);
90 }
92 static char *errmsg(struct xsd_sockmsg *rep)
93 {
94 char *res;
96 if (!rep) {
97 char msg[] = "No reply";
98 size_t len = strlen(msg) + 1;
99 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
100 }
101 if (rep->type != XS_ERROR)
102 return NULL;
103 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
104 memcpy(res, rep + 1, rep->len);
105 res[rep->len] = 0;
106 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
107 return res;
108 }
110 static void memcpy_from_ring(const void *Ring,
111 void *Dest,
112 int off,
113 int len)
114 {
115 int c1, c2;
116 const char *ring = Ring;
117 char *dest = Dest;
118 c1 = min(len, XENSTORE_RING_SIZE - off);
119 c2 = len - c1;
120 memcpy(dest, ring + off, c1);
121 memcpy(dest + c1, ring, c2);
122 }
124 static void xb_write(
125 WDFDEVICE Device,
126 int type,
127 int req_id,
128 xenbus_transaction_t trans_id,
129 const struct write_req *req,
130 int nr_reqs)
131 {
132 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
133 XENSTORE_RING_IDX prod;
134 int r;
135 size_t len = 0;
136 const struct write_req *cur_req;
137 size_t req_off;
138 size_t total_off;
139 size_t this_chunk;
140 struct xsd_sockmsg m = {type, req_id, trans_id };
141 struct write_req header_req = { &m, sizeof(m) };
143 //KdPrint((__DRIVER_NAME " --> xb_write\n"));
145 for (r = 0; r < nr_reqs; r++)
146 len += req[r].len;
147 m.len = len;
148 len += sizeof(m);
150 cur_req = &header_req;
152 // BUG_ON(len > XENSTORE_RING_SIZE);
153 /* Wait for the ring to drain to the point where we can send the
154 message. */
155 prod = xpdd->xen_store_interface->req_prod;
157 //KdPrint((__DRIVER_NAME " prod = %08x\n", prod));
159 if (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
160 {
161 /* Wait for there to be space on the ring */
162 //KdPrint((__DRIVER_NAME " prod %d, len %d, cons %d, size %d; waiting.\n", prod, len, xen_store_interface->req_cons, XENSTORE_RING_SIZE));
163 // wait_event(xb_waitq, xen_store_interface->req_prod + len - xen_store_interface->req_cons <= XENSTORE_RING_SIZE);
164 //KdPrint((__DRIVER_NAME " Back from wait.\n"));
165 prod = xpdd->xen_store_interface->req_prod;
166 }
168 /* We're now guaranteed to be able to send the message without
169 overflowing the ring. Do so. */
171 total_off = 0;
172 req_off = 0;
174 while (total_off < len)
175 {
176 this_chunk = min(cur_req->len - req_off,XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
177 memcpy((char *)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), (char *)cur_req->data + req_off, this_chunk);
178 prod += this_chunk;
179 req_off += this_chunk;
180 total_off += this_chunk;
181 if (req_off == cur_req->len)
182 {
183 req_off = 0;
184 if (cur_req == &header_req)
185 cur_req = req;
186 else
187 cur_req++;
188 }
189 }
191 //KdPrint((__DRIVER_NAME " Complete main loop of xb_write.\n"));
193 // BUG_ON(req_off != 0);
194 // BUG_ON(total_off != len);
195 // BUG_ON(prod > xen_store_interface->req_cons + XENSTORE_RING_SIZE);
197 /* Remote must see entire message before updating indexes */
198 //_WriteBarrier();
199 KeMemoryBarrier();
201 xpdd->xen_store_interface->req_prod += len;
203 //KdPrint((__DRIVER_NAME " prod = %08x\n", xen_store_interface->req_prod));
205 /* Send evtchn to notify remote */
206 EvtChn_Notify(Device, xpdd->xen_store_evtchn);
208 //KdPrint((__DRIVER_NAME " <-- xb_write\n"));
209 }
211 static struct xsd_sockmsg *
212 xenbus_msg_reply(
213 WDFDEVICE Device,
214 int type,
215 xenbus_transaction_t trans,
216 struct write_req *io,
217 int nr_reqs)
218 {
219 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
220 int id;
221 // DEFINE_WAIT(w);
222 struct xsd_sockmsg *rep;
224 // KdPrint((__DRIVER_NAME " --> xenbus_msg_reply\n"));
226 id = allocate_xenbus_id(Device);
227 // add_waiter(w, req_info[id].waitq);
229 xb_write(Device, type, id, trans, io, nr_reqs);
230 //
231 // schedule();
232 // remove_waiter(w);
233 // wake(current);
234 //
235 // KdPrint((__DRIVER_NAME " starting wait\n"));
237 KeWaitForSingleObject(&xpdd->req_info[id].WaitEvent, Executive, KernelMode, FALSE, NULL);
239 //KdPrint((__DRIVER_NAME " wait complete\n"));
241 rep = xpdd->req_info[id].Reply;
242 // BUG_ON(rep->req_id != id);
243 release_xenbus_id(Device, id);
244 // KdPrint((__DRIVER_NAME " <-- xenbus_msg_reply\n"));
245 return rep;
246 }
248 char *
249 XenBus_Read(
250 PVOID Context,
251 xenbus_transaction_t xbt,
252 const char *path,
253 char **value)
254 {
255 WDFDEVICE Device = Context;
256 struct write_req req[] = { {path, strlen(path) + 1} };
257 struct xsd_sockmsg *rep;
258 char *res;
259 char *msg;
261 rep = xenbus_msg_reply(Device, XS_READ, xbt, req, ARRAY_SIZE(req));
262 msg = errmsg(rep);
263 if (msg) {
264 *value = NULL;
265 return msg;
266 }
267 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
268 memcpy(res, rep + 1, rep->len);
269 res[rep->len] = 0;
270 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
271 *value = res;
272 return NULL;
273 }
275 char *
276 XenBus_Write(
277 PVOID Context,
278 xenbus_transaction_t xbt,
279 const char *path,
280 const char *value)
281 {
282 WDFDEVICE Device = Context;
283 struct write_req req[] = {
284 {path, strlen(path) + 1},
285 {value, strlen(value) + 1},
286 };
287 struct xsd_sockmsg *rep;
288 char *msg;
290 rep = xenbus_msg_reply(Device, XS_WRITE, xbt, req, ARRAY_SIZE(req));
291 msg = errmsg(rep);
292 if (msg)
293 return msg;
294 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
295 return NULL;
296 }
298 NTSTATUS
299 XenBus_Init(WDFDEVICE Device)
300 {
301 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
302 NTSTATUS Status;
303 int i;
305 //KdPrint((__DRIVER_NAME " --> XenBus_Init\n"));
307 xpdd->xen_store_evtchn = EvtChn_GetXenStorePort(Device);
308 xpdd->xen_store_interface = EvtChn_GetXenStoreRingAddr(Device);
310 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
311 xpdd->XenBus_WatchEntries[i].Active = 0;
313 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
314 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
315 xpdd->XenBus_ShuttingDown = FALSE;
317 //InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
318 //Status = PsCreateSystemThread(&XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, &oa, NULL, NULL, XenBus_ReadThreadProc, NULL);
319 Status = PsCreateSystemThread(&xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, Device);
321 //InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
322 //Status = PsCreateSystemThread(&XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, &oa, NULL, NULL, XenBus_WatchThreadProc, NULL);
323 Status = PsCreateSystemThread(&xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, Device);
325 KdPrint((__DRIVER_NAME " <-- XenBus_Init\n"));
327 return STATUS_SUCCESS;
328 }
330 NTSTATUS
331 XenBus_Start(WDFDEVICE Device)
332 {
333 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
335 KdPrint((__DRIVER_NAME " --> XenBus_Start\n"));
337 EvtChn_BindDpc(Device, xpdd->xen_store_evtchn, XenBus_Interrupt, Device);
339 KdPrint((__DRIVER_NAME " <-- XenBus_Start\n"));
341 return STATUS_SUCCESS;
342 }
344 NTSTATUS
345 XenBus_Stop(WDFDEVICE Device)
346 {
347 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
348 int i;
350 KdPrint((__DRIVER_NAME " --> XenBus_Stop\n"));
352 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
353 {
354 if (xpdd->XenBus_WatchEntries[i].Active)
355 XenBus_RemWatch(Device, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path,
356 xpdd->XenBus_WatchEntries[i].ServiceRoutine,
357 xpdd->XenBus_WatchEntries[i].ServiceContext);
358 }
360 EvtChn_Unbind(Device, xpdd->xen_store_evtchn);
362 KdPrint((__DRIVER_NAME " <-- XenBus_Stop\n"));
364 return STATUS_SUCCESS;
365 }
367 NTSTATUS
368 XenBus_Close(WDFDEVICE Device)
369 {
370 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
371 //KWAIT_BLOCK WaitBlockArray[2];
372 PVOID WaitArray[2];
374 xpdd->XenBus_ShuttingDown = TRUE;
376 KdPrint((__DRIVER_NAME " Signalling Threads\n"));
377 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
378 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
379 KdPrint((__DRIVER_NAME " Waiting for threads to die\n"));
380 ObReferenceObjectByHandle(xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
381 ObReferenceObjectByHandle(xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
382 //KeWaitForMultipleObjects(1, &WaitArray[0], WaitAny, Executive, KernelMode, FALSE, NULL, WaitBlockArray);
383 KdPrint((__DRIVER_NAME " Waiting for ReadThread\n"));
384 KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
385 KdPrint((__DRIVER_NAME " Waiting for WatchThread\n"));
386 //KeWaitForMultipleObjects(1, &WaitArray[1], WaitAny, Executive, KernelMode, FALSE, NULL, WaitBlockArray);
387 KeWaitForSingleObject(WaitArray[1], Executive, KernelMode, FALSE, NULL);
388 KdPrint((__DRIVER_NAME " Threads are dead\n"));
390 xpdd->XenBus_ShuttingDown = FALSE;
392 // ObDereferenceObject(WaitArray[0]);
393 // ObDereferenceObject(WaitArray[1]);
395 KdPrint((__DRIVER_NAME " A\n"));
397 ZwClose(xpdd->XenBus_WatchThreadHandle);
399 KdPrint((__DRIVER_NAME " B\n"));
401 ZwClose(xpdd->XenBus_ReadThreadHandle);
403 KdPrint((__DRIVER_NAME " <-- XenBus_Close\n"));
405 return STATUS_SUCCESS;
406 }
408 char *
409 XenBus_List(
410 PVOID Context,
411 xenbus_transaction_t xbt,
412 const char *pre,
413 char ***contents)
414 {
415 WDFDEVICE Device = Context;
416 struct xsd_sockmsg *reply, *repmsg;
417 struct write_req req[] = { { pre, strlen(pre)+1 } };
418 ULONG nr_elems, x, i;
419 char **res;
420 char *msg;
422 //KdPrint((__DRIVER_NAME " --> xenbus_ls\n"));
424 repmsg = xenbus_msg_reply(Device, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
425 msg = errmsg(repmsg);
426 if (msg)
427 {
428 *contents = NULL;
429 //KdPrint((__DRIVER_NAME " <-- xenbus_ls (error)\n"));
430 return msg;
431 }
432 reply = repmsg + 1;
433 for (x = nr_elems = 0; x < repmsg->len; x++)
434 {
435 nr_elems += (((char *)reply)[x] == 0);
436 }
437 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
438 XENPCI_POOL_TAG);
439 for (x = i = 0; i < nr_elems; i++)
440 {
441 int l = strlen((char *)reply + x);
442 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
443 memcpy(res[i], (char *)reply + x, l + 1);
444 x += l + 1;
445 }
446 res[i] = NULL;
447 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
448 *contents = res;
449 //KdPrint((__DRIVER_NAME " <-- xenbus_ls\n"));
450 return NULL;
451 }
453 static void
454 XenBus_ReadThreadProc(PVOID StartContext)
455 {
456 int NewWriteIndex;
457 struct xsd_sockmsg msg;
458 char *payload;
459 char *path, *token;
460 WDFDEVICE Device = StartContext;
461 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
463 for(;;)
464 {
465 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
466 if (xpdd->XenBus_ShuttingDown)
467 {
468 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
469 PsTerminateSystemThread(0);
470 }
471 //KdPrint((__DRIVER_NAME " ReadThread Woken (Count = %d)\n", ReadThreadWaitCount++));
472 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
473 {
474 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
475 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
476 {
477 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
478 break;
479 }
480 //_ReadBarrier();
481 KeMemoryBarrier();
482 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
483 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
484 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
485 {
486 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
487 break;
488 }
490 if (msg.type != XS_WATCH_EVENT)
491 {
492 xpdd->req_info[msg.req_id].Reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
493 memcpy_from_ring(xpdd->xen_store_interface->rsp,
494 xpdd->req_info[msg.req_id].Reply,
495 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
496 msg.len + sizeof(msg));
497 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
498 KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, 1, FALSE);
499 }
500 else // a watch: add to watch ring and signal watch thread
501 {
502 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
503 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
504 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
505 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
506 path = payload + sizeof(msg);
507 token = path + strlen(path) + 1;
509 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
510 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
511 {
512 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
513 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
514 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
515 }
516 else
517 {
518 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
519 // drop the message on the floor
520 continue;
521 }
523 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
524 //KdPrint((__DRIVER_NAME " +++ Watch Path = %s Token = %s\n", path, token));
525 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
526 }
527 }
528 }
529 }
531 static void
532 XenBus_WatchThreadProc(PVOID StartContext)
533 {
534 int index;
535 PXENBUS_WATCH_ENTRY entry;
536 WDFDEVICE Device = StartContext;
537 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
539 for(;;)
540 {
541 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
542 if (xpdd->XenBus_ShuttingDown)
543 {
544 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
545 PsTerminateSystemThread(0);
546 }
547 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
548 {
549 xpdd->XenBus_WatchRingReadIndex =
550 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
551 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
552 //XenBus_WatchRing[XenBus_WatchRingReadIndex].Path
553 //XenBus_WatchRing[XenBus_WatchRingReadIndex].Token
555 entry = &xpdd->XenBus_WatchEntries[index];
556 if (!entry->Active)
557 {
558 KdPrint((__DRIVER_NAME " +++ Watch not active! = %s Token = %s\n",
559 xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path,
560 xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token));
561 continue;
562 }
563 entry->Count++;
564 if (!entry->ServiceRoutine)
565 {
566 KdPrint((__DRIVER_NAME " +++ no handler for watch! = %s Token = %s\n",
567 xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path,
568 xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token));
569 continue;
570 }
571 //KdPrint((__DRIVER_NAME " +++ Watch Triggered Path = %s Token = %d (%s)\n", XenBus_WatchRing[XenBus_WatchRingReadIndex].Path, index, XenBus_WatchRing[XenBus_WatchRingReadIndex].Token));
572 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
573 }
574 }
575 }
577 char *
578 XenBus_AddWatch(
579 PVOID Context,
580 xenbus_transaction_t xbt,
581 const char *Path,
582 PXENBUS_WATCH_CALLBACK ServiceRoutine,
583 PVOID ServiceContext)
584 {
585 WDFDEVICE Device = Context;
586 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
587 struct xsd_sockmsg *rep;
588 char *msg;
589 int i;
590 char Token[20];
591 struct write_req req[2];
593 // KdPrint((__DRIVER_NAME " --> XenBus_AddWatch\n"));
595 // check that Path < 128 chars
597 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
598 if (xpdd->XenBus_WatchEntries[i].Active == 0)
599 break;
601 if (i == MAX_WATCH_ENTRIES)
602 {
603 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
604 return NULL;
605 }
607 req[0].data = Path;
608 req[0].len = strlen(Path) + 1;
610 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
611 req[1].data = Token;
612 req[1].len = strlen(Token) + 1;
614 rep = xenbus_msg_reply(Device, XS_WATCH, xbt, req, ARRAY_SIZE(req));
616 msg = errmsg(rep);
617 if (msg)
618 return msg;
620 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
622 strncpy(xpdd->XenBus_WatchEntries[i].Path, Path, 128);
623 xpdd->XenBus_WatchEntries[i].ServiceRoutine = ServiceRoutine;
624 xpdd->XenBus_WatchEntries[i].ServiceContext = ServiceContext;
625 xpdd->XenBus_WatchEntries[i].Count = 0;
626 xpdd->XenBus_WatchEntries[i].Active = 1;
628 // KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
630 return NULL;
631 }
633 char *
634 XenBus_RemWatch(
635 PVOID Context,
636 xenbus_transaction_t xbt,
637 const char *Path,
638 PXENBUS_WATCH_CALLBACK ServiceRoutine,
639 PVOID ServiceContext)
640 {
641 WDFDEVICE Device = Context;
642 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
643 struct xsd_sockmsg *rep;
644 char *msg;
645 int i;
646 char Token[20];
647 struct write_req req[2];
649 //KdPrint((__DRIVER_NAME " --> XenBus_RemWatch\n"));
651 // check that Path < 128 chars
653 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
654 if (xpdd->XenBus_WatchEntries[i].Active == 1
655 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
656 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
657 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
658 break;
659 }
661 if (i == MAX_WATCH_ENTRIES)
662 {
663 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
664 return NULL;
665 }
667 req[0].data = Path;
668 req[0].len = strlen(Path) + 1;
670 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
671 req[1].data = Token;
672 req[1].len = strlen(Token) + 1;
674 rep = xenbus_msg_reply(Device, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
676 msg = errmsg(rep);
677 if (msg)
678 return msg;
680 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
682 xpdd->XenBus_WatchEntries[i].Active = 0;
684 //KdPrint((__DRIVER_NAME " <-- XenBus_RemWatch\n"));
686 return NULL;
687 }
690 char *
691 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
692 {
693 WDFDEVICE Device = Context;
694 /* xenstored becomes angry if you send a length 0 message, so just
695 shove a nul terminator on the end */
696 struct write_req req = { "", 1};
697 struct xsd_sockmsg *rep;
698 char *err;
700 rep = xenbus_msg_reply(Device, XS_TRANSACTION_START, 0, &req, 1);
701 err = errmsg(rep);
702 if (err)
703 return err;
704 *xbt = atoi((char *)(rep + 1));
705 //sscanf((char *)(rep + 1), "%u", xbt);
706 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
707 return NULL;
708 }
710 char *
711 XenBus_EndTransaction(
712 PVOID Context,
713 xenbus_transaction_t t,
714 int abort,
715 int *retry)
716 {
717 WDFDEVICE Device = Context;
718 struct xsd_sockmsg *rep;
719 struct write_req req;
720 char *err;
722 *retry = 0;
724 req.data = abort ? "F" : "T";
725 req.len = 2;
726 rep = xenbus_msg_reply(Device, XS_TRANSACTION_END, t, &req, 1);
727 err = errmsg(rep);
728 if (err) {
729 if (!strcmp(err, "EAGAIN")) {
730 *retry = 1;
731 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
732 return NULL;
733 } else {
734 return err;
735 }
736 }
737 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
738 return NULL;
739 }
741 static BOOLEAN
742 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext)
743 {
744 WDFDEVICE Device = ServiceContext;
745 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
747 UNREFERENCED_PARAMETER(Interrupt);
749 //KdPrint((__DRIVER_NAME " --> XenBus_Interrupt (Count = %d)\n", ReadThreadSetCount++));
751 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
753 //KdPrint((__DRIVER_NAME " <-- XenBus_Interrupt\n"));
755 return TRUE;
756 }
758 char *
759 XenBus_Printf(
760 PVOID Context,
761 xenbus_transaction_t xbt,
762 const char *path,
763 const char *fmt,
764 ...)
765 {
766 WDFDEVICE Device = Context;
767 va_list ap;
768 char buf[1024];
770 va_start(ap, fmt);
771 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
772 va_end(ap);
773 return XenBus_Write(Device, xbt, path, buf);
774 }