linux-stable/drivers/platform/surface/aggregator/ssh_parser.h
Maximilian Luz c167b9c7e3 platform/surface: Add Surface Aggregator subsystem
Add Surface System Aggregator Module core and Surface Serial Hub driver,
required for the embedded controller found on Microsoft Surface devices.

The Surface System Aggregator Module (SSAM, SAM or Surface Aggregator)
is an embedded controller (EC) found on 4th and later generation
Microsoft Surface devices, with the exception of the Surface Go series.
This EC provides various functionality, depending on the device in
question. This can include battery status and thermal reporting (5th and
later generations), but also HID keyboard (6th+) and touchpad input
(7th+) on Surface Laptop and Surface Book 3 series devices.

This patch provides the basic necessities for communication with the SAM
EC on 5th and later generation devices. On these devices, the EC
provides an interface that acts as serial device, called the Surface
Serial Hub (SSH). 4th generation devices, on which the EC interface is
provided via an HID-over-I2C device, are not supported by this patch.

Specifically, this patch adds a driver for the SSH device (device HID
MSHW0084 in ACPI), as well as a controller structure and associated API.
This represents the functional core of the Surface Aggregator kernel
subsystem, introduced with this patch, and will be expanded upon in
subsequent commits.

The SSH driver acts as the main attachment point for this subsystem and
sets-up and manages the controller structure. The controller in turn
provides a basic communication interface, allowing to send requests from
host to EC and receiving the corresponding responses, as well as
managing and receiving events, sent from EC to host. It is structured
into multiple layers, with the top layer presenting the API used by
other kernel drivers and the lower layers modeled after the serial
protocol used for communication.

Said other drivers are then responsible for providing the (Surface model
specific) functionality accessible through the EC (e.g. battery status
reporting, thermal information, ...) via said controller structure and
API, and will be added in future commits.

Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Link: https://lore.kernel.org/r/20201221183959.1186143-2-luzmaximilian@gmail.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2021-01-06 23:45:33 +01:00

154 lines
4.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0+ */
/*
* SSH message parser.
*
* Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H
#define _SURFACE_AGGREGATOR_SSH_PARSER_H
#include <linux/device.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/surface_aggregator/serial_hub.h>
/**
* struct sshp_buf - Parser buffer for SSH messages.
* @ptr: Pointer to the beginning of the buffer.
* @len: Number of bytes used in the buffer.
* @cap: Maximum capacity of the buffer.
*/
struct sshp_buf {
u8 *ptr;
size_t len;
size_t cap;
};
/**
* sshp_buf_init() - Initialize a SSH parser buffer.
* @buf: The buffer to initialize.
* @ptr: The memory backing the buffer.
* @cap: The length of the memory backing the buffer, i.e. its capacity.
*
* Initializes the buffer with the given memory as backing and set its used
* length to zero.
*/
static inline void sshp_buf_init(struct sshp_buf *buf, u8 *ptr, size_t cap)
{
buf->ptr = ptr;
buf->len = 0;
buf->cap = cap;
}
/**
* sshp_buf_alloc() - Allocate and initialize a SSH parser buffer.
* @buf: The buffer to initialize/allocate to.
* @cap: The desired capacity of the buffer.
* @flags: The flags used for allocating the memory.
*
* Allocates @cap bytes and initializes the provided buffer struct with the
* allocated memory.
*
* Return: Returns zero on success and %-ENOMEM if allocation failed.
*/
static inline int sshp_buf_alloc(struct sshp_buf *buf, size_t cap, gfp_t flags)
{
u8 *ptr;
ptr = kzalloc(cap, flags);
if (!ptr)
return -ENOMEM;
sshp_buf_init(buf, ptr, cap);
return 0;
}
/**
* sshp_buf_free() - Free a SSH parser buffer.
* @buf: The buffer to free.
*
* Frees a SSH parser buffer by freeing the memory backing it and then
* resetting its pointer to %NULL and length and capacity to zero. Intended to
* free a buffer previously allocated with sshp_buf_alloc().
*/
static inline void sshp_buf_free(struct sshp_buf *buf)
{
kfree(buf->ptr);
buf->ptr = NULL;
buf->len = 0;
buf->cap = 0;
}
/**
* sshp_buf_drop() - Drop data from the beginning of the buffer.
* @buf: The buffer to drop data from.
* @n: The number of bytes to drop.
*
* Drops the first @n bytes from the buffer. Re-aligns any remaining data to
* the beginning of the buffer.
*/
static inline void sshp_buf_drop(struct sshp_buf *buf, size_t n)
{
memmove(buf->ptr, buf->ptr + n, buf->len - n);
buf->len -= n;
}
/**
* sshp_buf_read_from_fifo() - Transfer data from a fifo to the buffer.
* @buf: The buffer to write the data into.
* @fifo: The fifo to read the data from.
*
* Transfers the data contained in the fifo to the buffer, removing it from
* the fifo. This function will try to transfer as much data as possible,
* limited either by the remaining space in the buffer or by the number of
* bytes available in the fifo.
*
* Return: Returns the number of bytes transferred.
*/
static inline size_t sshp_buf_read_from_fifo(struct sshp_buf *buf,
struct kfifo *fifo)
{
size_t n;
n = kfifo_out(fifo, buf->ptr + buf->len, buf->cap - buf->len);
buf->len += n;
return n;
}
/**
* sshp_buf_span_from() - Initialize a span from the given buffer and offset.
* @buf: The buffer to create the span from.
* @offset: The offset in the buffer at which the span should start.
* @span: The span to initialize (output).
*
* Initializes the provided span to point to the memory at the given offset in
* the buffer, with the length of the span being capped by the number of bytes
* used in the buffer after the offset (i.e. bytes remaining after the
* offset).
*
* Warning: This function does not validate that @offset is less than or equal
* to the number of bytes used in the buffer or the buffer capacity. This must
* be guaranteed by the caller.
*/
static inline void sshp_buf_span_from(struct sshp_buf *buf, size_t offset,
struct ssam_span *span)
{
span->ptr = buf->ptr + offset;
span->len = buf->len - offset;
}
bool sshp_find_syn(const struct ssam_span *src, struct ssam_span *rem);
int sshp_parse_frame(const struct device *dev, const struct ssam_span *source,
struct ssh_frame **frame, struct ssam_span *payload,
size_t maxlen);
int sshp_parse_command(const struct device *dev, const struct ssam_span *source,
struct ssh_command **command,
struct ssam_span *command_data);
#endif /* _SURFACE_AGGREGATOR_SSH_PARSER_h */