3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/dd/serial/pnp.c
6 * PURPOSE: Serial IRP_MJ_PNP operations
8 * PROGRAMMERS: Hervé Poussineau (poussine@freesurf.fr)
10 /* FIXME: call IoAcquireRemoveLock/IoReleaseRemoveLock around each I/O operation */
17 SerialAddDeviceInternal(
18 IN PDRIVER_OBJECT DriverObject
,
19 IN PDEVICE_OBJECT Pdo
,
20 OUT PDEVICE_OBJECT
* pFdo OPTIONAL
)
22 PDEVICE_OBJECT Fdo
= NULL
;
23 PSERIAL_DEVICE_EXTENSION DeviceExtension
= NULL
;
25 WCHAR DeviceNameBuffer
[32];
26 UNICODE_STRING DeviceName
;
27 //UNICODE_STRING SymbolicLinkName;
28 static ULONG DeviceNumber
= 0;
30 DPRINT("Serial: SerialAddDeviceInternal called\n");
32 /* Create new device object */
33 swprintf(DeviceNameBuffer
, L
"\\Device\\Serial%lu", DeviceNumber
);
34 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
35 Status
= IoCreateDevice(DriverObject
,
36 sizeof(SERIAL_DEVICE_EXTENSION
),
38 FILE_DEVICE_SERIAL_PORT
,
39 FILE_DEVICE_SECURE_OPEN
,
42 if (!NT_SUCCESS(Status
))
44 DPRINT("Serial: IoCreateDevice() failed with status 0x%08x\n", Status
);
48 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
49 RtlZeroMemory(DeviceExtension
, sizeof(SERIAL_DEVICE_EXTENSION
));
51 /* Register device interface */
52 #if 0 /* FIXME: activate */
53 Status
= IoRegisterDeviceInterface(Pdo
, &GUID_DEVINTERFACE_COMPORT
, NULL
, &SymbolicLinkName
);
54 if (!NT_SUCCESS(Status
))
56 DPRINT("Serial: IoRegisterDeviceInterface() failed with status 0x%08x\n", Status
);
59 DPRINT1("Serial: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName
);
60 Status
= IoSetDeviceInterfaceState(&SymbolicLinkName
, TRUE
);
61 if (!NT_SUCCESS(Status
))
63 DPRINT("Serial: IoSetDeviceInterfaceState() failed with status 0x%08x\n", Status
);
66 RtlFreeUnicodeString(&SymbolicLinkName
);
69 DeviceExtension
->SerialPortNumber
= DeviceNumber
++;
70 DeviceExtension
->Pdo
= Pdo
;
71 DeviceExtension
->PnpState
= dsStopped
;
72 Status
= InitializeCircularBuffer(&DeviceExtension
->InputBuffer
, 16);
73 if (!NT_SUCCESS(Status
)) goto ByeBye
;
74 Status
= InitializeCircularBuffer(&DeviceExtension
->OutputBuffer
, 16);
75 if (!NT_SUCCESS(Status
)) goto ByeBye
;
76 IoInitializeRemoveLock(&DeviceExtension
->RemoveLock
, SERIAL_TAG
, 0, 0);
77 //Fdo->Flags |= DO_POWER_PAGEABLE (or DO_POWER_INRUSH?)
78 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
79 if (!NT_SUCCESS(Status
))
81 DPRINT("Serial: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08x\n", Status
);
84 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
90 return STATUS_SUCCESS
;
95 FreeCircularBuffer(&DeviceExtension
->InputBuffer
);
96 FreeCircularBuffer(&DeviceExtension
->OutputBuffer
);
104 IN PDRIVER_OBJECT DriverObject
,
105 IN PDEVICE_OBJECT Pdo
)
107 /* Serial.sys is a legacy driver. AddDevice is called once
108 * with a NULL Pdo just after the driver initialization.
109 * Detect this case and return success.
112 return STATUS_SUCCESS
;
114 /* We have here a PDO that does not correspond to a legacy
115 * serial port. So call the internal AddDevice function.
117 DPRINT1("Serial: SerialAddDevice() called. Pdo 0x%p (should be NULL)\n", Pdo
);
118 /* FIXME: due to a bug, previously described AddDevice is
119 * not called with a NULL Pdo. Block this call (blocks
120 * unfortunately all the other PnP serial ports devices).
122 //return SerialAddDeviceInternal(DriverObject, Pdo, NULL);
123 return STATUS_UNSUCCESSFUL
;
127 SerialPnpStartDevice(
128 IN PDEVICE_OBJECT DeviceObject
,
129 IN PCM_RESOURCE_LIST ResourceList
)
131 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
132 WCHAR DeviceNameBuffer
[32];
133 UNICODE_STRING DeviceName
;
134 WCHAR LinkNameBuffer
[32];
135 UNICODE_STRING LinkName
;
136 WCHAR ComPortBuffer
[32];
137 UNICODE_STRING ComPort
;
141 KAFFINITY Affinity
= 0;
142 KINTERRUPT_MODE InterruptMode
= Latched
;
143 BOOLEAN ShareInterrupt
= TRUE
;
144 OBJECT_ATTRIBUTES objectAttributes
;
145 UNICODE_STRING KeyName
;
149 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
151 /* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device:
152 * - one when loading serial.sys
153 * - one when loading attached upper filter serenum.sys
154 * This behaviour MUST NOT exist.
155 * As PnP handling isn't right anyway, I didn't search how to correct this.
157 if (DeviceExtension
->PnpState
== dsStarted
) return STATUS_SUCCESS
;
159 DeviceExtension
->ComPort
= DeviceExtension
->SerialPortNumber
+ 1;
160 DeviceExtension
->BaudRate
= 19200 | SERIAL_BAUD_USER
;
161 DeviceExtension
->BaseAddress
= 0;
163 for (i
= 0; i
< ResourceList
->Count
; i
++)
165 for (j
= 0; j
< ResourceList
->List
[i
].PartialResourceList
.Count
; j
++)
167 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
= &ResourceList
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
168 switch (PartialDescriptor
->Type
)
170 case CmResourceTypePort
:
171 if (PartialDescriptor
->u
.Port
.Length
< 8)
172 return STATUS_INSUFFICIENT_RESOURCES
;
173 if (DeviceExtension
->BaseAddress
!= 0)
174 return STATUS_UNSUCCESSFUL
;
175 DeviceExtension
->BaseAddress
= PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
177 case CmResourceTypeInterrupt
:
179 return STATUS_UNSUCCESSFUL
;
180 Dirql
= (KIRQL
)PartialDescriptor
->u
.Interrupt
.Level
;
181 Vector
= PartialDescriptor
->u
.Interrupt
.Vector
;
182 Affinity
= PartialDescriptor
->u
.Interrupt
.Affinity
;
183 if (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
)
184 InterruptMode
= Latched
;
186 InterruptMode
= LevelSensitive
;
187 ShareInterrupt
= (PartialDescriptor
->ShareDisposition
== CmResourceShareShared
);
192 DPRINT("Serial: New COM port. Base = 0x%lx, Irql = %u\n",
193 DeviceExtension
->BaseAddress
, Dirql
);
194 if (!DeviceExtension
->BaseAddress
)
195 return STATUS_INSUFFICIENT_RESOURCES
;
196 /* FIXME: we should be able to continue and use polling method
197 * for read/write if we don't have an interrupt */
199 return STATUS_INSUFFICIENT_RESOURCES
;
201 /* Get current settings */
202 DeviceExtension
->IER
= READ_PORT_UCHAR(SER_IER((PUCHAR
)DeviceExtension
->BaseAddress
));
203 DeviceExtension
->MCR
= READ_PORT_UCHAR(SER_MCR((PUCHAR
)DeviceExtension
->BaseAddress
));
204 DeviceExtension
->MSR
= READ_PORT_UCHAR(SER_MSR((PUCHAR
)DeviceExtension
->BaseAddress
));
205 DeviceExtension
->WaitMask
= 0;
208 Status
= SerialSetBaudRate(DeviceExtension
, DeviceExtension
->BaudRate
);
209 if (!NT_SUCCESS(Status
))
211 DPRINT("Serial: SerialSetBaudRate() failed with status 0x%08x\n", Status
);
215 /* Set line control */
216 DeviceExtension
->SerialLineControl
.StopBits
= STOP_BIT_1
;
217 DeviceExtension
->SerialLineControl
.Parity
= NO_PARITY
;
218 DeviceExtension
->SerialLineControl
.WordLength
= 8;
219 Status
= SerialSetLineControl(DeviceExtension
, &DeviceExtension
->SerialLineControl
);
220 if (!NT_SUCCESS(Status
))
222 DPRINT("Serial: SerialSetLineControl() failed with status 0x%08x\n", Status
);
226 /* Create link \DosDevices\COMX -> \Device\SerialX */
227 swprintf(DeviceNameBuffer
, L
"\\Device\\Serial%lu", DeviceExtension
->SerialPortNumber
);
228 swprintf(LinkNameBuffer
, L
"\\DosDevices\\COM%lu", DeviceExtension
->ComPort
);
229 swprintf(ComPortBuffer
, L
"COM%lu", DeviceExtension
->ComPort
);
230 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
231 RtlInitUnicodeString(&LinkName
, LinkNameBuffer
);
232 RtlInitUnicodeString(&ComPort
, ComPortBuffer
);
233 Status
= IoCreateSymbolicLink(&LinkName
, &DeviceName
);
234 if (!NT_SUCCESS(Status
))
236 DPRINT("Serial: IoCreateSymbolicLink() failed with status 0x%08x\n", Status
);
240 /* Connect interrupt and enable them */
241 Status
= IoConnectInterrupt(
242 &DeviceExtension
->Interrupt
, SerialInterruptService
,
244 Vector
, Dirql
, Dirql
,
245 InterruptMode
, ShareInterrupt
,
247 if (!NT_SUCCESS(Status
))
249 DPRINT("Serial: IoConnectInterrupt() failed with status 0x%08x\n", Status
);
250 IoDeleteSymbolicLink(&LinkName
);
254 /* Write an entry value under HKLM\HARDWARE\DeviceMap\SERIALCOMM */
255 /* This step is not mandatory, so don't exit in case of error */
256 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\DeviceMap\\SERIALCOMM");
257 InitializeObjectAttributes(&objectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
258 Status
= ZwCreateKey(&hKey
, KEY_SET_VALUE
, &objectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
259 if (NT_SUCCESS(Status
))
261 /* Key = \Device\Serialx, Value = COMx */
262 ZwSetValueKey(hKey
, &DeviceName
, 0, REG_SZ
, &ComPortBuffer
, ComPort
.Length
+ sizeof(WCHAR
));
266 DeviceExtension
->PnpState
= dsStarted
;
268 DeviceExtension
->IER
|= 0x1f; /* Activate interrupt mode */
269 DeviceExtension
->IER
&= ~1; /* FIXME: Disable receive byte interrupt */
270 WRITE_PORT_UCHAR(SER_IER((PUCHAR
)DeviceExtension
->BaseAddress
), DeviceExtension
->IER
);
272 DeviceExtension
->MCR
|= 0x03; /* Activate DTR, RTS */
273 WRITE_PORT_UCHAR(SER_MCR((PUCHAR
)DeviceExtension
->BaseAddress
), DeviceExtension
->MCR
);
275 return STATUS_SUCCESS
;
280 IN PDEVICE_OBJECT DeviceObject
,
284 PIO_STACK_LOCATION Stack
;
285 ULONG Information
= 0;
288 Stack
= IoGetCurrentIrpStackLocation(Irp
);
289 MinorFunction
= Stack
->MinorFunction
;
291 switch (MinorFunction
)
293 case IRP_MN_START_DEVICE
:
295 DPRINT("Serial: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
297 /* Call lower driver */
298 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
299 if (NT_SUCCESS(Status
))
300 Status
= SerialPnpStartDevice(
302 Stack
->Parameters
.StartDevice
.AllocatedResources
);
305 /* IRP_MN_QUERY_STOP_DEVICE (FIXME: required) */
306 /* IRP_MN_STOP_DEVICE (FIXME: required) */
307 /* IRP_MN_CANCEL_STOP_DEVICE (FIXME: required) */
308 /* IRP_MN_QUERY_REMOVE_DEVICE (FIXME: required) */
309 /* case IRP_MN_REMOVE_DEVICE (FIXME: required) */
311 DPRINT("Serial: IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
313 IoReleaseRemoveLockAndWait
314 pass request to DeviceExtension-LowerDriver
315 IoDeleteDevice(Fdo) and/or IoDetachDevice
318 /* IRP_MN_CANCEL_REMOVE_DEVICE (FIXME: required) */
319 /* IRP_MN_SURPRISE_REMOVAL (FIXME: required) */
320 /* IRP_MN_QUERY_CAPABILITIES (optional) */
321 /* IRP_MN_QUERY_PNP_DEVICE_STATE (optional) */
322 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) */
323 /* IRP_MN_DEVICE_USAGE_NOTIFICATION (FIXME: required or optional ???) */
324 /* IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) */
325 /* IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) */
326 /* IRP_MN_QUERY_INTERFACE (optional) */
329 DPRINT1("Serial: unknown minor function 0x%x\n", MinorFunction
);
330 return ForwardIrpAndForget(DeviceObject
, Irp
);
334 Irp
->IoStatus
.Information
= Information
;
335 Irp
->IoStatus
.Status
= Status
;
336 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);