- A pattern for state machine
- A pattern for state machine II - SM framework
- A pattern for state machine III - SM framework
- An Sample Code for Syslogd - A log pattern with categorize, level and format
- An Sample Code for Syslogd - A log pattern with categorize, level and format II
- An Sample Code for threads control - A Wrap for service/threadstart/stop/periodical run
- An Sample Code for notification-chain
- A pattern for command table
2018年7月8日 星期日
Table Of Content for tag "Design Patterns with C "
2018年6月17日 星期日
Linux Kernel(15.3)- The Linux usage model for device tree data
這篇基本上就是"Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data的筆記
DT(Device Tree,或稱Open Firmware Device Tree)是一個資料結構(data structure)用於讓OS讀取硬體周邊訊息動態執行,因此OS就不用hard code硬體驅動。
所謂的"bindings"就是一組通用的DTS設定,用來描述其硬體,包含了data busses, interrupt lines, GPIO connections, and peripheral devices等等。
盡可能使用現有的binding來描述硬體,以最大限度地利用現有的代碼,但由於property和node名稱只是字串,因此通過定義新property和node可以輕鬆擴展現有binding。 不要沒做功課就自己建立新的binding,i2c busses就因為沒有先確認是否已經有人定義了相關的binding,就建立了新的binding,導致現在有兩套不相容的binding發生。
DT所做的只是提供一種language將硬體設定從device driver分離開來,如此可以透過傳入不同的DT給OS,以適應不同的硬體設定裝置. 進而減少一些重複的code。
DT在Linux底下有三個主要目的 1) platform identification, 2) runtime configuration, and 3) device population.
platform identification
首先kernel會先使用DT來辨識特定的機器,並且執行相關的初始化,比如ARM會在setup_arch()呼叫setup_machine_fdt()尋找適合的DT(比對DT root底下的"compatible" property。compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";上面的例子定義了"ti,omap3-beagleboard-xm",也宣稱相容"OMAP 3450 SOC"與"OMAP3"系列的SoC,你會注意到這樣的宣稱會從最具體的board到SoC的家族,關於compatible的值必須進行記錄說明其含義。
runtime configuration
一般來說,DT是firmware傳遞資料給kernel的唯一方法,PowerPC呼叫of_scan_flat_dt(early_init_dt_scan_root, NULL)執行early init,ARM則是呼叫mdesc = setup_machine_fdt(__atags_pointer)device population
在early configuration之後,kernel會用 unflatten_device_tree()將DT轉成device node tree,讓之後的init_early(), init_irq() and init_machine()等等使用,init_early()用於任何需要在啟動過程中儘早執行的設置,init_irq()用於設置中斷處理,而init_machine()負責建立Linux platform device,這裡主要呼叫of_platform_populate()建構platform device。之後的driver也是透過of_platform_populate()建構platform device。i2c_add_driver( ) @ i2c.h |-> i2c_register_driver() @i2c-core.c /* 將device_driver中的bus_type設成i2c_bus_type */ |--> driver_register() @driver.c |--> bus_add_driver() @bus.c /* 建立sysfs file node 與 attr */ |--> driver_attach() @dd.c |--> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) @bus.c |--> __driver_attach @dd.c |--> driver_match_device(drv, dev) @base.h |--> i2c_device_match() @i2c-core.c /*********************************************** 如果是device tree, 會透過 of_driver_match_device()去做匹配的動作 如果不是device tree就改用 i2c_match_id()去完成匹配的動作 ***************************************************/ /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; |--> driver_probe_device() @dd.c /*如果匹配成功, 接下來就要準備 call driver 中的 probe function*/ |--> really_probe() @dd.c |--> i2c_device_probe() @i2c-core.c |--> rt5627_i2c_probe() @rt5627.c from http://janbarry0914.blogspot.com/2014/08/device-tree-i2c-device-driver-match.html
-
參考資料:
- "Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data
- 在device tree的架構下, i2c device 與 driver 是如何 match
標籤:
Linux - kernel
2018年4月21日 星期六
A pattern for state machine II - SM framework
我將A pattern for state machine改寫成framework形式,使用者需要先使用sm_alloc()分配一個struct sm,再使用sm_fp_reg()將每個state的callback function掛上,最後有event要執行時,只要呼叫sm_run(sm, new_event)即可。
state的callback function的撰寫邏輯,大致與之前一樣,return下一個state,進入下一個state要做的動作,我都用do_state_x()包起來,而do_state_x()會return 該state。
sm.h
#ifndef SM_H #define SM_H struct sm { int cur_state; int prv_event; void *v; }; /** * state function * @return next state */ typedef int (*sm_st_fp)(struct sm *sm, int new_event); struct sm *sm_alloc(int num_of_state); int sm_run(struct sm *s, int new_event); int sm_fp_reg(struct sm *s, int state, sm_st_fp fp); #endif
sm.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "sm.h" struct _sm { struct sm s; int num_of_st; sm_st_fp fp[0]; }; struct sm *sm_alloc(int num_of_state) { struct _sm *_s; int sz; sz = sizeof(struct _sm) + sizeof(sm_st_fp) * num_of_state; _s = (struct _sm*) malloc(sz); if (!_s) { return NULL; } memset(_s, 0, sz); _s->num_of_st = num_of_state; return (struct sm*)_s; } int sm_run(struct sm *s, int new_event) { struct _sm *_s = (struct _sm*) s; if (s->cur_state > _s->num_of_st) { printf("out of st\n"); return -1; } if (!_s->fp[s->cur_state]) { printf("null fp\n"); return -1; } s->cur_state = _s->fp[s->cur_state](s, new_event); s->prv_event = new_event; return 0; } int sm_fp_reg(struct sm *s, int state, sm_st_fp fp) { struct _sm *_s = (struct _sm*) s; if (state > _s->num_of_st) { printf("out of st\n"); return -1; } _s->fp[state] = fp; return 0; }
main.c
因為是framework,所以,我把state/event都拉出來, 因此每個State Machine都應該定義自己的event與state。 enum state { STATE_1, STATE_2, STATE_3, STATE_4, }; enum event { E1 = 1, E2, E3, E4, }; int main(int argc, char *argv[]) { struct sm *s; char ch; s = sm_alloc(3); if (!s) { return -1; } sm_fp_reg(s, STATE_1, in_state_1); sm_fp_reg(s, STATE_2, in_state_2); sm_fp_reg(s, STATE_3, in_state_3); sm_fp_reg(s, STATE_4, in_state_4); while (1) { while (((ch = getc(stdin)) == '\n') || (ch < '0') || (ch > '4')); sm_run(s, ch - '0'); } return 0; }
refine callback function
因為是framework,所以,callback function的定義要改成return int。 int do_s1(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_1; } int do_s2(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_2; } int do_s3(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_3; } int do_s4(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_4; } int in_state_1(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E2: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do nothing\n"); return STATE_1; } } int in_state_2(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E3: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do s2 again\n"); return do_s2(); // do s2 again } } int in_state_3(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E2: printf("change to S4\n"); return do_s4(); default: printf("keep the same STATE && do nothing\n"); return STATE_3; } } int in_state_4(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E3: printf("change to S1\n"); return do_s1(); default: printf("keep the same STATE && do again\n"); return do_s4(); } }
訂閱:
文章 (Atom)
熱門文章
-
轉自 http://www.wretch.cc/blog/redsonoma/14021073 基本概念: 1> tty(終端設備的統稱): tty一詞源於Teletypes,或者teletypewriters,原來指的是電傳打字機,是通過串行線用打印機鍵盤通過閱...
-
Work queue提供一個interface,讓使用者輕易的建立kernel thread並且將work綁在這個kernel thread上面,如下圖[1]所示。 由於work queue是建立一個kernel thread來執行,所以是在process context...
-
(V)將介紹file operations中的ioctl。ioctl的prototype為: int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ...
-
這兩天電腦的word忽然都不能存檔,即便是另存新檔也不行,最後都只能放棄修改檔案,即便重新安裝過或者更新成2007也都不能存檔,最後就乖乖的google一下,原來是暫存的資料夾不存在,按照以下方式就可以解決了。 資料來源: word 2003不能存檔問題 編輯機碼的(reg...
-
System Call在HW和user space提供一層抽象層,主要目的有: 為user space提供硬體抽象層。比如,讀取檔案時,不用管檔案所在的媒體類型與檔案儲存類型。 System call能確保系統的安全與穩定。避免user space的無意或惡意的破壞。 ...
-
在kernel中建立thread可以使用kthread_create(),建立一個task,然後在調用wake_up_process(task)讓task真正的運行,如果要kill一個kthread可以使用kthread_stop()。 在kernel中,將kthread_cr...
-
Linux module練習手札I紀錄如何撰寫一個簡單的module,並且編輯它,以及load和unload一個module。 write a module #include <linux/init.h> #include <linux/module.h...
-
幾乎任何使用 TCP,UDP或UNIX-domain socket的動作都可以用nc來達成,常見的功能如。 simple TCP proxies shell-script based HTTP clients and servers network daemon testi...
-
很多人心中都有過一個問題 What is the difference between Platform driver and normal device driver? ,簡單的來說Platform devices就non-discoverable,也就是device本身沒辦法...
-
組成元件 要能正確顯示資料,必須包含資料倉儲(Store),資料欄位的定義(ColumnModel)。 首先我們先定義資料欄位: var cm = new Ext.grid.ColumnModel({ {header: 'Name', dataIndex...