ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

devctrl.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.