forked from nikkuss/x1e-nixos
init
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2020 Microsoft Corporation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 as published by
|
||||
# the Free Software Foundation.
|
||||
#
|
||||
|
||||
config SPI_HID
|
||||
tristate "HID over SPI transport layer"
|
||||
default n
|
||||
help
|
||||
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
|
||||
other HID based devices which is connected to your computer via SPI.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called spi-hid.
|
||||
@@ -0,0 +1,16 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m += spi-hid.o
|
||||
spi-hid-objs := spi-hid-core.o
|
||||
else
|
||||
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
|
||||
|
||||
install:
|
||||
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
|
||||
endif
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Stub hid-ids.h for out-of-tree spi-hid build
|
||||
* The actual hid-ids.h is not needed by spi-hid driver
|
||||
*/
|
||||
#ifndef HID_IDS_H_FILE
|
||||
#define HID_IDS_H_FILE
|
||||
|
||||
/* Empty stub - spi-hid doesn't use any HID vendor/device IDs */
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* HID over SPI (HIDSPI v3) transport driver for QSPI touchpads.
|
||||
*
|
||||
* Based on Microsoft's spi-hid v2 driver.
|
||||
* Copyright (c) 2020 Microsoft Corporation
|
||||
*/
|
||||
|
||||
#ifndef SPI_HID_CORE_H
|
||||
#define SPI_HID_CORE_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SPI_HID_INPUT_HEADER_SYNC_BYTE 0x5A
|
||||
#define SPI_HID_INPUT_HEADER_VERSION 0x03
|
||||
|
||||
#define SPI_HID_QSPI_READ_OPCODE 0xEB
|
||||
#define SPI_HID_QSPI_WRITE_OPCODE 0xE2
|
||||
#define SPI_HID_QSPI_CMD_LEN 4
|
||||
|
||||
#define SPI_HID_INPUT_HDR_ADDR 0x1000
|
||||
#define SPI_HID_INPUT_BDY_ADDR 0x1004
|
||||
#define SPI_HID_OUTPUT_ADDR 0x2000
|
||||
|
||||
#define SPI_HID_SUPPORTED_VERSION 0x0300
|
||||
|
||||
#define SPI_HID_BODY_HEADER_LEN 4
|
||||
|
||||
/* Input report types (device -> host) */
|
||||
#define SPI_HID_REPORT_TYPE_DATA 0x01
|
||||
#define SPI_HID_REPORT_TYPE_RESET_RESP 0x03
|
||||
#define SPI_HID_REPORT_TYPE_COMMAND_RESP 0x04
|
||||
#define SPI_HID_REPORT_TYPE_GET_FEATURE_RESP 0x05
|
||||
#define SPI_HID_REPORT_TYPE_DEVICE_DESC 0x07
|
||||
#define SPI_HID_REPORT_TYPE_REPORT_DESC 0x08
|
||||
#define SPI_HID_REPORT_TYPE_SET_FEATURE_RESP 0x09
|
||||
#define SPI_HID_REPORT_TYPE_OUTPUT_REPORT_RESP 0x0A
|
||||
#define SPI_HID_REPORT_TYPE_GET_INPUT_RESP 0x0B
|
||||
|
||||
/* Output report types (host -> device) */
|
||||
#define SPI_HID_OUT_DEVICE_DESC 0x01
|
||||
#define SPI_HID_OUT_REPORT_DESC 0x02
|
||||
#define SPI_HID_OUT_SET_FEATURE 0x03
|
||||
#define SPI_HID_OUT_GET_FEATURE 0x04
|
||||
#define SPI_HID_OUT_OUTPUT_REPORT 0x05
|
||||
#define SPI_HID_OUT_GET_INPUT_REPORT 0x06
|
||||
#define SPI_HID_OUT_COMMAND_CONTENT 0x07
|
||||
|
||||
#define SPI_HID_POWER_MODE_ACTIVE 0x01
|
||||
#define SPI_HID_POWER_MODE_SLEEP 0x02
|
||||
#define SPI_HID_POWER_MODE_OFF 0x03
|
||||
|
||||
#define SPI_HID_RESET_ASSERT_MS 300
|
||||
#define SPI_HID_POST_DIR_DELAY_MS 25
|
||||
#define SPI_HID_RESPONSE_TIMEOUT_MS 2000
|
||||
#define SPI_HID_MAX_RESET_ATTEMPTS 3
|
||||
#define SPI_HID_MAX_INIT_RETRIES 10
|
||||
|
||||
#define SPI_HID_INPUT_HEADER_LEN 4
|
||||
#define SPI_HID_MAX_INPUT_LEN SZ_8K
|
||||
|
||||
struct spi_hid_device_desc_raw {
|
||||
__le16 wDeviceDescLength;
|
||||
__le16 bcdVersion;
|
||||
__le16 wReportDescLength;
|
||||
__le16 wMaxInputLength;
|
||||
__le16 wMaxOutputLength;
|
||||
__le16 wMaxFragmentLength;
|
||||
__le16 wVendorID;
|
||||
__le16 wProductID;
|
||||
__le16 wVersionID;
|
||||
__le16 wFlags;
|
||||
__u8 reserved[4];
|
||||
} __packed;
|
||||
|
||||
/* Parsed device descriptor */
|
||||
struct spi_hid_device_descriptor {
|
||||
u16 hid_version;
|
||||
u16 report_descriptor_length;
|
||||
u16 max_input_length;
|
||||
u16 max_output_length;
|
||||
u16 max_fragment_length;
|
||||
u16 vendor_id;
|
||||
u16 product_id;
|
||||
u16 version_id;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
struct spi_hid_input_header {
|
||||
u8 version;
|
||||
u16 body_len;
|
||||
u8 last_frag;
|
||||
u8 sync_const;
|
||||
};
|
||||
|
||||
struct spi_hid_body_header {
|
||||
u8 report_type;
|
||||
u16 content_length;
|
||||
u8 content_id;
|
||||
};
|
||||
|
||||
struct spi_hid {
|
||||
struct spi_device *spi;
|
||||
struct hid_device *hid;
|
||||
|
||||
struct spi_hid_device_descriptor desc;
|
||||
|
||||
u8 *resp_buf;
|
||||
int resp_len;
|
||||
u8 resp_type;
|
||||
|
||||
u8 power_state;
|
||||
u8 attempts;
|
||||
|
||||
bool ready;
|
||||
bool irq_enabled;
|
||||
|
||||
struct regulator *supply;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pinctrl_reset;
|
||||
struct pinctrl_state *pinctrl_active;
|
||||
struct pinctrl_state *pinctrl_sleep;
|
||||
struct work_struct reset_work;
|
||||
struct work_struct create_device_work;
|
||||
struct work_struct refresh_device_work;
|
||||
|
||||
struct mutex lock;
|
||||
struct completion output_done;
|
||||
|
||||
u32 bus_error_count;
|
||||
int bus_last_error;
|
||||
|
||||
u32 dir_count;
|
||||
u32 powered;
|
||||
|
||||
u8 *rd_buf;
|
||||
int rd_len;
|
||||
|
||||
u8 *irq_hdr_tx;
|
||||
u8 *irq_hdr_rx;
|
||||
u8 *irq_bdy_tx;
|
||||
u8 *irq_bdy_rx;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,200 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* spi-hid_trace.h
|
||||
*
|
||||
* Copyright (c) 2020 Microsoft Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM spi_hid
|
||||
|
||||
#if !defined(_SPI_HID_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _SPI_HID_TRACE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include "spi-hid-core.h"
|
||||
|
||||
DECLARE_EVENT_CLASS(spi_hid_transfer,
|
||||
TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len,
|
||||
const void *rx_buf, u16 rx_len, int ret),
|
||||
|
||||
TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, bus_num)
|
||||
__field(int, chip_select)
|
||||
__field(int, len)
|
||||
__field(int, ret)
|
||||
__dynamic_array(u8, rx_buf, rx_len)
|
||||
__dynamic_array(u8, tx_buf, tx_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->bus_num = shid->spi->controller->bus_num;
|
||||
__entry->chip_select = shid->spi->chip_select;
|
||||
__entry->len = rx_len + tx_len;
|
||||
__entry->ret = ret;
|
||||
|
||||
memcpy(__get_dynamic_array(tx_buf), tx_buf, tx_len);
|
||||
memcpy(__get_dynamic_array(rx_buf), rx_buf, rx_len);
|
||||
),
|
||||
|
||||
TP_printk("spi%d.%d: len=%d tx=[%*phD] rx=[%*phD] --> %d",
|
||||
__entry->bus_num, __entry->chip_select, __entry->len,
|
||||
__get_dynamic_array_len(tx_buf), __get_dynamic_array(tx_buf),
|
||||
__get_dynamic_array_len(rx_buf), __get_dynamic_array(rx_buf),
|
||||
__entry->ret)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid_transfer, spi_hid_input_async,
|
||||
TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len,
|
||||
const void *rx_buf, u16 rx_len, int ret),
|
||||
TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid_transfer, spi_hid_input_header_complete,
|
||||
TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len,
|
||||
const void *rx_buf, u16 rx_len, int ret),
|
||||
TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid_transfer, spi_hid_input_body_complete,
|
||||
TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len,
|
||||
const void *rx_buf, u16 rx_len, int ret),
|
||||
TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid_transfer, spi_hid_output_begin,
|
||||
TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len,
|
||||
const void *rx_buf, u16 rx_len, int ret),
|
||||
TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid_transfer, spi_hid_output_end,
|
||||
TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len,
|
||||
const void *rx_buf, u16 rx_len, int ret),
|
||||
TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(spi_hid_irq,
|
||||
TP_PROTO(struct spi_hid *shid, int irq),
|
||||
|
||||
TP_ARGS(shid, irq),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, bus_num)
|
||||
__field(int, chip_select)
|
||||
__field(int, irq)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->bus_num = shid->spi->controller->bus_num;
|
||||
__entry->chip_select = shid->spi->chip_select;
|
||||
__entry->irq = irq;
|
||||
),
|
||||
|
||||
TP_printk("spi%d.%d: IRQ %d",
|
||||
__entry->bus_num, __entry->chip_select, __entry->irq)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid_irq, spi_hid_dev_irq,
|
||||
TP_PROTO(struct spi_hid *shid, int irq),
|
||||
TP_ARGS(shid, irq)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(spi_hid,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
|
||||
TP_ARGS(shid),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, bus_num)
|
||||
__field(int, chip_select)
|
||||
__field(int, input_stage)
|
||||
__field(int, power_state)
|
||||
__field(u32, input_transfer_pending)
|
||||
__field(bool, ready)
|
||||
|
||||
__field(int, vendor_id)
|
||||
__field(int, product_id)
|
||||
__field(int, max_input_length)
|
||||
__field(int, max_output_length)
|
||||
__field(u16, hid_version)
|
||||
__field(u16, report_descriptor_length)
|
||||
__field(u16, version_id)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->bus_num = shid->spi->controller->bus_num;
|
||||
__entry->chip_select = shid->spi->chip_select;
|
||||
__entry->input_stage = shid->input_stage;
|
||||
__entry->power_state = shid->power_state;
|
||||
__entry->input_transfer_pending = shid->input_transfer_pending;
|
||||
__entry->ready = shid->ready;
|
||||
|
||||
__entry->vendor_id = shid->desc.vendor_id;
|
||||
__entry->product_id = shid->desc.product_id;
|
||||
__entry->max_input_length = shid->desc.max_input_length;
|
||||
__entry->max_output_length = shid->desc.max_output_length;
|
||||
__entry->hid_version = shid->desc.hid_version;
|
||||
__entry->report_descriptor_length = shid->desc.report_descriptor_length;
|
||||
__entry->version_id = shid->desc.version_id;
|
||||
),
|
||||
|
||||
TP_printk("spi%d.%d: (%04x:%04x v%d) HID v%d.%d state i:%d p:%d len i:%d o:%d r:%d flags %c:%d",
|
||||
__entry->bus_num, __entry->chip_select, __entry->vendor_id,
|
||||
__entry->product_id, __entry->version_id,
|
||||
__entry->hid_version >> 8, __entry->hid_version & 0xff,
|
||||
__entry->input_stage, __entry->power_state,
|
||||
__entry->max_input_length, __entry->max_output_length,
|
||||
__entry->report_descriptor_length,
|
||||
__entry->ready ? 'R' : 'r',
|
||||
__entry->input_transfer_pending)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_bus_input_report,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_process_input_report,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_input_report_handler,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_reset_work,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_create_device_work,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_refresh_device_work,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(spi_hid, spi_hid_response_handler,
|
||||
TP_PROTO(struct spi_hid *shid),
|
||||
TP_ARGS(shid)
|
||||
);
|
||||
|
||||
#endif /* _SPI_HID_TRACE_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE spi-hid_trace
|
||||
#include <trace/define_trace.h>
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* trace.c - SPI HID Trace Support
|
||||
*
|
||||
* Copyright (C) 2020 Microsoft Corporation
|
||||
*
|
||||
* Author: Felipe Balbi <felipe.balbi@microsoft.com>
|
||||
*/
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "spi-hid_trace.h"
|
||||
Reference in New Issue
Block a user