Trace the ST related source code
預設OMAP4會把ST driver直接built in進kernel,另外GPS和FM driver則會compile成模組型式 :
CONFIG_TI_ST=y
CONFIG_ST_FM=m
CONFIG_ST_GPS=m
CONFIG_ST_GPS=m
GPS & FM driver path : kernel/drivers/staging/ti-st/
ST driver path : kernel/drivers/misc/ti-st
從上面知道,ST driver包含3個sub-moudules,所以這個目錄底下就有相對應的source code:
st_core.c st_kim.c st_ll.c
這三個檔案會被compile成叫st_drv.o....
UIM就有點小麻煩...因為TI在OMAP4 Blaze BSP裡面放了3個UIM code...
分別叫 "uim" , "uim-rfkill" , "uim-sysfs",該UIM的路徑是在mydroid/hardware/ti/wpan/ti_st/
之前知道UIM一支deamon,是系統boot時就開始run了,所以馬上就可以知道TI會在init.rc加入UIM service ...
service uim /system/bin/uim-sysfs
user root
group media bluetooth
oneshot
user root
group media bluetooth
oneshot
uim-sysfs加上oneshot,可以知道TI所使用的是 "uim-sysfs" ,從裡面的uim.c瞭解它會把st/bt/fm/gps等driver一個個insmod進去,利用lstat來檢查.ko是否存在。
因為現在是built-in,所以UIM並不會跑這段...
而是在更早之前,st_kim的init func是__init,所以在kernel一起來時就會register,而且還是register一個platform_drive的結構 :
static struct platform_driver kim_platform_driver = {.probe = kim_probe,.remove = kim_remove,.suspend = kim_suspend,.resume = kim_resume,.driver = {.name = "kim",.owner = THIS_MODULE,},};
出現了platform_driver結構,就一定會有想對應的platform_device結構來讓kernel assigned,所以可以在arch/arm/mach-omap2/board-4430sdp.c找到 :
struct ti_st_plat_data wilink_pdata = {.nshutdown_gpio = 55,.dev_name = BLUETOOTH_UART_DEV_NAME,.flow_cntrl = 1,.baud_rate = 3000000,.suspend = plat_kim_suspend,.resume = plat_kim_resume,};static struct platform_device wl128x_device = {.name = "kim",.id = -1,.dev.platform_data = &wilink_pdata,};static struct platform_device btwilink_device = {.name = "btwilink",.id = -1,};
nshutdown_gpio是BT/GPS/FM Enable pin...所以要改GPIO直接改這。(不太清楚TI怎麼去控制單一GPIO來防止3個device打架...還是真的3個只能開1個 !? 手邊沒平台...哎)
dev_name是UART deivce name...像是/dev/ttyxx之類的,所以要修改其它port,就修改這個定義。
接下來就是kim probe了,為每個device建構結構.....分配記憶體位址.....取得private data等等..
但這時就會去呼叫st_core,通知st_core initialization的時候到了....
int st_core_init(struct st_data_s **core_data){.....err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops);.....}
st_core 就最重要的就是註冊Line Discipline了。
什麼是Line Discipline ? 對 TTY device 的 I/O 動作,會經由 TTY core 送給 TTY driver,而資料往來於 TTY 與 TTY driver 的過程中...
可以這麼想,連結TTY Core和TTY driver資料往來的線,就叫Line Discipline。
Line Discipline是被設計成可以抽換的,例如,今天我想要讓這個TTY device是接收的資料是數據機而不要來自終端機,就把N_TTY改成N_PPP。
想要只接收藍芽的資料,就改成N_HCI....
簡言而之,就是Line Discipline會按照某個特殊的協議進行格式化,然後再送給TTY driver,讓TTY driver可以跟特定的硬體做溝通。
現在TI自己定義了一個N_TI_WL這個Line Discipline,所以porting時就要注意,要在kernel裡定義該Line Discipline....可以在kernel/include/linux/tty.h加入該定義。
接著st_kim會去request GPIO,並把GPIO設成輸出模式....
後面最後一道程序滿重要的,st_kim會create entries sysfs :
kim_gdata->kim_pdev = pdev;init_completion(&kim_gdata->kim_rcvd);init_completion(&kim_gdata->ldisc_installed);status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp);if (status) {pr_err("failed to create sysfs entries");return status;}/* copying platform data */strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN);kim_gdata->flow_cntrl = pdata->flow_cntrl;kim_gdata->baud_rate = pdata->baud_rate;pr_info("sysfs entries created\n");
其中uim_attr_grp的結構為 :
/* structures specific for sysfs entries */static struct kobj_attribute ldisc_install =__ATTR(install, 0444, (void *)show_install, NULL);static struct kobj_attribute uart_dev_name =__ATTR(dev_name, 0444, (void *)show_dev_name, NULL);static struct kobj_attribute uart_baud_rate =__ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL);static struct kobj_attribute uart_flow_cntrl =__ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL);static struct attribute *uim_attrs[] = {&ldisc_install.attr,&uart_dev_name.attr,&uart_baud_rate.attr,&uart_flow_cntrl.attr,NULL,};static struct attribute_group uim_attr_grp = {.attrs = uim_attrs,};
TI會去Create這些sysfs的最主要目的就是讓UIM能在user space透過該檔案系統去open在kernel space的st_core
到這裡st_kim和st_core的initialization就結束了,回頭繼續看UIM
UIM會去check剛剛的sysfs這些路徑有沒有建立成功 :
#define INSTALL_SYSFS_ENTRY "/sys/devices/platform/kim/install"
#define DEV_NAME_SYSFS "/sys/devices/platform/kim/dev_name"
#define BAUD_RATE_SYSFS "/sys/devices/platform/kim/baud_rate"
#define FLOW_CTRL_SYSFS "/sys/devices/platform/kim/flow_cntrl"
#define DEV_NAME_SYSFS "/sys/devices/platform/kim/dev_name"
#define BAUD_RATE_SYSFS "/sys/devices/platform/kim/baud_rate"
#define FLOW_CTRL_SYSFS "/sys/devices/platform/kim/flow_cntrl"
如果都有,而且BT/GPS/FM等相關的.ko和裝置節點都有存在的話,就會去create rfkill的路徑了 :
if (change_rfkill_perms() < 0) {
/* possible error condition */
UIM_ERR("rfkill not enabled in st_drv - BT on from UI might fail\n");
}
/* possible error condition */
UIM_ERR("rfkill not enabled in st_drv - BT on from UI might fail\n");
}
這樣一來,bluedroid (system/bluetooth/bluedroid/bluetooth.c)就可以透過rfkill來控制BT power。
然後UIM就去open st_core,讓st_core能成功install line discipline.
st_fd = open(INSTALL_SYSFS_ENTRY, O_RDONLY);if (st_fd < 0) {UIM_DBG("unable to open %s (%s)", INSTALL_SYSFS_ENTRY,strerror(errno));remove_modules();return -1;}
到這裡,UIM的任務就算暫時結束了 !
註 : hciattach的opation部份被改"-l"...它做的也只是print每個attach的結構,並沒做任何事...
所以hciattach的功用完全被UIM/KIM替代掉了,因為KIM己經把/dev/ttyx帶起來了 XD (如果
不用GPS的話...ST應該可以放一邊吧0.0?)
No comments:
Post a Comment