drivers/hid/hid-steam.c

Source file repositories/reference/linux-study-clean/drivers/hid/hid-steam.c

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-steam.c
Extension
.c
Size
55756 bytes
Lines
1881
Domain
Driver Families
Bucket
drivers/hid
Inferred role
Driver Families: implementation source
Status
source 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

struct steam_device {
	struct list_head list;
	spinlock_t lock;
	struct hid_device *hdev, *client_hdev;
	struct mutex report_mutex;
	unsigned long client_opened;
	struct input_dev __rcu *input;
	struct input_dev __rcu *sensors;
	unsigned long quirks;
	struct work_struct work_connect;
	bool connected;
	char serial_no[STEAM_SERIAL_LEN + 1];
	struct power_supply_desc battery_desc;
	struct power_supply __rcu *battery;
	u8 battery_charge;
	u16 voltage;
	struct delayed_work mode_switch;
	bool did_mode_switch;
	bool gamepad_mode;
	struct work_struct rumble_work;
	u16 rumble_left;
	u16 rumble_right;
	unsigned int sensor_timestamp_us;
	struct work_struct unregister_work;
};

static int steam_recv_report(struct steam_device *steam,
		u8 *data, int size)
{
	struct hid_report *r;
	u8 *buf;
	int ret;

	r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
	if (!r) {
		hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted -  nothing to read\n");
		return -EINVAL;
	}

	if (hid_report_len(r) < 64)
		return -EINVAL;

	buf = hid_alloc_report_buf(r, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	/*
	 * The report ID is always 0, so strip the first byte from the output.
	 * hid_report_len() is not counting the report ID, so +1 to the length
	 * or else we get a EOVERFLOW. We are safe from a buffer overflow
	 * because hid_alloc_report_buf() allocates +7 bytes.
	 */
	ret = hid_hw_raw_request(steam->hdev, 0x00,
			buf, hid_report_len(r) + 1,
			HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
	if (ret > 0)
		memcpy(data, buf + 1, min(size, ret - 1));
	kfree(buf);
	return ret;
}

static int steam_send_report(struct steam_device *steam,
		u8 *cmd, int size)
{
	struct hid_report *r;
	u8 *buf;
	unsigned int retries = 50;
	int ret;

	r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
	if (!r) {
		hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted -  nothing to read\n");
		return -EINVAL;
	}

	if (hid_report_len(r) < 64)
		return -EINVAL;

	buf = hid_alloc_report_buf(r, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	/* The report ID is always 0 */
	memcpy(buf + 1, cmd, size);

	/*
	 * Sometimes the wireless controller fails with EPIPE
	 * when sending a feature report.
	 * Doing a HID_REQ_GET_REPORT and waiting for a while
	 * seems to fix that.

Annotation

Implementation Notes