drivers/hid/hid-creative-sb0540.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-creative-sb0540.c
Extension
.c
Size
5810 bytes
Lines
269
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 creative_sb0540 {
	struct input_dev *input_dev;
	struct hid_device *hid;
	unsigned short keymap[ARRAY_SIZE(creative_sb0540_key_table)];
};

static inline u64 reverse(u64 data, int bits)
{
	int i;
	u64 c;

	c = 0;
	for (i = 0; i < bits; i++) {
		c |= (u64) (((data & (((u64) 1) << i)) ? 1 : 0))
			<< (bits - 1 - i);
	}
	return (c);
}

static int get_key(struct creative_sb0540 *creative_sb0540, u64 keycode)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(creative_sb0540_codes); i++) {
		if (creative_sb0540_codes[i] == keycode)
			return creative_sb0540->keymap[i];
	}

	return 0;

}

static int creative_sb0540_raw_event(struct hid_device *hid,
	struct hid_report *report, u8 *data, int len)
{
	struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
	u64 code, main_code;
	int key;

	if (len != 6 || !(hid->claimed & HID_CLAIMED_INPUT))
		return 0;

	/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
	code = reverse(data[5], 8);
	main_code = (code << 8) + ((~code) & 0xff);

	/*
	 * Flip to get values in the same format as
	 * remotes/creative/lircd.conf.alsa_usb in lirc
	 */
	main_code = ((main_code & 0xff) << 8) +
		((main_code & 0xff00) >> 8);

	key = get_key(creative_sb0540, main_code);
	if (key == 0 || key == KEY_RESERVED) {
		hid_err(hid, "Could not get a key for main_code %llX\n",
			main_code);
		return 0;
	}

	input_report_key(creative_sb0540->input_dev, key, 1);
	input_report_key(creative_sb0540->input_dev, key, 0);
	input_sync(creative_sb0540->input_dev);

	/* let hidraw and hiddev handle the report */
	return 0;
}

static int creative_sb0540_input_configured(struct hid_device *hid,
		struct hid_input *hidinput)
{
	struct input_dev *input_dev = hidinput->input;
	struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
	int i;

	creative_sb0540->input_dev = input_dev;

	input_dev->keycode = creative_sb0540->keymap;
	input_dev->keycodesize = sizeof(unsigned short);
	input_dev->keycodemax = ARRAY_SIZE(creative_sb0540->keymap);

	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);

	memcpy(creative_sb0540->keymap, creative_sb0540_key_table,
		sizeof(creative_sb0540->keymap));
	for (i = 0; i < ARRAY_SIZE(creative_sb0540_key_table); i++)
		set_bit(creative_sb0540->keymap[i], input_dev->keybit);
	clear_bit(KEY_RESERVED, input_dev->keybit);

	return 0;

Annotation

Implementation Notes