drivers/platform/surface/surface_dtx.c

Source file repositories/reference/linux-study-clean/drivers/platform/surface/surface_dtx.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/surface/surface_dtx.c
Extension
.c
Size
34163 bytes
Lines
1283
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations surface_dtx_fops = {
	.owner          = THIS_MODULE,
	.open           = surface_dtx_open,
	.release        = surface_dtx_release,
	.read           = surface_dtx_read,
	.poll           = surface_dtx_poll,
	.fasync         = surface_dtx_fasync,
	.unlocked_ioctl = surface_dtx_ioctl,
	.compat_ioctl   = surface_dtx_ioctl,
};


/* -- Event handling/forwarding. -------------------------------------------- */

/*
 * The device operation mode is not immediately updated on the EC when the
 * base has been connected, i.e. querying the device mode inside the
 * connection event callback yields an outdated value. Thus, we can only
 * determine the new tablet-mode switch and device mode values after some
 * time.
 *
 * These delays have been chosen by experimenting. We first delay on connect
 * events, then check and validate the device mode against the base state and
 * if invalid delay again by the "recheck" delay.
 */
#define SDTX_DEVICE_MODE_DELAY_CONNECT	msecs_to_jiffies(100)
#define SDTX_DEVICE_MODE_DELAY_RECHECK	msecs_to_jiffies(100)

struct sdtx_status_event {
	struct sdtx_event e;
	__u16 v;
} __packed;

struct sdtx_base_info_event {
	struct sdtx_event e;
	struct sdtx_base_info v;
} __packed;

union sdtx_generic_event {
	struct sdtx_event common;
	struct sdtx_status_event status;
	struct sdtx_base_info_event base;
};

static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay);

/* Must be executed with ddev->write_lock held. */
static void sdtx_push_event(struct sdtx_device *ddev, struct sdtx_event *evt)
{
	const size_t len = sizeof(struct sdtx_event) + evt->length;
	struct sdtx_client *client;

	lockdep_assert_held(&ddev->write_lock);

	down_read(&ddev->client_lock);
	list_for_each_entry(client, &ddev->client_list, node) {
		if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags))
			continue;

		if (likely(kfifo_avail(&client->buffer) >= len))
			kfifo_in(&client->buffer, (const u8 *)evt, len);
		else
			dev_warn(ddev->dev, "event buffer overrun\n");

		kill_fasync(&client->fasync, SIGIO, POLL_IN);
	}
	up_read(&ddev->client_lock);

	wake_up_interruptible(&ddev->waitq);
}

static u32 sdtx_notifier(struct ssam_event_notifier *nf, const struct ssam_event *in)
{
	struct sdtx_device *ddev = container_of(nf, struct sdtx_device, notif);
	union sdtx_generic_event event;
	size_t len;

	/* Validate event payload length. */
	switch (in->command_id) {
	case SAM_EVENT_CID_DTX_CONNECTION:
		len = 2 * sizeof(u8);
		break;

	case SAM_EVENT_CID_DTX_REQUEST:
		len = 0;
		break;

	case SAM_EVENT_CID_DTX_CANCEL:
		len = sizeof(u8);
		break;

Annotation

Implementation Notes