Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Linux Device Driver Development Cookbook

You're reading from  Linux Device Driver Development Cookbook

Product type Book
Published in May 2019
Publisher Packt
ISBN-13 9781838558802
Pages 356 pages
Edition 1st Edition
Languages
Author (1):
Rodolfo Giometti Rodolfo Giometti
Profile icon Rodolfo Giometti

Table of Contents (14) Chapters

Preface Installing the Development System A Peek Inside the Kernel Working with Char Drivers Using the Device Tree Managing Interrupts and Concurrency Miscellaneous Kernel Internals Advanced Char Driver Operations Additional Information: Working with Char Drivers Additional Information: Using the Device Tree Additional Information: Managing Interrupts and Concurrency Additional Information: Miscellaneous Kernel Internals Additional Information: Advanced Char Driver Operations Other Books You May Enjoy

Miscellaneous Kernel Internals

When developing inside the kernel, we may need to do some miscellaneous activities to implement our device drivers, such as dynamically allocating memory and using specific data types in order to store register data, or simply actively waiting some time in order to be sure that a peripheral has completed its reset procedure.

To perform all these tasks, Linux offers to kernel developers a rich set of useful functions, macros, and data types that we'll try to present in this chapter through the means of very simple example codes, because we wish to point out to the reader how he/she can use them to simplify device driver development. That's why, in this chapter, we will cover the following recipes:

  • Using kernel data types
  • Managing helper functions
  • Dynamic memory allocation
  • Managing kernel linked lists
  • Using kernel hash tables
  • Getting access...

Technical requirements

Using kernel data types

Often, data items of a particular size are required by the kernel code to match predefined binary structures, to hold peripheral's register data, to communicate with userspace or to simply to align data within structures by inserting padding fields.

Sometimes, kernel code requires data items of a specific size, perhaps to match predefined binary structures, to communicate with userspace, to hold peripheral's register data, or simply to align data within structures by inserting padding fields.

In this section, we're going to see some special data types that can be used by kernel developers to simplify their everyday job. In the following, we're going to see an example with fixed-size data types, which are very useful to define some kind of data that is intended to match exactly the structure of data expected by a device or by a communication...

Managing helper functions

During device driver development, we may need to concatenate a string or to compute its length or just copy or move a memory region (or a string). To do these common operations in the user space, we can use several functions, such as strcat(), strlen(), memcpy() (or strcpy()), and so on, and Linux offers us similarly named functions, which, of course, are safely usable in the kernel. (Note that kernel code cannot be linked against userspace glibc libraries.)

In this recipe, we will see how to use some kernel helpers in order to manage strings within the kernel.

Getting ready

If we take a look inside kernel sources at the include file linux/include/linux/string.h, we can see a long list of usual userspace...

Dynamic memory allocation

A good device driver should support neither more than one peripheral and (possibly) not a fixed number of them! However, even if we decide to restrict driver usage to just one peripheral, it may happen that we need to manage a variable number of data chunks so, in any case, we need to be able to manage dynamic memory allocation.

In this recipe, we will see how we can dynamically (and safely) allocate chunks of memory in the kernel space.

How to do it...

In order to show how we can allocate from memory within the kernel by using kmalloc(), vmalloc(), and kvmalloc(), we can again use a kernel module.

Inside the mem_alloc.c file, we can see some really simple code that shows how memory allocation works...

Managing kernel linked lists

When programming inside the kernel, it could be useful to have the ability to manage lists of data, so, to reduce the amount of duplicated code, kernel developers have created a standard implementation of circular, doubly linked lists.

In this recipe, we will see how to use lists in our code by using the Linux API.

Getting ready

To demonstrate how the list API works, we can again use a kernel module where we do some operations inside the module's init() function, as done previously.

How to do it...

In the list.c file, there is our example...

Using kernel hash tables

As for kernel lists, Linux offers to kernel developers a common interface to manage hash tables. Their implementation is based on a special version of the kernel lists seen in the preceding section and named hlist (which is still a doubly linked list but with a single pointer list head). This API is defined in the header file, linux/include/linux/hashtable.h.

In this recipe, we will show how we can use hash tables in our kernel code by using the Linux API.

Getting ready

Even in this recipe, we can use a kernel module to see how a test code works.

How to do it...

...

Getting access to I/O memory

In this recipe, we will see how to get access to the internal peripherals of a CPU or to any other memory mapped device that is connected to the CPU.

Getting ready

This time, we'll present an example using an already existing piece of code in the kernel sources, so now there is nothing to compile, but we can go directly to the root directory of ESPRESSObin's kernel sources.

How to do it...

  1. A good and really simple example about how to do a memory remap is reported in the linux/drivers/reset/reset-sunxi.c file in the sunxi_reset_init...

Spending time in the kernel

In this recipe, we will take a look at how we can delay the execution after some time in the future by using busy loops or more complex functions that may involve a suspension.

Getting ready

Even in this recipe, we can use a kernel module to see how a test code works.

How to do it...

In the time.c file, we can find a simple example exemplifying how the preceding functions work:

  1. As the first step, we declare a utility function to get the execution time in nanoseconds, of a line of code:
#define print_time(str, code)     \
do { ...
lock icon The rest of the chapter is locked
You have been reading a chapter from
Linux Device Driver Development Cookbook
Published in: May 2019 Publisher: Packt ISBN-13: 9781838558802
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}