|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1993 - Colorado Memory Systems, Inc.
4: All Rights Reserved
5:
6: Module Name:
7:
8: q117i_nt.c
9:
10: Abstract:
11:
12: NT device driver entry point, NT interface routines,
13: and thread for low-level irp functions.
14:
15: Revision History:
16:
17:
18:
19:
20: --*/
21:
22: #include "ntddk.h" // various NT definitions
23: #include "ntdddisk.h" // disk device driver I/O control codes
24: #include "common.h"
25: #include "drvtask.h" // this driver's data declarations
26: #include "mt1defs.h" // this driver's data declarations
27: #include "mt1strc.h" // this driver's data declarations
28: #include "q117data.h" // this driver's data declarations
29: #include "hilevel.h"
30:
31: //
32: // This is the actual definition of FloppyDebugLevel.
33: // Note that it is only defined if this is a "debug"
34: // build.
35: //
36: #if DBG
37: // extern ULONG QIC117DebugLevel = QIC117DBGP | QIC117WARN | QIC117INFO |
38: // QIC117SHOWTD | QIC117SHOWQD |
39: // QIC117SHOWPOLL | QIC117STOP |
40: // QIC117MAKEBAD | QIC117SHOWBAD |
41: // QIC117DRVSTAT;
42:
43: extern ULONG QIC117DebugLevel = 0x00000000;
44: //extern ULONG QIC117DebugLevel = QIC117SHOWTD | QIC117DBGP | QIC117WARN | QIC117INFO;
45:
46: #endif
47:
48: #ifdef ALLOC_PRAGMA
49: #pragma alloc_text(init,DriverEntry)
50: #endif
51:
52:
53: NTSTATUS
54: DriverEntry(
55: IN OUT PDRIVER_OBJECT DriverObject,
56: IN PUNICODE_STRING RegistryPath
57: )
58:
59: /*++
60:
61: Routine Description:
62:
63: This routine is the driver's entry point, called by the I/O system
64: to load the driver. This routine can be called any number of times,
65: as long as the IO system and the configuration manager conspire to
66: give it an unmanaged controller to support at each call. It could
67: also be called a single time and given all of the controllers at
68: once.
69:
70: It initializes the passed-in driver object, calls the configuration
71: manager to learn about the devices that it is to support, and for
72: each controller to be supported it calls a routine to initialize the
73: controller (and all drives attached to it).
74:
75: Arguments:
76:
77: DriverObject - a pointer to the object that represents this device
78: driver.
79:
80: Return Value:
81:
82: If we successfully initialize at least one drive, STATUS_SUCCESS is
83: returned.
84:
85: If we don't (because the configuration manager returns an error, or
86: the configuration manager says that there are no controllers or
87: drives to support, or no controllers or drives can be successfully
88: initialized), then the last error encountered is propogated.
89:
90: --*/
91:
92: {
93: PCONFIG_DATA configData; // pointer to config mgr's returned data
94: NTSTATUS ntStatus;
95: UCHAR controllerNumber;
96: BOOLEAN partlySuccessful = FALSE; // TRUE if any controller init'd properly
97:
98: UNREFERENCED_PARAMETER(RegistryPath);
99: CheckedDump(QIC117INFO,( "DriverEntry...\n" ));
100:
101: //
102: // Ask configuration manager for information on the hardware that
103: // we're supposed to support.
104: //
105:
106: #if DBG
107:
108: // DbgBreakPoint();
109:
110: #endif
111:
112: ntStatus = Q117iGetConfigurationInformation( &configData );
113:
114: //
115: // If Q117iGetConfigurationInformation() failed, just exit and propogate
116: // the error. If it said that there are no controllers to support,
117: // return an error.
118: // Otherwise, try to init the controllers. If at least one succeeds,
119: // return STATUS_SUCCESS, otherwise return the last error.
120: //
121:
122: configData->FloppyTapeCount = 0;
123:
124: if ( NT_SUCCESS( ntStatus ) ) {
125:
126: //
127: // Call Q117iInitializeController() for each controller (and its
128: // attached drives) that we're supposed to support.
129: //
130: // Return success if we successfully initialize at least one
131: // device; propogate error otherwise. Set an error first in
132: // case there aren't any controllers.
133: //
134:
135: ntStatus = STATUS_NO_SUCH_DEVICE;
136:
137: for ( controllerNumber = 0;
138: controllerNumber < configData->NumberOfControllers;
139: controllerNumber++ ) {
140:
141: ntStatus = Q117iInitializeController(
142: configData,
143: controllerNumber,
144: DriverObject,
145: RegistryPath );
146:
147: if ( NT_SUCCESS( ntStatus ) ) {
148:
149: partlySuccessful = TRUE;
150: }
151: }
152:
153: if ( partlySuccessful ) {
154:
155: ntStatus = STATUS_SUCCESS;
156:
157: //
158: // Initialize the driver object with this driver's entry points.
159: //
160:
161: DriverObject->MajorFunction[IRP_MJ_READ] =
162: q117Read;
163: DriverObject->MajorFunction[IRP_MJ_WRITE] =
164: q117Write;
165: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
166: q117DeviceControl;
167: DriverObject->MajorFunction[IRP_MJ_CREATE] =
168: q117Create;
169: DriverObject->MajorFunction[IRP_MJ_CLOSE] =
170: q117Close;
171: //DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
172: // q117Cleanup;
173: DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
174: Q117iTapeDispatchInternalDeviceControl;
175: }
176: }
177:
178: //
179: // NOTE: FUTURE delete configdata, if config mgr design calls for it
180: //
181:
182: #if DBG
183:
184: if ( !NT_SUCCESS( ntStatus ) ) {
185:
186: CheckedDump((QIC117INFO | QIC117DBGP),( "q117i: exiting with error %lx\n", ntStatus ));
187: }
188:
189: #endif
190:
191: if (configData) {
192:
193: ExFreePool(configData);
194:
195: }
196:
197: return ntStatus;
198: }
199:
200: NTSTATUS
201: Q117iTapeDispatchInternalDeviceControl(
202: IN PDEVICE_OBJECT DeviceObject,
203: IN OUT PIRP Irp
204: )
205:
206: /*++
207:
208: Routine Description:
209:
210: This routine is called by the I/O system to perform a device I/O
211: control function.
212:
213: Arguments:
214:
215: DeviceObject - a pointer to the object that represents the device
216: that I/O is to be done on.
217:
218: Irp - a pointer to the I/O Request Packet for this request.
219:
220: Return Value:
221:
222: STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
223: STATUS_INVALID_DEVICE_REQUEST otherwise.
224:
225: --*/
226:
227: {
228: PIO_STACK_LOCATION irpSp;
229: NTSTATUS ntStatus;
230: PTAPE_EXTENSION tapeExtension;
231:
232: tapeExtension = DeviceObject->DeviceExtension;
233:
234: irpSp = IoGetCurrentIrpStackLocation( Irp );
235:
236:
237: switch( irpSp->Parameters.DeviceIoControl.IoControlCode) {
238:
239: case IOCTL_QIC117_CLEAR_QUEUE:
240:
241: (VOID) KeResetEvent( &tapeExtension->QControllerData->ClearQueueEvent );
242:
243: tapeExtension->QControllerData->ClearQueue = TRUE;
244: tapeExtension->QControllerData->AbortRequested = TRUE;
245:
246: IoMarkIrpPending( Irp );
247:
248: (VOID) ExInterlockedInsertTailList(
249: &tapeExtension->QControllerData->ListEntry,
250: &Irp->Tail.Overlay.ListEntry,
251: &tapeExtension->QControllerData->ListSpinLock );
252:
253: (VOID) KeReleaseSemaphore(
254: &tapeExtension->QControllerData->RequestSemaphore,
255: (KPRIORITY) 0,
256: 1,
257: FALSE );
258:
259:
260: (VOID) KeWaitForSingleObject(
261: (PVOID) &tapeExtension->QControllerData->ClearQueueEvent,
262: Suspended,
263: KernelMode,
264: FALSE,
265: (PLARGE_INTEGER) NULL );
266:
267: tapeExtension->QControllerData->ClearQueue = FALSE;
268: ntStatus = STATUS_SUCCESS;
269:
270: break;
271:
272: case IOCTL_QIC117_DRIVE_REQUEST:
273:
274: IoMarkIrpPending( Irp );
275:
276: (VOID) ExInterlockedInsertTailList(
277: &tapeExtension->QControllerData->ListEntry,
278: &Irp->Tail.Overlay.ListEntry,
279: &tapeExtension->QControllerData->ListSpinLock );
280:
281: (VOID) KeReleaseSemaphore(
282: &tapeExtension->QControllerData->RequestSemaphore,
283: (KPRIORITY) 0,
284: 1,
285: FALSE );
286:
287: ntStatus = STATUS_PENDING;
288: break;
289:
290: default:
291: CheckedDump(QIC117DBGP,("q117i: invalid device request %x\n",
292: irpSp->Parameters.DeviceIoControl.IoControlCode ));
293:
294: ntStatus = STATUS_INVALID_DEVICE_REQUEST;
295:
296: }
297:
298: return ntStatus;
299: }
300:
301: BOOLEAN
302: Q117iTapeInterruptService(
303: IN PKINTERRUPT Interrupt,
304: IN OUT PVOID Context
305: )
306:
307: /*++
308:
309: Routine Description:
310:
311: This routine is called at DIRQL by the system when the controller
312: interrupts.
313:
314: Arguments:
315:
316: Interrupt - a pointer to the interrupt object.
317:
318: Context - a pointer to our controller data area for the controller
319: that interrupted. (This was set up by the call to
320: IoConnectInterrupt).
321:
322: Return Value:
323:
324: Normally returns TRUE, but will return FALSE if this interrupt was
325: not expected.
326:
327: --*/
328:
329: {
330: PTAPE_CONTROLLER_DATA controllerData;
331: PDEVICE_OBJECT currentDeviceObject;
332: SHORT i;
333: UCHAR statusByte;
334: BOOLEAN controllerStateError = FALSE;
335:
336: UNREFERENCED_PARAMETER( Interrupt );
337:
338: KeStallExecutionProcessor(10);
339:
340: controllerData = (PTAPE_CONTROLLER_DATA) Context;
341:
342: //
343: // CurrentDeviceObject is set to the device object that is
344: // expecting an interrupt.
345: //
346:
347: currentDeviceObject = controllerData->CurrentDeviceObject;
348:
349: if (currentDeviceObject == NULL &&
350: !controllerData->CurrentInterrupt) {
351:
352: return FALSE;
353:
354: } else {
355:
356: controllerData->CurrentDeviceObject = NULL;
357:
358: if ( controllerData->CommandHasResultPhase ) {
359:
360: //
361: // Result phase of previous command. (Note that we can't trust
362: // the CMD_BUSY bit in the status register to tell us whether
363: // there's result bytes or not; it's sometimes wrong).
364: // By reading the first result byte, we reset the interrupt.
365: // The other result bytes will be read by a thread.
366: // Note that we want to do this even if the interrupt is
367: // unexpected, to make sure the interrupt is dismissed.
368: //
369:
370: if ( ( READ_CONTROLLER( &controllerData->FDC_Addr->MSDSR.msr )
371: & (MSR_RQM | MSR_DIO) ) == (MSR_RQM | MSR_DIO) ) {
372:
373: controllerData->FifoByte =
374: READ_CONTROLLER( &controllerData->FDC_Addr->dr );
375:
376: } else {
377:
378: //
379: // Should never get here. If we do, DON'T wake up the thread;
380: // let it time out and reset the controller, or let another
381: // interrupt handle this.
382: //
383:
384: CheckedDump(QIC117DBGP,( "q117i: controller not ready to be read in ISR\n" ));
385:
386: controllerStateError = TRUE;
387:
388: }
389:
390: } else {
391:
392: //
393: // Previous command doesn't have a result phase. To read how it
394: // completed, issue a sense interrupt command. Don't read
395: // the result bytes from the sense interrupt; that is the
396: // responsibility of the calling thread.
397: // Note that we want to do this even if the interrupt is
398: // unexpected, to make sure the interrupt is dismissed.
399: //
400:
401: i = FDC_MSR_RETRIES;
402:
403: do {
404:
405: if ((READ_CONTROLLER(&controllerData->FDC_Addr->MSDSR.msr) & (MSR_RQM | MSR_DIO)) == MSR_RQM) {
406:
407: break;
408:
409: }
410:
411: KeStallExecutionProcessor( 12 );
412:
413: } while (--i > 0);
414:
415: if (i != 0) {
416:
417: WRITE_CONTROLLER(
418: &controllerData->FDC_Addr->dr,
419: FDC_SNS_INT );
420:
421: KeStallExecutionProcessor( 12 );
422:
423: //
424: // Wait for the controller to ACK the SenseInterrupt command, by
425: // showing busy. On very fast machines we can end up running
426: // driver's system-thread before the controller has had time to
427: // set the busy bit.
428: //
429:
430: for (i = FDC_MSR_RETRIES; i; i--) {
431:
432: if (READ_CONTROLLER(&controllerData->FDC_Addr->MSDSR.msr) & MSR_CB)
433: break;
434:
435: KeStallExecutionProcessor( 12 );
436:
437: }
438:
439: // Need to optimize the previous section
440:
441: if ( currentDeviceObject == NULL ) {
442:
443: //
444: // This is an unexpected interrupt, so nobody's going to
445: // read the result bytes. Read them now.
446: //
447:
448: READ_CONTROLLER( &controllerData->FDC_Addr->dr );
449: READ_CONTROLLER( &controllerData->FDC_Addr->dr );
450:
451: }
452:
453: } else {
454:
455: //
456: // Shouldn't get here. If we do, DON'T wake up the thread;
457: // let it time out and reset the controller, or let another
458: // interrupt take care of it.
459: //
460:
461: CheckedDump(QIC117DBGP,( "q117i: no result, but can't write SenseIntr\n" ));
462:
463: controllerStateError = TRUE;
464: }
465:
466: }
467:
468: //
469: // We've written to the controller, and we're about to leave. On
470: // machines with levelsensitive interrupts, we'll get another interrupt
471: // if we RETURN before the port is flushed. To make sure that doesn't
472: // happen, we'll do a read here.
473: //
474:
475: statusByte = READ_CONTROLLER( &controllerData->FDC_Addr->MSDSR.msr );
476:
477: //
478: // Let the interrupt settle.
479: //
480:
481: KeStallExecutionProcessor(10);
482:
483: if ( currentDeviceObject == NULL ) {
484:
485: //
486: // We didn't expect this interrupt. We've dismissed it just
487: // in case, but now return FALSE withOUT waking up the thread.
488: //
489:
490: CheckedDump(QIC117DBGP,( "q117i: unexpected interrupt\n" ));
491:
492: return FALSE;
493:
494: }
495:
496: if ( !controllerStateError ) {
497:
498: //
499: // Request a DPC for execution later to get the remainder of the
500: // floppy state.
501: //
502:
503: IoRequestDpc(
504: currentDeviceObject,
505: currentDeviceObject->CurrentIrp,
506: (PVOID) NULL );
507:
508: }
509:
510: return TRUE;
511:
512: }
513:
514: }
515:
516: VOID
517: Q117iTapeDeferredProcedure(
518: IN PKDPC Dpc,
519: IN PVOID DeferredContext,
520: IN PVOID SystemArgument1,
521: IN PVOID SystemArgument2
522: )
523:
524: /*++
525:
526: Routine Description:
527:
528: This routine is called at DISPATCH_LEVEL by the system at the
529: request of Q117iTapeInterruptService(). It simply sets the interrupt
530: event, which wakes up the floppy thread.
531:
532: Arguments:
533:
534: Dpc - a pointer to the DPC object used to invoke this routine.
535:
536: DeferredContext - a pointer to the device object associated with this
537: DPC.
538:
539: SystemArgument1 - unused.
540:
541: SystemArgument2 - unused.
542:
543: Return Value:
544:
545: None.
546:
547: --*/
548:
549: {
550: PDEVICE_OBJECT deviceObject;
551: PTAPE_EXTENSION tapeExtension;
552: union format_header hdrData; // sector id data
553: FDC_STATUS fStat; // FDC status response
554: SHORT statLength; // length of FDC status response
555: ULONG *hdrPtr; // pointer to sector id data for format
556: PHYSICAL_ADDRESS val;
557: struct seek_cmd seek;
558: struct fdc_result result;
559: SHORT i;
560:
561: UNREFERENCED_PARAMETER( Dpc );
562: UNREFERENCED_PARAMETER( SystemArgument1 );
563: UNREFERENCED_PARAMETER( SystemArgument2 );
564:
565: deviceObject = (PDEVICE_OBJECT) DeferredContext;
566: tapeExtension = deviceObject->DeviceExtension;
567:
568:
569: if (!tapeExtension->QControllerData->StartFormatMode) {
570:
571: (VOID) KeSetEvent(
572: &tapeExtension->QControllerData->InterruptEvent,
573: (KPRIORITY) 0,
574: FALSE );
575:
576: } else {
577:
578: //
579: // Format all of the segments on the tape track. Whenever a boundary
580: // condition is reached (e.g. sectors > sectors per floppy track)
581: // update the sector id information as necessary.
582: //
583:
584: if (tapeExtension->FmtOp.Segments == (SHORT)tapeExtension->TapeParms.SegTtrack) {
585:
586: IoFlushAdapterBuffers(
587: tapeExtension->QControllerData->AdapterObject,
588: tapeExtension->FmtOp.MdlAddress,
589: tapeExtension->QControllerData->MapRegisterBase,
590: (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
591: + tapeExtension->RdWrOp.BytesTransferredSoFar ),
592: tapeExtension->RdWrOp.TotalBytesOfTransfer,
593: DMA_READ );
594:
595: if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
596: tapeExtension,
597: (CHAR *)&fStat,
598: &statLength)) == NoErr) {
599:
600: if (fStat.ST0 & ST0_IC) {
601:
602: tapeExtension->FmtOp.retval = TimeOut;
603:
604: (VOID) KeSetEvent(
605: &tapeExtension->QControllerData->InterruptEvent,
606: (KPRIORITY) 0,
607: FALSE );
608:
609: }
610:
611: }
612:
613: tapeExtension->QControllerData->StartFormatMode = FALSE;
614:
615: if (tapeExtension->QControllerData->FDC_Pcn < 128) {
616:
617: seek.NCN = tapeExtension->QControllerData->FDC_Pcn + Report_Status;
618:
619: } else {
620:
621: seek.NCN = tapeExtension->QControllerData->FDC_Pcn - Report_Status;
622:
623: }
624:
625: seek.cmd = 0x0f;
626: seek.drive = (UCHAR)tapeExtension->DriveParms.DriveSelect;
627: tapeExtension->FmtOp.NCN = seek.NCN;
628:
629: tapeExtension->QControllerData->CurrentDeviceObject =
630: tapeExtension->QDeviceObject;
631:
632: if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
633: tapeExtension,
634: (CHAR *)&seek,
635: sizeof(seek),
636: FALSE)) == NoErr) {
637:
638: tapeExtension->QControllerData->EndFormatMode = TRUE;
639:
640: } else {
641:
642: //
643: // Request a DPC for execution later to get the remainder of the
644: // floppy state.
645: //
646:
647: (VOID) KeSetEvent(
648: &tapeExtension->QControllerData->InterruptEvent,
649: (KPRIORITY) 0,
650: FALSE );
651:
652: }
653:
654: } else if (tapeExtension->FmtOp.Segments == 0) {
655:
656: if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
657: tapeExtension,
658: (CHAR *)&result,
659: (SHORT *)&statLength)) == NoErr) {
660:
661: if ( !(result.ST0 & ST0_IC)) {
662:
663: //
664: // If we timed out, then we did the sense interrupt status
665: // without clearing the interrupt from the interrupt controller.
666: // Since the FDC did not indicate an error, we assume that we
667: // missed the interrupt and send the EOI. Only needed for an
668: // 82072.
669: //
670:
671: if (tapeExtension->QControllerData->InterfaceType != MicroChannel) {
672:
673: if (result.ST0 !=
674: (UCHAR)(tapeExtension->DriveParms.DriveSelect | ST0_SE)) {
675:
676: tapeExtension->FmtOp.retval = NECFlt;
677:
678: }
679: }
680:
681: if (tapeExtension->FmtOp.NCN != result.PCN) {
682:
683: tapeExtension->FmtOp.retval = CmdFlt;
684:
685: }
686:
687: tapeExtension->QControllerData->FDC_Pcn = result.PCN;
688:
689: } else {
690:
691: tapeExtension->FmtOp.retval = NECFlt;
692:
693: }
694:
695: }
696:
697: if (tapeExtension->FmtOp.retval == NoErr) {
698:
699: hdrPtr = tapeExtension->FmtOp.HdrPtr;
700: hdrData.hdr_struct.C = tapeExtension->FmtOp.Cylinder;
701: hdrData.hdr_struct.H = tapeExtension->FmtOp.Head;
702: hdrData.hdr_struct.N = FMT_BPS;
703:
704: for (i = 0; i < tapeExtension->TapeParms.FsectSeg; i++) {
705:
706: hdrData.hdr_struct.R = tapeExtension->FmtOp.Sector++;
707: *hdrPtr = hdrData.hdr_all;
708: ++hdrPtr;
709:
710: }
711:
712: //
713: // Start the format by programming the DMA, starting the tape, and
714: // starting the floppy controller.
715: //
716: // Map the transfer through the DMA hardware.
717: //
718:
719: tapeExtension->RdWrOp.BytesTransferredSoFar = 0l;
720: tapeExtension->RdWrOp.TotalBytesOfTransfer =
721: tapeExtension->TapeParms.FsectSeg * sizeof(ULONG);
722:
723: KeFlushIoBuffers( tapeExtension->FmtOp.MdlAddress, !DMA_READ, TRUE );
724:
725: val = IoMapTransfer(
726: tapeExtension->QControllerData->AdapterObject,
727: tapeExtension->FmtOp.MdlAddress,
728: tapeExtension->QControllerData->MapRegisterBase,
729: (PVOID)( (ULONG) MmGetMdlVirtualAddress(tapeExtension->FmtOp.MdlAddress)
730: + tapeExtension->RdWrOp.BytesTransferredSoFar ),
731: &tapeExtension->RdWrOp.TotalBytesOfTransfer,
732: DMA_READ );
733:
734: tapeExtension->QControllerData->CurrentDeviceObject =
735: tapeExtension->QDeviceObject;
736:
737: if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
738: tapeExtension,
739: (CHAR *)&tapeExtension->QControllerData->FmtCmd,
740: sizeof(FORMAT_CMD),
741: TRUE)) != NoErr) {
742:
743: IoFlushAdapterBuffers(
744: tapeExtension->QControllerData->AdapterObject,
745: tapeExtension->FmtOp.MdlAddress,
746: tapeExtension->QControllerData->MapRegisterBase,
747: (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
748: + tapeExtension->RdWrOp.BytesTransferredSoFar ),
749: tapeExtension->RdWrOp.TotalBytesOfTransfer,
750: DMA_READ );
751:
752: (VOID) KeSetEvent(
753: &tapeExtension->QControllerData->InterruptEvent,
754: (KPRIORITY) 0,
755: FALSE );
756:
757: }
758:
759: tapeExtension->FmtOp.Segments++;
760:
761: } else {
762:
763: (VOID) KeSetEvent(
764: &tapeExtension->QControllerData->InterruptEvent,
765: (KPRIORITY) 0,
766: FALSE );
767:
768: }
769:
770:
771: } else {
772:
773: IoFlushAdapterBuffers(
774: tapeExtension->QControllerData->AdapterObject,
775: tapeExtension->FmtOp.MdlAddress,
776: tapeExtension->QControllerData->MapRegisterBase,
777: (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
778: + tapeExtension->RdWrOp.BytesTransferredSoFar ),
779: tapeExtension->RdWrOp.TotalBytesOfTransfer,
780: DMA_READ );
781:
782: if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
783: tapeExtension,
784: (CHAR *)&fStat,
785: &statLength)) == NoErr) {
786:
787: if (fStat.ST0 & ST0_IC) {
788:
789: tapeExtension->FmtOp.retval = TimeOut;
790:
791: }
792: }
793:
794: if (tapeExtension->FmtOp.retval != NoErr) {
795:
796: (VOID) KeSetEvent(
797: &tapeExtension->QControllerData->InterruptEvent,
798: (KPRIORITY) 0,
799: FALSE );
800:
801: }
802:
803: if (tapeExtension->FmtOp.Sector > tapeExtension->TapeParms.FsectFtrack) {
804:
805: tapeExtension->FmtOp.Sector = 1;
806: tapeExtension->FmtOp.Cylinder++;
807:
808: if (tapeExtension->FmtOp.Cylinder ==
809: (UCHAR)tapeExtension->TapeParms.FtrackFside) {
810:
811: tapeExtension->FmtOp.Cylinder = 0;
812: tapeExtension->FmtOp.Head++;
813:
814: }
815: }
816:
817: //
818: // Set up the sector id information for this segment.
819: //
820:
821:
822: hdrPtr = tapeExtension->FmtOp.HdrPtr;
823: hdrData.hdr_struct.C = tapeExtension->FmtOp.Cylinder;
824: hdrData.hdr_struct.H = tapeExtension->FmtOp.Head;
825: hdrData.hdr_struct.N = FMT_BPS;
826:
827: for (i = 0; i < tapeExtension->TapeParms.FsectSeg; i++) {
828:
829: hdrData.hdr_struct.R = tapeExtension->FmtOp.Sector++;
830: *hdrPtr = hdrData.hdr_all;
831: ++hdrPtr;
832:
833: }
834:
835: //
836: // Start the format by programming the DMA, starting the tape, and
837: // starting the floppy controller.
838: //
839: // Map the transfer through the DMA hardware.
840: //
841:
842: tapeExtension->RdWrOp.BytesTransferredSoFar = 0l;
843: tapeExtension->RdWrOp.TotalBytesOfTransfer =
844: tapeExtension->TapeParms.FsectSeg * sizeof(ULONG);
845:
846: KeFlushIoBuffers( tapeExtension->FmtOp.MdlAddress, !DMA_READ, TRUE );
847:
848: val = IoMapTransfer(
849: tapeExtension->QControllerData->AdapterObject,
850: tapeExtension->FmtOp.MdlAddress,
851: tapeExtension->QControllerData->MapRegisterBase,
852: (PVOID)( (ULONG) MmGetMdlVirtualAddress(tapeExtension->FmtOp.MdlAddress)
853: + tapeExtension->RdWrOp.BytesTransferredSoFar ),
854: &tapeExtension->RdWrOp.TotalBytesOfTransfer,
855: DMA_READ );
856:
857: tapeExtension->QControllerData->CurrentDeviceObject =
858: tapeExtension->QDeviceObject;
859:
860: if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
861: tapeExtension,
862: (CHAR *)&tapeExtension->QControllerData->FmtCmd,
863: sizeof(FORMAT_CMD),
864: TRUE)) != NoErr) {
865:
866: IoFlushAdapterBuffers(
867: tapeExtension->QControllerData->AdapterObject,
868: tapeExtension->FmtOp.MdlAddress,
869: tapeExtension->QControllerData->MapRegisterBase,
870: (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
871: + tapeExtension->RdWrOp.BytesTransferredSoFar ),
872: tapeExtension->RdWrOp.TotalBytesOfTransfer,
873: DMA_READ );
874:
875: (VOID) KeSetEvent(
876: &tapeExtension->QControllerData->InterruptEvent,
877: (KPRIORITY) 0,
878: FALSE );
879:
880: }
881:
882: tapeExtension->FmtOp.Segments++;
883:
884: }
885:
886: }
887:
888: }
889:
890: VOID
891: Q117iTapeUnloadDriver(
892: IN PDRIVER_OBJECT DriverObject
893: )
894:
895: /*++
896:
897: Routine Description:
898:
899: This routine is called by the system to remove the driver from memory.
900:
901: When this routine is called, there is no I/O being done to this device.
902: The driver object is passed in, and from this the driver can find and
903: delete all of its device objects, extensions, etc.
904:
905: Arguments:
906:
907: DriverObject - a pointer to the object associated with this device
908: driver.
909:
910: Return Value:
911:
912: None.
913:
914: --*/
915:
916: {
917: UNREFERENCED_PARAMETER( DriverObject );
918:
919: // signal Q117iTapeThread() to unload itself
920: // disable interrupts from controller(s?)
921: // delete everything that's been allocated
922: }
923:
924: VOID
925: Q117iTapeThread(
926: PTAPE_CONTROLLER_DATA ControllerData
927: )
928:
929: /*++
930:
931: Routine Description:
932:
933: This is the code executed by the system thread created when the
934: floppy driver initializes. This thread loops forever (or until a
935: flag is set telling the thread to kill itself) processing packets
936: put into the queue by the dispatch routines.
937:
938: For each packet, this thread calls appropriate routines to process
939: the request, and then calls FlFinishOperation() to complete the
940: packet.
941:
942: Arguments:
943:
944: ControllerData - a pointer to our data area for the controller being
945: supported (there is one thread per controller).
946:
947: Return Value:
948:
949: None.
950:
951: --*/
952:
953: {
954: PIRP irp;
955: PIO_STACK_LOCATION irpSp;
956: PLIST_ENTRY request;
957: NTSTATUS ntStatus = 0;
958:
959: //
960: // Set thread priority to lowest realtime level.
961: //
962:
963: KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
964:
965: do {
966:
967: //
968: // Wait for a request from the dispatch routines.
969: // KeWaitForSingleObject won't return error here - this thread
970: // isn't alertable and won't take APCs, and we're not passing in
971: // a timeout.
972: //
973:
974: (VOID) KeWaitForSingleObject(
975: (PVOID) &ControllerData->RequestSemaphore,
976: UserRequest,
977: KernelMode,
978: FALSE,
979: (PLARGE_INTEGER) NULL );
980:
981: if ( ControllerData->UnloadingDriver ) {
982:
983: CheckedDump(QIC117INFO,( "q117i: Thread asked to kill itself\n" ));
984:
985: PsTerminateSystemThread( STATUS_SUCCESS );
986: }
987:
988: while ( !IsListEmpty( &( ControllerData->ListEntry ) ) ) {
989:
990: //
991: // Get the request from the queue. We know there is one,
992: // because of the check above.
993: //
994:
995: request = ExInterlockedRemoveHeadList(
996: &ControllerData->ListEntry,
997: &ControllerData->ListSpinLock );
998:
999:
1000: ControllerData->QueueEmpty =
1001: IsListEmpty( &( ControllerData->ListEntry ) );
1002:
1003: irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );
1004:
1005: irpSp = IoGetCurrentIrpStackLocation( irp );
1006:
1007: if ( ControllerData->ClearQueue ||
1008: irpSp->Parameters.DeviceIoControl.IoControlCode ==
1009: IOCTL_QIC117_CLEAR_QUEUE) {
1010:
1011: if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_QIC117_CLEAR_QUEUE) {
1012:
1013: CheckedDump(QIC117INFO,("Q117i: processing IOCTL_QIC117_CLEAR_QUEUE : TRUE\n"));
1014:
1015: irp->IoStatus.Status = Q117iClearIO( irp );
1016:
1017: // NOTE: This is temporary until we ca find how to
1018: // correctly free the Mdl using the io subsytem.
1019: if (irp->MdlAddress != NULL) {
1020: IoFreeMdl(irp->MdlAddress);
1021: irp->MdlAddress = NULL;
1022: }
1023:
1024: IoCompleteRequest( irp, IO_DISK_INCREMENT );
1025:
1026: (VOID) KeSetEvent(
1027: &ControllerData->ClearQueueEvent,
1028: (KPRIORITY) 0,
1029: FALSE );
1030:
1031: } else {
1032:
1033: CheckedDump(QIC117INFO,("Q117i: processing IOCTL_QIC117_DRIVE_REQUEST : TRUE\n"));
1034:
1035: irp->IoStatus.Status = STATUS_CANCELLED;
1036:
1037: // NOTE: This is temporary until we ca find how to
1038: // correctly free the Mdl using the io subsytem.
1039: if (irp->MdlAddress != NULL) {
1040: IoFreeMdl(irp->MdlAddress);
1041: irp->MdlAddress = NULL;
1042: }
1043:
1044: IoCompleteRequest( irp, IO_DISK_INCREMENT );
1045:
1046: }
1047:
1048: } else {
1049:
1050: irp->IoStatus.Status = Q117iProcessItem( irp );
1051:
1052: // NOTE: This is temporary until we ca find how to
1053: // correctly free the Mdl using the io subsytem.
1054: if (irp->MdlAddress != NULL) {
1055: IoFreeMdl(irp->MdlAddress);
1056: irp->MdlAddress = NULL;
1057: }
1058:
1059: IoCompleteRequest( irp, IO_DISK_INCREMENT );
1060:
1061: }
1062:
1063: } //while there's packets to process
1064:
1065: } while ( TRUE );
1066: }
1067:
1068: IO_ALLOCATION_ACTION
1069: Q117iTapeAllocateAdapterChannel(
1070: IN PDEVICE_OBJECT DeviceObject,
1071: IN PIRP Irp,
1072: IN PVOID MapRegisterBase,
1073: IN PVOID Context
1074: )
1075:
1076: /*++
1077:
1078: Routine Description:
1079:
1080: This DPC is called whenever the floppy thread is trying to allocate
1081: the adapter channel (like before doing a read or write). It saves
1082: the MapRegisterBase in the controller data area, and sets the
1083: AllocateAdapterChannelEvent to awaken the thread.
1084:
1085: Arguments:
1086:
1087: DeviceObject - unused.
1088:
1089: Irp - unused.
1090:
1091: MapRegisterBase - the base of the map registers that can be used
1092: for this transfer.
1093:
1094: Context - a pointer to our controller data area.
1095:
1096: Return Value:
1097:
1098: Returns Allocation Action 'KeepObject' which means that the adapter
1099: object will be held for now (to be released explicitly later).
1100:
1101: --*/
1102: {
1103: PTAPE_CONTROLLER_DATA controllerData = (PTAPE_CONTROLLER_DATA) Context;
1104:
1105: UNREFERENCED_PARAMETER( DeviceObject );
1106: UNREFERENCED_PARAMETER( Irp );
1107:
1108: controllerData->MapRegisterBase = MapRegisterBase;
1109:
1110: (VOID) KeSetEvent(
1111: &controllerData->AllocateAdapterChannelEvent,
1112: 0L,
1113: FALSE );
1114:
1115: return KeepObject;
1116: }
1117:
1118: NTSTATUS
1119: Q117iConfigCallBack(
1120: IN PVOID Context,
1121: IN PUNICODE_STRING PathName,
1122: IN INTERFACE_TYPE BusType,
1123: IN ULONG BusNumber,
1124: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
1125: IN CONFIGURATION_TYPE ControllerType,
1126: IN ULONG ControllerNumber,
1127: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
1128: IN CONFIGURATION_TYPE PeripheralType,
1129: IN ULONG PeripheralNumber,
1130: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
1131: )
1132:
1133: /*++
1134:
1135: Routine Description:
1136:
1137: This routine is used to acquire all of the configuration
1138: information for each floppy disk controller and the
1139: peripheral driver attached to that controller.
1140:
1141: Arguments:
1142:
1143: Context - Pointer to the confuration information we are building
1144: up.
1145:
1146: PathName - unicode registry path. Not Used.
1147:
1148: BusType - Internal, Isa, ...
1149:
1150: BusNumber - Which bus if we are on a multibus system.
1151:
1152: BusInformation - Configuration information about the bus. Not Used.
1153:
1154: ControllerType - Should always be DiskController.
1155:
1156: ControllerNumber - Which controller if there is more than one
1157: controller in the system.
1158:
1159: ControllerInformation - Array of pointers to the three pieces of
1160: registry information.
1161:
1162: PeripheralType - Should always be FloppyDiskPeripheral.
1163:
1164: PeripheralNumber - Which floppy if this controller is maintaining
1165: more than one.
1166:
1167: PeripheralInformation - Array of pointers to the three pieces of
1168: registry information.
1169:
1170: Return Value:
1171:
1172: STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
1173: if it couldn't map the base csr or acquire the adapter object, or
1174: all of the resource information couldn't be acquired.
1175:
1176: --*/
1177:
1178: {
1179:
1180: //
1181: // So we don't have to typecast the context.
1182: //
1183: PCONFIG_DATA config = Context;
1184:
1185: //
1186: // Simple iteration variable.
1187: //
1188: ULONG i;
1189:
1190: //
1191: // This boolean will be used to denote whether we've seen this
1192: // controller before.
1193: //
1194: BOOLEAN newController;
1195:
1196: //
1197: // This will be used to denote whether we even have room
1198: // for a new controller.
1199: //
1200: BOOLEAN outOfRoom;
1201:
1202: //
1203: // Iteration variable that will end up indexing to where
1204: // the controller information should be placed.
1205: //
1206: ULONG ControllerSlot;
1207:
1208: //
1209: // Short hand for referencing the particular controller config
1210: // information that we are building up.
1211: //
1212: PCONFIG_CONTROLLER_DATA controller;
1213:
1214: PCM_FULL_RESOURCE_DESCRIPTOR peripheralData = (PCM_FULL_RESOURCE_DESCRIPTOR)
1215: (((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
1216: PeripheralInformation[IoQueryDeviceConfigurationData]->DataOffset);
1217:
1218: //
1219: // These three boolean will tell us whether we got all the
1220: // information that we needed.
1221: //
1222: BOOLEAN foundPort = FALSE;
1223: BOOLEAN foundInterrupt = FALSE;
1224: BOOLEAN foundDma = FALSE;
1225:
1226: ASSERT(ControllerType == DiskController);
1227: ASSERT(PeripheralType == FloppyDiskPeripheral);
1228:
1229: //
1230: // Loop through the "slots" that we have for a new controller.
1231: // Determine if this is a controller that we've already seen,
1232: // or a new controller.
1233: //
1234:
1235: outOfRoom = TRUE;
1236: for (
1237: ControllerSlot = 0;
1238: ControllerSlot < MAXIMUM_CONTROLLERS_PER_MACHINE;
1239: ControllerSlot++
1240: ) {
1241:
1242: if (config->Controller[ControllerSlot].ActualControllerNumber == -1) {
1243:
1244: newController = TRUE;
1245: outOfRoom = FALSE;
1246: config->Controller[ControllerSlot].ActualControllerNumber =
1247: ControllerNumber;
1248: config->NumberOfControllers++;
1249: break;
1250:
1251: } else if (config->Controller[ControllerSlot].ActualControllerNumber
1252: == (LONG)ControllerNumber) {
1253:
1254: newController = FALSE;
1255: outOfRoom = FALSE;
1256: break;
1257:
1258: }
1259:
1260: }
1261:
1262: if (outOfRoom) {
1263:
1264: //
1265: // Just return and ignore the controller.
1266: //
1267:
1268: return STATUS_SUCCESS;
1269:
1270: }
1271:
1272: controller = &config->Controller[ControllerSlot];
1273:
1274: if (newController) {
1275:
1276: PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
1277: (PCM_FULL_RESOURCE_DESCRIPTOR)
1278: (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
1279: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
1280:
1281: //
1282: // We have the pointer. Save off the interface type and
1283: // the busnumber for use when we call the Hal and the
1284: // Io System.
1285: //
1286:
1287: controller->InterfaceType = BusType;
1288: controller->BusNumber = BusNumber;
1289: controller->SharableVector = TRUE;
1290: controller->SaveFloatState = FALSE;
1291:
1292: //
1293: // We need to get the following information out of the partial
1294: // resource descriptors.
1295: //
1296: // The irql and vector.
1297: //
1298: // The dma channel.
1299: //
1300: // The base address and span covered by the floppy controllers
1301: // registers.
1302: //
1303: // It is not defined how these appear in the partial resource
1304: // lists, so we will just loop over all of them. If we find
1305: // something we don't recognize, we drop that information on
1306: // the floor. When we have finished going through all the
1307: // partial information, we validate that we got the above
1308: // three.
1309: //
1310:
1311: CheckedDump(QIC117INFO,("Q117i: adding controller: %x slot: %x\n",ControllerNumber,ControllerSlot));
1312:
1313: for (
1314: i = 0;
1315: i < controllerData->PartialResourceList.Count;
1316: i++
1317: ) {
1318:
1319: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
1320: &controllerData->PartialResourceList.PartialDescriptors[i];
1321:
1322: switch (partial->Type) {
1323:
1324: case CmResourceTypePort: {
1325:
1326: BOOLEAN inIoSpace =
1327: #ifdef i386
1328: TRUE;
1329: #else
1330: FALSE;
1331: #endif
1332:
1333: foundPort = TRUE;
1334:
1335: //
1336: // Save of the pointer to the partial so
1337: // that we can later use it to report resources
1338: // and we can also use this later in the routine
1339: // to make sure that we got all of our resources.
1340: //
1341:
1342: controller->SpanOfControllerAddress =
1343: partial->u.Port.Length;
1344: controller->OriginalBaseAddress =
1345: partial->u.Port.Start;
1346: controller->ControllerBaseAddress = (PTAPE_ADDRESS)
1347: Q117iGetControllerBase(
1348: BusType,
1349: BusNumber,
1350: partial->u.Port.Start,
1351: controller->SpanOfControllerAddress,
1352: inIoSpace,
1353: &controller->MappedAddress
1354: );
1355:
1356: if (!controller->ControllerBaseAddress) {
1357:
1358: return STATUS_INSUFFICIENT_RESOURCES;
1359:
1360: }
1361:
1362: break;
1363: }
1364: case CmResourceTypeInterrupt: {
1365:
1366: foundInterrupt = TRUE;
1367: if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
1368:
1369: controller->InterruptMode = Latched;
1370:
1371: } else {
1372:
1373: controller->InterruptMode = LevelSensitive;
1374:
1375: }
1376:
1377: controller->OriginalIrql = partial->u.Interrupt.Level;
1378: controller->OriginalVector = partial->u.Interrupt.Vector;
1379: controller->ControllerVector =
1380: HalGetInterruptVector(
1381: BusType,
1382: BusNumber,
1383: partial->u.Interrupt.Level,
1384: partial->u.Interrupt.Vector,
1385: &controller->ControllerIrql,
1386: &controller->ProcessorMask
1387: );
1388:
1389: break;
1390: }
1391: case CmResourceTypeDma: {
1392:
1393: DEVICE_DESCRIPTION deviceDesc;
1394:
1395: RtlZeroMemory(&deviceDesc,sizeof(deviceDesc));
1396: foundDma = TRUE;
1397:
1398: controller->OriginalDmaChannel = partial->u.Dma.Channel;
1399:
1400: deviceDesc.Version = DEVICE_DESCRIPTION_VERSION;
1401: deviceDesc.DmaWidth = Width8Bits;
1402: deviceDesc.DemandMode = TRUE;
1403: deviceDesc.MaximumLength = 32l*1024l;
1404: deviceDesc.AutoInitialize = FALSE;
1405: deviceDesc.ScatterGather = FALSE;
1406: deviceDesc.DmaChannel = partial->u.Dma.Channel;
1407: deviceDesc.InterfaceType = BusType;
1408: deviceDesc.DmaSpeed = TypeA;
1409: controller->NumberOfMapRegisters = BYTES_TO_PAGES(32l*1024l);
1410: controller->AdapterObject =
1411: HalGetAdapter(
1412: &deviceDesc,
1413: &controller->NumberOfMapRegisters
1414: );
1415:
1416: CheckedDump(QIC117INFO,( "Q117i: Bus Type = %d\n",
1417: BusType ));
1418: CheckedDump(QIC117INFO,( "Q117i: Number of map registers = %d\n",
1419: controller->NumberOfMapRegisters ));
1420:
1421: if (!controller->AdapterObject) {
1422:
1423: return STATUS_INSUFFICIENT_RESOURCES;
1424:
1425: }
1426:
1427: break;
1428:
1429: }
1430: default: {
1431:
1432: break;
1433:
1434: }
1435:
1436: }
1437:
1438: }
1439:
1440: //
1441: // If we didn't get all the information then we return
1442: // insufficient resources.
1443: //
1444:
1445: if ((!foundPort) ||
1446: (!foundInterrupt) ||
1447: (!foundDma)) {
1448:
1449: return STATUS_INSUFFICIENT_RESOURCES;
1450:
1451: }
1452: controller->NumberOfTapeDrives++;
1453: controller->OkToUseThisController = TRUE;
1454:
1455: }
1456:
1457:
1458: return STATUS_SUCCESS;
1459: }
1460:
1461: NTSTATUS
1462: Q117iGetConfigurationInformation(
1463: OUT PCONFIG_DATA *ConfigData
1464: )
1465:
1466: /*++
1467:
1468: Routine Description:
1469:
1470: This routine is called by DriverEntry() to get information about the
1471: devices to be supported from configuration mangement and/or the
1472: hardware architecture layer (HAL).
1473:
1474: Arguments:
1475:
1476: ConfigData - a pointer to the pointer to a data structure that
1477: describes the controllers and the drives attached to them
1478:
1479: Return Value:
1480:
1481: Returns STATUS_SUCCESS unless there is no drive 0 or we didn't get
1482: any configuration information.
1483: NOTE: FUTURE return values may change when config mgr is finished.
1484:
1485: --*/
1486:
1487: {
1488: INTERFACE_TYPE InterfaceType;
1489: NTSTATUS Status;
1490: ULONG i;
1491:
1492: *ConfigData = ExAllocatePool(
1493: PagedPool,
1494: sizeof(CONFIG_DATA)
1495: );
1496:
1497: if (!*ConfigData) {
1498:
1499: return STATUS_INSUFFICIENT_RESOURCES;
1500:
1501: }
1502:
1503: //
1504: // Zero out the config structure and fill in the actual
1505: // controller numbers with -1's so that the callback routine
1506: // can recognize a new controller.
1507: //
1508:
1509: RtlZeroMemory(
1510: *ConfigData,
1511: sizeof(CONFIG_DATA)
1512: );
1513:
1514: for (
1515: i = 0;
1516: i < MAXIMUM_CONTROLLERS_PER_MACHINE;
1517: i++
1518: ) {
1519:
1520: (*ConfigData)->Controller[i].ActualControllerNumber = -1;
1521:
1522: }
1523:
1524: //
1525: // Go through all of the various bus types looking for
1526: // disk controllers. The disk controller sections of the
1527: // hardware registry only deal with the floppy drives.
1528: // The callout routine that can get called will then
1529: // look for information pertaining to a particular
1530: // device on the controller.
1531: //
1532:
1533: for (
1534: InterfaceType = 0;
1535: InterfaceType < MaximumInterfaceType;
1536: InterfaceType++
1537: ) {
1538:
1539: CONFIGURATION_TYPE Dc = DiskController;
1540: CONFIGURATION_TYPE Fp = FloppyDiskPeripheral;
1541:
1542: Status = IoQueryDeviceDescription(
1543: &InterfaceType,
1544: NULL,
1545: &Dc,
1546: NULL,
1547: &Fp,
1548: NULL,
1549: Q117iConfigCallBack,
1550: *ConfigData
1551: );
1552:
1553: if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) {
1554:
1555: ExFreePool(*ConfigData);
1556: *ConfigData = NULL;
1557: return Status;
1558:
1559: }
1560:
1561: }
1562:
1563: return STATUS_SUCCESS;
1564: }
1565:
1566: NTSTATUS
1567: Q117iInitializeController(
1568: IN PCONFIG_DATA ConfigData,
1569: IN UCHAR ControllerNumber,
1570: IN PDRIVER_OBJECT DriverObject,
1571: IN PUNICODE_STRING RegistryPath
1572: )
1573:
1574: /*++
1575:
1576: Routine Description:
1577:
1578: This routine is called at initialization time by DriverEntry() -
1579: once for each controller that the configuration manager tells it we
1580: have to support.
1581:
1582: When this routine is called, the configuration data has already been
1583: filled in.
1584:
1585: Arguments:
1586:
1587: ConfigData - a pointer to the structure that describes the
1588: controller and the disks attached to it, as given to us by the
1589: configuration manager.
1590:
1591: ControllerNumber - which controller in ConfigData we are
1592: initializing.
1593:
1594: DriverObject - a pointer to the object that represents this device
1595: driver.
1596:
1597: Return Value:
1598:
1599: STATUS_SUCCESS if this controller and at least one of its disks were
1600: initialized; an error otherwise.
1601:
1602: --*/
1603:
1604: {
1605: PTAPE_CONTROLLER_DATA controllerData;
1606: PVOID threadObject;
1607: NTSTATUS ntStatus;
1608: NTSTATUS ntStatus2;
1609: HANDLE threadHandle = 0;
1610: BOOLEAN partlySuccessful;
1611: LARGE_INTEGER timeout;
1612: UCHAR ntNameBuffer[256];
1613: STRING ntNameString;
1614: UNICODE_STRING ntUnicodeString;
1615:
1616: CheckedDump(QIC117INFO,( "Q117iInitializeController...\n" ));
1617:
1618: //
1619: // This routine will take attempt to "append" the resources
1620: // used by this controller into the resource map of the
1621: // registry. If there was a conflict with previously "declared"
1622: // data, then this routine will return false, in which case we
1623: // will NOT try to initialize this particular controller.
1624: //
1625:
1626: if (!Q117iReportResources(
1627: DriverObject,
1628: ConfigData,
1629: ControllerNumber
1630: )) {
1631:
1632: return STATUS_INSUFFICIENT_RESOURCES;
1633:
1634: }
1635:
1636: //
1637: // Allocate and zero-initialize data to describe this controller
1638: //
1639:
1640: controllerData = (PTAPE_CONTROLLER_DATA) ExAllocatePool(
1641: NonPagedPool,
1642: sizeof( TAPE_CONTROLLER_DATA ) );
1643:
1644: if ( controllerData == NULL ) {
1645:
1646: return STATUS_INSUFFICIENT_RESOURCES;
1647: }
1648:
1649: RtlZeroMemory( controllerData, sizeof( TAPE_CONTROLLER_DATA ) );
1650:
1651: (VOID) sprintf(
1652: ntNameBuffer,
1653: "\\Device\\FloppyControllerEvent%d",
1654: ControllerNumber );
1655:
1656: RtlInitString( &ntNameString, ntNameBuffer );
1657:
1658: ntStatus = RtlAnsiStringToUnicodeString(
1659: &ntUnicodeString,
1660: &ntNameString,
1661: TRUE );
1662:
1663: controllerData->ControllerEvent = IoCreateSynchronizationEvent(
1664: &ntUnicodeString,
1665: &controllerData->ControllerEventHandle);
1666:
1667: RtlFreeUnicodeString( &ntUnicodeString );
1668:
1669: if ( controllerData->ControllerEvent == NULL ) {
1670: return STATUS_INSUFFICIENT_RESOURCES;
1671: }
1672:
1673: //
1674: // Fill in some items that we got from configuration management and
1675: // the HAL.
1676: //
1677:
1678: controllerData->FDC_Addr = (PTAPE_ADDRESS)
1679: ConfigData->Controller[ControllerNumber].ControllerBaseAddress;
1680: controllerData->InterfaceType =
1681: ConfigData->Controller[ControllerNumber].InterfaceType;
1682: controllerData->ActualControllerNumber =
1683: ConfigData->Controller[ControllerNumber].ActualControllerNumber;
1684:
1685: controllerData->DriveSelect.Selected = FALSE;
1686: controllerData->DriveSelect.DeselectByte = dselb;
1687: controllerData->DriveSelect.SelectByte = selb;
1688:
1689: ntStatus = IoConnectInterrupt(
1690: (PKINTERRUPT *) &controllerData->InterruptObject,
1691: (PKSERVICE_ROUTINE) Q117iTapeInterruptService,
1692: (PVOID) controllerData,
1693: (PKSPIN_LOCK)NULL,
1694: ConfigData->Controller[ControllerNumber].ControllerVector,
1695: ConfigData->Controller[ControllerNumber].ControllerIrql,
1696: ConfigData->Controller[ControllerNumber].ControllerIrql,
1697: ConfigData->Controller[ControllerNumber].InterruptMode,
1698: ConfigData->Controller[ControllerNumber].SharableVector,
1699: ConfigData->Controller[ControllerNumber].ProcessorMask,
1700: ConfigData->Controller[ControllerNumber].SaveFloatState);
1701:
1702:
1703: if ( NT_SUCCESS( ntStatus ) ) {
1704: //
1705: // Initialize the interlocked request queue, including a
1706: // counting semaphore to indicate items in the queue
1707: //
1708:
1709: KeInitializeSemaphore(
1710: &controllerData->RequestSemaphore,
1711: 0L,
1712: MAXLONG );
1713:
1714: KeInitializeSpinLock( &controllerData->ListSpinLock );
1715:
1716: InitializeListHead( &controllerData->ListEntry );
1717:
1718: //
1719: // Initialize events to signal interrupts and adapter object
1720: // allocation
1721: //
1722:
1723: KeInitializeEvent(
1724: &controllerData->InterruptEvent,
1725: SynchronizationEvent,
1726: FALSE);
1727:
1728:
1729: KeInitializeEvent(
1730: &controllerData->AllocateAdapterChannelEvent,
1731: NotificationEvent,
1732: FALSE );
1733:
1734:
1735: KeInitializeEvent(
1736: &controllerData->ClearQueueEvent,
1737: SynchronizationEvent,
1738: FALSE);
1739:
1740:
1741:
1742: //
1743: // Create a thread with entry point Q117iTapeThread()
1744: //
1745:
1746: ntStatus = PsCreateSystemThread(
1747: &threadHandle,
1748: (ACCESS_MASK) 0L,
1749: (POBJECT_ATTRIBUTES) NULL,
1750: (HANDLE) 0L,
1751: (PCLIENT_ID) NULL,
1752: (PKSTART_ROUTINE) Q117iTapeThread,
1753: (PVOID) controllerData );
1754:
1755: #if DBG
1756: if ( !NT_SUCCESS( ntStatus ) ) {
1757:
1758: CheckedDump(QIC117DBGP,( "q117i: error %x creating thread\n", ntStatus ));
1759: }
1760: #endif
1761:
1762: if ( NT_SUCCESS( ntStatus ) ) {
1763:
1764: CheckedDump(QIC117INFO,("Q117iThread = %x\n",threadHandle));
1765:
1766: //
1767: // Call Q117iInitializeDrive() for each drive on the
1768: // controller
1769: //
1770:
1771: ConfigData->Controller[ControllerNumber].NumberOfTapeDrives++;
1772:
1773: ntStatus = STATUS_NO_SUCH_DEVICE;
1774: partlySuccessful = FALSE;
1775:
1776: ntStatus = Q117iInitializeDrive(
1777: ConfigData,
1778: controllerData,
1779: ControllerNumber,
1780: DriverObject,
1781: RegistryPath );
1782: }
1783:
1784: }
1785:
1786: //
1787: // If we're exiting with an error, clean up first.
1788: //
1789:
1790: if ( !NT_SUCCESS( ntStatus ) ) {
1791:
1792: CheckedDump(QIC117DBGP,( "q117i: InitializeController failing\n" ));
1793:
1794: //
1795: // If we created the thread, wake it up and tell it to kill itself.
1796: // Wait until it's dead. (Note that since it's a system thread,
1797: // it has to kill itself - we can't do it).
1798: //
1799:
1800: if ( threadHandle != 0 ) {
1801:
1802: controllerData->UnloadingDriver = TRUE;
1803:
1804: ntStatus2 = ObReferenceObjectByHandle(
1805: threadHandle,
1806: THREAD_ALL_ACCESS,
1807: NULL,
1808: KernelMode,
1809: (PVOID *) &threadObject,
1810: NULL );
1811:
1812: (VOID) KeReleaseSemaphore(
1813: &controllerData->RequestSemaphore,
1814: (KPRIORITY) 0,
1815: 1,
1816: FALSE );
1817:
1818: if ( NT_SUCCESS( ntStatus2 ) ) {
1819:
1820: //
1821: // The thread object will be signalled when it dies.
1822: //
1823:
1824: ntStatus2 = KeWaitForSingleObject(
1825: (PVOID) threadObject,
1826: Suspended,
1827: KernelMode,
1828: FALSE,
1829: (PLARGE_INTEGER) NULL );
1830:
1831: ASSERT( ntStatus2 == STATUS_SUCCESS );
1832:
1833: ObDereferenceObject( threadObject );
1834:
1835: } else {
1836:
1837: //
1838: // We can't get the thread object for some reason; just
1839: // block for a while to give the thread a chance to run
1840: // and die.
1841: //
1842:
1843: CheckedDump(QIC117DBGP,( "q117i: couldn't get thread object\n" ));
1844:
1845:
1846: timeout =
1847: RtlLargeIntegerNegate(
1848: RtlEnlargedIntegerMultiply(
1849: 10,
1850: 10l * 1000l
1851: )
1852: );
1853: (VOID) KeDelayExecutionThread(
1854: KernelMode,
1855: FALSE,
1856: &timeout );
1857: }
1858: }
1859:
1860:
1861: if ( controllerData->InterruptObject != NULL ) {
1862:
1863: (VOID) KeSetEvent(
1864: controllerData->ControllerEvent,
1865: (KPRIORITY) 0,
1866: FALSE );
1867:
1868: IoDisconnectInterrupt( controllerData->InterruptObject );
1869: }
1870:
1871: ExFreePool( controllerData );
1872:
1873: }
1874:
1875: return ntStatus;
1876: }
1877:
1878: BOOLEAN
1879: Q117iReportResources(
1880: IN PDRIVER_OBJECT DriverObject,
1881: IN PCONFIG_DATA ConfigData,
1882: IN UCHAR ControllerNumber
1883: )
1884:
1885: /*++
1886:
1887: Routine Description:
1888:
1889: This routine will build up a resource list using the
1890: data for this particular controller as well as all
1891: previous *successfully* configured controllers.
1892:
1893: N.B. This routine assumes that it called in controller
1894: number order.
1895:
1896: Arguments:
1897:
1898: DriverObject - a pointer to the object that represents this device
1899: driver.
1900:
1901: ConfigData - a pointer to the structure that describes the
1902: controller and the disks attached to it, as given to us by the
1903: configuration manager.
1904:
1905: ControllerNumber - which controller in ConfigData we are
1906: about to try to report.
1907:
1908: Return Value:
1909:
1910: TRUE if no conflict was detected, FALSE otherwise.
1911:
1912: --*/
1913:
1914: {
1915:
1916:
1917: ULONG sizeOfResourceList;
1918: ULONG numberOfFrds;
1919: LONG i;
1920: PCM_RESOURCE_LIST resourceList;
1921: PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;
1922:
1923: //
1924: // Loop through all of the controllers previous to this
1925: // controller. If the controllers previous to this one
1926: // didn't have a conflict, then accumulate the size of the
1927: // CM_FULL_RESOURCE_DESCRIPTOR associated with it.
1928: //
1929:
1930: for (
1931: i = 0,numberOfFrds = 0,sizeOfResourceList = 0;
1932: i <= ControllerNumber;
1933: i++
1934: ) {
1935:
1936: if (ConfigData->Controller[i].OkToUseThisController) {
1937:
1938: sizeOfResourceList += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
1939:
1940: //
1941: // The full resource descriptor already contains one
1942: // partial. Make room for three more.
1943: //
1944: // It will hold the irq "prd", the controller "csr" "prd" which
1945: // is actually in two pieces since we don't use one of the
1946: // registers, and the controller dma "prd".
1947: //
1948:
1949: sizeOfResourceList += 3*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1950: numberOfFrds++;
1951:
1952: }
1953:
1954: }
1955:
1956: //
1957: // Now we increment the length of the resource list by field offset
1958: // of the first frd. This will give us the length of what preceeds
1959: // the first frd in the resource list.
1960: //
1961:
1962: sizeOfResourceList += FIELD_OFFSET(
1963: CM_RESOURCE_LIST,
1964: List[0]
1965: );
1966:
1967: resourceList = ExAllocatePool(
1968: PagedPool,
1969: sizeOfResourceList
1970: );
1971:
1972: if (!resourceList) {
1973:
1974: return FALSE;
1975:
1976: }
1977:
1978: //
1979: // Zero out the field
1980: //
1981:
1982: RtlZeroMemory(
1983: resourceList,
1984: sizeOfResourceList
1985: );
1986:
1987: resourceList->Count = numberOfFrds;
1988: nextFrd = &resourceList->List[0];
1989:
1990: for (
1991: i = 0;
1992: numberOfFrds;
1993: i++
1994: ) {
1995:
1996: if (ConfigData->Controller[i].OkToUseThisController) {
1997:
1998: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
1999:
2000: nextFrd->InterfaceType = ConfigData->Controller[i].InterfaceType;
2001: nextFrd->BusNumber = ConfigData->Controller[i].BusNumber;
2002:
2003: //
2004: // We are only going to report 4 items no matter what
2005: // was in the original.
2006: //
2007:
2008: nextFrd->PartialResourceList.Count = 4;
2009:
2010: //
2011: // Now fill in the port data. We don't wish to share
2012: // this port range with anyone
2013: //
2014:
2015: partial = &nextFrd->PartialResourceList.PartialDescriptors[0];
2016:
2017: partial->Type = CmResourceTypePort;
2018: partial->ShareDisposition = CmResourceShareShared;
2019: partial->Flags = 0;
2020: partial->u.Port.Start =
2021: ConfigData->Controller[i].OriginalBaseAddress;
2022: partial->u.Port.Length = 6;
2023:
2024: partial++;
2025:
2026: partial->Type = CmResourceTypePort;
2027: partial->ShareDisposition = CmResourceShareShared;
2028: partial->Flags = 0;
2029: partial->u.Port.Start = RtlLargeIntegerAdd(
2030: ConfigData->Controller[i].OriginalBaseAddress,
2031: RtlConvertUlongToLargeInteger((ULONG)7)
2032: );
2033: partial->u.Port.Length = 1;
2034:
2035: partial++;
2036:
2037: partial->Type = CmResourceTypeDma;
2038: partial->ShareDisposition = CmResourceShareShared;
2039: partial->Flags = 0;
2040: partial->u.Dma.Channel =
2041: ConfigData->Controller[i].OriginalDmaChannel;
2042:
2043: partial++;
2044:
2045: //
2046: // Now fill in the irq stuff.
2047: //
2048:
2049: partial->Type = CmResourceTypeInterrupt;
2050: partial->ShareDisposition = CmResourceShareShared;
2051: partial->u.Interrupt.Level =
2052: ConfigData->Controller[i].OriginalIrql;
2053: partial->u.Interrupt.Vector =
2054: ConfigData->Controller[i].OriginalVector;
2055:
2056: if (ConfigData->Controller[i].InterruptMode == Latched) {
2057:
2058: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2059:
2060: } else {
2061:
2062: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2063:
2064: }
2065:
2066: partial++;
2067:
2068: nextFrd = (PVOID)partial;
2069:
2070: numberOfFrds--;
2071:
2072: }
2073:
2074: }
2075:
2076: IoReportResourceUsage(
2077: NULL,
2078: DriverObject,
2079: resourceList,
2080: sizeOfResourceList,
2081: NULL,
2082: NULL,
2083: 0,
2084: FALSE,
2085: &ConfigData->Controller[ControllerNumber].OkToUseThisController
2086: );
2087:
2088: //
2089: // The above routine sets the boolean the parameter
2090: // to TRUE if a conflict was detected.
2091: //
2092:
2093: ConfigData->Controller[ControllerNumber].OkToUseThisController =
2094: !ConfigData->Controller[ControllerNumber].OkToUseThisController;
2095:
2096: ExFreePool(resourceList);
2097:
2098: return ConfigData->Controller[ControllerNumber].OkToUseThisController;
2099:
2100: }
2101:
2102: NTSTATUS
2103: Q117iInitializeDrive(
2104: IN PCONFIG_DATA ConfigData,
2105: IN PTAPE_CONTROLLER_DATA ControllerData,
2106: IN UCHAR ControllerNum,
2107: IN PDRIVER_OBJECT DriverObject,
2108: IN PUNICODE_STRING RegistryPath
2109: )
2110:
2111: /*++
2112:
2113: Routine Description:
2114:
2115: This routine is called at initialization time by
2116: Q117iInitializeController(), once for each disk that we are supporting
2117: on the controller.
2118:
2119: Arguments:
2120:
2121: ConfigData - a pointer to the structure that describes the
2122: controller and the disks attached to it, as given to us by the
2123: configuration manager.
2124:
2125: ControllerData - a pointer to our data area for this controller.
2126:
2127: ControllerNum - which controller in ConfigData we're working on.
2128:
2129: DisketteNum - which logical disk on the current controller we're
2130: working on.
2131:
2132: DisketteUnit - which physical disk on the current controller we're
2133: working on. Only different from DisketteNum when we're creating a
2134: secondary device object for a previously initialized drive.
2135:
2136: DriverObject - a pointer to the object that represents this device
2137: driver.
2138:
2139: Return Value:
2140:
2141: STATUS_SUCCESS if this disk is initialized; an error otherwise.
2142:
2143: --*/
2144:
2145: {
2146: UCHAR ntNameBuffer[256];
2147: STRING ntNameString;
2148: UNICODE_STRING ntUnicodeString;
2149: NTSTATUS ntStatus;
2150: PDEVICE_OBJECT deviceObject = NULL;
2151: PTAPE_EXTENSION tapeExtension;
2152: STATUS retval;
2153:
2154: CheckedDump(QIC117INFO,( "Q117iInitializeDrive...\n" ));
2155:
2156: (VOID) sprintf(
2157: ntNameBuffer,
2158: "\\Device\\q117i%d", ConfigData->FloppyTapeCount);
2159:
2160: RtlInitString( &ntNameString, ntNameBuffer );
2161:
2162: ntStatus = RtlAnsiStringToUnicodeString(
2163: &ntUnicodeString,
2164: &ntNameString,
2165: TRUE );
2166:
2167: if ( NT_SUCCESS( ntStatus ) ) {
2168:
2169: //
2170: // Create a device object for this floppy drive.
2171: //
2172:
2173: ntStatus = IoCreateDevice(
2174: DriverObject,
2175: sizeof( TAPE_EXTENSION ),
2176: &ntUnicodeString,
2177: FILE_DEVICE_TAPE,
2178: FILE_REMOVABLE_MEDIA,
2179: FALSE,
2180: &deviceObject );
2181:
2182: RtlFreeUnicodeString(&ntUnicodeString);
2183:
2184: }
2185:
2186:
2187:
2188: if ( NT_SUCCESS( ntStatus ) ) {
2189:
2190: IoInitializeDpcRequest( deviceObject, Q117iTapeDeferredProcedure );
2191:
2192: tapeExtension = deviceObject->DeviceExtension;
2193: tapeExtension->SpeedChangeOK = FALSE;
2194: tapeExtension->PegasusSupported = TRUE;
2195: tapeExtension->Found = FALSE;
2196: tapeExtension->NoCart = TRUE;
2197: tapeExtension->ErrorSequence = 0;
2198: tapeExtension->TapeNumber = IoGetConfigurationInformation()->TapeCount;
2199: tapeExtension->DriveParms.Mode = PRIMARY_MODE;
2200: tapeExtension->DriveParms.Flavor = (UCHAR) UNKNOWN;
2201: tapeExtension->QDeviceObject = deviceObject;
2202: tapeExtension->QControllerData = ControllerData;
2203: tapeExtension->QControllerData->StartFormatMode = FALSE;
2204: tapeExtension->QControllerData->EndFormatMode = FALSE;
2205: tapeExtension->QControllerData->ClearQueue = FALSE;
2206: tapeExtension->QControllerData->AbortRequested = FALSE;
2207: tapeExtension->QControllerData->AdapterLocked = FALSE;
2208: tapeExtension->QControllerData->PerpendicularMode = FALSE;
2209: tapeExtension->XferRate.XferRate = SLOW;
2210: tapeExtension->XferRate.TapeSlow = TAPE_250Kbps;
2211: tapeExtension->XferRate.TapeFast = TAPE_500Kbps;
2212: tapeExtension->XferRate.FDC_Slow = FDC_250Kbps;
2213: tapeExtension->XferRate.FDC_Fast = FDC_500Kbps;
2214: tapeExtension->XferRate.SRT_Slow = SRT_250Kbps;
2215: tapeExtension->XferRate.SRT_Fast = SRT_500Kbps;
2216:
2217: tapeExtension->QControllerData->AdapterObject =
2218: ConfigData->Controller[ControllerNum].AdapterObject;
2219:
2220: tapeExtension->QControllerData->NumberOfMapRegisters =
2221: ConfigData->Controller[ControllerNum].NumberOfMapRegisters;
2222:
2223: tapeExtension->QControllerData->TapeExtension = tapeExtension;
2224:
2225: #if DBG
2226: tapeExtension->DbgHead = tapeExtension->DbgTail = 0;
2227: #endif
2228:
2229: tapeExtension->QControllerData->CurrentInterrupt = TRUE;
2230:
2231:
2232: retval = Q117iDLocateDrv(tapeExtension);
2233:
2234: tapeExtension->PersistentNewCart = FALSE;
2235: ntStatus = Q117iTranslateError( deviceObject, retval );
2236: tapeExtension->PersistentNewCart = TRUE;
2237:
2238: tapeExtension->QControllerData->CurrentInterrupt = FALSE;
2239: }
2240:
2241: //
2242: // Initialize the filer level tape device
2243: //
2244:
2245: if ( NT_SUCCESS( ntStatus ) ) {
2246:
2247: ntStatus = q117Initialize(
2248: DriverObject,
2249: deviceObject,
2250: RegistryPath,
2251: ConfigData->Controller[ControllerNum].AdapterObject,
2252: ConfigData->Controller[ControllerNum].NumberOfMapRegisters
2253: );
2254:
2255: }
2256:
2257: if ( NT_SUCCESS( ntStatus ) ) {
2258:
2259: ConfigData->FloppyTapeCount++;
2260:
2261: } else {
2262:
2263: //
2264: // If we're failing, clean up and delete the device object.
2265: //
2266:
2267: CheckedDump(QIC117DBGP,( "Q117i: InitializeDrive failing %x\n", ntStatus ));
2268:
2269: if ( deviceObject != NULL ) {
2270:
2271: IoDeleteDevice( deviceObject );
2272: }
2273: }
2274:
2275: return ntStatus;
2276: }
2277:
2278: ULONG
2279: Q117iGetControllerBase(
2280: IN INTERFACE_TYPE BusType,
2281: IN ULONG BusNumber,
2282: PHYSICAL_ADDRESS IoAddress,
2283: ULONG NumberOfBytes,
2284: BOOLEAN InIoSpace,
2285: PBOOLEAN MappedAddress
2286: )
2287:
2288: /*++
2289:
2290: Routine Description:
2291:
2292: This routine maps an IO address to system address space.
2293:
2294: Arguments:
2295:
2296: BusType - what type of bus - eisa, mca, isa
2297: IoBusNumber - which IO bus (for machines with multiple buses).
2298: IoAddress - base device address to be mapped.
2299: NumberOfBytes - number of bytes for which address is valid.
2300: InIoSpace - indicates an IO address.
2301: MappedAddress - indicates whether the address was mapped.
2302: This only has meaning if the address returned
2303: is non-null.
2304:
2305: Return Value:
2306:
2307: Mapped address
2308:
2309: --*/
2310:
2311: {
2312: PHYSICAL_ADDRESS cardAddress;
2313: ULONG addressSpace = InIoSpace;
2314: ULONG Address;
2315:
2316: HalTranslateBusAddress(
2317: BusType,
2318: BusNumber,
2319: IoAddress,
2320: &addressSpace,
2321: &cardAddress
2322: );
2323:
2324: //
2325: // Map the device base address into the virtual address space
2326: // if the address is in memory space.
2327: //
2328:
2329: if (!addressSpace) {
2330:
2331: Address = (ULONG)MmMapIoSpace(
2332: cardAddress,
2333: NumberOfBytes,
2334: FALSE
2335: );
2336:
2337: *MappedAddress = (BOOLEAN)((Address)?(TRUE):(FALSE));
2338:
2339:
2340: } else {
2341:
2342: Address = (ULONG)cardAddress.LowPart;
2343: }
2344:
2345: return Address;
2346:
2347: }
2348:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.