Fix sublanguage IDs in .rc files:
[reactos.git] / reactos / drivers / dd / serial / devctrl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Serial port driver
4 * FILE: drivers/dd/serial/devctrl.c
5 * PURPOSE: Serial IRP_MJ_DEVICE_CONTROL operations
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
8 */
9
10 #define NDEBUG
11 #include "serial.h"
12
13 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
14
15 static VOID
16 SerialGetUserBuffers(
17 IN PIRP Irp,
18 IN ULONG IoControlCode,
19 OUT PVOID* BufferIn,
20 OUT PVOID* BufferOut)
21 {
22 ASSERT(Irp);
23 ASSERT(BufferIn);
24 ASSERT(BufferOut);
25
26 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
27 {
28 case METHOD_BUFFERED:
29 *BufferIn = *BufferOut = Irp->AssociatedIrp.SystemBuffer;
30 break;
31 case METHOD_IN_DIRECT:
32 case METHOD_OUT_DIRECT:
33 *BufferIn = Irp->AssociatedIrp.SystemBuffer;
34 *BufferOut = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
35 break;
36 case METHOD_NEITHER:
37 *BufferIn = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.Type3InputBuffer;
38 *BufferOut = Irp->UserBuffer;
39 break;
40 default:
41 /* Should never happen */
42 *BufferIn = NULL;
43 *BufferOut = NULL;
44 break;
45 }
46 }
47
48 NTSTATUS STDCALL
49 SerialSetBaudRate(
50 IN PSERIAL_DEVICE_EXTENSION DeviceExtension,
51 IN ULONG NewBaudRate)
52 {
53 ULONG BaudRate;
54 USHORT divisor;
55 PUCHAR ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
56 NTSTATUS Status = STATUS_SUCCESS;
57
58 divisor = (USHORT)(BAUD_CLOCK / (CLOCKS_PER_BIT * NewBaudRate));
59 BaudRate = BAUD_CLOCK / (CLOCKS_PER_BIT * divisor);
60
61 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
62 if (NT_SUCCESS(Status))
63 {
64 UCHAR Lcr;
65 DPRINT("Serial: SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension->ComPort, BaudRate);
66 /* Set Bit 7 of LCR to expose baud registers */
67 Lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase));
68 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr | SR_LCR_DLAB);
69 /* Write the baud rate */
70 WRITE_PORT_UCHAR(SER_DLL(ComPortBase), divisor & 0xff);
71 WRITE_PORT_UCHAR(SER_DLM(ComPortBase), divisor >> 8);
72 /* Switch back to normal registers */
73 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr);
74
75 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
76 }
77
78 if (NT_SUCCESS(Status))
79 DeviceExtension->BaudRate = BaudRate;
80 return Status;
81 }
82
83 NTSTATUS STDCALL
84 SerialSetLineControl(
85 IN PSERIAL_DEVICE_EXTENSION DeviceExtension,
86 IN PSERIAL_LINE_CONTROL NewSettings)
87 {
88 PUCHAR ComPortBase;
89 UCHAR Lcr = 0;
90 NTSTATUS Status;
91
92 ASSERT(DeviceExtension);
93 ASSERT(NewSettings);
94
95 DPRINT("Serial: SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n",
96 DeviceExtension->ComPort, NewSettings->StopBits, NewSettings->Parity, NewSettings->WordLength);
97
98 /* Verify parameters */
99 switch (NewSettings->WordLength)
100 {
101 case 5: Lcr |= SR_LCR_CS5; break;
102 case 6: Lcr |= SR_LCR_CS6; break;
103 case 7: Lcr |= SR_LCR_CS7; break;
104 case 8: Lcr |= SR_LCR_CS8; break;
105 default: return STATUS_INVALID_PARAMETER;
106 }
107
108 if (NewSettings->WordLength < 5 || NewSettings->WordLength > 8)
109 return STATUS_INVALID_PARAMETER;
110
111 switch (NewSettings->Parity)
112 {
113 case NO_PARITY: Lcr |= SR_LCR_PNO; break;
114 case ODD_PARITY: Lcr |= SR_LCR_POD; break;
115 case EVEN_PARITY: Lcr |= SR_LCR_PEV; break;
116 case MARK_PARITY: Lcr |= SR_LCR_PMK; break;
117 case SPACE_PARITY: Lcr |= SR_LCR_PSP; break;
118 default: return STATUS_INVALID_PARAMETER;
119 }
120
121 switch (NewSettings->StopBits)
122 {
123 case STOP_BIT_1:
124 Lcr |= SR_LCR_ST1;
125 break;
126 case STOP_BITS_1_5:
127 if (NewSettings->WordLength != 5)
128 return STATUS_INVALID_PARAMETER;
129 Lcr |= SR_LCR_ST2;
130 break;
131 case STOP_BITS_2:
132 if (NewSettings->WordLength < 6 || NewSettings->WordLength > 8)
133 return STATUS_INVALID_PARAMETER;
134 Lcr |= SR_LCR_ST2;
135 break;
136 default:
137 return STATUS_INVALID_PARAMETER;
138 }
139
140 /* Update current parameters */
141 ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
142 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
143 if (!NT_SUCCESS(Status))
144 return Status;
145 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr);
146
147 /* Read junk out of RBR */
148 READ_PORT_UCHAR(SER_RBR(ComPortBase));
149 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
150
151 if (NT_SUCCESS(Status))
152 DeviceExtension->SerialLineControl = *NewSettings;
153
154 return Status;
155 }
156
157 static BOOLEAN
158 SerialClearPerfStats(
159 IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
160 {
161 ASSERT(DeviceExtension);
162
163 RtlZeroMemory(&DeviceExtension->SerialPerfStats, sizeof(SERIALPERF_STATS));
164 DeviceExtension->BreakInterruptErrorCount = 0;
165 return TRUE;
166 }
167
168 static BOOLEAN
169 SerialGetPerfStats(IN PIRP pIrp)
170 {
171 PSERIAL_DEVICE_EXTENSION pDeviceExtension;
172
173 ASSERT(pIrp);
174 pDeviceExtension = (PSERIAL_DEVICE_EXTENSION)
175 IoGetCurrentIrpStackLocation(pIrp)->DeviceObject->DeviceExtension;
176
177 /*
178 * we assume buffer is big enough to hold SerialPerfStats structure
179 * caller must verify this
180 */
181 RtlCopyMemory(
182 pIrp->AssociatedIrp.SystemBuffer,
183 &pDeviceExtension->SerialPerfStats,
184 sizeof(SERIALPERF_STATS)
185 );
186 return TRUE;
187 }
188
189 static NTSTATUS
190 SerialGetCommProp(
191 OUT PSERIAL_COMMPROP pCommProp,
192 IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
193 {
194 ASSERT(pCommProp);
195
196 RtlZeroMemory(pCommProp, sizeof(SERIAL_COMMPROP));
197
198 if (!(pCommProp->ProvSpec1 & COMMPROP_INITIALIZED))
199 pCommProp->PacketLength = sizeof(SERIAL_COMMPROP);
200 pCommProp->PacketVersion = 2;
201 pCommProp->ServiceMask = SERIAL_SP_SERIALCOMM;
202 pCommProp->MaxTxQueue = pCommProp->CurrentTxQueue = DeviceExtension->OutputBuffer.Length - 1;
203 pCommProp->MaxRxQueue = pCommProp->CurrentRxQueue = DeviceExtension->InputBuffer.Length - 1;
204 pCommProp->ProvSubType = PST_RS232;
205 pCommProp->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_INTTIMEOUTS | SERIAL_PCF_PARITY_CHECK
206 | SERIAL_PCF_RTSCTS | SERIAL_PCF_SETXCHAR | SERIAL_PCF_SPECIALCHARS | SERIAL_PCF_TOTALTIMEOUTS
207 | SERIAL_PCF_XONXOFF;
208 pCommProp->SettableParams = SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_HANDSHAKING
209 | SERIAL_SP_PARITY | SERIAL_SP_PARITY_CHECK | SERIAL_SP_STOPBITS;
210
211 /* SettableBaud is related to Uart type */
212 pCommProp->SettableBaud = SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_134_5
213 | SERIAL_BAUD_150 | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200
214 | SERIAL_BAUD_1800 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200
215 | SERIAL_BAUD_9600 | SERIAL_BAUD_USER;
216 pCommProp->MaxBaud = SERIAL_BAUD_USER;
217 if (DeviceExtension->UartType >= Uart16450)
218 {
219 pCommProp->SettableBaud |= SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400;
220 }
221 if (DeviceExtension->UartType >= Uart16550)
222 {
223 pCommProp->SettableBaud |= SERIAL_BAUD_56K | SERIAL_BAUD_57600 | SERIAL_BAUD_115200 | SERIAL_BAUD_128K;
224 }
225
226 pCommProp->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8;
227 pCommProp->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20
228 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE;
229
230 pCommProp->ProvSpec2 = 0; /* Size of provider-specific data */
231
232 return STATUS_SUCCESS;
233 }
234
235 static NTSTATUS
236 SerialGetCommStatus(
237 OUT PSERIAL_STATUS pSerialStatus,
238 IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
239 {
240 KIRQL Irql;
241
242 ASSERT(pSerialStatus);
243 RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS));
244
245 pSerialStatus->Errors = 0;
246 if (DeviceExtension->BreakInterruptErrorCount)
247 pSerialStatus->Errors |= SERIAL_ERROR_BREAK;
248 if (DeviceExtension->SerialPerfStats.FrameErrorCount)
249 pSerialStatus->Errors |= SERIAL_ERROR_FRAMING;
250 if (DeviceExtension->SerialPerfStats.SerialOverrunErrorCount)
251 pSerialStatus->Errors |= SERIAL_ERROR_OVERRUN;
252 if (DeviceExtension->SerialPerfStats.BufferOverrunErrorCount)
253 pSerialStatus->Errors |= SERIAL_ERROR_QUEUEOVERRUN;
254 if (DeviceExtension->SerialPerfStats.ParityErrorCount)
255 pSerialStatus->Errors |= SERIAL_ERROR_PARITY;
256
257 pSerialStatus->HoldReasons = 0; /* FIXME */
258
259 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
260 pSerialStatus->AmountInInQueue = (DeviceExtension->InputBuffer.WritePosition + DeviceExtension->InputBuffer.Length
261 - DeviceExtension->InputBuffer.ReadPosition) % DeviceExtension->InputBuffer.Length;
262 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
263
264 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
265 pSerialStatus->AmountInOutQueue = (DeviceExtension->OutputBuffer.WritePosition + DeviceExtension->OutputBuffer.Length
266 - DeviceExtension->OutputBuffer.ReadPosition) % DeviceExtension->OutputBuffer.Length;
267 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
268
269 pSerialStatus->EofReceived = FALSE; /* always FALSE */
270 pSerialStatus->WaitForImmediate = FALSE; /* always FALSE */
271
272 return STATUS_SUCCESS;
273 }
274
275 NTSTATUS STDCALL
276 SerialDeviceControl(
277 IN PDEVICE_OBJECT DeviceObject,
278 IN PIRP Irp)
279 {
280 PIO_STACK_LOCATION Stack;
281 ULONG IoControlCode;
282 PSERIAL_DEVICE_EXTENSION DeviceExtension;
283 ULONG LengthIn, LengthOut;
284 ULONG_PTR Information = 0;
285 PVOID BufferIn, BufferOut;
286 PUCHAR ComPortBase;
287 NTSTATUS Status;
288
289 DPRINT("Serial: IRP_MJ_DEVICE_CONTROL dispatch\n");
290
291 Stack = IoGetCurrentIrpStackLocation(Irp);
292 LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
293 LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
294 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
295 ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
296 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
297 SerialGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);
298
299 /* FIXME: need to probe buffers */
300 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
301 switch (IoControlCode)
302 {
303 case IOCTL_SERIAL_CLEAR_STATS:
304 {
305 DPRINT("Serial: IOCTL_SERIAL_CLEAR_STATS\n");
306 KeSynchronizeExecution(
307 DeviceExtension->Interrupt,
308 (PKSYNCHRONIZE_ROUTINE)SerialClearPerfStats,
309 DeviceExtension);
310 Status = STATUS_SUCCESS;
311 break;
312 }
313 case IOCTL_SERIAL_CLR_DTR:
314 {
315 DPRINT("Serial: IOCTL_SERIAL_CLR_DTR\n");
316 /* FIXME: If the handshake flow control of the device is configured to
317 * automatically use DTR, return STATUS_INVALID_PARAMETER */
318 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
319 if (NT_SUCCESS(Status))
320 {
321 DeviceExtension->MCR &= ~SR_MCR_DTR;
322 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
323 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
324 }
325 break;
326 }
327 case IOCTL_SERIAL_CLR_RTS:
328 {
329 DPRINT("Serial: IOCTL_SERIAL_CLR_RTS\n");
330 /* FIXME: If the handshake flow control of the device is configured to
331 * automatically use RTS, return STATUS_INVALID_PARAMETER */
332 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
333 if (NT_SUCCESS(Status))
334 {
335 DeviceExtension->MCR &= ~SR_MCR_RTS;
336 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
337 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
338 }
339 break;
340 }
341 case IOCTL_SERIAL_CONFIG_SIZE:
342 {
343 /* Obsolete on Microsoft Windows 2000+ */
344 PULONG pConfigSize;
345 DPRINT("Serial: IOCTL_SERIAL_CONFIG_SIZE\n");
346 if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
347 Status = STATUS_INVALID_PARAMETER;
348 else
349 {
350 pConfigSize = (PULONG)BufferOut;
351 *pConfigSize = 0;
352 Status = STATUS_SUCCESS;
353 }
354 break;
355 }
356 case IOCTL_SERIAL_GET_BAUD_RATE:
357 {
358 DPRINT("Serial: IOCTL_SERIAL_GET_BAUD_RATE\n");
359 if (LengthOut < sizeof(SERIAL_BAUD_RATE))
360 Status = STATUS_BUFFER_TOO_SMALL;
361 else if (BufferOut == NULL)
362 Status = STATUS_INVALID_PARAMETER;
363 else
364 {
365 ((PSERIAL_BAUD_RATE)BufferOut)->BaudRate = DeviceExtension->BaudRate;
366 Information = sizeof(SERIAL_BAUD_RATE);
367 Status = STATUS_SUCCESS;
368 }
369 break;
370 }
371 case IOCTL_SERIAL_GET_CHARS:
372 {
373 /* FIXME */
374 DPRINT1("Serial: IOCTL_SERIAL_GET_CHARS not implemented.\n");
375 Status = STATUS_NOT_IMPLEMENTED;
376 break;
377 }
378 case IOCTL_SERIAL_GET_COMMSTATUS:
379 {
380 DPRINT("Serial: IOCTL_SERIAL_GET_COMMSTATUS\n");
381 if (LengthOut < sizeof(SERIAL_STATUS))
382 {
383 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
384 Status = STATUS_BUFFER_TOO_SMALL;
385 }
386 else if (BufferOut == NULL)
387 {
388 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
389 Status = STATUS_INVALID_PARAMETER;
390 }
391 else
392 {
393 Status = SerialGetCommStatus((PSERIAL_STATUS)BufferOut, DeviceExtension);
394 Information = sizeof(SERIAL_STATUS);
395 }
396 break;
397 }
398 case IOCTL_SERIAL_GET_DTRRTS:
399 {
400 PULONG pDtrRts;
401 DPRINT("Serial: IOCTL_SERIAL_GET_DTRRTS\n");
402 if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
403 Status = STATUS_INVALID_PARAMETER;
404 else
405 {
406 pDtrRts = (PULONG)BufferOut;
407 *pDtrRts = 0;
408 if (DeviceExtension->MCR & SR_MCR_DTR)
409 *pDtrRts |= SERIAL_DTR_STATE;
410 if (DeviceExtension->MCR & SR_MCR_RTS)
411 *pDtrRts |= SERIAL_RTS_STATE;
412 Status = STATUS_SUCCESS;
413 }
414 break;
415 }
416 case IOCTL_SERIAL_GET_HANDFLOW:
417 {
418 /* FIXME */
419 DPRINT1("Serial: IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
420 Status = STATUS_NOT_IMPLEMENTED;
421 break;
422 }
423 case IOCTL_SERIAL_GET_LINE_CONTROL:
424 {
425 DPRINT("Serial: IOCTL_SERIAL_GET_LINE_CONTROL\n");
426 if (LengthOut < sizeof(SERIAL_LINE_CONTROL))
427 Status = STATUS_BUFFER_TOO_SMALL;
428 else if (BufferOut == NULL)
429 Status = STATUS_INVALID_PARAMETER;
430 else
431 {
432 *((PSERIAL_LINE_CONTROL)BufferOut) = DeviceExtension->SerialLineControl;
433 Information = sizeof(SERIAL_LINE_CONTROL);
434 Status = STATUS_SUCCESS;
435 }
436 break;
437 }
438 case IOCTL_SERIAL_GET_MODEM_CONTROL:
439 {
440 PULONG pMCR;
441 DPRINT("Serial: IOCTL_SERIAL_GET_MODEM_CONTROL\n");
442 if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
443 Status = STATUS_INVALID_PARAMETER;
444 else
445 {
446 pMCR = (PULONG)BufferOut;
447 *pMCR = DeviceExtension->MCR;
448 Status = STATUS_SUCCESS;
449 }
450 break;
451 }
452 case IOCTL_SERIAL_GET_MODEMSTATUS:
453 {
454 PULONG pMSR;
455 DPRINT("Serial: IOCTL_SERIAL_GET_MODEMSTATUS\n");
456 if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
457 Status = STATUS_INVALID_PARAMETER;
458 else
459 {
460 pMSR = (PULONG)BufferOut;
461 *pMSR = DeviceExtension->MSR;
462 Status = STATUS_SUCCESS;
463 }
464 break;
465 }
466 case IOCTL_SERIAL_GET_PROPERTIES:
467 {
468 DPRINT("Serial: IOCTL_SERIAL_GET_PROPERTIES\n");
469 if (LengthOut < sizeof(SERIAL_COMMPROP))
470 {
471 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
472 Status = STATUS_BUFFER_TOO_SMALL;
473 }
474 else if (BufferOut == NULL)
475 {
476 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
477 Status = STATUS_INVALID_PARAMETER;
478 }
479 else
480 {
481 Status = SerialGetCommProp((PSERIAL_COMMPROP)BufferOut, DeviceExtension);
482 Information = sizeof(SERIAL_COMMPROP);
483 }
484 break;
485 }
486 case IOCTL_SERIAL_GET_STATS:
487 {
488 DPRINT("Serial: IOCTL_SERIAL_GET_STATS\n");
489 if (LengthOut < sizeof(SERIALPERF_STATS))
490 {
491 DPRINT("Serial: return STATUS_BUFFER_TOO_SMALL\n");
492 Status = STATUS_BUFFER_TOO_SMALL;
493 }
494 else if (BufferOut == NULL)
495 {
496 DPRINT("Serial: return STATUS_INVALID_PARAMETER\n");
497 Status = STATUS_INVALID_PARAMETER;
498 }
499 else
500 {
501 KeSynchronizeExecution(DeviceExtension->Interrupt,
502 (PKSYNCHRONIZE_ROUTINE)SerialGetPerfStats, Irp);
503 Status = STATUS_SUCCESS;
504 Information = sizeof(SERIALPERF_STATS);
505 }
506 break;
507 }
508 case IOCTL_SERIAL_GET_TIMEOUTS:
509 {
510 DPRINT("Serial: IOCTL_SERIAL_GET_TIMEOUTS\n");
511 if (LengthOut != sizeof(SERIAL_TIMEOUTS) || BufferOut == NULL)
512 Status = STATUS_INVALID_PARAMETER;
513 else
514 {
515 *(PSERIAL_TIMEOUTS)BufferOut = DeviceExtension->SerialTimeOuts;
516 Status = STATUS_SUCCESS;
517 }
518 break;
519 }
520 case IOCTL_SERIAL_GET_WAIT_MASK:
521 {
522 PULONG pWaitMask;
523 DPRINT("Serial: IOCTL_SERIAL_GET_WAIT_MASK\n");
524 if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
525 Status = STATUS_INVALID_PARAMETER;
526 else
527 {
528 pWaitMask = (PULONG)BufferOut;
529 *pWaitMask = DeviceExtension->WaitMask;
530 Status = STATUS_SUCCESS;
531 }
532 break;
533 }
534 case IOCTL_SERIAL_IMMEDIATE_CHAR:
535 {
536 /* FIXME */
537 DPRINT1("Serial: IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
538 Status = STATUS_NOT_IMPLEMENTED;
539 break;
540 }
541 case IOCTL_SERIAL_LSRMST_INSERT:
542 {
543 /* FIXME */
544 DPRINT1("Serial: IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
545 Status = STATUS_NOT_IMPLEMENTED;
546 break;
547 }
548 case IOCTL_SERIAL_PURGE:
549 {
550 KIRQL Irql;
551 DPRINT("Serial: IOCTL_SERIAL_PURGE\n");
552 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
553 * should stop current request */
554 if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
555 Status = STATUS_INVALID_PARAMETER;
556 else
557 {
558 ULONG PurgeMask = *(PULONG)BufferIn;
559
560 Status = STATUS_SUCCESS;
561 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
562 if (PurgeMask & SERIAL_PURGE_RXCLEAR)
563 {
564 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
565 DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0;
566 if (DeviceExtension->UartType >= Uart16550A)
567 {
568 /* Clear also Uart FIFO */
569 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
570 if (NT_SUCCESS(Status))
571 {
572 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR);
573 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
574 }
575 }
576 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
577 }
578
579 if (PurgeMask & SERIAL_PURGE_TXCLEAR)
580 {
581 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
582 DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
583 if (DeviceExtension->UartType >= Uart16550A)
584 {
585 /* Clear also Uart FIFO */
586 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
587 if (NT_SUCCESS(Status))
588 {
589 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_XMIT);
590 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
591 }
592 }
593 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
594 }
595 }
596 break;
597 }
598 case IOCTL_SERIAL_RESET_DEVICE:
599 {
600 /* FIXME */
601 DPRINT1("Serial: IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
602 Status = STATUS_NOT_IMPLEMENTED;
603 break;
604 }
605 case IOCTL_SERIAL_SET_BAUD_RATE:
606 {
607 PULONG pNewBaudRate;
608 DPRINT("Serial: IOCTL_SERIAL_SET_BAUD_RATE\n");
609 if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
610 Status = STATUS_INVALID_PARAMETER;
611 else
612 {
613 pNewBaudRate = (PULONG)BufferIn;
614 Status = SerialSetBaudRate(DeviceExtension, *pNewBaudRate);
615 }
616 break;
617 }
618 case IOCTL_SERIAL_SET_BREAK_OFF:
619 {
620 /* FIXME */
621 DPRINT1("Serial: IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
622 Status = STATUS_NOT_IMPLEMENTED;
623 break;
624 }
625 case IOCTL_SERIAL_SET_BREAK_ON:
626 {
627 /* FIXME */
628 DPRINT1("Serial: IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
629 Status = STATUS_NOT_IMPLEMENTED;
630 break;
631 }
632 case IOCTL_SERIAL_SET_CHARS:
633 {
634 /* FIXME */
635 DPRINT1("Serial: IOCTL_SERIAL_SET_CHARS not implemented.\n");
636 Status = STATUS_NOT_IMPLEMENTED;
637 break;
638 }
639 case IOCTL_SERIAL_SET_DTR:
640 {
641 /* FIXME: If the handshake flow control of the device is configured to
642 * automatically use DTR, return STATUS_INVALID_PARAMETER */
643 DPRINT("Serial: IOCTL_SERIAL_SET_DTR\n");
644 if (!(DeviceExtension->MCR & SR_MCR_DTR))
645 {
646 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
647 if (NT_SUCCESS(Status))
648 {
649 DeviceExtension->MCR |= SR_MCR_DTR;
650 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
651 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
652 }
653 }
654 else
655 Status = STATUS_SUCCESS;
656 break;
657 }
658 case IOCTL_SERIAL_SET_FIFO_CONTROL:
659 {
660 DPRINT("Serial: IOCTL_SERIAL_SET_FIFO_CONTROL\n");
661 if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
662 Status = STATUS_INVALID_PARAMETER;
663 else
664 {
665 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
666 if (NT_SUCCESS(Status))
667 {
668 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), (UCHAR)((*(PULONG)BufferIn) & 0xff));
669 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
670 }
671 }
672 break;
673 }
674 case IOCTL_SERIAL_SET_HANDFLOW:
675 {
676 /* FIXME */
677 DPRINT1("Serial: IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
678 Status = STATUS_NOT_IMPLEMENTED;
679 break;
680 }
681 case IOCTL_SERIAL_SET_LINE_CONTROL:
682 {
683 DPRINT("Serial: IOCTL_SERIAL_SET_LINE_CONTROL\n");
684 if (LengthIn < sizeof(SERIAL_LINE_CONTROL))
685 Status = STATUS_BUFFER_TOO_SMALL;
686 else if (BufferIn == NULL)
687 Status = STATUS_INVALID_PARAMETER;
688 else
689 Status = SerialSetLineControl(DeviceExtension, (PSERIAL_LINE_CONTROL)BufferIn);
690 break;
691 }
692 case IOCTL_SERIAL_SET_MODEM_CONTROL:
693 {
694 PULONG pMCR;
695 DPRINT("Serial: IOCTL_SERIAL_SET_MODEM_CONTROL\n");
696 if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
697 Status = STATUS_INVALID_PARAMETER;
698 else
699 {
700 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
701 if (NT_SUCCESS(Status))
702 {
703 pMCR = (PULONG)BufferIn;
704 DeviceExtension->MCR = (UCHAR)(*pMCR & 0xff);
705 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
706 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
707 }
708 }
709 break;
710 }
711 case IOCTL_SERIAL_SET_QUEUE_SIZE:
712 {
713 if (LengthIn < sizeof(SERIAL_QUEUE_SIZE ))
714 return STATUS_BUFFER_TOO_SMALL;
715 else if (BufferIn == NULL)
716 return STATUS_INVALID_PARAMETER;
717 else
718 {
719 KIRQL Irql;
720 PSERIAL_QUEUE_SIZE NewQueueSize = (PSERIAL_QUEUE_SIZE)BufferIn;
721 Status = STATUS_SUCCESS;
722 if (NewQueueSize->InSize > DeviceExtension->InputBuffer.Length)
723 {
724 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
725 Status = IncreaseCircularBufferSize(&DeviceExtension->InputBuffer, NewQueueSize->InSize);
726 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
727 }
728 if (NT_SUCCESS(Status) && NewQueueSize->OutSize > DeviceExtension->OutputBuffer.Length)
729 {
730 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
731 Status = IncreaseCircularBufferSize(&DeviceExtension->OutputBuffer, NewQueueSize->OutSize);
732 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
733 }
734 }
735 break;
736 }
737 case IOCTL_SERIAL_SET_RTS:
738 {
739 /* FIXME: If the handshake flow control of the device is configured to
740 * automatically use DTR, return STATUS_INVALID_PARAMETER */
741 DPRINT("Serial: IOCTL_SERIAL_SET_RTS\n");
742 if (!(DeviceExtension->MCR & SR_MCR_RTS))
743 {
744 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
745 if (NT_SUCCESS(Status))
746 {
747 DeviceExtension->MCR |= SR_MCR_RTS;
748 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
749 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
750 }
751 }
752 else
753 Status = STATUS_SUCCESS;
754 break;
755 }
756 case IOCTL_SERIAL_SET_TIMEOUTS:
757 {
758 DPRINT("Serial: IOCTL_SERIAL_SET_TIMEOUTS\n");
759 if (LengthIn != sizeof(SERIAL_TIMEOUTS) || BufferIn == NULL)
760 Status = STATUS_INVALID_PARAMETER;
761 else
762 {
763 DeviceExtension->SerialTimeOuts = *(PSERIAL_TIMEOUTS)BufferIn;
764 Status = STATUS_SUCCESS;
765 }
766 break;
767 }
768 case IOCTL_SERIAL_SET_WAIT_MASK:
769 {
770 PULONG pWaitMask;
771 DPRINT("Serial: IOCTL_SERIAL_SET_WAIT_MASK\n");
772 if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
773 Status = STATUS_INVALID_PARAMETER;
774 else
775 {
776 pWaitMask = (PULONG)BufferIn;
777 DeviceExtension->WaitMask = *pWaitMask;
778 Status = STATUS_SUCCESS;
779 }
780 break;
781 }
782 case IOCTL_SERIAL_SET_XOFF:
783 {
784 /* FIXME */
785 DPRINT1("Serial: IOCTL_SERIAL_SET_XOFF not implemented.\n");
786 Status = STATUS_NOT_IMPLEMENTED;
787 break;
788 }
789 case IOCTL_SERIAL_SET_XON:
790 {
791 /* FIXME */
792 DPRINT1("Serial: IOCTL_SERIAL_SET_XON not implemented.\n");
793 Status = STATUS_NOT_IMPLEMENTED;
794 break;
795 }
796 case IOCTL_SERIAL_WAIT_ON_MASK:
797 {
798 /* FIXME */
799 DPRINT1("Serial: IOCTL_SERIAL_WAIT_ON_MASK not implemented.\n");
800 Status = STATUS_NOT_IMPLEMENTED;
801 break;
802 }
803 case IOCTL_SERIAL_XOFF_COUNTER:
804 {
805 /* FIXME */
806 DPRINT1("Serial: IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
807 Status = STATUS_NOT_IMPLEMENTED;
808 break;
809 }
810 default:
811 {
812 /* Pass Irp to lower driver */
813 DPRINT("Serial: Unknown IOCTL code 0x%x\n", Stack->Parameters.DeviceIoControl.IoControlCode);
814 IoSkipCurrentIrpStackLocation(Irp);
815 return IoCallDriver(DeviceExtension->LowerDevice, Irp);
816 }
817 }
818
819 Irp->IoStatus.Information = Information;
820 Irp->IoStatus.Status = Status;
821 IoCompleteRequest(Irp, IO_NO_INCREMENT);
822 return Status;
823 }