drivers/gpio/gpio-sloppy-logic-analyzer.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-sloppy-logic-analyzer.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-sloppy-logic-analyzer.c
Extension
.c
Size
8859 bytes
Lines
346
Domain
Driver Families
Bucket
drivers/gpio
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations fops_trigger = {
	.owner = THIS_MODULE,
	.open = trigger_open,
	.write = trigger_write,
	.release = single_release,
};

static int gpio_la_poll_probe(struct platform_device *pdev)
{
	struct gpio_la_poll_priv *priv;
	struct device *dev = &pdev->dev;
	const char *devname = dev_name(dev);
	const char *gpio_names[GPIO_LA_MAX_PROBES];
	char *meta = NULL;
	unsigned int i, meta_len = 0;
	int ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	ret = devm_mutex_init(dev, &priv->blob_lock);
	if (ret)
		return ret;

	fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE);

	priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN);
	if (IS_ERR(priv->descs))
		return PTR_ERR(priv->descs);

	/* artificial limit to keep 1 byte per sample for now */
	if (priv->descs->ndescs > GPIO_LA_MAX_PROBES)
		return -EFBIG;

	ret = device_property_read_string_array(dev, "probe-names", gpio_names,
						priv->descs->ndescs);
	if (ret >= 0 && ret != priv->descs->ndescs)
		ret = -EBADR;
	if (ret < 0)
		return dev_err_probe(dev, ret, "error naming the GPIOs");

	for (i = 0; i < priv->descs->ndescs; i++) {
		unsigned int add_len;
		char *new_meta, *consumer_name;

		if (gpiod_cansleep(priv->descs->desc[i]))
			return -EREMOTE;

		consumer_name = kasprintf(GFP_KERNEL, "%s: %s", devname, gpio_names[i]);
		if (!consumer_name)
			return -ENOMEM;
		gpiod_set_consumer_name(priv->descs->desc[i], consumer_name);
		kfree(consumer_name);

		/* '10' is length of 'probe00=\n\0' */
		add_len = strlen(gpio_names[i]) + 10;

		new_meta = devm_krealloc(dev, meta, meta_len + add_len, GFP_KERNEL);
		if (!new_meta)
			return -ENOMEM;

		meta = new_meta;
		meta_len += snprintf(meta + meta_len, add_len, "probe%02u=%s\n",
				     i + 1, gpio_names[i]);
	}

	platform_set_drvdata(pdev, priv);
	priv->dev = dev;

	priv->meta.data = meta;
	priv->meta.size = meta_len;
	priv->debug_dir = debugfs_create_dir(devname, gpio_la_poll_debug_dir);
	debugfs_create_blob("meta_data", 0400, priv->debug_dir, &priv->meta);
	debugfs_create_ulong("delay_ns", 0600, priv->debug_dir, &priv->delay_ns);
	debugfs_create_ulong("delay_ns_acquisition", 0400, priv->debug_dir, &priv->acq_delay);
	debugfs_create_file_unsafe("buf_size", 0600, priv->debug_dir, priv, &fops_buf_size);
	debugfs_create_file_unsafe("capture", 0200, priv->debug_dir, priv, &fops_capture);
	debugfs_create_file_unsafe("trigger", 0200, priv->debug_dir, priv, &fops_trigger);

	return 0;
}

static void gpio_la_poll_remove(struct platform_device *pdev)
{
	struct gpio_la_poll_priv *priv = platform_get_drvdata(pdev);

	mutex_lock(&priv->blob_lock);
	debugfs_remove_recursive(priv->debug_dir);
	mutex_unlock(&priv->blob_lock);

Annotation

Implementation Notes