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 */
18 IN PDRIVER_OBJECT DriverObject
,
19 IN PDEVICE_OBJECT Pdo
)
21 PDEVICE_OBJECT Fdo
= NULL
;
22 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
24 WCHAR DeviceNameBuffer
[32];
25 UNICODE_STRING DeviceName
;
26 //UNICODE_STRING SymbolicLinkName;
27 static ULONG DeviceNumber
= 0;
29 DPRINT("Serial: SerialAddDevice called\n");
31 /* Create new device object */
32 swprintf(DeviceNameBuffer
, L
"\\Device\\Serial%lu", DeviceNumber
);
33 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
34 Status
= IoCreateDevice(DriverObject
,
35 sizeof(SERIAL_DEVICE_EXTENSION
),
37 FILE_DEVICE_SERIAL_PORT
,
38 FILE_DEVICE_SECURE_OPEN
,
41 if (!NT_SUCCESS(Status
))
43 DPRINT("Serial: IoCreateDevice() failed with status 0x%08x\n", Status
);
47 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
48 RtlZeroMemory(DeviceExtension
, sizeof(SERIAL_DEVICE_EXTENSION
));
50 /* Register device interface */
51 #if 0 /* FIXME: activate */
52 Status
= IoRegisterDeviceInterface(Pdo
, &GUID_DEVINTERFACE_COMPORT
, NULL
, &SymbolicLinkName
);
53 if (!NT_SUCCESS(Status
))
55 DPRINT("Serial: IoRegisterDeviceInterface() failed with status 0x%08x\n", Status
);
58 DPRINT1("Serial: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName
);
59 Status
= IoSetDeviceInterfaceState(&SymbolicLinkName
, TRUE
);
60 if (!NT_SUCCESS(Status
))
62 DPRINT("Serial: IoSetDeviceInterfaceState() failed with status 0x%08x\n", Status
);
65 RtlFreeUnicodeString(&SymbolicLinkName
);
68 DeviceExtension
->SerialPortNumber
= DeviceNumber
++;
69 DeviceExtension
->Pdo
= Pdo
;
70 DeviceExtension
->PnpState
= dsStopped
;
71 Status
= InitializeCircularBuffer(&DeviceExtension
->InputBuffer
, 16);
72 if (!NT_SUCCESS(Status
)) goto ByeBye
;
73 Status
= InitializeCircularBuffer(&DeviceExtension
->OutputBuffer
, 16);
74 if (!NT_SUCCESS(Status
)) goto ByeBye
;
75 IoInitializeRemoveLock(&DeviceExtension
->RemoveLock
, SERIAL_TAG
, 0, 0);
76 //Fdo->Flags |= DO_POWER_PAGEABLE (or DO_POWER_INRUSH?)
77 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
78 if (!NT_SUCCESS(Status
))
80 DPRINT("Serial: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08x\n", Status
);
83 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
85 return STATUS_SUCCESS
;
90 FreeCircularBuffer(&DeviceExtension
->InputBuffer
);
91 FreeCircularBuffer(&DeviceExtension
->OutputBuffer
);
99 IN PDEVICE_OBJECT DeviceObject
,
102 PIO_STACK_LOCATION Stack
;
103 //PCM_RESOURCE_LIST ResourceList;
104 PSERIAL_DEVICE_EXTENSION DeviceExtension
;
105 WCHAR DeviceNameBuffer
[32];
106 UNICODE_STRING DeviceName
;
107 WCHAR LinkNameBuffer
[32];
108 UNICODE_STRING LinkName
;
109 WCHAR ComPortBuffer
[32];
110 UNICODE_STRING ComPort
;
115 OBJECT_ATTRIBUTES objectAttributes
;
116 UNICODE_STRING KeyName
;
120 Stack
= IoGetCurrentIrpStackLocation(Irp
);
121 DeviceExtension
= (PSERIAL_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
123 /* FIXME: actually, IRP_MN_START_DEVICE is sent twice to each serial device:
124 * - one when loading serial.sys
125 * - one when loading attached upper filter serenum.sys
126 * This behaviour MUST NOT exist.
127 * As PnP handling isn't right anyway, I didn't search how to correct this.
129 if (DeviceExtension
->PnpState
== dsStarted
) return STATUS_SUCCESS
;
132 /* FIXME: PnP isn't correctly implemented and doesn't give us a list
133 * of our own resources. Use default values instead.
135 switch (DeviceExtension
->SerialPortNumber
)
138 DPRINT("Serial: creating COM1:\n");
139 DeviceExtension
->ComPort
= 1;
140 DeviceExtension
->BaudRate
= 19200 | SERIAL_BAUD_USER
;
141 DeviceExtension
->BaseAddress
= 0x3F8;
142 DeviceExtension
->Irq
= 4;
145 DPRINT("Serial: creating COM2:\n");
146 DeviceExtension
->ComPort
= 2;
147 DeviceExtension
->BaudRate
= 19200 | SERIAL_BAUD_USER
;
148 DeviceExtension
->BaseAddress
= 0x2F8;
149 DeviceExtension
->Irq
= 3;
152 DPRINT1("Serial: too much ports detected. Forgetting this one...\n");
153 return STATUS_INSUFFICIENT_RESOURCES
;
156 DPRINT1("Serial: ResourceList %p, ResourceListTranslated %p\n",
157 Stack
->Parameters
.StartDevice
.AllocatedResources
,
158 Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
);
159 ResourceList
= Stack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
;
160 for (i
= 0; i
< ResourceList
->Count
; i
++)
162 DPRINT1("Serial: Interface type = 0x%x\n", ResourceList
->List
[i
].InterfaceType
);
163 DPRINT1("Serial: Bus number = 0x%x\n", ResourceList
->List
[i
].BusNumber
);
164 for (j
= 0; i
< ResourceList
->List
[i
].PartialResourceList
.Count
; j
++)
166 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
= &ResourceList
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
167 DPRINT1("Serial: Type 0x%x, Share disposition 0x%x, Flags 0x%x\n",
168 PartialDescriptor
->Type
,
169 PartialDescriptor
->ShareDisposition
,
170 PartialDescriptor
->Flags
);
171 switch (PartialDescriptor
->Type
)
173 case CmResourceTypePort
:
174 DeviceExtension
->BaseAddress
= PartialDescriptor
->u
.Port
.Start
.u
.LowPart
;
175 DPRINT1("Serial: CmResourceTypePort = %lu\n", DeviceExtension
->BaseAddress
);
177 case CmResourceTypeInterrupt
:
178 /* FIXME: Detect if interrupt is shareable and/or latched */
179 /* FIXME: use also ->u.Interrupt.Vector and ->u.Interrupt.Affinity
180 * to remove call to HalGetInterruptVector(...) */
181 DeviceExtension
->Irq
= PartialDescriptor
->u
.Interrupt
.Level
;
182 DPRINT1("Serial: Irq = %lu\n", DeviceExtension
->Irq
);
187 DeviceExtension
->BaudRate
= 19200 | SERIAL_BAUD_USER
;
188 /* FIXME: use polling if no interrupt was found? */
189 DeviceExtension
->ComPort
= 5; /* FIXME: use incremental value, or find it in resource list */
192 /* Get current settings */
193 DeviceExtension
->IER
= READ_PORT_UCHAR(SER_IER((PUCHAR
)DeviceExtension
->BaseAddress
));
194 DeviceExtension
->MCR
= READ_PORT_UCHAR(SER_MCR((PUCHAR
)DeviceExtension
->BaseAddress
));
195 DeviceExtension
->MSR
= READ_PORT_UCHAR(SER_MSR((PUCHAR
)DeviceExtension
->BaseAddress
));
196 DeviceExtension
->WaitMask
= 0;
199 Status
= SerialSetBaudRate(DeviceExtension
, DeviceExtension
->BaudRate
);
200 if (!NT_SUCCESS(Status
))
202 DPRINT("Serial: SerialSetBaudRate() failed with status 0x%08x\n", Status
);
206 /* Set line control */
207 DeviceExtension
->SerialLineControl
.StopBits
= STOP_BIT_1
;
208 DeviceExtension
->SerialLineControl
.Parity
= NO_PARITY
;
209 DeviceExtension
->SerialLineControl
.WordLength
= 8;
210 Status
= SerialSetLineControl(DeviceExtension
, &DeviceExtension
->SerialLineControl
);
211 if (!NT_SUCCESS(Status
))
213 DPRINT("Serial: SerialSetLineControl() failed with status 0x%08x\n", Status
);
217 /* Create link \DosDevices\COMX -> \Device\SerialX */
218 swprintf(DeviceNameBuffer
, L
"\\Device\\Serial%lu", DeviceExtension
->SerialPortNumber
);
219 swprintf(LinkNameBuffer
, L
"\\DosDevices\\COM%lu", DeviceExtension
->ComPort
);
220 swprintf(ComPortBuffer
, L
"COM%lu", DeviceExtension
->ComPort
);
221 RtlInitUnicodeString(&DeviceName
, DeviceNameBuffer
);
222 RtlInitUnicodeString(&LinkName
, LinkNameBuffer
);
223 RtlInitUnicodeString(&ComPort
, ComPortBuffer
);
224 Status
= IoCreateSymbolicLink(&LinkName
, &DeviceName
);
225 if (!NT_SUCCESS(Status
))
227 DPRINT("Serial: IoCreateSymbolicLink() failed with status 0x%08x\n", Status
);
231 /* Connect interrupt and enable them */
232 Vector
= HalGetInterruptVector(Internal
, 0, 0, DeviceExtension
->Irq
, &Dirql
, &Affinity
);
233 Status
= IoConnectInterrupt(
234 &DeviceExtension
->Interrupt
, SerialInterruptService
,
235 DeviceObject
, NULL
, Vector
, Dirql
, Dirql
, Latched
,
236 FALSE
/* FIXME: or TRUE to share interrupt on PCI bus? */,
238 if (!NT_SUCCESS(Status
))
240 DPRINT("Serial: IoConnectInterrupt() failed with status 0x%08x\n", Status
);
241 IoDeleteSymbolicLink(&LinkName
);
245 /* Write an entry value under HKLM\HARDWARE\DeviceMap\SERIALCOMM */
246 /* This step is not mandatory, so don't exit in case of error */
247 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\DeviceMap\\SERIALCOMM");
248 InitializeObjectAttributes(&objectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
249 Status
= ZwCreateKey(&hKey
, KEY_SET_VALUE
, &objectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
250 if (NT_SUCCESS(Status
))
252 /* Key = \Device\Serialx, Value = COMx */
253 ZwSetValueKey(hKey
, &DeviceName
, 0, REG_SZ
, &ComPortBuffer
, ComPort
.Length
+ sizeof(WCHAR
));
257 DeviceExtension
->PnpState
= dsStarted
;
259 DeviceExtension
->IER
|= 0x1f; /* Activate interrupt mode */
260 DeviceExtension
->IER
&= ~1; /* FIXME: Disable receive byte interrupt */
261 WRITE_PORT_UCHAR(SER_IER((PUCHAR
)DeviceExtension
->BaseAddress
), DeviceExtension
->IER
);
263 DeviceExtension
->MCR
|= 0x03; /* Activate DTR, RTS */
264 WRITE_PORT_UCHAR(SER_MCR((PUCHAR
)DeviceExtension
->BaseAddress
), DeviceExtension
->MCR
);
266 return STATUS_SUCCESS
;
271 IN PDEVICE_OBJECT DeviceObject
,
275 PIO_STACK_LOCATION Stack
;
276 ULONG Information
= 0;
279 Stack
= IoGetCurrentIrpStackLocation(Irp
);
280 MinorFunction
= Stack
->MinorFunction
;
282 switch (MinorFunction
)
284 case IRP_MN_START_DEVICE
:
286 DPRINT("Serial: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
288 /* Call lower driver */
289 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
290 if (NT_SUCCESS(Status
))
291 Status
= SerialPnpStartDevice(DeviceObject
, Irp
);
294 /* IRP_MN_QUERY_STOP_DEVICE (FIXME: required) */
295 /* IRP_MN_STOP_DEVICE (FIXME: required) */
296 /* IRP_MN_CANCEL_STOP_DEVICE (FIXME: required) */
297 /* IRP_MN_QUERY_REMOVE_DEVICE (FIXME: required) */
298 /* case IRP_MN_REMOVE_DEVICE (FIXME: required) */
300 DPRINT("Serial: IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
302 IoReleaseRemoveLockAndWait
303 pass request to DeviceExtension-LowerDriver
304 IoDeleteDevice(Fdo) and/or IoDetachDevice
307 /* IRP_MN_CANCEL_REMOVE_DEVICE (FIXME: required) */
308 /* IRP_MN_SURPRISE_REMOVAL (FIXME: required) */
309 /* IRP_MN_QUERY_CAPABILITIES (optional) */
310 /* IRP_MN_QUERY_PNP_DEVICE_STATE (optional) */
311 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) */
312 /* IRP_MN_DEVICE_USAGE_NOTIFICATION (FIXME: required or optional ???) */
313 /* IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) */
314 /* IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) */
315 /* IRP_MN_QUERY_INTERFACE (optional) */
318 DPRINT1("Serial: unknown minor function 0x%x\n", MinorFunction
);
319 return ForwardIrpAndForget(DeviceObject
, Irp
);
323 Irp
->IoStatus
.Information
= Information
;
324 Irp
->IoStatus
.Status
= Status
;
325 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);