1. Building kernel module
1.1 Ex: The following code is a complete
"hello world" module
1. Building kernel module (cont.)
This module defines two functions, one to be invoked when the module is loaded into
the kernel (hello_init) and one for when the module is removed (hello_exit). The
module_init and module_exit lines use special kernel macros to indicate the role of
these two functions.
After success to build that code, you can test the module with the
insmod and rmmod utilities, as shown below. Note that only the
superuser can load and unload a module.
17 trang |
Chia sẻ: candy98 | Lượt xem: 465 | Lượt tải: 0
Bạn đang xem nội dung tài liệu Step by step to build driver and application in Linux, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
STEP BY STEP TO BUILD
DRIVER AND APPLICATION
IN LINUX
1. Building kernel module
1.1 Ex: The following code is a complete
"hello world" module:
1. Building kernel module (cont.)
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
This module defines two functions, one to be invoked when the module is loaded into
the kernel (hello_init) and one for when the module is removed (hello_exit). The
module_init and module_exit lines use special kernel macros to indicate the role of
these two functions
1. Building kernel module (cont.)
After success to build that code, you can test the module with the
insmod and rmmod utilities, as shown below. Note that only the
superuser can load and unload a module.
root# insmod ./hello.ko
Hello, world root
# rmmod hello
Goodbye cruel world
root#
1. Building kernel module (cont.)
1.2 Add Char driver to module
We develop a character driver because
- This class is suitable for most simple hardware devices.
- Char drivers are also easier to understand than block drivers or
network drivers.
The classic way to register a char device driver is with:
1. Building kernel module (cont.)
int register_chrdev (unsigned int major, const char *name,
struct file_operations *fops);
- major is the major number of interest
- name is the name of the driver (it appears in /proc/devices)
- fops is the default file_operations structure.
- A call to register_chrdev registers minor numbers 0-255 for the
given major.
If you use register_chrdev, the proper function to remove your
device(s) from the system is:
int unregister_chrdev(unsigned int major, const char *name);
- major and name must be the same as those passed to
register_chrdev, or the call will fail.
1. Building kernel module (cont.)
Ioctl Method
int (*ioctl) (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
- The inode and filp pointers are the values corresponding to the file
descriptor fd passed on by the application.
- The cmd argument is passed from the user unchanged.
- The optional arg argument is passed in the form of an unsigned
long, regardless of whether it was given by the user as an integer or
a pointer.
Most ioctl implementations consist of a big switch statement that
selects the correct behavior according to the cmd argument
1. Building kernel module (cont.)
This include file declares functions used by kernel code to move data to and
from user space.
#include
unsigned long copy_from_user (void *to, const void *from, unsigned long count);
- from: pointer in user-space
- to: pointer in kernel-space
- count: total bytes to copy
unsigned long copy_to_user (void *to, const void *from, unsigned long count);
- from: pointer in kernel-space
- to: pointer in user-space
- count: total bytes to copy
1. Building kernel module (cont.)
Macro:
put_user(datum, ptr)
_ _put_user(datum, ptr)
- These macros write the datum to user space;
- It is used whenever single values are being transferred.
- It allows the passing of any type of pointer to put_user.
- The size of the data transfer depends on the type of the ptr argument .
Macro:
get_user(local, ptr)
_ _get_user(local, ptr)
- They behave like put_user and _ _put_user, but transfer data in the opposite
direction.
1. Building kernel module (cont.)
Note: All functions and macros should only be used if the address
has already been verified with access_ok:
int access_ok (int type, const void *addr, unsigned long size);
- The type argument should be either VERIFY_READ or
VERIFY_WRITE.
- The addr argument holds a user-space address.
- size is a byte count.
If you need to both read and write at the given address, use
VERIFY_WRITE.
Unlike most kernel functions, access_ok returns a boolean value: 1
for success (access is OK) and 0 for failure (access is not OK). If it
returns false, the driver should usually return -EFAULT to the caller.
2. Adding module to kernel
Command:
/sbin/insmode
After calling insmod, reads /proc/devices in order to create the
special file(s). (/dev/driver_file)
A typical /proc/devices file looks like the following:
Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
5 cua
6 lp
7 vcs
10 misc
13 input
14 sound
29 fb
36 netlink
128 ptm
129 ptm
130 ptm
131 ptm
132 ptm
133 ptm
134 ptm
135 ptm
136 pts
137 pts
138 pts
139 pts
140 pts
141 pts
142 pts
143 pts
162 raw
180 usb
188 ttyUSB
253 DataFast5
254 DataFast5_INT
Block devices:
1 ramdisk
2 fd
3 ide0
9 md
12 unnamed
Command to get major number from /proc/devices:
Major = `cat /proc/devices | awk "\\$2==\"$driver_name\"
{print \\$1}"`
Adapting Major number to your device name which you will
use in application:
mknod /dev/${device}0 c Major 0
Ex: File ./load for DF5 machine:
#!/bin/sh
module="gdsdf5_driver"
device="gdsdf5"
mode="666"
# Group: since distributions do it differently, look for wheel or use staff
if grep '^staff:' /etc/group > /dev/null; then
group="staff"
else
group="wheel"
fi
# remove stale nodes
rm -f /dev/${device}?
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod ./$module.o $* || exit 1
#major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`
mknod /dev/${device}0 c 254 0
# give appropriate group/permissions
chgrp $group /dev/${device}0
chmod $mode /dev/${device}0
ln -sf ${device}0 /dev/${device}
Driver_name = DataFast5
major=`cat /proc/devices | awk "\\$2==\"$Driver_name\" {print \\$1}"`
/dev/${device}0 c $major 0
3. Building application
In user space, the ioctl system call has the following prototype:
int ioctl(int fd, unsigned long cmd, ...);
- The cmd argument is the same with this in kernel space.
- The third argument depends on the specific control command
being issued (the second argument). Using a pointer is the way to
pass arbitrary data to the ioctl call; the device is then able to
exchange any amount of data with user space.
- fd argument is file descriptor which passed on by the application
and are the same parameters passed to the open method.
fd = open ( device_name , mode_open ) ;
4. Removing kernel module
Command:
/sbin/rmmode
Ex: File ./unload for DF5 machine:
#!/bin/sh
module="gdsdf5_driver"
device="gdsdf5"
# invoke rmmod with all arguments we got
/sbin/rmmod $module $* || exit 1
# remove nodes
rm -f /dev/${device}0 /dev/${device}
exit 0
Thanks you
for your attention