ubuntu 在 R40e 上 還有 Debian 在 Sempron 2600 上

2014年3月25日 星期二

Dynamic Audio Power Management管理的包含 codec 和 machine level 的 power system.

DAPM 把系統分為四個 domain:
  • Codec domain -- 通常只有在codec probe/remove, suspend/resume 時才會控制到這個 domain 的 power.
  • Platform/Machine domain -- input, output path 的控制,通常由 machine level 的 code 控制,經由 asynchronous event 觸發,例如: HP inserted.
  • Path domain -- audio subsystem signal paths. 當 user program(e.g. alsamixer, amixer) 更改 mux, mixer 設定時,就會設定這個 domain 的 power.
  • Stream domain -- DAC 和 ADC, 當 playback/capture 開始,停止時,就會動用到這個 domain 的 power.

2014年3月19日 星期三

from System Server to Input fd

framewors/base/services/java/com/android/server/SystemServer.java --> WindowManagerService.main( )

frameworks/base/services/java/com/android/server/WindowManagerService.java --> new InputManager( )

frameworks/base/services/java/com/android/server/InputManager.java --> nativeInit( )

frameworks/base/services/jni/com_android_server_InputManager.cpp --> new NativeInputManager( )
--> new InputManager( )

frameworks/base/libs/ui/InputManager.cpp --> new InputReaderThread( )

frameworks/base/libs/ui/InputReader.cpp --> loopOnce( ) --> mEventHub->getEvent( )

frameworks/base/libs/ui/EventHub.cpp --> getEvent( )
            const struct pollfd& pfd = mFDs[mInputDeviceIndex];
            if (pfd.revents & POLLIN) {
                       readSize = read(pfd.fd, mInputBufferData,sizeof(struct input_event) * INPUT_BUFFER_SIZE);
                       mInputBufferCount = readSize / sizeof(struct input_event);
                       mInputBufferIndex = 0;
             }

            if (mInputBufferIndex < mInputBufferCount) {
                       const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
                       const device_t* device = mDevices[mInputDeviceIndex];
             

read(mFDs[mInputDeviceIndex].fd..)
mFDs[] 是 /dev/input node

read 的內容 (struct input_event) 是定義在 kernel/include/linux/input.h:
struct input_event {
        struct timeval time;
        __u16 type;
        __u16 code;
        __s32 value;
};

2014年3月18日 星期二

alsa device ioctl

利用 device 的 hwdep 介面 call ioctl:

Android.mk :
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CFLAGS := \
        -fPIC -D_POSIX_SOURCE \
        -DALSA_CONFIG_DIR=\"/system/usr/share/alsa\" \
        -DALSA_PLUGIN_DIR=\"/system/usr/lib/alsa-lib\" \
        -DALSA_DEVICE_DIRECTORY=\"/dev/snd/\"

LOCAL_C_INCLUDES := \
        external/alsa-lib/include

LOCAL_SRC_FILES := \
        asound_ioctl.c


LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := asound_ioctl

LOCAL_SHARED_LIBRARIES := \
        libaudio \
        libasound \
        libc

include $(BUILD_EXECUTABLE)

要給alsa-lib 的 path

...
...
其中 rt56xx_ioctl.h 就是 alsa device rt56xx 的 driver header, 從 kernel code copy 出來的..
#include <linux/ioctl.h>

struct rt56xx_cmd {
        size_t number;
        int *buf;
};

enum {
        RT_READ_CODEC_REG_IOCTL = _IOR('R', 0x01, struct rt56xx_cmd),
        RT_WRITE_CODEC_REG_IOCTL = _IOW('R', 0x01, struct rt56xx_cmd),
        RT_READ_ALL_CODEC_REG_IOCTL = _IOR('R', 0x02, struct rt56xx_cmd),
        RT_READ_CODEC_INDEX_IOCTL = _IOR('R', 0x03, struct rt56xx_cmd),
        RT_WRITE_CODEC_INDEX_IOCTL = _IOW('R', 0x03, struct rt56xx_cmd),
        RT_READ_CODEC_DSP_IOCTL = _IOR('R', 0x04, struct rt56xx_cmd),
        RT_WRITE_CODEC_DSP_IOCTL = _IOW('R', 0x04, struct rt56xx_cmd),
        RT_SET_CODEC_HWEQ_IOCTL = _IOW('R', 0x05, struct rt56xx_cmd),
        RT_GET_CODEC_HWEQ_IOCTL = _IOR('R', 0x05, struct rt56xx_cmd),
        RT_SET_CODEC_SPK_VOL_IOCTL = _IOW('R', 0x06, struct rt56xx_cmd),
        RT_GET_CODEC_SPK_VOL_IOCTL = _IOR('R', 0x06, struct rt56xx_cmd),
        RT_SET_CODEC_MIC_GAIN_IOCTL = _IOW('R', 0x07, struct rt56xx_cmd),
        RT_GET_CODEC_MIC_GAIN_IOCTL = _IOR('R', 0x07, struct rt56xx_cmd),
        RT_SET_CODEC_3D_SPK_IOCTL = _IOW('R', 0x08, struct rt56xx_cmd),
        RT_GET_CODEC_3D_SPK_IOCTL = _IOR('R', 0x08, struct rt56xx_cmd),
        RT_SET_CODEC_MP3PLUS_IOCTL = _IOW('R', 0x09, struct rt56xx_cmd),
        RT_GET_CODEC_MP3PLUS_IOCTL = _IOR('R', 0x09, struct rt56xx_cmd),
        RT_SET_CODEC_3D_HEADPHONE_IOCTL = _IOW('R', 0x0a, struct rt56xx_cmd),
        RT_GET_CODEC_3D_HEADPHONE_IOCTL = _IOR('R', 0x0a, struct rt56xx_cmd),
        RT_SET_CODEC_BASS_BACK_IOCTL = _IOW('R', 0x0b, struct rt56xx_cmd),
        RT_GET_CODEC_BASS_BACK_IOCTL = _IOR('R', 0x0b, struct rt56xx_cmd),
        RT_SET_CODEC_DIPOLE_SPK_IOCTL = _IOW('R', 0x0c, struct rt56xx_cmd),
        RT_GET_CODEC_DIPOLE_SPK_IOCTL = _IOR('R', 0x0c, struct rt56xx_cmd),
        RT_SET_CODEC_DRC_AGC_ENABLE_IOCTL = _IOW('R', 0x0d, struct rt56xx_cmd),
        RT_GET_CODEC_DRC_AGC_ENABLE_IOCTL = _IOR('R', 0x0d, struct rt56xx_cmd),
        RT_SET_CODEC_DSP_MODE_IOCTL = _IOW('R', 0x0e, struct rt56xx_cmd),
        RT_GET_CODEC_DSP_MODE_IOCTL = _IOR('R', 0x0e, struct rt56xx_cmd),
        RT_SET_CODEC_WNR_ENABLE_IOCTL = _IOW('R', 0x0f, struct rt56xx_cmd),
        ....


2014年3月7日 星期五

alsa device node

alsa device 的列表:
$ cat /proc/asound/devices
 0: [ 0]   : control
 16: [ 0- 0]: digital audio playback
 24: [ 0- 0]: digital audio capture
 32: [ 1]   : control
 33:        : timer
 48: [ 1- 0]: digital audio playback
 56: [ 1- 0]: digital audio capture
 64: [ 2]   : control
 80: [ 2- 0]: digital audio playback
 96: [ 3]   : control
100: [ 3- 0]: hardware dependent
112: [ 3- 0]: digital audio playback
120: [ 3- 0]: digital audio capture
第一行的數字就是 device node 的 minor number


對應到 /dev/snd/ 下:
bash-4.2# ls -l /dev/snd
crw-rw-rw-    1 1000     1005       14,   4 Jan  1  1970 audio
crw-rw-rw-    1 1000     1005       14,  20 Jan  1  1970 audio1
crw-rw-rw-    1 1000     1005       14,  36 Jan  1  1970 audio2
crw-rw-rw-    1 1000     1005       14,  52 Jan  1  1970 audio3
crw-rw-rw-    1 1000     1005      116,   0 Jan  1  1970 controlC0
crw-rw-rw-    1 1000     1005      116,  32 Jan  1  1970 controlC1
crw-rw-rw-    1 1000     1005      116,  64 Jan  1  1970 controlC2
crw-rw-rw-    1 1000     1005      116,  96 Jan  1  1970 controlC3
crw-rw----    1 1000     1005       14,   3 Jan  1  1970 dsp
crw-rw----    1 1000     1005       14,  19 Jan  1  1970 dsp1
crw-rw-rw-    1 1000     1005       14,  35 Jan  1  1970 dsp2
crw-rw-rw-    1 1000     1005       14,  51 Jan  1  1970 dsp3
crw-rw-rw-    1 1000     1005      116, 100 Jan  1  1970 hwC3D0
crw-rw----    1 1000     1005       14,   0 Jan  1  1970 mixer
crw-rw-rw-    1 1000     1005       14,  16 Jan  1  1970 mixer1
crw-rw-rw-    1 1000     1005       14,  32 Jan  1  1970 mixer2
crw-rw-rw-    1 1000     1005       14,  48 Jan  1  1970 mixer3
crw-rw-rw-    1 1000     1005      116,  24 Jan  1  1970 pcmC0D0c
crw-rw-rw-    1 1000     1005      116,  16 Jan  1  1970 pcmC0D0p
crw-rw-rw-    1 1000     1005      116,  56 Jan  1  1970 pcmC1D0c
crw-rw-rw-    1 1000     1005      116,  48 Jan  1  1970 pcmC1D0p
crw-rw-rw-    1 1000     1005      116,  80 Jan  1  1970 pcmC2D0p
crw-rw-rw-    1 1000     1005      116, 120 Jan  1  1970 pcmC3D0c
crw-rw-rw-    1 1000     1005      116, 112 Jan  1  1970 pcmC3D0p
crw-rw-rw-    1 1000     1005      116,  33 Jan  1  1970 timer
可以看到 major, minor number.

對照,
bash-4.2# alsa_aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: ssfinneraudi [SSF internal audio], device 0: SSF internal audio [SSF internal audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 1: csrbtcodec [ccs-btcodec], device 0: btcodec hifi btcodec-usppcm-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: ssochdmi [ssoc-hdmi], device 0: HDMI ssoc-hdmi-audio-codec-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 3: ssocrt5625 [ssoc-rt5625], device 0: RT5625 rt5625-aif1-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

2014年3月4日 星期二

sound soc codec driver reading notes..

http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/sound/alsa/soc/DAI.txt?h=linux-3.0.y

DAI : Digital Audio Interface
I2S
===

 I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and
Rx lines are used for audio transmission, whilst the bit clock (BCLK) and
left/right clock (LRC) synchronise the link. I2S is flexible in that either the
controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
usually varies depending on the sample rate and the master system clock
(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
ADC and DAC LRCLKs, this allows for simultaneous capture and playback at
different sample rates.

I2S has several different operating modes:-

 o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC
         transition.

 o Left Justified - MSB is transmitted on transition of LRC.

 o Right Justified - MSB is transmitted sample size BCLKs before LRC
                     transition.


http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/sound/alsa/soc/machine.txt?h=linux-3.0.y

就是 board 的 driver, 聯繫 chip 的 i2s 和 外接的 codec.

Machine DAI Configuration
-------------------------
The machine DAI configuration glues all the codec and CPU DAIs together. It can
also be used to set up the DAI system clock and for any machine related DAI
initialisation e.g. the machine audio map can be connected to the codec audio
map, unconnected codec pins can be set as such. Please see corgi.c, spitz.c
for examples.

struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.

/* corgi digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link corgi_dai = {
 .name = "WM8731",
 .stream_name = "WM8731",
 .cpu_dai_name = "pxa-is2-dai",
 .codec_dai_name = "wm8731-hifi",
 .platform_name = "pxa-pcm-audio",
 .codec_name = "wm8713-codec.0-001a",
 .init = corgi_wm8731_init,
 .ops = &corgi_ops,
};

struct snd_soc_card then sets up the machine with its DAIs. e.g.

/* corgi audio machine driver */
static struct snd_soc_card snd_soc_corgi = {
 .name = "Corgi",
 .dai_link = &corgi_dai,
 .num_links = 1,
};

有關 I2S master/slave 的定義/操作..
http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/include/sound/soc-dai.h?h=linux-3.0.y#n66

/*
 * DAI hardware clock masters.
 *
 * This is wrt the codec, the inverse is true for the interface
 * i.e. if the codec is clk and FRM master then the interface is
 * clk and frame slave.
 */
#define SND_SOC_DAIFMT_CBM_CFM  (0 << 12) /* codec clk & FRM master */
#define SND_SOC_DAIFMT_CBS_CFM  (1 << 12) /* codec clk slave & FRM master */
#define SND_SOC_DAIFMT_CBM_CFS  (2 << 12) /* codec clk master & frame slave */
#define SND_SOC_DAIFMT_CBS_CFS  (3 << 12) /* codec clk & FRM slave */

有兩路
  • AIF1 : stereo
  • AIF2 : voice

可以使用各自的 clock source.

clock source 的選擇有:
  • MCLK : 就是 I2S 的 MCLK
  • PLL : 振盪器輸入,經由內部 PLL 倍頻
這個動作是由 set_dai_sysclk( ) 完成的。

這個也屬於alsa arch 標準 module interface 之一:
snd_soc_dai_ops 中的 set_sysclk:

struct snd_soc_dai_ops {
        /*
         * DAI clocking configuration, all optional.
         * Called by soc_card drivers, normally in their hw_params.
         */
        int (*set_sysclk)(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir);
        int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out);
        int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);

        /*
         * DAI format configuration
         * Called by soc_card drivers, normally in their hw_params.
         */
        int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
        int (*set_tdm_slot)(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
        int (*set_channel_map)(struct snd_soc_dai *dai, unsigned int tx_num, unsigned int *tx_slot, unsigned int rx_num, unsigned int *rx_slot);
        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);

        /*
         * DAI digital mute - optional.
         * Called by soc-core to minimise any pops.
         */
        int (*digital_mute)(struct snd_soc_dai *dai, int mute);

        /*
         * ALSA PCM audio operations - all optional.
         * Called by soc-core during audio PCM operations.
         */
        int (*startup)(struct snd_pcm_substream *, struct snd_soc_dai *);
        void (*shutdown)(struct snd_pcm_substream *, struct snd_soc_dai *);
        int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *, struct snd_soc_dai *);
        int (*hw_free)(struct snd_pcm_substream *, struct snd_soc_dai *);
        int (*prepare)(struct snd_pcm_substream *, struct snd_soc_dai *);
        int (*trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *);
        /*
         * For hardware based FIFO caused delay reporting.
         * Optional.
         */
        snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, struct snd_soc_dai *);
};
structure 間的關係
snd_soc_card
   |
   + dai_link --- snd_soc_dai_link
                     |
                     + ops ---------------- snd_soc_ops
                     |                         |
                     |                         + hw_params
                     + stream name
                     |
                     + cpu dai name
                     |
                     + codec dai name
                     |
                     + codec name
                     |
                     + platform name

標籤

網誌存檔