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 IN UART_TYPE UartType
,
21 OUT PDEVICE_OBJECT
* pFdo OPTIONAL
)
23 PDEVICE_OBJECT Fdo
= NULL
;
24 PSERIAL_DEVICE_EXTENSION DeviceExtension
= NULL
;
26 WCHAR DeviceNameBuffer
[32];
27 UNICODE_STRING DeviceName
;
28 //UNICODE_STRING SymbolicLinkName;
29 static ULONG DeviceNumber
= 0;
31 DPRINT("Serial: SerialAddDeviceInternal called\n");
33 /* Create new device object */
34 swprintf(DeviceNameBuffer
, L
"\\Device\\Serial%lu", DeviceNumber
);
35 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
36 Status
= IoCreateDevice(DriverObject
,
37 sizeof(SERIAL_DEVICE_EXTENSION
),
39 FILE_DEVICE_SERIAL_PORT
,
40 FILE_DEVICE_SECURE_OPEN
,
43 if (!NT_SUCCESS(Status
))
45 DPRINT("Serial: IoCreateDevice() failed with status 0x%08x\n", Status
);
49 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
50 RtlZeroMemory(DeviceExtension
, sizeof(SERIAL_DEVICE_EXTENSION
));
52 /* Register device interface */
53 #if 0 /* FIXME: activate */
54 Status
= IoRegisterDeviceInterface(Pdo
, &GUID_DEVINTERFACE_COMPORT
, NULL
, &SymbolicLinkName
);
55 if (!NT_SUCCESS(Status
))
57 DPRINT("Serial: IoRegisterDeviceInterface() failed with status 0x%08x\n", Status
);
60 DPRINT1("Serial: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName
);
61 Status
= IoSetDeviceInterfaceState(&SymbolicLinkName
, TRUE
);
62 if (!NT_SUCCESS(Status
))
64 DPRINT("Serial: IoSetDeviceInterfaceState() failed with status 0x%08x\n", Status
);
67 RtlFreeUnicodeString(&SymbolicLinkName
);
70 DeviceExtension
->SerialPortNumber
= DeviceNumber
++;
71 DeviceExtension
->Pdo
= Pdo
;
72 DeviceExtension
->PnpState
= dsStopped
;
73 DeviceExtension
->UartType
= UartType
;
74 Status
= InitializeCircularBuffer(&DeviceExtension
->InputBuffer
, 16);
75 if (!NT_SUCCESS(Status
)) goto ByeBye
;
76 Status
= InitializeCircularBuffer(&DeviceExtension
->OutputBuffer
, 16);
77 if (!NT_SUCCESS(Status
)) goto ByeBye
;
78 IoInitializeRemoveLock(&DeviceExtension
->RemoveLock
, SERIAL_TAG
, 0, 0);
79 KeInitializeSpinLock(&DeviceExtension
->InputBufferLock
);
80 KeInitializeSpinLock(&DeviceExtension
->OutputBufferLock
);
81 KeInitializeDpc(&DeviceExtension
->ReceivedByteDpc
, SerialReceiveByte
, DeviceExtension
);
82 KeInitializeDpc(&DeviceExtension
->SendByteDpc
, SerialSendByte
, DeviceExtension
);
83 //Fdo->Flags |= DO_POWER_PAGEABLE (or DO_POWER_INRUSH?)
84 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
85 if (!NT_SUCCESS(Status
))
87 DPRINT("Serial: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08x\n", Status
);
90 Fdo
->Flags
|= DO_BUFFERED_IO
;
91 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
97 return STATUS_SUCCESS
;
102 FreeCircularBuffer(&DeviceExtension
->InputBuffer
);
103 FreeCircularBuffer(&DeviceExtension
->OutputBuffer
);
111 IN PDRIVER_OBJECT DriverObject
,
112 IN PDEVICE_OBJECT Pdo
)
114 /* Serial.sys is a legacy driver. AddDevice is called once
115 * with a NULL Pdo just after the driver initialization.
116 * Detect this case and return success.
119 return STATUS_SUCCESS
;
121 /* We have here a PDO that does not correspond to a legacy
122 * serial port. So call the internal AddDevice function.
124 DPRINT1("Serial: SerialAddDevice() called. Pdo 0x%p (should be NULL)\n", Pdo
);
125 /* FIXME: due to a bug, previously described AddDevice is
126 * not called with a NULL Pdo. Block this call (blocks
127 * unfortunately all the other PnP serial ports devices).
129 //return SerialAddDeviceInternal(DriverObject, Pdo, UartUnknown, NULL);
130 return STATUS_UNSUCCESSFUL
;
134 SerialPnpStartDevice(
135 IN PDEVICE_OBJECT DeviceObject
,
136 IN PCM_RESOURCE_LIST ResourceList
)
138 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
139 WCHAR DeviceNameBuffer
[32];
140 UNICODE_STRING DeviceName
;
141 WCHAR LinkNameBuffer
[32];
142 UNICODE_STRING LinkName
;
143 WCHAR ComPortBuffer
[32];
144 UNICODE_STRING ComPort
;
148 KAFFINITY Affinity
= 0;
149 KINTERRUPT_MODE InterruptMode
= Latched
;
150 BOOLEAN ShareInterrupt
= TRUE
;
151 OBJECT_ATTRIBUTES objectAttributes
;
153 UNICODE_STRING KeyName
;
157 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
159 ASSERT(DeviceExtension
->PnpState
== dsStopped
);
161 DeviceExtension
->ComPort
= DeviceExtension
->SerialPortNumber
+ 1;
162 DeviceExtension
->BaudRate
= 19200 | SERIAL_BAUD_USER
;
163 DeviceExtension
->BaseAddress
= 0;
165 for (i
= 0; i
< ResourceList
->Count
; i
++)
167 for (j
= 0; j
< ResourceList
->List
[i
].PartialResourceList
.Count
; j
++)
169 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
= &ResourceList
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
170 switch (PartialDescriptor
->Type
)
172 case CmResourceTypePort
:
173 if (PartialDescriptor
->u
.Port
.Length
< 8)
174 return STATUS_INSUFFICIENT_RESOURCES
;
175 if (DeviceExtension
->BaseAddress
!= 0)
176 return STATUS_UNSUCCESSFUL
;
177 DeviceExtension
->BaseAddress
= PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
179 case CmResourceTypeInterrupt
:
181 return STATUS_UNSUCCESSFUL
;
182 Dirql
= (KIRQL
)PartialDescriptor
->u
.Interrupt
.Level
;
183 Vector
= PartialDescriptor
->u
.Interrupt
.Vector
;
184 Affinity
= PartialDescriptor
->u
.Interrupt
.Affinity
;
185 if (PartialDescriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
)
186 InterruptMode
= Latched
;
188 InterruptMode
= LevelSensitive
;
189 ShareInterrupt
= (PartialDescriptor
->ShareDisposition
== CmResourceShareShared
);
194 DPRINT("Serial: New COM port. Base = 0x%lx, Irql = %u\n",
195 DeviceExtension
->BaseAddress
, Dirql
);
196 if (!DeviceExtension
->BaseAddress
)
197 return STATUS_INSUFFICIENT_RESOURCES
;
198 /* FIXME: we should be able to continue and use polling method
199 * for read/write if we don't have an interrupt */
201 return STATUS_INSUFFICIENT_RESOURCES
;
202 ComPortBase
= (PUCHAR
)DeviceExtension
->BaseAddress
;
204 if (DeviceExtension
->UartType
== UartUnknown
)
205 DeviceExtension
->UartType
= SerialDetectUartType(ComPortBase
);
207 /* Get current settings */
208 DeviceExtension
->IER
= READ_PORT_UCHAR(SER_IER(ComPortBase
));
209 DeviceExtension
->MCR
= READ_PORT_UCHAR(SER_MCR(ComPortBase
));
210 DeviceExtension
->MSR
= READ_PORT_UCHAR(SER_MSR(ComPortBase
));
211 DeviceExtension
->WaitMask
= 0;
214 Status
= SerialSetBaudRate(DeviceExtension
, DeviceExtension
->BaudRate
);
215 if (!NT_SUCCESS(Status
))
217 DPRINT("Serial: SerialSetBaudRate() failed with status 0x%08x\n", Status
);
221 /* Set line control */
222 DeviceExtension
->SerialLineControl
.StopBits
= STOP_BIT_1
;
223 DeviceExtension
->SerialLineControl
.Parity
= NO_PARITY
;
224 DeviceExtension
->SerialLineControl
.WordLength
= 8;
225 Status
= SerialSetLineControl(DeviceExtension
, &DeviceExtension
->SerialLineControl
);
226 if (!NT_SUCCESS(Status
))
228 DPRINT("Serial: SerialSetLineControl() failed with status 0x%08x\n", Status
);
232 /* Clear receive/transmit buffers */
233 if (DeviceExtension
->UartType
>= Uart16550
)
235 WRITE_PORT_UCHAR(SER_FCR(ComPortBase
),
236 SR_FCR_CLEAR_RCVR
| SR_FCR_CLEAR_XMIT
);
239 /* Create link \DosDevices\COMX -> \Device\SerialX */
240 swprintf(DeviceNameBuffer
, L
"\\Device\\Serial%lu", DeviceExtension
->SerialPortNumber
);
241 swprintf(LinkNameBuffer
, L
"\\DosDevices\\COM%lu", DeviceExtension
->ComPort
);
242 swprintf(ComPortBuffer
, L
"COM%lu", DeviceExtension
->ComPort
);
243 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
244 RtlInitUnicodeString(&LinkName
, LinkNameBuffer
);
245 RtlInitUnicodeString(&ComPort
, ComPortBuffer
);
246 Status
= IoCreateSymbolicLink(&LinkName
, &DeviceName
);
247 if (!NT_SUCCESS(Status
))
249 DPRINT("Serial: IoCreateSymbolicLink() failed with status 0x%08x\n", Status
);
253 /* Connect interrupt and enable them */
254 Status
= IoConnectInterrupt(
255 &DeviceExtension
->Interrupt
, SerialInterruptService
,
257 Vector
, Dirql
, Dirql
,
258 InterruptMode
, ShareInterrupt
,
260 if (!NT_SUCCESS(Status
))
262 DPRINT("Serial: IoConnectInterrupt() failed with status 0x%08x\n", Status
);
263 IoDeleteSymbolicLink(&LinkName
);
267 /* Write an entry value under HKLM\HARDWARE\DeviceMap\SERIALCOMM */
268 /* This step is not mandatory, so don't exit in case of error */
269 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\DeviceMap\\SERIALCOMM");
270 InitializeObjectAttributes(&objectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
271 Status
= ZwCreateKey(&hKey
, KEY_SET_VALUE
, &objectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
272 if (NT_SUCCESS(Status
))
274 /* Key = \Device\Serialx, Value = COMx */
275 ZwSetValueKey(hKey
, &DeviceName
, 0, REG_SZ
, &ComPortBuffer
, ComPort
.Length
+ sizeof(WCHAR
));
279 DeviceExtension
->PnpState
= dsStarted
;
281 DeviceExtension
->IER
|= 0x1f; /* Activate interrupt mode */
282 DeviceExtension
->IER
&= ~1; /* FIXME: Disable receive byte interrupt */
283 WRITE_PORT_UCHAR(SER_IER(ComPortBase
), DeviceExtension
->IER
);
285 DeviceExtension
->MCR
|= 0x03; /* Activate DTR, RTS */
286 WRITE_PORT_UCHAR(SER_MCR(ComPortBase
), DeviceExtension
->MCR
);
288 return STATUS_SUCCESS
;
293 IN PDEVICE_OBJECT DeviceObject
,
297 PIO_STACK_LOCATION Stack
;
298 ULONG Information
= 0;
301 Stack
= IoGetCurrentIrpStackLocation(Irp
);
302 MinorFunction
= Stack
->MinorFunction
;
304 switch (MinorFunction
)
306 case IRP_MN_START_DEVICE
:
308 DPRINT("Serial: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
310 /* Call lower driver */
311 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
312 if (NT_SUCCESS(Status
))
313 Status
= SerialPnpStartDevice(
315 Stack
->Parameters
.StartDevice
.AllocatedResources
);
318 /* IRP_MN_QUERY_STOP_DEVICE (FIXME: required) */
319 /* IRP_MN_STOP_DEVICE (FIXME: required) */
320 /* IRP_MN_CANCEL_STOP_DEVICE (FIXME: required) */
321 /* IRP_MN_QUERY_REMOVE_DEVICE (FIXME: required) */
322 /* case IRP_MN_REMOVE_DEVICE (FIXME: required) */
324 DPRINT("Serial: IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
326 IoReleaseRemoveLockAndWait
327 pass request to DeviceExtension-LowerDriver
328 IoDeleteDevice(Fdo) and/or IoDetachDevice
331 /* IRP_MN_CANCEL_REMOVE_DEVICE (FIXME: required) */
332 /* IRP_MN_SURPRISE_REMOVAL (FIXME: required) */
333 /* IRP_MN_QUERY_CAPABILITIES (optional) */
334 /* IRP_MN_QUERY_PNP_DEVICE_STATE (optional) */
335 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) */
336 /* IRP_MN_DEVICE_USAGE_NOTIFICATION (FIXME: required or optional ???) */
337 /* IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) */
338 /* IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) */
339 /* IRP_MN_QUERY_INTERFACE (optional) */
342 DPRINT1("Serial: unknown minor function 0x%x\n", MinorFunction
);
343 return ForwardIrpAndForget(DeviceObject
, Irp
);
347 Irp
->IoStatus
.Information
= Information
;
348 Irp
->IoStatus
.Status
= Status
;
349 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);