close

從很久以前就很想去撰寫這類的文章,但因為文筆不夠生動,知識技巧和技術深度其實都無法寫到自己想要的感覺,所以等了很久,雖然現在還是很肉腳,但至少我找到想要的主題,讓我們慢慢進入linux 世界吧!

 

先談論我的工作內容,不管在第一個工作(代理商)或是第二個工作(系統廠),其實每個工作接觸的面和點都不同,像是在代理商自家產品要很了解,尤其是在regisiter & datasheet,因為不提供total solution,不然有提供solution 是買人家的system 在po自家公司的code,非常少見所以不列入討論範圍,所以後來轉型開始往driver(kernel space)面少點深,在第二個工作已經進來三個月,就接了兩個project,第一個是keil c 8051的架構(這個找時間在額外開一個文章來討論),第二個就是從8051 porting到 MIPS linux embedded system,時間很趕沒時間去發揮到很多,對專案程度而已第二家公司摸的會比較多面但時間緊湊摸不到點,因為在這過程也在學習所以這次開始po文,當作是一個成長紀錄,廢話不多說就開始吧!!

 

撰寫driver有很多技巧,在你面對硬體上也有不同的特性,像是大架構arm mips 雖然大家都說他很相似,其實還是很多不同的地方,舉例來說在gpio mips就是一個單一feature 在arm 部分 就有分periph,更不用提x86 或是 其他的,在細看內容 小從簡單的gpio up/down 到 gpio 寫出 i2c 或是usb等等,要了解需求在針對需求用對方法,下列介紹就針對我現在在看的地方。

 

如果不知道是剛入門不知道去哪邊找資料 下載code來看,請到atmel因為那邊datasheet是開放式下載的,我看到很多論壇都在討論samsung chip,我也很想同樂樂阿,但是他的原廠網站並沒有提供資料,在加上atmel有出原廠的ek(demo board)所有資料都可以找到,也可以去這裡下載kernel code(此連結是到原廠官網),所以來吧!!想學免費的請跟著點進去自己下載來練練功,檔案很多先不管其他的。

 

在arch\arm\mach-at91這個路徑下,你會看到Board-ek.c,這裡面放的是driver init,如果用source insight看到的你應該可以看到function連結出去很多,若是用其他編輯軟體就要自己找一下了,在這個檔案你會看到device init 都有 platform_device_register 這個function,這個就是註冊 該drvice的function,但此時kernel尚未看的見device,這個又要討論linux kernel2.6 跟 2.4 driver的差異,晚一點在補文來討論,此時需要將init function用module_init,才算真正的完整註冊。

platform 這個概念,在開發底層驅動程序時,首先要確認的就是設備的資源信息,例如設備的地址,在2.6內核中將每個設備的資源用結構 platform_device 來描述,該結構體定義在linux\include\linux\platform_device.h 的struct platform_device 此結構有一個重要的地方就是 resource可參考程式碼,來觀看大概的流程:

在At91cap9_devices.c (linux-2.6.25\arch\arm\mach-at91)  

static struct resource eth_resources[] = {
    [0] = {
        .start    = AT91CAP9_BASE_EMAC,
        .end    = AT91CAP9_BASE_EMAC + SZ_16K - 1,
        .flags    = IORESOURCE_MEM,
    },
    [1] = {
        .start    = AT91CAP9_ID_EMAC,
        .end    = AT91CAP9_ID_EMAC,
        .flags    = IORESOURCE_IRQ,
    },
};

可以看到上面其實 define resource 好了,這時候才可以用 platform_device開始填入註冊資訊
static struct platform_device at91cap9_eth_device = {
    .name        = "macb",
    .id        = -1,
    .dev        = {
                .dma_mask        = &eth_dmamask,
                .coherent_dma_mask    = DMA_BIT_MASK(32),
                .platform_data        = &eth_data,
    },
    .resource    = eth_resources,
    .num_resources    = ARRAY_SIZE(eth_resources),
};
最後才再將相關要register 寫在init function
void __init at91_add_device_eth(struct at91_eth_data *data)
{
    if (!data)
        return;

    if (data->phy_irq_pin) {
        at91_set_gpio_input(data->phy_irq_pin, 0);
        at91_set_deglitch(data->phy_irq_pin, 1);
    }

    /* Pins used for MII and RMII */
    at91_set_A_periph(AT91_PIN_PB21, 0);    /* ETXCK_EREFCK */
    at91_set_A_periph(AT91_PIN_PB22, 0);    /* ERXDV */
    at91_set_A_periph(AT91_PIN_PB25, 0);    /* ERX0 */
    at91_set_A_periph(AT91_PIN_PB26, 0);    /* ERX1 */
    at91_set_A_periph(AT91_PIN_PB27, 0);    /* ERXER */
    at91_set_A_periph(AT91_PIN_PB28, 0);    /* ETXEN */
    at91_set_A_periph(AT91_PIN_PB23, 0);    /* ETX0 */
    at91_set_A_periph(AT91_PIN_PB24, 0);    /* ETX1 */
    at91_set_A_periph(AT91_PIN_PB30, 0);    /* EMDIO */
    at91_set_A_periph(AT91_PIN_PB29, 0);    /* EMDC */

    if (!data->is_rmii) {
        at91_set_B_periph(AT91_PIN_PC25, 0);    /* ECRS */
        at91_set_B_periph(AT91_PIN_PC26, 0);    /* ECOL */
        at91_set_B_periph(AT91_PIN_PC22, 0);    /* ERX2 */
        at91_set_B_periph(AT91_PIN_PC23, 0);    /* ERX3 */
        at91_set_B_periph(AT91_PIN_PC27, 0);    /* ERXCK */
        at91_set_B_periph(AT91_PIN_PC20, 0);    /* ETX2 */
        at91_set_B_periph(AT91_PIN_PC21, 0);    /* ETX3 */
        at91_set_B_periph(AT91_PIN_PC24, 0);    /* ETXER */
    }

    eth_data = *data;
    platform_device_register(&at91cap9_eth_device);
}
然後你在追code到上層
#define MACHINE_START(_type,_name)            \
static const struct machine_desc __mach_desc_##_type    \
 __used                            \
 __attribute__((__section__(".arch.info.init"))) = {    \
    .nr        = MACH_TYPE_##_type,        \
    .name        = _name,

#define MACHINE_END                \
};
你會發現他用了MACHINE_START 跟傳統的module_init有一點不一樣,他是直接設好macro,到時候直接使用就可以把arch的info宣告好,但我的建議是先別想說你懂不懂他在做啥,先懂流程你要先確定resource填寫是否正確,在往下一步platform_device填寫,在去init 將填寫的東西註冊,註冊也可以分好幾種填寫方式,後來在討論詳細一點,當相關code都已經撰寫完成,會遇到一個問題你要如何掛載,當embedded system會比較麻煩,因為你必須將你寫好的driver 放到root file底下,你在ap端 才能呼叫到,在這邊又可以討論makefile和mkimg這兩個檔案,如何建立好的檔案利用mkimg放到root file,其實之前mount的方法是用openembedded,後來到這家公司又發現busybox這個好用的東西,若是你在改寫的地方是人家常用的會比較建議就直接改寫,這邊可以討論的東西太多了看後面有沒有機會在往後講下去,這篇先初步的介紹。
arrow
arrow
    全站熱搜

    funlife1 發表在 痞客邦 留言(0) 人氣()