writing-char-drivers

v2026.09.24

Character driver skill for Linux kernel char devices. Use when implementing file_operations, cdev, copy_to_user, ioctl, or mmap for userspace interfaces. Activates on queries about char device, cdev, file_operations, copy_from_user, ioctl, or kernel mmap.

GitHub
安装命令
npx skhub add mohitmishra786/writing-char-drivers
Markdown
SKILL.md

Writing Character Drivers

Purpose

Guide agents through Linux character device implementation: struct file_operations, cdev registration, safe userspace copies, ioctl design, and basic mmap — focused depth beyond skills/kernel/device-drivers.

When to Use

  • Exposing hardware to /dev/mydev
  • Implementing read/write/poll from kernel
  • Defining ioctl commands with type-safe macros
  • Mapping device MMIO to userspace (carefully)

Workflow

1. Char device registration

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#define MY_MAJOR 0   /* 0 = dynamic alloc */
#define MY_MINOR 0

static dev_t devno;
static struct cdev my_cdev;
static struct class *class;

static const struct file_operations my_fops = {
    .owner          = THIS_MODULE,
    .open           = my_open,
    .release        = my_release,
    .read           = my_read,
    .write          = my_write,
    .unlocked_ioctl = my_ioctl,
    .llseek         = no_llseek,
};

static int __init my_init(void)
{
    int ret = alloc_chrdev_region(&devno, MY_MINOR, 1, "mydev");
    if (ret)
        return ret;

    cdev_init(&my_cdev, &my_fops);
    ret = cdev_add(&my_cdev, devno, 1);
    if (ret)
        goto err_cdev;

    class = class_create("mydev");
    device_create(class, NULL, devno, NULL, "mydev");
    return 0;

err_cdev:
    unregister_chrdev_region(devno, 1);
    return ret;
}

Modern drivers often use devm_* variants inside probe.

2. Safe userspace I/O

static ssize_t my_read(struct file *filp, char __user *buf,
                       size_t count, loff_t *ppos)
{
    char kbuf[128];
    ssize_t len;

    if (*ppos >= sizeof(kbuf))
        return 0;
    len = min(count, sizeof(kbuf) - *ppos);
    memcpy(kbuf, "data", 4);
    if (copy_to_user(buf, kbuf + *ppos, len))
        return -EFAULT;
    *ppos += len;
    return len;
}

Never dereference __user pointers directly.

3. ioctl pattern

#include <linux/ioctl.h>

#define MY_IOC_MAGIC 'k'
#define MY_IOC_RESET  _IO(MY_IOC_MAGIC, 0)
#define MY_IOC_SET    _IOW(MY_IOC_MAGIC, 1, int)

static long my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    switch (cmd) {
    case MY_IOC_RESET:
        return 0;
    case MY_IOC_SET: {
        int val;
        if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
            return -EFAULT;
        return 0;
    }
    default:
        return -ENOTTY;
    }
}

Use _IOWR with fixed-size structs; prefer compat_ioctl on bi-arch.

4. mmap (device memory)

static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
    unsigned long size = vma->vm_end - vma->vm_start;
    phys_addr_t phys = device_phys_base;

    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    return remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
                           size, vma->vm_page_prot);
}

Prefer mmap of DMA buffers only with explicit size limits and permission checks.

5. poll / async I/O

Implement poll + wake_up_interruptible for blocking reads; use fasync_helper for SIGIO.

6. Agent usage

/writing-char-drivers Add unlocked_ioctl SET_SPEED to existing platform driver

Common Problems

SymptomCauseFix
-EFAULTBad user pointerValidate access_ok (older) / rely on copy_*
ENOTTYWrong ioctl magicMatch userspace ioctl.h
Major conflictStatic major takenUse alloc_chrdev_region
mmap SIGSEGVCached mapping to devicepgprot_noncached
Sleep in ioctlHolding spinlockDrop lock before blocking

Related Skills

  • skills/kernel-dev/platform-device-model — probe context
  • skills/kernel/device-drivers — full driver lifecycle
  • skills/kernel/kernel-concurrency — locking in file ops
  • skills/kernel-dev/kernel-debugging-advanced — trace ioctl path
  • skills/low-level-programming/linux-kernel-modules — module boilerplate
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/kernel-dev/writing-char-drivers

默认分支

main

最新提交

bdc5847

Tree SHA

1178323