drivers/gpio/gpiolib-cdev.c
Source file repositories/reference/linux-study-clean/drivers/gpio/gpiolib-cdev.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/gpio/gpiolib-cdev.c- Extension
.c- Size
- 73668 bytes
- Lines
- 2774
- 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.
- 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.
- Defines an operation table; this is where Linux turns generic core objects into subsystem-specific behavior.
- Touches user memory; correctness depends on fault-safe copying and privilege boundary handling.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/anon_inodes.hlinux/atomic.hlinux/bitmap.hlinux/build_bug.hlinux/cdev.hlinux/cleanup.hlinux/compat.hlinux/compiler.hlinux/device.hlinux/err.hlinux/file.hlinux/gpio.hlinux/gpio/driver.hlinux/hte.hlinux/interrupt.hlinux/irqreturn.hlinux/kfifo.hlinux/module.hlinux/mutex.hlinux/overflow.hlinux/pinctrl/consumer.hlinux/poll.hlinux/seq_file.hlinux/spinlock.hlinux/string.hlinux/timekeeping.hlinux/uaccess.hlinux/workqueue.huapi/linux/gpio.hgpiolib.hgpiolib-cdev.h
Detected Declarations
struct linehandle_statestruct linestruct linereqstruct lineevent_statestruct compat_gpioeevent_datastruct gpio_chardev_datastruct lineinfo_changed_ctxfunction linehandle_validate_flagsfunction linehandle_flags_to_desc_flagsfunction linehandle_set_configfunction linehandle_ioctlfunction linehandle_ioctl_compatfunction linehandle_freefunction linehandle_releasefunction linehandle_createfunction linereq_unregistered_notifyfunction linereq_put_eventfunction scoped_guardfunction line_event_timestampfunction line_event_idfunction free_irq_labelfunction process_hw_ts_threadfunction process_hw_tsfunction hte_edge_setupfunction hte_edge_setupfunction edge_irq_threadfunction edge_irq_handlerfunction debounced_valuefunction debounce_irq_handlerfunction debounce_work_funcfunction debounce_setupfunction gpio_v2_line_config_debouncedfunction gpio_v2_line_config_debounce_periodfunction edge_detector_stopfunction edge_detector_fifo_initfunction edge_detector_setupfunction edge_detector_updatefunction gpio_v2_line_config_flagsfunction gpio_v2_line_config_output_valuefunction gpio_v2_line_flags_validatefunction gpio_v2_line_config_validatefunction gpio_v2_line_config_flags_to_desc_flagsfunction linereq_get_valuesfunction linereq_set_valuesfunction linereq_set_configfunction linereq_ioctlfunction linereq_ioctl_compatfunction linereq_poll
Annotated Snippet
static const struct file_operations linehandle_fileops = {
.release = linehandle_release,
.owner = THIS_MODULE,
.llseek = noop_llseek,
.unlocked_ioctl = linehandle_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = linehandle_ioctl_compat,
#endif
};
DEFINE_FREE(linehandle_free, struct linehandle_state *, if (!IS_ERR_OR_NULL(_T)) linehandle_free(_T))
static int linehandle_create(struct gpio_device *gdev, void __user *ip)
{
struct gpiohandle_request handlereq;
struct linehandle_state *lh __free(linehandle_free) = NULL;
int i, ret;
u32 lflags;
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
return -EFAULT;
if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX))
return -EINVAL;
lflags = handlereq.flags;
ret = linehandle_validate_flags(lflags);
if (ret)
return ret;
lh = kzalloc_obj(*lh);
if (!lh)
return -ENOMEM;
lh->gdev = gpio_device_get(gdev);
if (handlereq.consumer_label[0] != '\0') {
/* label is only initialized if consumer_label is set */
lh->label = kstrndup(handlereq.consumer_label,
sizeof(handlereq.consumer_label) - 1,
GFP_KERNEL);
if (!lh->label)
return -ENOMEM;
}
lh->num_descs = handlereq.lines;
/* Request each GPIO */
for (i = 0; i < handlereq.lines; i++) {
u32 offset = handlereq.lineoffsets[i];
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
ret = gpiod_request_user(desc, lh->label);
if (ret)
return ret;
lh->descs[i] = desc;
linehandle_flags_to_desc_flags(handlereq.flags, &desc->flags);
ret = gpiod_set_transitory(desc, false);
if (ret < 0)
return ret;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!handlereq.default_values[i];
ret = gpiod_direction_output_nonotify(desc, val);
if (ret)
return ret;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
ret = gpiod_direction_input_nonotify(desc);
if (ret)
return ret;
}
gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
offset);
}
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
anon_inode_getfile("gpio-linehandle", &linehandle_fileops,
lh, O_RDONLY | O_CLOEXEC));
if (fdf.err)
Annotation
- Immediate include surface: `linux/anon_inodes.h`, `linux/atomic.h`, `linux/bitmap.h`, `linux/build_bug.h`, `linux/cdev.h`, `linux/cleanup.h`, `linux/compat.h`, `linux/compiler.h`.
- Detected declarations: `struct linehandle_state`, `struct line`, `struct linereq`, `struct lineevent_state`, `struct compat_gpioeevent_data`, `struct gpio_chardev_data`, `struct lineinfo_changed_ctx`, `function linehandle_validate_flags`, `function linehandle_flags_to_desc_flags`, `function linehandle_set_config`.
- Atlas domain: Driver Families / drivers/gpio.
- Implementation status: pattern implementation candidate.
- This snippet crosses the user/kernel memory boundary; validate fault handling and access checks before translating the pattern.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.