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.)  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.

pdf17 trang | Chia sẻ: candy98 | Lượt xem: 465 | Lượt tải: 0download
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