2016/12/19

rtl8188eu ..

有人很好新 build 好了所有 kernel 版本的 ko..

...猜是從 這裡 build 的。

現在是 4.4.34+, build 930
所以 download path 是...https://dl.dropboxusercontent.com/u/80256631/8188eu-4.4.34-930.tar.gz
糟糕,dropbox public folder 功能要關了...


很麻煩。這個 wifi chip。

ap mode, trial1:
wifi dongle as access point, soft ap 8188eu on linux

這個是 source,要拉下來 make, make install
還好也有附 uninstall:
install:
        install -p -m 644 8188eu.ko  $(MODDESTDIR)
        @if [ -a /lib/modules/$(KVER)/kernel/drivers/staging/rtl8188eu/r8188eu.ko ] ; then modprobe -r r8188eu; fi;
        @echo "blacklist r8188eu" > /etc/modprobe.d/50-8188eu.conf
        cp rtl8188eufw.bin /lib/firmware/.
        /sbin/depmod -a ${KVER}
        mkdir -p /lib/firmware/rtlwifi
        cp rtl8188eufw.bin /lib/firmware/rtlwifi/.

uninstall:
        rm -f $(MODDESTDIR)/8188eu.ko
        /sbin/depmod -a ${KVER}
        @rm /etc/modprobe.d/50-8188eu.conf
build 好的安裝路徑是: /lib/modules/$(KVER)/kernel/drivers/net/wireless

2016/12/12

流水帳:wifi display...

WifiDisplaySetting.java: DEBUG=true
onCreate 後就啟動了...WifiP2pManager.initialize( )

framework/base/services/java/com/android/server/display/DisplayManagerService.java: DEBUG=true;
framework/base/services/java/com/android/server/display/WifiDisplayAdapter.java: DEBUG=true;
framework/base/services/java/com/android/server/display/WifiDisplayController.java: DEBUG=true

真正connect 的流程就在 WifiDisplayController.java: updateConnection()

大概就是..先 disconnect from the old one.
然後再call WifiP2pManager.connect( )
連線完成 call WifiP2pManager.setMiracastMode( )
然後叫 RemoteDispkay.listen( ) 這個 P2p connection...

有點跑掉...

framework/base/java/android/net/wifi/WifiNative.java: DBG=true;
doCommand : wifi_command
libhardware_legacy

wpa_ctrl_request( ) : TAG WifiHW
在 wpa_supplicant_8

是在 wpa_supplicant_8/wpa_supplicant/Android.mk
src/common/wpa_ctrl.c
有兩個 implement, depend on CTRL_IFACE_SOCKET 或是 CONFIG_CTRL_IFACE_NAMED_PIPE
因為 IFACE_UNIX, 所以是 IFACE_SOCKET
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
                     char *reply, size_t *reply_len,
                     void (*msg_cb)(char *msg, size_t len))
..
wpa_ctrl structure 包含一個 socket.是 溝通的界面。
在 libhardware_legacy/wifi/wifi.c (wpa_supplicant 使用者) 中 是先呼叫:
wifi_connect_on_socket_path(const char *path)
{
   ctrl_conn = wpa_ctrl_open(path);
取得 connect socket
caller 是..
/* Establishes the control and monitor socket connections on the interface */
int wifi_connect_to_supplicant()
{
    static char path[PATH_MAX];

    if (access(IFACE_DIR, F_OK) == 0) {
        snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
    } else {
        snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
    }
    return wifi_connect_on_socket_path(path);
}
其中..
static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
property_get("wifi.interface",primary_iface,..);
wifi.interface 定義在 system.prop : wlan0

完成後,用 android 的 system control:
    property_set("ctl.start", supplicant_name);
啟動 wpa_supplicant service.
根據 P2P 有沒有啟動, ctrl.start 的 service 不一樣:
static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
static const char SUPP_PROP_NAME[]      = "init.svc.wpa_supplicant";
static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
static const char P2P_PROP_NAME[]       = "init.svc.p2p_supplicant";

找一下 libwpa_client..
其中只有:
  • src/common/wpa_ctrl.c
  • src/utils/os_unix.c

在 Android.mk:
include $(CLEAR_VARS)
LOCAL_MODULE = libwpa_client
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_COPY_HEADERS_TO := libwpa_client
LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
include $(BUILD_SHARED_LIBRARY)
所以會把 wpa_ctrl.h copy 到 out folder 的 include/libwpa_client/ 下面。

所以有使用到的 project...
./frameworks/base/core/jni/Android.mk: libwpa_client \
./hardware/libhardware_legacy/wifi/Android.mk:LOCAL_SHARED_LIBRARIES += libnetutils libwpa_client
就 include "libwpa_client/wpa_ctrl.h"

framework/.../jni call 到 libhardware_legacy 的 wificommand.
沒有直接 call libwpa_client 的 api

所以所有call libwpa_client 的應該都是經過 libhardware_legacy

2016/11/29

bookmark: wifi display /Miracast sink


然後還有這篇,被 刪掉的 blog:
要改的部份:

1. #include <gui/SurfaceTextureClient.h> ==> #include <gui/Surface.h>
2. ISurfaceTexture ===> IGraphicBufferProducer

3. IMediaPlayerService    mPlayer = service->create(getpid(), mPlayerClient, 0); ==>
    mPlayer = service->create( mPlayerClient, 0);

4. sp<ISurfaceTexture> getSurfaceTexture(); ==>;    sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;

比較仔細的是這一篇:https://github.com/kensuke/How-to-Miracast-on-AOSP/wiki/Android-4.4
但是 build 會出現:
frameworks/av/media/libstagefright/wifi-display/wfd.cpp:348: error: undefined reference to 
'android::WifiDisplaySink::WifiDisplaySink(unsigned int, 
                                           android::sp<android::ANetworkSession> const&, 
                                           android::sp<android::IGraphicBufferProducer> const&, 
                                           android::sp<android::AMessage> const&)'

2016/11/16

wifi worklog 隨便記

init.rc:
service p2p_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant \
    -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
    -I/system/etc/wifi/wpa_supplicant_overlay.conf -N \
    -ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf \
    -I/system/etc/wifi/p2p_supplicant_overlay.conf \
    -O/data/misc/wifi/sockets \
    -puse_p2p_group_interface=1 \
    -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
    socket wpa_wlan0 dgram 660 wifi wifi
    class main
    disabled
    oneshot

然後在 device/.../ 下有 wifi_bt_common.mk

2016/11/14

eMMC 的 hardware rese pin - RST_n

JESD84-C44.pdf
Embedded MultiMediaCard
(e•MMC) Mechanical Standard,
with Optional Reset Signal

p.7:
Reset :RST_n 
Reset signal is used for host resetting device, moving the device to pre-idle state.
By default, the RST_n signal is temporary disabled in device. Host need to set bit[0:1] in
the extended CSD register [162] to 0x1 to enable this functionality before the host uses.

About Extended CSD Register:
The 512 bytes long Extended CSD register defines the Device properties and selected modes.
The Higher 320 bytes are the Properties segment, which defines the Device capabilities and cannot be
modified by the host. 
The lower 192 bytes are the Modes segment, which defines the configuration the
Device is working in. These modes can be changed by the host by means of the SWITCH command.

更新版:EMMC_JESD84-A441
p.164:
RST_n_FUNCTION [162]

For backward compatibility reason, RST_n signal is temporary disabled in device by default. Host may
need to set the signal as either permanently enable or permanently disable before it uses the card.
Bit[7:2]: Reserved
Bit[1:0]: RST_n_ENABLE (Reable and Writable once)
0x0: RST_n signal is temporarily disabled (default)
0x1: RST_n signal is permanently enabled
0x2: RST_n signal is permanently disabled
0x3: Reserved

By default, RST_n_ENABLE is set to 0x0, which is RST_n is temporarily disabled. Host can change the
value to either 0x1 (permanently enabled) or 0x2 (permanently disabled). Once host sets the value to either
one, the value can not be changed again.

Once host sets RST_n_ENABLE bits to 0x2 (permanently disabled), the card will not accept the input of
RST_n signal permanently.
During the disable period, the card has to take care that any state of RST_n (high, low and floating) will
not cause any issue (i.e. mal function and high leakage current in the input buffer) in the device.
When RST_n_ENABLE is set to 0x1 (permanently enabled), the card accepts the input of RST_n permanently.
Host can not change the bits back to the disabled values. Also, when host set RST_n_ENABLE to
0x1, the card must not start resetting internal circuits by triggering the register bit change. Internal reset
sequence must be triggered by RST_n rising edge but not by the register change.
Since card does not have any internal pull up or pull down resistor on RST_n terminal, host has to pull up
or down RST_n to prevent the input circuits from flowing unnecessary leakage current when RST_n is
enabled

http://www.mt-system.ru/sites/default/files/klmxgxge4a-x001mmc4_41_2ynm_based_emmc1_1.pdf
p.22
Extend CSD register 162 的 properties 是:R/W: One time programmable and readable

一樣,在 micross eMMC datasheet 也有。
說得更仔細, ECSD 的幾種 cell :
R  Read-only
R/W  One-time programmable and readable
R/W/E  Multiple writable with the value kept after a power cycle, assertion of the RST_n signal, and any
  CMD0 reset, and readable
R/W/C_P  Writable after the value is cleared by a power cycle and assertion of the RST_n signal (the
  value not cleared by CMD0 reset) and readable
R/W/E_P  Multiple writable with the value reset after a power cycle, assertion of the RST_n signal, and
  any CMD0 reset, and readable
W/E_P  Multiple writable with the value reset after power cycle, assertion of the RST_n signal, and any
  CMD0 reset, and not readable

所以 chip 的 ECSD 162 一但 enable 後,就沒辦法 disable 了。
--- 和 A441 說的不一樣?


Software 的 reset 是... CMD0
ref: SD Physical Layer Spec
p.24:
4.2.1 Card Reset
The command GO_IDLE_STATE (CMD0) is the software reset command and sets each card into Idle
State regardless of the current card state. Cards in Inactive State are not affected by this command.
After power-on by the host, all cards are in Idle State, including the cards that have been in Inactive
State before.
After power-on or CMD0, all cards’ CMD lines are in input mode, waiting for start bit of the next command.
The cards are initialized with a default relative card address (RCA=0x0000) and with a default
driver stage register setting (lowest speed, highest driving current capability). 

2016/10/26

banana pi -- jessie

很可惜的板子。
以前的 banana pi 只要 800,那時候一堆人用得很愉快。
後來,不知怎麼,所有的賣家都改成賣 1200 以上。
可惜,雖然只差 400
但是,1200 等級得的板子,大多效能,功能都比 banana pi 好很多。
-- raspberry pi 3. orange pi, ... etc

所以,他就失去了優勢,漸漸的沒落下去。
現在好像沒人用了。


用的是 banaian, 下載最新版就是 jessie 了。
燒錄一樣,解開 zip 後直接 dd

uart console TX.RX.GND 在版上gpio 旁邊有印
開機,在 ipv6 那版會卡一下,就跳出 login prompt
username: root
password: pi
開機完會有提示要你 run banaian-config
回答問題,把 root partition 加大。
timezone 選 Taipei
重開機,OK

看一下 sources.list, 竟然是標準的 debian.org
加入 proxy:
/etc/apt/apt.conf:

Acquire::http::Proxy "http://192.168.100.132:3128"
然後就可以 apt-get update 了..
出現 kernel 需要更新: linux-image-3.4-banaian


設定 ntp ... ref: ntpdate

run banania-update
這會用到 curl ,用 script run 不會 reference 環境變數,
所以只好修改 banania-update 這個 script, 在 curl 的命令中加入 -x option
ref: http://www.cyberciti.biz/faq/linux-unix-curl-command-with-proxy-username-password-http-options/
之後就可以 run 了...


repository 要放在 usb disk 上,所以要 mount usb disk 到 /home/git/ 下。
owner 要是 git
所以 format 完 usb disk 後,要先 mount 近來,然後去,,
 sudo chown git:git .
這樣 mount point 就會是 git:git 了。
ref:http://r40eubuntu.blogspot.tw/2014/11/mount-partition-and-owner.html


wifi

ref: http://r40eubuntu.blogspot.tw/2015/05/wifi-on-banana-pi-tp-link-tl-wn725n.html
插上,改一下 /etc/network/interfaces 就可以了。

routing table 會依照 network interface 啟動的順序決定 default gw 和 dns (resolv.conf)
要用 wlan 做 default gw 和 dns
所以..
先插著 wlan 開機,OK後,再插上 eth0
很奇怪,有時候 eth0 dhcp 部會正常動作,所以要手動 ifdown, ifup 一次。
之後, resolve.conf 會被改掉 (eth0)
所以要改回來...
nameserver 172.20.10.1

ap mode:

使用 hostapd 跟 dnsmasq 了。
/etc/hostapd/hostapd.conf
設定 SSID, password, wlan interface

/etc/dnsmasq.conf
設定 dnsmasq 的 ip range

然後就是 iptable
和 interfaces 要把 wlan1 設 static ip.

2016/10/7

FIQ_DEBUGGER console

arm kernel 有一個 option 是 CONFIG_FIQ_DEBUGGER_CONSOLE
如果開啟的話,就會讓 kernel 內部的 debug console 功能起動。
再開啟一個 CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE 的話,就會用 debug UART 作為 kernel fiq debugger 的界面。

所以 kernel console 一邊作為 shell console 用,另一方面,也被作為 kernel debugger console用。

要讓 kernel debugger console 啟動,送出 Break 鍵。
用 Putty 的話,就是設定為 VT100+ 模式。
然後輸入 Ctrl-Break 就可以。,
console 會顯示:
#fiq debugger mode
debug >
這樣就進入 kernel debugger mode 了,

輸入 help 可以看 支援的 command
要回到 console mode 就輸入 console 就可以。

在 kernel debug mode 時,系統一樣正常運作。

minicom 要輸入 brk 的話,是 'Ctrl-A F'
tera term 的話,在 control 有一個 send break

2016/9/23

repo sync fail: unable to read sha1 file of ...

error: unable to read sha1 file of gradle-1.4-all.zip (25ee925013e572af4735884757af1e2228c103b0)
Traceback (most recent call last):
  File "/home/charles-chang/px3sdk_raw/.repo/repo/main.py", line 500, in 
    _Main(sys.argv[1:])
  File "/home/charles-chang/px3sdk_raw/.repo/repo/main.py", line 476, in _Main
    result = repo._Run(argv) or 0
  File "/home/charles-chang/px3sdk_raw/.repo/repo/main.py", line 155, in _Run
    result = cmd.Execute(copts, cargs)
  File "/home/charles-chang/px3sdk_raw/.repo/repo/subcmds/sync.py", line 675, in Execute
    project.Sync_LocalHalf(syncbuf)
  File "/home/charles-chang/px3sdk_raw/.repo/repo/project.py", line 1170, in Sync_LocalHalf
    self._InitWorkTree()
  File "/home/charles-chang/px3sdk_raw/.repo/repo/project.py", line 2230, in _InitWorkTree
    raise GitError("cannot initialize work tree")
error.GitError: cannot initialize work tree
可能是因為常常Ctrl-C 來中斷/resume repo sync , 所以最後 repo sync checkout 的時候, git 內容有錯了。

無稐怎樣 gc, fsck, 都沒辦法修復。
單獨,參考 manifest.xml 的 gradle project 去 clone 出來,checkout 也 OK

所以,只好...到 .repo/ 下 search 所以 gradl*:
有關的是:
./projects/tools/external/gradle.git
./project-objects/platform/tools/external/gradle.git

把這兩個刪掉。
整個 bsp 也刪掉,留下 .repo 這個 folder

然後再做 repo sync..就 OK了

2016/9/22

ssh config : 不同 server 給不同的 key, ignore key change

ssh 就是自己產生一對 key, 把public 的送給別人,讓別人可以用 你給的key 來認證你。

所以,也可以產生很多對key, 然後一個 server 給一個,每個 server 都給不同的 pub key
當然,這樣就要小心,在連線的時候,要拿對key
ssh -i id_rsa_therightone servername

這樣很麻煩,所以 ssh 就給一個 config, 讓你可以寫 key- sever 的對應。
這樣 ssh 就會自動照這格 config 拿正確的key 來連。

.ssh/config 的內容:
Host my3rd
    HostName the3.my.com
    user  charles
    IdentityFile ~/.ssh/id_rsa_key1

Host my4th
    HostName the4.my.com
    user checko
    IdentityFile ~/.ssh/id_rsa_key4

另外,如果 ssh 連線的 server 不在 .ssh/config 中,
ssh 也沒有加上 -i (指定 key file) 的選項。
ssh 就會用 .ssh/id_rsa 來連。



這個 config 很有趣,好像只會認得 Host,
以上面的例子來說..
ssh my3rd
會正確的使用 id_rsa_key1

但是用server 真正的名子:
ssh the3.my.com
就不會用 id_rsa_key4 了。

我猜這是為了一個 server 用不同user name login..
這樣才可以用 Host 來區分,

如果是 embedded system, 一直更換 key 的情況,ssh 連線出現:
Hostkey verification failed
M
可以在 config 加入:
$ cat .ssh/config
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
這樣都不會檢查了...

ssh-agent .真的就是一個agent

為了安全,用 ssh private, public key...
然後key還加上密碼。

這樣登入雖然安全了,但是又恢復到每次登入都要輸入密碼。
所以就出現 ssh-agent, 會聽你的通訊,在要輸入密碼的時候,自動幫你輸入密碼。
--- 這樣幫 key 加上密碼不就沒意義了?

所以,啟動 ssh-agent 邦你工作的時候,ssh-agent 會需要你輸入密碼,這樣他才能幫你。
所以:
ssh-add : 加入 key, 要 ssh-agent 幫你傳key
ssh-add 會對每一個 key, 如果有須要密碼的,請妳輸入密碼,他會記下來,以後好幫你輸入。

這樣就改成...只要啟動 ssh-agent 時輸入一次密碼就好,避免掉每次都需要輸入的問題。


2016/9/6

reboot ..

最後 reset 是...arm/arm/mach-kk40/reset.c
static void kk40_arch_reset(char mode, const char *cmd)
{
        u32 boot_flag = 0;
        u32 boot_mode = BOOT_MODE_REBOOT;

        if (cmd) {
                if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader"))
                        boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER;
                else if(!strcmp(cmd, "recovery"))
                        boot_flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER;
                else if (!strcmp(cmd, "charge"))
                        boot_mode = BOOT_MODE_CHARGE;
        } else {
                if (is_panic)
                        boot_mode = BOOT_MODE_PANIC;
        }
#ifndef RK30_PMU_BASE
        writel_relaxed(boot_flag, RK30_GRF_BASE + GRF_OS_REG4); // for loader
        writel_relaxed(boot_mode, RK30_GRF_BASE + GRF_OS_REG5); // for linux
#else
        writel_relaxed(boot_flag, RK30_PMU_BASE + PMU_SYS_REG0);        // for loader
        writel_relaxed(boot_mode, RK30_PMU_BASE + PMU_SYS_REG1);        // for linux
#endif
 ....

所以會reboot flag 和 mode 會被寫入 cpu register...

2016/8/23

fuchsia test build...

ref: https://fuchsia.googlesource.com/manifest/+/master/README.md

因為還在初期的開發過程,所以每天 builod 的狀況可能會不一樣。

在 debian jessie 上 build.
一開始 go language 得的版本有問題。
缺了 UnsetEvn 和 StringCompare 這兩個 function
jessie 是 1.3, 測試 1.4 還是不夠,最後用 1.5 才 OK

go 環境很簡單,就 到 go 網站 download 安裝包,解開,follow READE 設定 GOROOT path 和 update PATH 就可以呼叫到正確的 go 版本。
然後繼續 follow 說明...

出現 native_viewport 不認識 MX_DISPLAY_FORMAT_RGB_565
發現是新版本的 display.h 變更了 constant 的名子,改叫 MX_PIXEL_FORMAT_RGB_565. 所以全部修改。



上面好像是 user program.
下面這個好像才是 OS.... https://fuchsia.googlesource.com/magenta/+/HEAD/docs/getting_started.md

2016/8/16

fragement

fragement 可以視為 view 元件的一個擴展。
在 layout 的 xml 中可以擺放 fragment 元件。
然後再為 fragment 元件寫 layout, action handler

所以可以視為 "可以自訂內容的 view 元件"

既然是由 programmer 自己寫的元件,所以在 layout 中擺放時,fragment 區段就有一些規定,
像 name 就是實做那個 fragment 的 full class name

fragment 的 life cycle 跟一般 activity 有點類似。
也有自己的 layout

所以主要的 activity 把 自己的 layout view (包含 fragment的layout xml) 設定完畢後。
android 系統自然會知道 layout 內容,一一呼叫起對應的 fragment class

2016/8/15

android application profiling with Android Device Monitor

tools -- android -- android device monitor

Device tab 會列出所有正在 run 的 process
選一下要 monitor 的 process
按下device tab 上的一個有紅點的 icon (Start Method Profiling)
出現 "Profiling Options"
選 Trace base profiling -- 因為想知道是那一個 function 花時間。
按下去以後,就開始 monitor 了,所以要趕快去操作 app,
花時間的部份都操作完後,案一下 device tab 剛剛那個變成黑點的紅點 icon (stop method profiling)

device tab 右邊會出現 ddmsXXXXXXX 的 profiling 結果。

上面是時間條,下面是 function 的顏色和總共花的時間。
找一個長的按下去就會繼續看該 function 裡面花的匙間,
然後找出時間最長的...
repeat...


  • incl Cpu Time(%): Include caller & self
  • Excl Cpu Time(%):
  • Incl Real Time:
  • Excl Real Time:
  • Calls + Recur Calls / Total:function执行的次数,Call表示function call的次数,Recur Call表示recursive call 的次數
  • Cpu Time / Call:每次执行函数所用的cpu time。
  • Real Time / Call: 同上

systrace 好像更強

2016/8/3

implicit declaration of function 'strict_strtoul

3.x 的 driver code 拿到 4.x build 出現..
 error: implicit declaration of function 'strict_strtoul' [-Werror=implicit-function-declaration]


然後kernel source 竟然找不到 strict_strtoul

然後..http://dpdk.org/dev/patchwork/patch/1911/
strict_strtoul() was just a redefinition of kstrtoul() for a long
time. From kernel version of 3.18, strict_strtoul() will not be
defined at all. A compile time kernel version check is needed to
decide which function or macro can be used for a specific version
of kernel.

也就說..直接用 kstrtoul 就好了。

2016/7/28

multi window / app in Android

ref: https://github.com/darkenk/OkienkaTest
這一個人寫了一個 launcher app. 可以開啟多個 app, 變成 multi window

但是在 Android N 以後,好像就native support multi window 了:
https://developer.android.com/preview/features/multi-window.html?hl=zh-tw

然後 XDA 說,android 6 的 userdebug build, 開啟 developer mode, 就會多一個 multi window mode 的選項。
http://forum.xda-developers.com/android/general/guide-enable-multi-window-mode-android-t3121483

2016/7/26

vi : set tab to 4 spaces and replace all

很麻煩,有些source code tab 用 4 個 space.
而不是 tab

所以...ref http://vim.wikia.com/wiki/Converting_tabs_to_spaces

:set tabstop=4 shiftwidth=4 expandtab
一行做完。

如果要 vi 修改整個 source...
再下..
:set retab


2016/7/25

tinycap : support capture to stdout

https://github.com/tinyalsa/tinyalsa/pull/31/commits/5741cc04a4b20fd0997c8de6808c3a2557291d0d
這個人把 tinycap 加上從 stdout 輸出的功能。

大概就是,, stdout 時..
  • 不需要做 file header
  • 不能 print message

所以,增加了兩個 flag:
  • no_header : 不要做 file header
  • prinfo : print message

2016/7/21

thread--event--
  if (connect_change)
        hub_port_connect_change( );

hub_port_connect_change--hub_port_init

2016/7/18

static inline int hub_is_superspeed(struct usb_device *hdev)
{
        return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
}

ch11.h:
/*
 * Hub Device descriptor
 * USB Hub class device protocols
 */

#define USB_HUB_PR_FS           0 /* Full speed hub */
#define USB_HUB_PR_HS_NO_TT     0 /* Hi-speed hub without TT */
#define USB_HUB_PR_HS_SINGLE_TT 1 /* Hi-speed hub with single TT */
#define USB_HUB_PR_HS_MULTI_TT  2 /* Hi-speed hub with multiple TT */
#define USB_HUB_PR_SS           3 /* Super speed hub */


ch9.h:
hubdev->state
enum usb_device_state {
        /* NOTATTACHED isn't in the USB spec, and this state acts
         * the same as ATTACHED ... but it's clearer this way.
         */
        USB_STATE_NOTATTACHED = 0,

        /* chapter 9 and authentication (wireless) device states */
        USB_STATE_ATTACHED,
        USB_STATE_POWERED,                      /* wired */
        USB_STATE_RECONNECTING,                 /* auth */
        USB_STATE_UNAUTHENTICATED,              /* auth */
        USB_STATE_DEFAULT,                      /* limited function */
        USB_STATE_ADDRESS,
        USB_STATE_CONFIGURED,                   /* most functions */

        USB_STATE_SUSPENDED

        /* NOTE:  there are actually four different SUSPENDED
         * states, returning to POWERED, DEFAULT, ADDRESS, or
         * CONFIGURED respectively when SOF tokens flow again.
         * At this level there's no difference between L1 and L2
         * suspend states.  (L2 being original USB 1.1 suspend.)
         */
};


2016/7/11

buildroot 好像持續開發中,所以command 有變化,google 到的 command 跟文章的時間有關。

只要rebuild 一個 package 的話,就用:
$ make <pkg>-rebuild


至於有哪些package name 可以用...我到現在還沒找到...
https://www.quora.com/How-can-I-trigger-the-rebuild-of-Linux-kernel-in-Buildroot

linux kernel 的話好像是 ...
make linux-rebuild

2016/7/6

buildroot for iMX6

ref:
就先 clone buildroot 下來...
.. 姊果 clone 不下來,所以只好download tar 下來解。

用.. 2015.05 的版本。
解開後,用 imx6 sabreauto 的config:
find 一下 freescale_*_defconfig
$ make freescale_imx6dlsabreauto_defconfig
$ make


make 之前可以用 make menuconfig 看一下配置。kernel , uboot 版本之類。
make 後,就會去 download source, patch..
因為有過 proxy, 所以有些 git:// target 會 fetch failed.
這時候中斷,接上 no proxy 的 network, 再繼續 make
然後fetch tar ball 又要過 proxy,, 又接上 ethernet...
反覆..終於 build OK

build 好在: out/images

然後就 follow reference.
這個SD partition 配置是:
  • boot region : iMX 從 1024 開始 load bin, 這區域要放 uboot
  • vfat partition : 第一個 partition, 要是 fat, 裡面是 uImage 和 dtb
  • root fs : 第二個 partition, 是 EXT4, 就是 image: rootfs 的內容

燒錄的動作略有不同。
這個 buildroot build 出來的 uboot 是 u-boot.imx, 不是 bin
所以直接 dd 到 1024 的地方...
$ sudo dd if=u-boot.imx of=/dev/sdb bs=1k seek=1
這樣開機已經可以看到 uboot message... 當然,boot to kernel failed

接著 formate /dev/sdb1 為 vfat, copy uImage 和 imx6dl-sabreauto.dtb 過去。
這時候開機,已經可以看到開進 kernel,, 當然,開到一半就 kernel trap.. 因為 VFS: Unable to mount rootfs on unknown-block(179,2)

把 sdb2 format 成 ext4 後..
照著..
# mount /dev/ /mnt
# tar -C /mnt -xvf output/images/rootfs.tar
# umount /mnt
之後,一樣, Unable to mount,,
但是在 bootlog 中明明有看到..mmcblk0p2

..結果是... hardware 不一樣...
因為用 microSD, 所以沒有做 write protect detection, 所以 kernel 認為...
mmcblk0: mmc0:59b4 USD 7,51GiB (ro)
是 readonly,, 所以不能當作 root..

2016/6/30

註冊要成功,看:sound/soc/soc-core.c : snd_soc_register_card(struct snd_soc_card *)
裡面會檢查 card 裡 dai_link 的內容...

  • codec_name 和 codec_of_node 一定要有一格有值,但是不能都有值
  • codec_dai_name 必須要有值。
  • platform_name 和 platform_of_node 不可以兩個都有值,但是可以都是 null
  • cpu_dai_name, cpu_name, cpu_of_node 要有一個有值

card
link = card-&dai_link[i];

link->codec_name
link->codec_of_node

link->codec_dai_name

link->platform_name
link->cpu_of_node

可以在 snd_soc_register_card 里 print dai_link 的內容檢查。

2016/6/28

driver init

static struct platform_driver imx_wm8962_driver = {
        .driver = {
                .name = "imx-wm8962",
                .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
                .of_match_table = imx_wm8962_dt_ids,
        },
        .probe = imx_wm8962_probe,
        .remove = imx_wm8962_remove,
};
module_platform_driver(imx_wm8962_driver);


module_platform_driver(imx_wm8962_drvier) 展開:(platform_device.h)
#define module_platform_driver(__platform_driver) \
        module_driver(__platform_driver, platform_driver_register, \
                        platform_driver_unregister)
所以
module_driver(imx_wm8962_driver, platform_driver_register, platform_driver_unregister)


module_driver 再展開..(device.h)
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
        return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
        __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

所以..

static int __init imx_wm8962_driver_init(void)
{
    return platform_driver_register( &(imx_wm8962_driver) );
}
module_init(imx_wm8962_driver_init)'

static void __exit imx_wm8962_driver_exit(void)
{
    platform_driver_unregister(&(imx_wm8962_driver));
}
module_exit(imx_wm8962_exit);


最後的 macro : module_init, module_exit: (init.h)
#define module_init(x)  __initcall(x);
#define module_exit(x)  __exitcall(x);

然後

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn) \
        static exitcall_t __exitcall_##fn __exit_call = fn

所以要去看 platform_driver_register ( platform.c )

int platform_driver_register(struct platform_driver *drv)
{
        printk("%s -- %pS\n",__func__,__builtin_return_address(0));
        drv->driver.bus = &platform_bus_type;
        if (drv->probe)
                drv->driver.probe = platform_drv_probe;
        if (drv->remove)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;

        return driver_register(&drv->driver);
}
他把 依照宣告的 platform_driver 變數內容,設定好 driver.driver 的資料,call driver_register( )
-- 其中 platform_drv_probe/remove/shutdown 也都在這個 source file 中。

driver_register -- bus_add_driver -- driver__attach -- driver_probe_device -- really_probe



bus: 'platform': driver_probe_device: matched device sound-wm8962.33 with driver imx-wm8962


log:
do_one_initcall imx_wm8962_driver_init
platform_driver_register
bus_add_driver
...
static char *initcall_level_names[] __initdata = {
        "early",
        "core",
        "postcore",
        "arch",
        "subsys",
        "fs",
        "device",
        "late",
};


include..
#define __define_initcall(fn, id) \
        static initcall_t __initcall_##fn##id __used \
        __attribute__((__section__(".initcall" #id ".init"))) = fn

/*
 * Early initcalls run before initializing SMP.
 *
 * Only for built-in code, not modules.
 */
#define early_initcall(fn)              __define_initcall(fn, early)

/*
 * A "pure" initcall has no dependencies on anything else, and purely
 * initializes variables that couldn't be statically initialized.
 *
 * This only exists for built-in code, not for modules.
 * Keep main.c:initcall_level_names[] in sync.
 */
#define pure_initcall(fn)               __define_initcall(fn, 0)

#define core_initcall(fn)               __define_initcall(fn, 1)
#define core_initcall_sync(fn)          __define_initcall(fn, 1s)
#define postcore_initcall(fn)           __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
#define arch_initcall(fn)               __define_initcall(fn, 3)
#define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
#define subsys_initcall(fn)             __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
#define fs_initcall(fn)                 __define_initcall(fn, 5)
#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
#define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
#define device_initcall(fn)             __define_initcall(fn, 6)
#define device_initcall_sync(fn)        __define_initcall(fn, 6s)
#define late_initcall(fn)               __define_initcall(fn, 7)
#define late_initcall_sync(fn)          __define_initcall(fn, 7s)

#define __initcall(fn) device_initcall(fn)



啟動程序會依照 initcall_level_names[] 的順序把 section 內 function 一一呼叫。

所以 module 有 init function 要在啟動時被呼叫,就自己決定一下該在什麼時候,然後宣告..
以 sound_core.c 為例:
static int __init init_soundcore(void)
{
        int rc;

        rc = init_oss_soundcore();
        if (rc)
                return rc;

        sound_class = class_create(THIS_MODULE, "sound");
        if (IS_ERR(sound_class)) {
                cleanup_oss_soundcore();
                return PTR_ERR(sound_class);
        }

        sound_class->devnode = sound_devnode;

        return 0;
}

static void __exit cleanup_soundcore(void)
{
        cleanup_oss_soundcore();
        class_destroy(sound_class);
}

subsys_initcall(init_soundcore);
module_exit(cleanup_soundcore);

就可以,


2016/6/24

lxc debian

所以 lxc 就是共用 kernel. 然後跟 chroot 有點像...
但是command 和 qemu 比較像。

大概就是使用相同的 kernel

在 debian 上使用 lxc 很簡單,
就是裝了lxc 這個 package 後,用 lxc-create 一個 image,
然後用 lxc-start 來 run

create 的時候可以指定版本,在command 最後用:
-- -r wheezy
否則 default 版本是跟 host 一樣。(現在是 jessie)

啟動時,加上 -d 可以 run 在背景。
之後用 lxc-console 開啟 console

要退出用 Ctrl-A q

退出後,用 lxc-stop 停止
如果不要了,可以用 lxc-destroy 把 image 刪掉 (在 /var/lib/lxc)

至於 網路部份,就要用 host bridge 的方式開啟。

2016/6/23

lxc on raspberry pi jessie

參考:
debian wiki lxc

raspberry pi 手動 root image

安裝完 lxc, libvirt-bin

用 lxc-checkconfig
說 找步道,所以 follow 他得說明: modprobe configs 再 run 一次..
pi@raspberrypi:~ $ sudo lxc-checkconfig 
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: missing
Network namespace: enabled
Multiple /dev/pts instances: enabled

--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: missing

--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

lxc-create 會到 debian.org 去找 root image, 但是raspbian 用的是 raspbian.org, 所以會fail:
Cannot check Release signature; keyring file not available /usr/share/keyrings/debian-archive-keyring.pgp

這一篇 有說,要修改 lxc-templete
在 /usr/share/lxc/templates 中新增一個 lxc-raspbian
然後就可以用 lxc-create 來 create 一個 raspbian 的 root image

lxc-raspbian 就從 lxc-debian 改。
就改 MIRROR 就好,把 debian.org 改 raspbian.org

結果 fail,, 一堆不能 download..
E: Couldn't download packages: cpio dash debconf debconf-i18n debianutils dialog diffutils dmsetup dpkg e2fslibs e2fsprogs findutils  
gcc-4.6-base gcc-4.7-base gcc-4.8-base gcc-4.9-base gnupg gpgv grep gzip hostname ifupdown init init-system-helpers initramfs-tools 
initscripts insserv iproute iproute2 isc-dhcp-client isc-dhcp-common klibc-utils kmod libacl1 libapt-pkg4.12 libattr1 libaudit-common 
libaudit1 libblkid1 libbsd0 libbz2-1.0 libc-bin libc6 libcap2 libcap2-bin libcomerr2 libcryptsetup4 libdb5.3 libdbus-1-3 libdebconfclient0 
libdevmapper1.02.1 libdns-export100 libdrm2 libedit2 libgcc1 libgcrypt20


直接 root 帳號run lxc-create debian ...
download OK, 最後 ..
W: Failure trying to run: chroot /var/cache/lxc/debian/partial-jessie-armhf mount -t proc proc /proc
W: See /var/cache/lxc/debian/partial-jessie-armhf/debootstrap/debootstrap.log for details
Failed to download the rootfs, aborting.
Failed to download 'debian base'
failed to install debian
lxc_container: container creation template for debian8 failed
去 /var/cache/lxc/debian/下是空的。


這一篇 好像有上面的解答。
他提供一個 lxc-pi, 然後遇到一樣的 mount proc fail 時的解法..


最後還是用手動的,用 debootstrap 建立 root image..Link

pi@raspberrypi:~ $ sudo mkdir -p /var/lxc/guests/tt2
pi@raspberrypi:~ $ sudo http_proxy="http://myproxy:3128" debootstrap jessie /var/lxc/guests/tt2/fs/ http://archive.raspbian.org/raspbian


然後進去改 password..
pi@raspberrypi:~ $ sudo chroot /var/lxc/guests/tt2/fs/
root@raspberrypi:/# passwd
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
root@raspberrypi:/# exit

做 config 檔
pi@raspberrypi:~ $ sudo vi /var/lxc/guests/tt2/config
內容是..
lxc.utsname = tt2
lxc.tty = 2
lxc.rootfs = /var/lxc/guests/tt2/fs

create:
pi@raspberrypi:~ $ sudo lxc-create -f /var/lxc/guests/tt2/config -n tt2

啟動..
pi@raspberrypi:~ $ sudo lxc-start -n tt2
systemd 215 running in system mode. (+PAM +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ -SECCOMP -APPARMOR)
Detected virtualization 'lxc'.
Detected architecture 'arm'.

Welcome to Raspbian GNU/Linux 8 (jessie)!

Set hostname to .
Cannot add dependency job for unit dbus.socket, ignoring: Unit dbus.socket failed to load: No such file or directory.
Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such file or directory.
[  OK  ] Reached target Remote File Systems (Pre).
....
....
[  OK  ] Started Update UTMP about System Runlevel Changes.

Raspbian GNU/Linux 8 raspberrypi console

raspberrypi login: root
Password: 
Linux raspberrypi 4.4.11+ #888 Mon May 23 20:02:58 BST 2016 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@raspberrypi:~# 

要退出的話,好像要 poweroff -- 跟正常電腦關機一樣...

-d run 在背景用 lxc-console 的話沒有反應。
只能 run 在前景。


升級到 stretch 後,default 變成 daemon mode,所以反而要加 '-F' 指定開在 foreground mode

2016/6/22

PiFm : Raspberry 用 GPIO 發射 FM

就是這一篇:Turning the Raspberry Pi Into an FM Transmitter

download source with compiled files
在 GPIO4 上差一根 杜邦線 當天線。
然後在 run pifm 就可以。

就像 alsa 的 aplay 一樣,他只吃 wav, 而且要告訴他 wav 的 sampling rate, channel (mono/stereo)

$sudo ./pifm my.wav 100.0 48000 stereo

然後google 一下 raspberry pi fm
會有一堆,連 RDS 廣播的程式也有。

2016/6/14

snd_pcm_open_substream -- EXIT
snd_pcm_open -- EXIT
snd_pcm_playback_open -- EXIT
snd_pcm_hw_refine -- snd_pcm_hw_params+0x74/0x374: subdevice #0
snd_pcm_hw_refine -- snd_pcm_hw_param_first+0xf4/0x1c0: subdevice #0
snd_pcm_hw_refine -- snd_pcm_hw_param_first+0xf4/0x1c0: subdevice #0
imx_cs42888_surround_hw_params -- soc_pcm_hw_params+0x13c/0x464
fsl_esai_set_dai_sysclk -- snd_soc_dai_set_sysclk+0x38/0x7c, dir:1 f:24576000
fsl_esai_set_dai_tdm_slot -- snd_soc_dai_set_tdm_slot+0x30/0x40, slot_width:16, slots:2
fsl_esai_hw_params -- soc_pcm_hw_params+0x194/0x464 : bclk:1536000, p_rat:48000, slot_w:16, slots:2
fsl_esai_set_bclk -- soc_pcm_hw_params+0x194/0x464, tx, 1536000
Playing sample: 2 ch, 48000 hz, 16 bit
..
snd_pcm_open_substream -- EXIT
snd_pcm_open -- EXIT
snd_pcm_hw_refine -- snd_pcm_hw_params+0x74/0x374: subdevice #0
snd_pcm_hw_refine -- snd_pcm_hw_param_first+0xf4/0x1c0: subdevice #0
snd_pcm_hw_refine -- snd_pcm_hw_param_first+0xf4/0x1c0: subdevice #0
imx_cs42888_surround_hw_params -- soc_pcm_hw_params+0x13c/0x464
fsl_esai_set_dai_sysclk -- snd_soc_dai_set_sysclk+0x38/0x7c, dir:1 f:24576000
fsl_esai_set_dai_tdm_slot -- snd_soc_dai_set_tdm_slot+0x30/0x40, slot_width:16, slots:2
fsl_esai_hw_params -- soc_pcm_hw_params+0x194/0x464 : bclk:1536000, p_rat:48000, slot_w:16, slots:2
fsl_esai_set_bclk -- soc_pcm_hw_params+0x194/0x464, rx, 1536000
Capturing sample: 2 ch, 48000 hz, 16 bit

2016/6/13

imx6 esai . synchronous , asynchronous..

datasheet 有:
.. the transmitter and receiver sections may use common clock and 
synchronization signals (synchronous operation mode),
or they may have their own seperate clock and sync signals (asynchronous operation mode)..
所以 TX, RX 可以共用 CLK, FS, 並不是一定要分開。

區分的方式..
The SYN bit in ESAI_SAICR register selects synchronous or asynchronous operation..


source code..

sound/soc/fsl/fsl_esai.c..
/**
 * fsl_esai: ESAI private data
 * ....
 * ....
 * @synchronous: if using tx/rx synchronous mode
 */
struct fsl_esai {
        ...
        bool synchronous;
        char name[32];
};
driver private data 有一個item 紀錄是synchronous

這個 item 是由 dts 來決定..
static int fsl_esai_probe(struct platform_device *pdev)
{
        ....
        esai_priv->synchronous =
                of_property_read_bool(np, "fsl,esai-synchronous");

所以看一下 dts/dtsi..
--- 找不到。

所以 Documentation/devicetree/bindings/sound/fsl,esai.txt:
    ....
  - fsl,esai-synchronous: This is a boolean property. If present, indicating
    that ESAI would work in the synchronous mode, which means all the settings
    for Receiving would be duplicated from Transmition related registers.

Example:

esai: esai@02024000 {
        compatible = "fsl,imx35-esai";
        reg = <0x02024000 0x4000>;
        interrupts = <0 51 0x04>;
        clocks = <&clks 208>, <&clks 118>, <&clks 208>;
        clock-names = "core", "extal", "fsys";
        dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
        dma-names = "rx", "tx";
        fsl,fifo-depth = <128>;
        fsl,esai-synchronous;
        status = "disabled";
};
iceweasel (45.0esr-1) unstable; urgency=medium

  * The iceweasel package was replaced with the firefox-esr package.

  * Preferences under /etc/iceweasel/prefs will need to be copied manually
    to /etc/firefox-esr.
  * Other customizations under /etc/iceweasel will need additional manual
    steps, through CCK2 or addons.

 -- Mike Hommey   Mon, 7 Mar 2016 07:45:02 +0900
firefox 的 license 改了?

果然,iceweasel 變成 firefox...
注音輸入還是有點問題,....

2016/5/26

攔截VOLUME UP 鍵

ref: https://gitlab.com/checko/InterceptVolumeUp

就是用 onKeyDown, onKeyUp

public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode==KeyEvent.KEYCODE_VOLUME_UP) {
            Log.i(TAG,event.toString());
            return true;
        }

        return super.onKeyDown(keyCode,event);
    }
記得,處理過(攔截), 就要 return true.
不處理,交給系統的話,就要 call super.onKeyDown/Up
不能只return false,
否則還是沒有動做。

2016/5/25

svn : set executable attrib to files

svn 如果一開始 add file 時,沒有加 executable attrib, 之後要加,他都當沒看到。
所以要用 svn 特別為 file attrib 設的command。

像,要把所有 .sh file 都加上 x:
$ svn propset svn:executable "777" *.sh

設完後,用 svn status 就可以看到 file 被改變了。
就可以commit


ref:http://stackoverflow.com/questions/6874085/how-to-set-execute-attribute-to-a-file-and-check-it-in-svn-from-windows

2016/5/23

2016/5/19

Preload resource warnning..

出現一堆 message:
W/Resources(  220): Preloaded drawable resource #0x10802a5 (android:drawable/dialog_top_holo_dark) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x10802a6 (android:drawable/dialog_top_holo_light) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x1080358 (android:drawable/ic_dialog_alert_holo_dark) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x1080359 (android:drawable/ic_dialog_alert_holo_light) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x1080496 (android:drawable/list_divider_holo_dark) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x1080497 (android:drawable/list_divider_holo_light) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x1080497 (android:drawable/list_divider_holo_light) that varies with configuration!!
W/Resources(  220): Preloaded drawable resource #0x10800c2 (android:drawable/ab_transparent_dark_holo) that varies with configuration!!

grep 一下,出自於:frameworks/base/core/java/android/content/res/Resources.java 2240,12 84%
    private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
            int resourceId, String name) {
        // We allow preloading of resources even if they vary by font scale (which
        // doesn't impact resource selection) or density (which we handle specially by
        // simply turning off all preloading), as well as any other configs specified
        // by the caller.
        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
            String resName;
            try {
                resName = getResourceName(resourceId);
            } catch (NotFoundException e) {
                resName = "?";
            }
            // This should never happen in production, so we should log a
            // warning even if we're not debugging.
            Log.w(TAG, "Preloaded " + name + " resource #0x"
                    + Integer.toHexString(resourceId)
                    + " (" + resName + ") that varies with configuration!!");
            return false;
        }
        if (TRACE_FOR_PRELOAD) {
            String resName;
            try {
                resName = getResourceName(resourceId);
            } catch (NotFoundException e) {
                resName = "?";
            }
            Log.w(TAG, "Preloading " + name + " resource #0x"
                    + Integer.toHexString(resourceId)
                    + " (" + resName + ")");
        }
        return true;
    }

MasterVolume..

framework/base/media/java/android/media/AudioService.java
    public void setMasterVolume(int volume, int flags, String callingPackage) {
        if (mUseFixedVolume) {
            return;
        }

        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
                callingPackage) != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        if (volume < 0) {
            volume = 0;
        } else if (volume > MAX_MASTER_VOLUME) {
            volume = MAX_MASTER_VOLUME;
        }
        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
    }

    private void doSetMasterVolume(float volume, int flags) {
        // don't allow changing master volume when muted
        if (!AudioSystem.getMasterMute()) {
            int oldVolume = getMasterVolume();
            AudioSystem.setMasterVolume(volume);

            int newVolume = getMasterVolume();
            if (newVolume != oldVolume) {
                // Post a persist master volume msg
                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
            }
            // Send the volume update regardless whether there was a change.
            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
        }
    }

最後call 到 framework/av/service/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::setMasterVolume(float value)
{
 ....
 ...
    // Set master volume in the HALs which support it.
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        AutoMutex lock(mHardwareLock);
        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);

        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
        if (dev->canSetMasterVolume()) {
            dev->hwDevice()->set_master_volume(dev->hwDevice(), value);
        }
        mHardwareStatus = AUDIO_HW_IDLE;
    }

所以 AudioHwDevice 要 implement canSetMasterVolume( ), 然後實做 set_master_volume( )

再查 canSetMasterVolume..
一樣,在 AudioFlinger.h:
    class AudioHwDevice {
         ...
         ...
        bool canSetMasterVolume() const {
            return (0 != (mFlags & AHWD_CAN_SET_MASTER_VOLUME));
        }


mFlag 是在 AudioHwDevice 生成時給定的...
        AudioHwDevice(audio_module_handle_t handle,
                      const char *moduleName,
                      audio_hw_device_t *hwDevice,
                      Flags flags)
            : mHandle(handle), mModuleName(strdup(moduleName))
            , mHwDevice(hwDevice)
            , mFlags(flags) { }

同樣的地方...
audioflinger 在 load audio.xxx.xxx module 時,會測試 audio module 是否有 implement set_master_volume( )
好決定生成 AudioHwDevice 時,flag 要不要加上 AHWD_CAN_SET_MASTER_VOLUME:
    AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
    {  
        ....
        ....
        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
        if ((NULL != dev->set_master_volume) &&
            (OK == dev->set_master_volume(dev, mMasterVolume))) {
            flags = static_cast<AudioHwDevice::Flags>(flags |
                    AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
        }

        mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
        if ((NULL != dev->set_master_mute) &&
            (OK == dev->set_master_mute(dev, mMasterMute))) {
            flags = static_cast<AudioHwDevice::Flags>(flags |
                    AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
        }
        ...
     }
     ...
    audio_module_handle_t handle = nextUniqueId();
    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));


然後在 hw_module 的 source (imx6): hardware/imx/alsa/tinyalsa_hal.c:
static int adev_open(const hw_module_t* module, const char* name,
                     hw_device_t** device)
{
    ....
    adev->hw_device.set_master_volume       = adev_set_master_volume;

有 module function table 的 assign,
implement 是:
static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
{
    return -ENOSYS;
}
.. 也就是說...沒有提供這個功能。

所以把 return value 從 -ENOSYS 改成 0

然後,還要改...
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8006659..ecb8780 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -65,7 +65,7 @@
 
     <!-- Flag indicating that the media framework should allow changing
          master volume stream and nothing else . -->
-    <bool name="config_useMasterVolume">false</bool>
+    <bool name="config_useMasterVolume">true</bool>
叫 ..
./media/java/android/media/AudioManager.java:585:                com.android.internal.R.bool.config_useMasterVolume);
./media/java/android/media/AudioService.java:641:                com.android.internal.R.bool.config_useMasterVolume);
這兩個 source 用 MasterVolume

另外 UI:

2016/5/18

handle Key Event 的位置..

framework/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java 有一段:
    protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
        /* ****************************************************************************
         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
         *
         * If your key handling must happen before the app gets a crack at the event,
         * it goes in PhoneWindowManager.
         *
         * If your key handling should happen in all windows, and does not depend on
         * the state of the current application, other than that the current
         * application can override the behavior by handling the event itself, it
         * should go in PhoneFallbackEventHandler.
         *
         * Only if your handling depends on the window, and the fact that it has
         * a DecorView, should it go here.
         * ****************************************************************************/
  • 在所有 app 能拿到之前 : PhoneWindowManager
  • 除非 app 有自己處理,否則交給你處理: PhoneFallbackEventHandler
  • 你有用到 DecoView... : PhoneWindow.java

android safe mode..

在 framework/base/service/com/android/server/wm/WindowManagerService.java:
    public boolean detectSafeMode() {
        if (!mInputMonitor.waitForInputDevicesReady(
                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
            Slog.w(TAG, "Devices still not ready after waiting "
                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
                   + " milliseconds before attempting to detect safe mode.");
        }

        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
                KeyEvent.KEYCODE_MENU);
        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
                KeyEvent.KEYCODE_DPAD_CENTER);
        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
                InputManagerService.BTN_MOUSE);
        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
                KeyEvent.KEYCODE_VOLUME_DOWN);
        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
                || volumeDownState > 0;
        try {
            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
                mSafeMode = true;
                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
            }
        } catch (IllegalArgumentException e) {
        }
        if (mSafeMode) {
            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
        } else {
            Log.i(TAG, "SAFE MODE not enabled");
        }
        mPolicy.setSafeMode(mSafeMode);
        return mSafeMode;
    }

所以有很多方式(按鍵)進入 safemode:
  • menu button
  • dpad (?) button
  • mouse button
  • volume down

ref:https://www.asus.com/tw/support/faq/1005163

2016/5/11

ALSA driver, add support 24000Hz Sample Rate..

include/uapi/sound/asound.h
#define SNDRV_MASK_MAX  256

struct snd_mask {
        __u32 bits[(SNDRV_MASK_MAX+31)/32];
};


tinypcminfo : 會列出 sound card 的 property (rules), 例如:
root@sabreauto_6q:/ # tinypcminfo -D 0                                         
Info for card 0, device 0:

PCM out:
      Access: 0x000009
   Format[0]: 0x000045
   Format[1]: 00000000
 Format Name: S8, S16_LE, S24_LE
   Subformat: 0x000001
        Rate: min=48000Hz max=192000Hz
    Channels: min=1  max=12
 Sample bits: min=8  max=32
 Period size: min=3  max=65535
Period count: min=2  max=255

PCM in:
      Access: 0x000009
   Format[0]: 0x000045
   Format[1]: 00000000
 Format Name: S8, S16_LE, S24_LE
   Subformat: 0x000001
        Rate: min=48000Hz max=192000Hz
    Channels: min=1  max=8
 Sample bits: min=8  max=32
 Period size: min=4  max=65535
Period count: min=2  max=255


然後看到 fsl_esai.c 李有..
#define FSL_ESAI_RATES          SNDRV_PCM_RATE_8000_192000
...
...
        .probe = fsl_esai_dai_probe,
        .playback = {
                .stream_name = "esai-Playback",
                .channels_min = 1,
                .channels_max = 12,
                .rates = FSL_ESAI_RATES,
                .formats = FSL_ESAI_FORMATS,
        },
        .capture = {
                .stream_name = "esai-Capture",
                .channels_min = 1,
                .channels_max = 8,
                .rates = FSL_ESAI_RATES,
                .formats = FSL_ESAI_FORMATS,
        },
        .ops = &fsl_esai_dai_ops,
};


找一下這個..
include/sound/pcm.h:

/* If you change this don't forget to change rates[] table in pcm_native.c */
#define SNDRV_PCM_RATE_5512             (1<<0)          /* 5512Hz */
#define SNDRV_PCM_RATE_8000             (1<<1)          /* 8000Hz */
#define SNDRV_PCM_RATE_11025            (1<<2)          /* 11025Hz */
#define SNDRV_PCM_RATE_16000            (1<<3)          /* 16000Hz */
#define SNDRV_PCM_RATE_22050            (1<<4)          /* 22050Hz */
#define SNDRV_PCM_RATE_32000            (1<<5)          /* 32000Hz */
#define SNDRV_PCM_RATE_44100            (1<<6)          /* 44100Hz */
#define SNDRV_PCM_RATE_48000            (1<<7)          /* 48000Hz */
#define SNDRV_PCM_RATE_64000            (1<<8)          /* 64000Hz */
#define SNDRV_PCM_RATE_88200            (1<<9)          /* 88200Hz */
#define SNDRV_PCM_RATE_96000            (1<<10)         /* 96000Hz */
#define SNDRV_PCM_RATE_176400           (1<<11)         /* 176400Hz */
#define SNDRV_PCM_RATE_192000           (1<<12)         /* 192000Hz */

#define SNDRV_PCM_RATE_CONTINUOUS       (1<<30)         /* continuous range */
#define SNDRV_PCM_RATE_KNOT             (1<<31)         /* supports more non-continuos rates */

#define SNDRV_PCM_RATE_8000_44100       (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
                                         SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\
                                         SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100)
#define SNDRV_PCM_RATE_8000_48000       (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000)
#define SNDRV_PCM_RATE_8000_96000       (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\
                                         SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
#define SNDRV_PCM_RATE_8000_192000      (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\

裡面沒有 24000....

又,有 comment..." If you change this don't forget to change rates[] table in pcm_native.c "
大概是可以自己修改的意思,所以,...插入一個 24000

然後去看看 pcm_native.c..
也有對應的 code, 和檢查,所以照著修改...
#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 13
#error "Change this table"
#endif

static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 24000, 32000, 44100,
                                 48000, 64000, 88200, 96000, 176400, 192000 };
這樣 build 完就可以 support 2400 了...


alsa driver 決定 sound card 的 sample rate range 是由一堆rules 取交集,
這些 rule 可能是 i2s, sound card, hardwae, software driver..
最後 pcm_native.c 會把所有的 rule 做交集取出有效的 range.

2016/5/6

  • 應該要把 jni 獨立在令一個 class, 不要和 MainActivity 關聯,這樣以後 refactory 比較方便
  • 要設法處理每個 view 中 widget/control 的 value 保存問題。尤其是共用 layout 和 handler 時,要分離出保存value 的code 有點不方便

2016/4/28

android . SeekBar -- 中間起始

這是github 上的 project: https://github.com/vashisthg/StartPointSeekBar

他自己寫的 seekbar widget.

project 包含 widget library 和 demo project

使用時只要library project 就可以。


Android Studio 的 project 中,使用這個 library 的方法:
  • File -- New -- Module , 出現新 Dialog
  • Dialog 中出現很多 item, 選 'Import Gradle Project',然後 Next
  • Source Directory 選到 StartPointSeekBar/Library
  • 要給名稱,.,就沿用 library 好了
這樣在 專案中就會出現一個 library folder

使用:

在 layout xml 中首先要加入:
    xmlns:custom="http://schemas.android.com/apk/res-auto"
例如..
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

然後就可以在 xml 中加入 這個 seekbar 了..
    <com.vashisthg.startpointseekbar.StartPointSeekBar
        android:id="@+id/seek_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        custom:minValue="-40.0"
        custom:maxValue="+40.0"
       />


使用的 app build.gradle 的 dependency 要加上:
compile project(':library')

要是在 gradle-experimental 的話,要大幅度修改:
apply plugin: 'com.android.model.library'

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.3"

        defaultConfig.with {
            minSdkVersion.apiLevel = 21
            targetSdkVersion.apiLevel = 23
            versionCode = 2
            versionName = "1.2"
        }
    }

    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles.add(file('proguard-android.txt'))
        }
    }
}

dependencies {
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

Progress Change Handler 跟一般 Seekbar 一樣..
        StartPointSeekBar seekBar = (StartPointSeekBar) findViewById(R.id.seek_bar);
        seekBar.setOnSeekBarChangeListener(new StartPointSeekBar.OnSeekBarChangeListener() {
            @Override
            public void onOnSeekBarValueChange(StartPointSeekBar bar, double value) {
                Log.d(LOGTAG, "seekbar value:" + value);
            }
        });


        // setting progress on your own
        seekBar.setProgress(+20);
    }

2016/4/20

read permission without 'show'

開機出現這個 message:
Attribute aabubu_addr: read permission without 'show'


這個的出處是:driver/base/core.c
int device_create_file(struct device *dev,
                       const struct device_attribute *attr)
{
        int error = 0;

        if (dev) {
                WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
                        "Attribute %s: write permission without 'store'\n",
                        attr->attr.name);
                WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
                        "Attribute %s: read permission without 'show'\n",
                        attr->attr.name);
                error = sysfs_create_file(&dev->kobj, &attr->attr);
        }

        return error;
}
所以是 createfile 時,給了 S_IRUGO 屬性,但是沒有實做 show function

找到 driver attr 屬性:
只有..
static DEVICE_ATTR(aabubu_addr, 0666, NULL, aabubu_addr_store);
果然,沒有實做 aabubu_addr_show

所以修改 addribure, 把 0666 改 0222 就 OK 了。

2016/4/18

TabLayout

ref: http://www.truiton.com/2015/06/android-tabs-example-fragments-viewpager/

原來 tab 是手動做出來的。

再看 http://givemepass.blogspot.tw/2015/10/tablayout.html
這個也是 step by step: http://givemepass-blog.logdown.com/posts/288943-how-to-use-tablayout

原來是 android support library 新增加 actionbar 元件。

Support Library 要額外download, 會放在 extra/ 下。

裡面有這些 features

不僅提供舊OS能有新 interface 的 api support, 同時也有新增加的 feature

根據你的 OS 版本不同,要用的內容也不一樣

要用的話,除了要download, 還要修改 build.gradle, 加入
compile 'com.android.support:design:23.2.1
-- 開啟 SDK Manager 來看裝的是那一版。


根據上面兩個 ref link, 合併在一起: https://github.com/checko/TabLayout

原來TabLayout 是主要元件。
所以 main layout 上要擺一個 TabLayout (android.support.design.widget.TabLayout)
然後還需要一個區域:ViewPager (android.support.v4.view.ViewPager)

這個 ViewPager 就是用來讓 TabLayout 根據click 和滑動變更內容的區域。
TabLayout 基本上只負責 顯示 title, 反應 click/swipe 來變更 ViewPager 內容。
不管ViewPager 裡面的動作。

負責反應click, swipe 的是 TabLayout.setOnTabSelectedListener()
負責 swipe , 因為動作在ViewPager, 所以是 ViewPager.addOnPageChangeListener()

然後把 ViewPager 和每一個 page 內容 (layout) 連在一起的是 PagerAdapter 這個 class
要繼承這個 class, 實做 instantiateItem(..,int position ) 時,根據 position 把page 內容(layout)生出來。


在 ViewPager 李的每個 view 裡面的 widget (view), 只有用那個 view 才access 得到。
舉例來說,page 2 李有一個 TextView,
要用
view = getLayoutInflater().inflate(R.layout.page_2, container, false);
mTextView = (TextView) view.findValueById(R.id.tvppp);
在 MainActivity 的 OnCreate 裡,access 不到。

2016/4/15

git svn , 把 git project 丟到 svn 上

git svn clone https://my-srver/svnproject
cd svnproject
git checkout git-svn
git remote add local ~/mylocal/gitproject
git fetch local
git pull local master
git svn dcommit
比較奇怪的動作是 git checkout git-svn這個隱含的動作。
之後,對 master 做dcommit 動作都會update到 svn server
..但是用 git commit 只會 update local git repo.

2016/4/12

  • cpu_dai : cpu 端的裝置,像 I2S, ESAI
  • codec_dai : 就是 codec, 像 CS42888 和 WM8962

snd_soc_ops, 放在 snd_soc_dai_link , 他又是在 snd_soc_card:
snd_soc_card {
  snd_soc_dai_link {
     snd_soc_ops {
        .startup
        ,hw_params
     } ops
  } dai_link
}

2016/4/11

Device Driver , kernel boot.

Device Driver
  Device Tree and Open Firmware Support
    Support for device tree in /proc
module_platform_driver(imx_wm8962_driver);
include/linux/platform_device.h
/* module_platform_driver() - Helper macro for drivers that don't do
 * anything special in module init/exit.  This eliminates a lot of
 * boilerplate.  Each module may only use this macro once, and
 * calling it replaces module_init() and module_exit()
 */
#define module_platform_driver(__platform_driver) \
        module_driver(__platform_driver, platform_driver_register, \
                        platform_driver_unregister)

/* module_platform_driver_probe() - Helper macro for drivers that don't do
 * anything special in module init/exit.  This eliminates a lot of
 * boilerplate.  Each module may only use this macro once, and
 * calling it replaces module_init() and module_exit()
 */

include/linux/device.h
/**
 * module_driver() - Helper macro for drivers that don't do anything
 * special in module init/exit. This eliminates a lot of boilerplate.
 * Each module may only use this macro once, and calling it replaces
 * module_init() and module_exit().
 *
 * @__driver: driver name
 * @__register: register function for this driver type
 * @__unregister: unregister function for this driver type
 * @...: Additional arguments to be passed to __register and __unregister.
 *
 * Use this macro to construct bus specific macros for registering
 * drivers, and do not use it on its own.
 */
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
        return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
        __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

所以是 call platform_driver_register(imx_wm8962_driver)

./drivers/base/platform.c:541:EXPORT_SYMBOL_GPL(platform_driver_register);
/**
 * platform_driver_register - register a driver for platform-level devices
 * @drv: platform driver structure
 */
int platform_driver_register(struct platform_driver *drv)
{
        drv->driver.bus = &platform_bus_type;
        if (drv->probe)
                drv->driver.probe = platform_drv_probe;
        if (drv->remove)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;

        return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);

至於要call 到 XXX_probe( ), 有一堆要檢查,主要是確認 platform driver 跟 platform data 有 match
match 的方式有很多種,有 bus, 有 name, 還有用 of_device (也就是 dtd) 內的 compatible 字串比較,

新版 driver 好像把所有 driver 都賦予一個 bus, 非 bus 的就給 platform 這個 'bus'

code 都在 driver/base/bus.c, dd.c, platform.c 和 driver/of/base.c

base.c:
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
                                           const struct device_node *node)
{
        if (!matches)
                return NULL;

        while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
                int match = 1;
                if (matches->name[0])
                        match &= node->name
                                && !strcmp(matches->name, node->name);
                if (matches->type[0])
                        match &= node->type
                                && !strcmp(matches->type, node->type);
                if (matches->compatible[0])
                        match &= __of_device_is_compatible(node,
                                                           matches->compatible);
                if (match)
                        return matches;
                matches++;
        }
        return NULL;
}

compatible 的比較:
/** Checks if the given "compat" string matches one of the strings in
 * the device's "compatible" property
 */
static int __of_device_is_compatible(const struct device_node *device,
                                     const char *compat)
{
        const char* cp;
        int cplen, l;

        cp = __of_get_property(device, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
                if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
                        return 1;
                l = strlen(cp) + 1;
                cp += l;
                cplen -= l;
        }

        return 0;
}

2016/4/7

imx6 sabresd soud, ssi, audmux dtd

sabresd

imx6dl-sabresd.dts:
  
  imx6qdl.dtsi:
    ssi1.2.3  "fsl.imx6q-ssi","fsl-imx21-ssi"
    audmux    "fsl,imx6q-audmux","fsl,imx31-audmux"
    iomuxc
      pinctrl_audmux_1 (AUD4)
      pinctrl_audmux_2 (AUD3)
      pinctrl_audmux_3 (AUD5)
  
  imx6qdl-sabresd.dtsi:
    sound ssi2       "fsl,imx6q-sabresd-wm8962","fsl,imx-audio-wm8962"
    ssi2 i2s-slave
    audmux pinctrl_audmux_2
 
大概相關的幾個 node


driver code 相關

實際設定 AUDMUX 的地方在 sound/soc/fsl/imx-wm8962.c:
static int imx_wm8962_probe(struct platform_device *pdev)
{
       .....
       .....

        of_property_read_u32(np, "mux-int-port", &int_port);
        of_property_read_u32(np, "mux-ext-port", &ext_port);
        
        int_port--;
        ext_port--;
        ret = imx_audmux_v2_configure_port(int_port,
                        IMX_AUDMUX_V2_PTCR_SYN |
                        IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
                        IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
                        IMX_AUDMUX_V2_PTCR_TFSDIR |
                        IMX_AUDMUX_V2_PTCR_TCLKDIR,
                        IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
       ....


所以要看這個drver ("imx-audio-wm8962") 的 dtb..
imx6qdl-sabresd.dtsi
        sound {
                compatible = "fsl,imx6q-sabresd-wm8962",
                           "fsl,imx-audio-wm8962";
                model = "wm8962-audio";
                cpu-dai = <&ssi2>;
                audio-codec = <&codec>;
                audio-routing =
                        "Headphone Jack", "HPOUTL",
                        "Headphone Jack", "HPOUTR",
                        "Ext Spk", "SPKOUTL",
                        "Ext Spk", "SPKOUTR",
                        "MICBIAS", "AMIC",
                        "IN3R", "MICBIAS",
                        "DMIC", "MICBIAS",
                        "DMICDAT", "DMIC";
                mux-int-port = <2>;
                mux-ext-port = <3>;
                hp-det-gpios = <&gpio7 8 1>;
                mic-det-gpios = <&gpio1 9 1>;
        };
有 mux-int-port, mux-ext-port 兩個 value

cpu-dai 是 ssi2 ,所以mux-int-port 就是 2
audmux 用的是 pinctrl_audmux_2:
&audmux {
        pinctrl-names = "default"; 
        pinctrl-0 = <&pinctrl_audmux_2>;
        status = "okay";
};
這個 pinctrl 就是..
                pinctrl_audmux_2: audmux-2 {
                        fsl,pins = <
                                MX6QDL_PAD_CSI0_DAT7__AUD3_RXD  0x130b0
                                MX6QDL_PAD_CSI0_DAT4__AUD3_TXC  0x130b0
                                MX6QDL_PAD_CSI0_DAT5__AUD3_TXD  0x110b0
                                MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
                        >;
                }; 
對應 AUD3, 所以 mux-ext-port 是 3

imx6 ssi & audmux

Chap 9.11 Audio subsystem
Chap 16.1 Digital Audio Multuplexer

  • SSI-1.2.3
  • AUDMUX
  • ESAI
  • SPDIF
  • ASRC
  • MLB
IOMUX 也要 config


SSI

SSI 三組,輸出不是直接到 chip pin腳。
是接到 AUDMUX, 再由 AUDMUX 的接腳輸出。

SSI 有以下模式:
  • SSI normal
  • SSI network
  • I2S
  • AC-97

SSI 有 T/R FIFO 和 DMA
SSI1.2.3 可以有個別的clk..個別的 stream 內容。


AUDMUX

audmux 是 routing 用。
有三個 internal port 和 4 個 external port

internal port 直接接到 SSI1.2.3, 不可以變更。
所以 imx6 的 IOMUX pinout 只看到 AUD3.4.5.6
-- 根據 datasheet 的圖,internal 是 AUD1.2.7 -- 大概internal 的第 3 組是後來才加的。

2016/4/6

Android Auto HeadUnit -- XDA

XDA 上有人reverse eng 了 android auto protocol. 寫了一個 headunit app:
http://forum.xda-developers.com/general/paid-software/android-4-1-headunit-android-auto-t3125252

Android Auto 的使用方式是:
  • Android Auto Headunit (也就是車用主機) -- 裝這個 app 就可以
  • 手機要裝 Android Auto App, 這只有在 support 的國家才找得到,不然就只有download apk 自己裝。http://www.apkmirror.com/apk/google-inc/android-auto/
  • HeadUnit 要有 usb host 功能,用 usb cable 連 android 手機和 Headunit
  • 手機要 disable usb debug mode, 開啟 Android Auto app
  • Headunit 會出現 usb permission dialog, 確認與許
第一次連線,手機會 download 一些 supoort 的 android auto app, 所以要有網路連線

* 跟 usb 連線有很大關係,所以用短一點的線,如果失敗,多插拔幾次。

2016/4/1

imx6 CLKO

imx6 提供兩個 clock output: CLKO1, CLKO2

CLKO1 可以選擇 GPIO0 做 clk output
CLKO2 可以選擇 GPIO3 做 clk output

CLKO1.2 的控制 register 在 CCM_CCOSR (offset 0x60)

對照 kernel source : clk-imx6q.c
在 source code 李,叫 cko1, cko2
        clk[cko1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
        clk[cko2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
        ....
        clk[cko1_podf]        = imx_clk_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
        clk[cko2_podf]        = imx_clk_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
        ....
        clk[cko1_sel]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
        clk[cko2_sel]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
        ....

clk 是 struct clk

clk 軟體模型,依照一般 clk 的設置,叫下面的名子。:
  • clk source : parent, mux (imx_clk_mux)
  • divider : divider (imx_clk_divider)
  • enable/disable : gate (imx_clk_gate)
對照宣告的時候,後面的數字就是 register 的 offset, bit-shift , bit-width
拿 gate 來看,對照 datasheet, CCM_CCOSR:

  • bit 24: CLKO2_EN : enable/disable CLKO2
  • bit 21-23 : CLKO2_DIV : divider by 1,2,3,4...8
  • bit 16-20 : CLKO2_SEL : clko2 的 clk src
  • bit 7 : CLKO1_EN
  • bit 4-6 : CLKO1_DIV
  • bit 0-3 : CLKO1_SEL
可以對照看上面code 的宣告。

然後,因為這三個類型的操作不太相同,所以要為每個類型寫一個 operatio function.
各是:clk-gate2.c, clk-fixup-div.c, clk-fixup-mix.c

以 gate 來說。
implement imx_clk_gate 的code 在 clk-gate2.c
static struct clk_ops clk_gate2_ops = {
        .enable = clk_gate2_enable,
        .disable = clk_gate2_disable,
        .is_enabled = clk_gate2_is_enabled,
};
主要就是要實做這三個 gate 的 function.
enable/disable 最後 就是...
static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable)
{
        u32 reg;

        reg = readl(gate->reg);
        if (enable)
                reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx;
        else
                reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx);
        writel(reg, gate->reg);
}

統一的 clk interface 在 driver/clk/clk.c
呼叫 clk_enable( ) 就會:
static int __clk_enable(struct clk *clk)
{
        int ret = 0;

        if (!clk)
                return 0;

        if (WARN_ON(clk->prepare_count == 0))
                return -ESHUTDOWN;

        if (clk->enable_count == 0) {
                ret = __clk_enable(clk->parent);

                if (ret)
                        return ret;

                if (clk->ops->enable) {
                        ret = clk->ops->enable(clk->hw);
                        if (ret) {
                                __clk_disable(clk->parent);
                                return ret;
                        }
                }
        }

        clk->enable_count++;
        return 0;
}

-- 另外,一般用 clk_prepare_enable( )

所以,一定要 call 過 enable( ), 那個 clock 才會動。

2016/3/24

Android Studio 1.5.1 and JNI

https://codelabs.developers.google.com/codelabs/android-studio-jni/index.html?index=..%2F..%2Findex#0
照這一篇,step by step

重點大概是..
  • 要用 gradle-experimental:0.4.0
  • 所以配合的 gradle 是 2.8 (雖然最新的是 2.12)
  • build.gradle (Module: app) 內容要 follow experimanetal 的格式來寫。* 注意 "=" 號
  • build.gradle (Module: app) 新增 jni module
這樣改完,sync project 後,就可以寫 code 了。

寫 code 有很方便的 code-gen.只要在java code 宣告 native, 之後在宣告處出現的紅色燈泡按下...Create Function....
就會幫你寫好 c source 的 function 外框。

2016/3/22

PQI Air, A500 的 adaptor Mode

就是到 access page . advance.-- internet setting -- Operation Mode, 選 Bridge Mode
確認後等一陣子,再連上去後就 OK 了。

連上的 client 會向LAN request IP.

--- 在 user manual 上可以看到說明。

OpenGL texture compression support , android

http://developer.android.com/intl/zh-tw/guide/topics/graphics/opengl.html#textures
The Android framework provides support for the ETC1 compression format as a standard feature,
..
Beyond the ETC formats, Android devices have varied support for texture compression based on their GPU chipsets and OpenGL implementations.


如果真的要使用特定的 TC 功能,記得宣告在 manifest 中:
Note: Once you decide which texture compression formats your application will support, make sure you declare them in your manifest using <supports-gl-texture> . Using this declaration enables filtering by external services such as Google Play, so that your app is installed only on devices that support the formats your app requires. For details, see OpenGL manifest declarations.

google playstore 會依照 manifest 內容,決定用戶的手機能不能安裝該程式:
Each time you upload an application to the Google Play Developer Console, Google Play scans the application's manifest file and looks for any elements. It extracts the format descriptors from the elements and stores them internally as metadata associated with the application .apk and the application version.

When a user searches or browses for applications on Google Play, the service compares the texture compression formats supported by the application with those supported by the user's device. The comparison is based on the format descriptor strings and a match must be exact.

If any of an application's supported texture compression formats is also supported by the device, Google Play allows the user to see the application and potentially download it. Otherwise, if none of the application's formats is supported by the device, Google Play filters the application so that it is not available for download.
http://developer.android.com/intl/zh-tw/guide/topics/manifest/supports-gl-texture-element.html#market-texture-filtering

2016/3/8

tinyalsa : tinyplay

root@sabreauto_6q:/ # tinyplay                                                 
Usage: tinyplay file.wav [-D card] [-d device] [-p period_size] [-n n_periods] 

看一下source:
pcm.c : pcm_open( )
    snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
             flags & PCM_IN ? 'c' : 'p');

    pcm->flags = flags;
    pcm->fd = open(fn, O_RDWR);
看一下系統 /dev/snd/..
1|root@sabreauto_6q:/ # ls /dev/snd/
controlC0
controlC1
pcmC0D0c
pcmC0D0p
pcmC1D0c
timer
所以play 就是...
# tinyplay 1ch48k.wav -D 0 -d 0

bookmark : wandboard

2016/3/7

idmapping -- nfs with user permission

from http://serverfault.com/questions/514118/mapping-uid-and-gid-of-local-user-to-the-mounted-nfs-share


This is what idmapping is suppose to do. First of all, enable is on the client and server:
# echo N > /sys/module/nfs/parameters/nfs4_disable_idmapping
clean idmap cache and restart idmap daemon:
# nfsidmap -c
# service rpcidmapd restart
Now on server and the client will send instead of numeric IDs string principals like bob@YOURDOMAIN.COM. You need to have bob account on the both hosts - client and server. Nevertheless, the numeric ID's can be different.

shareimprove this answer
answered Sep 30 '14 at 5:32

kofemann
1,163717

Ftr, on nfs server the path is /sys/module/nfsd/parameters/nfs4_disable_idmapping (nfsd, not nfs) – Mike Purcell Dec 21 '15 at 19:42

原來 idmapd 要而外啟動,
ref: http://jamyy.us.to/blog/2014/03/6166.html

環境:
Server: CentOS / Fedora
Client: Debian / Ubuntu
Server
# yum install nfs-utils
# vi /etc/idmapd.conf
Domain = localdomain
# vi /etc/exports
/path *(rw,sync,no_root_squash,no_subtree_check)
# exportfs -rv
# service rpcbind start
# service nfs start
# chkconfig nfs on
# chkconfig rpcbind on
Client
$ sudo apt-get install nfs-common
$ sudo vi /etc/idmapd.conf
Domain = localdomain
$ sudo service nfs-common restart (Debian)
或
$ sudo service idmapd restart (Ubuntu 12.04)
Ubuntu 13.10 只要改好 /etc/idmapd.conf 立即生效, 無需其他操作
$ mount -t nfs4 remote:/path /local/mount/point

其他:

2016/3/4

android 6.0 : fingerprint cannot exceed 91 bytes..

出現了
error: ro.build.fingerprint cannot exceed 91 bytes:
然後網路上說,改一些 PROP_VALUE_MAX 的值:
http://stackoverflow.com/questions/28776970/android-build-error-ro-build-fingerprint-cannot-exceed-91-bytes
Edit build/tools/post_process_props.py. Change lines as follows:

PROP_NAME_MAX = 31
# PROP_VALUE_MAX = 91
PROP_VALUE_MAX = 128
Edit bionic/libc/include/sys/system_properties.h. Change lines as follows:

#define PROP_NAME_MAX   32
// #define PROP_VALUE_MAX  92
#define PROP_VALUE_MAX  128
Do

make clean
make
所以照著改...
然後就出現...
In file included from hardware/qcom/camera/QCamera/HAL/core/src/QCameraHWI_Record.cpp:27:0:
In function 'int property_get(const char*, char*, const char*)',
    inlined from 'virtual android::status_t android::QCameraStream_record::getBuf(mm_camera_frame_len_offset*, uint8_t, uint8_t*, mm_camera_buf_def_t*)' 
at 
hardware/qcom/camera/QCamera/HAL/core/src/QCameraHWI_Record.cpp:220:60:
system/core/include/cutils/properties.h:122:41: 
error: call to '__property_get_too_small_error' declared with attribute error: 
property_get() called with too small of a buffer
         __property_get_too_small_error();
因為一開始出現了 ...所以改 PROPERTY_VALUE_MAX 從 92 改 128.
結果出現上面的錯誤。

因為google 很好心的寫了一個 check, 在 system/core/include/properties.h:
int property_get(const char *key, char *value, const char *default_value) {
   size_t bos = __bos(value);
   if (bos < PROPERTY_VALUE_MAX) {
      __property_get_too_small_error();
      ...

所以問題應該是在call property_get( ) function 的 code, 傳入的 array size 太小。
所以打開 QCameraHWI_Record.cpp : 220 : 60:
char value[100];
...
property_get("persist.camera.mem.usecache",value,"1");
...
把 value[100] 改 value[PROPERTY_VALUE_MAX]

2016/3/2

imx6 CLK.

struct clk 宣告在:include/linux/clk-private.h

裡面除了 struck clk 外,還定義了:
DEFINE_CLK
DEFINE_CLK_FIXED_RATE
DEFINE_CLK_GATE
DEFINE_CLK_DIVIDER
DEFINE_CLK_DIVIDER_TABLE
DEFINE_CLK_MUX
DEFINE_CLK_FIXED_FACTOR
但是這些imx 都沒用...

是在arch/arm/mach-imx/clk-imx6q.c 中宣告,生成。
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
device tree 宣告在: imx6qdl.dtsi:
                        clks: ccm@020c4000 {
                                compatible = "fsl,imx6q-ccm";
                                reg = <0x020c4000 0x4000>;
                                interrupts = <0 87 0x04 0 88 0x04>;
                                #clock-cells = <1>;
                        };

在 Documentation/devicetree/bindings/clock/imx6q-clock.txt 有清楚的說明:

每個使用clk 的裝置(consumer) 都要在 device tree 中指名使用到的 clk id
imx bsp 把所有的 clk 排列在一起,並且給每個clk 一個index

        Clock                   ID
        ---------------------------
        dummy                   0
        ckil                    1
        ckih                    2
        osc                     3
        pll2_pfd0_352m          4
        pll2_pfd1_594m          5
        pll2_pfd2_396m          6
        pll3_pfd0_720m          7
        pll3_pfd1_540m          8
        pll3_pfd2_508m          9
        pll3_pfd3_454m          10
        pll2_198m               11
        pll3_120m               12
        pll3_80m                13
        pll3_60m                14
        twd                     15
        step                    16
        pll1_sw                 17
        periph_pre              18
        periph2_pre             19
        periph_clk2_sel         20
        periph2_clk2_sel        21
        axi_sel                 22
        esai_sel                23
        spdif1_sel              24
        spdif_sel               25
        ...

這個表其實宣告在 clk-imx6q.c 的 enum mx6q_clks {}

系統clock 的 device node:
Examples:

clks: ccm@020c4000 {
        compatible = "fsl,imx6q-ccm";
        reg = <0x020c4000 0x4000>;
        interrupts = <0 87 0x04 0 88 0x04>;
        #clock-cells = <1>;
};

以 serial port (UART) 為例,他使用兩種clk, ipg, serial, 所以 device node 是:
uart1: serial@02020000 {
        compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
        reg = <0x02020000 0x4000>;
        interrupts = <0 26 0x04>;
        clocks = <&clks 160>, <&clks 161>;
        clock-names = "ipg", "per";
        status = "disabled";
};
idex 分別是 160, 161


clock 的 hierachy 是寫在 clk-imx6q.c:
imx6q_clocks_init( ):
約略是由上而下...
        clk[dummy] = imx_clk_fixed("dummy", 0);
        clk[ckil] = imx_obtain_fixed_clock("ckil", 0);
        clk[ckih] = imx_obtain_fixed_clock("ckih1", 0);
        clk[osc] = imx_obtain_fixed_clock("osc", 0);
        /* Clock source from external clock via ANACLK1/2 PADs */
        clk[anaclk1] = imx_obtain_fixed_clock("anaclk1", 0);
        clk[anaclk2] = imx_obtain_fixed_clock("anaclk2", 0);
ckil : external low freq
ckih : external high freq clock and internal oscillator
osc : the 24MHz
anaclk1, anaclk2 : another external osc in

這幾個 最源頭的 clk 都定義在 dts 中。

最後系統的 clk hierachy, 在 debugfs 中可以看到: wondboard:
root@wandboard:/sys/kernel/debug/clk # busybox find . -name 'esai*'
./osc/pll2_bus/pll2_pfd2_396m/periph_pre/periph/ahb/esai_ipg
./osc/pll2_bus/pll2_pfd2_396m/periph_pre/periph/ahb/esai_mem
./osc/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel
./osc/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel/esai_pred
./osc/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel/esai_pred/esai_podf
./osc/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel/esai_pred/esai_podf/esai_extal
sabreauto:
root@sabreauto_6q:/sys/kernel/debug/clk # busybox find . -name 'esai*'
./osc/pll2_bus/pll2_pfd2_396m/periph_pre/periph/ahb/esai_ipg
./osc/pll2_bus/pll2_pfd2_396m/periph_pre/periph/ahb/esai_mem
./anaclk2/lvds2_in/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel
./anaclk2/lvds2_in/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel/esai_pred
./anaclk2/lvds2_in/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel/esai_pred/esai_podf
./anaclk2/lvds2_in/pll4_sel/pll4_audio/pll4_post_div/pll4_audio_div/esai_sel/esai_pred/esai_podf/esai_extal
因為 mach-imx6q.c 的 ..
static void __init imx6q_audio_lvds2_init(void)
{
        struct clk *pll4_sel, *lvds2_in, *pll4_audio_div, *esai_extal;

        printk("%s\n",__func__);

        pll4_audio_div = clk_get_sys(NULL, "pll4_audio_div");
        pll4_sel = clk_get_sys(NULL, "pll4_sel");
        lvds2_in = clk_get_sys(NULL, "lvds2_in");
        esai_extal = clk_get_sys(NULL, "esai_extal");
        if (IS_ERR(pll4_audio_div) || IS_ERR(pll4_sel) ||
            IS_ERR(lvds2_in) || IS_ERR(esai_extal))
                return;

        if (clk_get_rate(lvds2_in) != ESAI_AUDIO_MCLK)
                return;

        clk_set_parent(pll4_sel, lvds2_in);
        clk_set_rate(pll4_audio_div, 786432000);
        clk_set_rate(esai_extal, ESAI_AUDIO_MCLK);
}
把 pll4_sel 的 parent 改到 lvds2_in
pll4_sel 的 parent 可以是:
{ "osc", "lvds1_in", "lvds2_in", "dummy", }


2016/2/18

from: http://www.cnblogs.com/enyusmile/p/4442077.html

说明:

我的操作系统环境:ubuntu 14.04 LTS 64位

进入源代码根目录
. build/envsetup.sh(让mmm起作用)
mmm development/tools/idegen/(生成idegen.jar等文件)
sh ./development/tools/idegen/idegen.sh(生成android.irp等文件)
打开android studio导入源码里的android.irp文件(打开Android studio,点击File > Open,选择刚刚生成的android.ipr即可)

    参考:http://www.jianshu.com/p/c85984cf99e2
        http://www.cnblogs.com/qianxudetianxia/p/3721202.html
        http://blog.csdn.net/zhenwenxian/article/details/7102049

ref:
其他:
wand 已經 build 好, robotimxsd
先在 wand 上看 run 起來?
follow instruction build idesign.jar
..

2016/2/16

bitbake 是用 python 寫的tool
他依照bitbake metadata (.bbclass, .bb) 的task內容,判斷task 的dependency, 安排 build 的順序。

bitbake 安裝完,會有一個 class/base.bbclass , 這是基本的 metadata, 會被所有的 metadata include
所以所有project(/task)共同的部份,可以寫在這裡。

openembedded ..

ref: http://www.openembedded.org/wiki/OE-Core_Standalone_Setup

所以 oe 跟 yocto 根本一樣。

-- 有被proxy 檔的可以改clone github mirror, 有 https : http://www.openembedded.org/wiki/Mirrors

大概就是 clone oe-core, 再到oe-core 下面 clone bitbake.
然後 run envsetup, 指定 build 目錄。
然後就開使用bitbake build

 /oe-core
  |
  +- bitbake
  |
  +- meta(s)
  |
  +- scripts
因為oe-core 自己是一個 git project, 所以bitbake 有被寫進 .gitignore 中。


這一篇有說為什麼: http://stackoverflow.com/questions/35904769/what-are-the-differences-between-open-embedded-core-and-meta-openembedded
At the start of the OpenEmbedded Project, there was only one set of recipes. By 2010, the sheer size of the meta-data was a problem. (You can see the old repository here: https://github.com/openembedded/openembedded) The start of the Yocto Project provided manpower to do something OpenEmbedded had talked about for years, start splitting the recipes into useful and easier to maintain subsets. Openembedded-core are the set of recipes that most people need to use to build a small, useful embedded device. Meta-openembedded was everything else. The meta-openembedded layers are used to extend the capability of openembedded-core by increasing the number of recipes to build more software for your project. Since then, we have been working on meta-openembedded to divide it into smaller groups of recipes grouped by technology, which is why meta-openembedded contains several layers now.
大概是說,openembedded 只有一個 recipts, meta-openembedded 就做openedbedded 沒包到的 recipts
yocto 就利用多 recipts 的方法做出一堆公能。

2016/2/2

wandboard, yocto

follow : http://wiki.wandboard.org/Getting_started_with_Yocto_on_Wandboard
但是只能用 dizzy
一樣..

repo init -u https://github.com/Freescale/fsl-community-bsp-platform -b dizzy
repo sync
然後..
export MACHINE=wandboard-dual
. setup-environment build
會到 build 目錄..
Welcome to Freescale Community BSP

The Yocto Project has extensive documentation about OE including a
reference manual which can be found at:
    http://yoctoproject.org/documentation

For more information about OpenEmbedded see their website:
    http://www.openembedded.org/

You can now run 'bitbake '

Common targets are:
    core-image-minimal
    meta-toolchain
    meta-toolchain-sdk
    adt-installer
    meta-ide-support

Your configuration files at build have not been touched.
myserver:~/wandyocto/build$ 
然後build.. minimal..
bitbake core-image-minimal
build 好的東西會在..
build/tmp/deploy/images/wandboard-dual/
其中的 core-image-minimal-wandboard-dual.sdcard 就是 sd card image,
直接 dd 到 sd card 就可以。

開機以後,會出現 login prompt, default username=root, 沒有 password