ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pnp.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.