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...
注音輸入還是有點問題,....