VOID sndStopDMA( IN PGLOBAL_DEVICE_INFO pGDI ) /*++ Routine Description: Stop the DMA at once by disabling the hardware Free the adapter channel. (Opposite of sndStartDMA). Arguments: pGDI - pointer to global device info Return Value: None --*/ { // // Pass HALT DMA to the MIPSSND // if (pGDI->DMABusy) { KeSynchronizeExecution(pGDI->pInterrupt, StopDMA, pGDI); // // Flush our buffers // sndFlush(pGDI, 0); sndFlush(pGDI, 1); // // Stop the DMA controller // if (pGDI->Usage == SoundInterruptUsageWaveIn) { IoFreeAdapterChannel(pGDI->pAdapterObject[2]); IoFreeAdapterChannel(pGDI->pAdapterObject[3]); } else { IoFreeAdapterChannel(pGDI->pAdapterObject[0]); IoFreeAdapterChannel(pGDI->pAdapterObject[1]); } } dprintf4(" dma_stopped"); // // Note our new state // pGDI->DMABusy = FALSE; }
/////////////////////////////////////////////////////////////////////////////// // // OsrAdapterControlWrite // // This is routine is called by the I/O Manager when the Adapter resources // (such as map registers) requested by the OsrStartWriteIrp function are // available for our use. // // INPUTS: // // DeviceObject - Address of the DEVICE_OBJECT for our device. // // MapRegisterBase - Base address of the Map registers that have been // reserved by the I/O Manager and HAL for our use. // // Context - address of the Write Irp for the operation to be started on the // device. // // OUTPUTS: // // None. // // RETURNS: // // DeallocateObjectKeepRegisters - indicates that the map registers that // were allocated to us should not be deallocated at this time. // We will deallocate them with the Read operation completes. // // IRQL: // // This routine is called at IRQL_DISPATCH_LEVEL. // // NOTES: // /////////////////////////////////////////////////////////////////////////////// IO_ALLOCATION_ACTION OsrAdapterControlWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP NotUsed, IN PVOID MapRegisterBase, IN PVOID Context) { PIRP irp = (PIRP) Context; PIO_STACK_LOCATION ioStack; POSR_DEVICE_EXT devExt; PUCHAR baseVa; #if DBG DbgPrint("AdapterControlWrite: Irp = 0x%0x\n", irp); #endif devExt = DeviceObject->DeviceExtension; ioStack = IoGetCurrentIrpStackLocation(irp); devExt->WriteLength = ioStack->Parameters.Write.Length - devExt->WriteSoFar; #if DBG DbgPrint("AdapterControlWrite: Length remaining = %d. \n", devExt->WriteLength); #endif // // Get set-up for the transfer // devExt->WriteMapRegBase = MapRegisterBase; baseVa = MmGetMdlVirtualAddress(irp->MdlAddress); devExt->WriteStartingOffset = devExt->WriteSoFar; // // Get the base address and length of the segment to write. // devExt->WritePaToDevice = IoMapTransfer(devExt->WriteAdapter, irp->MdlAddress, MapRegisterBase, baseVa+(devExt->WriteSoFar), &devExt->WriteLength, TRUE); // WriteToDevice // // Update the length transfered so far // devExt->WriteSoFar += devExt->WriteLength; // // Put the request on the device // (VOID)KeSynchronizeExecution(devExt->InterruptObject, OsrStartWriteOnDevice, DeviceObject); return(DeallocateObjectKeepRegisters); }
VOID SerialInvokePerhapsLowerRTS( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) /*++ Routine Description: This dpc routine exists solely to call the code that tests if the rts line should be lowered when TRANSMIT TOGGLE flow control is being used. Arguments: Dpc - Not Used. DeferredContext - Really points to the device extension. SystemContext1 - Not Used. SystemContext2 - Not Used. Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemContext1); UNREFERENCED_PARAMETER(SystemContext2); KeSynchronizeExecution( Extension->Interrupt, SerialPerhapsLowerRTS, Extension ); }
NTSTATUS SerialIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine provides the initial processing for all of the Ioctrls for the serial device. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call --*/ { // // The status that gets returned to the caller and // set in the Irp. // NTSTATUS Status; // // The current stack location. This contains all of the // information we need to process this particular request. // PIO_STACK_LOCATION IrpSp; // // Just what it says. This is the serial specific device // extension of the device object create for the serial driver. // PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; // // A temporary to hold the old IRQL so that it can be // restored once we complete/validate this request. // KIRQL OldIrql; SerialDump( SERIRPPATH, ("SERIAL: Dispatch entry for: %x\n",Irp) ); if (SerialCompleteIfError( DeviceObject, Irp ) != STATUS_SUCCESS) { return STATUS_CANCELLED; } IrpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Information = 0L; Status = STATUS_SUCCESS; switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SERIAL_SET_BAUD_RATE : { ULONG BaudRate; // // Will hold the value of the appropriate divisor for // the requested baud rate. If the baudrate is invalid // (because the device won't support that baud rate) then // this value is undefined. // // Note: in one sense the concept of a valid baud rate // is cloudy. We could allow the user to request any // baud rate. We could then calculate the divisor needed // for that baud rate. As long as the divisor wasn't less // than one we would be "ok". (The percentage difference // between the "true" divisor and the "rounded" value given // to the hardware might make it unusable, but... ) It would // really be up to the user to "Know" whether the baud rate // is suitable. So much for theory, *We* only support a given // set of baud rates. // SHORT AppropriateDivisor; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) { Status = STATUS_BUFFER_TOO_SMALL; break; } else { BaudRate = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate; } // // Get the baud rate from the irp. We pass it // to a routine which will set the correct divisor. // Status = SerialGetDivisorFromBaud( Extension->ClockRate, BaudRate, &AppropriateDivisor ); KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if (NT_SUCCESS(Status)) { SERIAL_IOCTL_SYNC S; Extension->CurrentBaud = BaudRate; S.Extension = Extension; S.Data = (PVOID)AppropriateDivisor; KeSynchronizeExecution( Extension->Interrupt, SerialSetBaud, &S ); } KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_BAUD_RATE: { PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); Br->BaudRate = Extension->CurrentBaud; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE); break; } case IOCTL_SERIAL_SET_LINE_CONTROL: { // // Points to the line control record in the Irp. // PSERIAL_LINE_CONTROL Lc = ((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer)); UCHAR LData; UCHAR LStop; UCHAR LParity; UCHAR Mask = 0xff; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { Status = STATUS_BUFFER_TOO_SMALL; break; } switch (Lc->WordLength) { case 5: { LData = SERIAL_5_DATA; Mask = 0x1f; break; } case 6: { LData = SERIAL_6_DATA; Mask = 0x3f; break; } case 7: { LData = SERIAL_7_DATA; Mask = 0x7f; break; } case 8: { LData = SERIAL_8_DATA; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } } switch (Lc->Parity) { case NO_PARITY: { LParity = SERIAL_NONE_PARITY; break; } case EVEN_PARITY: { LParity = SERIAL_EVEN_PARITY; break; } case ODD_PARITY: { LParity = SERIAL_ODD_PARITY; break; } case SPACE_PARITY: { LParity = SERIAL_SPACE_PARITY; break; } case MARK_PARITY: { LParity = SERIAL_MARK_PARITY; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; break; } } switch (Lc->StopBits) { case STOP_BIT_1: { LStop = SERIAL_1_STOP; break; } case STOP_BITS_1_5: { if (LData != SERIAL_5_DATA) { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } LStop = SERIAL_1_5_STOP; break; } case STOP_BITS_2: { if (LData == SERIAL_5_DATA) { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } LStop = SERIAL_2_STOP; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); Extension->LineControl = (UCHAR)((Extension->LineControl & SERIAL_LCR_BREAK) | (LData | LParity | LStop)); Extension->ValidDataMask = Mask; KeSynchronizeExecution( Extension->Interrupt, SerialSetLineControl, Extension ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) { Lc->WordLength = 5; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_6_DATA) { Lc->WordLength = 6; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_7_DATA) { Lc->WordLength = 7; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_8_DATA) { Lc->WordLength = 8; } if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY) { Lc->Parity = NO_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_ODD_PARITY) { Lc->Parity = ODD_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_EVEN_PARITY) { Lc->Parity = EVEN_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_MARK_PARITY) { Lc->Parity = MARK_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_SPACE_PARITY) { Lc->Parity = SPACE_PARITY; } if (Extension->LineControl & SERIAL_2_STOP) { if (Lc->WordLength == 5) { Lc->StopBits = STOP_BITS_1_5; } else { Lc->StopBits = STOP_BITS_2; } } else { Lc->StopBits = STOP_BIT_1; } Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_TIMEOUTS: { PSERIAL_TIMEOUTS NewTimeouts = ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer)); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) && (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) { Status = STATUS_INVALID_PARAMETER; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); Extension->Timeouts.ReadIntervalTimeout = NewTimeouts->ReadIntervalTimeout; Extension->Timeouts.ReadTotalTimeoutMultiplier = NewTimeouts->ReadTotalTimeoutMultiplier; Extension->Timeouts.ReadTotalTimeoutConstant = NewTimeouts->ReadTotalTimeoutConstant; Extension->Timeouts.WriteTotalTimeoutMultiplier = NewTimeouts->WriteTotalTimeoutMultiplier; Extension->Timeouts.WriteTotalTimeoutConstant = NewTimeouts->WriteTotalTimeoutConstant; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_TIMEOUTS: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); *((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = Extension->Timeouts; Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_CHARS: { SERIAL_IOCTL_SYNC S; PSERIAL_CHARS NewChars = ((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer)); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // The only thing that can be wrong with the chars // is that the xon and xoff characters are the // same. // #if 0 if (NewChars->XonChar == NewChars->XoffChar) { Status = STATUS_INVALID_PARAMETER; break; } #endif // // We acquire the control lock so that only // one request can GET or SET the characters // at a time. The sets could be synchronized // by the interrupt spinlock, but that wouldn't // prevent multiple gets at the same time. // S.Extension = Extension; S.Data = NewChars; KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); // // Under the protection of the lock, make sure that // the xon and xoff characters aren't the same as // the escape character. // if (Extension->EscapeChar) { if ((Extension->EscapeChar == NewChars->XonChar) || (Extension->EscapeChar == NewChars->XoffChar)) { Status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } } KeSynchronizeExecution( Extension->Interrupt, SerialSetChars, &S ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_CHARS: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); *((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer) = Extension->SpecialChars; Irp->IoStatus.Information = sizeof(SERIAL_CHARS); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_DTR: case IOCTL_SERIAL_CLR_DTR: { // // We acquire the lock so that we can check whether // automatic dtr flow control is enabled. If it is // then we return an error since the app is not allowed // to touch this if it is automatic. // KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } else { KeSynchronizeExecution( Extension->Interrupt, ((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR)? (SerialSetDTR):(SerialClrDTR)), Extension ); } KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_RESET_DEVICE: { break; } case IOCTL_SERIAL_SET_RTS: case IOCTL_SERIAL_CLR_RTS: { // // We acquire the lock so that we can check whether // automatic rts flow control or transmit toggleing // is enabled. If it is then we return an error since // the app is not allowed to touch this if it is automatic // or toggling. // KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if (((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) || ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } else { KeSynchronizeExecution( Extension->Interrupt, ((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_RTS)? (SerialSetRTS):(SerialClrRTS)), Extension ); } KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_XOFF: { KeSynchronizeExecution( Extension->Interrupt, SerialPretendXoff, Extension ); break; } case IOCTL_SERIAL_SET_XON: { KeSynchronizeExecution( Extension->Interrupt, SerialPretendXon, Extension ); break; } case IOCTL_SERIAL_SET_BREAK_ON: { KeSynchronizeExecution( Extension->Interrupt, SerialTurnOnBreak, Extension ); break; } case IOCTL_SERIAL_SET_BREAK_OFF: { KeSynchronizeExecution( Extension->Interrupt, SerialTurnOffBreak, Extension ); break; } case IOCTL_SERIAL_SET_QUEUE_SIZE: { // // Type ahead buffer is fixed, so we just validate // the the users request is not bigger that our // own internal buffer size. // PSERIAL_QUEUE_SIZE Rs = ((PSERIAL_QUEUE_SIZE)(Irp->AssociatedIrp.SystemBuffer)); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_QUEUE_SIZE)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // We have to allocate the memory for the new // buffer while we're still in the context of the // caller. We don't even try to protect this // with a lock because the value could be stale // as soon as we release the lock - The only time // we will know for sure is when we actually try // to do the resize. // if (Rs->InSize <= Extension->BufferSize) { Status = STATUS_SUCCESS; break; } try { IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ExAllocatePoolWithQuota( NonPagedPool, Rs->InSize ); } except (EXCEPTION_EXECUTE_HANDLER) { IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL; Status = GetExceptionCode(); } if (!IrpSp->Parameters.DeviceIoControl.Type3InputBuffer) { break; } // // Well the data passed was big enough. Do the request. // // There are two reason we place it in the read queue: // // 1) We want to serialize these resize requests so that // they don't contend with each other. // // 2) We want to serialize these requests with reads since // we don't want reads and resizes contending over the // read buffer. // return SerialStartOrQueue( Extension, Irp, &Extension->ReadQueue, &Extension->CurrentReadIrp, SerialStartRead ); break; } case IOCTL_SERIAL_GET_WAIT_MASK: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // Simple scalar read. No reason to acquire a lock. // Irp->IoStatus.Information = sizeof(ULONG); *((ULONG *)Irp->AssociatedIrp.SystemBuffer) = Extension->IsrWaitMask; break; } case IOCTL_SERIAL_SET_WAIT_MASK: { ULONG NewMask; SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: In Ioctl processing for set mask\n") ); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { SerialDump( SERDIAG3, ("SERIAL: Invalid size fo the buffer %d\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength) ); Status = STATUS_BUFFER_TOO_SMALL; break; } else { NewMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer); } // // Make sure that the mask only contains valid // waitable events. // if (NewMask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2)) { SerialDump( SERDIAG3, ("SERIAL: Unknown mask %x\n",NewMask) ); Status = STATUS_INVALID_PARAMETER; break; } // // Either start this irp or put it on the // queue. // SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: Starting or queuing set mask irp %x\n",Irp) ); return SerialStartOrQueue( Extension, Irp, &Extension->MaskQueue, &Extension->CurrentMaskIrp, SerialStartMask ); } case IOCTL_SERIAL_WAIT_ON_MASK: { SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: In Ioctl processing for wait mask\n") ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { SerialDump( SERDIAG3, ("SERIAL: Invalid size fo the buffer %d\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength) ); Status = STATUS_BUFFER_TOO_SMALL; break; } // // Either start this irp or put it on the // queue. // SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: Starting or queuing wait mask irp %x\n",Irp) ); return SerialStartOrQueue( Extension, Irp, &Extension->MaskQueue, &Extension->CurrentMaskIrp, SerialStartMask ); } case IOCTL_SERIAL_IMMEDIATE_CHAR: { KIRQL OldIrql; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { Status = STATUS_BUFFER_TOO_SMALL; break; } IoAcquireCancelSpinLock(&OldIrql); if (Extension->CurrentImmediateIrp) { Status = STATUS_INVALID_PARAMETER; IoReleaseCancelSpinLock(OldIrql); } else { // // We can queue the char. We need to set // a cancel routine because flow control could // keep the char from transmitting. Make sure // that the irp hasn't already been canceled. // if (Irp->Cancel) { IoReleaseCancelSpinLock(OldIrql); Status = STATUS_CANCELLED; } else { Extension->CurrentImmediateIrp = Irp; Extension->TotalCharsQueued++; IoReleaseCancelSpinLock(OldIrql); SerialStartImmediate(Extension); return STATUS_PENDING; } } break; } case IOCTL_SERIAL_PURGE: { ULONG Mask; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // Check to make sure that the mask only has // 0 or the other appropriate values. // Mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer)); if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR ) ) )) { Status = STATUS_INVALID_PARAMETER; break; } // // Either start this irp or put it on the // queue. // return SerialStartOrQueue( Extension, Irp, &Extension->PurgeQueue, &Extension->CurrentPurgeIrp, SerialStartPurge ); } case IOCTL_SERIAL_GET_HANDFLOW: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW); KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); *((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) = Extension->HandFlow; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_HANDFLOW: { SERIAL_IOCTL_SYNC S; PSERIAL_HANDFLOW HandFlow = Irp->AssociatedIrp.SystemBuffer; // // Make sure that the hand shake and control is the // right size. // if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // Make sure that there are no invalid bits set in // the control and handshake. // if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) { Status = STATUS_INVALID_PARAMETER; break; } if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) { Status = STATUS_INVALID_PARAMETER; break; } // // Make sure that the app hasn't set an invlid DTR mode. // if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { Status = STATUS_INVALID_PARAMETER; break; } // // Make sure that haven't set totally invalid xon/xoff // limits. // if ((HandFlow->XonLimit < 0) || ((ULONG)HandFlow->XonLimit > Extension->BufferSize)) { Status = STATUS_INVALID_PARAMETER; break; } if ((HandFlow->XoffLimit < 0) || ((ULONG)HandFlow->XoffLimit > Extension->BufferSize)) { Status = STATUS_INVALID_PARAMETER; break; } S.Extension = Extension; S.Data = HandFlow; KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); // // Under the protection of the lock, make sure that // we aren't turning on error replacement when we // are doing line status/modem status insertion. // if (Extension->EscapeChar) { if (HandFlow->FlowReplace & SERIAL_ERROR_CHAR) { Status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } } KeSynchronizeExecution( Extension->Interrupt, SerialSetHandFlow, &S ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_MODEMSTATUS: { SERIAL_IOCTL_SYNC S; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); S.Extension = Extension; S.Data = Irp->AssociatedIrp.SystemBuffer; KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); KeSynchronizeExecution( Extension->Interrupt, SerialGetModemUpdate, &S ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_DTRRTS: { ULONG ModemControl; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Status = STATUS_SUCCESS; // // Reading this hardware has no effect on the device. // ModemControl = READ_MODEM_CONTROL(Extension->Controller); ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE; *(PULONG)Irp->AssociatedIrp.SystemBuffer = ModemControl; break; } case IOCTL_SERIAL_GET_COMMSTATUS: { SERIAL_IOCTL_SYNC S; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_STATUS); S.Extension = Extension; S.Data = Irp->AssociatedIrp.SystemBuffer; // // Acquire the cancel spin lock so nothing much // changes while were getting the state. // IoAcquireCancelSpinLock(&OldIrql); KeSynchronizeExecution( Extension->Interrupt, SerialGetCommStatus, &S ); IoReleaseCancelSpinLock(OldIrql); break; } case IOCTL_SERIAL_GET_PROPERTIES: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // No synchronization is required since this information // is "static". // SerialGetProperties( Extension, Irp->AssociatedIrp.SystemBuffer ); Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP); Irp->IoStatus.Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_XOFF_COUNTER: { PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_XOFF_COUNTER)) { Status = STATUS_BUFFER_TOO_SMALL; break; } if (Xc->Counter <= 0) { Status = STATUS_INVALID_PARAMETER; break; } // // So far so good. Put the irp onto the write queue. // return SerialStartOrQueue( Extension, Irp, &Extension->WriteQueue, &Extension->CurrentWriteIrp, SerialStartWrite ); } case IOCTL_SERIAL_LSRMST_INSERT: { PUCHAR escapeChar = Irp->AssociatedIrp.SystemBuffer; // // Make sure we get a byte. // if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if (*escapeChar) { // // We've got some escape work to do. We will make sure that // the character is not the same as the Xon or Xoff character, // or that we are already doing error replacement. // if ((*escapeChar == Extension->SpecialChars.XoffChar) || (*escapeChar == Extension->SpecialChars.XonChar) || (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) { Status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } } KeSynchronizeExecution( Extension->Interrupt, SerialSetEscapeChar, Irp ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_CONFIG_SIZE: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Status = STATUS_SUCCESS; *(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; break; } case IOCTL_SERIAL_GET_STATS: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIALPERF_STATS); Irp->IoStatus.Status = STATUS_SUCCESS; KeSynchronizeExecution( Extension->Interrupt, SerialGetStats, Irp ); break; } case IOCTL_SERIAL_CLEAR_STATS: { KeSynchronizeExecution( Extension->Interrupt, SerialClearStats, Extension ); break; } default: { Status = STATUS_INVALID_PARAMETER; break; } } DoneWithIoctl:; Irp->IoStatus.Status = Status; SerialDump( SERIRPPATH, ("SERIAL: Complete Irp: %x\n",Irp) ); IoCompleteRequest( Irp, 0 ); return Status; }
VOID DBusStartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine starts an I/O operation for the device. Arguments: DeviceObject - Pointer to the device object. Irp - Pointer to the request packet. Return Value: None. --*/ { PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpSp; BusPrint((2, "DBusStartIo: enter\n")); deviceExtension = DeviceObject->DeviceExtension; // // Bump the error log sequence number. // deviceExtension->SequenceNumber += 1; // // Get a pointer to the current parameters for this request. The // information is contained in the current stack location. // irpSp = IoGetCurrentIrpStackLocation(Irp); // // We know we got here with an internal device control request. Switch // on IoControlCode. // switch(irpSp->Parameters.DeviceIoControl.IoControlCode) { // // Enable mouse interrupts, by calling BusEnableInterrupts // synchronously. // case IOCTL_INTERNAL_MOUSE_ENABLE: KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusEnableInterrupts, (PVOID) deviceExtension ); BusPrint(( 2, "DBusStartIo: mouse enable (count %d)\n", deviceExtension->MouseEnableCount )); Irp->IoStatus.Status = STATUS_SUCCESS; // // Complete the request. // IoStartNextPacket(DeviceObject, FALSE); IoCompleteRequest(Irp, IO_MOUSE_INCREMENT); break; // // Disable mouse interrupts, by calling BusDisableInterrupts // synchronously. // case IOCTL_INTERNAL_MOUSE_DISABLE: BusPrint((2, "DBusStartIo: mouse disable")); if (deviceExtension->MouseEnableCount == 0) { // // Mouse already disabled. // BusPrint((2, " - error\n")); Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR; } else { // // Disable mouse by calling BusDisableInterrupts. // KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusDisableInterrupts, (PVOID) deviceExtension ); BusPrint(( 2, " (count %d)\n", deviceExtension->MouseEnableCount )); Irp->IoStatus.Status = STATUS_SUCCESS; } // // Complete the request. // IoStartNextPacket(DeviceObject, FALSE); IoCompleteRequest(Irp, IO_MOUSE_INCREMENT); break; default: BusPrint((2, "DBusStartIo: INVALID REQUEST\n")); // // Log an internal error. Note that we're calling the // error log DPC routine directly, rather than duplicating // code. // BusErrorLogDpc( (PKDPC) NULL, DeviceObject, Irp, (PVOID) (ULONG) BUSMOUSE_INVALID_STARTIO_REQUEST ); ASSERT(FALSE); break; } BusPrint((2, "DBusStartIo: exit\n")); return; }
VOID DBusIsrDpc( IN PKDPC Dpc, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This routine runs at DISPATCH_LEVEL IRQL to finish processing mouse interrupts. It is queued in the mouse ISR. The real work is done via a callback to the connected mouse class driver. Arguments: Dpc - Pointer to the DPC object. DeviceObject - Pointer to the device object. Irp - Pointer to the Irp. Context - Not used. Return Value: None. --*/ { PDEVICE_EXTENSION deviceExtension; GET_DATA_POINTER_CONTEXT getPointerContext; SET_DATA_POINTER_CONTEXT setPointerContext; VARIABLE_OPERATION_CONTEXT operationContext; PVOID classService; PVOID classDeviceObject; LONG interlockedResult; BOOLEAN moreDpcProcessing; ULONG dataNotConsumed = 0; ULONG inputDataConsumed = 0; LARGE_INTEGER deltaTime; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(Irp); UNREFERENCED_PARAMETER(Context); BusPrint((2, "DBusIsrDpc: enter\n")); deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; // // Use DpcInterlockVariable to determine whether the DPC is running // concurrently on another processor. We only want one instantiation // of the DPC to actually do any work. DpcInterlockVariable is -1 // when no DPC is executing. We increment it, and if the result is // zero then the current instantiation is the only one executing, and it // is okay to proceed. Otherwise, we just return. // // operationContext.VariableAddress = &deviceExtension->DpcInterlockVariable; operationContext.Operation = IncrementOperation; operationContext.NewValue = &interlockedResult; KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusDpcVariableOperation, (PVOID) &operationContext ); moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE; while (moreDpcProcessing) { dataNotConsumed = 0; inputDataConsumed = 0; // // Get the port InputData queue pointers synchronously. // getPointerContext.DeviceExtension = deviceExtension; setPointerContext.DeviceExtension = deviceExtension; setPointerContext.InputCount = 0; KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusGetDataQueuePointer, (PVOID) &getPointerContext ); if (getPointerContext.InputCount != 0) { // // Call the connected class driver's callback ISR with the // port InputData queue pointers. If we have to wrap the queue, // break the operation into two pieces, and call the class callback // ISR once for each piece. // classDeviceObject = deviceExtension->ConnectData.ClassDeviceObject; classService = deviceExtension->ConnectData.ClassService; ASSERT(classService != NULL); if (getPointerContext.DataOut >= getPointerContext.DataIn) { // // We'll have to wrap the InputData circular buffer. Call // the class callback ISR with the chunk of data starting at // DataOut and ending at the end of the queue. // BusPrint(( 2, "DBusIsrDpc: calling class callback\n" )); BusPrint(( 2, "DBusIsrDpc: with Start 0x%x and End 0x%x\n", getPointerContext.DataOut, deviceExtension->DataEnd )); (*(PSERVICE_CALLBACK_ROUTINE) classService)( classDeviceObject, getPointerContext.DataOut, deviceExtension->DataEnd, &inputDataConsumed ); dataNotConsumed = (((PUCHAR) deviceExtension->DataEnd - (PUCHAR) getPointerContext.DataOut) / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed; BusPrint(( 2, "DBusIsrDpc: (Wrap) Call callback consumed %d items, left %d\n", inputDataConsumed, dataNotConsumed )); setPointerContext.InputCount += inputDataConsumed; if (dataNotConsumed) { setPointerContext.DataOut = ((PUCHAR)getPointerContext.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA)); } else { setPointerContext.DataOut = deviceExtension->InputData; getPointerContext.DataOut = setPointerContext.DataOut; } } // // Call the class callback ISR with data remaining in the queue. // if ((dataNotConsumed == 0) && (inputDataConsumed < getPointerContext.InputCount)){ BusPrint(( 2, "DBusIsrDpc: calling class callback\n" )); BusPrint(( 2, "DBusIsrDpc: with Start 0x%x and End 0x%x\n", getPointerContext.DataOut, getPointerContext.DataIn )); (*(PSERVICE_CALLBACK_ROUTINE) classService)( classDeviceObject, getPointerContext.DataOut, getPointerContext.DataIn, &inputDataConsumed ); dataNotConsumed = (((PUCHAR) getPointerContext.DataIn - (PUCHAR) getPointerContext.DataOut) / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed; BusPrint(( 2, "DBusIsrDpc: Call callback consumed %d items, left %d\n", inputDataConsumed, dataNotConsumed )); setPointerContext.DataOut = ((PUCHAR)getPointerContext.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA)); setPointerContext.InputCount += inputDataConsumed; } // // Update the port InputData queue DataOut pointer and InputCount // synchronously. // KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusSetDataQueuePointer, (PVOID) &setPointerContext ); } if (dataNotConsumed) { // // The class driver was unable to consume all the data. // Reset the interlocked variable to -1. We do not want // to attempt to move more data to the class driver at this // point, because it is already overloaded. Need to wait a // while to give the Raw Input Thread a chance to read some // of the data out of the class driver's queue. We accomplish // this "wait" via a timer. // BusPrint((2, "DBusIsrDpc: set timer in DPC\n")); operationContext.Operation = WriteOperation; interlockedResult = -1; operationContext.NewValue = &interlockedResult; KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusDpcVariableOperation, (PVOID) &operationContext ); deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000); deltaTime.HighPart = -1; (VOID) KeSetTimer( &deviceExtension->DataConsumptionTimer, deltaTime, &deviceExtension->IsrDpcRetry ); moreDpcProcessing = FALSE; } else { // // Decrement DpcInterlockVariable. If the result goes negative, // then we're all finished processing the DPC. Otherwise, either // the ISR incremented DpcInterlockVariable because it has more // work for the ISR DPC to do, or a concurrent DPC executed on // some processor while the current DPC was running (the // concurrent DPC wouldn't have done any work). Make sure that // the current DPC handles any extra work that is ready to be // done. // operationContext.Operation = DecrementOperation; operationContext.NewValue = &interlockedResult; KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusDpcVariableOperation, (PVOID) &operationContext ); if (interlockedResult != -1) { // // The interlocked variable is still greater than or equal to // zero. Reset it to zero, so that we execute the loop one // more time (assuming no more DPCs execute and bump the // variable up again). // operationContext.Operation = WriteOperation; interlockedResult = 0; operationContext.NewValue = &interlockedResult; KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusDpcVariableOperation, (PVOID) &operationContext ); BusPrint((2, "BUSMOUSE-DBusIsrDpc: loop in DPC\n")); } else { moreDpcProcessing = FALSE; } } } BusPrint((2, "DBusIsrDpc: exit\n")); }
NTSTATUS DBusInternalDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine is the dispatch routine for internal device control requests. Arguments: DeviceObject - Pointer to the device object. Irp - Pointer to the request packet. Return Value: Status is returned. --*/ { PIO_STACK_LOCATION irpSp; PDEVICE_EXTENSION deviceExtension; NTSTATUS status; BusPrint((2,"DBusInternalDeviceControl: enter\n")); // // Get a pointer to the device extension. // deviceExtension = DeviceObject->DeviceExtension; // // Initialize the returned Information field. // Irp->IoStatus.Information = 0; // // Get a pointer to the current parameters for this request. The // information is contained in the current stack location. // irpSp = IoGetCurrentIrpStackLocation(Irp); // // Case on the device control subfunction that is being performed by the // requestor. // switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { // // Connect a mouse class device driver to the port driver. // case IOCTL_INTERNAL_MOUSE_CONNECT: BusPrint(( 2, "DBusInternalDeviceControl: mouse connect\n" )); // // Only allow one connection. // // FUTURE: Consider allowing multiple connections, just for // the sake of generality? // if (deviceExtension->ConnectData.ClassService != NULL) { BusPrint(( 2, "DBusInternalDeviceControl: error - already connected\n" )); status = STATUS_SHARING_VIOLATION; break; } else if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) { BusPrint(( 2, "DBusInternalDeviceControl: error - invalid buffer length\n" )); status = STATUS_INVALID_PARAMETER; break; } // // Copy the connection parameters to the device extension. // deviceExtension->ConnectData = *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer)); // // Reinitialize the port input data queue synchronously. // KeSynchronizeExecution( deviceExtension->InterruptObject, (PKSYNCHRONIZE_ROUTINE) BusInitializeDataQueue, (PVOID) deviceExtension ); // // Set the completion status. // status = STATUS_SUCCESS; break; // // Disconnect a mouse class device driver from the port driver. // // NOTE: Not implemented. // case IOCTL_INTERNAL_MOUSE_DISCONNECT: BusPrint(( 2, "DBusInternalDeviceControl: mouse disconnect\n" )); // // Perform a mouse interrupt disable call. // // // Clear the connection parameters in the device extension. // NOTE: Must synchronize this with the mouse ISR. // // //deviceExtension->ConnectData.ClassDeviceObject = // Null; //deviceExtension->ConnectData.ClassService = // Null; // // Set the completion status. // status = STATUS_NOT_IMPLEMENTED; break; // // Enable mouse interrupts (mark the request pending and handle // it in StartIo). // case IOCTL_INTERNAL_MOUSE_ENABLE: BusPrint(( 2, "DBusInternalDeviceControl: mouse enable\n" )); status = STATUS_PENDING; break; // // Disable mouse interrupts (mark the request pending and handle // it in StartIo). // case IOCTL_INTERNAL_MOUSE_DISABLE: BusPrint(( 2, "DBusInternalDeviceControl: mouse disable\n" )); status = STATUS_PENDING; break; // // Query the mouse attributes. First check for adequate buffer // length. Then, copy the mouse attributes from the device // extension to the output buffer. // case IOCTL_MOUSE_QUERY_ATTRIBUTES: BusPrint(( 2, "DBusInternalDeviceControl: mouse query attributes\n" )); if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES)) { status = STATUS_BUFFER_TOO_SMALL; } else { // // Copy the attributes from the DeviceExtension to the // buffer. // *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = deviceExtension->Configuration.MouseAttributes; Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); status = STATUS_SUCCESS; } break; default: BusPrint(( 2, "DBusInternalDeviceControl: INVALID REQUEST\n" )); status = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status = status; if (status == STATUS_PENDING) { IoMarkIrpPending(Irp); IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL); } else { IoCompleteRequest(Irp, IO_NO_INCREMENT); } BusPrint((2,"DBusInternalDeviceControl: exit\n")); return(status); }
VOID SerialStartTimerLowerRTS( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) /*++ Routine Description: This routine starts a timer that when it expires will start a dpc that will check if it can lower the rts line because there are no characters in the hardware. Arguments: Dpc - Not Used. DeferredContext - Really points to the device extension. SystemContext1 - Not Used. SystemContext2 - Not Used. Return Value: None. --*/ { PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; LARGE_INTEGER CharTime; KIRQL OldIrql; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemContext1); UNREFERENCED_PARAMETER(SystemContext2); // // Take out the lock to prevent the line control // from changing out from under us while we calculate // a character time. // KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); CharTime = SerialGetCharTime(Extension); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); CharTime.QuadPart = -CharTime.QuadPart; if (KeSetTimer( &Extension->LowerRTSTimer, CharTime, &Extension->PerhapsLowerRTSDpc )) { // // The timer was already in the timer queue. This implies // that one path of execution that was trying to lower // the RTS has "died". Synchronize with the ISR so that // we can lower the count. // KeSynchronizeExecution( Extension->Interrupt, SerialDecrementRTSCounter, Extension ); } }
/////////////////////////////////////////////////////////////////////////////// // // OsrAdapterControlRead // // This is routine is called by the I/O Manager when the Adapter resources // (such as map registers) requested by the OsrStartReadIrp function are // available for our use. // // INPUTS: // // DeviceObject - Address of the DEVICE_OBJECT for our device. // // MapRegisterBase - Base address of the Map registers that have been // reserved for us use. // // Context - address of the Read Irp for the operation to be started // // OUTPUTS: // // None. // // RETURNS: // // DeallocateObjectKeepRegisters - indicates that the Mapping Registers that // were allocated to us should not be deallocated at this time. We // will deallocate them from the DpcForIsr when the Read completes. // // IRQL: // // This routine is called at IRQL_DISPATCH_LEVEL. // // NOTES: // /////////////////////////////////////////////////////////////////////////////// IO_ALLOCATION_ACTION OsrAdapterControlRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP NotUsed, IN PVOID MapRegisterBase, IN PVOID Context) { PIRP irp = (PIRP) Context; PIO_STACK_LOCATION ioStack; POSR_DEVICE_EXT devExt; PUCHAR baseVa; #if DBG DbgPrint("AdapterControlRead: Irp = 0x%0x\n", irp); DbgPrint("AdapterControlRead: Map Register Base = 0x%0x\n", MapRegisterBase); #endif devExt = DeviceObject->DeviceExtension; ioStack = IoGetCurrentIrpStackLocation(irp); devExt->ReadLength = ioStack->Parameters.Read.Length - devExt->ReadSoFar; #if DBG DbgPrint("AdapterControlRead: Length remaining = %d. \n", devExt->ReadLength); #endif // // Get set-up for the transfer // devExt->ReadMapRegBase = MapRegisterBase; devExt->ReadStartingOffset = devExt->ReadSoFar; // // Get requestor's virtual address of the buffer. This is used by // IoMapTransfer() as an index into the buffer to track the progress // of the map operation. // baseVa = MmGetMdlVirtualAddress(irp->MdlAddress); // // Get the logical base address and length of a fragment of the // requestor's buffer. // // Even though we are a Busmaster device, our device does not support // scatter/gather. Thus, we can only use a single base address and length // at a time. If the requestor's buffer has more fragments, we will // do additional DMA operations (one for each fragment) until the entire // transfer has been completed. // devExt->ReadPaToDevice = IoMapTransfer(devExt->ReadAdapter, irp->MdlAddress, MapRegisterBase, baseVa+(devExt->ReadSoFar), &devExt->ReadLength, FALSE); // FALSE = READ from device // // Track the length of the requestor's buffer we've read so far. // devExt->ReadSoFar += devExt->ReadLength; // // Start the request on the device -- Base Address and Length // of this fragment are stored in the device extension // (VOID)KeSynchronizeExecution(devExt->InterruptObject, OsrStartReadOnDevice, DeviceObject); return(DeallocateObjectKeepRegisters); }
IO_ALLOCATION_ACTION sndProgramDMA( IN PDEVICE_OBJECT pDO, IN PIRP pIrp, IN PVOID pMRB, IN PVOID Context ) /*++ Routine Description: This routine is executed when an adapter channel is allocated for our DMA needs. Arguments: pDO - Device object pIrp - IO request packet pMRB - Context - Which buffer are we using Return Value: Tell the system what to do with the adapter object --*/ { PGLOBAL_DEVICE_INFO pGDI; int WhichBuffer; UNREFERENCED_PARAMETER(pIrp); WhichBuffer = (int) Context; pGDI = ((PLOCAL_DEVICE_INFO)pDO->DeviceExtension)->pGlobalInfo; pGDI->pMRB[WhichBuffer] = pMRB; sndReStartDMA(pGDI, WhichBuffer); // // return a value that says we want to keep the channel // and map registers. // if (WhichBuffer == 0) { // // Do the other one. // if (pGDI->Usage == SoundInterruptUsageWaveIn) { dprintf4("Allocating adapter channel (buffer = 3)"); IoAllocateAdapterChannel(pGDI->pAdapterObject[3], pGDI->pWaveInDevObj, BYTES_TO_PAGES(pGDI->DmaHalfBufferSize), sndProgramDMA, (PVOID)1); // next buffer } else { dprintf4("Allocating adapter channel (buffer = 1)"); IoAllocateAdapterChannel(pGDI->pAdapterObject[1], pGDI->pWaveOutDevObj, BYTES_TO_PAGES(pGDI->DmaHalfBufferSize), sndProgramDMA, (PVOID)1); // next buffer } // // Execution will continue in sndProgramDMA when the // adapter has been allocated (AGAIN) // } else { // // Now program the hardware on the card to begin the transfer. // Note that this must be synchronized with the isr // dprintf4("Calling (sync) sndInitiate"); KeSynchronizeExecution(pGDI->pInterrupt, pGDI->StartDMA, pGDI); // // Execution continues in the SoundInitiate routine // } return KeepObject; }
NTSTATUS NTAPI SerialDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION Stack; ULONG IoControlCode; PSERIAL_DEVICE_EXTENSION DeviceExtension; ULONG LengthIn, LengthOut; ULONG_PTR Information = 0; PVOID BufferIn, BufferOut; PUCHAR ComPortBase; NTSTATUS Status; TRACE_(SERIAL, "IRP_MJ_DEVICE_CONTROL dispatch\n"); Stack = IoGetCurrentIrpStackLocation(Irp); LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength; LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength; DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode; SerialGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut); /* FIXME: need to probe buffers */ /* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */ switch (IoControlCode) { case IOCTL_SERIAL_CLEAR_STATS: { TRACE_(SERIAL, "IOCTL_SERIAL_CLEAR_STATS\n"); KeSynchronizeExecution( DeviceExtension->Interrupt, (PKSYNCHRONIZE_ROUTINE)SerialClearPerfStats, DeviceExtension); Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_CLR_DTR: { TRACE_(SERIAL, "IOCTL_SERIAL_CLR_DTR\n"); /* FIXME: If the handshake flow control of the device is configured to * automatically use DTR, return STATUS_INVALID_PARAMETER */ Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { DeviceExtension->MCR &= ~SR_MCR_DTR; WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } break; } case IOCTL_SERIAL_CLR_RTS: { TRACE_(SERIAL, "IOCTL_SERIAL_CLR_RTS\n"); /* FIXME: If the handshake flow control of the device is configured to * automatically use RTS, return STATUS_INVALID_PARAMETER */ Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { DeviceExtension->MCR &= ~SR_MCR_RTS; WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } break; } case IOCTL_SERIAL_CONFIG_SIZE: { /* Obsolete on Microsoft Windows 2000+ */ PULONG pConfigSize; TRACE_(SERIAL, "IOCTL_SERIAL_CONFIG_SIZE\n"); if (LengthOut != sizeof(ULONG) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pConfigSize = (PULONG)BufferOut; *pConfigSize = 0; Information = sizeof(ULONG); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_BAUD_RATE: { TRACE_(SERIAL, "IOCTL_SERIAL_GET_BAUD_RATE\n"); if (LengthOut < sizeof(SERIAL_BAUD_RATE)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { ((PSERIAL_BAUD_RATE)BufferOut)->BaudRate = DeviceExtension->BaudRate; Information = sizeof(SERIAL_BAUD_RATE); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_CHARS: { /* FIXME */ PSERIAL_CHARS pSerialChars; ERR_(SERIAL, "IOCTL_SERIAL_GET_CHARS not implemented.\n"); if (LengthOut < sizeof(SERIAL_CHARS)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pSerialChars = (PSERIAL_CHARS)BufferOut; pSerialChars->EofChar = 0; pSerialChars->ErrorChar = 0; pSerialChars->BreakChar = 0; pSerialChars->EventChar = 0; pSerialChars->XonChar = 0; pSerialChars->XoffChar = 0; Information = sizeof(SERIAL_CHARS); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_COMMSTATUS: { TRACE_(SERIAL, "IOCTL_SERIAL_GET_COMMSTATUS\n"); if (LengthOut < sizeof(SERIAL_STATUS)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { Status = SerialGetCommStatus((PSERIAL_STATUS)BufferOut, DeviceExtension); Information = sizeof(SERIAL_STATUS); } break; } case IOCTL_SERIAL_GET_DTRRTS: { PULONG pDtrRts; TRACE_(SERIAL, "IOCTL_SERIAL_GET_DTRRTS\n"); if (LengthOut != sizeof(ULONG) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pDtrRts = (PULONG)BufferOut; *pDtrRts = 0; if (DeviceExtension->MCR & SR_MCR_DTR) *pDtrRts |= SERIAL_DTR_STATE; if (DeviceExtension->MCR & SR_MCR_RTS) *pDtrRts |= SERIAL_RTS_STATE; Information = sizeof(ULONG); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_HANDFLOW: { /* FIXME */ PSERIAL_HANDFLOW pSerialHandflow; ERR_(SERIAL, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n"); if (LengthOut < sizeof(SERIAL_HANDFLOW)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pSerialHandflow = (PSERIAL_HANDFLOW)BufferOut; pSerialHandflow->ControlHandShake = 0; pSerialHandflow->FlowReplace = 0; pSerialHandflow->XonLimit = 0; pSerialHandflow->XoffLimit = 0; Information = sizeof(SERIAL_HANDFLOW); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { TRACE_(SERIAL, "IOCTL_SERIAL_GET_LINE_CONTROL\n"); if (LengthOut < sizeof(SERIAL_LINE_CONTROL)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { *((PSERIAL_LINE_CONTROL)BufferOut) = DeviceExtension->SerialLineControl; Information = sizeof(SERIAL_LINE_CONTROL); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_MODEM_CONTROL: { PULONG pMCR; TRACE_(SERIAL, "IOCTL_SERIAL_GET_MODEM_CONTROL\n"); if (LengthOut != sizeof(ULONG) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pMCR = (PULONG)BufferOut; *pMCR = DeviceExtension->MCR; Information = sizeof(ULONG); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_MODEMSTATUS: { PULONG pMSR; TRACE_(SERIAL, "IOCTL_SERIAL_GET_MODEMSTATUS\n"); if (LengthOut != sizeof(ULONG) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pMSR = (PULONG)BufferOut; *pMSR = DeviceExtension->MSR; Information = sizeof(ULONG); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_PROPERTIES: { TRACE_(SERIAL, "IOCTL_SERIAL_GET_PROPERTIES\n"); if (LengthOut < sizeof(SERIAL_COMMPROP)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { Status = SerialGetCommProp((PSERIAL_COMMPROP)BufferOut, DeviceExtension); Information = sizeof(SERIAL_COMMPROP); } break; } case IOCTL_SERIAL_GET_STATS: { TRACE_(SERIAL, "IOCTL_SERIAL_GET_STATS\n"); if (LengthOut < sizeof(SERIALPERF_STATS)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { KeSynchronizeExecution(DeviceExtension->Interrupt, (PKSYNCHRONIZE_ROUTINE)SerialGetPerfStats, Irp); Information = sizeof(SERIALPERF_STATS); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_TIMEOUTS: { TRACE_(SERIAL, "IOCTL_SERIAL_GET_TIMEOUTS\n"); if (LengthOut != sizeof(SERIAL_TIMEOUTS) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { *(PSERIAL_TIMEOUTS)BufferOut = DeviceExtension->SerialTimeOuts; Information = sizeof(SERIAL_TIMEOUTS); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_GET_WAIT_MASK: { PULONG pWaitMask; TRACE_(SERIAL, "IOCTL_SERIAL_GET_WAIT_MASK\n"); if (LengthOut != sizeof(ULONG) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { pWaitMask = (PULONG)BufferOut; *pWaitMask = DeviceExtension->WaitMask; Information = sizeof(ULONG); Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_IMMEDIATE_CHAR: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_LSRMST_INSERT: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_PURGE: { KIRQL Irql; TRACE_(SERIAL, "IOCTL_SERIAL_PURGE\n"); /* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT * should stop current request */ if (LengthIn != sizeof(ULONG) || BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else { ULONG PurgeMask = *(PULONG)BufferIn; Status = STATUS_SUCCESS; /* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */ if (PurgeMask & SERIAL_PURGE_RXCLEAR) { KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0; if (DeviceExtension->UartType >= Uart16550A) { /* Clear also Uart FIFO */ Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } } KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); } if (PurgeMask & SERIAL_PURGE_TXCLEAR) { KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0; if (DeviceExtension->UartType >= Uart16550A) { /* Clear also Uart FIFO */ Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_XMIT); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } } KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); } } break; } case IOCTL_SERIAL_RESET_DEVICE: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_SET_BAUD_RATE: { PULONG pNewBaudRate; TRACE_(SERIAL, "IOCTL_SERIAL_SET_BAUD_RATE\n"); if (LengthIn != sizeof(ULONG) || BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else { pNewBaudRate = (PULONG)BufferIn; Status = SerialSetBaudRate(DeviceExtension, *pNewBaudRate); } break; } case IOCTL_SERIAL_SET_BREAK_OFF: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_SET_BREAK_ON: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_SET_CHARS: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_SET_CHARS not implemented.\n"); Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_SET_DTR: { /* FIXME: If the handshake flow control of the device is configured to * automatically use DTR, return STATUS_INVALID_PARAMETER */ TRACE_(SERIAL, "IOCTL_SERIAL_SET_DTR\n"); if (!(DeviceExtension->MCR & SR_MCR_DTR)) { Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { DeviceExtension->MCR |= SR_MCR_DTR; WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } } else Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_SET_FIFO_CONTROL: { TRACE_(SERIAL, "IOCTL_SERIAL_SET_FIFO_CONTROL\n"); if (LengthIn != sizeof(ULONG) || BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else { Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { WRITE_PORT_UCHAR(SER_FCR(ComPortBase), (UCHAR)((*(PULONG)BufferIn) & 0xff)); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } } break; } case IOCTL_SERIAL_SET_HANDFLOW: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n"); Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_SET_LINE_CONTROL: { TRACE_(SERIAL, "IOCTL_SERIAL_SET_LINE_CONTROL\n"); if (LengthIn < sizeof(SERIAL_LINE_CONTROL)) Status = STATUS_BUFFER_TOO_SMALL; else if (BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else Status = SerialSetLineControl(DeviceExtension, (PSERIAL_LINE_CONTROL)BufferIn); break; } case IOCTL_SERIAL_SET_MODEM_CONTROL: { PULONG pMCR; TRACE_(SERIAL, "IOCTL_SERIAL_SET_MODEM_CONTROL\n"); if (LengthIn != sizeof(ULONG) || BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else { Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { pMCR = (PULONG)BufferIn; DeviceExtension->MCR = (UCHAR)(*pMCR & 0xff); WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } } break; } case IOCTL_SERIAL_SET_QUEUE_SIZE: { if (LengthIn < sizeof(SERIAL_QUEUE_SIZE )) return STATUS_BUFFER_TOO_SMALL; else if (BufferIn == NULL) return STATUS_INVALID_PARAMETER; else { KIRQL Irql; PSERIAL_QUEUE_SIZE NewQueueSize = (PSERIAL_QUEUE_SIZE)BufferIn; Status = STATUS_SUCCESS; if (NewQueueSize->InSize > DeviceExtension->InputBuffer.Length) { KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); Status = IncreaseCircularBufferSize(&DeviceExtension->InputBuffer, NewQueueSize->InSize); KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); } if (NT_SUCCESS(Status) && NewQueueSize->OutSize > DeviceExtension->OutputBuffer.Length) { KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); Status = IncreaseCircularBufferSize(&DeviceExtension->OutputBuffer, NewQueueSize->OutSize); KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); } } break; } case IOCTL_SERIAL_SET_RTS: { /* FIXME: If the handshake flow control of the device is configured to * automatically use DTR, return STATUS_INVALID_PARAMETER */ TRACE_(SERIAL, "IOCTL_SERIAL_SET_RTS\n"); if (!(DeviceExtension->MCR & SR_MCR_RTS)) { Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { DeviceExtension->MCR |= SR_MCR_RTS; WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } } else Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_SET_TIMEOUTS: { TRACE_(SERIAL, "IOCTL_SERIAL_SET_TIMEOUTS\n"); if (LengthIn != sizeof(SERIAL_TIMEOUTS) || BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else { DeviceExtension->SerialTimeOuts = *(PSERIAL_TIMEOUTS)BufferIn; Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_SET_WAIT_MASK: { PULONG pWaitMask = (PULONG)BufferIn; TRACE_(SERIAL, "IOCTL_SERIAL_SET_WAIT_MASK\n"); if (LengthIn != sizeof(ULONG) || BufferIn == NULL) Status = STATUS_INVALID_PARAMETER; else if (DeviceExtension->WaitOnMaskIrp) /* FIXME: Race condition ; field may be currently in modification */ { WARN_(SERIAL, "An IRP is already currently processed\n"); Status = STATUS_INVALID_PARAMETER; } else { DeviceExtension->WaitMask = *pWaitMask; Status = STATUS_SUCCESS; } break; } case IOCTL_SERIAL_SET_XOFF: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_SET_XOFF not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_SET_XON: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_SET_XON not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } case IOCTL_SERIAL_WAIT_ON_MASK: { PIRP WaitingIrp; TRACE_(SERIAL, "IOCTL_SERIAL_WAIT_ON_MASK\n"); if (LengthOut != sizeof(ULONG) || BufferOut == NULL) Status = STATUS_INVALID_PARAMETER; else { IoMarkIrpPending(Irp); WaitingIrp = InterlockedCompareExchangePointer( &DeviceExtension->WaitOnMaskIrp, Irp, NULL); /* Check if an Irp is already pending */ if (WaitingIrp != NULL) { /* Unable to have a 2nd pending IRP for this IOCTL */ WARN_(SERIAL, "Unable to pend a second IRP for IOCTL_SERIAL_WAIT_ON_MASK\n"); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return STATUS_PENDING; } break; } case IOCTL_SERIAL_XOFF_COUNTER: { /* FIXME */ ERR_(SERIAL, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n"); Status = STATUS_NOT_IMPLEMENTED; break; } default: { /* Pass Irp to lower driver */ TRACE_(SERIAL, "Unknown IOCTL code 0x%x\n", Stack->Parameters.DeviceIoControl.IoControlCode); IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(DeviceExtension->LowerDevice, Irp); } } Irp->IoStatus.Status = Status; if (Status == STATUS_PENDING) { IoMarkIrpPending(Irp); } else { Irp->IoStatus.Information = Information; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return Status; }
NTSTATUS SerialStartPurge( IN PSERIAL_DEVICE_EXTENSION Extension ) /*++ Routine Description: Depending on the mask in the current irp, purge the interrupt buffer, the read queue, or the write queue, or all of the above. Arguments: Extension - Pointer to the device extension. Return Value: Will return STATUS_SUCCESS always. This is reasonable since the DPC completion code that calls this routine doesn't care and the purge request always goes through to completion once it's started. --*/ { PIRP NewIrp; do { ULONG Mask; Mask = *((ULONG *) (Extension->CurrentPurgeIrp->AssociatedIrp.SystemBuffer)); if (Mask & SERIAL_PURGE_TXABORT) { SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->WriteQueue, &Extension->CurrentWriteIrp ); SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->WriteQueue, &Extension->CurrentXoffIrp ); } if (Mask & SERIAL_PURGE_RXABORT) { SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->ReadQueue, &Extension->CurrentReadIrp ); } if (Mask & SERIAL_PURGE_RXCLEAR) { KIRQL OldIrql; // // Clean out the interrupt buffer. // // Note that we do this under protection of the // the drivers control lock so that we don't hose // the pointers if there is currently a read that // is reading out of the buffer. // KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); KeSynchronizeExecution( Extension->Interrupt, SerialPurgeInterruptBuff, Extension ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); } Extension->CurrentPurgeIrp->IoStatus.Status = STATUS_SUCCESS; Extension->CurrentPurgeIrp->IoStatus.Information = 0; SerialGetNextIrp( &Extension->CurrentPurgeIrp, &Extension->PurgeQueue, &NewIrp, TRUE ); } while (NewIrp); return STATUS_SUCCESS; }
BOOLEAN KspSynchronizedEventRoutine( IN KSEVENTS_LOCKTYPE EventsFlags, IN PVOID EventsLock, IN PKSEVENT_SYNCHRONIZED_ROUTINE SynchronizedRoutine, IN PKSEVENT_CTX Ctx) { BOOLEAN Result = FALSE; KIRQL OldLevel; if (EventsFlags == KSEVENTS_NONE) { /* no synchronization required */ Result = SynchronizedRoutine(Ctx); } else if (EventsFlags == KSEVENTS_SPINLOCK) { /* use spin lock */ KeAcquireSpinLock((PKSPIN_LOCK)EventsLock, &OldLevel); Result = SynchronizedRoutine(Ctx); KeReleaseSpinLock((PKSPIN_LOCK)EventsLock, OldLevel); } else if (EventsFlags == KSEVENTS_MUTEX) { /* use a mutex */ KeWaitForSingleObject(EventsLock, Executive, KernelMode, FALSE, NULL); Result = SynchronizedRoutine(Ctx); KeReleaseMutex((PRKMUTEX)EventsLock, FALSE); } else if (EventsFlags == KSEVENTS_FMUTEX) { /* use a fast mutex */ ExAcquireFastMutex((PFAST_MUTEX)EventsLock); Result = SynchronizedRoutine(Ctx); ExReleaseFastMutex((PFAST_MUTEX)EventsLock); } else if (EventsFlags == KSEVENTS_FMUTEXUNSAFE) { /* acquire fast mutex unsafe */ KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe((PFAST_MUTEX)EventsLock); Result = SynchronizedRoutine(Ctx); ExReleaseFastMutexUnsafe((PFAST_MUTEX)EventsLock); KeLeaveCriticalRegion(); } else if (EventsFlags == KSEVENTS_INTERRUPT) { /* use interrupt for locking */ Result = KeSynchronizeExecution((PKINTERRUPT)EventsLock, (PKSYNCHRONIZE_ROUTINE)SynchronizedRoutine, (PVOID)Ctx); } else if (EventsFlags == KSEVENTS_ERESOURCE) { /* use an eresource */ KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite((PERESOURCE)EventsLock, TRUE); Result = SynchronizedRoutine(Ctx); ExReleaseResourceLite((PERESOURCE)EventsLock); KeLeaveCriticalRegion(); } return Result; }