/*---------------------------------------------------------------------- pnp.c - 4-18-00 Remove IoStartNextPacket call from PnPBoardFDO function 4-06-00 Reject irps for query_device_relations if not a bus_relation request 3-30-99 fix hybernate power on to restore dtr/rts states properly, in RestorePortSettings(). 2-15-99 - allow to hibernate with open ports, restore ports when comes back up now - kpb. 11-24-98 - fix power handling to avoid crash, allow hibernation if no ports open. kpb ----------------------------------------------------------------------*/ #include "precomp.h" #ifdef NT50 NTSTATUS PnPBoardFDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp); NTSTATUS PnPPortFDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp); NTSTATUS PnpPortPDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp); NTSTATUS BoardBusRelations(IN PDEVICE_OBJECT devobj, IN PIRP Irp); NTSTATUS WaitForLowerPdo(IN PDEVICE_OBJECT fdo, IN PIRP Irp); NTSTATUS BoardFilterResReq(IN PDEVICE_OBJECT devobj, IN PIRP Irp); NTSTATUS SerialRemoveFdo(IN PDEVICE_OBJECT pFdo); NTSTATUS SerialIoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj, PIRP PIrp); NTSTATUS Serial_PDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS Serial_FDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS PowerUpDevice(PSERIAL_DEVICE_EXTENSION Ext); void RestorePortSettings(PSERIAL_DEVICE_EXTENSION Ext); //NTSTATUS SerialPoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt, // PDEVICE_OBJECT PDevObj, // PIRP PIrp); //NTSTATUS SerialSetPowerD0(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS OurPowerCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); NTSTATUS SerialD3Complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); NTSTATUS SerialStartDevice( IN PDEVICE_OBJECT Fdo, IN PIRP Irp); NTSTATUS SerialSyncCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT SerialSyncEvent ); NTSTATUS SerialFinishStartDevice(IN PDEVICE_OBJECT Fdo, IN PCM_RESOURCE_LIST resourceList, IN PCM_RESOURCE_LIST trResourceList); static NTSTATUS RocketPortSpecialStartup(PSERIAL_DEVICE_EXTENSION Ext); #if DBG static char *power_strs[] = { "WAIT_WAKE", // 0x00 "POWER_SEQUENCE", // 0x01 "SET_POWER", // 0x02 "QUERY_POWER", // 0x03 "UNKNOWN", // NULL}; static char *pnp_strs[] = { "START_DEVICE", // 0x00 "QUERY_REMOVE_DEVICE", // 0x01 "REMOVE_DEVICE", // 0x02 "CANCEL_REMOVE_DEVICE", // 0x03 "STOP_DEVICE", // 0x04 "QUERY_STOP_DEVICE", // 0x05 "CANCEL_STOP_DEVICE", // 0x06 "QUERY_DEVICE_RELATIONS", // 0x07 "QUERY_INTERFACE", // 0x08 "QUERY_CAPABILITIES", // 0x09 "QUERY_RESOURCES", // 0x0A "QUERY_RESOURCE_REQUIREMENTS", // 0x0B "QUERY_DEVICE_TEXT", // 0x0C "FILTER_RESOURCE_REQUIREMENTS", // 0x0D "UNKNOWN", // "READ_CONFIG", // 0x0F "WRITE_CONFIG", // 0x10 "EJECT", // 0x11 "SET_LOCK", // 0x12 "QUERY_ID", // 0x13 "QUERY_PNP_DEVICE_STATE", // 0x14 "QUERY_BUS_INFORMATION", // 0x15 "PAGING_NOTIFICATION", // 0x16 NULL}; #endif /*---------------------------------------------------------------------- SerialPnpDispatch - This is a dispatch routine for the IRPs that come to the driver with the IRP_MJ_PNP major code (plug-and-play IRPs). |----------------------------------------------------------------------*/ NTSTATUS SerialPnpDispatch(IN PDEVICE_OBJECT devobj, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension; //PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_NOT_SUPPORTED; BOOLEAN acceptingIRPs; int index; // dump out some debug info index = irpStack->MinorFunction; if (index > 0x16) index = 0x0e; #ifdef DO_BUS_EXTENDER if (Ext->IsPDO) { MyKdPrint(D_Pnp,("Port PDO %s PnPIrp:%d,%s\n", Ext->SymbolicLinkName, irpStack->MinorFunction, pnp_strs[index])) InterlockedIncrement(&Ext->PendingIRPCnt); return PnpPortPDO(devobj, Irp); } else #endif { if (Ext->DeviceType == DEV_BOARD) { MyKdPrint(D_Pnp,("Board %s PnPIrp:%d,%s\n", Ext->SymbolicLinkName, irpStack->MinorFunction, pnp_strs[index])) } else { MyKdPrint(D_Pnp,("Port %s PnPIrp:%d,%s\n", Ext->SymbolicLinkName, irpStack->MinorFunction, pnp_strs[index])) } acceptingIRPs = SerialIRPPrologue(Ext); #if 0 if ((irpStack->MinorFunction != IRP_MN_REMOVE_DEVICE) && (irpStack->MinorFunction != IRP_MN_CANCEL_REMOVE_DEVICE) && (irpStack->MinorFunction != IRP_MN_STOP_DEVICE) && (irpStack->MinorFunction != IRP_MN_CANCEL_STOP_DEVICE) && (acceptingIRPs == FALSE)) { MyKdPrint(D_Pnp,("Removed!\n")) Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; SerialCompleteRequest(Ext, Irp, IO_NO_INCREMENT); return STATUS_NO_SUCH_DEVICE; } #endif if (Ext->DeviceType == DEV_BOARD) { return PnPBoardFDO(devobj, Irp); } else { //return PnPPortFDO(devobj, Irp); return PnPBoardFDO(devobj, Irp); } } } /*---------------------------------------------------------------------- PnPBoardFDO - This handles both Board and Port FDO's |----------------------------------------------------------------------*/ NTSTATUS PnPBoardFDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG pendingIRPs; int pass_down = 1; ASSERT( devobj ); ASSERT( Ext ); #if DBG if (* ((BYTE *)(Irp)) != 6) // in signiture of irp { MyKdPrint(D_Pnp,("bad irp!!!\n")) } #endif switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: // 0x00 MyKdPrint(D_Pnp,("StartDevice\n")) status = SerialStartDevice(devobj, Irp); // // Is this were we should register and enable the device, or should it be in // the PDO start? (see DoPnpAssoc(Pdo) in pnpadd.c) // Irp->IoStatus.Status = status; pass_down = 0; // already passed down break; case IRP_MN_STOP_DEVICE: // 0x04 // need to unhook from resources so system rebalance resources // on the fly. MyKdPrint(D_Pnp,("StopDevice\n")) //Ext->Flags |= SERIAL_FLAGS_STOPPED; Ext->PNPState = SERIAL_PNP_STOPPING; Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_STOPPED; Ext->DevicePNPAccept &= ~SERIAL_PNPACCEPT_STOPPING; InterlockedDecrement(&Ext->PendingIRPCnt); // after dec, =1 pendingIRPs = InterlockedDecrement(&Ext->PendingIRPCnt); // after dec, =0 if (pendingIRPs) { KeWaitForSingleObject(&Ext->PendingIRPEvent, Executive, KernelMode, FALSE, NULL); } Ext->FdoStarted = FALSE; // this should stop service of the device #ifdef NT50 if (Ext->DeviceType != DEV_BOARD) { // Disable the interface status = IoSetDeviceInterfaceState( &Ext->DeviceClassSymbolicName, FALSE); if (!NT_SUCCESS(status)) { MyKdPrint(D_Error,("Couldn't clear class association for %s\n", UToC1(&Ext->DeviceClassSymbolicName))) } else { MyKdPrint(D_PnpAdd, ("Cleared class association for device: %s\n and ", UToC1(&Ext->DeviceClassSymbolicName))) } } #endif // Re-increment the count for exit InterlockedIncrement(&Ext->PendingIRPCnt); //after inc=1 InterlockedIncrement(&Ext->PendingIRPCnt); //after inc=2 // exit this irp decr it to=1 status = STATUS_SUCCESS; Irp->IoStatus.Status = STATUS_SUCCESS; //Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; //pass_down = 0; // we are failing it break; #if 0 case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7 if ( irpStack->Parameters.QueryDeviceRelations.Type != BusRelations ) { // // Verifier requires pass down is PDO present // if ( (Ext->DeviceType == DEV_BOARD) && (pdo == 0) ) { status = STATUS_NOT_IMPLEMENTED; pass_down = 0; }; break; } if (!Driver.NoPnpPorts) { if (Ext->DeviceType == DEV_BOARD) { status = BoardBusRelations(devobj, Irp); } } break; #endif #ifdef DO_BUS_EXTENDER case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7 // // Verifier requires pass down is PDO present // if ( (Ext->DeviceType == DEV_BOARD) && (pdo == 0) ) { pass_down = 0; } if ( irpStack->Parameters.QueryDeviceRelations.Type != BusRelations ) { status = STATUS_NOT_IMPLEMENTED; break; } if (!Driver.NoPnpPorts) { if (Ext->DeviceType == DEV_BOARD) { status = BoardBusRelations(devobj, Irp); } } break; #endif #ifdef DO_BRD_FILTER_RES_REQ case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 0x0D if (Ext->DeviceType == DEV_BOARD) { status = BoardFilterResReq(devobj, Irp); pass_down = 0; // already passed down } break; #endif case IRP_MN_QUERY_STOP_DEVICE: // 0x05 MyKdPrint(D_Pnp,("QueryStopDevice\n")) status = STATUS_SUCCESS; if (Ext->DeviceType == DEV_BOARD) { if (is_board_in_use(Ext)) status = STATUS_DEVICE_BUSY; } else { if (Ext->DeviceIsOpen) status = STATUS_DEVICE_BUSY; } if (status == STATUS_DEVICE_BUSY) { MyKdPrint(D_Pnp,("Can't Remove, Busy\n")) Irp->IoStatus.Status = STATUS_DEVICE_BUSY; pass_down = 0; // we are failing it out, no need to pass down } else { Ext->PNPState = SERIAL_PNP_QSTOP; // this is hosing up things(kpb) //Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_STOPPING; Irp->IoStatus.Status = STATUS_SUCCESS; status = STATUS_SUCCESS; } break; case IRP_MN_CANCEL_STOP_DEVICE: // 0x06 MyKdPrint(D_Pnp,("CancelStopDevice\n")) if (Ext->PNPState == SERIAL_PNP_QSTOP) { Ext->PNPState = SERIAL_PNP_STARTED; Ext->DevicePNPAccept &= ~SERIAL_PNPACCEPT_STOPPING; } Irp->IoStatus.Status = STATUS_SUCCESS; status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: MyKdPrint(D_Pnp,("CancelRemoveDevice\n")) // Restore the device state Ext->PNPState = SERIAL_PNP_STARTED; Ext->DevicePNPAccept &= ~SERIAL_PNPACCEPT_REMOVING; Irp->IoStatus.Status = STATUS_SUCCESS; status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: // 0x01 // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. MyKdPrint(D_Pnp,("QueryRemoveDevice\n")) status = STATUS_SUCCESS; if (Ext->DeviceType == DEV_BOARD) { if (is_board_in_use(Ext)) status = STATUS_DEVICE_BUSY; } else { if (Ext->DeviceIsOpen) status = STATUS_DEVICE_BUSY; } if (status == STATUS_DEVICE_BUSY) { MyKdPrint(D_Pnp,("Can't Remove, Busy\n")) Irp->IoStatus.Status = STATUS_DEVICE_BUSY; pass_down = 0; // we are failing it out, no need to pass down } else { Ext->PNPState = SERIAL_PNP_QREMOVE; Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_REMOVING; Irp->IoStatus.Status = STATUS_SUCCESS; status = STATUS_SUCCESS; } break; case IRP_MN_REMOVE_DEVICE: // 0x02 // If we get this, we have to remove // Mark as not accepting requests Ext->DevicePNPAccept |= SERIAL_PNPACCEPT_REMOVING; // Complete all pending requests SerialKillPendingIrps(devobj); // Pass the irp down //WaitForLowerPdo(devobj, Irp); Irp->IoStatus.Status = STATUS_SUCCESS; MyKdPrint(D_Pnp,("RemoveDevice\n")) IoSkipCurrentIrpStackLocation (Irp); //IoCopyCurrentIrpStackLocationToNext(Irp); // We do decrement here because we incremented on entry here. //SerialIRPEpilogue(Ext); SerialIoCallDriver(Ext, pdo, Irp); // Wait for any pending requests we raced on. pendingIRPs = InterlockedDecrement(&Ext->PendingIRPCnt); MyKdPrint(D_Pnp,("Remove, C\n")) if (pendingIRPs) { MyKdPrint(D_Pnp,("Irp Wait\n")) KeWaitForSingleObject(&Ext->PendingIRPEvent, Executive, KernelMode, FALSE, NULL); } // Remove us SerialRemoveFdo(devobj); status = STATUS_SUCCESS; // MyKdPrint(D_Pnp,("End PnPDispatch(Remove)\n")) return status; // BAIL case IRP_MN_QUERY_INTERFACE: // 0x8 case IRP_MN_QUERY_RESOURCES : // 0x0A case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 0x0B case IRP_MN_READ_CONFIG: // 0x0f case IRP_MN_WRITE_CONFIG: // 0x10 case IRP_MN_EJECT: // 0x11 case IRP_MN_SET_LOCK: // 0x12 //case IRP_MN_PNP_DEVICE_STATE: // 0x14 case IRP_MN_QUERY_BUS_INFORMATION: // 0x15 //case IRP_MN_PAGING_NOTIFICATION: // 0x16 default: MyKdPrint(D_Pnp,("Unhandled\n")); // all these get passed down, we don't set the status return code break; } // switch (irpStack->MinorFunction) #if DBG if (* ((BYTE *)(Irp)) != 6) // in signiture of irp { MyKdPrint(D_Pnp,("bad irp b!!!\n")) } #endif if (pass_down) { MyKdPrint(D_Pnp,(" Send irp down\n")) // Pass to driver beneath us IoSkipCurrentIrpStackLocation(Irp); status = SerialIoCallDriver(Ext, pdo, Irp); } else { Irp->IoStatus.Status = status; //MyKdPrint(D_Pnp,(" Complete irp\n")) SerialCompleteRequest(Ext, Irp, IO_NO_INCREMENT); } // MyKdPrint(D_Pnp,(" End PnPDispatch\n")) return status; } #ifdef DO_BUS_EXTENDER /*---------------------------------------------------------------------- PnpPortPDO - |----------------------------------------------------------------------*/ NTSTATUS PnpPortPDO(IN PDEVICE_OBJECT devobj, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = Irp->IoStatus.Status; switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: // 0x00 status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: MyKdPrint(D_Pnp,("Remove PDO\n")) // shut down everything, call iodelete device status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_QUERY_CAPABILITIES: { // x09 PDEVICE_CAPABILITIES deviceCapabilities; deviceCapabilities=irpStack->Parameters.DeviceCapabilities.Capabilities; MyKdPrint(D_Pnp,("Report Caps.\n")) // Set the capabilities. deviceCapabilities->Version = 1; deviceCapabilities->Size = sizeof (DEVICE_CAPABILITIES); // We cannot wake the system. deviceCapabilities->SystemWake = PowerSystemUnspecified; deviceCapabilities->DeviceWake = PowerDeviceUnspecified; // We have no latencies deviceCapabilities->D1Latency = 0; deviceCapabilities->D2Latency = 0; deviceCapabilities->D3Latency = 0; // No locking or ejection deviceCapabilities->LockSupported = FALSE; deviceCapabilities->EjectSupported = FALSE; // Device can be physically removed. // Technically there is no physical device to remove, but this bus // driver can yank the PDO from the PlugPlay system, when ever it // receives an IOCTL_GAMEENUM_REMOVE_PORT device control command. //deviceCapabilities->Removable = TRUE; // we switch this to FALSE to emulate the stock com port behavior, kpb deviceCapabilities->Removable = FALSE; // not Docking device deviceCapabilities->DockDevice = FALSE; // BUGBUG: should we do uniqueID??? deviceCapabilities->UniqueID = FALSE; status = STATUS_SUCCESS; } break; case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7 if (irpStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) break; // { PDEVICE_RELATIONS pDevRel; // No one else should respond to this since we are the PDO ASSERT(Irp->IoStatus.Information == 0); if (Irp->IoStatus.Information != 0) { break; } pDevRel = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); if (pDevRel == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } pDevRel->Count = 1; pDevRel->Objects[0] = devobj; ObReferenceObject(devobj); status = STATUS_SUCCESS; Irp->IoStatus.Information = (ULONG_PTR)pDevRel; } break; case IRP_MN_QUERY_ID: // 0x13 { switch (irpStack->Parameters.QueryId.IdType) { case BusQueryInstanceID: { WCHAR *wstr; CHAR our_id[40]; // Build an instance ID. This is what PnP uses to tell if it has // seen this thing before or not. // its used to form the ENUM\ key name along with the DeviceID. //Sprintf(our_id, "Ctm_%s", Ext->NtNameForPort); Sprintf(our_id, "Port%04d", PortExtToIndex(Ext,0)); MyKdPrint(D_Pnp,("InstanceId:%s\n", our_id)) wstr = str_to_wstr_dup(our_id, PagedPool); if ( wstr ) { // as per serenum bus enumerator: status = STATUS_SUCCESS; } else { status = STATUS_INSUFFICIENT_RESOURCES; } Irp->IoStatus.Information = (ULONG)wstr; } break; case BusQueryDeviceID: { // This is the name used under ENUM to form the device instance // name under which any new PDO nodes will be created. // after find new hardware install we find this as an example // new port node under ENUM: // Enum\CtmPort\RDevice\6&Port0000 // Enum\CtmPort\RDevice\6&Port0000\Control // Enum\CtmPort\RDevice\6&Port0000\Device Parameters // Enum\CtmPort\RDevice\6&Port0000\LogConf WCHAR *wstr; CHAR our_id[40]; #ifdef S_VS strcpy(our_id, "CtmPort\\VSPORT"); #else strcpy(our_id, "CtmPort\\RKPORT"); #endif wstr = str_to_wstr_dup(our_id, PagedPool); MyKdPrint(D_Pnp,("DevID:%s\n", our_id)) Irp->IoStatus.Information = (ULONG)wstr; if ( wstr ) { status = STATUS_SUCCESS; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } break; case BusQueryHardwareIDs: { // return a multi WCHAR (null terminated) string (null terminated) // array for use in matching hardare ids in inf files; WCHAR *wstr; CHAR our_id[40]; #ifdef S_VS Sprintf(our_id, "CtmvPort%04d", PortExtToIndex(Ext, 0 /* driver_flag */) ); #else Sprintf(our_id, "CtmPort%04d", PortExtToIndex(Ext, 0 /* driver_flag */) ); #endif MyKdPrint(D_Pnp,("HrdwrID:%s\n", our_id)) wstr = str_to_wstr_dup(our_id, PagedPool); Irp->IoStatus.Information = (ULONG)wstr; if ( wstr ) { status = STATUS_SUCCESS; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } //BusQueryHardwareIDs break; case BusQueryCompatibleIDs: { #if 0 WCHAR *wstr; CHAR our_id[40]; // The generic ids for installation of this pdo. Sprintf(our_id, "Cpt_CtmPort0001"); MyKdPrint(D_Pnp,("CompID:%s\n", our_id)) wstr = str_to_wstr_dup(our_id, PagedPool); Irp->IoStatus.Information = (ULONG)wstr; status = STATUS_SUCCESS; #endif // no compatible id's Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; } break; default: MyKdPrint(D_Pnp,(" UnHandled\n")) // Irp->IoStatus.Information = 0; // status = STATUS_SUCCESS; break; } // switch IdType } // IRP_MN_QUERY_ID break; case IRP_MN_QUERY_DEVICE_TEXT: // 0x0C MyKdPrint(D_Pnp,("QueryDevText\n")) if (irpStack->Parameters.QueryDeviceText.DeviceTextType != DeviceTextDescription) { MyKdPrint(D_Pnp,(" Unhandled Text Type\n")) break; } { // this is put in the Found New Hardware dialog box message. WCHAR *wstr; #if DBG if (Irp->IoStatus.Information != 0) { MyKdPrint(D_Error,("StrExists!\n")) } #endif #ifdef S_VS wstr = str_to_wstr_dup("Comtrol VS Port", PagedPool); #else wstr = str_to_wstr_dup("Comtrol Port", PagedPool); #endif Irp->IoStatus.Information = (ULONG)wstr; if ( wstr ) { status = STATUS_SUCCESS; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } break; // IRP_MN_QUERY_DEVICE_TEXT default: //MyKdPrint(D_Pnp,(" PDO Unhandled\n")) break; } Irp->IoStatus.Status = status; InterlockedDecrement(&Ext->PendingIRPCnt); IoCompleteRequest (Irp, IO_NO_INCREMENT); MyKdPrint(D_Pnp,(" PDO Dispatch End\n")) return status; } /*---------------------------------------------------------------------- BoardBusRelations - handle IRP_MN_QUERY_DEVICE_RELATIONS: // 0x7 for our board FDO entity. |----------------------------------------------------------------------*/ NTSTATUS BoardBusRelations(IN PDEVICE_OBJECT devobj, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = devobj->DeviceExtension; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG i, length, NumPDOs; PDEVICE_RELATIONS relations; PSERIAL_DEVICE_EXTENSION ext; ASSERT( devobj ); switch (irpStack->Parameters.QueryDeviceRelations.Type) { case BusRelations: MyKdPrint(D_Pnp,("BusRelations\n")) // Tell the plug and play system about all the PDOs. // // There might also be device relations below and above this FDO, // so, be sure to propagate the relations from the upper drivers. // // No Completion routine is needed so long as the status is preset // to success. (PDOs complete plug and play irps with the current // IoStatus.Status and IoStatus.Information as the default.) // NumPDOs = 0; // count the number of pdo's // count up pdo's for device ext = Ext->port_pdo_ext; while (ext != NULL) { ++NumPDOs; ext = ext->port_ext; } // The current number of PDOs i = 0; if (Irp->IoStatus.Information != 0) i = ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count; MyKdPrint(D_Pnp, ("Num PDOs:%d + %d\n", i, NumPDOs)) length = sizeof(DEVICE_RELATIONS) + ((NumPDOs + i) * sizeof (PDEVICE_OBJECT)); relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, length); if (NULL == relations) { return STATUS_INSUFFICIENT_RESOURCES; } // Copy in the device objects so far if (i) { RtlCopyMemory ( relations->Objects, ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Objects, i * sizeof (PDEVICE_OBJECT)); } relations->Count = NumPDOs + i; // // For each PDO on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The PlugPlay system will dereference the object when it is done with // it and free the device relations buffer. // ext = Ext->port_pdo_ext; while (ext != NULL) { relations->Objects[i++] = ext->DeviceObject; ObReferenceObject (ext->DeviceObject); // add 1 to lock on this object ext = ext->port_ext; } // Set up and pass the IRP further down the stack Irp->IoStatus.Status = STATUS_SUCCESS; if (0 != Irp->IoStatus.Information) { ExFreePool ((PVOID) Irp->IoStatus.Information); } Irp->IoStatus.Information = (ULONG) relations; break; case EjectionRelations: MyKdPrint(D_Pnp, ("EjectRelations\n")) break; case PowerRelations: MyKdPrint(D_Pnp,("PowerRelations\n")) break; case RemovalRelations: MyKdPrint(D_Pnp,("RemovalRelations\n")) break; case TargetDeviceRelation: MyKdPrint(D_Pnp,("TargetDeviceRelations\n")) break; default: MyKdPrint(D_Pnp,("UnknownRelations\n")) break; } // switch .Type status = STATUS_SUCCESS; return status; } #endif /*---------------------------------------------------------------------- WaitForLowerPdo - |----------------------------------------------------------------------*/ NTSTATUS WaitForLowerPdo(IN PDEVICE_OBJECT fdo, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = fdo->DeviceExtension; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; NTSTATUS status; KEVENT Event; KeInitializeEvent(&Event, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, SerialSyncCompletion, &Event, TRUE, TRUE, TRUE); status = IoCallDriver(pdo, Irp); // Wait for lower drivers to be done with the Irp if (status == STATUS_PENDING) { MyKdPrint(D_Pnp,("WaitPend\n")) KeWaitForSingleObject (&Event, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } if (!NT_SUCCESS(status)) { MyKdPrint(D_Pnp,("WaitErr\n")) return status; } return 0; } /*---------------------------------------------------------------------- SerialPowerDispatch - This is a dispatch routine for the IRPs that come to the driver with the IRP_MJ_POWER major code (power IRPs). Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call |----------------------------------------------------------------------*/ NTSTATUS SerialPowerDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; BOOLEAN hook_it = FALSE; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; BOOLEAN acceptingIRPs = TRUE; int index; // dump out some debug info index = irpStack->MinorFunction; if (index > 0x3) index = 0x4; if (Ext->IsPDO) { #if DBG MyKdPrint(D_PnpPower,("Port PDO PowerIrp:%d,%s\n", irpStack->MinorFunction, power_strs[index])) #endif return Serial_PDO_Power (DeviceObject, Irp); } // else it's a FDO #if DBG if (Ext->DeviceType == DEV_BOARD) { MyKdPrint(D_PnpPower,("Board PowerIrp:%d,%s\n", irpStack->MinorFunction, power_strs[index])) } else { MyKdPrint(D_PnpPower,("Port PowerIrp:%d,%s\n", irpStack->MinorFunction, power_strs[index])) } #endif return Serial_FDO_Power (DeviceObject, Irp); } /*---------------------------------------------------------------------- Serial_FDO_Power - Handle board and port FDO power handling. |----------------------------------------------------------------------*/ NTSTATUS Serial_FDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; BOOLEAN hook_it = FALSE; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; PDEVICE_OBJECT pPdo = Ext->Pdo; BOOLEAN acceptingIRPs = TRUE; POWER_STATE powerState; POWER_STATE_TYPE powerType; int ChangePower = 0; int fail_it = 0; powerType = irpStack->Parameters.Power.Type; powerState = irpStack->Parameters.Power.State; status = STATUS_SUCCESS; acceptingIRPs = SerialIRPPrologue(Ext); if (acceptingIRPs == FALSE) { MyKdPrint(D_PnpPower,("Removed!\n")) status = STATUS_NO_SUCH_DEVICE; // ????????????? fail_it = 1; } else { switch (irpStack->MinorFunction) { case IRP_MN_SET_POWER: MyKdPrint(D_PnpPower,("SET_POWER Type %d, SysState %d, DevStat %d\n",powerType,powerState.SystemState,powerState.DeviceState)); // Perform different ops if it was system or device switch (irpStack->Parameters.Power.Type) { case DevicePowerState: // do power up & down work on device ChangePower = 1; break; case SystemPowerState: //if (pDevExt->OwnsPowerPolicy != TRUE) { // status = STATUS_SUCCESS; // goto PowerExit; // } ChangePower = 1; switch (irpStack->Parameters.Power.State.SystemState) { case PowerSystemUnspecified: powerState.DeviceState = PowerDeviceUnspecified; break; case PowerSystemWorking: powerState.DeviceState = PowerDeviceD0; break; case PowerSystemSleeping1: case PowerSystemSleeping2: case PowerSystemSleeping3: case PowerSystemHibernate: case PowerSystemShutdown: case PowerSystemMaximum: default: powerState.DeviceState = PowerDeviceD3; break; } break; // end case SystemPowerState } // end switch if (ChangePower) { // If we are already in the requested state, just pass the IRP down if (Ext->PowerState == powerState.DeviceState) { MyKdPrint(D_PnpPower,(" Same\n")) status = STATUS_SUCCESS; Irp->IoStatus.Status = status; ChangePower = 0; } } if (ChangePower) { MyKdPrint(D_PnpPower,("ExtPowerState %d, DeviceState %d\n",Ext->PowerState,powerState.DeviceState)); switch (powerState.DeviceState) { case PowerDeviceD0: if (Ext->DeviceType == DEV_BOARD) { // powering up board. MyKdPrint(D_PnpPower,(" Hook\n")) ASSERT(Ext->LowerDeviceObject); hook_it = TRUE; } break; case PowerDeviceD1: case PowerDeviceD2: case PowerDeviceD3: default: // we should be doing this on the way up in the hook routine. MyKdPrint(D_PnpPower,(" PwDown\n")) // Before we power down, call PoSetPowerState PoSetPowerState(DeviceObject, powerType, powerState); // Shut it down //..... // Ext->PowerState = powerState.DeviceState; // PowerDeviceD0; if (Ext->DeviceType == DEV_BOARD) { MyKdPrint(D_PnpPower,(" PwDown Board\n")) // shut some things down, so it comes back up ok #if S_RK Ext->config->RocketPortFound = 0; // this tells if its started #endif Ext->config->HardwareStarted = FALSE; } Irp->IoStatus.Status = STATUS_SUCCESS; status = STATUS_SUCCESS; break; } // switch (IrpSp->Parameters.Power.State.DeviceState) } // ChangePower break; // SET_POWER case IRP_MN_QUERY_POWER: MyKdPrint(D_PnpPower,(" QueryPower SystemState 0x%x\n",irpStack->Parameters.Power.State.SystemState)) // if they want to go to a power-off state(sleep, hibernate, etc) if (irpStack->Parameters.Power.State.SystemState != PowerSystemWorking) { MyKdPrint(D_PnpPower,(" QueryPower turn off\n")) // only handle power logic for the board as a whole if (Ext->DeviceType == DEV_BOARD) { MyKdPrint(D_PnpPower,(" PwDown Board\n")) // if a port is open and being used, then fail the request #if 0 // try to get the wake up restore of hardware working... // kpb, 2-7-99 if (is_board_in_use(Ext)) { MyKdPrint(D_PnpPower,(" PwDown Board In Use!\n")) // if wants to powerdown // BUGBUG:, refuse hibernation status = STATUS_NO_SUCH_DEVICE; // ? fail_it = 1; } else #endif { MyKdPrint(D_PnpPower,(" PwDown Board, allow it!\n")) #ifdef MTM_CLOSE_NIC_ATTEMPT if ( Driver.nics ) { for( i=0; iIoStatus.Status = status; } break; //case IRP_MN_WAIT_WAKE: // Here is where support for a // serial device (like a modem) waking the system when the // phone rings. //case IRP_MN_POWER_SEQUENCE: default: break; } // switch (irpStack->MinorFunction) } // else, handle irp if (fail_it) { // status assumed set above PoStartNextPowerIrp (Irp); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; InterlockedDecrement(&Ext->PendingIRPCnt); IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // Pass to the lower driver if (hook_it) { IoCopyCurrentIrpStackLocationToNext (Irp); MyKdPrint(D_PnpPower,(" Hooked\n")) IoSetCompletionRoutine(Irp, OurPowerCompletion, NULL, TRUE, TRUE, TRUE); MyKdPrint(D_PnpPower,(" Ready to send Irp 0x%x to PDO 0x%x\n", Irp, pdo)) status = PoCallDriver(pdo, Irp); // hooking proc is responsible for decrementing reference count in ext // and calling PoStartNextPowerIrp(). } else { IoCopyCurrentIrpStackLocationToNext (Irp); /// try this ^ instead ---- IoSkipCurrentIrpStackLocation (Irp); MyKdPrint(D_PnpPower,(" Passed\n")) PoStartNextPowerIrp(Irp); status = PoCallDriver(pdo, Irp); SerialIRPEpilogue(Ext); } MyKdPrint(D_PnpPower,("End PowerDisp\n")) return status; } /*---------------------------------------------------------------------- Serial_PDO_Power - Handle port PDO power handling. |----------------------------------------------------------------------*/ NTSTATUS Serial_PDO_Power (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; BOOLEAN hook_it = FALSE; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; BOOLEAN acceptingIRPs = TRUE; POWER_STATE powerState; POWER_STATE_TYPE powerType; powerType = irpStack->Parameters.Power.Type; powerState = irpStack->Parameters.Power.State; status = STATUS_SUCCESS; switch (irpStack->MinorFunction) { case IRP_MN_SET_POWER: if (powerType == SystemPowerState) { MyKdPrint(D_PnpPower,(" SysPower\n")) status = STATUS_SUCCESS; Irp->IoStatus.Status = status; break; } if (powerType != DevicePowerState) { MyKdPrint(D_PnpPower,(" OtherType\n")) // They asked for a system power state change which we can't do. // Pass it down to the lower driver. status = STATUS_SUCCESS; Irp->IoStatus.Status = status; break; } // If we are already in the requested state, just pass the IRP down if (Ext->PowerState == powerState.DeviceState) { MyKdPrint(D_PnpPower,(" Same\n")) status = STATUS_SUCCESS; Irp->IoStatus.Status = status; break; } MyKdPrint(D_PnpPower,(" Set\n")) Ext->PowerState = powerState.DeviceState; // PowerDeviceD0; PoSetPowerState(DeviceObject, powerType, powerState); break; case IRP_MN_QUERY_POWER: status = STATUS_SUCCESS; break; case IRP_MN_WAIT_WAKE: case IRP_MN_POWER_SEQUENCE: default: MyKdPrint(D_PnpPower,("Not Imp!\n")) status = STATUS_NOT_IMPLEMENTED; break; } Irp->IoStatus.Status = status; PoStartNextPowerIrp (Irp); IoCompleteRequest (Irp, IO_NO_INCREMENT); MyKdPrint(D_PnpPower,("End PDO PowerDisp\n")) return status; } /*---------------------------------------------------------------------- SerialStartDevice - This routine first passes the start device Irp down the stack then it picks up the resources for the device, ititializes, puts it on any appropriate lists (i.e shared interrupt or interrupt status) and connects the interrupt. Arguments: Fdo - Pointer to the functional device object for this device Irp - Pointer to the IRP for the current request Return Value: Return status |----------------------------------------------------------------------*/ NTSTATUS SerialStartDevice( IN PDEVICE_OBJECT Fdo, IN PIRP Irp) { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_NOT_IMPLEMENTED; PSERIAL_DEVICE_EXTENSION Ext = Fdo->DeviceExtension; PDEVICE_OBJECT pdo = Ext->LowerDeviceObject; MyKdPrint(D_Pnp,("SerialStartDevice\n")) // Set up the external naming and create the symbolic link // Pass this down to the Pdo status = WaitForLowerPdo(Fdo, Irp); status = STATUS_SUCCESS; // Do the serial specific items to start the device status = SerialFinishStartDevice(Fdo, irpStack->Parameters.StartDevice.AllocatedResources, irpStack->Parameters.StartDevice.AllocatedResourcesTranslated); Irp->IoStatus.Status = status; MyKdPrint(D_Pnp,("End Start Dev\n")) return status; } /*---------------------------------------------------------------------- SerialSyncCompletion - |----------------------------------------------------------------------*/ NTSTATUS SerialSyncCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT SerialSyncEvent ) { KeSetEvent(SerialSyncEvent, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } /*---------------------------------------------------------------------- SerialFinishStartDevice - This routine starts driver hardware. On the RocketPort, this is a board, or a port. On the VS, this would be the whole VS driver (all boxes) or a individual port. A Pnp ADDDEVICE call(in pnpadd.c) should have been seen before this to setup the driver. After this, we may see Starts or Stops on the hardware, which the OS may start and stop to change resource assignments, etc. Arguments: Fdo - Pointer to the Functional Device Object that is starting resourceList - Pointer to the untranslated resources needed by this device trResourceList - Pointer to the translated resources needed by this device PUserData - Pointer to the user-specified resources/attributes Return Value: STATUS_SUCCESS on success, something else appropriate on failure |----------------------------------------------------------------------*/ NTSTATUS SerialFinishStartDevice(IN PDEVICE_OBJECT Fdo, IN PCM_RESOURCE_LIST resourceList, IN PCM_RESOURCE_LIST trResourceList) { PSERIAL_DEVICE_EXTENSION Ext = Fdo->DeviceExtension; NTSTATUS status; DEVICE_CONFIG *pConfig; PSERIAL_DEVICE_EXTENSION newExtension = NULL; PDEVICE_OBJECT NewDevObj; int ch; int is_fdo = 1; #ifdef NT50 PWSTR iBuffer; #endif MyKdPrint(D_Pnp,("SerialFinishStartDevice\n")) pConfig = Ext->config; MyKdPrint(D_Pnp,("ChkPt A\n")) if (Ext->DeviceType != DEV_BOARD) { MyKdPrint(D_Pnp,("Start PnpPort\n")) Ext->FdoStarted = TRUE; // i don't thinks this is used on ports #ifdef NT50 // Create a symbolic link with IoRegisterDeviceInterface() // status = IoRegisterDeviceInterface( Ext->Pdo, (LPGUID)&GUID_CLASS_COMPORT, NULL, &Ext->DeviceClassSymbolicName ); if (!NT_SUCCESS(status)) { MyKdPrint(D_Error,("Couldn't register class association\n")) Ext->DeviceClassSymbolicName.Buffer = NULL; } else { MyKdPrint(D_Init, ("Registering class association for:\n PDO:0x%8x\nSymLink %s\n", Ext->Pdo, UToC1(&Ext->DeviceClassSymbolicName))) } // Now set the symbolic link for the interface association // status = IoSetDeviceInterfaceState( &Ext->DeviceClassSymbolicName, TRUE); if (!NT_SUCCESS(status)) { MyKdPrint(D_Error,("Couldn't set class association for %s\n", UToC1(&Ext->DeviceClassSymbolicName))) } else { MyKdPrint(D_PnpAdd, ("Enable class association for device: %s\n", UToC1(&Ext->DeviceClassSymbolicName))) } #if 0 // Strictly for verification - get the entire list of COM class interfaces // for up to 6 COM ports status = IoGetDeviceInterfaces( (LPGUID)&GUID_CLASS_COMPORT, NULL, // No PDO - get 'em all 0, &iBuffer ); if (!NT_SUCCESS(status)) { MyKdPrint(D_Error,("Couldn't get interface list for GUID_CLASS_COMPORT\n")) } else { PWCHAR pwbuf = iBuffer; char cbuf[128]; int j = 0; int ofs = 0; while ( (pwbuf != 0) && (j < 8) ){ WStrToCStr( cbuf, pwbuf, sizeof(cbuf) ); MyKdPrint(D_Pnp, ("COM port interface %d: %s\n", j, cbuf)) ofs += strlen(cbuf) + 1; pwbuf = &iBuffer[ofs]; j++; } ExFreePool(iBuffer); } #endif #endif status = STATUS_SUCCESS; return status; } if (Ext->FdoStarted == TRUE) { MyKdPrint(D_Error,("ReStart PnpBrd\n")) status = STATUS_SUCCESS; return status; } if (!Driver.NoPnpPorts) is_fdo = 0; // eject PDOs representing port hardware. // Get the configuration info for the device. #ifdef S_RK status = RkGetPnpResourceToConfig(Fdo, resourceList, trResourceList, pConfig); if (!NT_SUCCESS (status)) { Eprintf("StartErr 1N"); return status; } #ifdef DO_ISA_BUS_ALIAS_IO status = Report_Alias_IO(Ext); if (status != 0) { Eprintf("StartErr Alias-IO"); MyKdPrint(D_Pnp,("Error 1P\n")) status = STATUS_INSUFFICIENT_RESOURCES; return status; } MyKdPrint(D_Pnp,("ChkPt B\n")) #endif //DELF MyKdPrint(D_Pnp,("INIT RCK\n")) //END DELF status = RocketPortSpecialStartup(Ext); if (status != STATUS_SUCCESS) { Eprintf("StartErr 1J"); return status; } #endif MyKdPrint(D_Pnp,("ChkPt C\n")) #ifdef S_VS status = VSSpecialStartup(Ext); if (status != STATUS_SUCCESS) { Eprintf("StartErr 1J"); return status; } #endif //----- Create our port devices, if we are doing pnp ports, then // create PDO's, if not, then create normal com-port device objects // (same as FDO's.) for (ch=0; chconfig->NumPorts; ch++) { //MyKdPrint(D_Pnp,("FS,ChanInit:%d\n", ch)) status = CreatePortDevice( Driver.GlobalDriverObject, Ext, // parent ext. &newExtension, ch, is_fdo); if (status != STATUS_SUCCESS) { Eprintf("StartErr 1Q"); return status; } NewDevObj = newExtension->DeviceObject; //return the new device object NewDevObj->Flags |= DO_POWER_PAGABLE; if (!is_fdo) // eject PDOs representing port hardware. newExtension->IsPDO = 1; // we are a pdo #if S_RK if (Ext->config->RocketPortFound) // if started(not delayed isa) #endif { status = StartPortHardware(newExtension, ch); // channel num, port index if (status != STATUS_SUCCESS) { Eprintf("StartErr 1O"); return status; } } } // for ports #ifdef S_RK if (Ext->config->RocketPortFound) // if started(not delayed isa) #endif { Ext->config->HardwareStarted = TRUE; // send ROW configuration to SocketModems InitSocketModems(Ext); #ifdef S_RK InitRocketModemII (Ext); #endif } MyKdPrint(D_Pnp,("ChkPt D\n")) //---- start up the timer if (!Driver.TimerCreated) { #ifdef S_RK Driver.SetupIrq = 0; #endif //MyKdPrint(D_Pnp,("before rcktinitpolltimer\n")) RcktInitPollTimer(); //MyKdPrint(D_Pnp,("after rcktinitpolltimer\n")) KeSetTimer(&Driver.PollTimer, Driver.PollIntervalTime, &Driver.TimerDpc); } MyKdPrint(D_Pnp,("ChkPt F, after\n")) Ext->FdoStarted = TRUE; //if (Drier.VerboseLog) // Eprintf("Success start dev"); status = STATUS_SUCCESS; return status; } #ifdef S_RK /*----------------------------------------------------------------------- RocketPortSpecialStartup - |-----------------------------------------------------------------------*/ static NTSTATUS RocketPortSpecialStartup(PSERIAL_DEVICE_EXTENSION Ext) { int ch; int start_isa_flag; NTSTATUS status = STATUS_SUCCESS; PSERIAL_DEVICE_EXTENSION tmpExt; PSERIAL_DEVICE_EXTENSION newExt; if (Ext->config->BusType == Isa) { MyKdPrint(D_PnpPower,("pnp- ISA brd Index:%d\n", Ext->config->ISABrdIndex)) if (Ext->config->ISABrdIndex == 0) start_isa_flag = 1; else if (is_first_isa_card_started()) start_isa_flag = 1; else { MyKdPrint(D_PnpPower,("Delay 2ndary ISA card start\n")) start_isa_flag = 0; } } //----- Init the RocketPort hardware if ((Ext->config->BusType == Isa) && (!start_isa_flag)) status = 0; // skip, can't start until we get the first board else { status = InitController(Ext); // this sets RocketPortFound = TRUE if ok if (status != 0) { status = STATUS_INSUFFICIENT_RESOURCES; MyKdPrint(D_Error,("Brd failed startup\n")) //if (Driver.VerboseLog) // Eprintf("Error InitCtrl"); return status; } MyKdPrint(D_PnpPower,("Brd started\n")) } if ((Ext->config->BusType == Isa) && (is_first_isa_card_started()) && (is_isa_cards_pending_start()) ) { MyKdPrint(D_Pnp,("Do Pending\n")) tmpExt = Driver.board_ext; while (tmpExt) { if ((tmpExt->config->BusType == Isa) && (!tmpExt->config->RocketPortFound)) // this tells if its started { MyKdPrint(D_Pnp,("Pending 1A\n")) status = InitController(tmpExt); // this sets RocketPortFound = TRUE if ok if (status != 0) { status = STATUS_INSUFFICIENT_RESOURCES; if (Driver.VerboseLog) Eprintf("Error 5C"); return status; } MyKdPrint(D_Pnp,("Pend 2A\n")) //----- Find and initialize the controller ports newExt = tmpExt->port_ext; ch=0; while (newExt) { status = StartPortHardware(newExt, ch); // channel num, port index if (status != STATUS_SUCCESS) { Eprintf("StartErr 1N"); return status; } newExt = newExt->port_ext; ++ch; } tmpExt->config->HardwareStarted = TRUE; // send ROW configuration to SocketModems InitSocketModems(tmpExt); MyKdPrint(D_Pnp,("Pending OK\n")) } tmpExt = tmpExt->board_ext; } } // if isa boards to startup return status; } #endif /*----------------------------------------------------------------------- This routine kills any irps pending for the passed device object. Arguments: DeviceObject - Pointer to the device object whose irps must die. Return Value: VOID |-----------------------------------------------------------------------*/ VOID SerialKillPendingIrps(PDEVICE_OBJECT DeviceObject) { PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; KIRQL oldIrql; //PAGED_CODE(); //SerialDump (SERTRACECALLS,("SERIAL: Enter SerialKillPendingIrps\n")); // this is for the FDO, which currently is the BOARD, so we have to // do all ports for this board.(THIS IS NOT A PORT EXTENSION!!!!!) // First kill all the reads and writes. SerialKillAllReadsOrWrites( DeviceObject, &extension->WriteQueue, &extension->CurrentWriteIrp ); SerialKillAllReadsOrWrites( DeviceObject, &extension->ReadQueue, &extension->CurrentReadIrp ); // Next get rid of purges. SerialKillAllReadsOrWrites( DeviceObject, &extension->PurgeQueue, &extension->CurrentPurgeIrp ); // Now get rid a pending wait mask irp. IoAcquireCancelSpinLock(&oldIrql); if (extension->CurrentWaitIrp) { PDRIVER_CANCEL cancelRoutine; cancelRoutine = extension->CurrentWaitIrp->CancelRoutine; extension->CurrentWaitIrp->Cancel = TRUE; if (cancelRoutine) { extension->CurrentWaitIrp->CancelIrql = oldIrql; extension->CurrentWaitIrp->CancelRoutine = NULL; cancelRoutine( DeviceObject, extension->CurrentWaitIrp ); } } else { IoReleaseCancelSpinLock(oldIrql); } //SerialDump (SERTRACECALLS,("SERIAL: Leave SerialKillPendingIrps\n")); } /*----------------------------------------------------------------------- This function must be called at any IRP dispatch entry point. It, with SerialIRPPrologue(), keeps track of all pending IRP's for the given PDevObj. Arguments: PDevObj - Pointer to the device object we are tracking pending IRP's for. Return Value: None. |-----------------------------------------------------------------------*/ VOID SerialIRPEpilogue(IN PSERIAL_DEVICE_EXTENSION PDevExt) { ULONG pendingCnt; pendingCnt = InterlockedDecrement(&PDevExt->PendingIRPCnt); #if DBG //MyKdPrint(D_Pnp,("Exit PendingIrpCnt:%d\n", PDevExt->PendingIRPCnt)) #endif if (pendingCnt == 0) { MyKdPrint(D_Pnp,("Set PendingIRPEvent\n")) KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE); } } /*----------------------------------------------------------------------- SerialIoCallDriver - |-----------------------------------------------------------------------*/ NTSTATUS SerialIoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj, PIRP PIrp) { NTSTATUS status; ASSERT( PDevObj ); status = IoCallDriver(PDevObj, PIrp); SerialIRPEpilogue(PDevExt); return status; } /*----------------------------------------------------------------------- SerialPoCallDriver - |-----------------------------------------------------------------------*/ NTSTATUS SerialPoCallDriver(PSERIAL_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj, PIRP PIrp) { NTSTATUS status; status = PoCallDriver(PDevObj, PIrp); SerialIRPEpilogue(PDevExt); return status; } /*----------------------------------------------------------------------- This routine is a completion handler that is called after the COM port has been powered up. It sets the COM port in a known state by calling SerialReset, SerialMarkClose, SerialClrRTS, and SerialClrDTR. The it does a PoCompleteRequest to finish off the power Irp. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Context - None Return Value: Return status in IRP when being called (if not STATUS_SUCCESS) or STATUS_SUCCESS. |-----------------------------------------------------------------------*/ NTSTATUS OurPowerCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { NTSTATUS status = Irp->IoStatus.Status; PSERIAL_DEVICE_EXTENSION Ext = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); POWER_STATE powerState; POWER_STATE_TYPE powerType; powerType = irpStack->Parameters.Power.Type; powerState = irpStack->Parameters.Power.State; MyKdPrint(D_PnpPower,("In OurPowerCompletion\n")) if (irpStack->MinorFunction == IRP_MN_SET_POWER) { if (powerState.DeviceState == PowerDeviceD0) { MyKdPrint(D_PnpPower,("Restoring to Power On State D0\n")) status = STATUS_SUCCESS; // set hardware to known power up state Ext->PowerState = powerState.DeviceState; // PowerDeviceD0; if (Ext->DeviceType == DEV_BOARD) { status = PowerUpDevice(Ext); } // board device else if (Ext->DeviceType == DEV_PORT) { Ext->config->HardwareStarted = TRUE; } PoSetPowerState(DeviceObject, powerType, powerState); } else // if (powerState.DeviceState == PowerDeviceD3) { status = STATUS_SUCCESS; // Clear the flag saying we are waiting for a power down Ext->ReceivedQueryD3 = FALSE; Ext->PowerState = PowerDeviceD3; } } InterlockedDecrement(&Ext->PendingIRPCnt); PoStartNextPowerIrp(Irp); return status; } /*----------------------------------------------------------------------- RestorePortSettings - Try to restore port hardware settings. Called after power-off sleep mode. |-----------------------------------------------------------------------*/ void RestorePortSettings(PSERIAL_DEVICE_EXTENSION Ext) { SERIAL_HANDFLOW TempHandFlow; DWORD TempDTRRTSStatus; DWORD xorDTRRTSStatus; #ifdef S_RK // remember what the status of pins are coming into this // so we can try to put them back to what they were prior to // hardware re-initialization. TempDTRRTSStatus = Ext->DTRRTSStatus; // SERIAL_DTR_STATE; if(sGetChanStatus(Ext->ChP) & STATMODE) { // Take channel out of statmode if necessary sDisRxStatusMode(Ext->ChP); } // pDisLocalLoopback(Ext->Port); // Clear any pending modem changes sGetChanIntID(Ext->ChP); sEnRxFIFO(Ext->ChP); // Enable Rx sEnTransmit(Ext->ChP); // Enable Tx sSetRxTrigger(Ext->ChP,TRIG_1); // always trigger sEnInterrupts(Ext->ChP, Ext->IntEnables);// allow interrupts ForceExtensionSettings(Ext); // make a temp. copy of handflow struct memcpy(&TempHandFlow, &Ext->HandFlow, sizeof(TempHandFlow)); // force updates in SerialSetHandFlow, which looks for delta change. Ext->HandFlow.ControlHandShake = ~TempHandFlow.ControlHandShake; Ext->HandFlow.FlowReplace = ~TempHandFlow.FlowReplace; SerialSetHandFlow(Ext, &TempHandFlow); // in ioctl.c // program hardware baudrate ProgramBaudRate(Ext, Ext->BaudRate); xorDTRRTSStatus = Ext->DTRRTSStatus ^ TempDTRRTSStatus; // try to restore the actual dtr & rts outputs if (xorDTRRTSStatus & SERIAL_DTR_STATE) // changed { // if not auto-handshake dtr mode if (!((Ext->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE )) { if (TempDTRRTSStatus & SERIAL_DTR_STATE) // was on { sSetDTR(Ext->ChP); } else { sClrDTR(Ext->ChP); } } // not auto-dtr flow } // chg in dtr if (xorDTRRTSStatus & SERIAL_RTS_STATE) // changed { // if not auto-flow control rts if (!((Ext->HandFlow.ControlHandShake & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE)) { if (TempDTRRTSStatus & SERIAL_RTS_STATE) // was on { sSetRTS(Ext->ChP); } else { sClrRTS(Ext->ChP); } } // chg in rts Ext->DTRRTSStatus = TempDTRRTSStatus; } #endif // the VS boxes will not be powered off, and will hold their state // so no hardware re-initialization is needed. The box will have // probably timed out the connection, and force a re-sync operation, // we might want to pro-actively start this so there is a smaller // delay... } /*----------------------------------------------------------------------- PowerUpDevice - Used to bring power back on after turning it off. |-----------------------------------------------------------------------*/ NTSTATUS PowerUpDevice(PSERIAL_DEVICE_EXTENSION Ext) { PSERIAL_DEVICE_EXTENSION port_ext; int ch; NTSTATUS status = STATUS_SUCCESS; #ifdef S_RK MyKdPrint(D_PnpPower,("RocketPort Init %d\n",Ext->config->HardwareStarted)) status = RocketPortSpecialStartup(Ext); if (status != STATUS_SUCCESS) { MyKdPrint(D_Error,("RocketPort Init Failed\n")) //return status; } if (Ext->config->RocketPortFound) // if started(not delayed isa) Ext->config->HardwareStarted = TRUE; #endif #ifdef S_VS MyKdPrint(D_PnpPower,("VS Init\n")) status = VSSpecialStartup(Ext); if (status != STATUS_SUCCESS) { MyKdPrint(D_Error,("VS Init Failed\n")) //return status; } Ext->config->HardwareStarted = TRUE; #endif if (Ext->config->HardwareStarted == TRUE) { if (Ext->port_ext == NULL) {MyKdPrint(D_Error,("No Ports\n")) } //----- Find and initialize the controller ports port_ext = Ext->port_ext; ch=0; while (port_ext) { MyKdPrint(D_PnpPower,("PowerUp Port %d\n", ch)) status = StartPortHardware(port_ext, ch); // channel num, port index if (status != STATUS_SUCCESS) { MyKdPrint(D_Error,("PortPowerUp Err1\n")) return status; } MyKdPrint(D_PnpPower,("PowerUp Port %d Restore\n", ch)) RestorePortSettings(port_ext); port_ext = port_ext->port_ext; ++ch; } } else { MyKdPrint(D_Error,("Not started\n")) } // send ROW configuration to SocketModems //InitSocketModems(Ext); status = STATUS_SUCCESS; return status; } /*----------------------------------------------------------------------- SerialRemoveFdo - |-----------------------------------------------------------------------*/ NTSTATUS SerialRemoveFdo(IN PDEVICE_OBJECT pFdo) { PSERIAL_DEVICE_EXTENSION extension = pFdo->DeviceExtension; MyKdPrint(D_Pnp,("SerialRemoveFdo\n")) // Only do these things if the device has started //(comment out 8-15-98) if (extension->FdoStarted) { if (extension->DeviceType == DEV_BOARD) { // BUGBUG, shut down this board(are we deallocating resources?)!!! RcktDeleteBoard(extension); if (Driver.board_ext == NULL) // no more boards, so delete driver obj { // Delete Driver obj RcktDeleteDriverObj(Driver.driver_ext); Driver.driver_ext = NULL; // no more boards #ifdef S_VS // to allow the driver to unload from nt50, we need to // stop the nic-binding thread, shut down the nic // cards and the protocol from ndis init_stop(); // unload thread, ndis nic cards, etc #endif { PDEVICE_OBJECT currentDevice = Driver.GlobalDriverObject->DeviceObject; int i; i = 0; while(currentDevice) { currentDevice = currentDevice->NextDevice; if (currentDevice) ++i; } if (i != 0) { MyKdPrint(D_Pnp,("Err, %d Devices still remain\n",i)) } else { MyKdPrint(D_Pnp,("Ok remove\n")) } } } } else { RcktDeletePort(extension); // must be a port fdo, kill it } } MyKdPrint(D_Pnp,("End SerialRemoveFdo\n")) return STATUS_SUCCESS; } #endif // NT50 /*----------------------------------------------------------------------- This function must be called at any IRP dispatch entry point. It, with SerialIRPEpilogue(), keeps track of all pending IRP's for the given PDevObj. Arguments: PDevObj - Pointer to the device object we are tracking pending IRP's for. Return Value: TRUE if the device can accept IRP's. |-----------------------------------------------------------------------*/ BOOLEAN SerialIRPPrologue(IN PSERIAL_DEVICE_EXTENSION PDevExt) { InterlockedIncrement(&PDevExt->PendingIRPCnt); #ifdef NT50 return PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK ? TRUE : FALSE; #else return TRUE; #endif }