VOID CyapaBootWorkItem( IN WDFWORKITEM WorkItem ) { WDFDEVICE Device = (WDFDEVICE)WdfWorkItemGetParentObject(WorkItem); PDEVICE_CONTEXT pDevice = GetDeviceContext(Device); cyapa_boot_regs boot; csgesture_softc *sc = &pDevice->sc; if (!sc->infoSetup) { struct cyapa_cap cap; SpbReadDataSynchronously(&pDevice->I2CContext, CMD_QUERY_CAPABILITIES, &cap, sizeof(cap)); if (strncmp((const char *)cap.prod_ida, "CYTRA", 5) != 0) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "[cyapainit] Product ID \"%5.5s\" mismatch\n", cap.prod_ida); SpbReadDataSynchronously(&pDevice->I2CContext, CMD_QUERY_CAPABILITIES, &cap, sizeof(cap)); } sc->resx = ((cap.max_abs_xy_high << 4) & 0x0F00) | cap.max_abs_x_low; sc->resy = ((cap.max_abs_xy_high << 8) & 0x0F00) | cap.max_abs_y_low; sc->phyx = ((cap.phy_siz_xy_high << 4) & 0x0F00) | cap.phy_siz_x_low; sc->phyy = ((cap.phy_siz_xy_high << 8) & 0x0F00) | cap.phy_siz_y_low; CyapaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "[cyapainit] %5.5s-%6.6s-%2.2s buttons=%c%c%c res=%dx%d\n", cap.prod_ida, cap.prod_idb, cap.prod_idc, ((cap.buttons & CYAPA_FNGR_LEFT) ? 'L' : '-'), ((cap.buttons & CYAPA_FNGR_MIDDLE) ? 'M' : '-'), ((cap.buttons & CYAPA_FNGR_RIGHT) ? 'R' : '-'), sc->resx, sc->resy); for (int i = 0; i < 5; i++) { sc->product_id[i] = cap.prod_ida[i]; } sc->product_id[5] = '-'; for (int i = 0; i < 6; i++) { sc->product_id[i + 6] = cap.prod_idb[i]; } sc->product_id[12] = '-'; for (int i = 0; i < 2; i++) { sc->product_id[i + 13] = cap.prod_idc[i]; } sc->product_id[15] = '\0'; sprintf(sc->firmware_version, "%d.%d", cap.fw_maj_ver, cap.fw_min_ver); sc->infoSetup = true; } cyapa_set_power_mode(pDevice, CMD_POWER_MODE_FULL); SpbReadDataSynchronously(&pDevice->I2CContext, CMD_BOOT_STATUS, &boot, sizeof(boot)); WdfObjectDelete(WorkItem); }
VOID OnTopLevelIoDefault( _In_ WDFQUEUE FxQueue, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: Accepts all incoming requests and pends or forwards appropriately. Arguments: FxQueue - Handle to the framework queue object that is associated with the I/O request. FxRequest - Handle to a framework request object. Return Value: None. --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxQueue); WDFDEVICE device; PDEVICE_CONTEXT pDevice; WDF_REQUEST_PARAMETERS params; NTSTATUS status; device = WdfIoQueueGetDevice(FxQueue); pDevice = GetDeviceContext(device); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(FxRequest, ¶ms); status = WdfRequestForwardToIoQueue(FxRequest, pDevice->SpbQueue); if (!NT_SUCCESS(status)) { CyapaPrint( DEBUG_LEVEL_ERROR, DBG_IOCTL, "Failed to forward WDFREQUEST %p to SPB queue %p - %!STATUS!", FxRequest, pDevice->SpbQueue, status); WdfRequestComplete(FxRequest, status); } FuncExit(TRACE_FLAG_SPBAPI); }
VOID OnIoDeviceControl( _In_ WDFQUEUE FxQueue, _In_ WDFREQUEST FxRequest, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: FxQueue - Handle to the framework queue object that is associated with the I/O request. FxRequest - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { FuncEntry(TRACE_FLAG_SPBAPI); WDFDEVICE device; PDEVICE_CONTEXT pDevice; BOOLEAN fSync = FALSE; NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); device = WdfIoQueueGetDevice(FxQueue); pDevice = GetDeviceContext(device); CyapaPrint( DEBUG_LEVEL_INFO, DBG_IOCTL, "DeviceIoControl request %p received with IOCTL=%lu", FxRequest, IoControlCode); CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%s, Queue:0x%p, Request:0x%p\n", DbgHidInternalIoctlString(IoControlCode), FxQueue, FxRequest ); // // Translate the test IOCTL into the appropriate // SPB API method. Open and close are completed // synchronously. // switch (IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: // // Retrieves the device's HID descriptor. // status = CyapaGetHidDescriptor(device, FxRequest); fSync = TRUE; break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: // //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. // status = CyapaGetDeviceAttributes(FxRequest); fSync = TRUE; break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: // //Obtains the report descriptor for the HID device. // status = CyapaGetReportDescriptor(device, FxRequest); fSync = TRUE; break; case IOCTL_HID_GET_STRING: // // Requests that the HID minidriver retrieve a human-readable string // for either the manufacturer ID, the product ID, or the serial number // from the string descriptor of the device. The minidriver must send // a Get String Descriptor request to the device, in order to retrieve // the string descriptor, then it must extract the string at the // appropriate index from the string descriptor and return it in the // output buffer indicated by the IRP. Before sending the Get String // Descriptor request, the minidriver must retrieve the appropriate // index for the manufacturer ID, the product ID or the serial number // from the device extension of a top level collection associated with // the device. // status = CyapaGetString(FxRequest); fSync = TRUE; break; case IOCTL_HID_WRITE_REPORT: case IOCTL_HID_SET_OUTPUT_REPORT: // //Transmits a class driver-supplied report to the device. // status = CyapaWriteReport(pDevice, FxRequest); fSync = TRUE; break; case IOCTL_HID_READ_REPORT: case IOCTL_HID_GET_INPUT_REPORT: // // Returns a report from the device into a class driver-supplied buffer. // status = CyapaReadReport(pDevice, FxRequest, &fSync); break; case IOCTL_HID_GET_FEATURE: // // returns a feature report associated with a top-level collection // status = CyapaGetFeature(pDevice, FxRequest, &fSync); break; case IOCTL_HID_ACTIVATE_DEVICE: // // Makes the device ready for I/O operations. // case IOCTL_HID_DEACTIVATE_DEVICE: // // Causes the device to cease operations and terminate all outstanding // I/O requests. // default: fSync = TRUE; status = STATUS_NOT_SUPPORTED; CyapaPrint( DEBUG_LEVEL_INFO, DBG_IOCTL, "Request %p received with unexpected IOCTL=%lu", FxRequest, IoControlCode); } // // Complete the request if necessary. // if (fSync) { CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%s completed, Queue:0x%p, Request:0x%p\n", DbgHidInternalIoctlString(IoControlCode), FxQueue, FxRequest ); WdfRequestComplete(FxRequest, status); } else { CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%s deferred, Queue:0x%p, Request:0x%p\n", DbgHidInternalIoctlString(IoControlCode), FxQueue, FxRequest ); } FuncExit(TRACE_FLAG_SPBAPI); }
NTSTATUS OnDeviceAdd( _In_ WDFDRIVER FxDriver, _Inout_ PWDFDEVICE_INIT FxDeviceInit ) /*++ Routine Description: This routine creates the device object for an SPB controller and the device's child objects. Arguments: FxDriver - the WDF driver object handle FxDeviceInit - information about the PDO that we are loading on Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); PDEVICE_CONTEXT pDevice; WDFDEVICE fxDevice; WDF_INTERRUPT_CONFIG interruptConfig; NTSTATUS status; UNREFERENCED_PARAMETER(FxDriver); // // Tell framework this is a filter driver. Filter drivers by default are // not power policy owners. This works well for this driver because // HIDclass driver is the power policy owner for HID minidrivers. // WdfFdoInitSetFilter(FxDeviceInit); // // Setup PNP/Power callbacks. // { WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(FxDeviceInit, &pnpCallbacks); } // // Set request attributes. // { WDF_OBJECT_ATTRIBUTES attributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &attributes, REQUEST_CONTEXT); WdfDeviceInitSetRequestAttributes(FxDeviceInit, &attributes); } // // Create the device. // { WDF_OBJECT_ATTRIBUTES deviceAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate( &FxDeviceInit, &deviceAttributes, &fxDevice); if (!NT_SUCCESS(status)) { CyapaPrint( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "Error creating WDFDEVICE - %!STATUS!", status); goto exit; } pDevice = GetDeviceContext(fxDevice); NT_ASSERT(pDevice != nullptr); pDevice->FxDevice = fxDevice; } // // Ensure device is disable-able // { WDF_DEVICE_STATE deviceState; WDF_DEVICE_STATE_INIT(&deviceState); deviceState.NotDisableable = WdfFalse; WdfDeviceSetDeviceState(pDevice->FxDevice, &deviceState); } // // Create queues to handle IO // { WDF_IO_QUEUE_CONFIG queueConfig; WDFQUEUE queue; // // Top-level queue // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoDefault = OnTopLevelIoDefault; queueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate( pDevice->FxDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue ); if (!NT_SUCCESS(status)) { CyapaPrint( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "Error creating top-level IO queue - %!STATUS!", status); goto exit; } // // Sequential SPB queue // WDF_IO_QUEUE_CONFIG_INIT( &queueConfig, WdfIoQueueDispatchSequential); queueConfig.EvtIoInternalDeviceControl = OnIoDeviceControl; queueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate( fxDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevice->SpbQueue ); if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto exit; } } WDF_IO_QUEUE_CONFIG queueConfig; WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); queueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate(pDevice->FxDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevice->ReportQueue ); if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Queue 2!\n"); CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); return status; } // // Create an interrupt object for hardware notifications // WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, OnInterruptIsr, NULL); interruptConfig.PassiveHandling = TRUE; status = WdfInterruptCreate( fxDevice, &interruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevice->Interrupt); if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Error creating WDF interrupt object - %!STATUS!", status); goto exit; } WDF_TIMER_CONFIG timerConfig; WDFTIMER hTimer; WDF_OBJECT_ATTRIBUTES attributes; WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, CyapaTimerFunc, 10); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = fxDevice; status = WdfTimerCreate(&timerConfig, &attributes, &hTimer); pDevice->Timer = hTimer; if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "(%!FUNC!) WdfTimerCreate failed status:%!STATUS!\n", status); return status; } CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Success! 0x%x\n", status); pDevice->DeviceMode = DEVICE_MODE_MOUSE; exit: FuncExit(TRACE_FLAG_WDFLOADING); return status; }
void TrackpadRawInput(PDEVICE_CONTEXT pDevice, struct cyapa_softc *sc, struct cyapa_regs *regs, int tickinc){ int nfingers; int afingers; /* actual fingers after culling */ int i; nfingers = CYAPA_FNGR_NUMFINGERS(regs->fngr); afingers = nfingers; // system("cls"); #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "stat %02x\tTracking ID: %d\tbuttons %c%c%c\tnfngrs=%d\n", regs->stat, regs->touch->id, ((regs->fngr & CYAPA_FNGR_LEFT) ? 'L' : '-'), ((regs->fngr & CYAPA_FNGR_MIDDLE) ? 'M' : '-'), ((regs->fngr & CYAPA_FNGR_RIGHT) ? 'R' : '-'), nfingers ); #endif for (i = 0; i < nfingers; ++i) { #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, " [x=%04d y=%04d p=%d]\n", CYAPA_TOUCH_X(regs, i), CYAPA_TOUCH_Y(regs, i), CYAPA_TOUCH_P(regs, i)); if (CYAPA_TOUCH_Y(regs, i) > 400){ if (CYAPA_TOUCH_X(regs, i) < 400){ CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Simulate left hardware button! %d\n", CYAPA_TOUCH_Y(regs, i)); } else { CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Simulate right hardware button! %d\n", CYAPA_TOUCH_Y(regs, i)); } } #endif if (CYAPA_TOUCH_P(regs, i) < cyapa_minpressure) --afingers; } if (regs->touch->id != sc->lastid){ sc->x = 0; sc->y = 0; sc->lastid = regs->touch->id; } int x = sc->x; int y = sc->y; bool overrideDeltas = false; if (afingers > 0){ #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Tick inc.\n"); #endif sc->tick += tickinc; x = CYAPA_TOUCH_X(regs, 0); y = CYAPA_TOUCH_Y(regs, 0); if (afingers > 1){ int x1 = CYAPA_TOUCH_X(regs, 0); int y1 = CYAPA_TOUCH_Y(regs, 0); int x2 = CYAPA_TOUCH_X(regs, 1); int y2 = CYAPA_TOUCH_Y(regs, 1); int d1 = distancesq(x1 - sc->x, y1 - sc->y); int d2 = distancesq(x1 - sc->x, y1 - sc->y); if (d2 < d1 || (y > 400 && y2 < 400)){ x = x2; y = y2; } #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%d %d\t%d %d\t%d %d\n", x, y, x1, y1, x2, y2); #endif } else { if (sc->mousedown && y > 400){ overrideDeltas = true; sc->x = 0; sc->y = 0; } } if ((overrideDeltas != true) && (sc->x == 0 && sc->y == 0)){ sc->x = x; sc->y = y; } } else { if (sc->tick < 10 && sc->tick != 0){ INPUT input; if (sc->lastnfingers == 1){ sc->mousebutton = 0; } else if (sc->lastnfingers == 2){ sc->mousebutton = 1; } else if (sc->lastnfingers == 3){ sc->mousebutton = 2; } else if (sc->lastnfingers == 4){ sc->mousebutton = 3; } input.mi.dx = 0; input.mi.dy = 0; input.mi.mouseData = 0; sc->mousedown = true; MySendInput(pDevice, &input, sc); sc->tickssincelastclick = 0; #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Tap to Click!\n"); #endif } sc->tick = 0; sc->hasmoved = false; sc->mousedownfromtap = false; sc->tickssincelastclick+=tickinc; #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Move Reset!\n"); #endif } int delta_x = x - sc->x, delta_y = y - sc->y; if (abs(delta_x) + abs(delta_y) > 10 && !sc->hasmoved){ sc->hasmoved = true; if (sc->tickssincelastclick < 10 && sc->tickssincelastclick >= 0){ INPUT input; input.mi.dx = 0; input.mi.dy = 0; input.mi.mouseData = 0; MySendInput(pDevice, &input, sc); sc->mousebutton = 0; sc->mousedown = true; sc->mousedownfromtap = true; sc->tickssincelastclick = 0; #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Move from tap!\n"); #endif } #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "Has moved!\n"); #endif } if (overrideDeltas){ delta_x = 0; delta_y = 0; } sc->lastnfingers = nfingers; if (CYAPA_TOUCH_P(regs, 0) < 20) sc->tick -= tickinc; if (CYAPA_TOUCH_P(regs, 0) < 10) sc->tick = 0; else if (sc->hasmoved) sc->tick = 0; if (sc->tick < 0) sc->tick = 0; INPUT input; if (afingers < 2 || sc->mousedown){ input.mi.dx = (BYTE)delta_x; input.mi.dy = (BYTE)delta_y; input.mi.dwFlags = MOUSEEVENTF_MOVE; if (delta_x != 0 && delta_y != 0) MySendInput(pDevice, &input, sc); } else if (afingers == 2){ if (abs(delta_x) > abs(delta_y)){ input.mi.dwFlags = MOUSEEVENTF_HWHEEL; input.mi.mouseData = (BYTE)-delta_x; MySendInput(pDevice, &input, sc); } else if (abs(delta_y) > abs(delta_x)){ input.mi.dwFlags = MOUSEEVENTF_WHEEL; input.mi.mouseData = (BYTE)delta_y; MySendInput(pDevice, &input, sc); } } else if (afingers == 3){ if (sc->hasmoved){ sc->multitaskingx += delta_x; sc->multitaskingy += delta_y; if (sc->multitaskinggesturetick > 5 && !sc->multitaskingdone){ if (abs(sc->multitaskingx) > abs(sc->multitaskingy)){ BYTE shiftKeys = KBD_LGUI_BIT | KBD_LCONTROL_BIT; BYTE keyCodes[KBD_KEY_CODES] = { 0, 0, 0, 0, 0, 0 }; if (sc->multitaskingx > 0) keyCodes[0] = 0x50; else keyCodes[0] = 0x4F; update_keyboard(pDevice, shiftKeys, keyCodes); shiftKeys = 0; keyCodes[0] = 0x0; update_keyboard(pDevice, shiftKeys, keyCodes); } else if (abs(sc->multitaskingy) > abs(sc->multitaskingx)){ BYTE shiftKeys = KBD_LGUI_BIT; BYTE keyCodes[KBD_KEY_CODES] = { 0, 0, 0, 0, 0, 0 }; if (sc->multitaskingy < 0) keyCodes[0] = 0x2B; else keyCodes[0] = 0x07; update_keyboard(pDevice, shiftKeys, keyCodes); shiftKeys = 0; keyCodes[0] = 0x0; update_keyboard(pDevice, shiftKeys, keyCodes); } sc->multitaskingdone = true; sc->multitaskinggesturetick = -1; } else if (sc->multitaskingdone){ if (sc->multitaskinggesturetick > 25){ sc->multitaskinggesturetick = -1; sc->multitaskingx = 0; sc->multitaskingy = 0; sc->multitaskingdone = false; } } #ifdef DEBUG CyapaPrint(DEBUG_LEVEL_INFO,DBG_IOCTL,"Multitasking Gestures!\n"); #endif sc->multitaskinggesturetick++; } } if (afingers != 3){ sc->multitaskinggesturetick = 0; sc->multitaskingx = 0; sc->multitaskingy = 0; sc->multitaskingdone = false; } if (afingers > 0){ if ((regs->fngr & CYAPA_FNGR_LEFT) != 0 && sc->mousedown == false){ sc->mousedown = true; if (afingers == 1){ if (sc->y < 400 || sc->x < 400){ sc->mousebutton = 0; } else { sc->mousebutton = 1; } } else if (afingers == 2){ sc->mousebutton = 1; } else if (afingers == 3){ sc->mousebutton = 2; } else if (afingers == 4){ sc->mousebutton = 3; } input.mi.dx = 0; input.mi.dy = 0; input.mi.mouseData = 0; MySendInput(pDevice, &input, sc); } if (!overrideDeltas){ sc->x = x; sc->y = y; } } else { if (!overrideDeltas){ sc->x = 0; sc->y = 0; } } if ((regs->fngr & CYAPA_FNGR_LEFT) == 0 && sc->mousedown == true && sc->mousedownfromtap != true){ sc->mousedown = false; if (sc->mousebutton == 3){ BYTE shiftKeys = KBD_LGUI_BIT; BYTE keyCodes[KBD_KEY_CODES] = { 0x04, 0, 0, 0, 0, 0 }; update_keyboard(pDevice, shiftKeys, keyCodes); shiftKeys = 0; keyCodes[0] = 0x0; update_keyboard(pDevice, shiftKeys, keyCodes); } sc->mousebutton = 0; input.mi.dx = 0; input.mi.dy = 0; input.mi.mouseData = 0; MySendInput(pDevice, &input, sc); } }