海尔集团激励行为案例:Linux2.6内核驱动移植2

来源:百度文库 编辑:中财网 时间:2024/04/30 10:43:20
Linux2.6内核驱动移植2

随着Linux2.6的发布,由于2.6内核做了教的改动,各个设备的驱动程序在不同程度上要进行改写。为了方便各位Linux爱好者我把自己整理的这分文档share出来。该文当列举了2.6内核同以前版本的绝大多数变化,可惜的是由于时间和精力有限没有详细列出各个函数的用法。
特别声明:该文档中的内容来自http://lwn.net,该网也上也有各个函数的较为详细的说明可供各位参考。如果需要该文档的word版的朋友, 请mail到weiriver@sohu.com索取。 

1、 使用新的入口 
必须包含 
module_init(your_init_func);
module_exit(your_exit_func);
老版本:int init_module(void);
void cleanup_module(voi);
2.4中两种都可以用,对如后面的入口函数不必要显示包含任何头文件。

2、 GPL 
MODULE_LICENSE("Dual BSD/GPL");
老版本:MODULE_LICENSE("GPL"); 

3、 模块参数 
必须显式包含
module_param(name, type, perm);
module_param_named(name, value, type, perm);
参数定义
module_param_string(name, string, len, perm);
module_param_array(name, type, num, perm);
老版本:MODULE_PARM(variable,type);
MODULE_PARM_DESC(variable,type); 

4、 模块别名 
MODULE_ALIAS("alias-name");
这是新增的,在老版本中需在/etc/modules.conf配置,现在在代码中就可以实现。 

5、 模块计数 
int try_module_get(&module);
module_put();
老版本:MOD_INC_USE_COUNT 和 MOD_DEC_USE_COUNT 

6、 符号导出 
只有显示的导出符号才能被其他模块使用,默认不导出所有的符号,不必使用EXPORT_NO_SYMBOL*
老板本:默认导出所有的符号,除非使用**PORT_NO_SYMBOLS 

7、 内核版本检查 
需要在多个文件中包含时,不必定义__NO_VERSION__
老版本:在多个文件中包含时,除在主文件外的其他文件中必须定义__NO_VERSION__,防止版本重复定义。 

8、 设备号 
kdev_t被废除不可用,新的dev_t拓展到了32位,12位主设备号,20位次设备号。
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);
老版本:8位主设备号,8位次设备号
int MAJOR(kdev_t dev);
int MINOR(kdev_t dev); 

9、 内存分配头文件变更 
所有的内存分配函数包含在头文件,而原来的不存在
老版本:内存分配函数包含在头文件

10、 结构体的初试化 
gcc开始采用ANSI C的struct结构体的初始化形式:
static struct some_structure = {
.field1 = value,
.field2 = value,
...
};
老版本:非标准的初试化形式
static struct some_structure = {
field1: value,
field2: value,
...
}; 

11、 用户模式帮助器
int call_usermodehelper(char *path, char **argv, char **envp,
int wait);
新增wait参数 

12、 request_module() 
request_module("foo-device-%d", number);
老版本:
char module_name[32];
printf(module_name, "foo-device-%d", number);
request_module(module_name); 

13、 dev_t引发的字符设备的变化 

1、取主次设备号为
unsigned iminor(struct inode *inode);
unsigned imajor(struct inode *inode);

2、老的register_chrdev()用法没变,保持向后兼容,但不能访问设备号大于256的设备。

3、新的接口为

a)注册字符设备范围
int register_chrdev_region(dev_t from, unsigned count, char *name); 

b)动态申请主设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name);
看了这两个函数郁闷吧^_^!怎么和file_operations结构联系起来啊?别急!

c)包含 ,利用struct cdev和file_operations连接
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *cdev, struct file_operations *fops);
int cdev_add(struct cdev *cdev, dev_t dev, unsigned count);
(分别为,申请cdev结构,和fops连接,将设备加入到系统中!好复杂啊!)
 
d)void cdev_del(struct cdev *cdev);
只有在cdev_add执行成功才可运行。 

e)辅助函数
kobject_put(&cdev->kobj);
struct kobject *cdev_get(struct cdev *cdev);
void cdev_put(struct cdev *cdev);
这一部分变化和新增的/sys/dev有一定的关联。

14、 新增对/proc的访问操作 


以前的/proc中只能得到string, seq_file操作能得到如long等多种数据。
相关函数:
static struct seq_operations 必须实现这个类似file_operations得数据中得各个成员函数。
seq_printf();
int seq_putc(struct seq_file *m, char c);
int seq_puts(struct seq_file *m, const char *s);
int seq_escape(struct seq_file *m, const char *s, const char *esc);
int seq_path(struct seq_file *m, struct vfsmount *mnt,
struct dentry *dentry, char *esc);
seq_open(file, &ct_seq_ops);
等等 

15、 底层内存分配 
1、头文件改为
2、分配标志GFP_BUFFER被取消,取而代之的是GFP_NOIO 和 GFP_NOFS
3、新增__GFP_REPEAT,__GFP_NOFAIL,__GFP_NORETRY分配标志
4、页面分配函数alloc_pages(),get_free_page()被包含在
5、对NUMA系统新增了几个函数:
a) struct page *alloc_pages_node(int node_id,
unsigned int gfp_mask,
unsigned int order);
b) void free_hot_page(struct page *page);
c) void free_cold_page(struct page *page);
6、 新增Memory pools

mempool_t *mempool_create(int min_nr,
mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn,
void *pool_data);
void *mempool_alloc(mempool_t *pool, int gfp_mask);
void mempool_free(void *element, mempool_t *pool);
int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask); 

16、 per-CPU变量 
get_cpu_var();
put_cpu_var();
void *alloc_percpu(type);
void free_percpu(const void *);
per_cpu_ptr(void *ptr, int cpu)
get_cpu_ptr(ptr)
put_cpu_ptr(ptr)
老版本使用
DEFINE_PER_CPU(type, name);
EXPORT_PER_CPU_SYMBOL(name);
EXPORT_PER_CPU_SYMBOL_GPL(name);
DECLARE_PER_CPU(type, name);
DEFINE_PER_CPU(int, mypcint);
2.6内核采用了可剥夺得调度方式这些宏都不安全。 

17、 内核时间变化 

1、现在的各个平台的HZ为
Alpha: 1024/1200; ARM: 100/128/200/1000; CRIS: 100; i386: 1000; IA-64: 1024; M68K: 100; M68K-nommu: 50-1000; MIPS: 100/128/1000; MIPS64: 100; PA-RISC: 100/1000; PowerPC32: 100; PowerPC64: 1000; S/390: 100; SPARC32: 100; SPARC64: 100; SuperH: 100/1000; UML: 100; v850: 24-100; x86-64: 1000.
2、由于HZ的变化,原来的jiffies计数器很快就溢出了,引入了新的计数器jiffies_64
3、#include 
u64 my_time = get_jiffies_64();
4、新的时间结构增加了纳秒成员变量
struct timespec current_kernel_time(void);
5、他的timer函数没变,新增
void add_timer_on(struct timer_list *timer, int cpu);
6、新增纳秒级延时函数
ndelay();
7、POSIX clocks 参考kernel/posix-timers.c 

18、 工作队列(workqueue)

1、任务队列(task queue )接口函数都被取消,新增了workqueue接口函数
struct workqueue_struct *create_workqueue(const char *name);
DECLARE_WORK(name, void (*function)(void *), void *data);
INIT_WORK(struct work_struct *work,
void (*function)(void *), void *data);
PREPARE_WORK(struct work_struct *work,
void (*function)(void *), void *data);
2、申明struct work_struct结构
int queue_work(struct workqueue_struct *queue,
struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *queue,
struct work_struct *work,
unsigned long delay);
int cancel_delayed_work(struct work_struct *work);
void flush_workqueue(struct workqueue_struct *queue);
void destroy_workqueue(struct workqueue_struct *queue);
int schedule_work(struct work_struct *work);
int schedule_delayed_work(struct work_struct *work, unsigned long delay); 

19、 新增创建VFS的"libfs"

libfs给创建一个新的文件系统提供了大量的API.
主要是对struct file_system_type的实现。
参考源代码:
drivers/hotplug/pci_hotplug_core.c
drivers/usb/core/inode.c
drivers/oprofile/oprofilefs.c
fs/ramfs/inode.c
fs/nfsd/nfsctl.c (simple_fill_super() example) 

20、 DMA的变化 

未变化的有:
void *pci_alloc_consistent(struct pci_dev *dev, size_t size,
dma_addr_t *dma_handle);
void pci_free_consistent(struct pci_dev *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
变化的有:
1、 void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, int flag);
void dma_free_coherent(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
2、列举了映射方向:
enum dma_data_direction {
DMA_BIDIRECTIONAL = 0,
DMA_TO_DEVICE = 1,
DMA_FROM_DEVICE = 2,
DMA_NONE = 3,
};
3、单映射
dma_addr_t dma_map_single(struct device *dev, void *addr,
size_t size,
enum dma_data_direction direction);
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
size_t size,
enum dma_data_direction direction);
4、页面映射
dma_addr_t dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction direction);
void dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
size_t size,
enum dma_data_direction direction);
5、有关scatter/gather的函数:
int dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction);
void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int nhwentries, enum dma_data_direction direction);
6、非一致性映射(Noncoherent DMA mappings)
void *dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, int flag);
void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
unsigned long offset, size_t size,
enum dma_data_direction direction);
void dma_free_noncoherent(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
7、DAC (double address cycle)
int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
void pci_dac_dma_sync_single(struct pci_dev *dev,
dma64_addr_t dma_addr,
size_t len, int direction); 

21、 互斥 

新增seqlock主要用于:
1、少量的数据保护
2、数据比较简单(没有指针),并且使用频率很高
3、对不产生任何副作用的数据的访问
4、访问时写者不被饿死

初始化
seqlock_t lock1 = SEQLOCK_UNLOCKED;
或seqlock_t lock2; seqlock_init(&lock2);
void write_seqlock(seqlock_t *sl);
void write_sequnlock(seqlock_t *sl);
int write_tryseqlock(seqlock_t *sl);
void write_seqlock_irqsave(seqlock_t *sl, long flags);
void write_sequnlock_irqrestore(seqlock_t *sl, long flags);
void write_seqlock_irq(seqlock_t *sl);
void write_sequnlock_irq(seqlock_t *sl);
void write_seqlock_bh(seqlock_t *sl);
void write_sequnlock_bh(seqlock_t *sl);
unsigned int read_seqbegin(seqlock_t *sl);
int read_seqretry(seqlock_t *sl, unsigned int iv);
unsigned int read_seqbegin_irqsave(seqlock_t *sl, long flags);
int read_seqretry_irqrestore(seqlock_t *sl, unsigned int iv, long flags); 

22、 内核可剥夺 


preempt_disable();
preempt_enable_no_resched();
preempt_enable_noresched();
preempt_check_resched(); 

23、 眠和唤醒 

1、原来的函数可用,新增下列函数:
prepare_to_wait_exclusive();
prepare_to_wait();
2、等待队列的变化
typedef int (*wait_queue_func_t)(wait_queue_t *wait,
unsigned mode, int sync);
void init_waitqueue_func_entry(wait_queue_t *queue,
wait_queue_func_t func); 

24、 新增完成事件(completion events) 


init_completion(&my_comp);
void wait_for_completion(struct completion *comp);
void complete(struct completion *comp);
void complete_all(struct completion *comp); 

25、 RCU(Read-copy-update)

rcu_read_lock();
void call_rcu(struct rcu_head *head, void (*func)(void *arg),
void *arg);

26、 中断处理 

1、中断处理有返回值了。
IRQ_RETVAL(handled);
2、cli(), sti(), save_flags(), 和 restore_flags()不再有效,应该使用local_save_flags() 或local_irq_disable()。
3、synchronize_irq()函数有改动
4、新增int can_request_irq(unsigned int irq, unsigned long flags);
5、 request_irq() 和free_irq() 从 改到了  

27、 异步I/O(AIO) 


ssize_t (*aio_read) (struct kiocb *iocb, char __user *buffer,
size_t count, loff_t pos);
ssize_t (*aio_write) (struct kiocb *iocb, const char __user *buffer,
size_t count, loff_t pos);
int (*aio_fsync) (struct kiocb *, int datasync);
新增到了file_operation结构中。
is_sync_kiocb(struct kiocb *iocb);
int aio_complete(struct kiocb *iocb, long res, long res2);

28、 网络驱动 

1、struct net_device *alloc_netdev(int sizeof_priv, const char *name,
void (*setup)(struct net_device *));
struct net_device *alloc_etherdev(int sizeof_priv);
2、新增NAPI(New API)
void netif_rx_schedule(struct net_device *dev);
void netif_rx_complete(struct net_device *dev);
int netif_rx_ni(struct sk_buff *skb);
(老版本为netif_rx())

29、 USB驱动 

老版本struct usb_driver取消了,新的结构体为
struct usb_class_driver {
char *name;
struct file_operations *fops;
mode_t mode;
int minor_base;
};
int usb_submit_urb(struct urb *urb, int mem_flags);
int (*probe) (struct usb_inte***ce *intf,
const struct usb_device_id *id);

30、 block I/O 层 

这一部分做的改动最大。不祥叙。

31、 mmap()

int remap_page_range(struct vm_area_struct *vma, unsigned long from,
unsigned long to, unsigned long size,
pgprot_t prot);
int io_remap_page_range(struct vm_area_struct *vma, unsigned long from,
unsigned long to, unsigned long size,
pgprot_t prot);
struct page *(*nopage)(struct vm_area_struct *area,
unsigned long address,
int *type);
int (*populate)(struct vm_area_struct *area, unsigned long address,
unsigned long len, pgprot_t prot, unsigned long pgoff,
int nonblock);
int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, struct page *page,
pgprot_t prot);
struct page *vmalloc_to_page(void *address); 

32、 零拷贝块I/O(Zero-copy block I/O) 

struct bio *bio_map_user(struct block_device *bdev,
unsigned long uaddr,
unsigned int len,
int write_to_vm);
void bio_unmap_user(struct bio *bio, int write_to_vm);
int get_user_pages(struct task_struct *task,
struct mm_struct *mm,
unsigned long start,
int len,
int write,
int force,
struct page **pages,
struct vm_area_struct **vmas); 

33、 高端内存操作kmaps 

void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *address, enum km_type type);
struct page *kmap_atomic_to_page(void *address);
老版本:kmap() 和 kunmap()。

34、 驱动模型

主要用于设备管理。
1、 sysfs
2、 Kobjects 

A unified device number allocator 

Traditionally, device drivers have added their devices to the system with calls to register_chrdev() or register_blkdev(). These functions served two functions: allocating a portion of the device number space, and ****** specific devices available to user space. In 2.6, things changed a bit. For character devices, register_chrdev() was replaced by the combination of alloc_chrdev_region(), which allocates device numbers, and cdev_add(), which attaches a device to a specific number. On the block side, register_blkdev() has become optional, but it can still be used to allocate a block major number. The association of block devices with numbers is done with add_disk(). 

In other words, the allocation of device number space and the association of specific numbers with devices have been split in the 2.6 kernel. Matt Mackall was looking at the allocation side recently, where he notice* * **ir amount of duplicated code between the char and block implementations. The current code is also unable to perform dynamic allocation of major numbers outside of the traditional 0..255 range. So Matt put together a patch which cleans things up a bit. 

The new allocation scheme relies on simple linked lists. When a new device number request comes in, the code searches the (sorted) list to see if the request can be satisfied. If so, a new entry is added to the list, and the starting device number is returned. This work is done by the new function register_dev(): 

  int register_dev(dev_t base, dev_t top, int size, const char *name,
           struct list_head *list, dev_t *ret);
This function requests that a range of size numbers be allocated from the given list. The first number should fall between base and top; if a suitable range is found, that first number will be returned in ret. The list is a simple, list_head structure which is initially empty; the caller must provide locking to prevent concurrent calls to register_dev() using the same list. 

The new inte***ce works; it also replaces a fair amount of common code in the char and block code. Other than some quibbles about potential performance problems resulting from the linear list search algorithm (which should not really matter, since device number allocation is a rare operation), there seem to be no real objections to the new scheme. So it may find its way into a -mm kernel before too long. 

A future change would allow the dynamic allocation of device numbers in the expanded range; for now, dynamic major numbers are allocated from 254 in descending order, as has been done for many years. The patch also retains the register_chrdev() and register_blkdev() inte***ces in a compatibility mode - even though both were essentially obsolete even before the change. At some point in the future, there may be an attempt to deprecate those inte***ces; that move would force changes in a great many drivers.