Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Using ioremap and readl/writel | Communicating with Hardware
Practice
Projects
Quizzes & Challenges
Quizzes
Challenges
/
C Device Drivers Basics

bookUsing ioremap and readl/writel

When writing device drivers in C for Linux, you often need to access hardware registers directly. Many modern devices use memory-mapped I/O, where device registers are mapped into the system's physical address space. However, you cannot access these physical addresses directly from kernel code. Instead, you must map them into the kernel's virtual address space using the ioremap function. This mapping provides your driver with a pointer you can use to safely access device registers.

map_device_register.c

map_device_register.c

copy
1234567891011121314151617181920212223242526272829303132333435
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> #define DEVICE_PHYS_ADDR 0xFE200000 #define DEVICE_REG_SIZE 0x1000 static void __iomem *device_base = NULL; static int __init map_device_init(void) { device_base = ioremap(DEVICE_PHYS_ADDR, DEVICE_REG_SIZE); if (!device_base) { pr_err("Failed to map device memory\n"); return -ENOMEM; } pr_info("Device memory mapped at %p\n", device_base); return 0; } static void __exit map_device_exit(void) { if (device_base) { iounmap(device_base); pr_info("Device memory unmapped\n"); } } module_init(map_device_init); module_exit(map_device_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Example: Mapping device register with ioremap");

After mapping device memory, you must access the registers safely. Direct pointer dereferencing is not allowed for memory-mapped I/O regions in the kernel, as it can lead to undefined behavior. Instead, you use the readl and writel functions, which are designed to safely read and write 32-bit values to and from the mapped addresses. These functions ensure the correct ordering and semantics required by the hardware and the kernel, and they reference the pointer returned by ioremap, as shown in the previous code.

access_registers.c

access_registers.c

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> #define DEVICE_PHYS_ADDR 0xFE200000 #define DEVICE_REG_SIZE 0x1000 #define DEVICE_REG_OFFSET 0x10 static void __iomem *device_base = NULL; static int __init access_registers_init(void) { u32 value; device_base = ioremap(DEVICE_PHYS_ADDR, DEVICE_REG_SIZE); if (!device_base) { pr_err("Failed to map device memory\n"); return -ENOMEM; } value = readl(device_base + DEVICE_REG_OFFSET); pr_info("Register value: 0x%08x\n", value); writel(0xA5A5A5A5, device_base + DEVICE_REG_OFFSET); pr_info("Wrote 0xA5A5A5A5 to register\n"); return 0; } static void __exit access_registers_exit(void) { if (device_base) { iounmap(device_base); pr_info("Device memory unmapped\n"); } } module_init(access_registers_init); module_exit(access_registers_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Example: Using readl/writel to access device registers");
question mark

What is the purpose of the ioremap function in kernel code?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 5. ChapterΒ 2

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

Suggested prompts:

Can you explain how to use `ioremap` in a device driver?

What are the differences between `readl`/`writel` and regular pointer access?

Are there any precautions to take when unmapping device memory?

bookUsing ioremap and readl/writel

Swipe to show menu

When writing device drivers in C for Linux, you often need to access hardware registers directly. Many modern devices use memory-mapped I/O, where device registers are mapped into the system's physical address space. However, you cannot access these physical addresses directly from kernel code. Instead, you must map them into the kernel's virtual address space using the ioremap function. This mapping provides your driver with a pointer you can use to safely access device registers.

map_device_register.c

map_device_register.c

copy
1234567891011121314151617181920212223242526272829303132333435
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> #define DEVICE_PHYS_ADDR 0xFE200000 #define DEVICE_REG_SIZE 0x1000 static void __iomem *device_base = NULL; static int __init map_device_init(void) { device_base = ioremap(DEVICE_PHYS_ADDR, DEVICE_REG_SIZE); if (!device_base) { pr_err("Failed to map device memory\n"); return -ENOMEM; } pr_info("Device memory mapped at %p\n", device_base); return 0; } static void __exit map_device_exit(void) { if (device_base) { iounmap(device_base); pr_info("Device memory unmapped\n"); } } module_init(map_device_init); module_exit(map_device_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Example: Mapping device register with ioremap");

After mapping device memory, you must access the registers safely. Direct pointer dereferencing is not allowed for memory-mapped I/O regions in the kernel, as it can lead to undefined behavior. Instead, you use the readl and writel functions, which are designed to safely read and write 32-bit values to and from the mapped addresses. These functions ensure the correct ordering and semantics required by the hardware and the kernel, and they reference the pointer returned by ioremap, as shown in the previous code.

access_registers.c

access_registers.c

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> #define DEVICE_PHYS_ADDR 0xFE200000 #define DEVICE_REG_SIZE 0x1000 #define DEVICE_REG_OFFSET 0x10 static void __iomem *device_base = NULL; static int __init access_registers_init(void) { u32 value; device_base = ioremap(DEVICE_PHYS_ADDR, DEVICE_REG_SIZE); if (!device_base) { pr_err("Failed to map device memory\n"); return -ENOMEM; } value = readl(device_base + DEVICE_REG_OFFSET); pr_info("Register value: 0x%08x\n", value); writel(0xA5A5A5A5, device_base + DEVICE_REG_OFFSET); pr_info("Wrote 0xA5A5A5A5 to register\n"); return 0; } static void __exit access_registers_exit(void) { if (device_base) { iounmap(device_base); pr_info("Device memory unmapped\n"); } } module_init(access_registers_init); module_exit(access_registers_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Example: Using readl/writel to access device registers");
question mark

What is the purpose of the ioremap function in kernel code?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 5. ChapterΒ 2
some-alt