Activate serial device interface only at the very end of IRP_MN_START_DEVICE
[reactos.git] / reactos / drivers / dd / serial / pnp.c
index 211f7ae..e1a9bcf 100644 (file)
@@ -1,11 +1,10 @@
-/* $Id:
- * 
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         Serial port driver
  * FILE:            drivers/dd/serial/pnp.c
  * PURPOSE:         Serial IRP_MJ_PNP operations
- * 
- * PROGRAMMERS:     HervĂ© Poussineau (poussine@freesurf.fr)
+ *
+ * PROGRAMMERS:     HervĂ© Poussineau (hpoussin@reactos.com)
  */
 /* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
 
@@ -26,12 +25,14 @@ SerialAddDeviceInternal(
        NTSTATUS Status;
        WCHAR DeviceNameBuffer[32];
        UNICODE_STRING DeviceName;
-       //UNICODE_STRING SymbolicLinkName;
        static ULONG DeviceNumber = 0;
        static ULONG ComPortNumber = 1;
 
        DPRINT("Serial: SerialAddDeviceInternal called\n");
-   
+
+       ASSERT(DriverObject);
+       ASSERT(Pdo);
+
        /* Create new device object */
        swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", DeviceNumber);
        RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
@@ -50,24 +51,14 @@ SerialAddDeviceInternal(
        }
        DeviceExtension = (PSERIAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
        RtlZeroMemory(DeviceExtension, sizeof(SERIAL_DEVICE_EXTENSION));
-       
+
        /* Register device interface */
-#if 0 /* FIXME: activate */
-       Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_COMPORT, NULL, &SymbolicLinkName);
+       Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_COMPORT, NULL, &DeviceExtension->SerialInterfaceName);
        if (!NT_SUCCESS(Status))
        {
                DPRINT("Serial: IoRegisterDeviceInterface() failed with status 0x%08x\n", Status);
                goto ByeBye;
        }
-       DPRINT1("Serial: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName);
-       Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
-       if (!NT_SUCCESS(Status))
-       {
-               DPRINT("Serial: IoSetDeviceInterfaceState() failed with status 0x%08x\n", Status);
-               goto ByeBye;
-       }
-       RtlFreeUnicodeString(&SymbolicLinkName);
-#endif
 
        DeviceExtension->SerialPortNumber = DeviceNumber++;
        if (pComPortNumber == NULL)
@@ -100,7 +91,7 @@ SerialAddDeviceInternal(
        {
                *pFdo = Fdo;
        }
-       
+
        return STATUS_SUCCESS;
 
 ByeBye:
@@ -124,19 +115,18 @@ SerialAddDevice(
         */
        if (Pdo == NULL)
                return STATUS_SUCCESS;
-       
-       /* We have here a PDO that does not correspond to a legacy
-        * serial port. So call the internal AddDevice function.
+
+       /* We have here a PDO not null. It represents a real serial
+        * port. So call the internal AddDevice function.
         */
        return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL, NULL);
-
-
 }
 
 NTSTATUS STDCALL
 SerialPnpStartDevice(
        IN PDEVICE_OBJECT DeviceObject,
-       IN PCM_RESOURCE_LIST ResourceList)
+       IN PCM_RESOURCE_LIST ResourceList,
+       IN PCM_RESOURCE_LIST ResourceListTranslated)
 {
        PSERIAL_DEVICE_EXTENSION DeviceExtension;
        WCHAR DeviceNameBuffer[32];
@@ -157,12 +147,14 @@ SerialPnpStartDevice(
        UNICODE_STRING KeyName;
        HANDLE hKey;
        NTSTATUS Status;
-       
+
        DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-       
+
+       ASSERT(ResourceList);
+       ASSERT(DeviceExtension);
        ASSERT(DeviceExtension->PnpState == dsStopped);
-       
-       DeviceExtension->BaudRate = 19200 | SERIAL_BAUD_USER;
+
+       DeviceExtension->BaudRate = 19200;
        DeviceExtension->BaseAddress = 0;
        Dirql = 0;
        for (i = 0; i < ResourceList->Count; i++)
@@ -170,6 +162,7 @@ SerialPnpStartDevice(
                for (j = 0; j < ResourceList->List[i].PartialResourceList.Count; j++)
                {
                        PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[i].PartialResourceList.PartialDescriptors[j];
+                       PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated = &ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
                        switch (PartialDescriptor->Type)
                        {
                                case CmResourceTypePort:
@@ -180,16 +173,14 @@ SerialPnpStartDevice(
                                        DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart;
                                        break;
                                case CmResourceTypeInterrupt:
-                                       if (Dirql != 0)
-                                               return STATUS_UNSUCCESSFUL;
-                                       Dirql = (KIRQL)PartialDescriptor->u.Interrupt.Level;
-                                       Vector = PartialDescriptor->u.Interrupt.Vector;
-                                       Affinity = PartialDescriptor->u.Interrupt.Affinity;
-                                       if (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
+                                       Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
+                                       Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
+                                       Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
+                                       if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
                                                InterruptMode = Latched;
                                        else
                                                InterruptMode = LevelSensitive;
-                                       ShareInterrupt = (PartialDescriptor->ShareDisposition == CmResourceShareShared);
+                                       ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
                                        break;
                        }
                }
@@ -201,15 +192,15 @@ SerialPnpStartDevice(
        if (!Dirql)
                return STATUS_INSUFFICIENT_RESOURCES;
        ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
-       
+
        if (DeviceExtension->UartType == UartUnknown)
                DeviceExtension->UartType = SerialDetectUartType(ComPortBase);
-       
+
        /* Get current settings */
        DeviceExtension->MCR = READ_PORT_UCHAR(SER_MCR(ComPortBase));
        DeviceExtension->MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase));
        DeviceExtension->WaitMask = 0;
-       
+
        /* Set baud rate */
        Status = SerialSetBaudRate(DeviceExtension, DeviceExtension->BaudRate);
        if (!NT_SUCCESS(Status))
@@ -217,7 +208,7 @@ SerialPnpStartDevice(
                DPRINT("Serial: SerialSetBaudRate() failed with status 0x%08x\n", Status);
                return Status;
        }
-       
+
        /* Set line control */
        DeviceExtension->SerialLineControl.StopBits = STOP_BIT_1;
        DeviceExtension->SerialLineControl.Parity = NO_PARITY;
@@ -228,7 +219,7 @@ SerialPnpStartDevice(
                DPRINT("Serial: SerialSetLineControl() failed with status 0x%08x\n", Status);
                return Status;
        }
-       
+
        /* Clear receive/transmit buffers */
        if (DeviceExtension->UartType >= Uart16550A)
        {
@@ -236,7 +227,7 @@ SerialPnpStartDevice(
                WRITE_PORT_UCHAR(SER_FCR(ComPortBase),
                        SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT);
        }
-       
+
        /* Create link \DosDevices\COMX -> \Device\SerialX */
        swprintf(DeviceNameBuffer, L"\\Device\\Serial%lu", DeviceExtension->SerialPortNumber);
        swprintf(LinkNameBuffer, L"\\DosDevices\\COM%lu", DeviceExtension->ComPort);
@@ -250,7 +241,7 @@ SerialPnpStartDevice(
                DPRINT("Serial: IoCreateSymbolicLink() failed with status 0x%08x\n", Status);
                return Status;
        }
-       
+
        /* Connect interrupt and enable them */
        Status = IoConnectInterrupt(
                &DeviceExtension->Interrupt, SerialInterruptService,
@@ -261,10 +252,11 @@ SerialPnpStartDevice(
        if (!NT_SUCCESS(Status))
        {
                DPRINT("Serial: IoConnectInterrupt() failed with status 0x%08x\n", Status);
+               IoSetDeviceInterfaceState(&DeviceExtension->SerialInterfaceName, FALSE);
                IoDeleteSymbolicLink(&LinkName);
                return Status;
        }
-       
+
        /* Write an entry value under HKLM\HARDWARE\DeviceMap\SERIALCOMM */
        /* This step is not mandatory, so don't exit in case of error */
        RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\DeviceMap\\SERIALCOMM");
@@ -273,21 +265,25 @@ SerialPnpStartDevice(
        if (NT_SUCCESS(Status))
        {
                /* Key = \Device\Serialx, Value = COMx */
-               ZwSetValueKey(hKey, &DeviceName, 0, REG_SZ, &ComPortBuffer, ComPort.Length + sizeof(WCHAR));
+               ZwSetValueKey(hKey, &DeviceName, 0, REG_SZ, ComPortBuffer, ComPort.Length + sizeof(WCHAR));
                ZwClose(hKey);
        }
-       
+
        DeviceExtension->PnpState = dsStarted;
-       
+
        /* Activate interrupt modes */
        IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
        IER |= SR_IER_DATA_RECEIVED | SR_IER_THR_EMPTY | SR_IER_LSR_CHANGE | SR_IER_MSR_CHANGE;
        WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER);
-       
+
        /* Activate DTR, RTS */
        DeviceExtension->MCR |= SR_MCR_DTR | SR_MCR_RTS;
        WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
-       
+
+       /* Activate serial interface */
+       IoSetDeviceInterfaceState(&DeviceExtension->SerialInterfaceName, TRUE);
+       /* We don't really care if the call succeeded or not... */
+
        return STATUS_SUCCESS;
 }
 
@@ -300,27 +296,45 @@ SerialPnp(
        PIO_STACK_LOCATION Stack;
        ULONG_PTR Information = 0;
        NTSTATUS Status;
-       
+
        Stack = IoGetCurrentIrpStackLocation(Irp);
        MinorFunction = Stack->MinorFunction;
-       
+
        switch (MinorFunction)
        {
-               case IRP_MN_START_DEVICE:
+               /* FIXME: do all these minor functions
+               IRP_MN_QUERY_REMOVE_DEVICE 0x1
+               IRP_MN_REMOVE_DEVICE 0x2
+               {
+                       DPRINT("Serial: IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
+                       IoAcquireRemoveLock
+                       IoReleaseRemoveLockAndWait
+                       pass request to DeviceExtension-LowerDriver
+                       disable interface
+                       IoDeleteDevice(Fdo) and/or IoDetachDevice
+                       break;
+               }
+               IRP_MN_CANCEL_REMOVE_DEVICE 0x3
+               IRP_MN_STOP_DEVICE 0x4
+               IRP_MN_QUERY_STOP_DEVICE 0x5
+               IRP_MN_CANCEL_STOP_DEVICE 0x6
+               IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) 0x7
+               IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
+               IRP_MN_QUERY_INTERFACE (optional) 0x8
+               IRP_MN_QUERY_CAPABILITIES (optional) 0x9
+               IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) 0xd
+               IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
+               IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
+               IRP_MN_SURPRISE_REMOVAL 0x17
+               */
+               case IRP_MN_START_DEVICE: /* 0x0 */
                {
                        BOOLEAN ConflictDetected;
                        DPRINT("Serial: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
-                       
-                       /* FIXME: first HACK: PnP manager can send multiple
-                        * IRP_MN_START_DEVICE for one device
-                        */
-                       if (((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState != dsStopped)
-                       {
-                               DPRINT1("Serial: device already started. Ignoring this irp!\n");
-                               Status = STATUS_SUCCESS;
-                               break;
-                       }
-                       /* FIXME: second HACK: verify that we have some allocated resources.
+
+                       ASSERT(((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState == dsStopped);
+
+                       /* FIXME: HACK: verify that we have some allocated resources.
                         * It seems not to be always the case on some hardware
                         */
                        if (Stack->Parameters.StartDevice.AllocatedResources == NULL)
@@ -330,7 +344,7 @@ SerialPnp(
                                Status = STATUS_INSUFFICIENT_RESOURCES;
                                break;
                        }
-                       /* FIXME: third HACK: verify that we don't have resource conflict,
+                       /* FIXME: HACK: verify that we don't have resource conflict,
                         * because PnP manager doesn't do it automatically
                         */
                        Status = IoReportResourceForDetection(
@@ -344,44 +358,44 @@ SerialPnp(
                                IoCompleteRequest(Irp, IO_NO_INCREMENT);
                                return Status;
                        }
-                       
+
                        /* Call lower driver */
                        Status = ForwardIrpAndWait(DeviceObject, Irp);
                        if (NT_SUCCESS(Status))
                                Status = SerialPnpStartDevice(
                                        DeviceObject,
-                                       Stack->Parameters.StartDevice.AllocatedResources);
+                                       Stack->Parameters.StartDevice.AllocatedResources,
+                                       Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
                        break;
                }
-               /* IRP_MN_QUERY_STOP_DEVICE (FIXME: required) */
-               /* IRP_MN_STOP_DEVICE (FIXME: required) */
-               /* IRP_MN_CANCEL_STOP_DEVICE (FIXME: required) */
-               /* IRP_MN_QUERY_REMOVE_DEVICE (FIXME: required) */
-               /* case IRP_MN_REMOVE_DEVICE (FIXME: required) */
-               /*{
-                       DPRINT("Serial: IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
-                       IoAcquireRemoveLock
-                       IoReleaseRemoveLockAndWait
-                       pass request to DeviceExtension-LowerDriver
-                       IoDeleteDevice(Fdo) and/or IoDetachDevice
+               case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
+               {
+                       switch (Stack->Parameters.QueryDeviceRelations.Type)
+                       {
+                               case BusRelations:
+                               {
+                                       DPRINT("Serial: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
+                                       return ForwardIrpAndForget(DeviceObject, Irp);
+                               }
+                               case RemovalRelations:
+                               {
+                                       DPRINT("Serial: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
+                                       return ForwardIrpAndForget(DeviceObject, Irp);
+                               }
+                               default:
+                                       DPRINT1("Serial: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
+                                               Stack->Parameters.QueryDeviceRelations.Type);
+                                       return ForwardIrpAndForget(DeviceObject, Irp);
+                       }
                        break;
-               }*/
-               /* IRP_MN_CANCEL_REMOVE_DEVICE (FIXME: required) */
-               /* IRP_MN_SURPRISE_REMOVAL (FIXME: required) */
-               /* IRP_MN_QUERY_CAPABILITIES (optional) */
-               /* IRP_MN_QUERY_PNP_DEVICE_STATE (optional) */
-               /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) */
-               /* IRP_MN_DEVICE_USAGE_NOTIFICATION (FIXME: required or optional ???) */
-               /* IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) */
-               /* IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) */
-               /* IRP_MN_QUERY_INTERFACE (optional) */
+               }
                default:
                {
                        DPRINT1("Serial: unknown minor function 0x%x\n", MinorFunction);
                        return ForwardIrpAndForget(DeviceObject, Irp);
                }
        }
-       
+
        Irp->IoStatus.Information = Information;
        Irp->IoStatus.Status = Status;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);