分类: LINUX
2007-10-26 09:23:44
Linux Driver
Development Note
By Stephen_du
Part 1 Driver
Basic
•1>Development
environment building(for X86)
a. Usually, the system never keep the built kernel files in system, this
makes sense, but to driver developer, this is not so good and we have to build
them for our environment; It’s very easy:
*Download the
kernel for your system
*Configure the
options(
make
menuconfig,load the configure file from /boot/config-$(shell uanme -r))
*make
*make modules_install
*make
install
After these
,you’ll find the header files and module files for driver developing under
“/libmodules /”uname-r”/”; Then our X86 environment is ready for working!
2>Driver types
(to existing mode ):
a.
Build-in-kernel(the driver code been compiled into kernel and initialized
during booting)
b. Module-mode(the
driver moduls are inserted into kernel after the system has started)
If the application
needs the device for working and the kernel itself will dynamically insert the
moduels into the kernel)
The two types are both useful; The first fits for the devices which
needed to work just as soon as kernel booted, and the modules type fits for
which are not used so often and need’t to occupied the resources in the kernel
until needed!
3>Simple
example for a module mode driver
•#include
•#include
•static int
init_hello(void){
•printk(KERN_DEBUG”Hello
stephen-du!\n”);
•return 0;
•}
•staic void
exit_hello(void){
•printk(KERN_DEBUG”Bye
bye stephen_du!\n”);
•}
•module_init(init_hello);
•Module_exit(exit_hello);
•EXPORT_SYMBOL(init_hello);
•EXPORT_SYMBOL(exit_hello);
•MODULE_AUTHOR(“Stephen_du”);
•MODULE_DESCRIPTION(“First
driver!”);
•MODULE_VERSION(
Makefile
for the C code before:
•Ifneq($(KERNELRELEASE),)
•obj-m = hello.o
•else
•KERNELDIR = /lib/
moduels/$(shell uname -r)/build
•PWD = $(shell
pwd)
•default:
$(MAKE) –C
$(KERNELDIR) M=$(PWD) moduels
endif
Knowledge point:
#include
module_init(init_function);
init_function not pointer
module_exit(exit_function);
__init
__initdata
__exit
__exitdata
•#include
•struct
task_struct* curremt;
•current->pid;
•current->comm;
•Infrmation for
modules in the kernel:
•/proc/modules
•/sys/module
•vermagic.o
•#include
•MODULE_DEVICE_LABEL();
•MODULE_ALIAS();
#include
printk();
4>Built-in mode
is not so much different but needs attention:
First,code become this:
#ifdef MODULE//we
want it linked into kernel
#include<> ……….
#define
MODULE_INC_COUNT//mod_use_count add 1
#define
MODULE_DEC_COUNT
#endif
other codes
……………………………….
The source code needed to be copied into the related directory to different
types, and the add the file to the makefile, then add an item in the menu!
Part 2 Create
Cross Compile Driver Env And Kernel Image
•1>In part 1 we
have known how to compile driver module on X86 and now let’s come to arm
paltform!
a. Prepare the arm
toolchain for use
b. Get
c. Make sure the
options needed
d. Make sure the
version of toolchain and kernel matched, or
else problems will come out during insmod
e. Uncompress the
tarball in the directory for working (the toolchain must be laid under the path
you made it!!)
f.
Went into the kernel root and modify the Makefile(find out ARCH and
CROSS_COMPILE make them ARCH=arm CROSS_COMPILE=arm-linux- )
g. Add the nand
device partition info support for our rootfs and driver which are linked into
the kernel(This is the most important step!!)
h.
make menuconfig and choose for compiling(this is the second important for many
problems come out after the kernel image written into flash!!)
•i. make zImage or
make bzImage(for larger kernel image) ;Problems might be great trouble,
and mainly from the wrong option and toolchain,we must patiently kick out
these!
• j. The
zImage file is under arch/arm/boot/zImage, write it into flash and boot;
Whether succeed or not depends on your before steps!
•k. make
modules_install(the files installed /lib/modules/$(shell uname -r))
•Attentions:
a. The toolchain
must be a proper one, not too old or too new; It’s better make by ourselves to
our need
b. Don’t
choose the unneeded options ,this can make our kernel smaller and work more
effectively and avoid problems as not supported by our hardware!!
c. The driver
should be in proper mode as descript before
d. Be careful
about devfs, its very likely leads to problem as can’t find the mtdblock2!and
VFS syn failed!
e. The debugging
job is so boring and being careful and patient is most important!
Part 3 ROOTFS And
Busybox
•1>Building
rootfs
a. Prepare cramfs
tools(so easy and convenient)
b.
Prepare busybox tarball
c. make a new
directory for our rootfs and
uncompressed the
tarball somewhere then, enter into the directory
d.
Just as make kernel make menuconfig and choose what you needed
e.
make to compile ;then make install and the files will be installed under
_install directory by default and also you can choose other place by pointing
out in an option;
f.
Copy all the files under _install into the new directory we made before and
prepare the directory such as dev root tmp and etc and so on; Add the files
needed in the specific directory such as:
inittab under etc
fstab(can copied from the example directory!)
Init.d
After these steps
,use the mkcramfs command to make a ramdisk for writing. If everything goes
well we can go into driver development on our arm platform!
Part 3 Linux
Memory Space
•1)How Linux uses
physical memory
Linux manage
physical memory under the principle of page allocating, so no one other than linux
can access physical memory directly; The paging system “map” the physical
memory into a “virtual” memory space, and this space are mainly divided
into two parts:
Physical
space Logical space
1>The kernel
space
In kernel
space can only be used by kernel (The total
2>The user
space
User space are used by user programs and can be access randomly by kernel.
So,we can see the
kernel and user memory space are in different priority and make sense
Part 4 Linux
memory management
•1.Raw view
•1)Page and slab
Linux split
physical memory into small pieces which are called pages(The size of page is
different on special cpu platform;On arm it is 4K;PAGE_OFFSET and PAGE_SHIFT
are used for descripting it); This is the smallest size linux can allocate; But
this sometimes don’t work efficiently enough .For example large area
memory!
•Linux arrange
1page 4pages 8pages …till 256pages in a list and try to find a node fitting for
the request; Even so problem still exists,if we need a lot of 1K memory and you
will find memory wasted so slab is introduced in linux memory management
,that is complex and I will not discuss it!
•2)How pages are
mapped?
• We discuss
in part 1 linux map physical memory into high
• Linux uses
three layer map architecture for being compatible with cpus and in arm we just
use two in actual
Part 5 How to get
memory in the kernel space
•Get memory in
physical mapped area
•1)Get pages
void*
get_free_page()
void*get_free_pages()
•2)
Part 6 The 1st
kind of device:character device in linux
•1>Data
structure:
•#include
dev_t
contains the major
and minor device number
Int MAJOR(dev_t);
macro for getting
major number from dev_t;
Int MINOR(dev_t);
dev_t
MKDEV(unsigned int major,unsigned minor);
make a dev_t with
given major and minor
•#include
Int
register_chrdev_region(dev_t,unsigned int,char*);
Int
alloc_chrdev_region(dev_t,unsigned int ,unsigned int,char*);
void
unregister_chrdev_region(dev_t,unsigned int);
int
register_chrdev(unsigned int ,const char*,struct file_operations*);
struct
file_operations;
struct file;
struct inode;
•2>Sample for
character device :fb device
•
We can’t access the physical address in the kernel for the reason of linux
paging technology but linux has supplied us a way for this application! And we
can just “access” the physical address of displaying memory as will!
Technology used:
• a. virtual
to physical(macro __va())
phisical
virtual(macro __pa()) this will be explained in the next parts
b. ioremap()
this will map
displaying physical address to the kernel virtual address space
c. the
writeb(),readb(),writeb_p(),readb_p() and so on
these are
used for initialize the register for display panel
d. register_chrdev() and unregister_chrdev()(for 2.4 kernel)
e. kmalloc()
allocate memory
for driver in the kernel
f.
dma related
g. device node
structure
struct fb_info;
struct
file_operations
not ended
Part 7 The
Concurrency and Race Condition Control
•1>Semaphore
#include
struct
semaphore;
void
sem_init(struct semaphore*,int);
DECLARE_MUTEX(struct
semaphore*);
DECLARE_MUTEX_LOCKED(struct
semaphore*);
For dynamically
initializing a semaphore at runtime, use these while not uppers:
init_NUTEX(struct
semaphore*);
init_MUTEX_LOCKED(strcut
semaphore*);
int down(struct
semaphore*);(uninterruptible) decrease semaphore;
int
down_interruptible(struct semaphore*);
Int
down_trylock(struct semaphore*);if can’t lock return immediately
void up(struct
semaphore*);increase semaphore;