drivers/hid/hid-picolcd_leds.c

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

File Facts

System
Linux kernel
Corpus path
drivers/hid/hid-picolcd_leds.c
Extension
.c
Size
4053 bytes
Lines
164
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

if (value == LED_OFF && state) {
			data->led_state &= ~(1 << i);
			picolcd_leds_set(data);
		} else if (value != LED_OFF && !state) {
			data->led_state |= 1 << i;
			picolcd_leds_set(data);
		}
		break;
	}
}

static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
{
	struct device *dev;
	struct hid_device *hdev;
	struct picolcd_data *data;
	int i, value = 0;

	dev  = led_cdev->dev->parent;
	hdev = to_hid_device(dev);
	data = hid_get_drvdata(hdev);
	for (i = 0; i < 8; i++)
		if (led_cdev == data->led[i]) {
			value = (data->led_state >> i) & 1;
			break;
		}
	return value ? LED_FULL : LED_OFF;
}

int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
{
	struct device *dev = &data->hdev->dev;
	struct led_classdev *led;
	size_t name_sz = strlen(dev_name(dev)) + 8;
	char *name;
	int i, ret = 0;

	if (!report)
		return -ENODEV;
	if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
			report->field[0]->report_size != 8) {
		dev_err(dev, "unsupported LED_STATE report");
		return -EINVAL;
	}

	for (i = 0; i < 8; i++) {
		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
		if (!led) {
			dev_err(dev, "can't allocate memory for LED %d\n", i);
			ret = -ENOMEM;
			goto err;
		}
		name = (void *)(&led[1]);
		snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
		led->name = name;
		led->brightness = 0;
		led->max_brightness = 1;
		led->brightness_get = picolcd_led_get_brightness;
		led->brightness_set = picolcd_led_set_brightness;

		data->led[i] = led;
		ret = led_classdev_register(dev, data->led[i]);
		if (ret) {
			data->led[i] = NULL;
			kfree(led);
			dev_err(dev, "can't register LED %d\n", i);
			goto err;
		}
	}
	return 0;
err:
	for (i = 0; i < 8; i++)
		if (data->led[i]) {
			led = data->led[i];
			data->led[i] = NULL;
			led_classdev_unregister(led);
			kfree(led);
		}
	return ret;
}

void picolcd_exit_leds(struct picolcd_data *data)
{
	struct led_classdev *led;
	int i;

	for (i = 0; i < 8; i++) {
		led = data->led[i];
		data->led[i] = NULL;
		if (!led)

Annotation

Implementation Notes