示例#1
0
/*! \brief Activate and deactive a line on the IEC serial bus

 This function activates (sets to 0V, L) and deactivates 
 (set to 5V, H) lines on the IEC serial bus.

 \param Pdx
   Pointer to the device extension.

 \param Set
   The mask of which lines should be set. This has to be a bitwise OR
   between the constants IEC_DATA, IEC_CLOCK, IEC_ATN, and IEC_RESET

 \param Release
   The mask of which lines should be released. This has to be a bitwise
   OR between the constants IEC_DATA, IEC_CLOCK, IEC_ATN, and IEC_RESET

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, it
   returns one of the error status values.

 \remark
   If a bit is specified in the Set as well as in the Release mask, the
   effect is undefined.
*/
NTSTATUS
cbmiec_iec_setrelease(IN PDEVICE_EXTENSION Pdx, IN USHORT Set, IN USHORT Release)
{
    NTSTATUS ntStatus;

    FUNC_ENTER();

    FUNC_PARAM((DBG_PREFIX "set = 0x%02x, release = 0x%02x", Set, Release));

    ntStatus = STATUS_SUCCESS;

    DBG_ASSERT((Set & Release) == 0);

    // Set the correct line as given by the call

    if ( (Set & ~(IEC_LINE_DATA | IEC_LINE_CLOCK | IEC_LINE_ATN | IEC_LINE_RESET))
        || (Release & ~(IEC_LINE_DATA | IEC_LINE_CLOCK | IEC_LINE_ATN | IEC_LINE_RESET)))
    {
        // there was some bit set that is not recognized, return
        // with an error
        ntStatus = STATUS_INVALID_PARAMETER;
    }
    else
    {
        ULONG set_mask = 0;
        ULONG release_mask = 0;

        SET_RELEASE_LINE(DATA,  DATA);
        SET_RELEASE_LINE(CLOCK, CLK);
        SET_RELEASE_LINE(ATN,   ATN);
        SET_RELEASE_LINE(RESET, RESET);

#ifdef TEST_BIDIR

        #define PP_BIDIR_OUT   PP_LP_BIDIR
        #define IEC_LINE_BIDIR PP_BIDIR_OUT

        SET_RELEASE_LINE(BIDIR, BIDIR);

        #undef PP_BIDIR_OUT
        #undef IEC_LINE_BIDIR

#endif // #ifdef TEST_BIDIR

        CBMIEC_SET_RELEASE(set_mask, release_mask);

    }

    FUNC_LEAVE_NTSTATUS(ntStatus );
}
示例#2
0
/*! \brief Send an UNLISTEN over the IEC bus

 This function sends an UNLISTEN to the IEC bus.

 \param Pdx
   Pointer to the device extension.

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, it
   returns one of the error status values.
*/
NTSTATUS
cbmiec_unlisten(IN PDEVICE_EXTENSION Pdx)
{
    NTSTATUS ntStatus;
    ULONG sent;
    UCHAR buffer;

    FUNC_ENTER();

    // send a 0x3F (unlisten) under control of ATN

    buffer = 0x3f;
    ntStatus = cbmiec_i_raw_write(Pdx, &buffer, 1, &sent, 1, 0);

    Pdx->DoNotReleaseBus = FALSE;

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#3
0
NTSTATUS
cbm_cleanup(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
{
    PIO_STACK_LOCATION irpSp;
    PDEVICE_EXTENSION pdx;
    NTSTATUS ntStatus;

    FUNC_ENTER();

    pdx = Fdo->DeviceExtension;
    irpSp = IoGetCurrentIrpStackLocation(Irp);

    /* Let the QUEUE itself perform all relevant steps */
    QueueCleanup(&pdx->IrpQueue, irpSp->FileObject);

    /* We're done, complete the IRP */
    ntStatus = QueueCompleteIrp(NULL, Irp, STATUS_SUCCESS, 0);

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#4
0
文件: talk.c 项目: jkaessens/opencbm
/*! \brief Send a TALK over the IEC bus

 This function sends a TALK to the IEC bus.

 \param Pdx
   Pointer to the device extension.

 \param Device
   Device (primary) address

 \param Secaddr
   Secondary address

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, it
   returns one of the error status values.
*/
NTSTATUS
cbmiec_talk(IN PDEVICE_EXTENSION Pdx, IN UCHAR Device, IN UCHAR Secaddr)
{
    NTSTATUS ntStatus;
    ULONG sent;
    UCHAR buffer[2];

    FUNC_ENTER();

    FUNC_PARAM((DBG_PREFIX "Device = 0x%02x, Secaddr = 0x%02x", (int)Device, (int)Secaddr));

    // send a 0x4x / 0x6y (talk device x, secaddr y) under control of ATN

    buffer[0] = 0x40 | Device;
    buffer[1] = 0x60 | Secaddr;
    ntStatus = cbmiec_i_raw_write(Pdx, buffer, 2, &sent, 1, 1);

    Pdx->DoNotReleaseBus = TRUE;

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#5
0
文件: init.c 项目: jkaessens/opencbm
/*! \brief Initialize the IEC bus

 This function initializes the IEC bus itself, and sets some
 variables in the device extension. It has to be called before
 any other IEC function is called.

 \param Pdx
   Pointer to the device extension.

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, it
   returns one of the error status values.
*/
NTSTATUS
cbmiec_init(IN PDEVICE_EXTENSION Pdx)
{
    NTSTATUS ntStatus;

    FUNC_ENTER();

    // Initialize the event which is used to wake up the
    // task in wait_for_listener()

    DBG_IRQL( == PASSIVE_LEVEL);
    KeInitializeEvent(&Pdx->EventWaitForListener, SynchronizationEvent, FALSE);

#ifdef USE_DPC

    // Initialize the DPC object which will be used for waking
    // up cbmiec_wait_for_listener() later

    DBG_IRQL( == PASSIVE_LEVEL)
    IoInitializeDpcRequest(Pdx->Fdo, cbmiec_dpc);

#endif // #ifdef USE_DPC

    ntStatus = cbmiec_testcable(Pdx);

    if (!NT_SUCCESS(ntStatus)) {
        FUNC_LEAVE_NTSTATUS(ntStatus);
    }

    Pdx->IecBusy = FALSE;

    if (!Pdx->DoNotReleaseBus)
    {
        CBMIEC_RELEASE(PP_RESET_OUT | PP_DATA_OUT | PP_ATN_OUT | PP_LP_BIDIR | PP_LP_IRQ);
        CBMIEC_SET(PP_CLK_OUT);
    }

    FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
}
示例#6
0
/*! \brief Allocate a parallel port for using it

 This function allocates a parallel port, preventing other
 drivers from accessing it.

 \param Pdx
   Pointer to a device extension which contains the DEVICE_OBJECT 
   of the parallel port driver.

 This function has to be balanced with a corresponding ParPortFree()
 This function must be run at IRQL == PASSIVE_LEVEL.
*/
NTSTATUS
ParPortAllocate(PDEVICE_EXTENSION Pdx)
{
    NTSTATUS ntStatus;

    FUNC_ENTER();

    DBG_ASSERT(Pdx);
    DBG_ASSERT(Pdx->ParallelPortAllocated == FALSE);

    // allocate the parallel port

    ntStatus = ParPortIoctlInOut(Pdx, IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE,
                                 NULL, 0, NULL, 0);

    // if we were successfull, remember this in the pdx

    if (NT_SUCCESS(ntStatus))
    {
        Pdx->ParallelPortAllocated = TRUE;
    }

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#7
0
/*! \brief Check the buffer of an read or write IRP

 Check the buffer of an read or write IRP

 \param IrpSp: 
   Pointer to the IO_STACK_LOCATION of the IRP which contains the input buffer.

 \return 
   If the provided buffer is valid, this function returns
   STATUS_SUCCESS. If not, it returns an appropriate error value.
*/
static NTSTATUS
cbm_checkbuffer(IN PIO_STACK_LOCATION IrpSp)
{
    NTSTATUS ntStatus;

    FUNC_ENTER();

    // The following code assumes that the read and write structure are exactly
    // the same (despite the name). This ASSERT() makes sure that we are informed
    // if this is not the case.

    DBG_ASSERT(&IrpSp->Parameters.Read.ByteOffset == &IrpSp->Parameters.Write.ByteOffset);

    if ((IrpSp->Parameters.Write.ByteOffset.HighPart != 0) ||
        (IrpSp->Parameters.Write.ByteOffset.LowPart != 0)) 
    {
        ntStatus = STATUS_INVALID_PARAMETER;
    } 
    else 
    {
        ntStatus = STATUS_SUCCESS;
    }
    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#8
0
文件: ioctl.c 项目: jkaessens/opencbm
/*! \brief Executes IOCTLs

 Executes IRPs containing the IRP_MJ_DEVICE_CONTROL I/O function code.

 \param Pdx
   Pointer to the DEVICE_EXTENSION structure.

 \param Irp
   Pointer to an IRP structure that describes the requested I/O operation.

 \return
   If the routine succeeds, it returns STATUS_SUCCESS.
   Otherwise, it return one of the error status values:
   \n STATUS_SUCCESS              - Success.
   \n STATUS_BUFFER_TOO_SMALL     - Buffer too small.

 This function does not perform any validity checks on the input and
 output buffer! This should already been done in cbm_devicecontrol.
*/
NTSTATUS
cbm_execute_devicecontrol(IN PDEVICE_EXTENSION Pdx, IN PIRP Irp)
{
    PPAR_SET_INFORMATION setInfo;
    PIO_STACK_LOCATION irpSp;
    ULONG_PTR returnLength;
    NTSTATUS ntStatus;

    FUNC_ENTER();

    // As not every IOCTL needs to return a value, we initialize
    // the return length here. This way, it needs only be altered
    // if the IOCTL returns some value.

    returnLength = 0;

    // get the current IRP stack location

    irpSp = IoGetCurrentIrpStackLocation(Irp);

    PERF_EVENT_IOCTL_EXECUTE(irpSp->Parameters.DeviceIoControl.IoControlCode);

    DBG_IRPPATH_EXECUTE("Execute Ioctl");

    // Call the appropriate function for processing the IOCTL
    // PrimaryAddresses are ANDed with 0x1F, as these are the only legitimate
    // primary addresses allowed for a IEC serial bus.

    switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {

    case CBMCTRL_TALK:
        DBG_IRP(CBMCTRL_TALK);
        ntStatus = cbmiec_talk(Pdx, INPUTVALUE(CBMT_TALK_IN)->PrimaryAddress & 0x1F,
                               INPUTVALUE(CBMT_TALK_IN)->SecondaryAddress);
        break;

    case CBMCTRL_LISTEN:
        DBG_IRP(CBMCTRL_LISTEN);
        ntStatus = cbmiec_listen(Pdx, INPUTVALUE(CBMT_LISTEN_IN)->PrimaryAddress & 0x1F,
                                 INPUTVALUE(CBMT_LISTEN_IN)->SecondaryAddress);
        break;

    case CBMCTRL_UNTALK:
        DBG_IRP(CBMCTRL_UNTALK);
        ntStatus = cbmiec_untalk(Pdx);
        break;

    case CBMCTRL_UNLISTEN:
        DBG_IRP(CBMCTRL_UNLISTEN);
        ntStatus = cbmiec_unlisten(Pdx);
        break;

    case CBMCTRL_OPEN:
        DBG_IRP(CBMCTRL_OPEN);
        ntStatus = cbmiec_open(Pdx, INPUTVALUE(CBMT_OPEN_IN)->PrimaryAddress & 0x1F,
                               INPUTVALUE(CBMT_OPEN_IN)->SecondaryAddress);
        break;

    case CBMCTRL_CLOSE:
        DBG_IRP(CBMCTRL_CLOSE);
        ntStatus = cbmiec_close(Pdx,INPUTVALUE(CBMT_CLOSE_IN)->PrimaryAddress & 0x1F,
                                INPUTVALUE(CBMT_CLOSE_IN)->SecondaryAddress);
        break;

    case CBMCTRL_RESET:
        DBG_IRP(CBMCTRL_RESET);
        ntStatus = cbmiec_reset(Pdx);
        break;

    case CBMCTRL_GET_EOI:
        DBG_IRP(CBMCTRL_GET_EOI);
        returnLength = sizeof(CBMT_GET_EOI_OUT);
        ntStatus = cbmiec_get_eoi(Pdx, &(OUTPUTVALUE(CBMT_GET_EOI_OUT)->Decision));
        break;

    case CBMCTRL_CLEAR_EOI:
        DBG_IRP(CBMCTRL_CLEAR_EOI);
        ntStatus = cbmiec_clear_eoi(Pdx);
        break;

    case CBMCTRL_PP_READ:
        DBG_IRP(CBMCTRL_PP_READ);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_PP_READ_OUT), STATUS_SUCCESS);
        returnLength = sizeof(CBMT_PP_READ_OUT);
        ntStatus = cbmiec_pp_read(Pdx, &(OUTPUTVALUE(CBMT_PP_READ_OUT)->Byte));
        break;

    case CBMCTRL_PP_WRITE:
        DBG_IRP(CBMCTRL_PP_WRITE);
        ntStatus = cbmiec_pp_write(Pdx, INPUTVALUE(CBMT_PP_WRITE_IN)->Byte);
        break;

    case CBMCTRL_IEC_POLL:
        DBG_IRP(CBMCTRL_IEC_POLL);
        returnLength = sizeof(CBMT_IEC_POLL_OUT);
        ntStatus = cbmiec_iec_poll(Pdx, &(OUTPUTVALUE(CBMT_IEC_POLL_OUT)->Line));
        break;

    case CBMCTRL_IEC_SET:
        DBG_IRP(CBMCTRL_IEC_SET);
        ntStatus = cbmiec_iec_set(Pdx, INPUTVALUE(CBMT_IEC_SET_IN)->Line);
        break;

    case CBMCTRL_IEC_RELEASE:
        DBG_IRP(CBMCTRL_IEC_RELEASE);
        ntStatus = cbmiec_iec_release(Pdx, INPUTVALUE(CBMT_IEC_RELEASE_IN)->Line);
        break;

    case CBMCTRL_IEC_SETRELEASE:
        DBG_IRP(CBMCTRL_IEC_SETRELEASE);
        ntStatus = cbmiec_iec_setrelease(Pdx,
                                         INPUTVALUE(CBMT_IEC_SETRELEASE_IN)->State,
                                         INPUTVALUE(CBMT_IEC_SETRELEASE_IN)->Line);
        break;

    case CBMCTRL_IEC_WAIT:
        DBG_IRP(CBMCTRL_IEC_WAIT);
        returnLength = sizeof(CBMT_IEC_WAIT_OUT);
        ntStatus = cbmiec_iec_wait(Pdx, INPUTVALUE(CBMT_IEC_WAIT_IN)->Line,
                                   INPUTVALUE(CBMT_IEC_WAIT_IN)->State,
                                   &(OUTPUTVALUE(CBMT_IEC_WAIT_OUT)->Line));
        break;

    case CBMCTRL_PARBURST_READ:
        DBG_IRP(CBMCTRL_PARBURST_READ);
        returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
        ntStatus = cbmiec_parallel_burst_read(Pdx, &(OUTPUTVALUE(CBMT_PARBURST_PREAD_OUT)->Byte));
        break;

    case CBMCTRL_PARBURST_WRITE:
        DBG_IRP(CBMCTRL_PARBURST_READ);
        returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
        ntStatus = cbmiec_parallel_burst_write(Pdx, INPUTVALUE(CBMT_PARBURST_PWRITE_IN)->Byte);
        break;

    case CBMCTRL_PARBURST_READ_TRACK:
        DBG_IRP(CBMCTRL_PARBURST_READ_TRACK);
        returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
        ntStatus = cbmiec_parallel_burst_read_track(Pdx,
                   Irp->AssociatedIrp.SystemBuffer, (ULONG) returnLength);
        break;

    case CBMCTRL_PARBURST_WRITE_TRACK:
        DBG_IRP(CBMCTRL_PARBURST_WRITE_TRACK);
        returnLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
        ntStatus = cbmiec_parallel_burst_write_track(Pdx,
                   Irp->AssociatedIrp.SystemBuffer, (ULONG) returnLength);
        break;

    case CBMCTRL_I_INSTALL:
        DBG_IRP(CBMCTRL_I_INSTALL);
        returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
        ntStatus = cbm_install(Pdx, OUTPUTVALUE(CBMT_I_INSTALL_OUT), (PULONG) &returnLength);
        break;

    case CBMCTRL_PARPORT_LOCK:
        DBG_IRP(CBMCTRL_PARPORT_LOCK);
        ntStatus = cbm_lock(Pdx);
        break;

    case CBMCTRL_PARPORT_UNLOCK:
        DBG_IRP(CBMCTRL_PARPORT_UNLOCK);
        ntStatus = cbm_unlock(Pdx);
        break;

    case CBMCTRL_UPDATE:
        DBG_IRP(CBMCTRL_UPDATE);
        cbm_init_registry(NULL, Pdx);
        ntStatus = STATUS_SUCCESS;
        break;

#if DBG

    case CBMCTRL_I_READDBG:
        DBG_IRP(CBMCTRL_I_READDBG);
        returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
        ntStatus = cbm_dbg_readbuffer(Pdx, OUTPUTVALUE(CHAR), (PULONG) &returnLength);
        break;

#endif // #if DBG

    default:
        // As cbm_devicecontrol() already checked the IRP,
        // this piece of code should never be entered. If it
        // is, this is a sign of a forgotten IOCTL, or a severe
        // programming error

        DBG_ERROR((DBG_PREFIX "unknown IRP_MJ_DEVICE_CONTROL"));
        DBG_ASSERT(("THIS SHOULD NOT HAPPEN!", 0));
        ntStatus = STATUS_INVALID_PARAMETER;
        break;
    }

    // If an error occurred, make sure not to return anything.

    if (!NT_SUCCESS(ntStatus))
    {
        returnLength = 0;
    }

    // Complete the request:

    DBG_IRPPATH_COMPLETE("Execute Ioctl");
    QueueCompleteIrp(&Pdx->IrpQueue, Irp, ntStatus, returnLength);

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#9
0
文件: ioctl.c 项目: jkaessens/opencbm
/*! \brief Services IOCTLs

 Services IRPs containing the IRP_MJ_DEVICE_CONTROL I/O function code.

 \param Fdo
   Pointer to a DEVICE_OBJECT structure.
   This is the device object for the target device,
   previously created by the driver's AddDevice routine.

 \param Irp
   Pointer to an IRP structure that describes the requested I/O operation.

 \return
   If the routine succeeds, it returns STATUS_SUCCESS.
   Otherwise, it return one of the error status values:
   \n STATUS_SUCCESS              - Success.
   \n STATUS_PENDING              - Request pending.
   \n STATUS_BUFFER_TOO_SMALL     - Buffer too small.
   \n STATUS_INVALID_PARAMETER    - Invalid io control request.

 The driver's DriverEntry routine stored this routine's address in
 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL].

 Generally, all Dispatch routines execute in an arbitrary thread context
 at IRQL PASSIVE_LEVEL, but there are exceptions.
*/
NTSTATUS
cbm_devicecontrol(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
{
    PPAR_SET_INFORMATION setInfo;
    PIO_STACK_LOCATION irpSp;
    PDEVICE_EXTENSION pdx;
    NTSTATUS ntStatus;
    BOOLEAN fastStart;

    FUNC_ENTER();

    // get the device extension

    pdx = Fdo->DeviceExtension;

    // get the current IRP stack location

    irpSp = IoGetCurrentIrpStackLocation(Irp);


    DBG_IRPPATH_PROCESS("Ioctl");

    // assume we do not want to perform a faststart of this IRP

    fastStart = FALSE;

    // Now, check the input and/or output buffers of the given
    // IOCTLs if they are at least as big as the specification.
    // If not, the IRP (and thus the IOCTL) is failed

    switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {

    case CBMCTRL_TALK:
        DBG_IRP(CBMCTRL_TALK);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_TALK_IN), STATUS_SUCCESS);
        break;

    case CBMCTRL_LISTEN:
        DBG_IRP(CBMCTRL_LISTEN);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_LISTEN_IN), STATUS_SUCCESS);
        break;

    case CBMCTRL_UNTALK:
        DBG_IRP(CBMCTRL_UNTALK);
        ntStatus = STATUS_SUCCESS;
        break;

    case CBMCTRL_UNLISTEN:
        DBG_IRP(CBMCTRL_UNLISTEN);
        ntStatus = STATUS_SUCCESS;
        break;

    case CBMCTRL_OPEN:
        DBG_IRP(CBMCTRL_OPEN);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_OPEN_IN), STATUS_SUCCESS);
        break;

    case CBMCTRL_CLOSE:
        DBG_IRP(CBMCTRL_CLOSE);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_CLOSE_IN), STATUS_SUCCESS);
        break;

    case CBMCTRL_RESET:
        DBG_IRP(CBMCTRL_RESET);
        ntStatus = STATUS_SUCCESS;
        break;

    case CBMCTRL_GET_EOI:
        DBG_IRP(CBMCTRL_GET_EOI);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_GET_EOI_OUT), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_CLEAR_EOI:
        DBG_IRP(CBMCTRL_CLEAR_EOI);
        ntStatus = STATUS_SUCCESS;
        fastStart = TRUE;
        break;

    case CBMCTRL_PP_READ:
        DBG_IRP(CBMCTRL_PP_READ);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_PP_READ_OUT), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_PP_WRITE:
        DBG_IRP(CBMCTRL_PP_WRITE);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_PP_WRITE_IN), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_IEC_POLL:
        DBG_IRP(CBMCTRL_IEC_POLL);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_IEC_POLL_OUT), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_IEC_SET:
        DBG_IRP(CBMCTRL_IEC_SET);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_SET_IN), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_IEC_RELEASE:
        DBG_IRP(CBMCTRL_IEC_RELEASE);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_RELEASE_IN), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_IEC_SETRELEASE:
        DBG_IRP(CBMCTRL_IEC_SETRELEASE);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_SETRELEASE_IN), STATUS_SUCCESS);
        fastStart = TRUE;
        break;

    case CBMCTRL_IEC_WAIT:
        DBG_IRP(CBMCTRL_IEC_WAIT);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_IEC_WAIT_OUT),
                                         cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_WAIT_IN), STATUS_SUCCESS));
        break;

    case CBMCTRL_PARBURST_READ:
        DBG_IRP(CBMCTRL_PARBURST_READ);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_PARBURST_PREAD_OUT), STATUS_SUCCESS);
        break;

    case CBMCTRL_PARBURST_WRITE:
        DBG_IRP(CBMCTRL_PARBURST_WRITE);
        ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_PARBURST_PWRITE_IN), STATUS_SUCCESS);
        break;

    case CBMCTRL_PARBURST_READ_TRACK:
        DBG_IRP(CBMCTRL_PARBURST_READ_TRACK);
        ntStatus = cbm_checkoutputbuffer(irpSp, 1, STATUS_SUCCESS);
        break;

    case CBMCTRL_PARBURST_WRITE_TRACK:
        DBG_IRP(CBMCTRL_PARBURST_WRITE_TRACK);
        ntStatus = cbm_checkinputbuffer(irpSp, 1, STATUS_SUCCESS);
        break;

    case CBMCTRL_I_INSTALL:
        DBG_IRP(CBMCTRL_I_INSTALL);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_I_INSTALL_OUT), STATUS_SUCCESS);
        break;

    case CBMCTRL_PARPORT_LOCK:
        DBG_IRP(CBMCTRL_PARPORT_LOCK);
        ntStatus = STATUS_SUCCESS;
        break;

    case CBMCTRL_PARPORT_UNLOCK:
        DBG_IRP(CBMCTRL_PARPORT_UNLOCK);
        ntStatus = STATUS_SUCCESS;
        break;

    case CBMCTRL_UPDATE:
        DBG_IRP(CBMCTRL_UPDATE);
        ntStatus = STATUS_SUCCESS;
        fastStart = TRUE;
        break;

#if DBG

    case CBMCTRL_I_READDBG:
        DBG_IRP(CBMCTRL_I_READDBG);
        ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CHAR), STATUS_SUCCESS);
        break;

#endif // #if DBG

    default:
        DBG_ERROR((DBG_PREFIX "unknown IRP_MJ_DEVICE_CONTROL"));
        ntStatus = STATUS_INVALID_PARAMETER;
        break;
    }

    if (NT_SUCCESS(ntStatus))
    {
        PERF_EVENT_IOCTL_QUEUE(irpSp->Parameters.DeviceIoControl.IoControlCode);

        // queue the IRP to be processed
        // If faststart is TRUE, it will be processed immediately
        // (for performance reasons)

        ntStatus = QueueStartPacket(&pdx->IrpQueue, Irp, fastStart, Fdo);
    }
    else
    {
        // there was an error, complete the request
        // with that error status

        QueueCompleteIrp(NULL, Irp, ntStatus, 0);
    }

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#10
0
/*! \internal \brief Send an IOCTL to the parallel port driver

 This function sends an IOCTL to the parallel port driver.
 It is an internal helper function for the following functions.

 \param Pdx
   Pointer to the device extension of the driver

 \param Ioctl
   The IOCTL to perform

 \param InBuffer
   Pointer to a buffer which holds the input.
   This can be NULL.

 \param InBufferLength
   Length of the buffer pointed to by InBuffer. 
   Must be 0 if InBuffer == NULL.

 \param OutBuffer
   Pointer to a buffer which will get the output.
   This can be NULL.

 \param OutBufferLength
   Length of the buffer pointed to by OutBuffer. 
   Must be 0 if OutBuffer == NULL.

 This function must be run at IRQL == PASSIVE_LEVEL.
*/
static NTSTATUS
ParPortIoctlInOut(IN PDEVICE_EXTENSION Pdx, IN ULONG Ioctl, 
                  IN PVOID InBuffer, IN ULONG InBufferLength, 
                  OUT PVOID OutBuffer, IN ULONG OutBufferLength)
{
    IO_STATUS_BLOCK ioStatusBlock;
    NTSTATUS ntStatus;
    KEVENT event;   // event to be signalled when the IOCTL has finished
    PIRP irp;

    FUNC_ENTER();

    // Initialize the event which we will use to be notified
    // when the IRP has finished

    DBG_IRQL( == PASSIVE_LEVEL);
    KeInitializeEvent(&event, NotificationEvent, FALSE);

    ntStatus = STATUS_SUCCESS;

    // build an IRP for this IOCTL

    DBG_IRQL( == PASSIVE_LEVEL);
    irp = IoBuildDeviceIoControlRequest(
        Ioctl,
        Pdx->ParallelPortFdo,
        InBuffer,
        InBufferLength,
        OutBuffer,
        OutBufferLength,
        TRUE,           // it's an internal device control
        &event,
        &ioStatusBlock
        );

    if (irp)
    {
        PIO_STACK_LOCATION irpStack;

        // get the current IRP stack location

        DBG_IRQL( <= DISPATCH_LEVEL);
        irpStack = IoGetNextIrpStackLocation(irp);

        // Reference the file object we are about to call.
        // This ensures the driver is not removed while we call it,
        // even if the underlying hardware is removed

        DBG_IRQL( <= DISPATCH_LEVEL);
        ObReferenceObject(Pdx->ParallelPortFileObject);

        // tell the IRP stack location to which file object we are
        // referring

        irpStack->FileObject = Pdx->ParallelPortFileObject;

        // Call the driver to perform the requested IOCTL

        DBG_IRQL( <= DISPATCH_LEVEL);
        ntStatus = IoCallDriver(Pdx->ParallelPortFdo, irp);

        // We're done, we can dereference the file object again

        DBG_IRQL( <= DISPATCH_LEVEL);
        ObDereferenceObject(Pdx->ParallelPortFileObject);

        if (!NT_SUCCESS(ntStatus))
        {
            DBG_WARN((DBG_PREFIX "IoCallDriver FAILED!"));
        }
        else 
        {
            // wait for the IRP to be completed

            DBG_IRQL( <= DISPATCH_LEVEL /* = only if timeout of NULL */);
            ntStatus = KeWaitForSingleObject(
               &event, 
               Executive, 
               KernelMode, 
               FALSE, // we are not alertable
               NULL);

            if (!NT_SUCCESS(ntStatus)) 
            {
                DBG_WARN((DBG_PREFIX "KeWaitForSingleObject FAILED!"));
            }
        }
    }

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#11
0
/*! \brief Initialize the knowledge on a parallel port

 This function gets some knowledge on a parallel port,
 and stores this info into the given DEVICE_EXTENSION.

 \param ParallelPortName
   UNICODE_STRING which holds the name of the parallel port driver

 \param Pdx
   Device extension which will be initialized with the needed
   knowledge on the parallel port.

 This function should be called before any other parallel port
 function is called. Usually, it is done in the driver's 
 AddDevice (WDM) or DriverEntry (WKM, WDM) function.

 One of the purposes of this function is to make sure the
 parallel port driver is not unloaded from memory (via 
 IoGetDeviceObjectPointer()).

 This function must be run at IRQL == PASSIVE_LEVEL.
*/
NTSTATUS
ParPortInit(PUNICODE_STRING ParallelPortName, PDEVICE_EXTENSION Pdx)
{
    NTSTATUS ntStatus;

    FUNC_ENTER();

    DBG_ASSERT(ParallelPortName);
    DBG_ASSERT(Pdx);

    // First of all, get the PDEVICE_OBJECT of the parallel port driver

    DBG_IRQL( == PASSIVE_LEVEL);
    ntStatus = IoGetDeviceObjectPointer(ParallelPortName, 
                                        FILE_READ_ATTRIBUTES,
                                        &Pdx->ParallelPortFileObject,
                                        &Pdx->ParallelPortFdo);

    if (!NT_SUCCESS(ntStatus))
    {
        DBG_WARN((DBG_PREFIX "IoGetDeviceObjectPointer() FAILED!"));
        FUNC_LEAVE_NTSTATUS(ntStatus);
    }

    // Allocate memory to hold to parallel port info

    DBG_IRQL( == PASSIVE_LEVEL);
    Pdx->PortInfo = (PPARALLEL_PORT_INFORMATION) ExAllocatePoolWithTag(NonPagedPool, 
        sizeof(*Pdx->PortInfo), MTAG_PPINFO);

    // If we got memory, get the info out of the parallel port driver

    if (Pdx->PortInfo)
    {
        ntStatus = ParPortIoctlInOut(Pdx, IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO,
                                     NULL, 0,
                                     Pdx->PortInfo, sizeof(*Pdx->PortInfo));
    }
    else
    {
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    }

    if (NT_SUCCESS(ntStatus))
    {
        Pdx->ParPortPortAddress = Pdx->PortInfo->Controller;
        DBG_PPORT((DBG_PREFIX "Got parallel port information:"));
        DBG_PPORT((DBG_PREFIX "- OriginalController = 0x%p", Pdx->PortInfo->OriginalController));
        DBG_PPORT((DBG_PREFIX "- Controller         = 0x%p", Pdx->PortInfo->Controller));
        DBG_PPORT((DBG_PREFIX "- Span of controller = 0x%08x", Pdx->PortInfo->SpanOfController));
        DBG_PPORT((DBG_PREFIX "- TryAllocatePort    = 0x%p", Pdx->PortInfo->TryAllocatePort));
        DBG_PPORT((DBG_PREFIX "- FreePort           = 0x%p", Pdx->PortInfo->FreePort));
        DBG_PPORT((DBG_PREFIX "- QueryNumWaiters    = 0x%p", Pdx->PortInfo->QueryNumWaiters));
        DBG_PPORT((DBG_PREFIX "- Context            = 0x%p", Pdx->PortInfo->Context));
    }

    // if we failed getting the parallel port info, but there was memory
    // allocated, free the memory.

    if (!NT_SUCCESS(ntStatus) && Pdx->PortInfo)
    {
        DBG_IRQL( < DISPATCH_LEVEL);
        ExFreePool(Pdx->PortInfo);
        Pdx->PortInfo = NULL;
    }
示例#12
0
/*! \brief Services reads from or writes to the driver

 Services reads from or writes to the driver

 \param Fdo
   Pointer to a DEVICE_OBJECT structure. 
   This is the device object for the target device, 
   previously created by the driver's AddDevice routine.

 \param Irp
   Pointer to an IRP structure that describes the requested I/O operation. 

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. 
   Otherwise, it return one of the error status values.

 The driver's DriverEntry routine stored this routine's address in 
 DriverObject->MajorFunction[IRP_MJ_READ] and
 DriverObject->MajorFunction[IRP_MJ_WRITE].

 Generally, all Dispatch routines execute in an arbitrary thread context 
 at IRQL PASSIVE_LEVEL, but there are exceptions.
*/
NTSTATUS
cbm_readwrite(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
{
    PIO_STACK_LOCATION irpSp;
    PDEVICE_EXTENSION pdx;
    NTSTATUS ntStatus;
    ULONG readWriteBytesProcessed;
    ULONG readWriteLength;
    PUCHAR readWriteBuffer;

    FUNC_ENTER();

    // get the device extension

    pdx = Fdo->DeviceExtension;

    // get the current IRP stack location

    irpSp = IoGetCurrentIrpStackLocation(Irp);

    // Check if the buffer is valid

    ntStatus = cbm_checkbuffer(irpSp);

    DBG_IRPPATH_PROCESS("read/write");

    // Number of read (or written) bytes are 0 until now.
    // This is needed for finding out if we had success, or if something went wrong

    readWriteLength = 0;


    if (NT_SUCCESS(ntStatus))
    {
        // The following code assumes that the read and write structure are exactly
        // the same (despite the name). This ASSERT() makes sure that we are informed
        // if this is not the case.

        DBG_ASSERT(&irpSp->Parameters.Read.Length == &irpSp->Parameters.Write.Length);

        // Get the number of bytes to be read or written

        readWriteLength = irpSp->Parameters.Read.Length;

        // If we do performance measurements, log the appropriate event

        if (irpSp->MajorFunction == IRP_MJ_READ)
        {
            PERF_EVENT_READ_QUEUE(irpSp->Parameters.Read.Length);
        }
        else
        {
            PERF_EVENT_WRITE_QUEUE(irpSp->Parameters.Write.Length);
        }

        // If the read or write request has another length than 0,
        // then queue the IRP for being processed later.

        if (readWriteLength != 0)
        {
            // now, queue the IRP to be processed

            ntStatus = QueueStartPacket(&pdx->IrpQueue, Irp, FALSE, Fdo);
        }
    }

    if (!NT_SUCCESS(ntStatus) || readWriteLength == 0)
    {
        // there was an error, or a read/write request with length 0:
        // Thus, complete the request

        QueueCompleteIrp(NULL, Irp, ntStatus, 0);
    }

    FUNC_LEAVE_NTSTATUS(ntStatus);
}
示例#13
0
/*! \brief Executes reads from or writes to the driver

 Services reads from or writes to the driver

 \param Pdx
   Pointer to the DEVICE_EXTENSION structure.

 \param Irp
   Pointer to an IRP structure that describes the requested I/O operation. 

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. 
   Otherwise, it return one of the error status values.

 This function does not perform any validity checks on the input and 
 output buffer! This should already been done in cbm_readwrite.
*/
NTSTATUS
cbm_execute_readwrite(IN PDEVICE_EXTENSION Pdx, IN PIRP Irp)
{
    PIO_STACK_LOCATION irpSp;
    NTSTATUS ntStatus;
    ULONG readWriteBytesProcessed;
    ULONG readWriteLength;
    PUCHAR readWriteBuffer;

    FUNC_ENTER();

    // get the current IRP stack location

    irpSp = IoGetCurrentIrpStackLocation(Irp);

    // The following code assumes that the read and write structure are exactly
    // the same (despite the name). This ASSERT() makes sure that we are informed
    // if this is not the case.

    DBG_ASSERT(&irpSp->Parameters.Read.Length == &irpSp->Parameters.Write.Length);

    // Find out how much bytes are to be read/written

    readWriteLength = irpSp->Parameters.Read.Length;

    // get the buffer where the bytes to be written are / where the bytes to be read
    // should be placed

    readWriteBuffer = Irp->AssociatedIrp.SystemBuffer;

    // If we do performance measurements, log the appropriate event

    if (irpSp->MajorFunction == IRP_MJ_READ)
    {
        PERF_EVENT_READ_EXECUTE(irpSp->Parameters.Read.Length);
    }
    else
    {
        PERF_EVENT_WRITE_EXECUTE(irpSp->Parameters.Write.Length);
    }

    DBG_IRPPATH_EXECUTE("read/write");

    // As this has been tested in cbm_readwrite() already, we should not get
    // any zero length here. Anyway, be sure that this does not happen with the
    // help of this ASSERT()

    DBG_ASSERT(readWriteLength != 0);

    if (readWriteLength != 0)
    {
        // Execute the appropriate function (read or write)

        switch (irpSp->MajorFunction)
        {
        case IRP_MJ_READ: 
            ntStatus = cbmiec_raw_read(Pdx, readWriteBuffer, readWriteLength,
                &readWriteBytesProcessed);
            break;

        case IRP_MJ_WRITE:
            ntStatus = cbmiec_raw_write(Pdx, readWriteBuffer, readWriteLength,
                &readWriteBytesProcessed);
            break;

        default:
            DBG_ERROR((DBG_PREFIX "UNKNOWN IRP_MJ code in cbm_readwrite!"));
            ntStatus = STATUS_INTERNAL_ERROR;
            readWriteBytesProcessed = 0;
            break;
        }
    }

    // It would not make sense to pend the IRP here. Thus, make sure this does
    // not happen at all

    DBG_ASSERT(ntStatus != STATUS_PENDING);

    // If the read or write has not been pended, we are ready the complete this
    // IRP
    //! \todo Remove this, is this does not make sense.

    if (ntStatus != STATUS_PENDING)
    {
        QueueCompleteIrp(&Pdx->IrpQueue, Irp, ntStatus, readWriteBytesProcessed);
    }

    FUNC_LEAVE_NTSTATUS(ntStatus);
}