Chinaunix首页 | 论坛 | 博客
  • 博客访问: 829176
  • 博文数量: 168
  • 博客积分: 5431
  • 博客等级: 大校
  • 技术积分: 1560
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-22 11:56
文章存档

2015年(2)

2014年(1)

2013年(12)

2012年(12)

2011年(15)

2010年(5)

2009年(16)

2008年(41)

2007年(64)

分类: LINUX

2007-10-26 09:23:44

Linux Driver Development Note
By Stephen_du 07-4-12

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(0.0.0);
  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 a 2.1.14.1 kernel tarball
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 4G linear address space of high 3G which is from 0xC0000000 – 0xffffffff);And the kernel map the amount of physical memory into it( if physical memory is larger than 1024-128M the kernel still will keep 128M for “vmalloc”), the left virtual space are called “unmap” kernel space which will be used by “vmalloc”  and some special paging usage.
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 3G-4G space, but what about the details?And now I will talk about it.
  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;

Linux Driver Development Note

By Stephen_du 07-4-12



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(0.0.0);

  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 a 2.1.14.1 kernel tarball

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 4G linear address space of high 3G which is from 0xC0000000 – 0xffffffff);And the kernel map the amount of physical memory into it( if physical memory is larger than 1024-128M the kernel still will keep 128M for “vmalloc”), the left virtual space are called “unmap” kernel space which will be used by “vmalloc”  and some special paging usage.

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 3G-4G space, but what about the details?And now I will talk about it.

•  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;

 

阅读(1397) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~