drivers/hid/hid-bigbenff.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-bigbenff.c
Extension
.c
Size
16172 bytes
Lines
495
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 bigben_device {
	struct hid_device *hid;
	struct hid_report *report;
	spinlock_t lock;
	bool removed;
	u8 led_state;         /* LED1 = 1 .. LED4 = 8 */
	u8 right_motor_on;    /* right motor off/on 0/1 */
	u8 left_motor_force;  /* left motor force 0-255 */
	struct led_classdev *leds[NUM_LEDS];
	bool work_led;
	bool work_ff;
	struct work_struct worker;
};

static inline void bigben_schedule_work(struct bigben_device *bigben)
{
	unsigned long flags;

	spin_lock_irqsave(&bigben->lock, flags);
	if (!bigben->removed)
		schedule_work(&bigben->worker);
	spin_unlock_irqrestore(&bigben->lock, flags);
}

static void bigben_worker(struct work_struct *work)
{
	struct bigben_device *bigben = container_of(work,
		struct bigben_device, worker);
	struct hid_field *report_field = bigben->report->field[0];
	bool do_work_led = false;
	bool do_work_ff = false;
	u8 *buf;
	u32 len;
	unsigned long flags;

	buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL);
	if (!buf)
		return;

	len = hid_report_len(bigben->report);

	/* LED work */
	spin_lock_irqsave(&bigben->lock, flags);

	if (bigben->work_led) {
		bigben->work_led = false;
		do_work_led = true;
		report_field->value[0] = 0x01; /* 1 = led message */
		report_field->value[1] = 0x08; /* reserved value, always 8 */
		report_field->value[2] = bigben->led_state;
		report_field->value[3] = 0x00; /* padding */
		report_field->value[4] = 0x00; /* padding */
		report_field->value[5] = 0x00; /* padding */
		report_field->value[6] = 0x00; /* padding */
		report_field->value[7] = 0x00; /* padding */
		hid_output_report(bigben->report, buf);
	}

	spin_unlock_irqrestore(&bigben->lock, flags);

	if (do_work_led) {
		hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len,
				   bigben->report->type, HID_REQ_SET_REPORT);
	}

	/* FF work */
	spin_lock_irqsave(&bigben->lock, flags);

	if (bigben->work_ff) {
		bigben->work_ff = false;
		do_work_ff = true;
		report_field->value[0] = 0x02; /* 2 = rumble effect message */
		report_field->value[1] = 0x08; /* reserved value, always 8 */
		report_field->value[2] = bigben->right_motor_on;
		report_field->value[3] = bigben->left_motor_force;
		report_field->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */
		report_field->value[5] = 0x00; /* padding */
		report_field->value[6] = 0x00; /* padding */
		report_field->value[7] = 0x00; /* padding */
		hid_output_report(bigben->report, buf);
	}

	spin_unlock_irqrestore(&bigben->lock, flags);

	if (do_work_ff) {
		hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len,
				   bigben->report->type, HID_REQ_SET_REPORT);
	}

	kfree(buf);

Annotation

Implementation Notes