Step by step to build driver and application in linux



tải về 26.09 Kb.
Chuyển đổi dữ liệu30.08.2016
Kích26.09 Kb.



Greystone Data Systems Vietnam

Lot 62, Linh Trung Export Processing Zone II, Thu Duc District, HCMC, Vietnam






STEP BY STEP TO BUILD DRIVER AND APPLICATION IN LINUX





  1. Kernel Modules và các bước thao tác

Việc tạo ra 1 lớp driver trên linux được quản lý dưới dạng từng module chạy trong kernel, những module đó được gọi là kernel module. Mỗi module sẽ cung cấp những chức năng riêng biệt mà application có thể gọi xuống để thực thi.


Các bước thao tác với Kernel module

+ Xây dựng một mudule hoàn chỉnh.

+ Add module đã xậy dựng được vào kernel.

+ Viết application thao tác tới những chức năng mà module đó cung cấp.

+ Remove module ra khỏi kernel sau khi sử dụng xong.


  1. Các xây dựng một module hoàn chỉnh

  1. Tạo một module đơn giản để add và remove với kernel

#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);



  1. Xây dựng Char Driver trong 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 (which we get to in later chapters). Our ultimate aim is to write a modularized char driver.

We describe the older char device registration interface, but new code should not use it; this mechanism will likely go away in a future kernel.

The classic way to register a char device driver is with:


int register_chrdev(unsigned int major, const char *name,

struct file_operations *fops);

Here, major is the major number of interest, name is the name of the driver (it appears in /proc/devices), and fops is the default file_operations structure. A call to register_chrdev registers minor numbers 0-255 for the given major, and sets up a default cdev structure for each. Drivers using this interface must be prepared to handle open calls on all 256 minor numbers (whether they correspond to real devices or not), and they cannot use major or minor numbers greater than 255.

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.



Ioctl Method

The ioctl driver method has a prototype that differs somewhat from the user-space version:

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 and are the same parameters passed to the open method. The cmd argument is passed from the user unchanged, and 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

This include file declares functions used by kernel code to move data to and from user space.

#include


Copy data between user space and kernel space.

unsigned long copy_from_user (void *to, const void *from, unsigned long count);

unsigned long copy_to_user (void *to, const void *from, unsigned long count);


put_user(datum, ptr)

_ _put_user(datum, ptr)

These macros write the datum to user space; they are relatively fast and should be called instead of copy_to_user whenever single values are being transferred. The macros have been written to allow the passing of any type of pointer to put_user, as long as it is a user-space address. The size of the data transfer depends on the type of the ptr argument and is determined at compile time using the sizeof and typeof compiler builtins. As a result, if ptr is a char pointer, one byte is transferred, and so on for two, four, and possibly eight bytes.
get_user(local, ptr)

_ _get_user(local, ptr)

They behave like put_user and _ _put_user, but transfer data in the opposite direction. The value retrieved is stored in the local variable local.
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 first argument should be either VERIFY_READ or VERIFY_WRITE, depending on whether the action to be performed is reading the user-space memory area or writing it. The addr argument holds a user-space address, and size is a byte count. If ioctl, for instance, needs to read an integer value from user space, size is sizeof(int). If you need to both read and write at the given address, use VERIFY_WRITE, since it is a superset of VERIFY_READ. 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.




  1. Add module vào kernel và lấy device-name cho application

/sbin/insmode


File module của DF5 là gdsdf5_driver.o

Sau khi add module vào kernel, thì driver tương ứng sẽ được đăng ký trong /proc/devices dưới dạng sau:


frame1

Sau khi add module vào kernel, programer sẽ lấy Major number tương ứng trong /proc/devices bằng câu lệnh:

Major = `cat /proc/devices | awk "\\$2==\"$driver_name\" {print \\$1}"`
Và gán Major number vào /dev/device_name (sẽ được application sử dụng khi handle) bằng câu lệnh:

mknod /dev/${device}0 c Major 0


Các bước này tương ứng với ./load trên DF5:

#!/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}



  1. Xây dựng Application sử dụng các chức năng module cung cấp

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 actual nature of the third argument depends on the specific control command being issued (the second argument). Some commands take no arguments, some take an integer value, and some take a pointer to other data. 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 ) ;

Char devices are accessed through names in the filesystem. Those names are called special files or device files or simply nodes of the filesystem tree; they are conventionally located in the /dev directory



  1. Remove module ra khỏi kernel

rmmode

Tương ứng ./unload trên DF5



This controlled document is the property of Greystone Data Systems. Any duplication, reproduction, or transmission to unauthorized parties without the written permission of Greystone Data Systems is prohibited.







Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2019
được sử dụng cho việc quản lý

    Quê hương