|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: waitmask.c
8:
9: Abstract:
10:
11: This module contains the code that is very specific to get/set/wait
12: on event mask operations in the serial driver
13:
14: Author:
15:
16: Anthony V. Ercolano 26-Sep-1991
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History :
23:
24: --*/
25:
26: #include <stddef.h>
27: #include "ntddk.h"
28: #include "ntddser.h"
29: #include "serial.h"
30: #include "serialp.h"
31:
32:
33: BOOLEAN
34: SerialGrabWaitFromIsr(
35: IN PVOID Context
36: );
37:
38: BOOLEAN
39: SerialGiveWaitToIsr(
40: IN PVOID Context
41: );
42:
43: BOOLEAN
44: SerialFinishOldWait(
45: IN PVOID Context
46: );
47:
48:
49: NTSTATUS
50: SerialStartMask(
51: IN PSERIAL_DEVICE_EXTENSION Extension
52: )
53:
54: /*++
55:
56: Routine Description:
57:
58: This routine is used to process the set mask and wait
59: mask ioctls. Calls to this routine are serialized by
60: placing irps in the list under the protection of the
61: cancel spin lock.
62:
63: Arguments:
64:
65: Extension - A pointer to the serial device extension.
66:
67: Return Value:
68:
69: Will return pending for everything put the first
70: request that we actually process. Even in that
71: case it will return pending unless it can complete
72: it right away.
73:
74:
75: --*/
76:
77: {
78:
79: //
80: // The current stack location. This contains much of the
81: // information we need to process this particular request.
82: //
83: PIO_STACK_LOCATION IrpSp;
84:
85: PIRP NewIrp;
86:
87: BOOLEAN SetFirstStatus = FALSE;
88: NTSTATUS FirstStatus;
89:
90: SerialDump(
91: SERDIAG3,
92: ("SERIAL: In SerialStartMask\n")
93: );
94:
95: ASSERT(Extension->CurrentMaskIrp);
96:
97: do {
98:
99: SerialDump(
100: SERDIAG4,
101: ("SERIAL: STARMASK - CurrentMaskIrp: %x\n",Extension->CurrentMaskIrp)
102: );
103: IrpSp = IoGetCurrentIrpStackLocation(Extension->CurrentMaskIrp);
104:
105: ASSERT((IrpSp->Parameters.DeviceIoControl.IoControlCode ==
106: IOCTL_SERIAL_WAIT_ON_MASK) ||
107: (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
108: IOCTL_SERIAL_SET_WAIT_MASK));
109:
110: if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
111: IOCTL_SERIAL_SET_WAIT_MASK) {
112:
113: SerialDump(
114: SERDIAG4,
115: ("SERIAL - %x is a SETMASK irp\n",Extension->CurrentMaskIrp)
116: );
117:
118: //
119: // Complete the old wait if there is one.
120: //
121:
122: KeSynchronizeExecution(
123: Extension->Interrupt,
124: SerialFinishOldWait,
125: Extension
126: );
127:
128: //
129: // Any current waits should be on its way to completion
130: // at this point. There certainly shouldn't be any
131: // irp mask location.
132: //
133:
134: ASSERT(!Extension->IrpMaskLocation);
135:
136: Extension->CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
137:
138: if (!SetFirstStatus) {
139:
140: SerialDump(
141: SERDIAG4,
142: ("SERIAL: %x was the first irp processed by this\n"
143: "------- invocation of startmask\n",Extension->CurrentMaskIrp)
144: );
145: FirstStatus = STATUS_SUCCESS;
146: SetFirstStatus = TRUE;
147:
148: }
149:
150: //
151: // The following call will also cause the current
152: // call to be completed.
153: //
154:
155: SerialGetNextIrp(
156: &Extension->CurrentMaskIrp,
157: &Extension->MaskQueue,
158: &NewIrp,
159: TRUE
160: );
161: SerialDump(
162: SERDIAG4,
163: ("SERIAL: Perhaps another mask irp was found in the queue\n"
164: "------- %x/%x <- values should be the same\n",
165: Extension->CurrentMaskIrp,NewIrp)
166: );
167:
168:
169: } else {
170:
171: //
172: // First make sure that we have a non-zero mask.
173: // If the app queues a wait on a zero mask it can't
174: // be statisfied so it makes no sense to start it.
175: //
176:
177: if ((!Extension->IsrWaitMask) || (Extension->CurrentWaitIrp)) {
178:
179: SerialDump(
180: SERDIAG4,
181: ("SERIAL: WaitIrp is invalid\n"
182: "------- IsrWaitMask: %x\n"
183: "------- CurrentWaitIrp: %x\n",
184: Extension->IsrWaitMask,
185: Extension->CurrentWaitIrp)
186: );
187:
188: Extension->CurrentMaskIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
189:
190: if (!SetFirstStatus) {
191:
192: SerialDump(
193: SERDIAG4,
194: ("SERIAL: %x was the first irp processed by this\n"
195: "------- invocation of startmask\n",Extension->CurrentMaskIrp)
196: );
197: FirstStatus = STATUS_INVALID_PARAMETER;
198: SetFirstStatus = TRUE;
199:
200: }
201:
202: SerialGetNextIrp(
203: &Extension->CurrentMaskIrp,
204: &Extension->MaskQueue,
205: &NewIrp,
206: TRUE
207: );
208: SerialDump(
209: SERDIAG4,
210: ("SERIAL: Perhaps another mask irp was found in the queue\n"
211: "------- %x/%x <- values should be the same\n",
212: Extension->CurrentMaskIrp,NewIrp)
213: );
214:
215: } else {
216:
217: KIRQL OldIrql;
218:
219: //
220: // Make the current mask irp the current wait irp and
221: // get a new current mask irp. Note that when we get
222: // the new current mask irp we DO NOT complete the
223: // old current mask irp (which is now the current wait
224: // irp.
225: //
226: // Then under the protection of the cancel spin lock
227: // we check to see if the current wait irp needs to
228: // be canceled
229: //
230:
231: IoAcquireCancelSpinLock(&OldIrql);
232:
233: if (Extension->CurrentMaskIrp->Cancel) {
234:
235: SerialDump(
236: SERDIAG4,
237: ("SERIAL: %x irp was already marked as cancelled\n",
238: Extension->CurrentMaskIrp)
239: );
240: IoReleaseCancelSpinLock(OldIrql);
241: Extension->CurrentMaskIrp->IoStatus.Status = STATUS_CANCELLED;
242:
243: if (!SetFirstStatus) {
244:
245: SerialDump(
246: SERDIAG4,
247: ("SERIAL: %x was the first irp processed by this\n"
248: "------- invocation of startmask\n",Extension->CurrentMaskIrp)
249: );
250: FirstStatus = STATUS_CANCELLED;
251: SetFirstStatus = TRUE;
252:
253: }
254:
255: SerialGetNextIrp(
256: &Extension->CurrentMaskIrp,
257: &Extension->MaskQueue,
258: &NewIrp,
259: TRUE
260: );
261: SerialDump(
262: SERDIAG4,
263: ("SERIAL: Perhaps another mask irp was found in the queue\n"
264: "------- %x/%x <- values should be the same\n",
265: Extension->CurrentMaskIrp,NewIrp)
266: );
267:
268: } else {
269:
270: SerialDump(
271: SERDIAG4,
272: ("SERIAL: %x will become the current wait irp\n",
273: Extension->CurrentMaskIrp)
274: );
275: if (!SetFirstStatus) {
276:
277: SerialDump(
278: SERDIAG4,
279: ("SERIAL: %x was the first irp processed by this\n"
280: "------- invocation of startmask\n",Extension->CurrentMaskIrp)
281: );
282: FirstStatus = STATUS_PENDING;
283: SetFirstStatus = TRUE;
284:
285: //
286: // If we haven't already set a first status
287: // then there is a chance that this packet
288: // was never on the queue. We should mark
289: // it as pending.
290: //
291:
292: IoMarkIrpPending(Extension->CurrentMaskIrp);
293:
294: }
295:
296: //
297: // There should never be a mask location when
298: // there isn't a current wait irp. At this point
299: // there shouldn't be a current wait irp also.
300: //
301:
302: ASSERT(!Extension->IrpMaskLocation);
303: ASSERT(!Extension->CurrentWaitIrp);
304:
305: Extension->CurrentWaitIrp = Extension->CurrentMaskIrp;
306: SERIAL_INIT_REFERENCE(Extension->CurrentWaitIrp);
307: IoSetCancelRoutine(
308: Extension->CurrentWaitIrp,
309: SerialCancelWait
310: );
311:
312: //
313: // Since the cancel routine has a reference to
314: // the irp we need to update the reference
315: // count.
316: //
317:
318: SERIAL_INC_REFERENCE(Extension->CurrentWaitIrp);
319:
320: KeSynchronizeExecution(
321: Extension->Interrupt,
322: SerialGiveWaitToIsr,
323: Extension
324: );
325:
326: IoReleaseCancelSpinLock(OldIrql);
327:
328: SerialGetNextIrp(
329: &Extension->CurrentMaskIrp,
330: &Extension->MaskQueue,
331: &NewIrp,
332: FALSE
333: );
334: SerialDump(
335: SERDIAG4,
336: ("SERIAL: Perhaps another mask irp was found in the queue\n"
337: "------- %x/%x <- values should be the same\n",
338: Extension->CurrentMaskIrp,NewIrp)
339: );
340:
341: }
342:
343: }
344:
345: }
346:
347: } while (NewIrp);
348:
349: return FirstStatus;
350:
351: }
352:
353: BOOLEAN
354: SerialGrabWaitFromIsr(
355: IN PVOID Context
356: )
357:
358: /*++
359:
360: Routine Description:
361:
362: This routine will check to see if the ISR still knows about
363: a wait irp by checking to see if the IrpMaskLocation is non-null.
364: If it is then it will zero the Irpmasklocation (which in effect
365: grabs the irp away from the isr). This routine is only called
366: buy the cancel code for the wait.
367:
368: NOTE: This is called by KeSynchronizeExecution.
369:
370: Arguments:
371:
372: Context - A pointer to the device extension
373:
374: Return Value:
375:
376: Always FALSE.
377:
378: --*/
379:
380: {
381:
382: PSERIAL_DEVICE_EXTENSION Extension = Context;
383:
384: SerialDump(
385: SERDIAG3,
386: ("SERIAL: In SerialGrabWaitFromIsr\n")
387: );
388:
389: if (Extension->IrpMaskLocation) {
390:
391: SerialDump(
392: SERDIAG4,
393: ("SERIAL: The isr still owns the irp %x, mask location is %x\n"
394: "------- and system buffer is %x\n",
395: Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
396: Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer)
397: );
398:
399: //
400: // The isr still "owns" the irp.
401: //
402:
403: *Extension->IrpMaskLocation = 0;
404: Extension->IrpMaskLocation = NULL;
405:
406: Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
407:
408: //
409: // Since the isr no longer references the irp we need to
410: // decrement the reference count.
411: //
412:
413: SERIAL_DEC_REFERENCE(Extension->CurrentWaitIrp);
414:
415: }
416:
417: return FALSE;
418: }
419:
420: BOOLEAN
421: SerialGiveWaitToIsr(
422: IN PVOID Context
423: )
424:
425: /*++
426:
427: Routine Description:
428:
429: This routine simply sets a variable in the device extension
430: so that the isr knows that we have a wait irp.
431:
432: NOTE: This is called by KeSynchronizeExecution.
433:
434: NOTE: This routine assumes that it is called with the
435: cancel spinlock held.
436:
437: Arguments:
438:
439: Context - Simply a pointer to the device extension.
440:
441: Return Value:
442:
443: Always FALSE.
444:
445: --*/
446:
447: {
448:
449: PSERIAL_DEVICE_EXTENSION Extension = Context;
450:
451: SerialDump(
452: SERDIAG3,
453: ("SERIAL: In SerialGiveWaitToIsr\n")
454: );
455: //
456: // There certainly shouldn't be a current mask location at
457: // this point since we have a new current wait irp.
458: //
459:
460: ASSERT(!Extension->IrpMaskLocation);
461:
462: //
463: // The isr may or may not actually reference this irp. It
464: // won't if the wait can be satisfied immediately. However,
465: // since it will then go through the normal completion sequence,
466: // we need to have an incremented reference count anyway.
467: //
468:
469: SERIAL_INC_REFERENCE(Extension->CurrentWaitIrp);
470:
471: if (!Extension->HistoryMask) {
472:
473: SerialDump(
474: SERDIAG4,
475: ("SERIAL: No events occured prior to the wait call\n")
476: );
477:
478: //
479: // Although this wait might not be for empty transmit
480: // queue, it doesn't hurt anything to set it to false.
481: //
482:
483: Extension->EmptiedTransmit = FALSE;
484:
485: //
486: // Record where the "completion mask" should be set.
487: //
488:
489: Extension->IrpMaskLocation =
490: Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer;
491: SerialDump(
492: SERDIAG4,
493: ("SERIAL: The isr owns the irp %x, mask location is %x\n"
494: "------- and system buffer is %x\n",
495: Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
496: Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer)
497: );
498:
499: } else {
500:
501: SerialDump(
502: SERDIAG4,
503: ("SERIAL: %x occurred prior to the wait - starting the\n"
504: "------- completion code for %x\n",
505: Extension->HistoryMask,Extension->CurrentWaitIrp)
506: );
507: *((ULONG *)Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer) =
508: Extension->HistoryMask;
509: Extension->HistoryMask = 0;
510: Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
511: Extension->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
512:
513: KeInsertQueueDpc(
514: &Extension->CommWaitDpc,
515: NULL,
516: NULL
517: );
518:
519: }
520:
521: return FALSE;
522: }
523:
524: BOOLEAN
525: SerialFinishOldWait(
526: IN PVOID Context
527: )
528:
529: /*++
530:
531: Routine Description:
532:
533: This routine will check to see if the ISR still knows about
534: a wait irp by checking to see if the Irpmasklocation is non-null.
535: If it is then it will zero the Irpmasklocation (which in effect
536: grabs the irp away from the isr). This routine is only called
537: buy the cancel code for the wait.
538:
539: NOTE: This is called by KeSynchronizeExecution.
540:
541: Arguments:
542:
543: Context - A pointer to the device extension
544:
545: Return Value:
546:
547: Always FALSE.
548:
549: --*/
550:
551: {
552:
553: PSERIAL_DEVICE_EXTENSION Extension = Context;
554:
555: SerialDump(
556: SERDIAG3,
557: ("SERIAL: In SerialFinishOldWait\n")
558: );
559: if (Extension->IrpMaskLocation) {
560:
561: SerialDump(
562: SERDIAG4,
563: ("SERIAL: The isr still owns the irp %x, mask location is %x\n"
564: "------- and system buffer is %x\n",
565: Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
566: Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer)
567: );
568: //
569: // The isr still "owns" the irp.
570: //
571:
572: *Extension->IrpMaskLocation = 0;
573: Extension->IrpMaskLocation = NULL;
574:
575: Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
576:
577: //
578: // We don't decrement the reference since the completion routine
579: // will do that.
580: //
581:
582: KeInsertQueueDpc(
583: &Extension->CommWaitDpc,
584: NULL,
585: NULL
586: );
587:
588: }
589:
590: //
591: // Don't wipe out any historical data we are still interested in.
592: //
593:
594: Extension->HistoryMask &= *((ULONG *)Extension->CurrentMaskIrp->
595: AssociatedIrp.SystemBuffer);
596:
597: Extension->IsrWaitMask = *((ULONG *)Extension->CurrentMaskIrp->
598: AssociatedIrp.SystemBuffer);
599: SerialDump(
600: SERDIAG4,
601: ("SERIAL: Set mask location of %x, in irp %x, with system buffer of %x\n",
602: Extension->IrpMaskLocation,
603: Extension->CurrentMaskIrp,Extension->CurrentMaskIrp->AssociatedIrp.SystemBuffer)
604: );
605: return FALSE;
606: }
607:
608: VOID
609: SerialCancelWait(
610: IN PDEVICE_OBJECT DeviceObject,
611: IN PIRP Irp
612: )
613:
614: /*++
615:
616: Routine Description:
617:
618: This routine is used to cancel a irp that is waiting on
619: a comm event.
620:
621: Arguments:
622:
623: DeviceObject - Pointer to the device object for this device
624:
625: Irp - Pointer to the IRP for the current request
626:
627: Return Value:
628:
629: None.
630:
631: --*/
632:
633: {
634:
635: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
636:
637: SerialDump(
638: SERDIAG3,
639: ("SERIAL: In SerialCancelWait\n")
640: );
641:
642: SerialDump(
643: SERDIAG4,
644: ("SERIAL: Canceling wait for irp %x\n",Extension->CurrentWaitIrp)
645: );
646: SerialTryToCompleteCurrent(
647: Extension,
648: SerialGrabWaitFromIsr,
649: Irp->CancelIrql,
650: STATUS_CANCELLED,
651: &Extension->CurrentWaitIrp,
652: NULL,
653: NULL,
654: NULL,
655: NULL,
656: NULL
657: );
658:
659: }
660:
661: VOID
662: SerialCompleteWait(
663: IN PKDPC Dpc,
664: IN PVOID DeferredContext,
665: IN PVOID SystemContext1,
666: IN PVOID SystemContext2
667: )
668:
669: {
670:
671: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
672: KIRQL OldIrql;
673:
674: SerialDump(
675: SERDIAG3,
676: ("SERIAL: In SerialCompleteWait\n")
677: );
678: UNREFERENCED_PARAMETER(Dpc);
679: UNREFERENCED_PARAMETER(SystemContext1);
680: UNREFERENCED_PARAMETER(SystemContext2);
681:
682: IoAcquireCancelSpinLock(&OldIrql);
683:
684: SerialDump(
685: SERDIAG4,
686: ("SERIAL: Completing wait for irp %x\n",Extension->CurrentWaitIrp)
687: );
688: SerialTryToCompleteCurrent(
689: Extension,
690: NULL,
691: OldIrql,
692: STATUS_SUCCESS,
693: &Extension->CurrentWaitIrp,
694: NULL,
695: NULL,
696: NULL,
697: NULL,
698: NULL
699: );
700:
701: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.