Writing Linux device drivers
I sent an email to John Williams at PetaLogix and asked him if they had some information about writing Linux device drivers. Here is his answer:.
"We don't document how to write device drivers as such, since that is a
generic topic relevant across all Linux systems.
There is the petalinux-new-module command which is used to create a
template loadable module, which might be the first step of creating a
You might like to look at the UIO framework - userspace IO. We use it
a lot and it is a nice way of making simple driver interfaces".
I am not a Linux kernel expert and know nothing about the internals of the Linux kernel. Let's try the two other methods.
Device drivers for custom hardware
For many types of devices, what is really needed is some way to handle an interrupt and provide access to the memory space of the device. The logic of controlling the device does not necessarily have to be within the kernel if the device does not need to take advantage of any of other resources that the kernel provides. In this tutorial, we will explore two ways of achieving direct access to the hardware from user space:
- Direct access to device registers via /dev/mem
- User Space I/O (UIO) framework.
Writing a kernel driver is overkill for some devices, and the development process is more complicated because it requires writing kernel code. In this tutorial, we will create our first very simple UIO driver and learn how to load a module in Linux.
Userspace access via /dev/mem
"/dev/mem" is a virtual file representing the memory map of the whole system. To access the device from user space, we can open "/dev/mem", and then use mmap() to map the device to memory, and then we can access the device by using the pointer which points to the mapped memory. Here are some of the characteristics:
- Userspace interface to system address space
- Accessed via mmap() system call
- Must be root or have appropriate permissions
- Quite a blunt tool – must be used carefully
- Can bypass protections provided by the MMU
- Possible to corrupt kernel, device or other processes memory
- Very simple – no kernel module or code
- Good for quick prototyping / IP verification
- peek/poke utilities
- Portable (in a very basic sense)
- No interrupt handling possible
- No protection against simultaneous access
- Need to know physical address of IP
OK for prototyping – not recommended for production
Running an example
Run the following command to create an application called "gpio-dev-mem-test"
Here is the generated directory:
Replace the file gpio-dev-mem-test.c with the file that can be downloaded from here.
Enable the build and installation of the application from menuconfig by running:
Save the configuration.
Build a new image
Run make to compile the application and build it into the Linux image.
--> cd $PETALINUX/software/petalinux-dist
Boot the board
For instruction on how to boot the system see part 76. After logging in to the Linux, try the gpio-dev-mem-test command to directly access the GPIO devices.
This command will turn on all four LEDs on the board.
Creating an UIO driver
In this section we will create an UIO driver using the enhanced generic UIO framework. We will start by generating a new application called "gpio-uio-test".
Replace the file gpio-uio-test.c with the file that can be downloaded from here.
Configure user application
Run petalinux-config-apps and select the <gpio-uio-test> application.
Save the configuration.
Configure the kernel to support UIO
Although, we can implement the control logic of the devices totally in user space, we need to enable the UIO framework in the kernel. We will configure the UIO subsystem to be built as a loadable module. However, it is also possible to build it directly into the kernel if we prefer.
Run petalinux-config-kernel to open the kernel menuconfig
Select Device Drivers
In the Device Drivers menu scroll down to the "Userspace I/O drivers". Select it as a <M>.
Because the kernel is configured to support loadable modules by default, for those loadable device drivers, we can select it as built-it or module. "<*>" means built-in and "<M>" means module. If a driver is selected as a module, it will not be loaded when booting Linux. We can load it after Linux boots by using the modprobe command (see below).
Go into the "Userspace I/O Drivers" menu and mark the "Userspace I/O platform driver with generic IRQ handling".
Exit the kernel menuconfig and save the configuration.
Identifying the device to be controlled by UIO
The "compatible" property on a device entry in the device tree (DTS) links the device to a kernel driver. We are going to mark the LEDs GPIO to be controlled as the UIO device, instead of the normal Xilinx GPIO device driver. The CTS file can be found here:
Edit the DTS file
We are going to use the UIO driver instead of the normal GPIO driver for our GPIO device (we have only one the 4bit LEDs). We will replace the compatible parameter line with: compatible="generic-uio"
Rebuilding and booting PetaLinux
Run make inside "petalinux-dist"
Reboot the system and login to the Linux system.
Load the UIO modules
Load the UIO modules using the following commands:
List the active loaded modules with the lsmod command. We can find the information of the loaded modules from: /sys/class/uio
Run mdev -s to make sure the /dev/uio0 correctly represents the UIO device. This command automatically creates device files in /dev for the devices found in: /sys/class/*
Try the gpio-uio-test command to turn on/off the LEDs on the board.
Top Previous Next