|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: immediat.c
8:
9: Abstract:
10:
11: This module contains the code that is very specific to transmit
12: immediate character 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: VOID
33: SerialGetNextImmediate(
34: IN PIRP *CurrentOpIrp,
35: IN PLIST_ENTRY QueueToProcess,
36: IN PIRP *NewIrp,
37: IN BOOLEAN CompleteCurrent
38: );
39:
40: VOID
41: SerialCancelImmediate(
42: IN PDEVICE_OBJECT DeviceObject,
43: IN PIRP Irp
44: );
45:
46: BOOLEAN
47: SerialGiveImmediateToIsr(
48: IN PVOID Context
49: );
50:
51: BOOLEAN
52: SerialGrabImmediateFromIsr(
53: IN PVOID Context
54: );
55:
56: BOOLEAN
57: SerialGiveImmediateToIsr(
58: IN PVOID Context
59: );
60:
61: BOOLEAN
62: SerialGrabImmediateFromIsr(
63: IN PVOID Context
64: );
65:
66:
67: VOID
68: SerialStartImmediate(
69: IN PSERIAL_DEVICE_EXTENSION Extension
70: )
71:
72: /*++
73:
74: Routine Description:
75:
76: This routine will calculate the timeouts needed for the
77: write. It will then hand the irp off to the isr. It
78: will need to be careful incase the irp has been canceled.
79:
80: Arguments:
81:
82: Extension - A pointer to the serial device extension.
83:
84: Return Value:
85:
86: None.
87:
88: --*/
89:
90: {
91:
92: KIRQL OldIrql;
93: LARGE_INTEGER TotalTime;
94: BOOLEAN UseATimer;
95: SERIAL_TIMEOUTS Timeouts;
96:
97:
98: UseATimer = FALSE;
99: Extension->CurrentImmediateIrp->IoStatus.Status = STATUS_PENDING;
100: IoMarkIrpPending(Extension->CurrentImmediateIrp);
101:
102: //
103: // Calculate the timeout value needed for the
104: // request. Note that the values stored in the
105: // timeout record are in milliseconds. Note that
106: // if the timeout values are zero then we won't start
107: // the timer.
108: //
109:
110: KeAcquireSpinLock(
111: &Extension->ControlLock,
112: &OldIrql
113: );
114:
115: Timeouts = Extension->Timeouts;
116:
117: KeReleaseSpinLock(
118: &Extension->ControlLock,
119: OldIrql
120: );
121:
122: if (Timeouts.WriteTotalTimeoutConstant ||
123: Timeouts.WriteTotalTimeoutMultiplier) {
124:
125: UseATimer = TRUE;
126:
127: //
128: // We have some timer values to calculate.
129: //
130:
131: TotalTime = RtlEnlargedUnsignedMultiply(
132: 1,
133: Timeouts.WriteTotalTimeoutMultiplier
134: );
135:
136: TotalTime = RtlLargeIntegerAdd(
137: TotalTime,
138: RtlConvertUlongToLargeInteger(
139: Timeouts.WriteTotalTimeoutConstant
140: )
141: );
142:
143: TotalTime = RtlExtendedIntegerMultiply(
144: TotalTime,
145: -10000
146: );
147:
148: }
149:
150: //
151: // As the irp might be going to the isr, this is a good time
152: // to initialize the reference count.
153: //
154:
155: SERIAL_INIT_REFERENCE(Extension->CurrentImmediateIrp);
156:
157: //
158: // We need to see if this irp should be canceled.
159: //
160:
161: IoAcquireCancelSpinLock(&OldIrql);
162: if (Extension->CurrentImmediateIrp->Cancel) {
163:
164: PIRP OldIrp = Extension->CurrentImmediateIrp;
165:
166: Extension->CurrentImmediateIrp = NULL;
167: IoReleaseCancelSpinLock(OldIrql);
168:
169: OldIrp->IoStatus.Status = STATUS_CANCELLED;
170: OldIrp->IoStatus.Information = 0;
171:
172: SerialDump(
173: SERIRPPATH,
174: ("SERIAL: Complete Irp: %x\n",OldIrp)
175: );
176: IoCompleteRequest(
177: OldIrp,
178: 0
179: );
180:
181: } else {
182:
183: //
184: // We give the irp to to the isr to write out.
185: // We set a cancel routine that knows how to
186: // grab the current write away from the isr.
187: //
188:
189: IoSetCancelRoutine(
190: Extension->CurrentImmediateIrp,
191: SerialCancelImmediate
192: );
193:
194: //
195: // Since the cancel routine knows about the irp we
196: // increment the reference count.
197: //
198:
199: SERIAL_INC_REFERENCE(Extension->CurrentImmediateIrp);
200:
201: if (UseATimer) {
202:
203: KeSetTimer(
204: &Extension->ImmediateTotalTimer,
205: TotalTime,
206: &Extension->TotalImmediateTimeoutDpc
207: );
208:
209: //
210: // Since the timer knows about the irp we increment
211: // the reference count.
212: //
213:
214: SERIAL_INC_REFERENCE(Extension->CurrentImmediateIrp);
215:
216: }
217:
218: KeSynchronizeExecution(
219: Extension->Interrupt,
220: SerialGiveImmediateToIsr,
221: Extension
222: );
223:
224: IoReleaseCancelSpinLock(OldIrql);
225:
226: }
227:
228: }
229:
230: VOID
231: SerialCompleteImmediate(
232: IN PKDPC Dpc,
233: IN PVOID DeferredContext,
234: IN PVOID SystemContext1,
235: IN PVOID SystemContext2
236: )
237:
238: {
239:
240: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
241: KIRQL OldIrql;
242:
243: UNREFERENCED_PARAMETER(Dpc);
244: UNREFERENCED_PARAMETER(SystemContext1);
245: UNREFERENCED_PARAMETER(SystemContext2);
246:
247: IoAcquireCancelSpinLock(&OldIrql);
248:
249: SerialTryToCompleteCurrent(
250: Extension,
251: NULL,
252: OldIrql,
253: STATUS_SUCCESS,
254: &Extension->CurrentImmediateIrp,
255: NULL,
256: NULL,
257: &Extension->ImmediateTotalTimer,
258: NULL,
259: SerialGetNextImmediate
260: );
261:
262: }
263:
264: VOID
265: SerialTimeoutImmediate(
266: IN PKDPC Dpc,
267: IN PVOID DeferredContext,
268: IN PVOID SystemContext1,
269: IN PVOID SystemContext2
270: )
271:
272: {
273:
274: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
275: KIRQL OldIrql;
276:
277: UNREFERENCED_PARAMETER(Dpc);
278: UNREFERENCED_PARAMETER(SystemContext1);
279: UNREFERENCED_PARAMETER(SystemContext2);
280:
281: IoAcquireCancelSpinLock(&OldIrql);
282:
283: SerialTryToCompleteCurrent(
284: Extension,
285: SerialGrabImmediateFromIsr,
286: OldIrql,
287: STATUS_TIMEOUT,
288: &Extension->CurrentImmediateIrp,
289: NULL,
290: NULL,
291: &Extension->ImmediateTotalTimer,
292: NULL,
293: SerialGetNextImmediate
294: );
295:
296: }
297:
298: VOID
299: SerialGetNextImmediate(
300: IN PIRP *CurrentOpIrp,
301: IN PLIST_ENTRY QueueToProcess,
302: IN PIRP *NewIrp,
303: IN BOOLEAN CompleteCurrent
304: )
305:
306: /*++
307:
308: Routine Description:
309:
310: This routine is used to complete the current immediate
311: irp. Even though the current immediate will always
312: be completed and there is no queue associated with it,
313: we use this routine so that we can try to satisfy
314: a wait for transmit queue empty event.
315:
316: Arguments:
317:
318: CurrentOpIrp - Pointer to the pointer that points to the
319: current write irp. This should point
320: to CurrentImmediateIrp.
321:
322: QueueToProcess - Always NULL.
323:
324: NewIrp - Always NULL on exit to this routine.
325:
326: CompleteCurrent - Should always be true for this routine.
327:
328:
329: Return Value:
330:
331: None.
332:
333: --*/
334:
335: {
336:
337: KIRQL OldIrql;
338: PSERIAL_DEVICE_EXTENSION Extension = CONTAINING_RECORD(
339: CurrentOpIrp,
340: SERIAL_DEVICE_EXTENSION,
341: CurrentImmediateIrp
342: );
343: PIRP OldIrp = *CurrentOpIrp;
344:
345: UNREFERENCED_PARAMETER(QueueToProcess);
346: UNREFERENCED_PARAMETER(CompleteCurrent);
347:
348: IoAcquireCancelSpinLock(&OldIrql);
349:
350: ASSERT(Extension->TotalCharsQueued >= 1);
351: Extension->TotalCharsQueued--;
352:
353: *CurrentOpIrp = NULL;
354: *NewIrp = NULL;
355: KeSynchronizeExecution(
356: Extension->Interrupt,
357: SerialProcessEmptyTransmit,
358: Extension
359: );
360: IoReleaseCancelSpinLock(OldIrql);
361:
362: SerialDump(
363: SERIRPPATH,
364: ("SERIAL: Complete Irp: %x\n",OldIrp)
365: );
366: IoCompleteRequest(
367: OldIrp,
368: IO_SERIAL_INCREMENT
369: );
370:
371: }
372:
373: VOID
374: SerialCancelImmediate(
375: IN PDEVICE_OBJECT DeviceObject,
376: IN PIRP Irp
377: )
378:
379: /*++
380:
381: Routine Description:
382:
383: This routine is used to cancel a irp that is waiting on
384: a comm event.
385:
386: Arguments:
387:
388: DeviceObject - Pointer to the device object for this device
389:
390: Irp - Pointer to the IRP for the current request
391:
392: Return Value:
393:
394: None.
395:
396: --*/
397:
398: {
399:
400: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
401:
402: SerialTryToCompleteCurrent(
403: Extension,
404: SerialGrabImmediateFromIsr,
405: Irp->CancelIrql,
406: STATUS_CANCELLED,
407: &Extension->CurrentImmediateIrp,
408: NULL,
409: NULL,
410: &Extension->ImmediateTotalTimer,
411: NULL,
412: SerialGetNextImmediate
413: );
414:
415: }
416:
417: BOOLEAN
418: SerialGiveImmediateToIsr(
419: IN PVOID Context
420: )
421:
422: /*++
423:
424: Routine Description:
425:
426: Try to start off the write by slipping it in behind
427: a transmit immediate char, or if that isn't available
428: and the transmit holding register is empty, "tickle"
429: the UART into interrupting with a transmit buffer
430: empty.
431:
432: NOTE: This routine is called by KeSynchronizeExecution.
433:
434: NOTE: This routine assumes that it is called with the
435: cancel spin lock held.
436:
437: Arguments:
438:
439: Context - Really a pointer to the device extension.
440:
441: Return Value:
442:
443: This routine always returns FALSE.
444:
445: --*/
446:
447: {
448:
449: PSERIAL_DEVICE_EXTENSION Extension = Context;
450:
451: Extension->TransmitImmediate = TRUE;
452: Extension->ImmediateChar =
453: *((UCHAR *)
454: (Extension->CurrentImmediateIrp->AssociatedIrp.SystemBuffer));
455:
456: //
457: // The isr now has a reference to the irp.
458: //
459:
460: SERIAL_INC_REFERENCE(Extension->CurrentImmediateIrp);
461:
462: //
463: // Check first to see if a write is going on. If
464: // there is then we'll just slip in during the write.
465: //
466:
467: if (!Extension->WriteLength) {
468:
469: //
470: // If there is no normal write transmitting then we
471: // will "re-enable" the transmit holding register empty
472: // interrupt. The 8250 family of devices will always
473: // signal a transmit holding register empty interrupt
474: // *ANY* time this bit is set to one. By doing things
475: // this way we can simply use the normal interrupt code
476: // to start off this write.
477: //
478: // We've been keeping track of whether the transmit holding
479: // register is empty so it we only need to do this
480: // if the register is empty.
481: //
482:
483: if (Extension->HoldingEmpty) {
484:
485: DISABLE_ALL_INTERRUPTS(Extension->Controller);
486: ENABLE_ALL_INTERRUPTS(Extension->Controller);
487:
488: }
489:
490: }
491:
492: return FALSE;
493:
494: }
495:
496: BOOLEAN
497: SerialGrabImmediateFromIsr(
498: IN PVOID Context
499: )
500:
501: /*++
502:
503: Routine Description:
504:
505:
506: This routine is used to grab the current irp, which could be timing
507: out or canceling, from the ISR
508:
509: NOTE: This routine is being called from KeSynchronizeExecution.
510:
511: NOTE: This routine assumes that the cancel spin lock is held
512: when this routine is called.
513:
514: Arguments:
515:
516: Context - Really a pointer to the device extension.
517:
518: Return Value:
519:
520: Always false.
521:
522: --*/
523:
524: {
525:
526: PSERIAL_DEVICE_EXTENSION Extension = Context;
527:
528: if (Extension->TransmitImmediate) {
529:
530: Extension->TransmitImmediate = FALSE;
531:
532: //
533: // Since the isr no longer references this irp, we can
534: // decrement it's reference count.
535: //
536:
537: SERIAL_DEC_REFERENCE(Extension->CurrentImmediateIrp);
538:
539: }
540:
541: return FALSE;
542:
543: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.