Linux Device Drivers 2nd Edition (779877), страница 15
Текст из файла (страница 15)
This is a case where it is not sufficient to define afew compatibility macros; instead, portability requires a fair amount of conditionalpreprocessor code, but the concepts are simple. The first step is to identify thekernel version in use and to define some symbols accordingly. What we chose todo in sysdep.h is define a macro REGISTER_SYMTAB() that expands to nothingon version 2.2 and later and expands to register_symtab on version 2.0. Also,_ _USE_OLD_SYMTAB_ _ is defined if the old code must be used.By making use of this code, a module that exports symbols may now do soportably. In the sample code is a module, called misc-modules/export.c, that doesnothing except export one symbol. The module, covered in more detail in “Version Control in Modules” in Chapter 11, includes the following lines to export thesymbol portably:#ifdef _ _USE_OLD_SYMTAB_ _static struct symbol_table export_syms = {#include <linux/symtab_begin.h>X(export_function),#include <linux/symtab_end.h>};#elseEXPORT_SYMBOL(export_function);#endifint export_init(void){REGISTER_SYMTAB(&export_syms);return 0;}4922 June 2001 16:34http://openlib.org.uaChapter 2: Building and Running ModulesIf _ _USE_OLD_SYMTAB_ _ is set (meaning that you are dealing with a 2.0 kernel), the symbol_table structure is defined as needed; otherwise, EXPORT_SYMBOLis used to export the symbol directly.
Then, in init_module, REGISTER_SYMTABis called; on anything but a 2.0 kernel, it will expand to nothing.Module Configuration ParametersMODULE_PARM was introduced in kernel version 2.1.18. With the 2.0 kernel, noparameters were declared explicitly; instead, insmod was able to change the valueof any variable within the module. This method had the disadvantage of providinguser access to variables for which this mode of access had not been intended;there was also no type checking of parameters. MODULE_PARM makes moduleparameters much cleaner and safer, but also makes Linux 2.2 modules incompatible with 2.0 kernels.If 2.0 compatibility is a concern, a simple preprocessor test can be used to definethe various MODULE_ macros to do nothing.
The header file sysdep.h in the sample code defines these macros when needed.Quick ReferenceThis section summarizes the kernel functions, variables, macros, and /pr oc filesthat we’ve touched on in this chapter. It is meant to act as a reference. Each itemis listed after the relevant header file, if any. A similar section appears at the endof every chapter from here on, summarizing the new symbols introduced in thechapter._ _KERNEL_ _MODULEPreprocessor symbols, which must both be defined to compile modularizedkernel code._ _SMP_ _A preprocessor symbol that must be defined when compiling modules forsymmetric multiprocessor systems.int init_module(void);void cleanup_module(void);Module entry points, which must be defined in the module object file.#include <linux/init.h>module_init(init_function);module_exit(cleanup_function);The modern mechanism for marking a module’s initialization and cleanupfunctions.5022 June 2001 16:34http://openlib.org.uaQuick Reference#include <linux/module.h>Required header.
It must be included by a module source.MOD_INC_USE_COUNT;MOD_DEC_USE_COUNT;MOD_IN_USE;Macros that act on the usage count./pr oc/modulesThe list of currently loaded modules. Entries contain the module name, theamount of memory each module occupies, and the usage count. Extra stringsare appended to each line to specify flags that are currently active for themodule.EXPORT_SYMTAB;Preprocessor macro, required for modules that export symbols.EXPORT_NO_SYMBOLS;Macro used to specify that the module exports no symbols to the kernel.EXPORT_SYMBOL (symbol);EXPORT_SYMBOL_NOVERS (symbol);Macro used to export a symbol to the kernel. The second form exports without using versioning information.int register_symtab(struct symbol_table *);Function used to specify the set of public symbols in the module.
Used in 2.0kernels only.#include <linux/symtab_begin.h>X(symbol),#include <linux/symtab_end.h>Headers and preprocessor macro used to declare a symbol table in the 2.0kernel.MODULE_PARM(variable, type);MODULE_PARM_DESC (variable, description);Macros that make a module variable available as a parameter that may beadjusted by the user at module load time.MODULE_AUTHOR(author);MODULE_DESCRIPTION(description);MODULE_SUPPORTED_DEVICE(device);Place documentation on the module in the object file.5122 June 2001 16:34http://openlib.org.uaChapter 2: Building and Running Modules#include <linux/version.h>Required header. It is included by <linux/module.h>,_ _NO_VERSION_ _ is defined (see later in this list).unlessLINUX_VERSION_CODEInteger macro, useful to #ifdef version dependencies.char kernel_version[] = UTS_RELEASE;Required variable in every module.
<linux/module.h> defines it, unless_ _NO_VERSION_ _ is defined (see the following entry)._ _NO_VERSION_ _Preprocessor symbol.<linux/module.h>.Preventsdeclarationofkernel_versionin#include <linux/sched.h>One of the most important header files. This file contains definitions of muchof the kernel API used by the driver, including functions for sleeping andnumerous variable declarations.struct task_struct *current;The current process.current->pidcurrent->commThe process ID and command name for the current process.#include <linux/kernel.h>int printk(const char * fmt, .
. . );The analogue of printf for kernel code.#include <linux/malloc.h>void *kmalloc(unsigned int size, int priority);void kfree(void *obj);Analogue of malloc and fr ee for kernel code. Use the value of GFP_KERNELas the priority.#include <linux/ioport.h>int check_region(unsigned long from, unsigned long extent);struct resource *request_region(unsigned long from, unsignedlong extent, const char *name);void release_region(unsigned long from, unsigned longextent);Functions used to register and release I/O ports.5222 June 2001 16:34http://openlib.org.uaQuick Referenceint check_mem_region (unsigned long start, unsigned longextent);struct resource *request_mem_region (unsigned long start,unsigned long extent, const char *name);void release_mem_region (unsigned long start, unsigned longextent);Macros used to register and release I/O memory regions./pr oc/ksymsThe public kernel symbol table./pr oc/ioportsThe list of ports used by installed devices./pr oc/iomemThe list of allocated memory regions.5322 June 2001 16:34http://openlib.org.uaCHAPTER THREECHAR DRIVERSThe goal of this chapter is to write a complete char device driver.
We’ll develop acharacter driver because this class is suitable for most simple hardware devices.Char drivers are also easier to understand than, for example, block drivers or network drivers. Our ultimate aim is to write a modularized char driver, but we won’ttalk about modularization issues in this chapter.Throughout the chapter, we’ll present code fragments extracted from a real devicedriver: scull, short for Simple Character Utility for Loading Localities. scull is a chardriver that acts on a memory area as though it were a device. A side effect of thisbehavior is that, as far as scull is concerned, the word device can be used interchangeably with “the memory area used by scull.”The advantage of scull is that it isn’t hardware dependent, since every computerhas memory.
scull just acts on some memory, allocated using kmalloc. Anyone cancompile and run scull, and scull is portable across the computer architectures onwhich Linux runs. On the other hand, the device doesn’t do anything “useful”other than demonstrating the interface between the kernel and char drivers andallowing the user to run some tests.The Design of scullThe first step of driver writing is defining the capabilities (the mechanism) thedriver will offer to user programs.
Since our “device” is part of the computer’smemory, we’re free to do what we want with it. It can be a sequential or randomaccess device, one device or many, and so on.To make scull be useful as a template for writing real drivers for real devices, we’llshow you how to implement several device abstractions on top of the computermemory, each with a different personality.The scull source implements the following devices. Each kind of device implemented by the module is referred to as a type :5422 June 2001 16:35http://openlib.org.uaMajor and Minor Numbersscull0 to scull3Four devices each consisting of a memory area that is both global and persistent. Global means that if the device is opened multiple times, the data contained within the device is shared by all the file descriptors that opened it.Persistent means that if the device is closed and reopened, data isn’t lost.
Thisdevice can be fun to work with, because it can be accessed and tested usingconventional commands such as cp, cat, and shell I/O redirection; we’ll examine its internals in this chapter.scullpipe0 to scullpipe3Four FIFO (first-in-first-out) devices, which act like pipes. One process readswhat another process writes.
If multiple processes read the same device, theycontend for data. The internals of scullpipe will show how blocking and nonblocking read and write can be implemented without having to resort to interrupts. Although real drivers synchronize with their devices using hardwareinterrupts, the topic of blocking and nonblocking operations is an importantone and is separate from interrupt handling (covered in Chapter 9).scullsinglescullprivsculluidscullwuidThese devices are similar to scull0, but with some limitations on when anopen is permitted. The first (scullsingle) allows only one process at a time touse the driver, whereas scullpriv is private to each virtual console (or X terminal session) because processes on each console/terminal will get a differentmemory area from processes on other consoles.