drivers/hid/hid-quirks.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-quirks.c
Extension
.c
Size
81785 bytes
Lines
1398
Domain
Driver Families
Bucket
drivers/hid
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 quirks_list_struct {
	struct hid_device_id hid_bl_item;
	struct list_head node;
};

static LIST_HEAD(dquirks_list);
static DEFINE_MUTEX(dquirks_lock);

/* Runtime ("dynamic") quirks manipulation functions */

/**
 * hid_exists_dquirk - find any dynamic quirks for a HID device
 * @hdev: the HID device to match
 *
 * Description:
 *         Scans dquirks_list for a matching dynamic quirk and returns
 *         the pointer to the relevant struct hid_device_id if found.
 *         Must be called with a read lock held on dquirks_lock.
 *
 * Return: NULL if no quirk found, struct hid_device_id * if found.
 */
static struct hid_device_id *hid_exists_dquirk(const struct hid_device *hdev)
{
	struct quirks_list_struct *q;
	struct hid_device_id *bl_entry = NULL;

	list_for_each_entry(q, &dquirks_list, node) {
		if (hid_match_one_id(hdev, &q->hid_bl_item)) {
			bl_entry = &q->hid_bl_item;
			break;
		}
	}

	if (bl_entry != NULL)
		dbg_hid("Found dynamic quirk 0x%lx for HID device 0x%04x:0x%04x\n",
			bl_entry->driver_data, bl_entry->vendor,
			bl_entry->product);

	return bl_entry;
}


/**
 * hid_modify_dquirk - add/replace a HID quirk
 * @id: the HID device to match
 * @quirks: the unsigned long quirks value to add/replace
 *
 * Description:
 *         If an dynamic quirk exists in memory for this device, replace its
 *         quirks value with what was provided.  Otherwise, add the quirk
 *         to the dynamic quirks list.
 *
 * Return: 0 OK, -error on failure.
 */
static int hid_modify_dquirk(const struct hid_device_id *id,
			     const unsigned long quirks)
{
	struct hid_device *hdev;
	struct quirks_list_struct *q_new, *q;
	int list_edited = 0;
	int ret = 0;

	hdev = kzalloc_obj(*hdev);
	if (!hdev)
		return -ENOMEM;

	q_new = kmalloc_obj(struct quirks_list_struct);
	if (!q_new) {
		ret = -ENOMEM;
		goto out;
	}

	hdev->bus = q_new->hid_bl_item.bus = id->bus;
	hdev->group = q_new->hid_bl_item.group = id->group;
	hdev->vendor = q_new->hid_bl_item.vendor = id->vendor;
	hdev->product = q_new->hid_bl_item.product = id->product;
	q_new->hid_bl_item.driver_data = quirks;

	mutex_lock(&dquirks_lock);

	list_for_each_entry(q, &dquirks_list, node) {

		if (hid_match_one_id(hdev, &q->hid_bl_item)) {

			list_replace(&q->node, &q_new->node);
			kfree(q);
			list_edited = 1;
			break;

		}

Annotation

Implementation Notes