mirror of
https://github.com/zsa/qmk_firmware.git
synced 2026-01-09 15:12:33 +00:00
feat: adds navigator trackball driver
This commit is contained in:
@@ -123,7 +123,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
|
||||
MOUSE_ENABLE := yes
|
||||
endif
|
||||
|
||||
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick azoteq_iqs5xx cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3320 pmw3360 pmw3389 pimoroni_trackball custom
|
||||
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick azoteq_iqs5xx cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3320 pmw3360 pmw3389 pimoroni_trackball navigator_trackball custom
|
||||
ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
|
||||
ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type)
|
||||
@@ -160,6 +160,9 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
|
||||
else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),)
|
||||
SPI_DRIVER_REQUIRED = yes
|
||||
SRC += drivers/sensors/pmw33xx_common.c
|
||||
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), navigator_trackball)
|
||||
I2C_DRIVER_REQUIRED = yes
|
||||
SRC += drivers/sensors/navigator.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
44
drivers/sensors/navigator.c
Normal file
44
drivers/sensors/navigator.c
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2025 ZSA Technology Labs, Inc <contact@zsa.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "quantum.h"
|
||||
#include "navigator.h"
|
||||
|
||||
float scroll_accumulated_h = 0;
|
||||
float scroll_accumulated_v = 0;
|
||||
|
||||
bool set_scrolling = false;
|
||||
bool navigator_turbo = false;
|
||||
bool navigator_aim = false;
|
||||
|
||||
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
|
||||
// Turbo mode is used to increase the speed of the mouse cursor
|
||||
// by multiplying the x and y values by a factor.
|
||||
if (navigator_turbo) {
|
||||
mouse_report.x *= NAVIGATOR_TURBO_MULTIPLIER;
|
||||
mouse_report.y *= NAVIGATOR_TURBO_MULTIPLIER;
|
||||
}
|
||||
// Aim mode is used to slow down the mouse cursor
|
||||
// by dividing the x and y values by a factor.
|
||||
if (navigator_aim) {
|
||||
mouse_report.x /= NAVIGATOR_AIM_DIVIDER;
|
||||
mouse_report.y /= NAVIGATOR_AIM_DIVIDER;
|
||||
}
|
||||
if (set_scrolling) {
|
||||
scroll_accumulated_h += (float)mouse_report.x / NAVIGATOR_SCROLL_DIVIDER;
|
||||
scroll_accumulated_v += (float)mouse_report.y / NAVIGATOR_SCROLL_DIVIDER;
|
||||
mouse_report.h = (int8_t)scroll_accumulated_h;
|
||||
#ifdef NAVIGATOR_SCROLL_INVERT
|
||||
mouse_report.v = (int8_t)-scroll_accumulated_v;
|
||||
#else
|
||||
mouse_report.v = (int8_t)scroll_accumulated_v;
|
||||
#endif
|
||||
|
||||
scroll_accumulated_h -= (int8_t)scroll_accumulated_h;
|
||||
scroll_accumulated_v -= (int8_t)scroll_accumulated_v;
|
||||
|
||||
mouse_report.x = 0;
|
||||
mouse_report.y = 0;
|
||||
}
|
||||
return mouse_report;
|
||||
}
|
||||
17
drivers/sensors/navigator.h
Normal file
17
drivers/sensors/navigator.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2025 ZSA Technology Labs, Inc <contact@zsa.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#ifndef NAVIGATOR_SCROLL_DIVIDER
|
||||
#define NAVIGATOR_SCROLL_DIVIDER 10
|
||||
#endif
|
||||
|
||||
#ifdef POINTING_DEVICE_DRIVER_navigator_trackball
|
||||
#define NAVIGATOR_TURBO_MULTIPLIER 3
|
||||
#define NAVIGATOR_AIM_DIVIDER 3
|
||||
#endif
|
||||
|
||||
#ifdef POINTING_DEVICE_DRIVER_navigator_trackpad
|
||||
#define NAVIGATOR_TURBO_MULTIPLIER 2
|
||||
#define NAVIGATOR_AIM_DIVIDER 2
|
||||
#endif
|
||||
281
drivers/sensors/navigator_trackball.c
Normal file
281
drivers/sensors/navigator_trackball.c
Normal file
@@ -0,0 +1,281 @@
|
||||
// Copyright 2025 ZSA Technology Labs, Inc <contact@zsa.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// This is the QMK driver for the Navigator Trackball. It is comprised of two ICs:
|
||||
// 1. The sci18is606 is a i2c to spi bridge that converts the i2c protocol to the spi protocol. It allows the trackball to
|
||||
// be plugged using the TRRS jack used by ZSA keyboards or any other split keyboard.
|
||||
// 2. The paw3805ek is a high-speed motion detection sensor. It is used to detect the motion of the trackball.
|
||||
|
||||
#include "i2c_master.h"
|
||||
#include "navigator_trackball.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "quantum.h"
|
||||
|
||||
const pointing_device_driver_t navigator_trackball_pointing_device_driver = {
|
||||
.init = navigator_trackball_device_init,
|
||||
.get_report = navigator_trackball_get_report,
|
||||
.get_cpi = navigator_trackball_get_cpi,
|
||||
.set_cpi = navigator_trackball_set_cpi
|
||||
};
|
||||
|
||||
uint8_t current_cpi = DEFAULT_CPI_TICK;
|
||||
|
||||
uint8_t has_motion = 0;
|
||||
|
||||
uint8_t trackball_init = 0;
|
||||
|
||||
deferred_token callback_token = 0;
|
||||
|
||||
// The sequence of commands to configure and boot the paw3805ek sensor.
|
||||
paw3805ek_reg_seq_t paw3805ek_configure_seq[] = {
|
||||
{0x06, 0x80}, // Software reset
|
||||
{0x00, 0x00}, // Request the sensor ID
|
||||
{0x09 | WRITE_REG_BIT, 0x5A}, // Disable the write protection
|
||||
#ifdef MOUSE_EXTENDED_REPORT
|
||||
{0x19 | WRITE_REG_BIT, 0x30}, // Set the sensor orientation, set motion data length to 16 bits
|
||||
#else
|
||||
{0x19 | WRITE_REG_BIT, 0x34}, // Set the sensor orientation, set motion data length to 8 bits
|
||||
#endif
|
||||
//{0x26 | WRITE_REG_BIT, 0x10}, // Enable burst mode
|
||||
{0x09 | WRITE_REG_BIT, 0x00}, // Enable the write protection
|
||||
};
|
||||
|
||||
// A wrapper function for i2c_transmit that adds the address of the bridge chip to the data.
|
||||
i2c_status_t sci18is606_write(uint8_t *data, uint8_t length) {
|
||||
return i2c_transmit(NAVIGATOR_TRACKBALL_ADDRESS, data, length, NAVIGATOR_TRACKBALL_TIMEOUT);
|
||||
}
|
||||
|
||||
// A wrapper function for i2c_receive that adds the address of the bridge chip to the data.
|
||||
i2c_status_t sci18is606_read(uint8_t *data, uint8_t length) {
|
||||
return i2c_receive(NAVIGATOR_TRACKBALL_ADDRESS, data, length, NAVIGATOR_TRACKBALL_TIMEOUT);
|
||||
}
|
||||
|
||||
// A wrapper function that allows to write and optionally read from the bridge chip.
|
||||
i2c_status_t sci18is606_spi_tx(uint8_t *data, uint8_t length, bool read) {
|
||||
i2c_status_t status = sci18is606_write(data, length);
|
||||
wait_us(length * 15);
|
||||
// Read the SPI response if the command expects it
|
||||
if (read) {
|
||||
status = sci18is606_read(data, length);
|
||||
}
|
||||
if (status != I2C_STATUS_SUCCESS) {
|
||||
trackball_init = 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Configure the bridge chip to enable SPI mode.
|
||||
i2c_status_t sci18is606_configure(void) {
|
||||
uint8_t spi_conf[2] = {SCI18IS606_CONF_SPI, SCI18IS606_CONF};
|
||||
i2c_status_t status = sci18is606_write(spi_conf, 2);
|
||||
wait_ms(10);
|
||||
if (status != I2C_STATUS_SUCCESS) {
|
||||
trackball_init = 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool paw3805ek_set_cpi(void) {
|
||||
uint8_t next_cpi_x = 0;
|
||||
uint8_t next_cpi_y = 0;
|
||||
// traverse the sequence by compairing the cpi_x value with the current cpi_x value
|
||||
// set the cpi to the next value in the sequence
|
||||
switch (current_cpi) {
|
||||
case 1: {
|
||||
next_cpi_x = CPI_X_800;
|
||||
next_cpi_y = CPI_Y_800;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
next_cpi_x = CPI_X_1000;
|
||||
next_cpi_y = CPI_Y_1000;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
next_cpi_x = CPI_X_1200;
|
||||
next_cpi_y = CPI_Y_1200;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
next_cpi_x = CPI_X_1600;
|
||||
next_cpi_y = CPI_Y_1600;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
next_cpi_x = CPI_X_2000;
|
||||
next_cpi_y = CPI_Y_2000;
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
next_cpi_x = CPI_X_2400;
|
||||
next_cpi_y = CPI_Y_2400;
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
next_cpi_x = CPI_X_3000;
|
||||
next_cpi_y = CPI_Y_3000;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
current_cpi = DEFAULT_CPI_TICK;
|
||||
next_cpi_x = CPI_X_800;
|
||||
next_cpi_y = CPI_Y_800;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
paw3805ek_reg_seq_t cpi_reg_seq[] = {
|
||||
{0x09 | WRITE_REG_BIT, 0x5A}, // Disable write protection
|
||||
{0x0D | WRITE_REG_BIT, next_cpi_x},
|
||||
{0x0E | WRITE_REG_BIT, next_cpi_y},
|
||||
{0x09 | WRITE_REG_BIT, 0x00}, // Enable the write protection
|
||||
};
|
||||
|
||||
// Run the spi sequence to configure the cpi.
|
||||
for (uint8_t i = 0; i < sizeof(cpi_reg_seq) / sizeof(paw3805ek_reg_seq_t); i++) {
|
||||
uint8_t buf[3];
|
||||
buf[0] = NCS_PIN;
|
||||
buf[1] = cpi_reg_seq[i].reg;
|
||||
buf[2] = cpi_reg_seq[i].data;
|
||||
if (sci18is606_spi_tx(buf, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Run the paw3805ek configuration sequence.
|
||||
bool paw3805ek_configure(void) {
|
||||
for (uint8_t i = 0; i < sizeof(paw3805ek_configure_seq) / sizeof(paw3805ek_reg_seq_t); i++) {
|
||||
uint8_t buf[3];
|
||||
buf[0] = NCS_PIN;
|
||||
buf[1] = paw3805ek_configure_seq[i].reg;
|
||||
buf[2] = paw3805ek_configure_seq[i].data;
|
||||
if (sci18is606_spi_tx(buf, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
// Wait for the sensor to restart after the software reset cmd
|
||||
wait_ms(1);
|
||||
|
||||
// Check the sensor ID to validate the spi link after the reset
|
||||
if (i == 1 && buf[1] != PAW3805EK_ID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Assert the CS pin to read the motion register.
|
||||
bool paw3805ek_has_motion(void) {
|
||||
uint8_t motion[3] = {0x01, 0x02, 0x00};
|
||||
if (sci18is606_spi_tx(motion, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
return motion[1] & 0x80;
|
||||
}
|
||||
|
||||
// Read the motion data from the paw3805ek sensor.
|
||||
void paw3804ek_read_motion(report_mouse_t *mouse_report) {
|
||||
#ifdef MOUSE_EXTENDED_REPORT
|
||||
uint8_t delta_x_l[2] = {0x01, 0x03};
|
||||
if (sci18is606_spi_tx(delta_x_l, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t delta_y_l[2] = {0x01, 0x04};
|
||||
if (sci18is606_spi_tx(delta_y_l, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t delta_x_h[2] = {0x01, 0x11};
|
||||
if (sci18is606_spi_tx(delta_x_h, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t delta_y_h[2] = {0x01, 0x12};
|
||||
if (sci18is606_spi_tx(delta_y_h, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
mouse_report->x = (int16_t)((delta_x_h[1] << 8) | delta_x_l[1]);
|
||||
mouse_report->y = (int16_t)((delta_y_h[1] << 8) | delta_y_l[1]);
|
||||
#else
|
||||
uint8_t delta_x[2] = {0x01, 0x03};
|
||||
if (sci18is606_spi_tx(delta_x, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t delta_y[2] = {0x01, 0x04};
|
||||
if (sci18is606_spi_tx(delta_y, 3, true) != I2C_STATUS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
mouse_report->x = delta_x[1];
|
||||
mouse_report->y = delta_y[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deffered execution callback that periodically checks for motion.
|
||||
uint32_t sci18is606_read_callback(uint32_t trigger_time, void *cb_arg) {
|
||||
if (!trackball_init) {
|
||||
navigator_trackball_device_init();
|
||||
return NAVIGATOR_TRACKBALL_PROBE;
|
||||
}
|
||||
if (paw3805ek_has_motion()) {
|
||||
has_motion = 1;
|
||||
}
|
||||
return NAVIGATOR_TRACKBALL_READ;
|
||||
}
|
||||
|
||||
void navigator_trackball_device_init(void) {
|
||||
i2c_init();
|
||||
if (sci18is606_configure() == I2C_STATUS_SUCCESS) {
|
||||
paw3805ek_configure();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
trackball_init = 1;
|
||||
if (!callback_token) {
|
||||
// Register the callback to read the trackball motion
|
||||
callback_token = defer_exec(NAVIGATOR_TRACKBALL_READ, sci18is606_read_callback, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
report_mouse_t navigator_trackball_get_report(report_mouse_t mouse_report) {
|
||||
if (!trackball_init) {
|
||||
return mouse_report;
|
||||
}
|
||||
|
||||
if (has_motion) {
|
||||
has_motion = 0;
|
||||
paw3804ek_read_motion(&mouse_report);
|
||||
}
|
||||
return mouse_report;
|
||||
}
|
||||
|
||||
uint16_t navigator_trackball_get_cpi(void) {
|
||||
return current_cpi;
|
||||
}
|
||||
|
||||
void restore_cpi(uint8_t cpi) {
|
||||
current_cpi = cpi;
|
||||
paw3805ek_set_cpi();
|
||||
}
|
||||
|
||||
void navigator_trackball_set_cpi(uint16_t cpi) {
|
||||
if (cpi == 0) { // Decrease one tick
|
||||
if (current_cpi > 1) {
|
||||
current_cpi--;
|
||||
paw3805ek_set_cpi();
|
||||
}
|
||||
} else {
|
||||
if (current_cpi < CPI_TICKS) {
|
||||
current_cpi++;
|
||||
paw3805ek_set_cpi();
|
||||
}
|
||||
}
|
||||
};
|
||||
70
drivers/sensors/navigator_trackball.h
Normal file
70
drivers/sensors/navigator_trackball.h
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2025 ZSA Technology Labs, Inc <contact@zsa.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "pointing_device.h"
|
||||
|
||||
#ifndef NAVIGATOR_TRACKBALL_ADDRESS
|
||||
# define NAVIGATOR_TRACKBALL_ADDRESS 0x50
|
||||
#endif
|
||||
|
||||
#ifndef NAVIGATOR_TRACKBALL_TIMEOUT
|
||||
# define NAVIGATOR_TRACKBALL_TIMEOUT 100
|
||||
#endif
|
||||
|
||||
#define NAVIGATOR_TRACKBALL_READ 7
|
||||
#define NAVIGATOR_TRACKBALL_PROBE 1000
|
||||
|
||||
#define NCS_PIN 0x01
|
||||
#define PAW3805EK_ID 0x31
|
||||
|
||||
#define SCI18IS606_CONF 0xDC //00001110b // MSB first, Mode 3, 155kHz
|
||||
|
||||
#define SCI18IS606_RW_SPI 0x00
|
||||
#define SCI18IS606_CONF_SPI 0xF0
|
||||
#define SCI18IS606_CLR_INT 0xF1
|
||||
#define SCI18IS606_GET_ID 0xFE
|
||||
|
||||
#define WRITE_REG_BIT 0x80
|
||||
/*
|
||||
The PAW3805EK datasheet suggests the following CPI values for the X and Y axes:
|
||||
CPI X-axis Y-axis
|
||||
800 0x1F 0x22
|
||||
1000 0x26 0x2A
|
||||
1200 0x2E 0x32
|
||||
1600 0x3C 0x43
|
||||
2000 0x4C 0x54
|
||||
2400 0x5B 0x64
|
||||
3000 0x70 0x7B
|
||||
*/
|
||||
#define CPI_TICKS 7
|
||||
#define DEFAULT_CPI_TICK 1
|
||||
#define CPI_X_800 0x1F
|
||||
#define CPI_Y_800 0x22
|
||||
#define CPI_X_1000 0x26
|
||||
#define CPI_Y_1000 0x2A
|
||||
#define CPI_X_1200 0x2E
|
||||
#define CPI_Y_1200 0x32
|
||||
#define CPI_X_1600 0x3C
|
||||
#define CPI_Y_1600 0x43
|
||||
#define CPI_X_2000 0x4C
|
||||
#define CPI_Y_2000 0x54
|
||||
#define CPI_X_2400 0x5B
|
||||
#define CPI_Y_2400 0x64
|
||||
#define CPI_X_3000 0x70
|
||||
#define CPI_Y_3000 0x7B
|
||||
|
||||
typedef struct {
|
||||
uint8_t reg;
|
||||
uint8_t data;
|
||||
} paw3805ek_reg_seq_t;
|
||||
|
||||
const pointing_device_driver_t navigator_trackball_pointing_device_driver;
|
||||
|
||||
void navigator_trackball_device_init(void);
|
||||
report_mouse_t navigator_trackball_get_report(report_mouse_t mouse_report);
|
||||
uint16_t navigator_trackball_get_cpi(void);
|
||||
void navigator_trackball_set_cpi(uint16_t cpi);
|
||||
void restore_cpi(uint8_t cpi);
|
||||
@@ -304,6 +304,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
|
||||
void eeconfig_init_kb(void) { // EEPROM is getting reset!
|
||||
keyboard_config.raw = 0;
|
||||
keyboard_config.led_level = 4;
|
||||
keyboard_config.navigator_cpi = 3;
|
||||
eeconfig_update_kb(keyboard_config.raw);
|
||||
eeconfig_init_user();
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef union {
|
||||
struct {
|
||||
uint8_t led_level : 3;
|
||||
bool disable_layer_led : 1;
|
||||
uint8_t navigator_cpi : 3;
|
||||
bool placeholder : 1;
|
||||
};
|
||||
} keyboard_config_t;
|
||||
|
||||
@@ -466,6 +466,7 @@ void eeconfig_init_kb(void) { // EEPROM is getting reset!
|
||||
keyboard_config.rgb_matrix_enable = true;
|
||||
keyboard_config.led_level = true;
|
||||
keyboard_config.led_level_res = 0b11;
|
||||
keyboard_config.navigator_cpi = 3;
|
||||
eeconfig_update_kb(keyboard_config.raw);
|
||||
eeconfig_init_user();
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ typedef union {
|
||||
bool rgb_matrix_enable :1;
|
||||
bool led_level :1;
|
||||
uint8_t led_level_res :2; // DO NOT REMOVE
|
||||
uint8_t navigator_cpi :3;
|
||||
|
||||
};
|
||||
} keyboard_config_t;
|
||||
|
||||
|
||||
@@ -301,6 +301,7 @@ void eeconfig_init_kb(void) { // EEPROM is getting reset!
|
||||
keyboard_config.raw = 0;
|
||||
keyboard_config.led_level = true;
|
||||
keyboard_config.led_level_res = 0b11;
|
||||
keyboard_config.navigator_cpi = 3;
|
||||
eeconfig_update_kb(keyboard_config.raw);
|
||||
eeconfig_init_user();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "quantum.h"
|
||||
|
||||
extern bool mcp23018_leds[];
|
||||
@@ -19,7 +20,7 @@ typedef union {
|
||||
uint32_t raw;
|
||||
struct {
|
||||
bool disable_layer_led : 1;
|
||||
bool placeholder : 1;
|
||||
uint8_t navigator_cpi : 3;
|
||||
bool led_level : 1;
|
||||
uint8_t led_level_res : 2; // DO NOT REMOVE
|
||||
};
|
||||
|
||||
@@ -74,6 +74,9 @@ typedef struct {
|
||||
# include "spi_master.h"
|
||||
# include "drivers/sensors/pmw33xx_common.h"
|
||||
# define POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
|
||||
elif defined(POINTING_DEVICE_DRIVER_navigator_trackball)
|
||||
# include "i2c_master.h"
|
||||
# include "drivers/sensors/navigator_trackball.h"
|
||||
#else
|
||||
void pointing_device_driver_init(void);
|
||||
report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report);
|
||||
|
||||
Reference in New Issue
Block a user