2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
5 * PURPOSE: Driver entry point
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
22 /* See debug.h for debug/trace constants */
23 DWORD DebugTraceLevel
= MIN_TRACE
;
27 PDEVICE_OBJECT TCPDeviceObject
= NULL
;
28 PDEVICE_OBJECT UDPDeviceObject
= NULL
;
29 PDEVICE_OBJECT IPDeviceObject
= NULL
;
30 PDEVICE_OBJECT RawIPDeviceObject
= NULL
;
31 NDIS_HANDLE GlobalPacketPool
= NULL
;
32 NDIS_HANDLE GlobalBufferPool
= NULL
;
33 TDIEntityID
*EntityList
= NULL
;
34 ULONG EntityCount
= 0;
35 UDP_STATISTICS UDPStats
;
39 PDRIVER_OBJECT DriverContext
,
41 ULONG UniqueErrorValue
,
47 * FUNCTION: Writes an error log entry
49 * DriverContext = Pointer to the driver or device object
50 * ErrorCode = An error code to put in the log entry
51 * UniqueErrorValue = UniqueErrorValue in the error log packet
52 * FinalStatus = FinalStatus in the error log packet
53 * String = If not NULL, a pointer to a string to put in log entry
54 * DumpDataCount = Number of ULONGs of dump data
55 * DumpData = Pointer to dump data for the log entry
59 PIO_ERROR_LOG_PACKET LogEntry
;
63 static WCHAR DriverName
[] = L
"TCP/IP";
65 EntrySize
= sizeof(IO_ERROR_LOG_PACKET
) +
66 (DumpDataCount
* sizeof(ULONG
)) + sizeof(DriverName
);
69 StringSize
= (wcslen(String
) * sizeof(WCHAR
)) + sizeof(UNICODE_NULL
);
70 EntrySize
+= (UCHAR
)StringSize
;
73 LogEntry
= (PIO_ERROR_LOG_PACKET
)IoAllocateErrorLogEntry(
74 DriverContext
, EntrySize
);
77 LogEntry
->MajorFunctionCode
= -1;
78 LogEntry
->RetryCount
= -1;
79 LogEntry
->DumpDataSize
= (USHORT
)(DumpDataCount
* sizeof(ULONG
));
80 LogEntry
->NumberOfStrings
= (String
== NULL
) ? 1 : 2;
81 LogEntry
->StringOffset
= sizeof(IO_ERROR_LOG_PACKET
) + (DumpDataCount
-1) * sizeof(ULONG
);
82 LogEntry
->EventCategory
= 0;
83 LogEntry
->ErrorCode
= ErrorCode
;
84 LogEntry
->UniqueErrorValue
= UniqueErrorValue
;
85 LogEntry
->FinalStatus
= FinalStatus
;
86 LogEntry
->SequenceNumber
= -1;
87 LogEntry
->IoControlCode
= 0;
90 RtlCopyMemory(LogEntry
->DumpData
, DumpData
, DumpDataCount
* sizeof(ULONG
));
92 pString
= ((PUCHAR
)LogEntry
) + LogEntry
->StringOffset
;
93 RtlCopyMemory(pString
, DriverName
, sizeof(DriverName
));
94 pString
+= sizeof(DriverName
);
97 RtlCopyMemory(pString
, String
, StringSize
);
99 IoWriteErrorLogEntry(LogEntry
);
106 * FUNCTION: Creates a file object
108 * DeviceObject = Pointer to a device object for this driver
109 * Irp = Pointer to a I/O request packet
111 * Status of the operation
113 NTSTATUS
TiCreateFileObject(
114 PDEVICE_OBJECT DeviceObject
,
117 PIO_STACK_LOCATION IrpSp
;
118 PFILE_FULL_EA_INFORMATION EaInfo
;
119 PTA_ADDRESS_IP Address
;
120 PTRANSPORT_CONTEXT Context
;
124 TI_DbgPrint(DEBUG_IRP
, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject
, Irp
));
126 EaInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
128 /* Parameter check */
130 TI_DbgPrint(MIN_TRACE
, ("No EA information in IRP.\n"));
131 return STATUS_INVALID_PARAMETER
;
134 /* Allocate resources here. We release them again if something failed */
135 Context
= ExAllocatePool(NonPagedPool
, sizeof(TRANSPORT_CONTEXT
));
137 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
138 return STATUS_INSUFFICIENT_RESOURCES
;
141 Context
->RefCount
= 1;
142 Context
->CancelIrps
= FALSE
;
143 KeInitializeEvent(&Context
->CleanupEvent
, NotificationEvent
, FALSE
);
145 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
146 IrpSp
->FileObject
->FsContext
= Context
;
147 Request
.RequestContext
= Irp
;
149 /* Branch to the right handler */
150 if ((EaInfo
->EaNameLength
==TDI_TRANSPORT_ADDRESS_LENGTH
) &&
151 (RtlCompareMemory(&EaInfo
->EaName
, TdiTransportAddress
,
152 TDI_TRANSPORT_ADDRESS_LENGTH
) == TDI_TRANSPORT_ADDRESS_LENGTH
)) {
153 /* This is a request to open an address */
155 /* Parameter checks */
156 Address
= (PTA_ADDRESS_IP
)(EaInfo
->EaName
+ EaInfo
->EaNameLength
+ 1);
157 if ((EaInfo
->EaValueLength
< sizeof(TA_ADDRESS_IP
)) ||
158 (Address
->TAAddressCount
!= 1) ||
159 (Address
->Address
[0].AddressLength
< sizeof(TDI_ADDRESS_IP
)) ||
160 (Address
->Address
[0].AddressType
!= TDI_ADDRESS_TYPE_IP
)) {
161 TI_DbgPrint(MIN_TRACE
, ("Parameters are invalid.\n"));
163 return STATUS_INVALID_PARAMETER
;
166 /* Open address file object */
167 /* FIXME: Protocol depends on device object */
168 Status
= FileOpenAddress(&Request
, Address
, IPPROTO_UDP
, NULL
);
169 if (NT_SUCCESS(Status
)) {
170 IrpSp
->FileObject
->FsContext2
= (PVOID
)TDI_TRANSPORT_ADDRESS_FILE
;
171 Context
->Handle
.AddressHandle
= Request
.Handle
.AddressHandle
;
174 TI_DbgPrint(MIN_TRACE
, ("Connection point, and control connections are not supported.\n"));
175 /* FIXME: Open a connection endpoint, or control connection */
176 Status
= STATUS_NOT_IMPLEMENTED
;
179 if (!NT_SUCCESS(Status
))
182 TI_DbgPrint(DEBUG_IRP
, ("Leaving. Status = (0x%X).\n", Status
));
188 VOID
TiCleanupFileObjectComplete(
192 * FUNCTION: Completes an object cleanup IRP I/O request
194 * Context = Pointer to the IRP for this request
195 * Status = Final status of the operation
199 PIO_STACK_LOCATION IrpSp
;
200 PTRANSPORT_CONTEXT TranContext
;
204 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
205 TranContext
= (PTRANSPORT_CONTEXT
)IrpSp
->FileObject
->FsContext
;
207 Irp
->IoStatus
.Status
= Status
;
209 IoAcquireCancelSpinLock(&OldIrql
);
211 /* Remove the initial reference provided at object creation time */
212 TranContext
->RefCount
--;
215 if (TranContext
->RefCount
!= 0)
216 TI_DbgPrint(DEBUG_REFCOUNT
, ("TranContext->RefCount is %i, should be 0.\n", TranContext
->RefCount
));
219 KeSetEvent(&TranContext
->CleanupEvent
, 0, FALSE
);
221 IoReleaseCancelSpinLock(OldIrql
);
226 * FUNCTION: Releases resources used by a file object
228 * DeviceObject = Pointer to a device object for this driver
229 * Irp = Pointer to a I/O request packet
231 * Status of the operation
233 * This function does not pend
235 NTSTATUS
TiCleanupFileObject(
236 PDEVICE_OBJECT DeviceObject
,
239 PIO_STACK_LOCATION IrpSp
;
240 PTRANSPORT_CONTEXT Context
;
245 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
246 Context
= IrpSp
->FileObject
->FsContext
;
248 TI_DbgPrint(MIN_TRACE
, ("Parameters are invalid.\n"));
249 return STATUS_INVALID_PARAMETER
;
252 IoAcquireCancelSpinLock(&OldIrql
);
254 Context
->CancelIrps
= TRUE
;
255 KeResetEvent(&Context
->CleanupEvent
);
257 IoReleaseCancelSpinLock(OldIrql
);
259 Request
.RequestNotifyObject
= TiCleanupFileObjectComplete
;
260 Request
.RequestContext
= Irp
;
262 switch ((ULONG_PTR
)IrpSp
->FileObject
->FsContext2
) {
263 case TDI_TRANSPORT_ADDRESS_FILE
:
264 Request
.Handle
.AddressHandle
= Context
->Handle
.AddressHandle
;
265 Status
= FileCloseAddress(&Request
);
268 case TDI_CONNECTION_FILE
:
269 Request
.Handle
.ConnectionContext
= Context
->Handle
.ConnectionContext
;
270 Status
= FileCloseConnection(&Request
);
273 case TDI_CONTROL_CHANNEL_FILE
:
274 Request
.Handle
.ControlChannel
= Context
->Handle
.ControlChannel
;
275 Status
= FileCloseControlChannel(&Request
);
279 /* This should never happen */
281 TI_DbgPrint(MIN_TRACE
, ("Unknown transport context.\n"));
283 IoAcquireCancelSpinLock(&OldIrql
);
284 Context
->CancelIrps
= FALSE
;
285 IoReleaseCancelSpinLock(OldIrql
);
287 return STATUS_INVALID_PARAMETER
;
290 if (Status
!= STATUS_PENDING
)
291 TiCleanupFileObjectComplete(Irp
, Status
);
293 KeWaitForSingleObject(&Context
->CleanupEvent
,
294 UserRequest
, KernelMode
, FALSE
, NULL
);
296 return Irp
->IoStatus
.Status
;
300 NTSTATUS
TiDispatchOpenClose(
301 PDEVICE_OBJECT DeviceObject
,
304 * FUNCTION: Main dispath routine
306 * DeviceObject = Pointer to a device object for this driver
307 * Irp = Pointer to a I/O request packet
309 * Status of the operation
312 PIO_STACK_LOCATION IrpSp
;
314 PTRANSPORT_CONTEXT Context
;
316 TI_DbgPrint(DEBUG_IRP
, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject
, Irp
));
318 IoMarkIrpPending(Irp
);
319 Irp
->IoStatus
.Status
= STATUS_PENDING
;
320 Irp
->IoStatus
.Information
= 0;
322 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
324 switch (IrpSp
->MajorFunction
) {
325 /* Open an address file, connection endpoint, or control connection */
327 Status
= TiCreateFileObject(DeviceObject
, Irp
);
330 /* Close an address file, connection endpoint, or control connection */
332 Context
= (PTRANSPORT_CONTEXT
)IrpSp
->FileObject
->FsContext
;
335 Status
= STATUS_SUCCESS
;
338 /* Release resources bound to an address file, connection endpoint,
339 or control connection */
341 Status
= TiCleanupFileObject(DeviceObject
, Irp
);
345 Status
= STATUS_INVALID_DEVICE_REQUEST
;
348 if (Status
!= STATUS_PENDING
) {
349 IrpSp
->Control
&= ~SL_PENDING_RETURNED
;
350 Irp
->IoStatus
.Status
= Status
;
352 TI_DbgPrint(DEBUG_IRP
, ("Completing IRP at (0x%X).\n", Irp
));
354 IoCompleteRequest(Irp
, IO_NETWORK_INCREMENT
);
357 TI_DbgPrint(DEBUG_IRP
, ("Leaving. Status is (0x%X)\n", Status
));
363 NTSTATUS
TiDispatchInternal(
364 PDEVICE_OBJECT DeviceObject
,
367 * FUNCTION: Internal IOCTL dispatch routine
369 * DeviceObject = Pointer to a device object for this driver
370 * Irp = Pointer to a I/O request packet
372 * Status of the operation
376 PIO_STACK_LOCATION IrpSp
;
378 TI_DbgPrint(DEBUG_IRP
, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject
, Irp
));
380 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
382 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
383 Irp
->IoStatus
.Information
= 0;
385 switch (IrpSp
->MinorFunction
) {
387 Status
= DispTdiReceive(Irp
);
390 case TDI_RECEIVE_DATAGRAM
:
391 Status
= DispTdiReceiveDatagram(Irp
);
395 Status
= DispTdiSend(Irp
);
398 case TDI_SEND_DATAGRAM
:
399 Status
= DispTdiSendDatagram(Irp
);
403 Status
= DispTdiAccept(Irp
);
407 Status
= DispTdiListen(Irp
);
411 Status
= DispTdiConnect(Irp
);
415 Status
= DispTdiDisconnect(Irp
);
418 case TDI_ASSOCIATE_ADDRESS
:
419 Status
= DispTdiAssociateAddress(Irp
);
422 case TDI_DISASSOCIATE_ADDRESS
:
423 Status
= DispTdiDisassociateAddress(Irp
);
426 case TDI_QUERY_INFORMATION
:
427 Status
= DispTdiQueryInformation(DeviceObject
, Irp
);
430 case TDI_SET_INFORMATION
:
431 Status
= DispTdiSetInformation(Irp
);
434 case TDI_SET_EVENT_HANDLER
:
435 Status
= DispTdiSetEventHandler(Irp
);
439 Status
= STATUS_SUCCESS
;
442 /* An unsupported IOCTL code was submitted */
444 Status
= STATUS_INVALID_DEVICE_REQUEST
;
447 if (Status
!= STATUS_PENDING
) {
448 Irp
->IoStatus
.Status
= Status
;
450 TI_DbgPrint(DEBUG_IRP
, ("Completing IRP at (0x%X).\n", Irp
));
452 IoCompleteRequest(Irp
, IO_NETWORK_INCREMENT
);
455 TI_DbgPrint(DEBUG_IRP
, ("Leaving. Status = (0x%X).\n", Status
));
462 PDEVICE_OBJECT DeviceObject
,
465 * FUNCTION: Dispath routine for IRP_MJ_DEVICE_CONTROL requests
467 * DeviceObject = Pointer to a device object for this driver
468 * Irp = Pointer to a I/O request packet
470 * Status of the operation
474 PIO_STACK_LOCATION IrpSp
;
476 TI_DbgPrint(DEBUG_IRP
, ("Called. IRP is at (0x%X).\n", Irp
));
478 Irp
->IoStatus
.Information
= 0;
480 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
482 Status
= TdiMapUserRequest(DeviceObject
, Irp
, IrpSp
);
483 if (NT_SUCCESS(Status
)) {
484 TiDispatchInternal(DeviceObject
, Irp
);
485 Status
= STATUS_PENDING
;
490 /* See if this request is TCP/IP specific */
491 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
) {
492 case IOCTL_TCP_QUERY_INFORMATION_EX
:
493 Status
= DispTdiQueryInformationEx(Irp
, IrpSp
);
496 case IOCTL_TCP_SET_INFORMATION_EX
:
497 Status
= DispTdiSetInformationEx(Irp
, IrpSp
);
501 TI_DbgPrint(MIN_TRACE
, ("Unknown IOCTL 0x%X\n",
502 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
));
503 Status
= STATUS_NOT_IMPLEMENTED
;
508 if (Status
!= STATUS_PENDING
) {
509 Irp
->IoStatus
.Status
= Status
;
511 TI_DbgPrint(DEBUG_IRP
, ("Completing IRP at (0x%X).\n", Irp
));
513 IoCompleteRequest(Irp
, IO_NETWORK_INCREMENT
);
516 TI_DbgPrint(DEBUG_IRP
, ("Leaving. Status = (0x%X).\n", Status
));
523 PDRIVER_OBJECT DriverObject
)
525 * FUNCTION: Unloads the driver
527 * DriverObject = Pointer to driver object created by the system
533 KeAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
534 if (!IsListEmpty(&AddressFileListHead
)) {
535 TI_DbgPrint(MIN_TRACE
, ("Open address file objects exists.\n"));
537 KeReleaseSpinLock(&AddressFileListLock
, OldIrql
);
540 /* Unregister loopback adapter */
541 LoopUnregisterAdapter(NULL
);
543 /* Unregister protocol with NDIS */
544 LANUnregisterProtocol();
546 /* Shutdown transport level protocol subsystems */
552 /* Shutdown network level protocol subsystem */
555 /* Free NDIS buffer descriptors */
556 if (GlobalBufferPool
)
557 NdisFreeBufferPool(GlobalBufferPool
);
559 /* Free NDIS packet descriptors */
560 if (GlobalPacketPool
)
561 NdisFreePacketPool(GlobalPacketPool
);
563 /* Release all device objects */
566 IoDeleteDevice(TCPDeviceObject
);
569 IoDeleteDevice(UDPDeviceObject
);
571 if (RawIPDeviceObject
)
572 IoDeleteDevice(RawIPDeviceObject
);
575 IoDeleteDevice(IPDeviceObject
);
578 ExFreePool(EntityList
);
580 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
589 PDRIVER_OBJECT DriverObject
,
590 PUNICODE_STRING RegistryPath
)
592 * FUNCTION: Main driver entry point
594 * DriverObject = Pointer to a driver object for this driver
595 * RegistryPath = Registry node for configuration parameters
597 * Status of driver initialization
601 UNICODE_STRING strDeviceName
;
602 STRING strNdisDeviceName
;
603 NDIS_STATUS NdisStatus
;
604 PLAN_ADAPTER Adapter
;
605 NDIS_STRING DeviceName
;
607 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
609 /* FIXME: Create symbolic links in Win32 namespace */
611 /* Create IP device object */
612 RtlInitUnicodeString(&strDeviceName
, DD_IP_DEVICE_NAME
);
613 Status
= IoCreateDevice(DriverObject
, 0, &strDeviceName
,
614 FILE_DEVICE_NETWORK
, 0, FALSE
, &IPDeviceObject
);
615 if (!NT_SUCCESS(Status
)) {
616 TI_DbgPrint(MIN_TRACE
, ("Failed to create IP device object. Status (0x%X).\n", Status
));
620 /* Create RawIP device object */
621 RtlInitUnicodeString(&strDeviceName
, DD_RAWIP_DEVICE_NAME
);
622 Status
= IoCreateDevice(DriverObject
, 0, &strDeviceName
,
623 FILE_DEVICE_NETWORK
, 0, FALSE
, &RawIPDeviceObject
);
624 if (!NT_SUCCESS(Status
)) {
625 TI_DbgPrint(MIN_TRACE
, ("Failed to create RawIP device object. Status (0x%X).\n", Status
));
626 TiUnload(DriverObject
);
630 /* Create UDP device object */
631 RtlInitUnicodeString(&strDeviceName
, DD_UDP_DEVICE_NAME
);
632 Status
= IoCreateDevice(DriverObject
, 0, &strDeviceName
,
633 FILE_DEVICE_NETWORK
, 0, FALSE
, &UDPDeviceObject
);
634 if (!NT_SUCCESS(Status
)) {
635 TI_DbgPrint(MIN_TRACE
, ("Failed to create UDP device object. Status (0x%X).\n", Status
));
636 TiUnload(DriverObject
);
640 /* Create TCP device object */
641 RtlInitUnicodeString(&strDeviceName
, DD_TCP_DEVICE_NAME
);
642 Status
= IoCreateDevice(DriverObject
, 0, &strDeviceName
,
643 FILE_DEVICE_NETWORK
, 0, FALSE
, &TCPDeviceObject
);
644 if (!NT_SUCCESS(Status
)) {
645 TI_DbgPrint(MIN_TRACE
, ("Failed to create TCP device object. Status (0x%X).\n", Status
));
646 TiUnload(DriverObject
);
650 /* Allocate NDIS packet descriptors */
651 NdisAllocatePacketPool(&NdisStatus
, &GlobalPacketPool
, 100, sizeof(PACKET_CONTEXT
));
652 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
653 TiUnload(DriverObject
);
654 return STATUS_INSUFFICIENT_RESOURCES
;
657 /* Allocate NDIS buffer descriptors */
658 NdisAllocateBufferPool(&NdisStatus
, &GlobalBufferPool
, 100);
659 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
660 TiUnload(DriverObject
);
661 return STATUS_INSUFFICIENT_RESOURCES
;
664 /* Initialize address file list and protecting spin lock */
665 InitializeListHead(&AddressFileListHead
);
666 KeInitializeSpinLock(&AddressFileListLock
);
668 /* Initialize interface list and protecting spin lock */
669 InitializeListHead(&InterfaceListHead
);
670 KeInitializeSpinLock(&InterfaceListLock
);
672 /* Initialize network level protocol subsystem */
673 IPStartup(DriverObject
, RegistryPath
);
675 /* Initialize transport level protocol subsystems */
681 /* Register protocol with NDIS */
682 RtlInitString(&strNdisDeviceName
, IP_DEVICE_NAME
);
683 Status
= LANRegisterProtocol(&strNdisDeviceName
);
684 if (!NT_SUCCESS(Status
)) {
687 EVENT_TRANSPORT_REGISTER_FAILED
,
688 TI_ERROR_DRIVERENTRY
,
693 TiUnload(DriverObject
);
697 /* Open loopback adapter */
698 if (!NT_SUCCESS(LoopRegisterAdapter(NULL
, NULL
))) {
699 TI_DbgPrint(MIN_TRACE
, ("Failed to create loopback adapter. Status (0x%X).\n", Status
));
700 TiUnload(DriverObject
);
701 return STATUS_INSUFFICIENT_RESOURCES
;
705 /* Open underlying adapter(s) we are bound to */
707 /* FIXME: Get binding information from registry */
709 /* Put your own NDIS adapter device name here */
712 NdisInitUnicodeString(&DeviceName
, L
"\\Device\\ne2000");
715 //NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1");
718 //NdisInitUnicodeString(&DeviceName, L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}");
720 NdisStatus
= LANRegisterAdapter(&DeviceName
, &Adapter
);
721 if (!NT_SUCCESS(NdisStatus
)) {
722 TI_DbgPrint(MIN_TRACE
, ("Failed to intialize adapter. Status (0x%X).\n", Status
));
725 EVENT_TRANSPORT_ADAPTER_NOT_FOUND
,
726 TI_ERROR_DRIVERENTRY
,
731 TiUnload(DriverObject
);
732 return STATUS_DEVICE_DOES_NOT_EXIST
;
736 /* Setup network layer and transport layer entities */
737 EntityList
= ExAllocatePool(NonPagedPool
, sizeof(TDIEntityID
) * 2);
738 if (!NT_SUCCESS(Status
)) {
739 TiUnload(DriverObject
);
740 return STATUS_INSUFFICIENT_RESOURCES
;
743 EntityList
[0].tei_entity
= CL_NL_ENTITY
;
744 EntityList
[0].tei_instance
= 0;
745 EntityList
[1].tei_entity
= CL_TL_ENTITY
;
746 EntityList
[1].tei_instance
= 0;
750 IPDeviceObject
->Flags
|= DO_DIRECT_IO
;
751 RawIPDeviceObject
->Flags
|= DO_DIRECT_IO
;
752 UDPDeviceObject
->Flags
|= DO_DIRECT_IO
;
753 TCPDeviceObject
->Flags
|= DO_DIRECT_IO
;
755 /* Initialize the driver object with this driver's entry points */
756 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = TiDispatchOpenClose
;
757 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = TiDispatchOpenClose
;
758 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = TiDispatchOpenClose
;
759 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = TiDispatchInternal
;
760 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = TiDispatch
;
762 DriverObject
->DriverUnload
= (PDRIVER_UNLOAD
)TiUnload
;
764 return STATUS_SUCCESS
;