Chapter 3. Writing your own kernel module

Table of Contents

struct uio_info
Adding an interrupt handler

Please have a look at uio_cif.c as an example. The following paragraphs explain the different sections of this file.

struct uio_info

This structure tells the framework the details of your driver, Some of the members are required, others are optional.

  • char *name: Required. The name of your driver as it will appear in sysfs. I recommend using the name of your module for this.

  • char *version: Required. This string appears in /sys/class/uio/uioX/version.

  • struct uio_mem mem[ MAX_UIO_MAPS ]: Required if you have memory that can be mapped with mmap(). For each mapping you need to fill one of the uio_mem structures. See the description below for details.

  • long irq: Required. If your hardware generates an interrupt, it's your modules task to determine the irq number during initialization. If you don't have a hardware generated interrupt but want to trigger the interrupt handler in some other way, set irq to UIO_IRQ_CUSTOM. If you had no interrupt at all, you could set irq to UIO_IRQ_NONE, though this rarely makes sense.

  • unsigned long irq_flags: Required if you've set irq to a hardware interrupt number. The flags given here will be used in the call to request_irq().

  • int (*mmap)(struct uio_info *info, struct vm_area_struct *vma): Optional. If you need a special mmap() function, you can set it here. If this pointer is not NULL, your mmap() will be called instead of the built-in one.

  • int (*open)(struct uio_info *info, struct inode *inode) : Optional. You might want to have your own open(), e.g. to enable interrupts only when your device is actually used.

  • int (*release)(struct uio_info *info, struct inode *inode) : Optional. If you define your own open(), you will probably also want a custom release() function.

Usually, your device will have one or more memory regions that can be mapped to user space. For each region, you have to set up a struct uio_mem in the mem[] array. Here's a description of the fields of struct uio_mem:

  • int memtype: Required if the mapping is used. Set this to UIO_MEM_PHYS if you you have physical memory on your card to be mapped. Use UIO_MEM_LOGICAL for logical memory (e.g. allocated with kmalloc()). There's also UIO_MEM_VIRTUAL for virtual memory.

  • unsigned long addr: Required if the mapping is used. Fill in the address of your memory block. This address is the one that appears in sysfs.

  • unsigned long size: Fill in the size of the memory block that addr points to. If size is zero, the mapping is considered unused. Note that you must initialize size with zero for all unused mappings.

  • void *internal_addr: If you have to access this memory region from within your kernel module, you will want to map it internally by using something like ioremap(). Addresses returned by this function cannot be mapped to user space, so you must not store it in addr. Use internal_addr instead to remember such an address.

Please do not touch the kobj element of struct uio_mem! It is used by the UIO framework to set up sysfs files for this mapping. Simply leave it alone.