天天看點

FL2440 Linux kernel + yaffs2根檔案移植過程(一)

本文全過程為自己親自試驗,成功移植了一個最基本功能的kernel、根檔案系統,現在将這個一耗時、耗精力 的過程寫下來,希望對遇到相同問題的朋友們有所幫助!

平台:飛淩fl2440

            windows xp sp2

            vmware 6.5.build-203739

             ubuntu 9.10

             交叉編譯器: 4.3.2

             核心:linux-2.6.28.7.tar.bz2           

             根檔案系統:busybox-1.19.4 busybox-1.19.4.tar.bz2

一、kernel的移植:

        整個過程參考的是這篇文章http://wenku.baidu.com/view/6cf79631eefdc8d376ee32d2.html,但該文章有些問題,下面的步驟對其進行了更改。

      移植步驟: 

1,我們首先在根目錄下建立fl2440目錄, 

mkdir /fl2440

然後到linux 核心官網下載下傳linux-2.6.28.7 的核心源碼包。位址如下 

http://www.kernel.org/pub/linux/kernel/v2.6/ 

或者 

ftp://ftp.kernel.org/pub/linux/kernel/v2.6/ 

下載下傳完畢,将核心源碼包放到/fl2440目錄下,然後解壓縮 

tar –jxvf linux-2.6.28.7.tar.bz2 

fl2440目錄下會多一個linux-2.6.28.7 的目錄

2,由于該核心源碼包中,沒有yaffs2 驅動,是以我們要将yaffs2 檔案系統的驅動添加到核心

源碼中。yaffs2的更新檔包需要登陸http://www.yaffs.net/download-yaffs-using-git,通過git方式擷取(在ubuntu中git clone git://www.aleph1.co.uk/yaffs2)或者到linuxidc網站下載下傳壓縮包,由于時間有點長,記不住自己用的那種方式了,下載下傳完後解壓,執行./patch-ker.sh   

c    m    /fl2440/linux-2.6.28.7 為kernel打上更新檔,顯示:

updating /fl2440/linux-2.6.28.7/fs/kconfig

updating /fl2440/linux-2.6.28.7/fs/makefile

如果上面的過程還需要其他的庫或工具,需要通過sudo apt-get install ***來安裝相應的工具

3. 修改linux-2.6.28.7/makefile,将 

arch   ?=$ (subarch) 

cross_compile      ?=   

修改為 

arch                        ?= arm 

cross_compile      ?= arm-linux- 

注意,這裡是在交叉編譯環境已經建立完成的情況下的,并且,arm-linux-已經添加進入了環

境變量中。如果沒做完這步,那麼你要先建立交叉編譯環境,并把arm-linux-導入到環境變量

中。這裡也可以直接添加,如cross_compile ?=/fl2440/usr/local/arm/4.3.2/bin/arm-none-linux-gnueabi-

我采用的後一種,如果用前面一種,需要更改/etc/bash.bashrc檔案

                 #vim /etc/bash.bashrc

                 在最後加上:

                export path=$path:/usr/local/arm/3.4.1/bin

                export path

另外還有其他幾種方法,百度一下吧, 安裝成功的标志arm-linux-gcc -v 以及 echo $path會傳回相應資訊。好像需要登出生效,或者source /root/.bashrc不用重新開機生效

4,修改機器碼。飛淩開發闆的bootloader 預設的機器碼是193,是以我們在使用fl2440 機器

的時候,需要修改機器碼。修改arch/arm/tools/mach-types。将 

s3c2440                arch_s3c2440                        s3c2440                                  362 

修改為193。 

這裡如果在配置時使用 

[*] smdk2410/a9m2410     

則這裡就不用修改了,當然了,我們一般不選smdk2410/a9m2410    ,是以要修改。

5,由于闆子使用的是12mhz 的晶振,而我們使用的smdk2440 的晶振頻率不是這個值,所

以我們要修改,要不然,會出現列印資訊亂碼的現象。 

檔案:arch/arm/mach-s3c2440/mach-smdk2440.c 

函數:static void __init smdk2440_map_io(void) 

/*s3c24xx_init_clocks(16934400);*/  s3c24xx_init_clocks(12000000);

6,修改mtd 分區。由于fl2440 和smdk2440 的nandflash 分區不同,是以這裡要修改,要不

然會在啟動的過程中會出現錯誤。需要和bootloader 中的分區資訊相同(128m),否則,啟

動時出錯。 

檔案:  arch/arm/plat-s3c24xx/common-smdk.c

結構體:static struct mtd_partition smdk_default_nand_part[] 

将源結構體删除,或者注釋掉,修改為以下形式 

static struct mtd_partition smdk_default_nand_part[] = { 

                [0] = { 

                                .name                = "boot", 

                                .size                = 0x00100000, 

                                .offset = 0 

                }, 

                [1] = { 

                                .name                = "myapp", 

                                .size                = 0x003c0000, 

                                .offset = 0x00140000, 

                [2] = { 

                                .name                = "kernel", 

                                .size                = 0x00300000, 

                                .offset = 0x00500000, 

                [3] = { 

                                .name                = "fs_yaffs", 

                                .size                = 0x03c00000,                  //30m 

                                .offset = 0x00800000, 

                },                 

                [4] = { 

                                .name                = "wince", 

                                .size                = 0x03c00000, 

                                .offset = 0x04400000, 

                } 

}; 

這裡注意,一定要将fs_yaffs 對應到3 上面,并且内容要和闆子上面的bootloader 一緻,要不

然會出現kernel panic 的錯誤。其他可以随意。

7,關閉ecc 校驗。 

檔案:drivers/mtd/nand/s3c2410.c 

函數:s3c2410_nand_init_chip 

/*chip->ecc.mode = nand_ecc_soft; */    chip->ecc.mode = nand_ecc_none; 

8,修改nandflash 驅動,支援fl2440 開發闆的nandflash 

檔案:drivers/mtd/nand/nand_bbt.c 

static struct nand_bbt_descr largepage_memorybased = {

   .options = 0, 

                .offs = 0, 

                .len = 1,                      //  原數值為2,支援2k 每頁的flash 修改為1。k9f1g08,k9f2g08

是2k 每頁的flash 

                .pattern = scan_ff_pattern 

static struct nand_bbt_descr largepage_flashbased = { 

                .options = nand_bbt_scan2ndpage, 

                .len = 1,                      //原數值為2,支援2k 每頁的flash 修改為1。k9f1g08,k9f2g08

};

9,增加devfs 檔案管理器的支援。我們所用的檔案系統使用的是devfs 檔案管理器。 

檔案:fs/kconfig, 

添加 

config devfs_fs 

                  bool "/dev file system support (obsolete)" 

                  default y         

config devfs_mount 

bool "automatically mount at boot" 

default y 

depends on devfs_fs 

10,     如果不考慮網絡裝置、lcd 顯示屏、觸摸屏等外圍裝置,這時就可以進行配置核心了。 

我們把s3c2410 的預設配置寫入config 檔案。指令如下 

make s3c2410_defconfig 

輸入如下指令進行核心配置,配置的過程,隻将提到的修改,其他預設。

make menuconfig 

配置檔案系統選項,配置yaffs2 檔案系統  ,修改配置如下 

file systems    --->   

[*] miscellaneous filesystems    ---> 

<*> yaffs2 file system support   

                -*-      512 byte / page devices           

                               [ ]          use older-style on-nand data format with pagestatus byte   

                [ ]              lets yaffs do its own ecc (new)             

                                 -*-      2048 byte (or larger) / page devices                                   

        [*]          autoselect yaffs2 format (new)           

[ ]          disable yaffs from doing ecc on tags by default (new) 

配置cpu相關選項,修改配置如下:  

system type  --->  

    s3c2440 machines  --->  

        [*] smdk2440 

        [*] smdk2440 with s3c2440 cpu module 

去掉s3c2400 machines、s3c2410 machines、s3c2412 machines、s3c2442 machines的所有

選項。如果現在編譯核心,下載下傳到開發闆中,核心就可以正常啟動了。 

編譯核心使用指令如下: 

make zimage 

生成的核心檔案在arch/arm/boot下面,檔案為zimage。現在燒寫到闆子上面,就能夠啟動

核心了,可是這還不行,還會出現lcd顯示不正常,觸屏不能使用等情況,這是由于沒有移植

相應的驅動或者驅動程式的參數不正确的原因。下面就對其進行改正。 

11,     移植usb host 驅動。 

在這個版本的linux 核心,已經對usb 驅動進行來很好的支援,僅僅需要修改配置。 

device drivers    --->   

        [*] usb support    ---> 

                {*}      support for host-side usb   

                [*]          usb device filesystem (deprecated)   

                [*]          usb device class-devices (deprecated) 

                <*>          ohci hcd support   

                <*>      usb mass storage support   

        [*] hid devices    --->   

                {*}      generic hid support

    [*]          /dev/hidraw raw hid device support 

        scsi device support    ---> 

                <*> scsi device support 

                [*] legacy /proc/scsi/ support 

                <*> scsi disk support   

                <*> scsi tape support 

如果從來沒有配置過核心的話,基本上上面的都是預設的。不過    <m>      usb  mass  storage 

support    改為<*>,而預設[  ]          /dev/hidraw  raw  hid  device  support    要改為<*>,而<m> 

scsi tape support 改為<*>。 

目前2.6.28.7 版本的根檔案系統的裝置管理器是靜态生成節點的,是以需要添加節點。開發闆

啟動以後,在/dev 目錄下輸入一下指令: 

  mknod sda1 b 8 1 

這個指令中的sda1 是裝置節點名 

12,     移植rtc 驅動 

在這個版本的linux 核心,已經對rtc 驅動進行來很好的支援,不需要修改配置。相應配置如

下 

device drivers    ---> 

        <*> real time clock    ---> 

                [*]      set system time from rtc on startup and resume 

                (rtc0)    rtc used to set the system time 

                [ ]      rtc debug support   

                            *** rtc interfaces ***   

                [*]      /sys/class/rtc/rtcn (sysfs) 

                [*]      /proc/driver/rtc (procfs for rtc0) 

                [*]      /dev/rtcn (character devices) 

                <*>      samsung s3c series soc rtc   

以上都是預設的。 

然後添加對裝置的支援 

打開arch/arm/mach-s3c2440/mach-smdk2440.c,添加裝置,代碼如下: 

static struct platform_device *smdk2440_devices[] __initdata = { 

                &s3c_device_usb, 

                &s3c_device_lcd, 

                &s3c_device_wdt, 

                &s3c_device_i2c0,

 &s3c_device_iis, 

                &s3c_device_rtc, 

13,     移植uda1341 驅動 

由于這裡要用到幾個頭檔案,而linux2.6.28.7 核心源碼中沒有,是以要建立。 

首先是在include/sound 下建立s3c24xx_uda134x.h,内容為 

#ifndef _s3c24xx_uda134x_h_ 

#define _s3c24xx_uda134x_h_ 1 

#include <sound/uda134x.h> 

struct s3c24xx_uda134x_platform_data { 

                int l3_clk; 

                int l3_mode; 

                int l3_data; 

                void (*power) (int); 

                int model; 

#endif 

然後在include/sound/下建立uda134x.h 檔案,内容為: 

#ifndef _uda134x_h 

#define _uda134x_h 

#include <sound/l3.h> 

struct uda134x_platform_data { 

                struct l3_pins l3; 

                int model; }                       //原文有錯誤,括号打錯了

#define uda134x_uda1340 1

#define uda134x_uda1341 2 

#define uda134x_uda1344 3 

#endif /* _uda134x_h */

接着在include/sound 下建立l3.h 檔案,内容為 

#ifndef _l3_h_ 

#define _l3_h_ 1 

struct l3_pins { 

                void (*setdat)(int); 

                void (*setclk)(int); 

                void (*setmode)(int); 

                int data_hold; 

                int data_setup; 

                int clock_high; 

                int mode_hold; 

                int mode; 

                int mode_setup; 

int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len); 

在arch/arm/mach-s3c2410/include/mach/下建立gpio-fns.h,内容為

/* s3c2410_gpio_cfgpin 

  * 

  * set the configuration of the given pin to the value passed. 

  * eg: 

  *        s3c2410_gpio_cfgpin(s3c2410_gpa(0), s3c2410_gpa0_addr0); 

  *        s3c2410_gpio_cfgpin(s3c2410_gpe(8), s3c2410_gpe8_sddat1); 

*/ 

extern void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function); 

extern unsigned int s3c2410_gpio_getcfg(unsigned int pin); 

/* s3c2410_gpio_getirq 

  * turn the given pin number into the corresponding irq number 

  * returns: 

  *            < 0 = no interrupt for this pin 

  *            >=0 = interrupt number for the pin 

extern int s3c2410_gpio_getirq(unsigned int pin); 

#ifdef config_cpu_s3c2400 

extern int s3c2400_gpio_getirq(unsigned int pin); 

#endif /* config_cpu_s3c2400 */ 

/* s3c2410_gpio_irqfilter 

  * set the irq filtering on the given pin 

  * on = 0 => disable filtering 

  *            1 => enable filtering 

  * config = s3c2410_eintflt_pclk or s3c2410_eintflt_extclk orred with 

  *                    width of filter (0 through 63)

 * 

extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, 

                                                                    unsigned int config); 

/* s3c2410_gpio_pullup 

  * configure the pull-up control on the given pin 

  * to = 1 => disable the pull-up 

  *            0 => enable the pull-up 

  * eg; 

  *      s3c2410_gpio_pullup(s3c2410_gpb(0), 0); 

  *      s3c2410_gpio_pullup(s3c2410_gpe(8), 0); 

extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to); 

/* s3c2410_gpio_getpull 

  * read the state of the pull-up on a given pin 

  * return: 

  *            < 0 => error code 

  *                0 => enabled 

  *                1 => disabled 

extern int s3c2410_gpio_getpull(unsigned int pin); 

extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to); 

extern unsigned int s3c2410_gpio_getpin(unsigned int pin); 

在平台上添加和配置uda1341: 

修改arch/arm/mach-s3c2440/mach-smdk2440.c。在開始添加頭檔案 

#include <sound/s3c24xx_uda134x.h> 

#include <mach/gpio-fns.h> 

添加裝置配置 

static struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = {

 .l3_clk = s3c2410_gpb4, 

                .l3_data = s3c2410_gpb3,                             //原文有錯誤

                .l3_mode = s3c2410_gpb2, 

                .model = uda134x_uda1341, 

static struct platform_device s3c24xx_uda134x = { 

                .name = "s3c24xx_uda134x", 

                .dev = { 

                                .platform_data        = &s3c24xx_uda134x_data, 

把裝置添加到平台當中 

                &s3c_device_i2c0, 

                &s3c_device_iis, 

                &s3c_device_rtc, 

                &s3c24xx_uda134x, 

配置如下 

        <*> sound card support    ---> 

                <*>      advanced linux sound architecture    ---> 

                        <*>      oss mixer api 

                        <*>      oss pcm (digital audio) api 

                                [*]          oss pcm (digital audio) api - include plugin system 

                                [*]      support old alsa api 

                                [*]      verbose procfs contents 

                                [*]      verbose printk 

                                [*]      generic sound devices    ---> 

                                <*>      alsa for soc audio support    ---> 

                                        <*>      soc audio for the samsung s3c24xx chips 

                                        <*>      soc i2s audio support uda134x wired to a s3c24xx 

配置前還有改變sound/soc/s3c24xx/kconfig 檔案 

在裡面添加如下内容 

config snd_s3c24xx_soc_s3c24xx_uda134x 

                tristate "soc i2s audio support uda134x wired to a s3c24xx" 

                depends on snd_s3c24xx_soc && arch_s3c2410 

                select snd_s3c24xx_soc_i2s 

                select snd_soc_l3 

                select snd_soc_uda134x 

隻有這樣,最後藍色部分才會出現 

14,     移植dm9000 驅動 

修改  drivers/net/dm9000.c  檔案,頭檔案增加

#include <mach/regs-gpio.h>   

#include <mach/irqs.h> 

#include <mach/hardware.h> 

在dm9000_probe  函數開始增加: 

unsigned char ne_def_eth_mac_addr[]={0x00,0x12,0x34,0x56,0x80,0x49}; 

        static void *bwscon; 

        static void *gpfcon; 

        static void *extint0; 

        static void *intmsk; 

        #define bwscon                      (0x48000000) 

        #define gpfcon                      (0x56000050) 

        #define extint0                      (0x56000088) 

        #define intmsk                      (0x4a000008) 

                bwscon=ioremap_nocache(bwscon,0x0000004); 

                gpfcon=ioremap_nocache(gpfcon,0x0000004); 

                extint0=ioremap_nocache(extint0,0x0000004); 

                intmsk=ioremap_nocache(intmsk,0x0000004); 

        writel(readl(bwscon)|0xc0000,bwscon); 

                writel( (readl(gpfcon) & ~(0x3 << 14)) | (0x2 << 14), gpfcon);   

                writel( readl(gpfcon) | (0x1 << 7), gpfcon); // disable pull-up 

                writel( (readl(extint0) & ~(0xf << 28)) | (0x4 << 28), extint0); //rising edge 

                writel( (readl(intmsk))    & ~0x80, intmsk); 

在這個函數的最後需要修改: 

if (!is_valid_ether_addr(ndev->dev_addr)) { 

                                /* try reading from mac */ 

                                  mac_src = "chip"; 

                                for (i = 0; i < 6; i++) 

                                                //ndev->dev_addr[i] = ior(db, i+dm9000_par);   

                                                ndev->dev_addr[i] = ne_def_eth_mac_addr[i]; 

修改arch/arm/mach-s3c2440/mach-smdk2440.c,添加裝置 

                &s3c24xx_uda134x, 

                &s3c_device_dm9000, 

修改  arch/arm/plat-s3c24xx/devs.c,添加頭檔案 

#include <linux/dm9000.h> 

static struct resource s3c_dm9000_resource[] = {   

                [0] = {   

                .start = s3c24xx_pa_dm9000,  

.end      = s3c24xx_pa_dm9000+ 0x3,   

                .flags = ioresource_mem   

                },   

                [1]={   

                .start = s3c24xx_pa_dm9000 + 0x4, //cmd pin is a2   

                .end = s3c24xx_pa_dm9000 + 0x4 + 0x7c,   

                [2] = {   

                .start = irq_eint7,   

                .end      = irq_eint7,   

                .flags = ioresource_irq   

                };   

                static struct dm9000_plat_data s3c_device_dm9000_platdata = {   

                .flags= dm9000_platf_16bitonly,   

                struct platform_device s3c_device_dm9000 = {   

                .name= "dm9000",   

                .id= 0,   

                .num_resources= array_size(s3c_dm9000_resource),   

                .resource= s3c_dm9000_resource,   

                    .dev= {   

                .platform_data = &s3c_device_dm9000_platdata,   

                    }   

};   

export_symbol(s3c_device_dm9000); 

最後藍色的部分,似乎其他的版本沒有 

修改  arch/arm/plat-s3c24xx/include/plat/devs.h 

或者有的版本是arch/arm/plat-s3c/include/plat/devs.h     

40 行附近,添加 

extern struct platform_device s3c_device_dm9000; 

修改arch/arm/mach-s3c2410/include/mach/map.h  檔案118 行左右 

/* dm9000 */   

#define      s3c24xx_pa_dm9000 0x20000300   

#define      s3c24xx_va_dm9000 0xe0000000 

或者是 

/* dm9000 */ 

#define      s3c24xx_va_dm9000 s3c2410_addr(0x02100300) 

15,     可能你會看到有的闆子上面能夠在開機的過程中顯示一個企鵝或者其他的圖像,如果

要是顯示企鵝的話,很簡單,隻需在配置核心過程中将下面進行配置就可以了。

graphics support    --->   

                                <*> support for frame buffer devices---à 

                                <*> s3c2410 lcd framebuffer support ,multi support!   

                                console display driver support    ---> 

                                                <*> framebuffer console support     

                             [*] bootup logo ---à 

                                                                [*]      standard 224-color linux logo 

這樣配置後,編譯的核心檔案就能顯示一個企鵝 

16,     3.5 寸lcd 顯示的移植 (注意,這裡要根據lcd此村進行更改)

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

/* lcd driver info */ 

static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = { 

                .lcdcon5                = s3c2410_lcdcon5_frm565 | 

                                                    s3c2410_lcdcon5_invvline | 

                                                    s3c2410_lcdcon5_invvframe | 

                                                    s3c2410_lcdcon5_pwren | 

                                                    s3c2410_lcdcon5_hwswp, 

                .type                                = s3c2410_lcdcon1_tft, 

                .width                                = 320, 

                .height                                = 240, 

                .pixclock                = 156250, 

                .xres                                = 320, 

                .yres                                = 240, 

                .bpp                                = 16, 

                .left_margin                = 20,//or8, 

                .right_margin                = 38,//or5, 

                .hsync_len                = 30,//or63, 

                .upper_margin                = 12,//or15, 

                .lower_margin                = 15,//or3, 

                .vsync_len                =3,//or5, 

static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = { 

                .displays                = &smdk2440_lcd_cfg, 

                .num_displays                = 1,//或者array_size(smdk2440_lcd_cfg), 

                .default_display = 0, 

#if 0 

                /* currently setup by downloader */ 

                .gpccon                                = 0xaa940659, 

                .gpccon_mask                = 0xffffffff, 

                .gpcup                                = 0x0000ffff, 

                .gpcup_mask                = 0xffffffff, 

                .gpdcon                                = 0xaa84aaa0, 

                .gpdcon_mask                = 0xffffffff, 

                .gpdup                                = 0x0000faff, 

                .gpdup_mask                = 0xffffffff, 

#endif

   .lpcsel                                =0,//((0xce6) & ~7) | 1<<4, 

上面紅色部分必須修改,否則顯示會不正常。其他參數預設。當然這裡不是随便改的,具體如

何改,稍後詳解。注意紅色參數後面的注釋 

lcd 的參數設定是需要根據lcd 的手冊來設定arch/arm/mach-s3c2440/mach-smdk2440.c 裡面

的s3c2410fb_display smdk2440_lcd_cfg 結構體 

例如從lq035nc111 的手冊可以得到如下一個表   

該表描述了該款并行lcd 的所有時鐘需求,在這裡我參照的全是典型值“typ”欄   

一個很具有參考價值的文檔檔案是 documentation/fb/framebuffer.txt  檔案,裡面給我們描述了

一個架構

還有一個很有用的公式  pixelclock:   

      xfree: in mhz   

      fb: in picoseconds (ps)   

      pixclock = 1000000 / dcf 

再結合結構體  static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = { 

        .lcdcon5        = s3c2410_lcdcon5_frm565 | 

                          s3c2410_lcdcon5_invvline | 

                          s3c2410_lcdcon5_invvframe | 

                          s3c2410_lcdcon5_pwren | 

                          s3c2410_lcdcon5_hwswp, 

        .type                = s3c2410_lcdcon1_tft, 

        .width = lcd_width, 

        .height = lcd_height, 

        .pixclock = lcd_pixclock, 

        .xres = lcd_width, 

        .yres = lcd_height,

    .bpp = 16, 

        .left_margin = lcd_left_margin, 

        .right_margin = lcd_right_margin, 

        .hsync_len = lcd_hsync_len, 

        .upper_margin = lcd_upper_margin , 

        .lower_margin = lcd_lower_margin, 

        .vsync_len = lcd_vsync_len, 

  pixclock:現在我們就可以開始設定這個結構體的參數了,有上面的表我們可以知道lcd 的

時鐘dclk 應該是156ns,這個對應結構體裡面的像素點時鐘pixclock,在來看看第四節提到的

一個公式  pixclock=1000000/dcf,這個dcf 就是lcd 的dclk 對應的頻率,注意,機關為mhz,

是以 dcf=1000  000  000/156  hz=1000/156  mhz;可以得到 pixclock=1000000/(1000/156)

=156000;   

width、height 的設定這個就沒什麼歧義了,對應320 和240   

bpp:其實我的這個lcd 手冊上說該屏是支援24 位色的,但是這裡填寫16 位,有空可以試試

24 位 

其他的參數:其他參數對應第3 節的表填寫   

xres                  <===========> tep(thd)(hsync display period) lcd_width 

yres                  <===========> tvd(vsync display period)lcd_height, 

left_margin    <===========> thf(hsync front-porch)lcd_left_margin, 

right_margin <===========> thb(hsync back-porch)lcd_right_margin 

hsync_len        <===========> ths(thp)(hsync pulse width) 

upper_margin <===========> tvf(vsync front-porch) 

lower_margin <===========> tvb(vsync back-porch ) 

vsync_len        <===========> tvs(tvp)(vsync pulse width) 

fl2440 用的lcd 手冊中的表格如下

進而可知, 

參數對應為 

                .width                    = 320, 

                .height                  = 240, 

                .pixclock              = 156000, 

                .xres                      =320, 

                .yres                      = 240, 

                .bpp                        = 16, 

                .left_margin        = 20, 

                .right_margin      = 38, 

                .hsync_len            = 30, 

                .upper_margin      = 12, 

                .lower_margin      = 15, 

                .vsync_len            = 3,

17,     移植看門狗 

修改配置

device drivers ---> 

        [*] watchdog timer support ---> 

                  <*> s3c2410 watchdog 

即可。其實預設配置就是這樣的。但是要是打開看門狗還需要修改源碼。 

18,     觸摸屏驅動移植 

檔案:arch/arm/plat-s3c24xx/devs.c 

頭檔案添加 

#include<mach/s3c2410_ts.h>      //y原文有誤

在最後一行的上面添加如下代碼 

/* touchscreen */ 

                struct platform_device s3c_device_ts = { 

                                .name                          = "s3c2410-ts", 

                                .id              = -1, 

                }; 

                export_symbol(s3c_device_ts); 

                static struct s3c2410_ts_mach_info s3c2410ts_info; 

                void set_s3c2410ts_info(struct s3c2410_ts_mach_info *hard_s3c2410ts_info) 

                { 

                                memcpy(&s3c2410ts_info,hard_s3c2410ts_info,sizeof(struct 

s3c2410_ts_mach_info)); 

                                s3c_device_ts.dev.platform_data = &s3c2410ts_info; 

                export_symbol(set_s3c2410ts_info); 

在arch/arm/mach-s3c2410/include/mach/下建立檔案s3c2410_ts.h,内容為: 

/* linux/include/asm/arch-s3c2410/s3c2410_ts.h 

  * copyright (c) 2005 arnaud patard <[email protected]> 

  * this program is free software; you can redistribute it and/or modify 

  * it under the terms of the gnu general public license version 2 as 

  * published by the free software foundation. 

  *    changelog: 

  *          24-mar-2005          rtp          created file 

  */ 

#ifndef __asm_arm_s3c2410_ts_h 

#define __asm_arm_s3c2410_ts_h

struct s3c2410_ts_mach_info { 

              int                          delay; 

              int                          presc; 

              int                          oversampling_shift; 

void __init set_s3c2410ts_info(struct s3c2410_ts_mach_info *hard_s3c2410ts_info); 

#endif /* __asm_arm_s3c2410_ts_h */ 

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

添加頭檔案#include<mach/s3c2410_ts.h> 

并在static struct platform_device *smdk2440_devices[] __initdata  結構體數組内添加 

&s3c_device_adc,(觸摸屏需要adc 的支援) 

&s3c_device_ts,          //最好将adc 添加到ts 前面,否則觸摸屏初始化時可能會出錯// 

并在上面結構體後面添加: 

/*config for touchscreen*/ 

static struct s3c2410_ts_mach_info smdk2410_ts_cfg __initdata = { 

                                .delay = 20000, 

                                .presc = 49, 

                                .oversampling_shift = 2, 

最後在static void __init smdk2440_machine_init(void)函數中增加下列代碼: 

set_s3c2410ts_info(&smdk2410_ts_cfg);      //原文有誤

由于2.6.22.7 中沒有觸屏驅動,是以要添加上。而在2.6.33 上面就有了,是以這裡改變的要大

些。 

在drivers/input/touchscreen 下建立ts.h 和s3c2410_ts.c 檔案,内容分别為: 

ts.h 内容: 

/* linux/include/asm/arch-s3c2410/ts.h 

  *          03-aug-2005          rtp          renamed to ts.h 

  */

#ifndef __asm_arm_ts_h 

#define __asm_arm_ts_h 

struct embedsky_ts_mach_info { 

void __init set_embedsky_ts_info(struct embedsky_ts_mach_info *hard_embedsky_ts_info); 

#endif /* __asm_arm_ts_h */ 

s3c2410_ts.c 内容為: 

/#include <linux/errno.h> 

#include <linux/kernel.h> 

#include <linux/module.h> 

#include <linux/slab.h> 

#include <linux/input.h> 

#include <linux/init.h> 

#include <linux/serio.h> 

#include <linux/delay.h> 

#include <linux/platform_device.h> 

#include <linux/clk.h> 

#include <asm/io.h> 

#include <asm/irq.h> 

#include <mach/regs-gpio.h> 

#include <mach/s3c2410_ts.h> 

#include <plat/regs-adc.h> 

#define true 1        //coasia added 

#define false 0        //coasia added 

#define filter_limit 25        //coasia added 

/* for ts.dev.id.version */ 

#define s3c2410tsversion                0x0101 

#define  tsc_sleep    (s3c2410_adctsc_pull_up_disable  | 

s3c2410_adctsc_xy_pst(0)) 

#define wait4int(x)    (((x)<<8) | \ 

                                          s3c2410_adctsc_ym_sen      |      s3c2410_adctsc_yp_sen      | 

s3c2410_adctsc_xp_sen | \ 

                                          s3c2410_adctsc_xy_pst(3)) 

#define   autopst                  (s3c2410_adctsc_ym_sen   |   s3c2410_adctsc_yp_sen   | 

                                          s3c2410_adctsc_auto_pst | s3c2410_adctsc_xy_pst(0)) 

#define debug_lvl      "<3>" //kern_debug 

module_author("arnaud patard <[email protected]>"); 

module_description("s3c2410 touchscreen driver");

module_license("gpl"); 

/* 

  * definitions & global arrays. 

static char *s3c2410ts_name = "s3c2410 touchscreen"; 

  * per-touchscreen data. 

struct s3c2410ts { 

                struct input_dev *dev; 

                long xp; 

                long yp; 

                int count; 

                int shift; 

static struct s3c2410ts ts; 

static void __iomem *base_addr; 

static inline void s3c2410_ts_connect(void) 

                s3c2410_gpio_cfgpin(s3c2410_gpg12, s3c2410_gpg12_xmon); 

                s3c2410_gpio_cfgpin(s3c2410_gpg13, s3c2410_gpg13_nxpon); 

                s3c2410_gpio_cfgpin(s3c2410_gpg14, s3c2410_gpg14_ymon); 

                s3c2410_gpio_cfgpin(s3c2410_gpg15, s3c2410_gpg15_nypon); 

static void touch_timer_fire(unsigned long data) 

                unsigned long data0; 

                unsigned long data1; 

                int updown; 

                data0 = readl(base_addr+s3c2410_adcdat0); 

                data1 = readl(base_addr+s3c2410_adcdat1); 

                updown     =     (!(data0     &     s3c2410_adcdat0_updown))     &&     (!(data1     & 

s3c2410_adcdat0_updown)); 

                if (updown) { 

                                if (ts.count != 0) { 

                                                ts.xp >>= ts.shift;

                                             ts.yp >>= ts.shift; 

#ifdef config_touchscreen_s3c2410_debug 

                                                { 

                                                                struct timeval tv; 

                                                                do_gettimeofday(&tv); 

                                                                printk(debug_lvl  "t:  %06d,  x:  %03ld,  y:  %03ld\n", 

(int)tv.tv_usec, ts.xp, ts.yp); 

                                                } 

                                                if (touch_pen_filtering(&ts.xp, &ts.yp)) {        //coasia added 

                                input_report_abs(ts.dev, abs_x, ts.xp);        //coasia added 

                                input_report_abs(ts.dev, abs_y, ts.yp);        //coasia added 

                                input_report_key(ts.dev, btn_touch, 1);        //coasia added 

                                input_report_abs(ts.dev, abs_pressure, 1);        //coasia added 

                                input_sync(ts.dev);        //coasia added 

                        }        //coasia added 

                                                input_report_abs(ts.dev, abs_x, ts.xp); 

                                                input_report_abs(ts.dev, abs_y, ts.yp); 

                                                input_report_key(ts.dev, btn_touch, 1); 

                                                input_report_abs(ts.dev, abs_pressure, 1); 

                                                input_sync(ts.dev); 

                                } 

                                ts.xp = 0; 

                                ts.yp = 0; 

                                ts.count = 0; 

                                writel(s3c2410_adctsc_pull_up_disable  |  autopst, 

base_addr+s3c2410_adctsc); 

                                writel(readl(base_addr+s3c2410_adccon)  | 

s3c2410_adccon_enable_start, base_addr+s3c2410_adccon); 

                } else { 

                                ts.count = 0;   

                                input_report_key(ts.dev, btn_touch, 0); 

                                input_report_abs(ts.dev, abs_pressure, 0); 

                                input_sync(ts.dev); 

                                writel(wait4int(0), base_addr+s3c2410_adctsc); 

}

static struct timer_list touch_timer = 

                                timer_initializer(touch_timer_fire, 0, 0); 

static irqreturn_t stylus_updown(int irq, void *dev_id) 

                /* todo we should never get an interrupt with updown set while 

                  * the timer is running, but maybe we ought to verify that the 

                  * timer isn't running anyways. */ 

                if (updown) 

                                touch_timer_fire(0); 

                return irq_handled; 

static irqreturn_t stylus_action(int irq, void *dev_id) 

                ts.xp += data0 & s3c2410_adcdat0_xpdata_mask; 

                ts.yp += data1 & s3c2410_adcdat1_ypdata_mask; 

                ts.count++; 

        if (ts.count < (1<<ts.shift)) { 

                                mod_timer(&touch_timer, jiffies+1); 

                                writel(wait4int(1), base_addr+s3c2410_adctsc);

     } 

static struct clk              *adc_clock; 

  * the functions for inserting/removing us as a module. 

static int __init s3c2410ts_probe(struct platform_device *pdev) 

                int rc; 

                struct s3c2410_ts_mach_info *info; 

                struct input_dev *input_dev; 

                info = ( struct s3c2410_ts_mach_info *)pdev->dev.platform_data; 

                if (!info) 

                                printk(kern_err "hm... too bad : no platform data for ts\n"); 

                                return -einval; 

                printk(debug_lvl "entering s3c2410ts_init\n"); 

                adc_clock = clk_get(null, "adc"); 

                if (!adc_clock) { 

                                printk(kern_err "failed to get adc clock source\n"); 

                                return -enoent; 

                clk_enable(adc_clock); 

                printk(debug_lvl "got and enabled clock\n"); 

                base_addr = ioremap(s3c2410_pa_adc,0x20); 

                if (base_addr == null) { 

                                printk(kern_err "failed to remap register block\n"); 

                                return -enomem; 

                }

  /* if we acutally are a s3c2410: configure gpios */ 

                if (!strcmp(pdev->name, "s3c2410-ts")) 

                                s3c2410_ts_connect(); 

                if ((info->presc&0xff) > 0) 

                                writel(s3c2410_adccon_prscen  | 

s3c2410_adccon_prscvl(info->presc&0xff),\ 

                                                          base_addr+s3c2410_adccon); 

                else   

                                writel(0,base_addr+s3c2410_adccon); 

                /* initialise registers */ 

                if ((info->delay&0xffff) > 0) 

                                writel(info->delay & 0xffff,    base_addr+s3c2410_adcdly); 

                writel(wait4int(0), base_addr+s3c2410_adctsc); 

                /* initialise input stuff */ 

                memset(&ts, 0, sizeof(struct s3c2410ts)); 

                input_dev = input_allocate_device(); 

                if (!input_dev) { 

                                printk(kern_err "unable to allocate the input device !!\n"); 

                ts.dev = input_dev; 

                ts.dev->evbit[0] = bit_mask(ev_syn) | bit_mask(ev_key) | 

                                                      bit_mask(ev_abs); 

                ts.dev->keybit[bit_word(btn_touch)] = bit_mask(btn_touch); 

                input_set_abs_params(ts.dev, abs_x, 0, 0x3ff, 0, 0); 

                input_set_abs_params(ts.dev, abs_y, 0, 0x3ff, 0, 0); 

                input_set_abs_params(ts.dev, abs_pressure, 0, 1, 0, 0); 

                //ts.dev->private = &ts; 

                ts.dev->name = s3c2410ts_name; 

                ts.dev->id.bustype = bus_rs232; 

                ts.dev->id.vendor = 0xdead; 

                ts.dev->id.product = 0xbeef; 

                ts.dev->id.version = s3c2410tsversion; 

                ts.shift = info->oversampling_shift; 

                /* get irqs */ 

                if (request_irq(irq_adc, stylus_action, irqf_sample_random, 

                                "s3c2410_action", ts.dev)) {

  printk(kern_err "s3c2410_ts.c: could not allocate ts irq_adc !\n"); 

                                iounmap(base_addr); 

                                return -eio; 

                if (request_irq(irq_tc, stylus_updown, irqf_sample_random, 

                                                "s3c2410_action", ts.dev)) { 

                                printk(kern_err "s3c2410_ts.c: could not allocate ts irq_tc !\n"); 

                                free_irq(irq_adc, ts.dev); 

                printk(kern_info "%s successfully loaded\n", s3c2410ts_name); 

                /* all went ok, so register to the input system */ 

                rc = input_register_device(ts.dev); 

                if (rc) { 

                                free_irq(irq_tc, ts.dev); 

                                clk_disable(adc_clock); 

                return 0; 

static int s3c2410ts_remove(struct platform_device *pdev) 

                disable_irq(irq_adc); 

                disable_irq(irq_tc); 

                free_irq(irq_tc,ts.dev); 

                free_irq(irq_adc,ts.dev); 

                if (adc_clock) { 

                                clk_put(adc_clock); 

                                adc_clock = null; 

                input_unregister_device(ts.dev); 

                iounmap(base_addr); 

#ifdef config_pm

static int s3c2410ts_suspend(struct platform_device *pdev, pm_message_t state) 

                writel(tsc_sleep, base_addr+s3c2410_adctsc); 

                writel(readl(base_addr+s3c2410_adccon) | s3c2410_adccon_stdbm, 

                              base_addr+s3c2410_adccon); 

                clk_disable(adc_clock); 

static int s3c2410ts_resume(struct platform_device *pdev) 

                struct s3c2410_ts_mach_info *info = 

                                ( struct s3c2410_ts_mach_info *)pdev->dev.platform_data; 

                msleep(1); 

                enable_irq(irq_adc); 

                enable_irq(irq_tc); 

                else 

#else 

#define s3c2410ts_suspend null 

#define s3c2410ts_resume    null 

static struct platform_driver s3c2410ts_driver = { 

              .driver                  = {

   .name      = "s3c2410-ts", 

                              .owner    = this_module, 

              }, 

              .probe                    = s3c2410ts_probe, 

              .remove                  = s3c2410ts_remove, 

              .suspend                = s3c2410ts_suspend, 

              .resume                  = s3c2410ts_resume, 

static struct platform_driver s3c2440ts_driver = { 

              .driver                  = { 

                              .name      = "s3c2440-ts", 

static int __init s3c2410ts_init(void) 

                rc = platform_driver_register(&s3c2410ts_driver); 

                if (rc < 0) 

                                return rc; 

                rc = platform_driver_register(&s3c2440ts_driver); 

                                platform_driver_unregister(&s3c2410ts_driver); 

                return rc; 

static void __exit s3c2410ts_exit(void) 

                platform_driver_unregister(&s3c2440ts_driver); 

                platform_driver_unregister(&s3c2410ts_driver); 

module_init(s3c2410ts_init); 

module_exit(s3c2410ts_exit); 

修改drivers/input/touchscreen 下的kconfig 檔案 

在if    input_touchscreen 下添加如下内容

config touchscreen_s3c2410 

                tristate "samsung s3c2410 touchscreen input driver" 

                depends on arch_s3c2410 && input && input_touchscreen 

                select serio 

                help 

                    say y here if you have the s3c2410 touchscreen. 

                    if unsure, say n. 

                    to compile this driver as a module, choose m here: the 

                    module will be called s3c2410_ts. 

config touchscreen_s3c2410_debug 

                boolean "samsung s3c2410 touchscreen debug messages" 

                depends on touchscreen_s3c2410 

                    select this if you want debug messages 

修改drivers/input/touchscreen 下的makefile 檔案 

在最後添加 

obj-$(config_touchscreen_s3c2410) += s3c2410_ts.o 

修改drivers/input 下的kconfig 檔案 

在config input_evdev 上面添加如下内容 

config input_tsdev 

                tristate "touchscreen interface" 

                ---help--- 

                    say y here if you have an application that only can understand the 

                    compaq touchscreen protocol for absolute pointer data. this is 

                    useful namely for embedded configurations. 

                    module will be called tsdev. 

config input_tsdev_screen_x 

                int "horizontal screen resolution" 

                depends on input_tsdev 

                default "1024" 

config input_tsdev_screen_y 

                int "vertical screen resolution" 

                default "768" 

修改drivers/input/下makefile 檔案

在obj-$(config_input_evbug)              += evbug.o 上面添加如下内容 

obj-$(config_input_tsdev)              += tsdev.o 

在drivers/input 下建立檔案tsdev.c,内容為: 

#define tsdev_minor_base                128 

#define tsdev_minors                        32 

/* first 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ 

#define tsdev_minor_mask                15 

#define tsdev_buffer_size              64

#include <linux/poll.h> 

#include <linux/moduleparam.h> 

#include <linux/major.h> 

#include <linux/random.h> 

#include <linux/time.h> 

#include <linux/device.h> 

#ifndef config_input_tsdev_screen_x 

#define config_input_tsdev_screen_x          240 

#ifndef config_input_tsdev_screen_y 

#define config_input_tsdev_screen_y          320 

module_author("james simmons <[email protected]>"); 

module_description("input driver to touchscreen converter"); 

static int xres = config_input_tsdev_screen_x; 

module_param(xres, uint, 0); 

module_parm_desc(xres, "horizontal screen resolution (can be negative for x-mirror)"); 

static int yres = config_input_tsdev_screen_y; 

module_param(yres, uint, 0); 

module_parm_desc(yres, "vertical screen resolution (can be negative for y-mirror)");

/* from compaq's touch screen specification version 0.2 (draft) */ 

struct ts_event { 

                short pressure; 

                short x; 

                short y; 

                short millisecs; 

struct ts_calibration { 

                int xscale; 

                int xtrans; 

                int yscale; 

                int ytrans; 

                int xyswap; 

struct tsdev { 

                int exist; 

                int open; 

                int minor; 

                char name[8]; 

                struct input_handle handle; 

                wait_queue_head_t wait; 

                struct list_head client_list; 

                spinlock_t client_lock; /* protects client_list */ 

                struct mutex mutex; 

                struct device dev; 

                int x, y, pressure; 

                struct ts_calibration cal; 

struct tsdev_client { 

                struct fasync_struct *fasync; 

                struct list_head node; 

                struct tsdev *tsdev; 

                struct ts_event buffer[tsdev_buffer_size]; 

                int head, tail; 

                spinlock_t buffer_lock; /* protects access to buffer, head and tail */ 

                int raw; 

/* the following ioctl codes are defined only for backward compatibility. 

  * don't use tsdev for new developement; use the tslib library instead. 

  * touchscreen calibration is a fully userspace task. 

/* use 'f' as magic number */

#define ioc_h3600_ts_magic    'f' 

#define ts_get_cal            _ior(ioc_h3600_ts_magic, 10, struct ts_calibration) 

#define ts_set_cal            _iow(ioc_h3600_ts_magic, 11, struct ts_calibration) 

static struct tsdev *tsdev_table[tsdev_minors/2]; 

static define_mutex(tsdev_table_mutex); 

static int tsdev_fasync(int fd, struct file *file, int on) 

                struct tsdev_client *client = file->private_data; 

                int retval; 

                retval = fasync_helper(fd, file, on, &client->fasync); 

                return retval < 0 ? retval : 0; 

static void tsdev_free(struct device *dev) 

                struct tsdev *tsdev = container_of(dev, struct tsdev, dev); 

                kfree(tsdev); 

static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client) 

                spin_lock(&tsdev->client_lock); 

                list_add_tail_rcu(&client->node, &tsdev->client_list); 

                spin_unlock(&tsdev->client_lock); 

                synchronize_sched(); 

static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client) 

                list_del_rcu(&client->node); 

static int tsdev_open_device(struct tsdev *tsdev) 

                retval = mutex_lock_interruptible(&tsdev->mutex); 

                if (retval) 

                                return retval;

 if (!tsdev->exist) 

                                retval = -enodev; 

                else if (!tsdev->open++) { 

                                retval = input_open_device(&tsdev->handle); 

                                if (retval) 

                                                tsdev->open--; 

                mutex_unlock(&tsdev->mutex); 

                return retval; 

static void tsdev_close_device(struct tsdev *tsdev) 

                mutex_lock(&tsdev->mutex); 

                if (tsdev->exist && !--tsdev->open) 

                                input_close_device(&tsdev->handle); 

  * wake up users waiting for io so they can disconnect from 

  * dead device. 

static void tsdev_hangup(struct tsdev *tsdev) 

                struct tsdev_client *client; 

                list_for_each_entry(client, &tsdev->client_list, node) 

                                kill_fasync(&client->fasync, sigio, poll_hup); 

                wake_up_interruptible(&tsdev->wait); 

static int tsdev_release(struct inode *inode, struct file *file) 

                struct tsdev *tsdev = client->tsdev; 

                tsdev_fasync(-1, file, 0); 

                tsdev_detach_client(tsdev, client); 

                kfree(client);

 tsdev_close_device(tsdev); 

                put_device(&tsdev->dev); 

static int tsdev_open(struct inode *inode, struct file *file) 

                int i = iminor(inode) - tsdev_minor_base; 

                int error; 

                if (i >= tsdev_minors) 

                                return -enodev; 

                error = mutex_lock_interruptible(&tsdev_table_mutex); 

                if (error) 

                                return error; 

                tsdev = tsdev_table[i & tsdev_minor_mask]; 

                if (tsdev) 

                                get_device(&tsdev->dev); 

                mutex_unlock(&tsdev_table_mutex); 

                if (!tsdev) 

                client = kzalloc(sizeof(struct tsdev_client), gfp_kernel); 

                if (!client) { 

                                error = -enomem; 

                                goto err_put_tsdev; 

                spin_lock_init(&client->buffer_lock); 

                client->tsdev = tsdev; 

                client->raw = i >= tsdev_minors / 2; 

                tsdev_attach_client(tsdev, client); 

                error = tsdev_open_device(tsdev); 

                                goto err_free_client; 

                file->private_data = client; 

                return 0;

  err_free_client: 

                kfree(client); 

  err_put_tsdev: 

                return error; 

static int tsdev_fetch_next_event(struct tsdev_client *client, 

                                                                    struct ts_event *event) 

                int have_event; 

                spin_lock_irq(&client->buffer_lock); 

                have_event = client->head != client->tail; 

                if (have_event) { 

                                *event = client->buffer[client->tail++]; 

                                client->tail &= tsdev_buffer_size - 1; 

                spin_unlock_irq(&client->buffer_lock); 

                return have_event; 

static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, 

                                                    loff_t *ppos) 

                struct ts_event event; 

                if (client->head == client->tail && tsdev->exist && 

                        (file->f_flags & o_nonblock)) 

                                return -eagain; 

                retval = wait_event_interruptible(tsdev->wait, 

                                                client->head != client->tail || !tsdev->exist); 

                                return retval; 

                if (!tsdev->exist) 

                while (retval + sizeof(struct ts_event) <= count &&

     tsdev_fetch_next_event(client, &event)) { 

                                if (copy_to_user(buffer + retval, &event, 

                                                                  sizeof(struct ts_event))) 

                                                return -efault; 

                                retval += sizeof(struct ts_event); 

/* no kernel lock - fine */ 

static unsigned int tsdev_poll(struct file *file, poll_table *wait) 

                poll_wait(file, &tsdev->wait, wait); 

                return ((client->head == client->tail) ? 0 : (pollin | pollrdnorm)) | 

                                (tsdev->exist ? 0 : (pollhup | pollerr)); 

static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 

                int retval = 0; 

                if (!tsdev->exist) { 

                                goto out; 

                switch (cmd) { 

                case ts_get_cal: 

                                if (copy_to_user((void __user *)arg, &tsdev->cal, 

                                                                  sizeof (struct ts_calibration))) 

                                                retval = -efault; 

                                break;   

                case ts_set_cal:

            if (copy_from_user(&tsdev->cal, (void __user *)arg, 

                                                                      sizeof(struct ts_calibration))) 

                                break; 

                default: 

                                retval = -einval; 

  out: 

static const struct file_operations tsdev_fops = { 

                .owner                    = this_module, 

                .open                      = tsdev_open, 

                .release                = tsdev_release, 

                .read                      = tsdev_read, 

                .poll                      = tsdev_poll, 

                .fasync                  = tsdev_fasync, 

                .unlocked_ioctl = tsdev_ioctl, 

static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client, 

                                                          int x, int y, int pressure, int millisecs) 

                struct ts_event *event; 

                int tmp; 

                /* interrupts are already disabled, just acquire the lock */ 

                spin_lock(&client->buffer_lock); 

                event = &client->buffer[client->head++]; 

                client->head &= tsdev_buffer_size - 1; 

                /* calibration */ 

                if (!client->raw) { 

                                x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; 

                                y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; 

                                if (tsdev->cal.xyswap) { 

                                                tmp = x; x = y; y = tmp; 

                event->millisecs = millisecs;

 event->x = x; 

                event->y = y; 

                event->pressure = pressure; 

                spin_unlock(&client->buffer_lock); 

                kill_fasync(&client->fasync, sigio, poll_in); 

static void tsdev_distribute_event(struct tsdev *tsdev) 

                struct timeval time; 

                int millisecs; 

                do_gettimeofday(&time); 

                millisecs = time.tv_usec / 1000; 

                list_for_each_entry_rcu(client, &tsdev->client_list, node) 

                                tsdev_pass_event(tsdev, client, 

                                                                  tsdev->x, tsdev->y, 

                                                                  tsdev->pressure, millisecs); 

static void tsdev_event(struct input_handle *handle, unsigned int type, 

                                                unsigned int code, int value) 

                struct tsdev *tsdev = handle->private; 

                struct input_dev *dev = handle->dev; 

                int wake_up_readers = 0; 

                switch (type) { 

                case ev_abs: 

                                switch (code) { 

                                case abs_x: 

                                                tsdev->x = value; 

                                                break; 

                                case abs_y: 

                                                tsdev->y = value; 

                                case abs_pressure: 

                                                if (value > dev->absmax[abs_pressure]) 

                                                                value = dev->absmax[abs_pressure];

              value -= dev->absmin[abs_pressure]; 

                                                if (value < 0) 

                                                                value = 0; 

                                                tsdev->pressure = value; 

                case ev_rel: 

                                case rel_x: 

                                                tsdev->x += value; 

                                                if (tsdev->x < 0) 

                                                                tsdev->x = 0; 

                                                else if (tsdev->x > xres) 

                                                                tsdev->x = xres; 

                                case rel_y: 

                                                tsdev->y += value; 

                                                if (tsdev->y < 0) 

                                                                tsdev->y = 0; 

                                                else if (tsdev->y > yres) 

                                                                tsdev->y = yres; 

                case ev_key: 

                                if (code == btn_touch || code == btn_mouse) { 

                                                switch (value) { 

                                                case 0: 

                                                                tsdev->pressure = 0; 

                                                                break; 

                                                case 1: 

                                                                if (!tsdev->pressure) 

                                                                                tsdev->pressure = 1; 

                case ev_syn: 

                                if (code == syn_report) {

       tsdev_distribute_event(tsdev); 

                                                wake_up_readers = 1; 

                if (wake_up_readers) 

                                wake_up_interruptible(&tsdev->wait); 

static int tsdev_install_chrdev(struct tsdev *tsdev) 

                tsdev_table[tsdev->minor] = tsdev; 

static void tsdev_remove_chrdev(struct tsdev *tsdev) 

                mutex_lock(&tsdev_table_mutex); 

                tsdev_table[tsdev->minor] = null; 

  * mark device non-existant. this disables writes, ioctls and 

  * prevents new users from opening the device. already posted 

  * blocking reads will stay, however new ones will fail. 

static void tsdev_mark_dead(struct tsdev *tsdev) 

                tsdev->exist = 0; 

static void tsdev_cleanup(struct tsdev *tsdev) 

                struct input_handle *handle = &tsdev->handle; 

                tsdev_mark_dead(tsdev); 

                tsdev_hangup(tsdev); 

                tsdev_remove_chrdev(tsdev); 

                /* tsdev is marked dead so noone else accesses tsdev->open */ 

                if (tsdev->open) 

                                input_close_device(handle); 

static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, 

                                                  const struct input_device_id *id) 

                int delta; 

                for (minor = 0; minor < tsdev_minors / 2; minor++) 

                                if (!tsdev_table[minor]) 

                if (minor == tsdev_minors) { 

                                printk(kern_err "tsdev: no more free tsdev devices\n"); 

                                return -enfile; 

                tsdev = kzalloc(sizeof(struct tsdev), gfp_kernel); 

                init_list_head(&tsdev->client_list); 

                spin_lock_init(&tsdev->client_lock); 

                mutex_init(&tsdev->mutex); 

                init_waitqueue_head(&tsdev->wait); 

                snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor); 

                tsdev->exist = 1; 

                tsdev->minor = minor; 

                tsdev->handle.dev = dev; 

                tsdev->handle.name = tsdev->name; 

                tsdev->handle.handler = handler; 

                tsdev->handle.private = tsdev; 

                /* precompute the rough calibration matrix */ 

                delta = dev->absmax [abs_x] - dev->absmin [abs_x] + 1; 

                if (delta == 0) 

                                delta = 1; 

                tsdev->cal.xscale = (xres << 8) / delta; 

                tsdev->cal.xtrans = - ((dev->absmin [abs_x] * tsdev->cal.xscale) >> 8); 

                delta = dev->absmax [abs_y] - dev->absmin [abs_y] + 1; 

                tsdev->cal.yscale = (yres << 8) / delta;

 tsdev->cal.ytrans = - ((dev->absmin [abs_y] * tsdev->cal.yscale) >> 8); 

                strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id)); 

                tsdev->dev.devt = mkdev(input_major, tsdev_minor_base + minor); 

                tsdev->dev.class = &input_class; 

                tsdev->dev.parent = &dev->dev; 

                tsdev->dev.release = tsdev_free; 

                device_initialize(&tsdev->dev); 

                error = input_register_handle(&tsdev->handle); 

                                goto err_free_tsdev; 

                error = tsdev_install_chrdev(tsdev); 

                                goto err_unregister_handle; 

                error = device_add(&tsdev->dev); 

                                goto err_cleanup_tsdev; 

  err_cleanup_tsdev: 

                tsdev_cleanup(tsdev);   

  err_unregister_handle: 

                input_unregister_handle(&tsdev->handle); 

  err_free_tsdev: 

static void tsdev_disconnect(struct input_handle *handle) 

                device_del(&tsdev->dev); 

                tsdev_cleanup(tsdev); 

                input_unregister_handle(handle); 

static const struct input_device_id tsdev_ids[] = { 

                            .flags                                    =         input_device_id_match_evbit         | 

input_device_id_match_keybit | input_device_id_match_relbit, 

                            .evbit        = { bit(ev_key) | bit(ev_rel) },

         .keybit      = { [btn_left/32] = bit(btn_left) }, 

                            .relbit      = { bit(rel_x) | bit(rel_y) }, 

                }, /* a mouse like device, at least one button, two relative axes */ 

input_device_id_match_keybit | input_device_id_match_absbit, 

                            .evbit        = { bit(ev_key) | bit(ev_abs) }, 

                            .keybit      = { [btn_touch/32] = bit(btn_touch) }, 

                            .absbit      = { bit(abs_x) | bit(abs_y) }, 

                }, /* a tablet like device, at least touch detection, two absolute axes */ 

input_device_id_match_absbit, 

                            .evbit        = { bit(ev_abs) }, 

                            .absbit      = { bit(abs_x) | bit(abs_y) | bit(abs_pressure) }, 

                }, /* a tablet like device with several gradations of pressure */ 

                {} /* terminating entry */ 

module_device_table(input, tsdev_ids); 

static struct input_handler tsdev_handler = { 

                .event                    = tsdev_event, 

                .connect                = tsdev_connect, 

                .disconnect          = tsdev_disconnect, 

                .fops                      = &tsdev_fops, 

                .minor                    = tsdev_minor_base, 

                .name                      = "tsdev", 

                .id_table              = tsdev_ids, 

static int __init tsdev_init(void) 

                return input_register_handler(&tsdev_handler); 

static void __exit tsdev_exit(void) 

                input_unregister_handler(&tsdev_handler); 

module_init(tsdev_init); 

module_exit(tsdev_exit);

修改arch/arm/plat-s3c24xx/s3c244x.c 

在void __init s3c244x_map_io(struct map_desc *mach_desc, int size)函數中,添加如下内容 

s3c_device_ts.name = "s3c2440-ts"; 

修改arch/arm/plat-s3c24xx/include/plat/devs.h,添加如下内容 

extern struct platform_device s3c_device_ts; 

在配置菜單中添加如下項: 

    <*>input device support  ---> 

<*>      touchscreen interface 

(1024)  horizontal screen resolution 

(768)      vertical screen resolution     

         <*>touchscreens  ---> 

                      <*>    samsung s3c2410 touchscreen input driver 

這裡如果選擇配置含有debug 字樣的那一選項,則核心在燒寫到闆子上,你每次

觸屏都會列印觸屏的坐标值。為了不讓列印,我們不選擇該項。 

19,     至此,移植基本完成,其他驅動可以自己根據具體情況進行添加。

繼續閱讀