Wednesday, August 08, 2018

GitHub Page + Jekyll

利用 GitHub Page + Jekyll theme 架設自己的 Blog 方法有數個方式,網上也得多人 提供了參考。在此,只是記錄自己的安裝流程。

架設

  • 必需先有 GitHub 帳號
  • Fork https://github.com/fongandrew/hydeout 到自己的 GitHub 並更名
    • 更名: Settings -> Settings -> Repository name -> 新名稱 -> Rename (更名目前測試會有問題,link 不對)
  • 設定 GitHub Pages
    • Settings -> GitHub Pages -> Source -> gh-pages branch -> Save。設定完後即會顯示出這個 Blog 的連結網址。此時預設的 Blog 即已生成,可以點選連結看看內容。
  • 在 local 端俢改內容並預覽,確定內容後上傳至 GitHub
    # 安裝必要的工具
    gem install bundler jekyll
    
    git clone https://github.com/NienfengYao/hydeout
    cd hydeout
    gie checkout gh-pages
    
    # 啟動 web server,此時便可透過 Browser 預覽內容了
    bundle exec jekyll serve --host 10.63.240.140 --port 4000
    # press ctrl-c to stop
    
    # 新增自己的新文章
    vim _post/2018-08-02-github-jekyll.md
    # 可以再啟動 local server,確認內容
    
    # 上傳修改後的結果至 GitHub
    git push

Reference

Wednesday, November 11, 2015

ModelViewTutorial

Study QT: Model/View Tutorial

很久沒碰 Python了,這次接到的任務是 Python + Qt 開發測試工具。一開始從需求清單中,找到了 QColumnView 來做主要的呈現。但接下來的過程中,卻找不太到充足的資料來使用這介面。以下便是學習這題目的資料。

  1. 透過 QT: Model/View Tutorial 了解 model (資料內容本身) 和 view (呈現方式) 彼此是如何運作的。具體內容請參考來源,在此我附上了相對應的 Python code 參考。

    1. ex01_readonly.py
    2. ex02_formatting.py
    3. ex03_changingmode.py
    4. ex04_headers.py
    5. ex05_edit.py
    6. ex06_treeview.py
    7. ex07_selections.py
  2. QColumnView 的最後一欄位,是用來做 preview 功能的。一開始不了解時,一直被為啥多了一個空白欄位感到不解,為移除最後這一欄位花了很多時間,最後看到文件中 previewWidget() 和 updatePreviewWidget signal,才了解最後一欄位的用意。以下為我寫的範例:

    1. ex08_columnview.py
        #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #
    # (c) 2015 RyanYao, http://nienfeng.blogspot.tw/
    #

    import sys
    import os
    from PySide import QtGui, QtCore


    class Example(QtGui.QMainWindow):
        def __init__(self):
            super(Example, self).__init__()
            self.initUI()

        def initUI(self):
            self.model = QtGui.QStandardItemModel()
            self.view = QtGui.QColumnView()
            self.setCentralWidget(self.view)
            self.view.setModel(self.model)
            self.view.updatePreviewWidget.connect(self.previewWidget)

            root = self.model.invisibleRootItem()
            for i in range(3):
                group = QtGui.QStandardItem("Group %d" % i)
                # childs = []
                for j in range(4):
                    child = QtGui.QStandardItem("Child %d-%d" % (i,j))
                    group.appendRow(child)
                root.appendRow(group)
            self.show()

        def previewWidget(self, index):
            print index.row(), index.column()
            hierarchyLevel = 1
            seekRoot = index

            while(seekRoot.parent() != QtCore.QModelIndex()):
                seekRoot = seekRoot.parent()
                hierarchyLevel += 1
            edit = QtGui.QPlainTextEdit()
            edit.appendPlainText("%s, Level %d" % (index.data(), hierarchyLevel))
            self.view.setPreviewWidget(edit);


    def main():
        app = QtGui.QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())


    if __name__ == '__main__':
        main()

Monday, May 14, 2012

PLL (Phase-locked loop)

  • Phase-locked loop    
    • A phase-locked loop or phase lock loop (PLL) is a control system that generates an output signal whose phase is related to the phase of an input "reference" signal. It is an electronic circuit consisting of a variable frequency oscillator and a phase detector. This circuit compares the phase of the input signal with the phase of the signal derived from its output oscillator and adjusts the frequency of its oscillator to keep the phases matched. The signal from the phase detector is used to control the oscillator in a feedback loop.
    • Frequency is the derivative of phase. Keeping the input and output phase in lock step implies keeping the input and output frequencies in lock step. Consequently, a phase-locked loop can track an input frequency, or it can generate a frequency that is a multiple of the input frequency. The former property is used for demodulation, and the latter property is used for indirect frequency synthesis.


  • 目前此 case 的設計:
    • 1. Most internal clocks originate with a 27MHz off-chip crystal.
    • 2. The system contains two, on-chip spread-spectrum phase-locked loops (SSPLLs) which use the 27MHz crystal oscillator clock as their input.
    • 3. Referring to Figure, PLL0 rate multiplies the 27MHz reference clock up to 1350MHz, and only the primary output of PLL0 is used. This 1350MHz output is used by the main system clock generator (cpu_clkgen).
    • 4. We can set the frequency of other device by dividing the primary output of PLL0/PLL1. Example, we set sdmmcclk to 100MHz and sd0clk to 50MHz and observe the frequency with scope after mapping the frequency to GPIO.

  •  Program. 當我們設定好 PLL0 時及相關的周邊倍頻 clock 時,依文件提及,可以將欲觀察的 device's clock mapping 到某二根 GPIO 觀察。以下為我測試的步驟。
    1. 設定 PLL0 (Regs: PLL0_CR0/PLL0_CR1/PLL0_CR2/PLL0_CR3/PLL0_SR)。這些值的設定主要還是來自原廠的提供,因為沒有相關的 Spec 可查)
    2. Enable Clock Gate (Regs: CGCR)。The Clock Gate Control Register allows various clocks inside the ASIC to be powered down under firmware control, to save power when the parts of the ASIC that use them are not in use。所以在測試時,我先將全部的 clock output 全打開。
    3. 將要觀查的 device frequency map to GPIO (Regs: CDCR1)。文中提及,會將欲觀察的 frequency map to GPIOB[31:30],且必需先將此二pin GPIOB[31:30] 設為 AltFun7,再將要觀察的 device frequency 填相對應的值至 CDCR1 中。
    4. 測試過程
      • evb gate_on // Enable all clock gate
      • evb pll0_set // Set PLL0
      • evb pll1_set // Set PLL1
      • evb io_out val // Set GPIOB[31:30] to AltFunc7 and the related value to CDCR1 to observe  the device's frequency

Friday, January 16, 2009

SVN 與 Trac 的備份、還原

-_-,硬碟竟然用不到半年就毀了,看來還是得有良好的備份習慣丫

  • 依之前建立的,只要將 Repository 目錄下的東西保存,即可在之後將資料回復
  • 假設系統毀了,回復步驟為
    1. 重新安裝所需軟體及設定 path
    2. 修改 httpd.conf (apache2 configure file) #Ryan ==================== start
      // enable mod_dav.so,並 load module for svn/trac
      LoadModule dav_module modules/mod_dav.so

      # For Subversion
      LoadModule dav_svn_module modules/mod_dav_svn.so
      LoadModule authz_svn_module modules/mod_authz_svn.so

      # For Trac
      LoadModule python_module modules/mod_python.so
      #Ryan ==================== end

      #Ryan =================== start
      //設定 svn/trac 可以透過 apache2 的尋訪路徑
      <location>
      DAV svn
      SVNParentPath H:/Repository/svn
      # <limitexcept>
      AuthType Basic
      AuthName "CompanyName"
      AuthUserFile "H:/Repository/project-users.db"
      Require valid-user
      # </limitexcept>
      </location>

      <location>
      SetHandler mod_python
      PythonHandler trac.web.modpython_frontend
      PythonOption TracEnvParentDir H:/Repository/trac
      PythonOption TracUriRoot /trac
      AuthType Basic
      AuthName "CompanyName"
      AuthUserFile "H:/Repository/project-users.db"
      Require valid-user
      </location>

      #Ryan =================== end
    3. 此時應該可以看到之前的 Trac project 了 (http://localhost/trac)。 但 trac project 與 svn project 的連結關係仍有問題。
    4. 針對對個 project, 修改 trac.ini 並 resync 即正常。 修改 S:\Repository\trac\zeppelin\conf\trac.ini -> [trac] -> repository_dir = s:\Repository\svn\projectname
      S:\AppServ\python\Scripts>trac-admin.exe S:\Repository\trac\projectname resync

太扯了,硬碟連續出狀況

昨天下午
本還想著目前的工作看來還蠻順利的
看來應該會有空餘的時間可以來看看 Django (想架站寫些 service 來玩玩)
但…但…

在昨天下午二~三時間,端了一杯水回座位上
疑…怎麼當機了(我的系統很少有異常狀況,performance也覺得能接受)
算了,重開機吧
……開機之後進不出,說是某個系統檔案毀損了,需要回復光碟
只能交給 MIS 處理了
……二十分鐘後,接到電話
天丫,竟說我硬碟毀了,完全捉不到…my god, 我 沒 備 份 丫…
看來 MIS 也沒撒,拿回來自己試,只有救回我的工作記錄而已
我是用 Trac 在記東西的,起碼有這在手,之前做的內容就一定能回復,只是需要時間來完成

於是,只好死了心的把硬碟送修,開始從頭建置工作環境了
但今天,竟然發現昨天才從 MIS 接手的新硬碟&系統
竟然無法刪除多個檔案或一個資料夾…天丫,這是什麼情況丫
檢查過了,也無壞毀情況丫,怎會這樣
只好又拿去給 MIS
但無法釐清是給我時的環境就是如此,還是我新安裝程式的問題
-_-,但我裝的也都是工作必要,且之前的工作環境 & 同事都裝的丫
然後就是終極大法 ==> 重灌

怎麼會這樣,太久沒拜拜了嗎
可是我上周末經過土地公廟時有用手拜一下丫
吼…
找個時間,再來好好的拜一下吧

=================================
備份策略

1. 每周將工作項目備份至隨身碟,需有控制版本的功能
2. 每月將資料整理後,備份至 DVD

至於系統&工作環境的部份,就算了吧,真的遇到再重灌,我不想額外買一顆大硬碟

Tuesday, September 09, 2008

操作 memory mapping register I/O

在寫 driver 時,最基本的動作通常是練習控制簡單的 I/O 動作讓某個裝置起作用。
在此便解釋如何控制,以及一些簡單的範例,取自:

  • 現代嵌入式系統開發專案實務:菜鳥成長日誌與專案經理的私房菜
  • linux-ldp-v1.2

操作 memory mapping register I/O

  • Memory Mapping Register: 寫驅動程式時,要控制接在 CPU 外部的晶片勢必是透過 CPU 的 PIN 腳,可能只是單純的將 GPIO pin 設為 high/low 來控制外部的 chip,同理外部的設備也可以透過 GPIO pin 將訊號傳給 CPU;或者驅動程式可以透過某種通訊協定來控制 I/C,例如 SPI 或 I2C等。但無論是何種 protocol,CPU 和 外部 chip 之間的資料與命令傳遞還是得透過 CPU 的 pin 腳。
  • 程式寫法
    *(volatile unsigned char *)(0x302CF)=0x00;
    • register 其實是一個位址,使用指標就可以對其設值或取值,要注意的是一定要用 volatile 關鍵字,否則 compiler 的最佳化功能很可能會把某些程式當作是沒意義的。

範例

  • 以下為一 LED driver example
    /* drv_LED.c
    - 假設 CPU 用 P1 這樣 pin 與 LED 相接
    - 當 P1 為 high/low 時, LED 會 on/off
    */

    void drv_init_LED(void)
    {
    //設定 P1 為 output pin
    *(volatile unsigned char*)0x200023 |= 0x02; //0000 0010

    //default: P1 is low, LED off
    *(volatile unsigned char*)0x200022 &= ~0x02; //1111 1101
    }

    void drv_LED_off()
    {
    //set P1 is low, LED off
    *(volatile unsigned char*)0x200022 &= ~0x02; //1111 1101
    }

    void drv_LED_on()
    {
    //set P1 is low, LED off
    *(volatile unsigned char*)0x200022 |= 0x02; //0000 0010
    }
  • 解釋 *(volatile unsigned char*)0x200022 |= 0x02;
    void drv_LED_on(void)
    {
    volatile unsigned char data; // value of register context
    volatile unsigned char* reg; // the point to register

    reg = (volatile unsigned char*) 0x200022;
    data = *reg; // get the value of the register in 0x200022
    data = data | 0x2; // set 1 to 2th bit
    *reg = data; // set the new data to register
    }
  • linux-ldp-v1.2 例子
    • omap_writel((omap_readl(OMAP2_CONTROL_PBIAS_1) | 0x6) & ~0x1, OMAP2_CONTROL_PBIAS_1);
    • /*
      * Functions to access the OMAP IO region
      *
      * NOTE: - Use omap_read/write[bwl] for physical register addresses
      * - Use __raw_read/write[bwl]() for virtual register addresses
      * - Use IO_ADDRESS(phys_addr) to convert registers to virtual addresses
      * - DO NOT use hardcoded virtual addresses to allow changing the
      * IO address space again if needed
      */
      #define omap_readb(a) (*(volatile unsigned char *)IO_ADDRESS(a))
      #define omap_readw(a) (*(volatile unsigned short *)IO_ADDRESS(a))
      #define omap_readl(a) (*(volatile unsigned int *)IO_ADDRESS(a))

      #define omap_writeb(v,a) (*(volatile unsigned char *)IO_ADDRESS(a) = (v))
      #define omap_writew(v,a) (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
      #define omap_writel(v,a) (*(volatile unsigned int *)IO_ADDRESS(a) = (v))
    • #define IO_OFFSET 0x90000000
      #define IO_ADDRESS(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */

Build Ramdisk for ARM


目標

  • 建置一個基本的 Ramdisk for arm,以便了解整個 file system 的開機流程。
  • ramdisk 主要程式由 busybox 提供,並包含基本的設定檔。
  • 建置平台為 Qemu: ARM Integrator/CP board 的模擬平台上。

Preview

  • 參考之前 Linux 2.6 的 initramfs 機制,了解 initramfs 的觀念。
  • Linux 2.6 核心將一個小的 ram-based initial root filesystem(initramfs) 包進核心,且若這個檔案系統包含一隻程式 /init,核心會將它當作第一隻程式執行。此時,找尋其他檔案系統並執行其他程式已不再是核心的問題,而是新程式的工作。

開機及初步 ramdisk

  • 由於Linux 2.6 核心已將一個小的 ram-based initial root filesystem(initramfs) 包進核心,所以我們可以先建立一個假的 ramdisk,只包含 init 來測試是否 kernel boot 成功與否。Ref: Jserv's blog: 深入理解 Linux 2.6 的 initramfs 機制 (上)
    mkdir hello-initramfs
    cd hello-initramfs
    vi init.c
    arm-none-linux-gnueabi-gcc -static -o init init.c # 編成 static 省麻煩
    file init # 確認編譯完成的檔案格式是否正確
    #init: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.14, statically linked, not stripped
    mkdir dev
    cd dev
    mknod -m 600 console c 5 1
    cd ..

    • init.c, 將開機停在執行 /init 時,以驗証我們的動作是否成功
      #include 
      int main()
      {
      printf("Hello World!\n");
      sleep(9999);
      return 0;
      }

  • Build Kernel
    • 取得最近的 kernel source,linux-2.6.26.3
    • 嚐試用 kernel source 裡的 integrator_defconfig 編譯 kernel,但在測試時發現沒有任何反應,所以先從 qemu 網站上可以下載的 arm-test-0.2.tar.gz 裡取出 .config 來編譯。
    • 修改 Makefile 以符合我們用的 cross compile
      ARCH            ?= arm
      CROSS_COMPILE ?= arm-none-linux-gnueabi-
    • make menuconfig,記得選取 initramfs 並填上 path
      [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
      (/home/ryan/qemu/hello-initramfs) Initramfs source file(s)
    • make zImage
    • 測試: qemu-system-arm -kernel linux-2.6.26.3/arch/arm/boot/zImage。可以看見開機時有成功執行 Hello World! 這個 fake init
      TCP cubic registered
      NET: Registered protocol family 17
      RPC: Registered udp transport module.
      RPC: Registered tcp transport module.
      802.1Q VLAN Support v1.8 Ben Greear
      All bugs added by David S. Miller
      VFP support v0.3: implementor 41 architecture 1 part 10 variant 9 rev 0
      Hello World!

  • 以 busybox 建置 ramdisk,將 busybox 編譯為 static。
    • 取得最新 soruce BusyBox 1.11.2
    • 修改 Makefile
      CROSS_COMPILE ?= arm-none-linux-gnueabi-
      ARCH ?= arm
    • make menuconfig。記得選取 static libnary
      [*] Build BusyBox as a static binary (no shared libs)
    • make install。會在目錄下產生 _install 目錄,這也是待會我們要移進 ramdisk 的內容
    • 檢查檔案格式
      file _install/bin/busybox
      #_install/bin/busybox: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.14, statically linked, stripped
  • 建置初步 ramdisk
    mkdir busybox-initramfs
    cd busybox-initramfs/
    cp -av ../busybox-1.11.2/_install/* .
    ln -s sbin/init init
    find ./ | cpio -o -H newc | gzip > ../busybox.initramfs.cpio.gz
    cd ..
  • 啟動
    qemu-system-arm -kernel linux-2.6.26.3/arch/arm/boot/zImage -initrd busybox.initramfs.cpio.gz
    • 此時會一直 argue 缺少 device 。此時可是自建相關的 device node,則可正常啟動。
    • 但我希望能由系統自行建立,所以先 copy arm_test 裡 file system 的 etc 目錄 來用,待之後再來分析流程。成功開機。
      cd busybox-initramfs
      cp ../arm-test/arm_root.img arm_root.img.gz
      gunzip arm_root.img.gz
      mkdir tmp
      cd tmp
      cpio -i -F ../arm_root.img
      cp -av etc ../
      touch mdev.conf # 這是因為開機時 complain 沒有這個檔,所以先做個假的。這是因為開始時有執行 mdev,而 mdev.conf 為它的設定檔。
      mkdir root
      cd ..
      rm -rf arm_root.img tmp
      find ./ | cpio -o -H newc | gzip > ../busybox.initramfs.cpio.gz
      qemu-system-arm -kernel linux-2.6.26.3/arch/arm/boot/zImage -initrd busybox.initramfs.cpio.gz

開機流程剖析

  • Linux kernel 在掛載 ramdisk 後,預設會尋找 /init 這隻程式,除非在内核傳遞参數裡有設置 init=/linuxrc 來指定要找的第一個程式。
  • 目前 /init 是由 busybox 所提供的,其預設行為可以參考 init (重要,read it)。
  • 建立 /etc/inittab,/init 預設會先分析此 script
    ::sysinit:/etc/init.d/rcS

    ::respawn:/sbin/getty -L 38400 tty1
    ::respawn:/sbin/getty -L 38400 tty2
    ::respawn:/sbin/getty -L 38400 tty3
    ::respawn:/sbin/getty -L 38400 tty4

    ::respawn:/sbin/getty -L ttyAMA0 115200 xterm
  • 由 /etc/inittab 所指定 (或 /etc/inittab 不存在時,init 的預設行為),會去執行 /etc/init.d/rcS。
    • 其執行的內容為
      • 掛載 virtual file system,參考Magic Linux开发入门指南(五),基本說明的蠻清楚的。
      • mdev: 初始 device node 及自動更新,參考 busybox 附帶的文檔 busybox-1.11.2/docs/mdev.txt
      • 其除為網路設定部份,這就先不處理了。
    • #! /bin/sh

      mkdir -p /proc
      mount -t proc proc /proc
      mkdir -p /sys
      mount -t sysfs sysfs /sys
      mkdir -p /dev/pts
      mount -t devpts devpts /dev/pts
      echo /sbin/mdev > /proc/sys/kernel/hotplug
      mdev -s
      hostname qemu
      ifconfig lo 127.0.0.1 up
      # This board doesn't have a hardware clock, so system time is way off.
      # The bugsybox dhcp client doesn't work when the clock is wrong.
      # Oh well.
      ifconfig eth0 10.0.2.15 up
      rdate 10.0.2.2
      ip route add default via 10.0.2.2
  • inittab 其餘的部份為本機端終端機啟動的個數,參考 Util-linux (getty 和login) 及 man getty。
    • 允許登錄系統(log in)和得到命令行提示符(bash prompt)。
    • 准備一個密碼文件/etc/passwd.login 登錄程序正是通過查詢該文件來確認您是否允許登錄的。我們可以只設置根系統用戶就夠了,而且不需要任何密碼!! 只需要在目標系統的密碼文件/etc/passwd加上此行 "root::0:0:root:/root:/bin/bash"即可。(/etc/group 也要加入 "root:x:0:")
  • /etc/issue: 在終端機介面登入的時,顯示提示的字串。(如果想要讓使用者登入後取得一些訊息,可以寫在 /etc/motd)
  • /etc/nsswitch.conf: name-server switch,用來控制名稱資訊轉換,例如,當系統要取得 password、group、host 等資訊時,會參考這個檔案以決定要從哪裡得到資訊。參考 man nsswitch.conf。
    # /etc/nsswitch.conf
    #
    # Example configuration of GNU Name Service Switch functionality.
    # If you have the `glibc-doc' and `info' packages installed, try:
    # `info libc "Name Service Switch"' for information about this file.

    passwd: compat
    group: compat
    shadow: compat

    hosts: files dns
    networks: files

    protocols: db files
    services: db files
    ethers: db files
    rpc: db files

    netgroup: nis
  • /etc/resolv.con: 參考簡介,man resolv.conf
    nameserver 10.0.2.3

Thursday, August 28, 2008

Blogger 有用的功能

針對目前的 Google Blogger 有些覺得不太滿意的地方。
以下便是針對這些點,找到的 solution。
之後應該會陸續將覺得有需要的功能一一找補強吧。

第一個 cross compile 成功的 kernel module - hello

第一個 kernel module - hello

The Linux Kernel Module Programming Guide 文上所說的,編寫第一個kernel module

  • hello.c
    #include  /* Needed by all modules */
    #include /* Needed for KERN_INFO */
    #include /* Needed for the macros */
    #define DRIVER_AUTHOR "Peter Jay Salzman "
    #define DRIVER_DESC "A sample driver"

    static int __init init_hello(void)
    {
    printk(KERN_INFO "Hello, world\n");
    return 0;
    }

    static void __exit cleanup_hello(void)
    {
    printk(KERN_INFO "Goodbye, world\n");
    }

    module_init(init_hello);
    module_exit(cleanup_hello);

    MODULE_LICENSE("GPL");
    MODULE_AUTHOR(DRIVER_AUTHOR); /* Who wrote this module? */
    MODULE_DESCRIPTION(DRIVER_DESC); /* What does this module do */
    MODULE_SUPPORTED_DEVICE("testdevice");

  • Makefile
    obj-m += hello.o
    all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

確定是可以在 X86 host 上成功編譯,運作也一切正常。
但問題來了,我該如何改寫 Makefile,使其能 cross compile 呢?
目前還不知道該如何解決,因為對 Makefile 及 cross compile 步驟還在粗淺的認識階段,以前也都是利用套件所提供的 configure 工具來代勞。
所以就想到將新增的 module 加到 kernel source 中,這樣就可以利用 kernel source 所提供 cross compile 的功能來幫我做相關設定了。


利用 kernel source 來 cross compile 新增的 module

  • 環境設定
    • Target Board 是 arm,所以在Makefile 裡: ARCH=arm, CROSS_COMPILE=arm-none-linux-gnueabi-
    • 新增一個 module,在 driver 目錄下新增一個測試目錄 rayn,測試 module 位於 driver/ryan/hello.c。
  • 編輯 configure 的選項
    • 修改 arch/arm/Kconfig (因為我們的target 為 arm,所以必需改在 arch/arm 裡的 Kconfig 才有用)
      • 加入這一行 source "drivers/ryan/Kconfig",將新增的測試目錄加到 configure 選項中
    • 修改 drivers/{Kconfig,Makefile}
      • Kconfig
        • 新增 source "drivers/ryan/Kconfig"
      • Makefile
        • 新增 obj-$(CONFIG_RYAN_TEST) += ryan/
    • 新增目錄,driver/ryan 及所需的檔案
      • Kconfig

        menu "RYAN test devices"

        config RYAN_TEST
        bool "RYAN test"

        config RYAN_TEST_HELLO
        tristate "The first kernel module - hello"
        depends on RYAN_TEST

        endmenu

      • Makefile
        obj-$(CONFIG_RYAN_TEST_HELLO)           += hello.o
      • hello.c
  • make menuconfig,將 hello 編為 module。可以看見新增的選項
    [*] RYAN test            
    The first kernel module - hello
  • make modules。可以看見 hello.ko 已生成。
    Building modules, stage 2.
    MODPOST 4 modules
    CC drivers/ryan/hello.mod.o
    LD [M] drivers/ryan/hello.ko
    CC fs/jffs2/jffs2.mod.o
    LD [M] fs/jffs2/jffs2.ko

  • 在 target 上測試

    bash-3.2# insmod ./hello.ko
    <6>Hello, world
    Hello, world
    bash-3.2# rm
    rm rmdir rmmod
    bash-3.2# rmmod hello
    <6>Goodbye, world
    Goodbye, world

完畢…

Wednesday, August 27, 2008

vi 命令速查

用 vi 時常忘記一些偶爾用到的指令,列出以下二個網址可以快速參考

vi 命令速查

使用 vi