Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendevctrl.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: Serial port driver 00004 * FILE: drivers/dd/serial/devctrl.c 00005 * PURPOSE: Serial IRP_MJ_DEVICE_CONTROL operations 00006 * 00007 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) 00008 */ 00009 00010 #include "serial.h" 00011 00012 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003) 00013 00014 static VOID 00015 SerialGetUserBuffers( 00016 IN PIRP Irp, 00017 IN ULONG IoControlCode, 00018 OUT PVOID* BufferIn, 00019 OUT PVOID* BufferOut) 00020 { 00021 ASSERT(Irp); 00022 ASSERT(BufferIn); 00023 ASSERT(BufferOut); 00024 00025 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode)) 00026 { 00027 case METHOD_BUFFERED: 00028 *BufferIn = *BufferOut = Irp->AssociatedIrp.SystemBuffer; 00029 break; 00030 case METHOD_IN_DIRECT: 00031 case METHOD_OUT_DIRECT: 00032 *BufferIn = Irp->AssociatedIrp.SystemBuffer; 00033 *BufferOut = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 00034 break; 00035 case METHOD_NEITHER: 00036 *BufferIn = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.Type3InputBuffer; 00037 *BufferOut = Irp->UserBuffer; 00038 break; 00039 default: 00040 /* Should never happen */ 00041 *BufferIn = NULL; 00042 *BufferOut = NULL; 00043 break; 00044 } 00045 } 00046 00047 NTSTATUS NTAPI 00048 SerialSetBaudRate( 00049 IN PSERIAL_DEVICE_EXTENSION DeviceExtension, 00050 IN ULONG NewBaudRate) 00051 { 00052 ULONG BaudRate; 00053 USHORT divisor; 00054 PUCHAR ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); 00055 NTSTATUS Status = STATUS_SUCCESS; 00056 00057 if (NewBaudRate == 0) 00058 return STATUS_INVALID_PARAMETER; 00059 00060 divisor = (USHORT)(BAUD_CLOCK / (CLOCKS_PER_BIT * NewBaudRate)); 00061 BaudRate = BAUD_CLOCK / (CLOCKS_PER_BIT * divisor); 00062 00063 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00064 if (NT_SUCCESS(Status)) 00065 { 00066 UCHAR Lcr; 00067 TRACE_(SERIAL, "SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension->ComPort, BaudRate); 00068 /* Set Bit 7 of LCR to expose baud registers */ 00069 Lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase)); 00070 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr | SR_LCR_DLAB); 00071 /* Write the baud rate */ 00072 WRITE_PORT_UCHAR(SER_DLL(ComPortBase), divisor & 0xff); 00073 WRITE_PORT_UCHAR(SER_DLM(ComPortBase), divisor >> 8); 00074 /* Switch back to normal registers */ 00075 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr); 00076 00077 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00078 } 00079 00080 if (NT_SUCCESS(Status)) 00081 DeviceExtension->BaudRate = BaudRate; 00082 return Status; 00083 } 00084 00085 NTSTATUS NTAPI 00086 SerialSetLineControl( 00087 IN PSERIAL_DEVICE_EXTENSION DeviceExtension, 00088 IN PSERIAL_LINE_CONTROL NewSettings) 00089 { 00090 PUCHAR ComPortBase; 00091 UCHAR Lcr = 0; 00092 NTSTATUS Status; 00093 00094 ASSERT(DeviceExtension); 00095 ASSERT(NewSettings); 00096 00097 TRACE_(SERIAL, "SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n", 00098 DeviceExtension->ComPort, NewSettings->StopBits, NewSettings->Parity, NewSettings->WordLength); 00099 00100 /* Verify parameters */ 00101 switch (NewSettings->WordLength) 00102 { 00103 case 5: Lcr |= SR_LCR_CS5; break; 00104 case 6: Lcr |= SR_LCR_CS6; break; 00105 case 7: Lcr |= SR_LCR_CS7; break; 00106 case 8: Lcr |= SR_LCR_CS8; break; 00107 default: return STATUS_INVALID_PARAMETER; 00108 } 00109 00110 if (NewSettings->WordLength < 5 || NewSettings->WordLength > 8) 00111 return STATUS_INVALID_PARAMETER; 00112 00113 switch (NewSettings->Parity) 00114 { 00115 case NO_PARITY: Lcr |= SR_LCR_PNO; break; 00116 case ODD_PARITY: Lcr |= SR_LCR_POD; break; 00117 case EVEN_PARITY: Lcr |= SR_LCR_PEV; break; 00118 case MARK_PARITY: Lcr |= SR_LCR_PMK; break; 00119 case SPACE_PARITY: Lcr |= SR_LCR_PSP; break; 00120 default: return STATUS_INVALID_PARAMETER; 00121 } 00122 00123 switch (NewSettings->StopBits) 00124 { 00125 case STOP_BIT_1: 00126 Lcr |= SR_LCR_ST1; 00127 break; 00128 case STOP_BITS_1_5: 00129 if (NewSettings->WordLength != 5) 00130 return STATUS_INVALID_PARAMETER; 00131 Lcr |= SR_LCR_ST2; 00132 break; 00133 case STOP_BITS_2: 00134 if (NewSettings->WordLength < 6 || NewSettings->WordLength > 8) 00135 return STATUS_INVALID_PARAMETER; 00136 Lcr |= SR_LCR_ST2; 00137 break; 00138 default: 00139 return STATUS_INVALID_PARAMETER; 00140 } 00141 00142 /* Update current parameters */ 00143 ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); 00144 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00145 if (!NT_SUCCESS(Status)) 00146 return Status; 00147 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr); 00148 00149 /* Read junk out of RBR */ 00150 READ_PORT_UCHAR(SER_RBR(ComPortBase)); 00151 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00152 00153 if (NT_SUCCESS(Status)) 00154 DeviceExtension->SerialLineControl = *NewSettings; 00155 00156 return Status; 00157 } 00158 00159 static BOOLEAN 00160 SerialClearPerfStats( 00161 IN PSERIAL_DEVICE_EXTENSION DeviceExtension) 00162 { 00163 ASSERT(DeviceExtension); 00164 00165 RtlZeroMemory(&DeviceExtension->SerialPerfStats, sizeof(SERIALPERF_STATS)); 00166 DeviceExtension->BreakInterruptErrorCount = 0; 00167 return TRUE; 00168 } 00169 00170 static BOOLEAN 00171 SerialGetPerfStats(IN PIRP pIrp) 00172 { 00173 PSERIAL_DEVICE_EXTENSION pDeviceExtension; 00174 00175 ASSERT(pIrp); 00176 pDeviceExtension = (PSERIAL_DEVICE_EXTENSION) 00177 IoGetCurrentIrpStackLocation(pIrp)->DeviceObject->DeviceExtension; 00178 00179 /* 00180 * we assume buffer is big enough to hold SerialPerfStats structure 00181 * caller must verify this 00182 */ 00183 RtlCopyMemory( 00184 pIrp->AssociatedIrp.SystemBuffer, 00185 &pDeviceExtension->SerialPerfStats, 00186 sizeof(SERIALPERF_STATS) 00187 ); 00188 return TRUE; 00189 } 00190 00191 static NTSTATUS 00192 SerialGetCommProp( 00193 OUT PSERIAL_COMMPROP pCommProp, 00194 IN PSERIAL_DEVICE_EXTENSION DeviceExtension) 00195 { 00196 ASSERT(pCommProp); 00197 00198 RtlZeroMemory(pCommProp, sizeof(SERIAL_COMMPROP)); 00199 00200 if (!(pCommProp->ProvSpec1 & COMMPROP_INITIALIZED)) 00201 pCommProp->PacketLength = sizeof(SERIAL_COMMPROP); 00202 pCommProp->PacketVersion = 2; 00203 pCommProp->ServiceMask = SERIAL_SP_SERIALCOMM; 00204 pCommProp->MaxTxQueue = pCommProp->CurrentTxQueue = DeviceExtension->OutputBuffer.Length - 1; 00205 pCommProp->MaxRxQueue = pCommProp->CurrentRxQueue = DeviceExtension->InputBuffer.Length - 1; 00206 pCommProp->ProvSubType = PST_RS232; 00207 pCommProp->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_INTTIMEOUTS | SERIAL_PCF_PARITY_CHECK 00208 | SERIAL_PCF_RTSCTS | SERIAL_PCF_SETXCHAR | SERIAL_PCF_SPECIALCHARS | SERIAL_PCF_TOTALTIMEOUTS 00209 | SERIAL_PCF_XONXOFF; 00210 pCommProp->SettableParams = SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_HANDSHAKING 00211 | SERIAL_SP_PARITY | SERIAL_SP_PARITY_CHECK | SERIAL_SP_STOPBITS; 00212 00213 /* SettableBaud is related to Uart type */ 00214 pCommProp->SettableBaud = SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_134_5 00215 | SERIAL_BAUD_150 | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200 00216 | SERIAL_BAUD_1800 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 00217 | SERIAL_BAUD_9600 | SERIAL_BAUD_USER; 00218 pCommProp->MaxBaud = SERIAL_BAUD_USER; 00219 if (DeviceExtension->UartType >= Uart16450) 00220 { 00221 pCommProp->SettableBaud |= SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400; 00222 } 00223 if (DeviceExtension->UartType >= Uart16550) 00224 { 00225 pCommProp->SettableBaud |= SERIAL_BAUD_56K | SERIAL_BAUD_57600 | SERIAL_BAUD_115200 | SERIAL_BAUD_128K; 00226 } 00227 00228 pCommProp->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; 00229 pCommProp->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 00230 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; 00231 00232 pCommProp->ProvSpec2 = 0; /* Size of provider-specific data */ 00233 00234 return STATUS_SUCCESS; 00235 } 00236 00237 static NTSTATUS 00238 SerialGetCommStatus( 00239 OUT PSERIAL_STATUS pSerialStatus, 00240 IN PSERIAL_DEVICE_EXTENSION DeviceExtension) 00241 { 00242 KIRQL Irql; 00243 00244 ASSERT(pSerialStatus); 00245 RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS)); 00246 00247 pSerialStatus->Errors = 0; 00248 if (DeviceExtension->BreakInterruptErrorCount) 00249 pSerialStatus->Errors |= SERIAL_ERROR_BREAK; 00250 if (DeviceExtension->SerialPerfStats.FrameErrorCount) 00251 pSerialStatus->Errors |= SERIAL_ERROR_FRAMING; 00252 if (DeviceExtension->SerialPerfStats.SerialOverrunErrorCount) 00253 pSerialStatus->Errors |= SERIAL_ERROR_OVERRUN; 00254 if (DeviceExtension->SerialPerfStats.BufferOverrunErrorCount) 00255 pSerialStatus->Errors |= SERIAL_ERROR_QUEUEOVERRUN; 00256 if (DeviceExtension->SerialPerfStats.ParityErrorCount) 00257 pSerialStatus->Errors |= SERIAL_ERROR_PARITY; 00258 00259 pSerialStatus->HoldReasons = 0; /* FIXME */ 00260 00261 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); 00262 pSerialStatus->AmountInInQueue = (DeviceExtension->InputBuffer.WritePosition + DeviceExtension->InputBuffer.Length 00263 - DeviceExtension->InputBuffer.ReadPosition) % DeviceExtension->InputBuffer.Length; 00264 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); 00265 00266 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); 00267 pSerialStatus->AmountInOutQueue = (DeviceExtension->OutputBuffer.WritePosition + DeviceExtension->OutputBuffer.Length 00268 - DeviceExtension->OutputBuffer.ReadPosition) % DeviceExtension->OutputBuffer.Length; 00269 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); 00270 00271 pSerialStatus->EofReceived = FALSE; /* always FALSE */ 00272 pSerialStatus->WaitForImmediate = FALSE; /* always FALSE */ 00273 00274 return STATUS_SUCCESS; 00275 } 00276 00277 NTSTATUS NTAPI 00278 SerialDeviceControl( 00279 IN PDEVICE_OBJECT DeviceObject, 00280 IN PIRP Irp) 00281 { 00282 PIO_STACK_LOCATION Stack; 00283 ULONG IoControlCode; 00284 PSERIAL_DEVICE_EXTENSION DeviceExtension; 00285 ULONG LengthIn, LengthOut; 00286 ULONG_PTR Information = 0; 00287 PVOID BufferIn, BufferOut; 00288 PUCHAR ComPortBase; 00289 NTSTATUS Status; 00290 00291 TRACE_(SERIAL, "IRP_MJ_DEVICE_CONTROL dispatch\n"); 00292 00293 Stack = IoGetCurrentIrpStackLocation(Irp); 00294 LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength; 00295 LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength; 00296 DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00297 ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); 00298 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode; 00299 SerialGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut); 00300 00301 /* FIXME: need to probe buffers */ 00302 /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */ 00303 switch (IoControlCode) 00304 { 00305 case IOCTL_SERIAL_CLEAR_STATS: 00306 { 00307 TRACE_(SERIAL, "IOCTL_SERIAL_CLEAR_STATS\n"); 00308 KeSynchronizeExecution( 00309 DeviceExtension->Interrupt, 00310 (PKSYNCHRONIZE_ROUTINE)SerialClearPerfStats, 00311 DeviceExtension); 00312 Status = STATUS_SUCCESS; 00313 break; 00314 } 00315 case IOCTL_SERIAL_CLR_DTR: 00316 { 00317 TRACE_(SERIAL, "IOCTL_SERIAL_CLR_DTR\n"); 00318 /* FIXME: If the handshake flow control of the device is configured to 00319 * automatically use DTR, return STATUS_INVALID_PARAMETER */ 00320 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00321 if (NT_SUCCESS(Status)) 00322 { 00323 DeviceExtension->MCR &= ~SR_MCR_DTR; 00324 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); 00325 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00326 } 00327 break; 00328 } 00329 case IOCTL_SERIAL_CLR_RTS: 00330 { 00331 TRACE_(SERIAL, "IOCTL_SERIAL_CLR_RTS\n"); 00332 /* FIXME: If the handshake flow control of the device is configured to 00333 * automatically use RTS, return STATUS_INVALID_PARAMETER */ 00334 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00335 if (NT_SUCCESS(Status)) 00336 { 00337 DeviceExtension->MCR &= ~SR_MCR_RTS; 00338 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); 00339 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00340 } 00341 break; 00342 } 00343 case IOCTL_SERIAL_CONFIG_SIZE: 00344 { 00345 /* Obsolete on Microsoft Windows 2000+ */ 00346 PULONG pConfigSize; 00347 TRACE_(SERIAL, "IOCTL_SERIAL_CONFIG_SIZE\n"); 00348 if (LengthOut != sizeof(ULONG) || BufferOut == NULL) 00349 Status = STATUS_INVALID_PARAMETER; 00350 else 00351 { 00352 pConfigSize = (PULONG)BufferOut; 00353 *pConfigSize = 0; 00354 Information = sizeof(ULONG); 00355 Status = STATUS_SUCCESS; 00356 } 00357 break; 00358 } 00359 case IOCTL_SERIAL_GET_BAUD_RATE: 00360 { 00361 TRACE_(SERIAL, "IOCTL_SERIAL_GET_BAUD_RATE\n"); 00362 if (LengthOut < sizeof(SERIAL_BAUD_RATE)) 00363 Status = STATUS_BUFFER_TOO_SMALL; 00364 else if (BufferOut == NULL) 00365 Status = STATUS_INVALID_PARAMETER; 00366 else 00367 { 00368 ((PSERIAL_BAUD_RATE)BufferOut)->BaudRate = DeviceExtension->BaudRate; 00369 Information = sizeof(SERIAL_BAUD_RATE); 00370 Status = STATUS_SUCCESS; 00371 } 00372 break; 00373 } 00374 case IOCTL_SERIAL_GET_CHARS: 00375 { 00376 /* FIXME */ 00377 PSERIAL_CHARS pSerialChars; 00378 ERR_(SERIAL, "IOCTL_SERIAL_GET_CHARS not implemented.\n"); 00379 if (LengthOut < sizeof(SERIAL_CHARS)) 00380 Status = STATUS_BUFFER_TOO_SMALL; 00381 else if (BufferOut == NULL) 00382 Status = STATUS_INVALID_PARAMETER; 00383 else 00384 { 00385 pSerialChars = (PSERIAL_CHARS)BufferOut; 00386 pSerialChars->EofChar = 0; 00387 pSerialChars->ErrorChar = 0; 00388 pSerialChars->BreakChar = 0; 00389 pSerialChars->EventChar = 0; 00390 pSerialChars->XonChar = 0; 00391 pSerialChars->XoffChar = 0; 00392 Information = sizeof(SERIAL_CHARS); 00393 Status = STATUS_SUCCESS; 00394 } 00395 break; 00396 } 00397 case IOCTL_SERIAL_GET_COMMSTATUS: 00398 { 00399 TRACE_(SERIAL, "IOCTL_SERIAL_GET_COMMSTATUS\n"); 00400 if (LengthOut < sizeof(SERIAL_STATUS)) 00401 Status = STATUS_BUFFER_TOO_SMALL; 00402 else if (BufferOut == NULL) 00403 Status = STATUS_INVALID_PARAMETER; 00404 else 00405 { 00406 Status = SerialGetCommStatus((PSERIAL_STATUS)BufferOut, DeviceExtension); 00407 Information = sizeof(SERIAL_STATUS); 00408 } 00409 break; 00410 } 00411 case IOCTL_SERIAL_GET_DTRRTS: 00412 { 00413 PULONG pDtrRts; 00414 TRACE_(SERIAL, "IOCTL_SERIAL_GET_DTRRTS\n"); 00415 if (LengthOut != sizeof(ULONG) || BufferOut == NULL) 00416 Status = STATUS_INVALID_PARAMETER; 00417 else 00418 { 00419 pDtrRts = (PULONG)BufferOut; 00420 *pDtrRts = 0; 00421 if (DeviceExtension->MCR & SR_MCR_DTR) 00422 *pDtrRts |= SERIAL_DTR_STATE; 00423 if (DeviceExtension->MCR & SR_MCR_RTS) 00424 *pDtrRts |= SERIAL_RTS_STATE; 00425 Information = sizeof(ULONG); 00426 Status = STATUS_SUCCESS; 00427 } 00428 break; 00429 } 00430 case IOCTL_SERIAL_GET_HANDFLOW: 00431 { 00432 /* FIXME */ 00433 PSERIAL_HANDFLOW pSerialHandflow; 00434 ERR_(SERIAL, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n"); 00435 if (LengthOut < sizeof(SERIAL_HANDFLOW)) 00436 Status = STATUS_BUFFER_TOO_SMALL; 00437 else if (BufferOut == NULL) 00438 Status = STATUS_INVALID_PARAMETER; 00439 else 00440 { 00441 pSerialHandflow = (PSERIAL_HANDFLOW)BufferOut; 00442 pSerialHandflow->ControlHandShake = 0; 00443 pSerialHandflow->FlowReplace = 0; 00444 pSerialHandflow->XonLimit = 0; 00445 pSerialHandflow->XoffLimit = 0; 00446 Information = sizeof(SERIAL_HANDFLOW); 00447 Status = STATUS_SUCCESS; 00448 } 00449 break; 00450 } 00451 case IOCTL_SERIAL_GET_LINE_CONTROL: 00452 { 00453 TRACE_(SERIAL, "IOCTL_SERIAL_GET_LINE_CONTROL\n"); 00454 if (LengthOut < sizeof(SERIAL_LINE_CONTROL)) 00455 Status = STATUS_BUFFER_TOO_SMALL; 00456 else if (BufferOut == NULL) 00457 Status = STATUS_INVALID_PARAMETER; 00458 else 00459 { 00460 *((PSERIAL_LINE_CONTROL)BufferOut) = DeviceExtension->SerialLineControl; 00461 Information = sizeof(SERIAL_LINE_CONTROL); 00462 Status = STATUS_SUCCESS; 00463 } 00464 break; 00465 } 00466 case IOCTL_SERIAL_GET_MODEM_CONTROL: 00467 { 00468 PULONG pMCR; 00469 TRACE_(SERIAL, "IOCTL_SERIAL_GET_MODEM_CONTROL\n"); 00470 if (LengthOut != sizeof(ULONG) || BufferOut == NULL) 00471 Status = STATUS_INVALID_PARAMETER; 00472 else 00473 { 00474 pMCR = (PULONG)BufferOut; 00475 *pMCR = DeviceExtension->MCR; 00476 Information = sizeof(ULONG); 00477 Status = STATUS_SUCCESS; 00478 } 00479 break; 00480 } 00481 case IOCTL_SERIAL_GET_MODEMSTATUS: 00482 { 00483 PULONG pMSR; 00484 TRACE_(SERIAL, "IOCTL_SERIAL_GET_MODEMSTATUS\n"); 00485 if (LengthOut != sizeof(ULONG) || BufferOut == NULL) 00486 Status = STATUS_INVALID_PARAMETER; 00487 else 00488 { 00489 pMSR = (PULONG)BufferOut; 00490 *pMSR = DeviceExtension->MSR; 00491 Information = sizeof(ULONG); 00492 Status = STATUS_SUCCESS; 00493 } 00494 break; 00495 } 00496 case IOCTL_SERIAL_GET_PROPERTIES: 00497 { 00498 TRACE_(SERIAL, "IOCTL_SERIAL_GET_PROPERTIES\n"); 00499 if (LengthOut < sizeof(SERIAL_COMMPROP)) 00500 Status = STATUS_BUFFER_TOO_SMALL; 00501 else if (BufferOut == NULL) 00502 Status = STATUS_INVALID_PARAMETER; 00503 else 00504 { 00505 Status = SerialGetCommProp((PSERIAL_COMMPROP)BufferOut, DeviceExtension); 00506 Information = sizeof(SERIAL_COMMPROP); 00507 } 00508 break; 00509 } 00510 case IOCTL_SERIAL_GET_STATS: 00511 { 00512 TRACE_(SERIAL, "IOCTL_SERIAL_GET_STATS\n"); 00513 if (LengthOut < sizeof(SERIALPERF_STATS)) 00514 Status = STATUS_BUFFER_TOO_SMALL; 00515 else if (BufferOut == NULL) 00516 Status = STATUS_INVALID_PARAMETER; 00517 else 00518 { 00519 KeSynchronizeExecution(DeviceExtension->Interrupt, 00520 (PKSYNCHRONIZE_ROUTINE)SerialGetPerfStats, Irp); 00521 Information = sizeof(SERIALPERF_STATS); 00522 Status = STATUS_SUCCESS; 00523 } 00524 break; 00525 } 00526 case IOCTL_SERIAL_GET_TIMEOUTS: 00527 { 00528 TRACE_(SERIAL, "IOCTL_SERIAL_GET_TIMEOUTS\n"); 00529 if (LengthOut != sizeof(SERIAL_TIMEOUTS) || BufferOut == NULL) 00530 Status = STATUS_INVALID_PARAMETER; 00531 else 00532 { 00533 *(PSERIAL_TIMEOUTS)BufferOut = DeviceExtension->SerialTimeOuts; 00534 Information = sizeof(SERIAL_TIMEOUTS); 00535 Status = STATUS_SUCCESS; 00536 } 00537 break; 00538 } 00539 case IOCTL_SERIAL_GET_WAIT_MASK: 00540 { 00541 PULONG pWaitMask; 00542 TRACE_(SERIAL, "IOCTL_SERIAL_GET_WAIT_MASK\n"); 00543 if (LengthOut != sizeof(ULONG) || BufferOut == NULL) 00544 Status = STATUS_INVALID_PARAMETER; 00545 else 00546 { 00547 pWaitMask = (PULONG)BufferOut; 00548 *pWaitMask = DeviceExtension->WaitMask; 00549 Information = sizeof(ULONG); 00550 Status = STATUS_SUCCESS; 00551 } 00552 break; 00553 } 00554 case IOCTL_SERIAL_IMMEDIATE_CHAR: 00555 { 00556 /* FIXME */ 00557 ERR_(SERIAL, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n"); 00558 Status = STATUS_NOT_IMPLEMENTED; 00559 break; 00560 } 00561 case IOCTL_SERIAL_LSRMST_INSERT: 00562 { 00563 /* FIXME */ 00564 ERR_(SERIAL, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n"); 00565 Status = STATUS_NOT_IMPLEMENTED; 00566 break; 00567 } 00568 case IOCTL_SERIAL_PURGE: 00569 { 00570 KIRQL Irql; 00571 TRACE_(SERIAL, "IOCTL_SERIAL_PURGE\n"); 00572 /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT 00573 * should stop current request */ 00574 if (LengthIn != sizeof(ULONG) || BufferIn == NULL) 00575 Status = STATUS_INVALID_PARAMETER; 00576 else 00577 { 00578 ULONG PurgeMask = *(PULONG)BufferIn; 00579 00580 Status = STATUS_SUCCESS; 00581 /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */ 00582 if (PurgeMask & SERIAL_PURGE_RXCLEAR) 00583 { 00584 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); 00585 DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0; 00586 if (DeviceExtension->UartType >= Uart16550A) 00587 { 00588 /* Clear also Uart FIFO */ 00589 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00590 if (NT_SUCCESS(Status)) 00591 { 00592 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR); 00593 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00594 } 00595 } 00596 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); 00597 } 00598 00599 if (PurgeMask & SERIAL_PURGE_TXCLEAR) 00600 { 00601 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); 00602 DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0; 00603 if (DeviceExtension->UartType >= Uart16550A) 00604 { 00605 /* Clear also Uart FIFO */ 00606 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00607 if (NT_SUCCESS(Status)) 00608 { 00609 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_XMIT); 00610 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00611 } 00612 } 00613 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); 00614 } 00615 } 00616 break; 00617 } 00618 case IOCTL_SERIAL_RESET_DEVICE: 00619 { 00620 /* FIXME */ 00621 ERR_(SERIAL, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n"); 00622 Status = STATUS_NOT_IMPLEMENTED; 00623 break; 00624 } 00625 case IOCTL_SERIAL_SET_BAUD_RATE: 00626 { 00627 PULONG pNewBaudRate; 00628 TRACE_(SERIAL, "IOCTL_SERIAL_SET_BAUD_RATE\n"); 00629 if (LengthIn != sizeof(ULONG) || BufferIn == NULL) 00630 Status = STATUS_INVALID_PARAMETER; 00631 else 00632 { 00633 pNewBaudRate = (PULONG)BufferIn; 00634 Status = SerialSetBaudRate(DeviceExtension, *pNewBaudRate); 00635 } 00636 break; 00637 } 00638 case IOCTL_SERIAL_SET_BREAK_OFF: 00639 { 00640 /* FIXME */ 00641 ERR_(SERIAL, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n"); 00642 Status = STATUS_NOT_IMPLEMENTED; 00643 break; 00644 } 00645 case IOCTL_SERIAL_SET_BREAK_ON: 00646 { 00647 /* FIXME */ 00648 ERR_(SERIAL, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n"); 00649 Status = STATUS_NOT_IMPLEMENTED; 00650 break; 00651 } 00652 case IOCTL_SERIAL_SET_CHARS: 00653 { 00654 /* FIXME */ 00655 ERR_(SERIAL, "IOCTL_SERIAL_SET_CHARS not implemented.\n"); 00656 Status = STATUS_SUCCESS; 00657 break; 00658 } 00659 case IOCTL_SERIAL_SET_DTR: 00660 { 00661 /* FIXME: If the handshake flow control of the device is configured to 00662 * automatically use DTR, return STATUS_INVALID_PARAMETER */ 00663 TRACE_(SERIAL, "IOCTL_SERIAL_SET_DTR\n"); 00664 if (!(DeviceExtension->MCR & SR_MCR_DTR)) 00665 { 00666 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00667 if (NT_SUCCESS(Status)) 00668 { 00669 DeviceExtension->MCR |= SR_MCR_DTR; 00670 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); 00671 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00672 } 00673 } 00674 else 00675 Status = STATUS_SUCCESS; 00676 break; 00677 } 00678 case IOCTL_SERIAL_SET_FIFO_CONTROL: 00679 { 00680 TRACE_(SERIAL, "IOCTL_SERIAL_SET_FIFO_CONTROL\n"); 00681 if (LengthIn != sizeof(ULONG) || BufferIn == NULL) 00682 Status = STATUS_INVALID_PARAMETER; 00683 else 00684 { 00685 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00686 if (NT_SUCCESS(Status)) 00687 { 00688 WRITE_PORT_UCHAR(SER_FCR(ComPortBase), (UCHAR)((*(PULONG)BufferIn) & 0xff)); 00689 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00690 } 00691 } 00692 break; 00693 } 00694 case IOCTL_SERIAL_SET_HANDFLOW: 00695 { 00696 /* FIXME */ 00697 ERR_(SERIAL, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n"); 00698 Status = STATUS_SUCCESS; 00699 break; 00700 } 00701 case IOCTL_SERIAL_SET_LINE_CONTROL: 00702 { 00703 TRACE_(SERIAL, "IOCTL_SERIAL_SET_LINE_CONTROL\n"); 00704 if (LengthIn < sizeof(SERIAL_LINE_CONTROL)) 00705 Status = STATUS_BUFFER_TOO_SMALL; 00706 else if (BufferIn == NULL) 00707 Status = STATUS_INVALID_PARAMETER; 00708 else 00709 Status = SerialSetLineControl(DeviceExtension, (PSERIAL_LINE_CONTROL)BufferIn); 00710 break; 00711 } 00712 case IOCTL_SERIAL_SET_MODEM_CONTROL: 00713 { 00714 PULONG pMCR; 00715 TRACE_(SERIAL, "IOCTL_SERIAL_SET_MODEM_CONTROL\n"); 00716 if (LengthIn != sizeof(ULONG) || BufferIn == NULL) 00717 Status = STATUS_INVALID_PARAMETER; 00718 else 00719 { 00720 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00721 if (NT_SUCCESS(Status)) 00722 { 00723 pMCR = (PULONG)BufferIn; 00724 DeviceExtension->MCR = (UCHAR)(*pMCR & 0xff); 00725 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); 00726 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00727 } 00728 } 00729 break; 00730 } 00731 case IOCTL_SERIAL_SET_QUEUE_SIZE: 00732 { 00733 if (LengthIn < sizeof(SERIAL_QUEUE_SIZE )) 00734 return STATUS_BUFFER_TOO_SMALL; 00735 else if (BufferIn == NULL) 00736 return STATUS_INVALID_PARAMETER; 00737 else 00738 { 00739 KIRQL Irql; 00740 PSERIAL_QUEUE_SIZE NewQueueSize = (PSERIAL_QUEUE_SIZE)BufferIn; 00741 Status = STATUS_SUCCESS; 00742 if (NewQueueSize->InSize > DeviceExtension->InputBuffer.Length) 00743 { 00744 KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); 00745 Status = IncreaseCircularBufferSize(&DeviceExtension->InputBuffer, NewQueueSize->InSize); 00746 KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); 00747 } 00748 if (NT_SUCCESS(Status) && NewQueueSize->OutSize > DeviceExtension->OutputBuffer.Length) 00749 { 00750 KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); 00751 Status = IncreaseCircularBufferSize(&DeviceExtension->OutputBuffer, NewQueueSize->OutSize); 00752 KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); 00753 } 00754 } 00755 break; 00756 } 00757 case IOCTL_SERIAL_SET_RTS: 00758 { 00759 /* FIXME: If the handshake flow control of the device is configured to 00760 * automatically use DTR, return STATUS_INVALID_PARAMETER */ 00761 TRACE_(SERIAL, "IOCTL_SERIAL_SET_RTS\n"); 00762 if (!(DeviceExtension->MCR & SR_MCR_RTS)) 00763 { 00764 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00765 if (NT_SUCCESS(Status)) 00766 { 00767 DeviceExtension->MCR |= SR_MCR_RTS; 00768 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); 00769 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); 00770 } 00771 } 00772 else 00773 Status = STATUS_SUCCESS; 00774 break; 00775 } 00776 case IOCTL_SERIAL_SET_TIMEOUTS: 00777 { 00778 TRACE_(SERIAL, "IOCTL_SERIAL_SET_TIMEOUTS\n"); 00779 if (LengthIn != sizeof(SERIAL_TIMEOUTS) || BufferIn == NULL) 00780 Status = STATUS_INVALID_PARAMETER; 00781 else 00782 { 00783 DeviceExtension->SerialTimeOuts = *(PSERIAL_TIMEOUTS)BufferIn; 00784 Status = STATUS_SUCCESS; 00785 } 00786 break; 00787 } 00788 case IOCTL_SERIAL_SET_WAIT_MASK: 00789 { 00790 PULONG pWaitMask = (PULONG)BufferIn; 00791 TRACE_(SERIAL, "IOCTL_SERIAL_SET_WAIT_MASK\n"); 00792 00793 if (LengthIn != sizeof(ULONG) || BufferIn == NULL) 00794 Status = STATUS_INVALID_PARAMETER; 00795 else if (DeviceExtension->WaitOnMaskIrp) /* FIXME: Race condition ; field may be currently in modification */ 00796 { 00797 WARN_(SERIAL, "An IRP is already currently processed\n"); 00798 Status = STATUS_INVALID_PARAMETER; 00799 } 00800 else 00801 { 00802 DeviceExtension->WaitMask = *pWaitMask; 00803 Status = STATUS_SUCCESS; 00804 } 00805 break; 00806 } 00807 case IOCTL_SERIAL_SET_XOFF: 00808 { 00809 /* FIXME */ 00810 ERR_(SERIAL, "IOCTL_SERIAL_SET_XOFF not implemented.\n"); 00811 Status = STATUS_NOT_IMPLEMENTED; 00812 break; 00813 } 00814 case IOCTL_SERIAL_SET_XON: 00815 { 00816 /* FIXME */ 00817 ERR_(SERIAL, "IOCTL_SERIAL_SET_XON not implemented.\n"); 00818 Status = STATUS_NOT_IMPLEMENTED; 00819 break; 00820 } 00821 case IOCTL_SERIAL_WAIT_ON_MASK: 00822 { 00823 PIRP WaitingIrp; 00824 TRACE_(SERIAL, "IOCTL_SERIAL_WAIT_ON_MASK\n"); 00825 00826 if (LengthOut != sizeof(ULONG) || BufferOut == NULL) 00827 Status = STATUS_INVALID_PARAMETER; 00828 else 00829 { 00830 /* FIXME: Race condition here: 00831 * If an interrupt comes before we can mark the Irp 00832 * as pending, it might be possible to complete the 00833 * Irp before pending it, leading to a crash! */ 00834 WaitingIrp = InterlockedCompareExchangePointer( 00835 (PVOID)&DeviceExtension->WaitOnMaskIrp, 00836 Irp, 00837 NULL); 00838 00839 /* Check if an Irp is already pending */ 00840 if (WaitingIrp != NULL) 00841 { 00842 /* Unable to have a 2nd pending IRP for this IOCTL */ 00843 WARN_(SERIAL, "Unable to pend a second IRP for IOCTL_SERIAL_WAIT_ON_MASK\n"); 00844 Status = STATUS_INVALID_PARAMETER; 00845 } 00846 else 00847 { 00848 Status = STATUS_PENDING; 00849 /* FIXME: immediately return if a wait event already occurred */ 00850 } 00851 } 00852 break; 00853 } 00854 case IOCTL_SERIAL_XOFF_COUNTER: 00855 { 00856 /* FIXME */ 00857 ERR_(SERIAL, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n"); 00858 Status = STATUS_NOT_IMPLEMENTED; 00859 break; 00860 } 00861 default: 00862 { 00863 /* Pass Irp to lower driver */ 00864 TRACE_(SERIAL, "Unknown IOCTL code 0x%x\n", Stack->Parameters.DeviceIoControl.IoControlCode); 00865 IoSkipCurrentIrpStackLocation(Irp); 00866 return IoCallDriver(DeviceExtension->LowerDevice, Irp); 00867 } 00868 } 00869 00870 Irp->IoStatus.Status = Status; 00871 if (Status == STATUS_PENDING) 00872 { 00873 IoMarkIrpPending(Irp); 00874 } 00875 else 00876 { 00877 Irp->IoStatus.Information = Information; 00878 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00879 } 00880 return Status; 00881 } Generated on Sat May 26 2012 04:26:04 for ReactOS by
1.7.6.1
|