2.6内核编译安装和驱动开发

      2.4内核和2.6内核有了很大的不同。我在开发Ver2.6版本的linux驱动的时候,需要升级redhat9.0 kernal 2.4.20-8 kernal2.6.1,其中碰到了很多问题!现在把我在网上找到的内容和我的实际问题写出来,便于别的朋友可以少走弯路


2.6内核编译安装和驱动开发
 
1.     2.6内核的编译和安装

2.4内核和2.6内核有了很大的不同。我在开发Ver2.6版本的linux驱动的时候,需要升级redhat9.0 kernal 2.4.20-8 kernal2.6.1,其中碰到了很多问题!现在把我在网上找到的内容和我的实际问题写出来,便于别的朋友可以少走弯路。

(1)    先说明2.6内核的一些显著的不同之处
改进包括改善对硬件构架的支持。在新版内核中增加对最新AMD 64位Opteron CPU以及PowerPC 64位CPU的支持;
把ucLinux中的一些部分集成,可以支持很多嵌入式处理器
更好地支持多处理器系统,将支持16个或以上的CPU、更好地支持嵌入式设备、对点击鼠标和键盘的反应速度更快和彻底改善了块设备软件插件等。
使用新的new 0(1) 调度程序;
使用真正的异步I/O以改善企业应用;
提高了文件系统的性能;
改进了线程功能,可以支持更多的线程;
改进了对宽带联网的支持等。
 
(2)准备工作

下面是在文档中给出了欲成功地升级到kernel-2.6.x所需的最小系统软件要求

o Gnu C 2.95.3 # gcc –version
o Gnu make 3.79.1 # make –version
o binutils 2.12 # ld -v
o util-linux 2.10o # fdformat –version
o module-init-tools 0.9.10 # depmod -V

o e2fsprogs 1.29 # tune2fs
o jfsutils 1.1.3 # fsck.jfs -V
o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs
o xfsprogs 2.6.0 # xfs_db -V
o pcmcia-cs 3.1.21 # cardmgr -V
o quota-tools 3.09 # quota -V
o PPP 2.4.0 # pppd –version
o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
o nfs-utils 1.0.5 # showmount –version
o procps 3.2.0 # ps –version
o oprofile 0.5.3 # oprofiled -version
对于RH8/9的用户而言, 上述要求基本上都能满足. 大概只有两个程序需要更新: modutils工具包和mkinitrd程序. 在我用Redhat9.0升级到2.6.1内核的过程中,没有升级mkinitrd,如果要升级mkinitrd.请参考如下方法:
可以到站点http://people.redhat.com/arjanv/2.6/RPMS.kernel/去下载最新的mkinitrd-3.5.15.1-2.i386.rpm包. 由于mkinitrd程序包依赖于device-mapper包, 而device-mapper包又倚赖于lvm2包, 因此你还要同时下载device-mapper-1.00.07-1.i386.rpm包和lvm2-2.00.08-2.i386.rpm包.

  1. 安装module-init-tools-3.0.tar.gz工具包

# configure –prefix=/
# make moveold
# make all install
# ./generate-modprobe.conf /etc/modprobe.conf

命令"make moveold"将把系统原来的modutils工具程序改名为"*.old"(比如,lsmod.old等等). NOTE! 这是非常重要的一步, 千万不要省略. 这将使得你可以继续使用原有的linux-2.4.x系统, 因为在2.4.x系统下, 新的module-init-tools工具包实际上是倚赖原来"*.old"程序来加载内核模块. 如果忘记了这一步也不要紧张, 可以先下载并安装原来的modutils程序包, 然后按照上面的步骤重来一遍就可以了.
    新的module-init-tools工具包不再使用原来的/etc/modules.conf配置文件了, 而是使用新的配置文件/etc/modprobe.conf. 因此必需用命令"./generate-modprobe.conf /etc/modprobe.conf"来生成新的配置文件/etc/modprobe.conf. 但是令人不爽的是, 这个生成的新配置文件存在BUG, 下面我们将会提到。主要是一些相应的设备驱动别名的变化,还有/proc/中系统目录的变化。

  1. 升级modutils工具包

先下载modutils-2.4.21-23.src.rpm的软件包。我升级的时候,下载的是modutils-2.4.27-1的软件包。

#rpm -e –nodeps modutils (强行卸载原有的modutilsRPM包)

#rpm -ivh modutils-2.4.21-23.src.rpm (把源代码包安装到了/usr/src/redhat目录下)

#cd /usr/src/redhat/SPECS (进入规范文件目录下)

#rpmbuild –bb modutils.spec (生成二进制的RPM包)

#cd ../RPMS/i386 (转入刚生成的二进制的RPM包所在位置)

#rpm -ivh modutils*.rpm (刚生成两个[modutils-2.4.21-23.i386.rpmmodutils-debuginfo-2.4.21.23.i386.rpm]二进制的RPM包,全部安装)

c. 更改说明

◆ 如果是从以前的redhat低版本升级,需要修改/etc/rc.d/rc.sysinit文件,原因是在2.4内核下的/proc/ksysms命令到了2.6中就不存在了。

打开#vi /etc/rc.d/rc.sysinit

找到如下得语句

if ! LC_ALL=C grep -iq nomodules /proc/cmdline 2>/dev/null && [ -f /proc/ksyms ]; then

USEMODULES=y

fi

替换成:

if ! LC_ALL=C grep -iq nomodules /proc/cmdline 2>/dev/null; then

USEMODULES=y

fi

这样子在新的内核才能加载模块!

还有一种改法: 2.6系统下,原来/proc/ksyms改名/proc/kallsyms,做相应的替换修改。对于支持Hotplug,就要把所有的ksyms修改过来!
 
◆ 关于rpm命令不能用的问题,就版本的rpm存在bug, 在可以选择升级或者修改profile文件,如下:

#vi /etc/profile (在文件的末尾加上几句如下)
if [`uname -r`="2.6.0" ];then
export LD_ASSUME_KERNEL=2.2.5
fi

输出LD_ASSUME_KERNEL用来骗过rpm

当然也可以直接键入 #export LD_ASSUME_KERNEL=2.2.5

(3) 内核的编译顺序

  在官方网站上来,下载2.6的内核的开发包,解压:

#make mrproper (刚解开的tar包不需此步骤,用来清除以前编译的文件)

#make gconfig (需要Gtk开发库的支持)

make config(文本方式)

make menuconfig(文本方式下的,菜单模式)

make xconfig(需要Qt开发库的支持) 我用的这个.

配置内核是很重要的一步,错误的选择很可能导致新编译的内核无法启动。

o 关于"Loadable Module support"选项, 一定要选上"Module unloading"和"Automatic kernel module loading"这两个选项.
o 关于"Processor type and features"选项, 一定要选上"Preemptible Kernel"选项, 这是2.6.x内核优于2.4.x内核的重要原因之一.
o 关于"Block Devices"的配置, 一定要选上对loopback和ramdisk的支持.
o 关于"Multi-device support(RAID and LVM)", 要选上"device mapper".
o 关于"Input device support", 记得要选上"Keyboards"和"Mice"的支持.
o 关于"Graphics support", 要选上对frame buffer的支持.
o 关于ALSA, 要选上"OSS API emulation"选项. OSS可以不用了.
o 关于USB, 能选的都选上吧
o 关于文件系统, 选上常用的那几种就可以了. 如果要体验sysfs的话, 要选上对sysfs的支持.

需要强调的是,为了防止文件系统挂接问题,定制内核配置文件时把对Ext3Ext2文件的支持直接编译进内核。不要选成Module方式!

      开始编译,make dep对于2.6已经不需要了。
# make bzImage
# make modules
# make modules_install
# make install
使用Grub作为引导程序,make install会自动把相应的引导配置写入Grub,很是方便。如果用lilo需要自己修改。

新内核的问题,对于usb的设备,通用USB host控制器驱动程序的别名更改为uhci-hcd (以前为usb-uhci)。支持USB键盘的模块名字也从keybdev变为usbkbd, 支持USB鼠标的模块名字也从mousedev改为usbmouse。usbcore2.6内核的usb设备核心。如果使用usb设备,需要修改相应的rc.sysinit文件。

另外一个比较大的变化,驱动的后缀名,从2.4*.o 变成 *.ko,对应有的驱动配置文件,要做相应的修改,在可以安装。
2.     2.6内核的驱动开发

  通过上面的修改,我们已经存在一个可以开发和测试Linux驱动的环境了,下面让我们了解一下2.6的驱动做了那些修改。

变化的内容比较多,我们只讲一些主要的。具体请参考参考文档[5]
内核版本检查
需要在多个文件中包含<linux/module.h>时,不必定义__NO_VERSION__
老版本:在多个文件中包含<linux/module.h>时,除在主文件外的其他文件中必须定义_
_NO_VERSION__,防止版本重复定义。
内存分配头文件变更
所有的内存分配函数包含在头文件<linux/slab.h>,而原来的<linux/malloc.h>不存在
老版本:内存分配函数包含在头文件<linux/malloc.h>
结构体的初试化
gcc开始采用ANSI Cstruct结构体的初始化形式:
static struct some_structure = {
.field1 = value,
.field2 = value,
..
};
老版本:非标准的初试化形式
static struct some_structure = {
field1: value,
field2: value,
..
};
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);
中断处理
1、中断处理有返回值了。
IRQ_RETVAL(handled)
2cli(), sti(), save_flags(), restore_flags()不再有效,应该使用local_save
_flags() local_irq_disable()
3synchronize_irq()函数有改动
4、新增int can_request_irq(unsigned int irq, unsigned long flags);
5 request_irq() free_irq() <linux/sched.h>改到了 <linux/interrupt.h>
网络驱动
1struct 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);
intnetif_rx_ni(struct sk_buff *skb);
(
老版本为netif_rx())
 

上面列到很多不同,实际开发驱动的时候,是另外一回事情。我们比较一下linux2.4.20,2.4.26,2.6.1网卡驱动的不同来分析驱动的变化。

 

比如我对2.4.262.6.1via_rhine.比较,其中via-rhine.c2.6.1的。

正在比较文件 via-rhine.c VIA-RHINE_2.4.C

***** via-rhine.c

        /* this should always be supported */

        if (pci_set_dma_mask(pdev, 0xffffffff)) {

                printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");

***** VIA-RHINE_2.4.C

        /* this should always be supported */

        if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {

                printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");

*****

   这个其没有什么大的不同。

 

***** via-rhine.c

        SET_MODULE_OWNER(dev);

        SET_NETDEV_DEV(dev, &pdev->dev);  

***** VIA-RHINE_2.4.C

        SET_MODULE_OWNER(dev);

*****

   设置网络的数据块的方式变化了,在2.6.1

***** via-rhine.c

err_out_free_netdev:

        free_netdev (dev);

err_out:

***** VIA-RHINE_2.4.C

err_out_free_netdev:

        kfree (dev);

err_out:

*****

***** via-rhine.c

        free_netdev(dev);

        pci_disable_device(pdev);

***** VIA-RHINE_2.4.C

        kfree(dev);

        pci_disable_device(pdev);

*****

当然释放方式也要相应改变。

基本上只是对于netdevice的申请和释放做了修改。

 

但是对应在在低一些版本,比如2.6.1via-rhine.c2.4.20via-rhine.c进行比较,不同之处就太多了!

对于网络设备的控制,在2.6的数据结构多了,ethtools_ops这个内容。

dev->ethtool_ops = &netdev_ethtool_ops;

static struct ethtool_ops netdev_ethtool_ops = {

        .get_drvinfo            = netdev_get_drvinfo,

        .get_settings           = netdev_get_settings,

        .set_settings           = netdev_set_settings,

        .nway_reset             = netdev_nway_reset,

        .get_link               = netdev_get_link,

        .get_msglevel           = netdev_get_msglevel,

        .set_msglevel           = netdev_set_msglevel,

        .get_sg                 = ethtool_op_get_sg,

        .get_tx_csum            = ethtool_op_get_tx_csum,

};

static struct pci_driver via_rhine_driver = {

       .name              = "via-rhine",

       .id_table     = via_rhine_pci_tbl,

       .probe              = via_rhine_init_one,

       .remove             = __devexit_p(via_rhine_remove_one),

};

相应的中断方式,也更改成2.6的模式。不过Linux好的地方就是有很多参考源码,慢慢改,怎么都可以改好。

 

如何编译外部的驱动程序

对应驱动的*.o文件变成*.ko文件,编译的方式变化很到。具体原因参考附录[4]

下面给出我在2.6.1下面用的Makefile,和编译的批处理文件

Makefile:

obj-m:=mydrv.o

编译的drv.sh

#!/bin/bash

subpath=$(pwd)

osver=$(uname -r)

srcpath=/lib/modules/${osver}/build/

rm -f *o

make -C ${srcpath} SUBDIRS=${subpath} modules

 
参考文档 (主要都是在网上查的资料)
[1]  The Guide of Upgrading to linux kernel 2.6.x  作者:Rongkai Zhan 日期: 2004-3-14
[2] 菜鸟编译内核(kernel2.6.0) 作者:飘雪心辰,日期: 2004-8-19
[3] 编内核时出现:module-init-tools在线等   出处:ChinaUnix-Linux讨论区精华帖

[4] Driver porting: compiling external modules  

from   http://lwn.net/Articles/driver-porting/

[5] Linux2.6内核驱动移植参考 作者:晏渭川


评论

该日志第一篇评论

发表评论

评论也有版权!