drivers/hid/hid-cougar.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-cougar.c
Extension
.c
Size
8412 bytes
Lines
342
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 cougar_shared {
	struct list_head list;
	struct kref kref;
	bool enabled;
	struct hid_device *dev;
	struct input_dev *input;
};

struct cougar {
	bool special_intf;
	struct cougar_shared *shared;
};

static LIST_HEAD(cougar_udev_list);
static DEFINE_MUTEX(cougar_udev_list_lock);

/**
 * cougar_fix_g6_mapping - configure the mapping for key G6/Spacebar
 */
static void cougar_fix_g6_mapping(void)
{
	int i;

	for (i = 0; cougar_mapping[i][0]; i++) {
		if (cougar_mapping[i][0] == COUGAR_KEY_G6) {
			cougar_mapping[i][1] =
				g6_is_space ? KEY_SPACE : KEY_F18;
			pr_info("cougar: G6 mapped to %s\n",
				g6_is_space ? "space" : "F18");
			return;
		}
	}
	pr_warn("cougar: no mappings defined for G6/spacebar");
}

/*
 * Constant-friendly rdesc fixup for mouse interface
 */
static const __u8 *cougar_report_fixup(struct hid_device *hdev, __u8 *rdesc,
				       unsigned int *rsize)
{
	if (*rsize >= 117 && rdesc[2] == 0x09 && rdesc[3] == 0x02 &&
	    (rdesc[115] | rdesc[116] << 8) >= HID_MAX_USAGES) {
		hid_info(hdev,
			"usage count exceeds max: fixing up report descriptor\n");
		rdesc[115] = ((HID_MAX_USAGES-1) & 0xff);
		rdesc[116] = ((HID_MAX_USAGES-1) >> 8);
	}
	return rdesc;
}

static struct cougar_shared *cougar_get_shared_data(struct hid_device *hdev)
{
	struct cougar_shared *shared;

	/* Try to find an already-probed interface from the same device */
	list_for_each_entry(shared, &cougar_udev_list, list) {
		if (hid_compare_device_paths(hdev, shared->dev, '/')) {
			kref_get(&shared->kref);
			return shared;
		}
	}
	return NULL;
}

static void cougar_release_shared_data(struct kref *kref)
{
	struct cougar_shared *shared = container_of(kref,
						    struct cougar_shared, kref);

	mutex_lock(&cougar_udev_list_lock);
	list_del(&shared->list);
	mutex_unlock(&cougar_udev_list_lock);

	kfree(shared);
}

static void cougar_remove_shared_data(void *resource)
{
	struct cougar *cougar = resource;

	if (cougar->shared) {
		kref_put(&cougar->shared->kref, cougar_release_shared_data);
		cougar->shared = NULL;
	}
}

/*
 * Bind the device group's shared data to this cougar struct.
 * If no shared data exists for this group, create and initialize it.

Annotation

Implementation Notes