为了说清楚要修改的地方,下面会比较啰嗦

Linux系统内核的源代码是开放的,因此我们可以从官网上下载Linux内核。

下载地址:https://www.kernel.org

解压之后进入内核会看到一下一下目录:



arch   COPYING  	crypto      drivers   	fs       init  	  Kbuild    kernel     MAINTAINERS  
mm     README   	samples  	security  	tools  	 virt	  block     CREDITS    Documentation  
firmware  include  ipc   Kconfig  lib     Makefile     net  REPORTING-BUGS  scripts  sound   usr



 其中每个目录的表示如下:



arch(cpu)   COPYING  	crypto(加密算法)      drivers(驱动)   	fs(file system)       init(init进程)  	  Kbuild(内核编译时使用的)    
kernel(Linux内核核心相关的)     MAINTAINERS(Linux内核的维护人员信息)    mm(内存管理)      README   	samples(Linux内核使用的示例)  	
security  	tools(工具)  	 virt(虚拟机)	  block(块设备)     CREDITS(感谢谁)    Documentation(文档)    firmware(系统固件)  
include(头文件)  ipc(进程间相互通信)   Kconfig(make menuconfig时使用的)  lib(Linux要使用的相关的库)     Makefile     
net(网络相关的)  REPORTING-BUGS  scripts(Linux内核编译的脚本)  sound(声卡相关的)   usr(用户)



内核要修改的地方其实很少,只需要改一下arch/arm/目录下我们要用的cpu的源代码就可以了。当我们要用到某个驱动时就修改一下driver目录下的驱动的代码。

在这里要把Linux内核烧录到基于Samsung S3C2440处理器的fl2440开发板上,Linux内核适用于很多架构的内核,可以在arch目录下看到:



alpha  avr32     cris  h8300  Kconfig  m68k        mips     parisc   s390   sh     tile  unicore32  xtensa
arm    blackfin  frv   ia64   m32r     microblaze  mn10300  powerpc  score  sparc  um    x86



在这里显示的并不是一种型号的CPU而是一种架构的CPU,我们要进入到arm架构里面去:



boot           mach-at91      mach-footbridge  mach-ixp23xx   mach-mv78xx0  mach-pnx4008   mach-s3c2443   mach-spear3xx   mach-w90x900  plat-orion      vfp
common         mach-bcmring   mach-gemini      mach-ixp4xx    mach-mx5      mach-pxa       mach-s3c24a0   mach-spear6xx   Makefile      plat-pxa
configs        mach-clps711x  mach-h720x       mach-kirkwood  mach-mxs      mach-realview  mach-s3c64xx   mach-tcc8k      mm            plat-s3c24xx
include        mach-cns3xxx   mach-imx         mach-ks8695    mach-netx     mach-rpc       mach-s5p64x0   mach-tegra      nwfpe         plat-s5p
Kconfig        mach-davinci   mach-integrator  mach-l7200     mach-nomadik  mach-s3c2400   mach-s5pc100   mach-u300       oprofile      plat-samsung
Kconfig.debug  mach-dove      mach-iop13xx     mach-loki      mach-nuc93x   mach-s3c2410   mach-s5pv210   mach-ux500      plat-iop      plat-spear
Kconfig-nommu  mach-ebsa110   mach-iop32x      mach-lpc32xx   mach-omap1    mach-s3c2412   mach-sa1100    mach-versatile  plat-mxc      plat-tcc
kernel         mach-ep93xx    mach-iop33x      mach-mmp       mach-omap2    mach-s3c2416   mach-shark     mach-vexpress   plat-nomadik  plat-versatile
lib            mach-exynos4   mach-ixp2000     mach-msm       mach-orion5x  mach-s3c2440   mach-shmobile  mach-vt8500     plat-omap     tools



惯例,第一步要改的是Makefile文件

[wangchengcheng@centos6 linux-3.0]$ vim Makefile

修改要编译的内核与交叉编译器:



1 @@ -192,8 +192,8 @@
2  # Default value for CROSS_COMPILE is not to prefix executables
3  # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
4  export KBUILD_BUILDHOST := $(SUBARCH)
5 -ARCH           ?= $(SUBARCH)
6 -CROSS_COMPILE  ?= $(CONFIG_CROSS_COMPILE:"%"=%)
7 +ARCH           ?= arm
8 +CROSS_COMPILE  ?= /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-



 其次要修改编译完成之后自动调用mkimage,这里的mkimage内核源代码并没有给提供,在编译好的u-boot的tools文件夹中,我们可以把它拷贝到当前目录下或者/bin/目录下或者/usr/bin/目录下。在这里我把它拷贝到了当前目录下。然后修改Makefile文件:



1 @@ -557,6 +557,9 @@
2  # This allow a user to issue only 'make' to build a kernel including modules
3  # Defaults to vmlinux, but the arch makefile usually adds further targets
4  all: vmlinux
5 +       cp arch/arm/boot/zImage . -f
6 +       mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d zImage linuxrom-s3c2440.bin
7 +       rm -f zImage



注:mkimage命令的作用是将内核编译出来的二进制文件转换为u-boot能够识别的二进制文件。

接下来改的地方是make distclean,当我们make distclean时我们希望把可执行文件linuxrom-s3c2440.bin文件给删掉:



1 @@ -1201,6 +1204,7 @@
2                 -o -name '.*.rej' -o -size 0 \
3                 -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
4                 -type f -print | xargs rm -f
5 +       @rm -f linuxrom-*.bin



到此,Makefile文件就修改完成了!要开始修改内核源代码了!

[wangchengcheng@centos6 linux-3.0]$ vim arch/arm/mach-s3c2440/mach-smdk2440.c

根据f2440开发板的原理图可知,其晶振频率为12MHZ因此要修改晶振频率:



1 @@ -155,12 +196,13 @@
 2         &s3c_device_wdt,
 3         &s3c_device_i2c0,
 4         &s3c_device_iis,
 5  };
 6 
 7  static void __init smdk2440_map_io(void)
 8  {
 9         s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
10 -       s3c24xx_init_clocks(16934400);
11 +       s3c24xx_init_clocks(12000000);
12         s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
13  }



接下来改串口,因为Linux的所有设备都是文件,文件的匹配需要用到name域来匹配。而Samsung公司串口的默认名字为"ttySAC"所以我们要把串口名字改成“ttyS”



1 @@ -54,7 +54,7 @@
2 
3  /* UART name and device definitions */
4 
5 -#define S3C24XX_SERIAL_NAME    "ttySAC"
6 +#define S3C24XX_SERIAL_NAME    "ttyS"
7  #define S3C24XX_SERIAL_MAJOR   204
8  #define S3C24XX_SERIAL_MINOR   64



最后修改machine id设备编号

由于将s3c2440的machine id与mini2440的machine id互换:

[wangchengcheng@centos6 linux-3.0]$ vim arch/arm/tools/mach-types



1 @@ -85,7 +85,7 @@
 2  bast                   ARCH_BAST               BAST                    331
 3  h1940                  ARCH_H1940              H1940                   347
 4  enp2611                        ARCH_ENP2611            ENP2611                 356
 5 -s3c2440                        ARCH_S3C2440            S3C2440                 362
 6 +s3c2440                        ARCH_S3C2440            S3C2440                 1999
 7  gumstix                        ARCH_GUMSTIX            GUMSTIX                 373
 8  omap_h2                        MACH_OMAP_H2            OMAP_H2                 382
 9  e740                   MACH_E740               E740                    384
10 @@ -356,7 +356,7 @@
11  snapper_9260           MACH_SNAPPER_9260       SNAPPER_9260            1987
12  dsm320                 MACH_DSM320             DSM320                  1988
13  exeda                  MACH_EXEDA              EXEDA                   1994
14 -mini2440               MACH_MINI2440           MINI2440                1999
15 +mini2440               MACH_MINI2440           MINI2440                362
16  colibri300             MACH_COLIBRI300         COLIBRI300              2000
17  linkstation_ls_hgl     MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL      2005
18  cpuat9g20              MACH_CPUAT9G20          CPUAT9G20               2031



到此内核源代码最基本的修改就告一段落了,内核的编译主要依赖于.config这个文件。内核用这个文件来指导编译器要编译的与不要编译的。由于直接修改.config文件过于复杂,就像修改u-boot一样繁琐效率又很低。在这里人们人性化的设计了图形化界面:make menuconfig

首先我们要在最高目录下创建一个.config文件,这里的.config文件参考mini2440的config文件:

[wangchengcheng@centos6 linux-3.0]$ cp arch/arm/configs/mini2440_defconfig .config

[wangchengcheng@centos6 linux-3.0]$ make menuconfig

我们将看到:

nuc 进入bios nuc 进入pe_3c

 选择System Type  --->  S3C2440 and S3C2442 Machines  ---> 不选[ ] MINI2440 development board,选择[*] SMDK2440与[*] SMDK2440 with S3C2440 CPU module

此时Linux内核已经初步修改完成,但是一些基本的驱动都没有加载。所以我们还是不能用它来做事情的。

添加硬盘分区:

[wangchengcheng@centos6 linux-3.0]$ vim arch/arm/plat-s3c24xx/common-smdk.c

 



1 /* NAND parititon from 2.4.18-swl5 */
 2 
 3 static struct mtd_partition smdk_default_nand_part[] = {
 4     [0] = {
 5         .name   = "bootloader",
 6         .size   = SZ_1M,
 7         .offset = 0,
 8     },
 9     [1] = {
10         .name   = "linux",
11         .offset = MTDPART_OFS_NXTBLK,
12         .size   = SZ_1M*15,
13     },
14     [2] = {
15         .name   = "rootfs",
16         .offset = MTDPART_OFS_NXTBLK,
17         .size   = SZ_1M*40,
18     },
19     [3] = {
20         .name   = "apps",
21         .offset = MTDPART_OFS_NXTBLK,
22         .size   = SZ_1M*50,
23     },
24     [4] = {
25         .name   = "data",
26         .offset = MTDPART_OFS_NXTBLK,
27         .size   = SZ_1M*50,
28     },
29     [5] = {
30         .name   = "backup",
31         .size   = SZ_1M * 100,
32         .size   = MTDPART_OFS_NXTBLK,
33     },
34 };
35 
36 static struct s3c2410_nand_set smdk_nand_sets[] = {
37     [0] = {



 

开发板上的nandflash是256M的,bootleader启动需要1M,内核需要15M,根文件系统需要40M,其他的自由分配。

注:此时要在进行分区就要选择相应的文件系统。nandflash常用的文件系统有:yaffs2,ubifs,cramfs已经initramfs等。

添加initramfs文件系统:

initramfs是最简单的文件系统的添加方式:make menuconfig  --->   General setup  --->   选中[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support,并且在()    Initramfs source file(s)中指定根文件目录树的路径(相对路径或者绝对路径都可以。)

添加DM9000网卡

修改arch/arm/mach-s3c2440/mach-smdk2440.c

#include <linux/dm9000.h>//添加DM9000网卡的头文件

添加如下代码

/* add DM9000 ethernet drivers ,whitch is modify by xiaohe */
#define DM9000_BASE    (S3C2410_CS4 + 0x300)
static struct resource s3c_dm9000_resource[] = {
     [0] = {
        .start = DM9000_BASE,
        .end   = DM9000_BASE + 3,
        .flags = IORESOURCE_MEM
    },
    [1] = {
        .start = DM9000_BASE + 4,
        .end   = DM9000_BASE + 7,
        .flags = IORESOURCE_MEM
    },
    [2] = {
        .start = IRQ_EINT7,
        .end   = IRQ_EINT7,
        .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
    }
};
/*        
 * The DM9000 has no eeprom, and it's MAC address is set by
 * the bootloader before starting the kernel.
 */
static struct dm9000_plat_data s3c_dm9000_pdata = {
    .flags      = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
};
 
static struct platform_device s3c_device_dm9000 = {
    .name       = "dm9000",
    .id     = -1,
    .num_resources  = ARRAY_SIZE(s3c_dm9000_resource),
    .resource   = s3c_dm9000_resource,
    .dev        = {
        .platform_data  = &s3c_dm9000_pdata,
    },
};
/* modify end  */
 
修改platform_device *smdk2440_devices[] __initdata结构体为如下,在其中添加启动DM9000
static struct platform_device *smdk2440_devices[] __initdata = {
    &s3c_device_ohci,
    &s3c_device_lcd,
    &s3c_device_wdt,
    &s3c_device_i2c0,
    &s3c_device_iis,
    &s3c_device_dm9000,
};
重新make之后,内核就可以支持DM9000网络了,这时我们就可以用tftp下载文件到内核里去。
这时输入ifconfig:
>: ifconfig
eth0 Link encap:Ethernet HWaddr 6A:C6:F1:ED:0D:F7 
 inet addr:192.168.1.111 Bcast:192.168.1.255 Mask:255.255.255.0
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:138 errors:0 dropped:0 overruns:0 frame:0
 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000 
 RX bytes:13167 (12.8 KiB) TX bytes:0 (0.0 B)
 Interrupt:51 Base address:0x4300

 

添加U盘驱动

一、添加U盘支持   

FL2440添加u盘的挂载比较简单,大部分的内容都是在内核里面做make menuconfig,配置内核。

Device Drivers  --->

     Generic Driver Options  --->

配置u盘的热插拔

     [*] Block devices  --->

低性能USB块设备驱动

     SCSI device support  --->

设备的支持

通用的支持

所有在每个SCSI LUN探针装置

     [*] USB support  --->

主机端USB支持

设备文件系统(不推荐使用)

设备类设备(不推荐使用)

监控

支持OHCI标准

支持USB海量存储

File systems  --->                                              //配置u盘的文件系统
       DOS/FAT/NT Filesystems  --->
                  <*> MSDOS fs support
                  <*> VFAT (Windows-95) fs support

默认代码页

默认字符集

配置u盘的语言格式支持,不过感觉着个配置没什么用,中文也支持不了,也许是因为linux对中文的支持并不好吧

                  <*>   Simplified Chinese charset (CP936, GB2312)

                  <*>   ASCII (United States)

                  <*>   NLS UTF-8

 

二、添加USB结构体变量,加厂商ID和设备ID

diff -Nuar linux-3.0/drivers/usb/serial/option.c linux-3.0-s3c2440/drivers/usb/serial/option.c
--- linux-3.0/drivers/usb/serial/option.c 2011-07-22 10:17:23.000000000 +0800
+++ linux-3.0-s3c2440/drivers/usb/serial/option.c 2015-12-07 16:31:30.555485473 +0800
@@ -51,6 +51,13 @@
 static void option_instat_callback(struct urb *urb); 
 /* Vendor and product IDs */
+static int vendor = 0; /* Add by guowenxue */
+static int product = 0; /* Add by guowenxue */
+
+/* Vendor and product IDs */
+#define OPTION_VENDOR_RESERVED 0xFFFF /* Add by guowenxue */
+#define OPTION_RESERVED_DEVICE 0xFFFF /* Add by guowenxue */ 
+
 #define OPTION_VENDOR_ID 0x0AF0
 #define OPTION_PRODUCT_COLT 0x5000
 #define OPTION_PRODUCT_RICOLA 0x6000
@@ -446,7 +453,8 @@
 .reason = OPTION_BLACKLIST_SENDSETUP
 }; 
-static const struct usb_device_id option_ids[] = {
+static struct usb_device_id option_ids[] = {
+ { USB_DEVICE(OPTION_VENDOR_RESERVED, OPTION_RESERVED_DEVICE) }, /* Add by guowenxue */
 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
@@ -1079,6 +1087,15 @@
 static int __init option_init(void)
 {
 int retval;
+
+ if ((vendor>0) && (product>0))
+ {
+ option_ids[0].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ option_ids[0].idVendor = vendor;
+ option_ids[0].idProduct = product;
+ printk("Register option drvier for modem vendor=0x%04x product=0x%04x\n", vendor, product);
+ }
+

三、加宏和USB进程

diff -Nuar linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c linux-3.0-s3c2440/arch/arm/mach-s3c2440/mach-smdk2440.c
--- linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c 2011-07-22 10:17:23.000000000 +0800
+++ linux-3.0-s3c2440/arch/arm/mach-s3c2440/mach-smdk2440.c 2015-12-07 16:31:30.532734715 +0800
@@ -23,6 +23,13 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>+/* add by guowenxue for norflash */
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -44,6 +51,11 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/ts.h> /*Add by guowenxue to support Touch screen, 2011.09.06*/
+#include <mach/regs-clock.h> /*Add by guowenxue 2012.07.15, for usb_s3c2440_init() */
+#include <linux/i2c.h> /*Add by guowenxue 2012.10.22, for AT24C512 driver */
+#include <linux/i2c/at24.h> /* Add by guowenxue 2012.10.22, for AT24C512 driver */
+#include <linux/delay.h>

加USB的init进程:

+int usb_s3c2440_init(void)
+{
+ /* Input Frequency is 12.0000MHz, and MDEV=0x38 PDIV=2 SDIV=2, so output frequency 48.00MHz */
+ unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x02); 
+ while (upllvalue != __raw_readl(S3C2410_UPLLCON)) 
+ { 
+ __raw_writel(upllvalue, S3C2410_UPLLCON); 
+ mdelay(1); 
+ }
+
+ return 0;
+}
+
 static void __init smdk2440_map_io(void) {
 s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
- s3c24xx_init_clocks(16934400);
+ s3c24xx_init_clocks(12000000); /*Modify by guowenxue, 2011.08.30*/
 s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
+ usb_s3c2440_init(); /* Add by guowenxue, 2012.07.15 */
 } 配置好之后,插上U盘就可以看到如下信息:
usb 1-1.1: new full speed USB device number 3 using s3c2410-ohci
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: new full speed USB device number 3 using s3c2410-ohci
usb 1-1.1: New USB device found, idVendor=048d, idProduct=1234
usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1.1: Product: 
usb 1-1.1: Manufacturer: 
usb 1-1.1: SerialNumber: 袎
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: New USB device found, idVendor=048d, idProduct=1234
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: Product: 
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: Manufacturer: 
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: SerialNumber: 袎
 uba:
Dec 31 17:44:35 root kern.info kernel: uba:

表示USB驱动uba已经装载成功,这时可能会出现一个问题,我们查看/mnt/usb/并没有U盘里的信息。

 

这是因为U盘没有挂载上去,将U盘挂载到/mnt/usb/下就可以了:

>: mount -t vfat /dev/uba /mnt/usb/

 

为什么U盘没有自动挂载上去呢?

查看自动挂载的配置文件/etc/mdev.conf:

>: vi mdev.conf
sd[a-z][0-9] 0:0 0777 @(mount /dev/$MDEV /mnt/usb)
sd[a-z] 0:0 0777 $(umount /mnt/usb)
ub[a-z][0-9] 0:0 0777 @(mount /dev/$MDEV /mnt/usb)
ub[a-z] 0:0 0777 $(umount /mnt/usb)
mmcblk[0-9]p[0-9] 0:0 0777 @(mount /dev/$MDEV /mnt/sdc)
mmcblk[0-9] 0:0 0777 $(umount /mnt/sdc)

原来是第三行的ub[a-z][0-9]的原因,因为我的U盘的驱动挂载上去之后只有uba没有后面的数字,而配置文件里后面有0-9的数字,所以没办法匹配,也就没办法挂载,在这里添加一行:

ub[a-z] 0:0 0777 @(mount /dev/$MDEV /mnt/usb)
ub[a-z] 0:0 0777 $(umount /mnt/usb)

这样就可以实现自动挂载了。