Difference between revisions of "EBC Exercise 26 Device Drivers"

From eLinux.org
Jump to: navigation, search
m (Minimal Device Driver Example: Updated for Molloy's example)
m (Passing Parameters: Added)
Line 65: Line 65:
  
 
should show your Exit message.
 
should show your Exit message.
 +
 +
==== Passing Parameters ====
 +
You can pass parameters when inserting a module. 
 +
 +
bone$ '''sudo insmod hello.ko name="Prof.Yoder"'''
 +
bone$ '''dmesg -H | tail -1'''
 +
[Sep24 16:53] EBB: Hello Prof.Yoder from the BBB LKM!
 +
bone$ '''sudo rmmod hello'''
 +
bone$ '''dmesg -H | tail -2'''
 +
[Sep24 16:53] EBB: Hello Prof.Yoder from the BBB LKM!
 +
[Sep24 16:54] EBB: Goodbye Prof.Yoder from the BBB LKM!
  
 
== Improvements to the Code in the Book==
 
== Improvements to the Code in the Book==

Revision as of 13:55, 24 September 2018

thumb‎ Embedded Linux Class by Mark A. Yoder


Derek Molloy's excelent Exploring BeagleBone [1] has an Extra Content section [2] on Linux Kernel Programming. Part 1 [3] is a nice example of a writing a minimal kernel module.

Here are instructions for compiling the example on the Bone.

Minimal Device Driver Example

Compiling

You need to load the correct kernel headers on the bone before you can compile the driver.

bone$ time sudo apt install linux-headers-`uname -r`

Note: Those are back quotes (top left on the keyboard, above the TAB key) around uname -r.

The uname command looks up the number of the kernel that's currently running. The back quotes take that number and past it after linux-headers- and does an apt install on it. A couple minutes later you have all the headers loaded.

Now load the examples and change to the correct directory and make.

bone$ git clone https://github.com/derekmolloy/exploringBB.git
bone$ cd exploringBB/extras/kernel/hello
bone$ make
make -C /lib/modules/4.14.67-ti-r73/build/ M=/home/debian/exploringBB/extras/kernel/hello modules
make[1]: Entering directory '/usr/src/linux-headers-4.14.67-ti-r73'
  CC [M]  /home/debian/exploringBB/extras/kernel/hello/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/debian/exploringBB/extras/kernel/hello/hello.mod.o
  LD [M]  /home/debian/exploringBB/extras/kernel/hello/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.14.67-ti-r73'
bone$ ls
 hello.c   hello.mod.c  hello.o   modules.order
hello.ko  hello.mod.o  Makefile  Module.symvers

Your newly compiled kernel module is in hello.ko.

Inserting your module

See if your module is there

bone$ modinfo hello
filename:       /home/debian/exploringBB/extras/kernel/hello/hello.ko
version:        0.1
description:    A simple Linux driver for the BBB.
author:         Derek Molloy
license:        GPL
srcversion:     0DD9FE0DE42157F9221E608
depends:        
name:           hello
vermagic:       4.14.67-ti-r73 SMP preempt mod_unload modversions ARMv7 p2v8 
parm:           name:The name to display in /var/log/kern.log (charp)

That looks good, now insmod the module and check the log file.

bone$ insmod hello.ko
bone$ dmesg -H | tail -1

[ +2.857480] EBB: Hello world from the BBB LKM!

You should see your Init message. And then...

bone$ rmmod hello
bone$ dmesg -H | tail -2
[  +4.182591] EBB: Hello world from the BBB LKM!
[  +3.542350] EBB: Goodbye world from the BBB LKM!

should show your Exit message.

Passing Parameters

You can pass parameters when inserting a module.

bone$ sudo insmod hello.ko name="Prof.Yoder"
bone$ dmesg -H | tail -1
[Sep24 16:53] EBB: Hello Prof.Yoder from the BBB LKM!
bone$ sudo rmmod hello
bone$ dmesg -H | tail -2
[Sep24 16:53] EBB: Hello Prof.Yoder from the BBB LKM!
[Sep24 16:54] EBB: Goodbye Prof.Yoder from the BBB LKM!

Improvements to the Code in the Book

The code in Listing 8-10 is incomplete. If you compile it as is and load the module, it will work, but if you then remove the module and try to reinsert it it may fail with an error. The reason for this is that the module is registered with the kernel on load with a command like this:

register_chrdev(MAJOR_NUMBER, NAME, FILE_OPERATIONS*);

But it is never unregistered when the module is unloaded. To properly unload the module, add this line of code to your module's exit function

unregister_chrdev(MAJOR_NUMBER, NAME);

This will properly unregister the module from the kernel and allow it to be inserted and removed from the kernel at will without restarting your system in between.

Listing 8-10 also uses the ioctl field in the file_operations struct. Newer kernels have removed this. If the code from the listing complains about ioctl being an unknown field, use unlocked_ioctl in its place:

struct file_operations hello_fops = {
    owner:           THIS_MODULE,
    read:            hello_read,
    write:           hello_write,
    unlocked_ioctl:  hello_ioctl,
    open:            hello_open,
    release:         hello_release,
};

Driver Methods

Section 8.3 on page 217 gives a longer example of how to use the file interface with modules. Implement the example. Be sure to fix the unsigned int format error, and make sure your exit function unregisters the device (unlike the Listing). I've created a build.sh script based on Section 8.5 of the text that makes building much faster.

host$ cd exercises/modules
host$ ./build.sh
make: Entering directory `/home/yoder/BeagleBoard/linux-dev/KERNEL'
  CC [M]  /home/yoder/BeagleBoard/exercises/modules/hello1.o
  CC [M]  /home/yoder/BeagleBoard/exercises/modules/hello2.o
  CC [M]  /home/yoder/BeagleBoard/exercises/modules/hello3.o
  Building modules, stage 2.
  MODPOST 3 modules
  CC      /home/yoder/BeagleBoard/exercises/modules/hello1.mod.o
  LD [M]  /home/yoder/BeagleBoard/exercises/modules/hello1.ko
  CC      /home/yoder/BeagleBoard/exercises/modules/hello2.mod.o
  LD [M]  /home/yoder/BeagleBoard/exercises/modules/hello2.ko
  CC      /home/yoder/BeagleBoard/exercises/modules/hello3.mod.o
  LD [M]  /home/yoder/BeagleBoard/exercises/modules/hello3.ko
make: Leaving directory `/home/yoder/BeagleBoard/linux-dev/KERNEL'
Warning: Permanently added 'bone,192.168.7.2' (RSA) to the list of known hosts.
hello1.ko                                     100% 3571     3.5KB/s   00:00    
hello2.ko                                     100% 4344     4.2KB/s   00:00    
hello3.ko                                     100% 6097     6.0KB/s   00:00 

It just compiled all three modules and scp'ed them to the bone. A quick listing shows many intermediate files were created.

host$ ls -a
.               .hello1.mod.o.cmd  .hello2.mod.o.cmd  .hello3.mod.o.cmd
..              hello1.o           hello2.o           hello3.o
build.sh        .hello1.o.cmd      .hello2.o.cmd      .hello3.o.cmd
hello1.c        hello2.c           hello3.c           Makefile
hello1.ko       hello2.ko          hello3.ko          modules.order
.hello1.ko.cmd  .hello2.ko.cmd     .hello3.ko.cmd     Module.symvers
hello1.mod.c    hello2.mod.c       hello3.mod.c       .tmp_versions
hello1.mod.o    hello2.mod.o       hello3.mod.o

Clean the extra files up with

host$ ./clean.sh

Now go to the Beagle and move the .ko file to the right place.

beagle$ cd /lib/modules/3.8.13-bone28/kernel/drivers/char/examples
beagle$ cp ~/hello3.ko .

Rebuild the dependency file and insert the module.

beagle$ depmod -a
beagle$ modprobe hello3

Create a node for the module and test it.

beagle$ mknod /dev/hello3 c 234 0
beagle$ cat /dev/hello3 
beagle$ dmesg | tail -4
[   71.219651] [drm:output_poll_execute], [CONNECTOR:5:HDMI-A-1] status updated from 2 to 2
[   76.099158] hello_open: successful
[   76.099260] hello_read: returning zero bytes
[   76.099294] hello_release: successful

It working!

Some Questions

  • The major device number 234 is part of a range of unassigned numbers. What is the range?
  • What's the new line added to hello_init do?
  • What does mknod do?
  • Once your device is running try $ cat /proc/devices. Do you see your device?

Optional Driver Work

Chapter 3 of Linux Device Drivers by Corbet, Rubini and Kroah-Hartman ([4]) gives some more details on device drivers. Our text uses an older, static, method for major device number allocation. The book, referenced above, uses the newer dynamic allocation.

  • Convert the example in our text to use the newer method. It's only a couple of additional lines, but you will have to read the book to know how to do it.
  • Modify the scull_load script (call it hello_load) on page 47, of chapter 3, to load your module. Hint: the back quotes are missing in this line in the text:
major=`awk "\\$2==\"$module\" {print \\$1}" /proc/devices)`

  • Test it with use-hello.c from page 222 of Embedded Linux Primer.
  • Write a hello_unload script that will rmmod the driver and remove the nodes in /dev
  • Modify hello.c to pass the major device number in as a parameter during insmod.

Optional: Stretch time, I though these would be easy, but after reading up on them, they look rather involved.

  • How can your driver find what the minor device number is?
  • Modify the driver to return some characters when /dev/hello1 is read.

Reference

How to Write and Submit a Linux Kernel Patch




thumb‎ Embedded Linux Class by Mark A. Yoder