Main Page | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

ioctl.c

Go to the documentation of this file.
00001 /*
00002  *  This program is free software; you can redistribute it and/or
00003  *  modify it under the terms of the GNU General Public License
00004  *  as published by the Free Software Foundation; either version
00005  *  2 of the License, or (at your option) any later version.
00006  *
00007  *  Copyright 2004 Spiro Trikaliotis
00008  *
00009  */
00010 
00020 #include <wdm.h>
00021 #include "cbm_driver.h"
00022 #include "cbmioctl.h"
00023 #include "iec.h"
00024 
00025 #include <parallel.h>
00026 
00027 
00045 static NTSTATUS
00046 cbm_checkinputbuffer(IN PIO_STACK_LOCATION IrpSp, USHORT Len, NTSTATUS StatusOnSuccess)
00047 {
00048     FUNC_ENTER();
00049 
00050     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < Len)
00051     {
00052         StatusOnSuccess = STATUS_BUFFER_TOO_SMALL;
00053     }
00054 
00055     FUNC_LEAVE_NTSTATUS(StatusOnSuccess);
00056 }
00057 
00075 static NTSTATUS
00076 cbm_checkoutputbuffer(IN PIO_STACK_LOCATION IrpSp, USHORT Len, NTSTATUS StatusOnSuccess)
00077 {
00078     FUNC_ENTER();
00079 
00080     if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < Len)
00081     {
00082         StatusOnSuccess = STATUS_BUFFER_TOO_SMALL;
00083     }
00084 
00085     FUNC_LEAVE_NTSTATUS(StatusOnSuccess);
00086 }
00087 
00114 NTSTATUS
00115 cbm_devicecontrol(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
00116 {
00117     PPAR_SET_INFORMATION setInfo;
00118     PIO_STACK_LOCATION irpSp;
00119     PDEVICE_EXTENSION pdx;
00120     NTSTATUS ntStatus;
00121     BOOLEAN fastStart;
00122 
00123     FUNC_ENTER();
00124 
00125     // get the device extension
00126 
00127     pdx = Fdo->DeviceExtension;
00128 
00129     // get the current IRP stack location
00130 
00131     irpSp = IoGetCurrentIrpStackLocation(Irp);
00132 
00133 
00134     DBG_IRPPATH_PROCESS("Ioctl");
00135 
00136     // assume we do not want to perform a faststart of this IRP
00137 
00138     fastStart = FALSE;
00139 
00140     // Now, check the input and/or output buffers of the given
00141     // IOCTLs if they are at least as big as the specification.
00142     // If not, the IRP (and thus the IOCTL) is failed
00143 
00144     switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
00145 
00146         case CBMCTRL_TALK:
00147             DBG_IRP(CBMCTRL_TALK);
00148             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_TALK_IN), STATUS_SUCCESS);
00149             break;
00150 
00151         case CBMCTRL_LISTEN:
00152             DBG_IRP(CBMCTRL_LISTEN);
00153             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_LISTEN_IN), STATUS_SUCCESS);
00154             break;
00155 
00156         case CBMCTRL_UNTALK:
00157             DBG_IRP(CBMCTRL_UNTALK);
00158             ntStatus = STATUS_SUCCESS;
00159             break;
00160 
00161         case CBMCTRL_UNLISTEN:
00162             DBG_IRP(CBMCTRL_UNLISTEN);
00163             ntStatus = STATUS_SUCCESS;
00164             break;
00165 
00166         case CBMCTRL_OPEN:
00167             DBG_IRP(CBMCTRL_OPEN);
00168             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_OPEN_IN), STATUS_SUCCESS);
00169             break;
00170 
00171         case CBMCTRL_CLOSE:
00172             DBG_IRP(CBMCTRL_CLOSE);
00173             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_CLOSE_IN), STATUS_SUCCESS);
00174             break;
00175 
00176         case CBMCTRL_RESET:
00177             DBG_IRP(CBMCTRL_RESET);
00178             ntStatus = STATUS_SUCCESS;
00179             break;
00180 
00181         case CBMCTRL_GET_EOI:
00182             DBG_IRP(CBMCTRL_GET_EOI);
00183             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_GET_EOI_OUT), STATUS_SUCCESS);
00184             fastStart = TRUE;
00185             break;
00186 
00187         case CBMCTRL_CLEAR_EOI:
00188             DBG_IRP(CBMCTRL_CLEAR_EOI);
00189             ntStatus = STATUS_SUCCESS;
00190             fastStart = TRUE;
00191             break;
00192 
00193         case CBMCTRL_PP_READ:
00194             DBG_IRP(CBMCTRL_PP_READ);
00195             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_PP_READ_OUT), STATUS_SUCCESS);
00196             fastStart = TRUE;
00197             break;
00198 
00199         case CBMCTRL_PP_WRITE:
00200             DBG_IRP(CBMCTRL_PP_WRITE);
00201             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_PP_WRITE_IN), STATUS_SUCCESS);
00202             fastStart = TRUE;
00203             break;
00204 
00205         case CBMCTRL_IEC_POLL:
00206             DBG_IRP(CBMCTRL_IEC_POLL);
00207             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_IEC_POLL_OUT), STATUS_SUCCESS);
00208             fastStart = TRUE;
00209             break;
00210 
00211         case CBMCTRL_IEC_SET:
00212             DBG_IRP(CBMCTRL_IEC_SET);
00213             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_SET_IN), STATUS_SUCCESS);
00214             fastStart = TRUE;
00215             break;
00216 
00217         case CBMCTRL_IEC_RELEASE:
00218             DBG_IRP(CBMCTRL_IEC_RELEASE);
00219             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_RELEASE_IN), STATUS_SUCCESS);
00220             fastStart = TRUE;
00221             break;
00222 
00223         case CBMCTRL_IEC_SETRELEASE:
00224             DBG_IRP(CBMCTRL_IEC_SETRELEASE);
00225             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_SETRELEASE_IN), STATUS_SUCCESS);
00226             fastStart = TRUE;
00227             break;
00228 
00229         case CBMCTRL_IEC_WAIT:
00230             DBG_IRP(CBMCTRL_IEC_WAIT);
00231             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_IEC_WAIT_OUT), 
00232                          cbm_checkinputbuffer(irpSp, sizeof(CBMT_IEC_WAIT_IN), STATUS_SUCCESS));
00233             break;
00234 
00235         case CBMCTRL_PARBURST_READ:
00236             DBG_IRP(CBMCTRL_PARBURST_READ);
00237             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_PARBURST_PREAD_OUT), STATUS_SUCCESS);
00238             break;
00239 
00240         case CBMCTRL_PARBURST_WRITE:
00241             DBG_IRP(CBMCTRL_PARBURST_WRITE);
00242             ntStatus = cbm_checkinputbuffer(irpSp, sizeof(CBMT_PARBURST_PWRITE_IN), STATUS_SUCCESS);
00243             break;
00244 
00245         case CBMCTRL_PARBURST_READ_TRACK:
00246             DBG_IRP(CBMCTRL_PARBURST_READ_TRACK);
00247             ntStatus = cbm_checkoutputbuffer(irpSp, 1, STATUS_SUCCESS);
00248             break;
00249 
00250         case CBMCTRL_PARBURST_WRITE_TRACK:
00251             DBG_IRP(CBMCTRL_PARBURST_WRITE_TRACK);
00252             ntStatus = cbm_checkinputbuffer(irpSp, 1, STATUS_SUCCESS);
00253             break;
00254 
00255         case CBMCTRL_I_INSTALL:
00256             DBG_IRP(CBMCTRL_I_INSTALL);
00257             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_I_INSTALL_OUT), STATUS_SUCCESS);
00258             break;
00259 
00260         case CBMCTRL_PARPORT_LOCK:
00261             DBG_IRP(CBMCTRL_PARPORT_LOCK);
00262             ntStatus = STATUS_SUCCESS;
00263             break;
00264 
00265         case CBMCTRL_PARPORT_UNLOCK:
00266             DBG_IRP(CBMCTRL_PARPORT_UNLOCK);
00267             ntStatus = STATUS_SUCCESS;
00268             break;
00269 
00270         case CBMCTRL_UPDATE:
00271             DBG_IRP(CBMCTRL_UPDATE);
00272             ntStatus = STATUS_SUCCESS;
00273             fastStart = TRUE;
00274             break;
00275 
00276 #if DBG
00277 
00278         case CBMCTRL_I_READDBG:
00279             DBG_IRP(CBMCTRL_I_READDBG);
00280             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CHAR), STATUS_SUCCESS);
00281             break;
00282 
00283 #endif // #if DBG
00284 
00285         default:
00286             DBG_ERROR((DBG_PREFIX "unknown IRP_MJ_DEVICE_CONTROL"));
00287             ntStatus = STATUS_INVALID_PARAMETER;
00288             break;
00289     }
00290 
00291     if (NT_SUCCESS(ntStatus))
00292     {
00293         PERF_EVENT_IOCTL_QUEUE(irpSp->Parameters.DeviceIoControl.IoControlCode);
00294 
00295         // queue the IRP to be processed
00296         // If faststart is TRUE, it will be processed immediately
00297         // (for performance reasons)
00298 
00299         ntStatus = QueueStartPacket(&pdx->IrpQueue, Irp, fastStart, Fdo);
00300     }
00301     else
00302     {
00303         // there was an error, complete the request
00304         // with that error status
00305 
00306         QueueCompleteIrp(NULL, Irp, ntStatus, 0);
00307     }
00308 
00309     FUNC_LEAVE_NTSTATUS(ntStatus);
00310 }
00311 
00315 #define INPUTVALUE(_ttt_) ((_ttt_ *) Irp->AssociatedIrp.SystemBuffer)
00316 
00320 #define OUTPUTVALUE(_ttt_) ((_ttt_ *) Irp->AssociatedIrp.SystemBuffer)
00321 
00341 NTSTATUS
00342 cbm_execute_devicecontrol(IN PDEVICE_EXTENSION Pdx, IN PIRP Irp)
00343 {
00344     PPAR_SET_INFORMATION setInfo;
00345     PIO_STACK_LOCATION irpSp;
00346     ULONG_PTR returnLength;
00347     NTSTATUS ntStatus;
00348 
00349     FUNC_ENTER();
00350 
00351     // As not every IOCTL needs to return a value, we initialize 
00352     // the return length here. This way, it needs only be altered
00353     // if the IOCTL returns some value.
00354 
00355     returnLength = 0;
00356 
00357     // get the current IRP stack location
00358 
00359     irpSp = IoGetCurrentIrpStackLocation(Irp);
00360 
00361     PERF_EVENT_IOCTL_EXECUTE(irpSp->Parameters.DeviceIoControl.IoControlCode);
00362 
00363     DBG_IRPPATH_EXECUTE("Execute Ioctl");
00364 
00365     // Call the appropriate function for processing the IOCTL
00366     // PrimaryAddresses are ANDed with 0x1F, as these are the only legitimate
00367     // primary addresses allowed for a IEC serial bus.
00368 
00369     switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
00370 
00371         case CBMCTRL_TALK:
00372             DBG_IRP(CBMCTRL_TALK);
00373             ntStatus = cbmiec_talk(Pdx, INPUTVALUE(CBMT_TALK_IN)->PrimaryAddress & 0x1F,
00374                                    INPUTVALUE(CBMT_TALK_IN)->SecondaryAddress);
00375             break;
00376 
00377         case CBMCTRL_LISTEN:
00378             DBG_IRP(CBMCTRL_LISTEN);
00379             ntStatus = cbmiec_listen(Pdx, INPUTVALUE(CBMT_LISTEN_IN)->PrimaryAddress & 0x1F,
00380                                      INPUTVALUE(CBMT_LISTEN_IN)->SecondaryAddress);
00381             break;
00382 
00383         case CBMCTRL_UNTALK:
00384             DBG_IRP(CBMCTRL_UNTALK);
00385             ntStatus = cbmiec_untalk(Pdx);
00386             break;
00387 
00388         case CBMCTRL_UNLISTEN:
00389             DBG_IRP(CBMCTRL_UNLISTEN);
00390             ntStatus = cbmiec_unlisten(Pdx);
00391             break;
00392 
00393         case CBMCTRL_OPEN:
00394             DBG_IRP(CBMCTRL_OPEN);
00395             ntStatus = cbmiec_open(Pdx, INPUTVALUE(CBMT_OPEN_IN)->PrimaryAddress & 0x1F,
00396                                    INPUTVALUE(CBMT_OPEN_IN)->SecondaryAddress);
00397             break;
00398 
00399         case CBMCTRL_CLOSE:
00400             DBG_IRP(CBMCTRL_CLOSE);
00401             ntStatus = cbmiec_close(Pdx,INPUTVALUE(CBMT_CLOSE_IN)->PrimaryAddress & 0x1F,
00402                                     INPUTVALUE(CBMT_CLOSE_IN)->SecondaryAddress);
00403             break;
00404 
00405         case CBMCTRL_RESET:
00406             DBG_IRP(CBMCTRL_RESET);
00407             ntStatus = cbmiec_reset(Pdx);
00408             break;
00409 
00410         case CBMCTRL_GET_EOI:
00411             DBG_IRP(CBMCTRL_GET_EOI);
00412             returnLength = sizeof(CBMT_GET_EOI_OUT);
00413             ntStatus = cbmiec_get_eoi(Pdx, &(OUTPUTVALUE(CBMT_GET_EOI_OUT)->Decision));
00414             break;
00415 
00416         case CBMCTRL_CLEAR_EOI:
00417             DBG_IRP(CBMCTRL_CLEAR_EOI);
00418             ntStatus = cbmiec_clear_eoi(Pdx);
00419             break;
00420 
00421         case CBMCTRL_PP_READ:
00422             DBG_IRP(CBMCTRL_PP_READ);
00423             ntStatus = cbm_checkoutputbuffer(irpSp, sizeof(CBMT_PP_READ_OUT), STATUS_SUCCESS);
00424             returnLength = sizeof(CBMT_PP_READ_OUT);
00425             ntStatus = cbmiec_pp_read(Pdx, &(OUTPUTVALUE(CBMT_PP_READ_OUT)->Byte));
00426             break;
00427 
00428         case CBMCTRL_PP_WRITE:
00429             DBG_IRP(CBMCTRL_PP_WRITE);
00430             ntStatus = cbmiec_pp_write(Pdx, INPUTVALUE(CBMT_PP_WRITE_IN)->Byte);
00431             break;
00432 
00433         case CBMCTRL_IEC_POLL:
00434             DBG_IRP(CBMCTRL_IEC_POLL);
00435             returnLength = sizeof(CBMT_IEC_POLL_OUT);
00436             ntStatus = cbmiec_iec_poll(Pdx, &(OUTPUTVALUE(CBMT_IEC_POLL_OUT)->Line));
00437             break;
00438 
00439         case CBMCTRL_IEC_SET:
00440             DBG_IRP(CBMCTRL_IEC_SET);
00441             ntStatus = cbmiec_iec_set(Pdx, INPUTVALUE(CBMT_IEC_SET_IN)->Line);
00442             break;
00443 
00444         case CBMCTRL_IEC_RELEASE:
00445             DBG_IRP(CBMCTRL_IEC_RELEASE);
00446             ntStatus = cbmiec_iec_release(Pdx, INPUTVALUE(CBMT_IEC_RELEASE_IN)->Line);
00447             break;
00448 
00449         case CBMCTRL_IEC_SETRELEASE:
00450             DBG_IRP(CBMCTRL_IEC_SETRELEASE);
00451             ntStatus = cbmiec_iec_setrelease(Pdx,
00452                             INPUTVALUE(CBMT_IEC_SETRELEASE_IN)->State,
00453                             INPUTVALUE(CBMT_IEC_SETRELEASE_IN)->Line);
00454             break;
00455 
00456         case CBMCTRL_IEC_WAIT:
00457             DBG_IRP(CBMCTRL_IEC_WAIT);
00458             returnLength = sizeof(CBMT_IEC_WAIT_OUT);
00459             ntStatus = cbmiec_iec_wait(Pdx, INPUTVALUE(CBMT_IEC_WAIT_IN)->Line, 
00460                                        INPUTVALUE(CBMT_IEC_WAIT_IN)->State,
00461                                        &(OUTPUTVALUE(CBMT_IEC_WAIT_OUT)->Line));
00462             break;
00463 
00464         case CBMCTRL_PARBURST_READ:
00465             DBG_IRP(CBMCTRL_PARBURST_READ);
00466             returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
00467             ntStatus = cbmiec_parallel_burst_read(Pdx, &(OUTPUTVALUE(CBMT_PARBURST_PREAD_OUT)->Byte));
00468             break;
00469 
00470         case CBMCTRL_PARBURST_WRITE:
00471             DBG_IRP(CBMCTRL_PARBURST_READ);
00472             returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
00473             ntStatus = cbmiec_parallel_burst_write(Pdx, INPUTVALUE(CBMT_PARBURST_PWRITE_IN)->Byte);
00474             break;
00475 
00476         case CBMCTRL_PARBURST_READ_TRACK:
00477             DBG_IRP(CBMCTRL_PARBURST_READ_TRACK);
00478             returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
00479             ntStatus = cbmiec_parallel_burst_read_track(Pdx, 
00480                 Irp->AssociatedIrp.SystemBuffer, (ULONG) returnLength);
00481             break;
00482 
00483         case CBMCTRL_PARBURST_WRITE_TRACK:
00484             DBG_IRP(CBMCTRL_PARBURST_WRITE_TRACK);
00485             returnLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
00486             ntStatus = cbmiec_parallel_burst_write_track(Pdx,
00487                 Irp->AssociatedIrp.SystemBuffer, (ULONG) returnLength);
00488             break;
00489 
00490         case CBMCTRL_I_INSTALL:
00491             DBG_IRP(CBMCTRL_I_INSTALL);
00492             returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
00493             ntStatus = cbm_install(Pdx, OUTPUTVALUE(CBMT_I_INSTALL_OUT), (PULONG) &returnLength);
00494             break;
00495 
00496         case CBMCTRL_PARPORT_LOCK:
00497             DBG_IRP(CBMCTRL_PARPORT_LOCK);
00498             ntStatus = cbm_lock(Pdx);
00499             break;
00500 
00501         case CBMCTRL_PARPORT_UNLOCK:
00502             DBG_IRP(CBMCTRL_PARPORT_UNLOCK);
00503             ntStatus = cbm_unlock(Pdx);
00504             break;
00505 
00506         case CBMCTRL_UPDATE:
00507             DBG_IRP(CBMCTRL_UPDATE);
00508             cbm_init_registry(NULL, Pdx);
00509             ntStatus = STATUS_SUCCESS;
00510             break;
00511 
00512 #if DBG
00513 
00514         case CBMCTRL_I_READDBG:
00515             DBG_IRP(CBMCTRL_I_READDBG);
00516             returnLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
00517             ntStatus = cbm_dbg_readbuffer(Pdx, OUTPUTVALUE(CHAR), (PULONG) &returnLength);
00518             break;
00519 
00520 #endif // #if DBG
00521 
00522         default:
00523             // As cbm_devicecontrol() already checked the IRP,
00524             // this piece of code should never be entered. If it
00525             // is, this is a sign of a forgotten IOCTL, or a severe
00526             // programming error
00527 
00528             DBG_ERROR((DBG_PREFIX "unknown IRP_MJ_DEVICE_CONTROL"));
00529             DBG_ASSERT(("THIS SHOULD NOT HAPPEN!", 0));
00530             ntStatus = STATUS_INVALID_PARAMETER;
00531             break;
00532     }
00533 
00534     // If an error occurred, make sure not to return anything.
00535 
00536     if (!NT_SUCCESS(ntStatus))
00537     {
00538         returnLength = 0;
00539     }
00540 
00541     // Complete the request:
00542 
00543     DBG_IRPPATH_COMPLETE("Execute Ioctl");
00544     QueueCompleteIrp(&Pdx->IrpQueue, Irp, ntStatus, returnLength);
00545 
00546     FUNC_LEAVE_NTSTATUS(ntStatus);
00547 }

Generated on Sun Apr 30 18:45:54 2006 for opencbm by  doxygen 1.4.2