Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpnp.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: Serial port driver 00004 * FILE: drivers/dd/serial/pnp.c 00005 * PURPOSE: Serial IRP_MJ_PNP operations 00006 * 00007 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) 00008 */ 00009 /* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */ 00010 00011 #define INITGUID 00012 #include "serial.h" 00013 00014 NTSTATUS NTAPI 00015 SerialAddDeviceInternal( 00016 IN PDRIVER_OBJECT DriverObject, 00017 IN PDEVICE_OBJECT Pdo, 00018 IN UART_TYPE UartType, 00019 IN PULONG pComPortNumber OPTIONAL, 00020 OUT PDEVICE_OBJECT* pFdo OPTIONAL) 00021 { 00022 PDEVICE_OBJECT Fdo = NULL; 00023 PSERIAL_DEVICE_EXTENSION DeviceExtension = NULL; 00024 NTSTATUS Status; 00025 WCHAR DeviceNameBuffer[32]; 00026 UNICODE_STRING DeviceName; 00027 00028 TRACE_(SERIAL, "SerialAddDeviceInternal()\n"); 00029 00030 ASSERT(DriverObject); 00031 ASSERT(Pdo); 00032 00033 /* Create new device object */ 00034 swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", IoGetConfigurationInformation()->SerialCount); 00035 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer); 00036 Status = IoCreateDevice(DriverObject, 00037 sizeof(SERIAL_DEVICE_EXTENSION), 00038 &DeviceName, 00039 FILE_DEVICE_SERIAL_PORT, 00040 FILE_DEVICE_SECURE_OPEN, 00041 FALSE, 00042 &Fdo); 00043 if (!NT_SUCCESS(Status)) 00044 { 00045 WARN_(SERIAL, "IoCreateDevice() failed with status 0x%08x\n", Status); 00046 Fdo = NULL; 00047 goto ByeBye; 00048 } 00049 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)Fdo->DeviceExtension; 00050 RtlZeroMemory(DeviceExtension, sizeof(SERIAL_DEVICE_EXTENSION)); 00051 00052 /* Register device interface */ 00053 Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_COMPORT, NULL, &DeviceExtension->SerialInterfaceName); 00054 if (!NT_SUCCESS(Status)) 00055 { 00056 WARN_(SERIAL, "IoRegisterDeviceInterface() failed with status 0x%08x\n", Status); 00057 goto ByeBye; 00058 } 00059 00060 DeviceExtension->SerialPortNumber = IoGetConfigurationInformation()->SerialCount++; 00061 if (pComPortNumber == NULL) 00062 DeviceExtension->ComPort = DeviceExtension->SerialPortNumber + 1; 00063 else 00064 DeviceExtension->ComPort = *pComPortNumber; 00065 DeviceExtension->Pdo = Pdo; 00066 DeviceExtension->PnpState = dsStopped; 00067 DeviceExtension->UartType = UartType; 00068 Status = InitializeCircularBuffer(&DeviceExtension->InputBuffer, 16); 00069 if (!NT_SUCCESS(Status)) goto ByeBye; 00070 Status = InitializeCircularBuffer(&DeviceExtension->OutputBuffer, 16); 00071 if (!NT_SUCCESS(Status)) goto ByeBye; 00072 IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERIAL_TAG, 0, 0); 00073 KeInitializeSpinLock(&DeviceExtension->InputBufferLock); 00074 KeInitializeSpinLock(&DeviceExtension->OutputBufferLock); 00075 KeInitializeEvent(&DeviceExtension->InputBufferNotEmpty, NotificationEvent, FALSE); 00076 KeInitializeDpc(&DeviceExtension->ReceivedByteDpc, SerialReceiveByte, DeviceExtension); 00077 KeInitializeDpc(&DeviceExtension->SendByteDpc, SerialSendByte, DeviceExtension); 00078 KeInitializeDpc(&DeviceExtension->CompleteIrpDpc, SerialCompleteIrp, DeviceExtension); 00079 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); 00080 if (!NT_SUCCESS(Status)) 00081 { 00082 WARN_(SERIAL, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08x\n", Status); 00083 goto ByeBye; 00084 } 00085 if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE) 00086 Fdo->Flags |= DO_POWER_PAGABLE; 00087 if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO) 00088 Fdo->Flags |= DO_BUFFERED_IO; 00089 if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO) 00090 Fdo->Flags |= DO_DIRECT_IO; 00091 00092 /* Choose default strategy */ 00093 if ((Fdo->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)) == 0) 00094 Fdo->Flags |= DO_BUFFERED_IO; 00095 00096 Fdo->Flags &= ~DO_DEVICE_INITIALIZING; 00097 if (pFdo) 00098 { 00099 *pFdo = Fdo; 00100 } 00101 00102 return STATUS_SUCCESS; 00103 00104 ByeBye: 00105 if (Fdo) 00106 { 00107 FreeCircularBuffer(&DeviceExtension->InputBuffer); 00108 FreeCircularBuffer(&DeviceExtension->OutputBuffer); 00109 IoDeleteDevice(Fdo); 00110 } 00111 return Status; 00112 } 00113 00114 NTSTATUS NTAPI 00115 SerialAddDevice( 00116 IN PDRIVER_OBJECT DriverObject, 00117 IN PDEVICE_OBJECT Pdo) 00118 { 00119 /* Serial.sys is a legacy driver. AddDevice is called once 00120 * with a NULL Pdo just after the driver initialization. 00121 * Detect this case and return success. 00122 */ 00123 if (Pdo == NULL) 00124 return STATUS_SUCCESS; 00125 00126 /* We have here a PDO not null. It represents a real serial 00127 * port. So call the internal AddDevice function. 00128 */ 00129 return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL, NULL); 00130 } 00131 00132 NTSTATUS NTAPI 00133 SerialPnpStartDevice( 00134 IN PDEVICE_OBJECT DeviceObject, 00135 IN PCM_RESOURCE_LIST ResourceList, 00136 IN PCM_RESOURCE_LIST ResourceListTranslated) 00137 { 00138 PSERIAL_DEVICE_EXTENSION DeviceExtension; 00139 WCHAR DeviceNameBuffer[32]; 00140 UNICODE_STRING DeviceName; 00141 WCHAR LinkNameBuffer[32]; 00142 UNICODE_STRING LinkName; 00143 WCHAR ComPortBuffer[32]; 00144 UNICODE_STRING ComPort; 00145 ULONG Vector = 0; 00146 ULONG i; 00147 UCHAR IER; 00148 KIRQL Dirql; 00149 KAFFINITY Affinity = 0; 00150 KINTERRUPT_MODE InterruptMode = Latched; 00151 BOOLEAN ShareInterrupt = TRUE; 00152 OBJECT_ATTRIBUTES objectAttributes; 00153 PUCHAR ComPortBase; 00154 UNICODE_STRING KeyName; 00155 HANDLE hKey; 00156 NTSTATUS Status; 00157 00158 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00159 00160 ASSERT(DeviceExtension); 00161 00162 if (!ResourceList) 00163 { 00164 WARN_(SERIAL, "No allocated resources sent to driver\n"); 00165 return STATUS_INSUFFICIENT_RESOURCES; 00166 } 00167 if (ResourceList->Count != 1) 00168 { 00169 WARN_(SERIAL, "Wrong number of allocated resources sent to driver\n"); 00170 return STATUS_INSUFFICIENT_RESOURCES; 00171 } 00172 if (ResourceList->List[0].PartialResourceList.Version != 1 00173 || ResourceList->List[0].PartialResourceList.Revision != 1 00174 || ResourceListTranslated->List[0].PartialResourceList.Version != 1 00175 || ResourceListTranslated->List[0].PartialResourceList.Revision != 1) 00176 { 00177 WARN_(SERIAL, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n", 00178 ResourceList->List[0].PartialResourceList.Version, 00179 ResourceList->List[0].PartialResourceList.Revision, 00180 ResourceListTranslated->List[0].PartialResourceList.Version, 00181 ResourceListTranslated->List[0].PartialResourceList.Revision); 00182 return STATUS_REVISION_MISMATCH; 00183 } 00184 00185 DeviceExtension->BaudRate = 19200; 00186 DeviceExtension->BaseAddress = 0; 00187 Dirql = 0; 00188 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 00189 { 00190 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 00191 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i]; 00192 switch (PartialDescriptor->Type) 00193 { 00194 case CmResourceTypePort: 00195 if (PartialDescriptor->u.Port.Length < 7) 00196 return STATUS_INSUFFICIENT_RESOURCES; 00197 if (DeviceExtension->BaseAddress != 0) 00198 return STATUS_UNSUCCESSFUL; 00199 DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart; 00200 break; 00201 case CmResourceTypeInterrupt: 00202 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level; 00203 Vector = PartialDescriptorTranslated->u.Interrupt.Vector; 00204 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity; 00205 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) 00206 InterruptMode = Latched; 00207 else 00208 InterruptMode = LevelSensitive; 00209 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared); 00210 break; 00211 } 00212 } 00213 INFO_(SERIAL, "New COM port. Base = 0x%lx, Irql = %u\n", 00214 DeviceExtension->BaseAddress, Dirql); 00215 if (!DeviceExtension->BaseAddress) 00216 return STATUS_INSUFFICIENT_RESOURCES; 00217 if (!Dirql) 00218 return STATUS_INSUFFICIENT_RESOURCES; 00219 ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); 00220 00221 /* Test if we are trying to start the serial port used for debugging */ 00222 INFO_(SERIAL, "Comparing addresses: KdComPortInUse: %p, ComPortBase: %p\n", KdComPortInUse, ComPortBase); 00223 if (KdComPortInUse == ComPortBase) 00224 { 00225 INFO_(SERIAL, "Failing IRP_MN_START_DEVICE as this serial port is used for debugging\n"); 00226 return STATUS_INSUFFICIENT_RESOURCES; 00227 } 00228 00229 if (DeviceExtension->UartType == UartUnknown) 00230 DeviceExtension->UartType = SerialDetectUartType(ComPortBase); 00231 00232 /* Get current settings */ 00233 DeviceExtension->MCR = READ_PORT_UCHAR(SER_MCR(ComPortBase)); 00234 DeviceExtension->MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase)); 00235 DeviceExtension->WaitMask = 0; 00236 00237 /* Set baud rate */ 00238 Status = SerialSetBaudRate(DeviceExtension, DeviceExtension->BaudRate); 00239 if (!NT_SUCCESS(Status)) 00240 { 00241 WARN_(SERIAL, "SerialSetBaudRate() failed with status 0x%08x\n", Status); 00242 return Status; 00243 } 00244 00245 /* Set line control */ 00246 DeviceExtension->SerialLineControl.StopBits = STOP_BIT_1; 00247 DeviceExtension->SerialLineControl.Parity = NO_PARITY; 00248 DeviceExtension->SerialLineControl.WordLength = 8; 00249 Status = SerialSetLineControl(DeviceExtension, &DeviceExtension->SerialLineControl); 00250 if (!NT_SUCCESS(Status)) 00251 { 00252 WARN_(SERIAL, "SerialSetLineControl() failed with status 0x%08x\n", Status); 00253 return Status; 00254 } 00255 00256 /* Clear receive/transmit buffers */ 00257 if (DeviceExtension->UartType >= Uart16550A) 00258 { 00259 /* 16550 UARTs also have FIFO queues, but they are unusable due to a bug */ 00260 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), 00261 SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT); 00262 } 00263 00264 /* Create link \DosDevices\COMX -> \Device\SerialX */ 00265 swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", DeviceExtension->SerialPortNumber); 00266 swprintf(LinkNameBuffer, L"\\DosDevices\\COM%lu", DeviceExtension->ComPort); 00267 swprintf(ComPortBuffer, L"COM%lu", DeviceExtension->ComPort); 00268 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer); 00269 RtlInitUnicodeString(&LinkName, LinkNameBuffer); 00270 RtlInitUnicodeString(&ComPort, ComPortBuffer); 00271 Status = IoCreateSymbolicLink(&LinkName, &DeviceName); 00272 if (!NT_SUCCESS(Status)) 00273 { 00274 WARN_(SERIAL, "IoCreateSymbolicLink() failed with status 0x%08x\n", Status); 00275 return Status; 00276 } 00277 00278 /* Connect interrupt and enable them */ 00279 Status = IoConnectInterrupt( 00280 &DeviceExtension->Interrupt, SerialInterruptService, 00281 DeviceObject, NULL, 00282 Vector, Dirql, Dirql, 00283 InterruptMode, ShareInterrupt, 00284 Affinity, FALSE); 00285 if (!NT_SUCCESS(Status)) 00286 { 00287 WARN_(SERIAL, "IoConnectInterrupt() failed with status 0x%08x\n", Status); 00288 IoSetDeviceInterfaceState(&DeviceExtension->SerialInterfaceName, FALSE); 00289 IoDeleteSymbolicLink(&LinkName); 00290 return Status; 00291 } 00292 00293 /* Write an entry value under HKLM\HARDWARE\DeviceMap\SERIALCOMM */ 00294 /* This step is not mandatory, so don't exit in case of error */ 00295 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\DeviceMap\\SERIALCOMM"); 00296 InitializeObjectAttributes(&objectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); 00297 Status = ZwCreateKey(&hKey, KEY_SET_VALUE, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL); 00298 if (NT_SUCCESS(Status)) 00299 { 00300 /* Key = \Device\Serialx, Value = COMx */ 00301 ZwSetValueKey(hKey, &DeviceName, 0, REG_SZ, ComPortBuffer, ComPort.Length + sizeof(WCHAR)); 00302 ZwClose(hKey); 00303 } 00304 00305 DeviceExtension->PnpState = dsStarted; 00306 00307 /* Activate interrupt modes */ 00308 IER = READ_PORT_UCHAR(SER_IER(ComPortBase)); 00309 IER |= SR_IER_DATA_RECEIVED | SR_IER_THR_EMPTY | SR_IER_LSR_CHANGE | SR_IER_MSR_CHANGE; 00310 WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER); 00311 00312 /* Activate DTR, RTS */ 00313 DeviceExtension->MCR |= SR_MCR_DTR | SR_MCR_RTS; 00314 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); 00315 00316 /* Activate serial interface */ 00317 IoSetDeviceInterfaceState(&DeviceExtension->SerialInterfaceName, TRUE); 00318 /* We don't really care if the call succeeded or not... */ 00319 00320 return STATUS_SUCCESS; 00321 } 00322 00323 NTSTATUS NTAPI 00324 SerialPnp( 00325 IN PDEVICE_OBJECT DeviceObject, 00326 IN PIRP Irp) 00327 { 00328 ULONG MinorFunction; 00329 PIO_STACK_LOCATION Stack; 00330 ULONG_PTR Information = 0; 00331 NTSTATUS Status; 00332 00333 Stack = IoGetCurrentIrpStackLocation(Irp); 00334 MinorFunction = Stack->MinorFunction; 00335 00336 switch (MinorFunction) 00337 { 00338 /* FIXME: do all these minor functions 00339 IRP_MN_QUERY_REMOVE_DEVICE 0x1 00340 IRP_MN_REMOVE_DEVICE 0x2 00341 { 00342 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n"); 00343 IoAcquireRemoveLock 00344 IoReleaseRemoveLockAndWait 00345 pass request to DeviceExtension-LowerDriver 00346 disable interface 00347 IoDeleteDevice(Fdo) and/or IoDetachDevice 00348 break; 00349 } 00350 IRP_MN_CANCEL_REMOVE_DEVICE 0x3 00351 IRP_MN_STOP_DEVICE 0x4 00352 IRP_MN_QUERY_STOP_DEVICE 0x5 00353 IRP_MN_CANCEL_STOP_DEVICE 0x6 00354 IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) 0x7 00355 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7 00356 IRP_MN_QUERY_INTERFACE (optional) 0x8 00357 IRP_MN_QUERY_CAPABILITIES (optional) 0x9 00358 IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) 0xd 00359 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14 00360 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16 00361 IRP_MN_SURPRISE_REMOVAL 0x17 00362 */ 00363 case IRP_MN_START_DEVICE: /* 0x0 */ 00364 { 00365 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 00366 00367 ASSERT(((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState == dsStopped); 00368 00369 /* Call lower driver */ 00370 Status = ForwardIrpAndWait(DeviceObject, Irp); 00371 if (NT_SUCCESS(Status)) 00372 Status = SerialPnpStartDevice( 00373 DeviceObject, 00374 Stack->Parameters.StartDevice.AllocatedResources, 00375 Stack->Parameters.StartDevice.AllocatedResourcesTranslated); 00376 break; 00377 } 00378 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */ 00379 { 00380 switch (Stack->Parameters.QueryDeviceRelations.Type) 00381 { 00382 case BusRelations: 00383 { 00384 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 00385 return ForwardIrpAndForget(DeviceObject, Irp); 00386 } 00387 case RemovalRelations: 00388 { 00389 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n"); 00390 return ForwardIrpAndForget(DeviceObject, Irp); 00391 } 00392 default: 00393 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 00394 Stack->Parameters.QueryDeviceRelations.Type); 00395 return ForwardIrpAndForget(DeviceObject, Irp); 00396 } 00397 break; 00398 } 00399 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0xd */ 00400 { 00401 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 00402 return ForwardIrpAndForget(DeviceObject, Irp); 00403 } 00404 default: 00405 { 00406 TRACE_(SERIAL, "Unknown minor function 0x%x\n", MinorFunction); 00407 return ForwardIrpAndForget(DeviceObject, Irp); 00408 } 00409 } 00410 00411 Irp->IoStatus.Information = Information; 00412 Irp->IoStatus.Status = Status; 00413 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00414 return Status; 00415 } Generated on Sat May 26 2012 04:16:33 for ReactOS by
1.7.6.1
|