레이블이 IF-SDCard인 게시물을 표시합니다. 모든 게시물 표시
레이블이 IF-SDCard인 게시물을 표시합니다. 모든 게시물 표시

2/13/2020

SD/MMC 와 udev 재분석 과 Rule 생성

1.  SD/MMC Spec 및 기본확인법 

MMC 혹은 SDCard 관련 Spec을 다시 확인하고자 한다면 아래의 사이트에서 확인




  • MMC(SDCARD) 관련 Spec
  1. Part 1. Physical Layer Simplified Specification 
  2. Part A2. SD Host Controller Simplified Specification
  3. Part E1. SDIO Simplified Specification 
  4. Part E7. Wireless LAN Simplified Addendum
  5. 이외 
대부분의 기본적인 내용은 Part1. Physical Layer Simplified Specification 을 보면 구조 및 기본동작이 이해가가능하며,
UHS-II 관련부분이나 다른 SD 확장 API를 본다면 해당 문서를 참조

SD/MMC 관련 Spec Download
  https://www.sdcard.org/downloads/pls/

1.1 SD/MMC 정보확인 

SD/MMC 기본 Register


  • SD/MMC Register 확인 
$ find /sys -name cid  // CID Register 제조사 및 제품정보 파악가능 (Spec참조)
/sys/devices/soc0/soc/2100000.aips-bus/219c000.usdhc/mmc_host/mmc3/mmc3:0001/cid     //eMMC
/sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/cid     //SDCard 

$ find /sys -name csd //CSD를 통해 MMC의 Spec 및 성능파악 (Spec참조)
/sys/devices/soc0/soc/2100000.aips-bus/219c000.usdhc/mmc_host/mmc3/mmc3:0001/csd //eMMC
/sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/csd //SDCard 

$ find /sys -name scr // SDCard에 설정된 기본정보 (Databit,SDCard 종류) 확인가능 (Spec)
/sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/scr  //SDCard 

$ find /sys -name dsr or rca or ocr //기타정보들 
  • SD/MMC 기본정보파악 
$ find /sys -name ios // 쉽게 MMC의 정보파악 
/sys/kernel/debug/mmc3/ios  //eMMC
/sys/kernel/debug/mmc2/ios  //SDCard

$ cat /sys/kernel/debug/mmc3/ios  //eMMC 8bit
clock:          198000000 Hz
actual clock:   198000000 Hz
vdd:            21 (3.3 ~ 3.4 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      3 (8 bits)
timing spec:    9 (mmc HS200)
signal voltage: 1 (1.80 V)
driver type:    0 (driver type B)

$ cat /sys/kernel/debug/mmc2/ios  //SD Card 4bit
clock:          50000000 Hz
actual clock:   49500000 Hz
vdd:            18 (3.0 ~ 3.1 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      2 (4 bits)
timing spec:    2 (sd high-speed)
signal voltage: 0 (3.30 V)
driver type:    0 (driver type B) 
  • SD Card의 경우 CD(Card Detection)/WP(Write Protection) 
$ cat /proc/interrupts | egrep "(mmc|cd)" // SDCard는 Hotplug를 위해 CD필요 
 63:        676       GPC  24 Level     mmc2  //SDCard
 64:       9336       GPC  25 Level     mmc3  //eMMC 
 78:          0       GPC   6 Edge      2224000.lcdif
126:          3  gpio-mxc  10 Edge      2198000.usdhc cd  //SDCard Card Detection (Hotplug)

// SD Card Detection의 GPIO 및 Trigger 및 IRQ 확인 
$ cat /sys/kernel/debug/gpio | grep cd  
 gpio-42  (                    |cd                  ) in  hi IRQ 
SD Card의 경우 CD 와 WP Pin을 GPIO로 연결하여 사용가능하며, 주로 CD 사용할 경우 Hotplug가능. WP 미사용

eMMC/SD Card 관련참고사항
  https://developer.toradex.com/knowledge-base/sd-mmc-card-(linux)

1.2 SD/MMC의 Kernel 관련정보 

  • i.MX Kernel Config
  1. MMC/SD/SDIO (CONFIG_MMC)
  2. MMC block (CONFIG_MMC_BLOCK)
  3. Secure Digital Host Controller Interface support (CONFIG_MMC_SDHCI)
  4. SDHCI support on the platform-specific bus (CONFIG_MMC_SDHCI_PLTFM)
  5. SDHCI platform support for the NXP eSDHC i.MX controller (CONFIG_MMC_SDHCI_ESDHC_IMX)

  • Kernel source의 drivers/mmc/host/  
  1. sdhci.c standard stack code
  2. sdhci-pltfm.c sdhci platform layer
  3. sdhci-esdhc.c uSDHC driver
  4. sdhci-esdhc-imx.c uSDHC driver header file

세부사항은 아래사이트 참고

  • i.MX 관련설정 (출처) 
MMC/SDCard/SDIO Kernel 설정을 비롯하여Device Tree 설정정보를제공
  https://www.digi.com/resources/documentation/digidocs/90001546/reference/bsp/cc6/r_mmc-sd-sdio.htm


  • MMC/SD Device Driver 세부분석 
새로 SD/MMC를 분석할 필요는 없는 것 같아 아래사이트를 참조하여 이해만하고 넘어감
  http://egloos.zum.com/furmuwon/v/11167927

  • SDCard 관련부분 Uboot 및 Kernel 설정 (Sitara/i.MX)
아래사이트에서 쉽게 설정이 가능하도록 제공
  https://www.digikey.com/eewiki/pages/viewpage.action?pageId=35193201#BeagleBoneBlack-uEnv.txtbasedbootscript
  https://www.digikey.com/eewiki/display/linuxonarm/i.MX6+SABRE+Lite
  https://developer.toradex.com/knowledge-base/sd-mmc-card-(linux)


1.3  Kernel의 Netlink uevent 와 udev 통신 

Kernel은 udevNETLINK_KOBJECT_UEVENT로 통신을 하고 있으며, 이곳에 add_uevent_var의 환경설정값을 추가하여 통신을 진행한다.
Kernel은 이외에도 다른 NETLINK도 사용하니 이것만 사용한다고 착각하지말자.

  • udev의 NETLINK_KOBJECT_UEVENT
ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
user에서 socket으로 protocol을 NETLINK_KOBJECT_UEVENT로 설정 
  https://elixir.bootlin.com/linux/v4.20.4/source/lib/kobject_uevent.c#L751

  • SD/MMC 관련소스
아래부분은 SD/MMC에서 공통으로사용되는 부분으로 필요할때만 보고, Chip Vendor관련부분은 상위에서 처럼 관련부분은 별도로 보자.
  https://elixir.bootlin.com/linux/v4.17.19/source/drivers/mmc/core
  https://elixir.bootlin.com/linux/v4.17.19/source/drivers/mmc/core/mmc.c

  • kobject_uevent->kobject_uevent_env
보통 uevent는 아래와 같이 동작을 하며, 아래와 같이 각각의 환경변수값을 uevent와 함께보내면, udevd은 이를 받아 database로 기록하여 사용한다고한다.
  1. retval = add_uevent_var(env, "ACTION=%s", action_string);
  2. retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  3. retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  4. retval = add_uevent_var(env, "%s", envp_ext[i]);  // 상위 NULL 이지만 sys에서 설정가능
  5. retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
  6. 기타 값 
  https://elixir.bootlin.com/linux/v4.20.4/source/lib/kobject_uevent.c#L454


  • kobject_synth_uevent 관련함수
  https://elixir.bootlin.com/linux/v4.20.4/source/lib/kobject_uevent.c#L192


  • kobject_uevent_env 의 확장값을 넣어 전송
  1. LEASE=1    :  상위 3번의 envp_ext[i] 값 설정 
  2. HOTPLUG=1 : 상위 3번의 envp_ext[i] 값 설정 
  https://elixir.bootlin.com/linux/v4.20.4/source/drivers/gpu/drm/drm_sysfs.c#L322
  https://elixir.bootlin.com/linux/v4.20.4/source/drivers/gpu/drm/drm_sysfs.c#L304


  • kobject 와 sysfiletem을 세부적으로 분석 (반드시 참고)
*** 관련내용을 찾다가 아래사이트에서 자세히 분석해줘서 이해하기가 더 쉬움 (감사할 따름)
  http://jake.dothome.co.kr/kobject/


  • device driver의 attribute의 구성을 쉽게 이해가능 (sys file system 구성)
attribute는 sys filesystem의 구성이기때문에 반드시 사용법 숙지하며, 이외에도 가끔 소스를 보면 다른 것도 존재하는 것 같은데, 그 부분은 추후 추가
  1. device_attribute
  2. bus_attribute
  3. class_attribute
  4. driver_attribute

오래전의 linux kernel과 attribute설정방법은 조금 다르지만 거의 비슷함
  http://jake.dothome.co.kr/device-driver-1/

2. udev 분석 및 테스트진행 

현재 udevadm command로 통합이되어 관련명령어를 모두 사용이 가능하며, 이를 이용하여 udev의 정보 및 테스트도 진행이 가능하다.

$ udevadm -h
udevadm [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]

Send control commands or test the device manager.

Commands:
  info          Query sysfs or the udev database  //
  trigger       Request events from the kernel
  settle        Wait for pending udev events
  control       Control the udev daemon
  monitor       Listen to kernel and udev events
  test          Test an event run
  test-builtin  Test a built-in command


  http://fibrevillage.com/sysadmin/93-udevadm-command-examples

2.1 udevadm info 기본분석방법 

udevadm info를 이용하여 udev의 database 정보와 sysfs 정보를 확인가능하므로, 이를 이용하여 udev 분석이 쉬어진다.

$ udevadm info  -h
udevadm info [OPTIONS] [DEVPATH|FILE]

Query sysfs or the udev database.

  -h --help                   Print this message
  -V --version                Print version of the program
  -q --query=TYPE             Query device information:
       name                     Name of device node
       symlink                 Pointing to node
       path                     sysfs device path
       property                The device properties
       all                      All values
  -p --path=SYSPATH           sysfs device path used for query or attribute walk
  -n --name=NAME              Node or symlink name used for query or attribute walk
  -r --root                   Prepend dev directory to path names
  -a --attribute-walk         Print all key matches walking along the chain
                              of parent devices
  -d --device-id-of-file=FILE Print major:minor of device containing this file
  -x --export                 Export key/value pairs
  -P --export-prefix          Export the key name with a prefix
  -e --export-db              Export the content of the udev database
  -c --cleanup-db             Clean up the udev database



  • sys filesystem의 uevent의 환경변수 값 확인 (udev database정보)
$ udevadm info  /dev/mmcblk2p1 
or
$ udevadm info  -q all /dev/mmcblk2p1 
or
$ udevadm info  /sys/block/mmcblk2/mmcblk2p1  // 3개의 정보들이 거의 동일하지만,DEVLINKS정보가 조금씩 다름 
// /sys/device/..../mmcblk2p1의 uevnet 파악가능 (P는 /sys PATH)
P: /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1     
N: mmcblk2p1   // /dev의 device node /dev/mmcblk2p1 
S: disk/by-id/mmc-SA02G_0x207dfb75-part1       // 상위 N의 /dev/mmcblk2p1 의 link file /dev/disk/by-id/mmc-SA02G_0x207dfb75-part1
S: disk/by-partuuid/0006c3b0-01                // 상위 N의 /dev/mmcblk2p1 의 link file /dev/disk/by-partuuid/0006c3b0-0
S: disk/by-path/platform-2198000.usdhc-part1   // 상위 N의 /dev/mmcblk2p1 의 link file /dev/disk/by-path/platform-2198000.usdhc-part1
S: disk/by-uuid/1497-59AD                      // 상위 N의 /dev/mmcblk2p1 의 link file /dev/disk/by-uuid/1497-59AD
E: DEVLINKS=/dev/disk/by-path/platform-2198000.usdhc-part1 /dev/disk/by-uuid/1497-59AD /dev/disk/by-partuuid/0006c3b0-01 /dev/disk/by-id/mmc-SA02G_0x207dfb75-part1
E: DEVNAME=/dev/mmcblk2p1
E: DEVPATH=/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1
E: DEVTYPE=partition
E: ID_FS_TYPE=vfat
E: ID_FS_USAGE=filesystem
E: ID_FS_UUID=1497-59AD
E: ID_FS_UUID_ENC=1497-59AD
E: ID_FS_VERSION=FAT32
E: ID_NAME=SA02G
E: ID_PART_ENTRY_DISK=179:24
E: ID_PART_ENTRY_NUMBER=1
E: ID_PART_ENTRY_OFFSET=73036
E: ID_PART_ENTRY_SCHEME=dos
E: ID_PART_ENTRY_SIZE=3002164
E: ID_PART_ENTRY_TYPE=0xc
E: ID_PART_ENTRY_UUID=0006c3b0-01
E: ID_PART_TABLE_TYPE=dos
E: ID_PART_TABLE_UUID=0006c3b0
E: ID_PATH=platform-2198000.usdhc
E: ID_PATH_TAG=platform-2198000_usdhc
E: ID_SERIAL=0x207dfb75
E: MAJOR=179
E: MINOR=25
E: PARTN=1
E: SUBSYSTEM=block
E: TAGS=:systemd:                   //  systemd의 *.device로 파일에서 추가됨 
E: USEC_INITIALIZED=7347510      //  cat /proc/uptime 갱신된 정보시간 (boot이후)

$ udevadm info  /dev/mmcblk2
or
$ udevadm info  -q all /dev/mmcblk2
or
$ udevadm info  /sys/block/mmcblk2
P: /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2 // uevent 정보확인 
N: mmcblk2
S: disk/by-id/mmc-SA02G_0x207dfb75
S: disk/by-path/platform-2198000.usdhc
E: DEVLINKS=/dev/disk/by-id/mmc-SA02G_0x207dfb75 /dev/disk/by-path/platform-2198000.usdhc
E: DEVNAME=/dev/mmcblk2
E: DEVPATH=/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2
E: DEVTYPE=disk
E: ID_NAME=SA02G
E: ID_PART_TABLE_TYPE=dos
E: ID_PART_TABLE_UUID=0006c3b0
E: ID_PATH=platform-2198000.usdhc
E: ID_PATH_TAG=platform-2198000_usdhc
E: ID_SERIAL=0x207dfb75
E: MAJOR=179
E: MINOR=24
E: SUBSYSTEM=block
E: TAGS=:systemd:             //  systemd의 *.device로 파일에서 추가됨 
E: USEC_INITIALIZED=6995415  //  cat /proc/uptime 갱신된 정보시간 (boot이후)


TAGS=:systemd 일 경우 systemd의 *.device로 udev rule에 추가
  https://www.freedesktop.org/software/systemd/man/systemd.device.html

systemd-udevd service 

  • 좌측 Node 의미 및 분석방법 
  1. N: is for device Name in /dev
  2. S: is for Symlinks to that device name in /dev  (추후 udev/rules/에서 SYMLINK)
  3. P: is for device Path in /sys
  4. E: is for device properties in udev
  https://askubuntu.com/questions/725951/what-do-devices-environment-variable-lists-prefixes-p-n-s-e-mean


  • P: Node는 /sys의 device path이므로 이곳의 uevent 를 확인중요
uevent 중심으로 분석을 해야함
$ cat /sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1/uevent
MAJOR=179
MINOR=25
DEVNAME=mmcblk2p1
DEVTYPE=partition
PARTN=1

$ cat /sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/uevent
MAJOR=179
MINOR=24
DEVNAME=mmcblk2
DEVTYPE=disk


  • N: /dev의 device name 확인
$ ls /dev/mmcblk*
/dev/mmcblk2       /dev/mmcblk3       /dev/mmcblk3boot1  /dev/mmcblk3p2
/dev/mmcblk2p1     /dev/mmcblk3boot0  /dev/mmcblk3p1     /dev/mmcblk3rpmb 

  • S:  상위 N: /dev의 device name의 symbolic link list 
상위 N:의 /dev/mmclbk2 or /dev/mmcblk2p1의 /dev 내의 symbolic link 말하며,이는 DEVLINKS와 동일하다.
rule에서도 SYMLINK을 이용하여 추가도 가능함

$ ls /dev/disk/by-id/
mmc-S0J57X_0x09231300        mmc-SA02G_0x207dfb75
mmc-S0J57X_0x09231300-part1  mmc-SA02G_0x207dfb75-part1
mmc-S0J57X_0x09231300-part2

$ ls /dev/disk/by-path/
platform-2198000.usdhc        platform-219c000.usdhc-boot1
platform-2198000.usdhc-part1  platform-219c000.usdhc-part1
platform-219c000.usdhc        platform-219c000.usdhc-part2
platform-219c000.usdhc-boot0

  • E: uevent를 통해 udev 설정된 환경값 
이부분은 아래와 기본정보는 /sys 의 uevent 로 확인가능하며, 다른정보는 database에서 가져옴

  • 이외 다른 uevent 값 검색 분석 
$ find /sys -name uevent | xargs cat  // 대부분 Device 정보 와 호환정보(연결)
....
MAJOR=253
MINOR=0
DEVNAME=rtc0
OF_NAME=snvs
OF_FULLNAME=/soc/aips-bus@2000000/snvs@20cc000
OF_COMPATIBLE_0=fsl,sec-v4.0-mon
OF_COMPATIBLE_1=syscon
OF_COMPATIBLE_2=simple-mfd
OF_COMPATIBLE_N=3
...
$ find /sys -name uevent | xargs cat | grep DEVLINKS
없음 
$ find /sys -name uevent | xargs cat | grep DEVNAME
DEVNAME=mem
DEVNAME=zero
DEVNAME=kmsg
DEVNAME=full
DEVNAME=urandom
DEVNAME=null
DEVNAME=random
DEVNAME=pxp_device
DEVNAME=hwrng
DEVNAME=autofs
......

2.2 udevadm info 의 attribute 분석 

udev의 기본적인 uevent의 정보와 sys filesystem의 attribute를 분석할때, -a를 옵션을 주어 분석이 가능하다.
ATTR{x}는 해당 /sys file 주소의 값들을 출력을 해주며, 추후 rule에서도 이를 적용가능하다.

  1. uevent 정보(KERNEL/SUBSYSTEM/DRIVER) 
  2. attribute 정보(ATTR{xxx}  

parent기반으로 분석되기때문에 호출되는 순서를 파악가능하며 최종단을 주목

$ udevadm info -a /dev/mmcblk2   // /dev node로  모든 attribute를 출력 
or
$ udevadm info -a /sys/block/mmcblk2  //sys filesystem의 모든 attribute를 출력 

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
// 아래 looking at device 위치에 /sys file의 uevent node 확인 (최종 device의 길이 중요)
  looking at device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2':  
    KERNEL=="mmcblk2"     //device의 node name (상위 device의 마지막 node)  uevent 정보는 별도의 db를 가지고 있음 
    SUBSYSTEM=="block"    //mmcblk2의 SUBSYSTEM   
    DRIVER==""            //uevent 의 정보 
    ATTR{alignment_offset}=="0"      // cat /sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/alignment_offset
    ATTR{capability}=="50"           // cat /sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/capability
    ATTR{discard_alignment}=="0"     // cat /sys/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/ext_range
    ATTR{ext_range}=="256"           //  ATTR{x} 모두 상동  
    ATTR{force_ro}=="0"
    ATTR{hidden}=="0"
    ATTR{inflight}=="       0        0"
    ATTR{range}=="8"
    ATTR{removable}=="0"
    ATTR{ro}=="0"
    ATTR{size}=="3842048"
    ATTR{stat}=="      95       16     6363      545        0        0        0        0        0      400      440        0        0        0        0"
// Parent device 의 uevent이며, 분석에 중요하며, SD Card Device의 정보를 얻은 시점 
  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234':  //   
    KERNELS=="mmc2:1234"
    SUBSYSTEMS=="mmc"
    DRIVERS=="mmcblk"
    ATTRS{cid}=="02544d534130324704207dfb7500a800"     // MMC의 Register CID  
    ATTRS{csd}=="002e00325b5aa3a9ffffff800a800000"     // MMC의 Register CSD   
    ATTRS{date}=="08/2010"                             // 날짜정보, Filesystem 기준으로 생각됨  
    ATTRS{dsr}=="0x404"                                // MMC의 Register DSR  
    ATTRS{erase_size}=="512"                           // MMC의 경우 512 block 단위임  
    ATTRS{fwrev}=="0x4"
    ATTRS{hwrev}=="0x0"
    ATTRS{manfid}=="0x000002"                          // 제조사 ID  
    ATTRS{name}=="SA02G"                               // SD Card Name 
    ATTRS{ocr}=="0x00040000"                           // MMC의 Register OCR  
    ATTRS{oemid}=="0x544d"
    ATTRS{preferred_erase_size}=="4194304"
    ATTRS{rca}=="0x1234"                               // MMC의 Register RCA  
    ATTRS{scr}=="0225800001000000"                     // MMC의 Register SCR  
    ATTRS{serial}=="0x207dfb75"
    ATTRS{ssr}=="00000000000000280202900100aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    ATTRS{type}=="SD"                                   // SD Card 임, eMMC가 아님  
// Parent device 의 uevent  SD Card Device를 찾은시점 
  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2':
    KERNELS=="mmc2"
    SUBSYSTEMS=="mmc_host"
    DRIVERS==""

  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc':
    KERNELS=="2198000.usdhc"
    SUBSYSTEMS=="platform"
    DRIVERS=="sdhci-esdhc-imx"
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc/2100000.aips-bus':
    KERNELS=="2100000.aips-bus"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc':
    KERNELS=="soc"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0':
    KERNELS=="soc0"
    SUBSYSTEMS=="soc"
    DRIVERS==""
    ATTRS{family}=="Freescale i.MX"
    ATTRS{revision}=="1.4"
    ATTRS{soc_id}=="i.MX6SX"

$ udevadm info -a  /dev/mmcblk2p1  // 각 Partition 정보와 비교 

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
// uevent node 확인가능. 상위 node에 mmcblk2p1 추가되었으며,나머지는 동일
  looking at device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1':
    KERNEL=="mmcblk2p1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="354304"
    ATTR{inflight}=="       0        0"
    ATTR{partition}=="1"
    ATTR{ro}=="0"
    ATTR{size}=="3002164"
    ATTR{start}=="73036"
    ATTR{stat}=="      53       16     4275      309        0        0        0        0        0      260      270        0        0        0        0"
// 상위 (udevadm info -a /dev/mmcblk2)  동일한 device node 이며 상위와 완전동일  
  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2':
    KERNELS=="mmcblk2"
    SUBSYSTEMS=="block"
    DRIVERS==""
    ATTRS{alignment_offset}=="0"
    ATTRS{capability}=="50"
    ATTRS{discard_alignment}=="0"
    ATTRS{ext_range}=="256"
    ATTRS{force_ro}=="0"
    ATTRS{hidden}=="0"
    ATTRS{inflight}=="       0        0"
    ATTRS{range}=="8"
    ATTRS{removable}=="0"
    ATTRS{ro}=="0"
    ATTRS{size}=="3842048"
    ATTRS{stat}=="      95       16     6363      545        0        0        0        0        0      400      440        0        0        0        0"

  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234':
    KERNELS=="mmc2:1234"
    SUBSYSTEMS=="mmc"
    DRIVERS=="mmcblk"
    ATTRS{cid}=="02544d534130324704207dfb7500a800"
    ATTRS{csd}=="002e00325b5aa3a9ffffff800a800000"
    ATTRS{date}=="08/2010"
    ATTRS{dsr}=="0x404"
    ATTRS{erase_size}=="512"
    ATTRS{fwrev}=="0x4"
    ATTRS{hwrev}=="0x0"
    ATTRS{manfid}=="0x000002"
    ATTRS{name}=="SA02G"
    ATTRS{ocr}=="0x00040000"
    ATTRS{oemid}=="0x544d"
    ATTRS{preferred_erase_size}=="4194304"
    ATTRS{rca}=="0x1234"
    ATTRS{scr}=="0225800001000000"
    ATTRS{serial}=="0x207dfb75"
    ATTRS{ssr}=="00000000000000280202900100aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    ATTRS{type}=="SD"

  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2':
    KERNELS=="mmc2"
    SUBSYSTEMS=="mmc_host"
    DRIVERS==""

  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2198000.usdhc':
    KERNELS=="2198000.usdhc"
    SUBSYSTEMS=="platform"
    DRIVERS=="sdhci-esdhc-imx"
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc/2100000.aips-bus':
    KERNELS=="2100000.aips-bus"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc':
    KERNELS=="soc"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0':
    KERNELS=="soc0"
    SUBSYSTEMS=="soc"
    DRIVERS==""
    ATTRS{family}=="Freescale i.MX"
    ATTRS{revision}=="1.4"
    ATTRS{soc_id}=="i.MX6SX"


2.3  udevadm monitor를 이용확인

udevadm의 monitor를 이용하여 sdcard의 card detection 부분을 체크

$ udevadm monitor  -h
udevadm monitor [OPTIONS]

Listen to kernel and udev events.

  -h --help                                Show this help
  -V --version                             Show package version
  -p --property                            Print the event properties
  -k --kernel                              Print kernel uevents
  -u --udev                                Print udev events
  -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem
  -t --tag-match=TAG                       Filter events by tag


실시간 모니터로 아래와 같이 uevent를 볼수 있으며 옵션을 추가하여 각 event를 더 확인하자.

$ udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

mmc2: card 1234 removed
KERNEL[179853.651358] remove   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1 (block)
KERNEL[179853.654058] remove   /devices/virtual/bdi/179:24 (bdi)
KERNEL[179853.654755] remove   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2 (block)
UDEV  [179853.662386] remove   /devices/virtual/bdi/179:24 (bdi)
KERNEL[179853.671233] unbind   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
KERNEL[179853.671436] remove   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
UDEV  [179853.699415] remove   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1 (block)
UDEV  [179853.704243] remove   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2 (block)
UDEV  [179853.715698] unbind   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
UDEV  [179853.716975] remove   /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
mmc2: host does not support reading read-only switch, assuming write-enable
mmc2: new high speed SD card at address 1234
KERNEL[179860.947683] add      /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
UDEV  [179860.956872] add      /devices/soc0/soc/2100000.aips-bummcblk2: mmc2:1234 SA02G 1.83 GiB
s/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
KERNEL[179860.966523] add      /devices/virtual/bd mmcblk2: p1
i/179:24 (bdi)
UDEV  [179860.977474] add      /devices/virtual/bdi/179:24 (bdi)
KERNEL[179860.978045] add      /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2 (block)
KERNEL[179860.980267] add      /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1 (block)
KERNEL[179860.983182] bind     /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)
UDEV  [179861.117857] add      /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2 (block)
FAT-fs (mmcblk2p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
UDEV  [179861.423592] add      /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234/block/mmcblk2/mmcblk2p1 (block)
UDEV  [179861.426851] bind     /devices/soc0/soc/2100000.aips-bus/2198000.usdhc/mmc_host/mmc2/mmc2:1234 (mmc)


3. udev Rule 만드는 법 

udevadm info 와 monitor를 통해 기본 udev의 정보와 sys file system의 정보를 이용하여 udev rule을 간단히 만들어보자.

  • udev rule의 기본저장장소
  1. /lib/udev/rules.d/
  2. /etc/udev/rules.d/  : User는 이곳에 설정하여 추가해서 넣자 
  3. /dev/udev/rules.d/

  • Rule에서 기본적으로 match되는 정보  
  1. KERNEL : device의 kernel 이름 , device의 이름과 match
  2. SUBSYSTEM : device의 subsystem과 match
  3. DRIVER: device와 관련된 driver name과 match
  4. NAME:  /dev 에서 사용되어지는 device node와 match  
  5. SYMLINK: NAME의 대신에 사용되어지는 symbloic link list
  6. ATTRS{x}: 상위 sys filesystem의 정보와 match
  7. ENV{DEVLINKS}: 상위 E: Node 정보와 match 

  • matching 할때 pattern 
  1. *:  어느 문자들이든 match
  2. ?:  어느 한 문자만  match
  3. []:  범위를 정해서 match

  • Event 와 실행 
  1. ACTION: 해당 정보의 device가 add or remove , change가 있을 경우 
  2. RUN : 조건이 충족되면 실행을 하는 command 

RUN에 ENV{ } 정보를 출력하고 싶다면, %E{xx}로 사용가능
SYMLINK를 이용하여 /dev에 새로 device node의 symblolic link 생성가능
좀 더 사용을 하면 GOTO와 LABEL을 사용하며, 예제를 보면 쉽게 이해가 가능


3.1  MMC Device 와 udev Rule 생성 

  • MMC의 동작 rule 생성 및 적용 
mmcblk2p 가 Hotplug 될 때, add와 remove에 맞게 간단히 RUN을 사용하여 작성

$ cat /etc/udev/rules.d/10-mmc.rules  //RUN을 추가하여 지속적으로 실행가능 
# Mount and remove mmc partitions manually for 32G  
# udevadm info /dev/mmcblk2 에서 E DEVNAME 부분확인 , 상위 환경변수부분 참조

ACTION=="add" KERNEL=="mmcblk[2]p[0-9]", RUN+="/bin/mkdir -p /media/card", RUN+="/bin/mount %E{DEVNAME} /media/card"
ACTION=="remove" KERNEL=="mmcblk[2]p[0-9]", RUN+="/bin/umount -f /media/card" , RUN+="/bin/rmdir /media/card"


udev Basic Rule 사용법 (systemd-udevd.service에서 관리)
  https://www.freedesktop.org/software/systemd/man/udev.html#
  http://www.reactivated.net/writing_udev_rules.html
  https://wiki.debian.org/udev

udev Rule의 예제 및 udevadm 사용법
  https://gnu-linux.org/writing-udev-rules-for-flash-drive.html
  https://kernel.googlesource.com/pub/scm/linux/hotplug/udev/+/1ed38f41749dde482e164e692255b60c38b5d876/etc/udev/rules.d/80-drivers.rules

udev 관련 Kernel 설정
  https://wiki.gentoo.org/wiki/Udev/ko


3.2 다른 Device 와 systemd 의 Service 연결적용 

  • udev 의 device(ttyACM0) 기본분석

일반적으로 많이 사용되는 USB Serial ttyACM에 udev에 연결하여 systemd 와 함께 service 할 수 있도록 설정.

$ ls /dev/ttyACM0                // USB serial 존재파악 

$ udevadm info -a -n /dev/ttyACM0                    // udev 값 분석 및 각 ATTRS 값 확인 


// 분석방법은 아래와 같이 최종 driver 단 기준부터 그 위의 KERNEL/SUBSYSTEM/ ATTRS  중심으로 파악  
...........
  looking at device '/devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1.1/1-1.1:1.0/tty/ttyACM0':
    KERNEL=="ttyACM0"
    SUBSYSTEM=="tty"
    DRIVER==""

  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1.1/1-1.1:1.0':
    KERNELS=="1-1.1:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="cdc_acm"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="02"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bInterfaceProtocol}=="01"
    ATTRS{bInterfaceSubClass}=="02"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{bmCapabilities}=="7"
    ATTRS{iad_bFirstInterface}=="00"
    ATTRS{iad_bFunctionClass}=="02"
    ATTRS{iad_bFunctionProtocol}=="01"
    ATTRS{iad_bFunctionSubClass}=="02"
    ATTRS{iad_bInterfaceCount}=="02"
    ATTRS{interface}=="PLSx"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1.1':
    KERNELS=="1-1.1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="ef"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{bDeviceSubClass}=="02"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="100mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}=="14"
    ATTRS{bcdDevice}=="1730"
    ATTRS{bmAttributes}=="e0"
    ATTRS{busnum}=="1"
    ATTRS{configuration}==""
    ATTRS{devnum}=="5"
    ATTRS{devpath}=="1.1"
    ATTRS{devspec}=="  (null)"
    ATTRS{idProduct}=="005b"
    ATTRS{idVendor}=="1e2d"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Cinterion Wireless Modules"
    ATTRS{maxchild}=="0"
    ATTRS{product}=="PLSx"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="unknown"
    ATTRS{rx_lanes}=="1"
    ATTRS{speed}=="480"
    ATTRS{tx_lanes}=="1"
    ATTRS{urbnum}=="122"
    ATTRS{version}==" 2.00"
.............
  looking at parent device '/devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{authorized_default}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bcdDevice}=="0419"
    ATTRS{bmAttributes}=="e0"
    ATTRS{busnum}=="1"
    ATTRS{configuration}==""
    ATTRS{devnum}=="1"
    ATTRS{devpath}=="0"
    ATTRS{idProduct}=="0002"
    ATTRS{idVendor}=="1d6b"
    ATTRS{interface_authorized_default}=="1"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Linux 4.19.35-1.1.0+g0f9917c ehci_hcd"
    ATTRS{maxchild}=="1"
    ATTRS{product}=="EHCI Host Controller"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="unknown"
    ATTRS{rx_lanes}=="1"
    ATTRS{serial}=="ci_hdrc.1"
    ATTRS{speed}=="480"
    ATTRS{tx_lanes}=="1"
    ATTRS{urbnum}=="25"
    ATTRS{version}==" 2.00"
.....

// USB CDC 중 ACM은 일반적으로 USB Serial로 많이 사용되지만, 꼭 Serial으로만 사용해야하는 것은 아니다. 
// 세부사항은 USB CDC 종류에서 각각 파악하자  

$ udevadm info -a -n /dev/ttyACM0 | grep serial  // ttyACM0을 USB Serial로 사용하기 위해 serial 이름파악 
ATTRS{serial}=="ci_hdrc.1"

  • udev 의 device(ttyACM0) 와 systemd 의 service 연결
각 udev rule에서 ttyACM 관련부분을 검색 한 후 이를 분석한 후, 직접 수정
$ find /etc/udev/rules.d/  -name *ttyACM*  // udev file 찾기 (우선순위 etc -> lib) 못찾으면 grep 사용 
$ find /lib/udev/rules.d/  -name *ttyACM*  

// 나의 경우, KERENL에, ttyACM0을 넣고, serial을 더 좀 더 확실히 하기 위해 ATTRS{serial} 추가했지만, 자기 구성대로 변경
// SYSTEMD_WANTS 사용시 udev database에 TAG+="systemd" 넣지 않는다면, systemd에서 찾지 못한다 (세부내용은 Manual)  
// 이기능은 systemd의 Want=에 추가되며, 추후 systemd의 *.socket 의 BindToDevice= 와 연결가능 

$ cat /etc/udev/rules.d/20-ttyACM0.rules  // KERNEL의 Device 와 Serial 이름으로 동작 
KERNEL=="ttyACM0", ATTRS{serial}=="ci_hdrc.1" , TAG+="systemd", ENV{SYSTEMD_WANTS}="my.service"

udev Rule에 TAG+="systemd"와 ENV{SYSTEMD_WANTS} 와 udev Database
  https://www.freedesktop.org/software/systemd/man/systemd.device.html
  https://www.freedesktop.org/software/systemd/man/udev.html#

  • 연결될 systemd의 service 구성

systemd의 service 중 (BindToDevice대신) BindTo 와 After 부분설정을 위해 각 값 검색
$ systemctl list-units --all --full   //  systemctl list-units --all --full 의 정보가 너무 많음 
$ systemctl list-units --all --full | grep ".device"   //  systemctl list-units --all --full 의 정보가 너무 많아 device만 찾음 

// device 구성을 보면, parent가 존재하므로, 점점 node가 길어지면, 최종으로 load되는 부분을 찾아야함 
// systemd.device에서 ttyACM0 or 상위 ATTR 값을 넣어 검색범위를 좁힘 
$ systemctl list-units --all --full | grep ".device" | grep "ci_hdrc.1" // systemd.device 에 상위 ATTR 값 동일부분확인
  dev-serial-by\x2dpath-platform\x2dci_hdrc.1\x2dusb\x2d0:1.1:1.0.device                                              loaded    active   plugged   PLSx         
  dev-serial-by\x2dpath-platform\x2dci_hdrc.1\x2dusb\x2d0:1.1:1.2.device                                              loaded    active   plugged   PLSx         
  dev-serial-by\x2dpath-platform\x2dci_hdrc.1\x2dusb\x2d0:1.1:1.4.device                                              loaded    active   plugged   PLSx         
  dev-serial-by\x2dpath-platform\x2dci_hdrc.1\x2dusb\x2d0:1.1:1.6.device                                              loaded    active   plugged   PLSx         
  dev-serial-by\x2dpath-platform\x2dci_hdrc.1\x2dusb\x2d0:1.1:1.8.device                                              loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.0-tty-ttyACM0.device loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.10-net-usb0.device   loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.12-net-usb1.device   loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.2-tty-ttyACM1.device loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.4-tty-ttyACM2.device loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.6-tty-ttyACM3.device loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.8-tty-ttyACM4.device loaded    active   plugged   PLSx

$ systemctl list-units --all --full | grep ".device" | grep "ttyACM0" // systemd.device 에 ttyACM0 재확인 
  dev-ttyACM0.device                                                                                                  loaded    active   plugged   PLSx         
  sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.0-tty-ttyACM0.device loaded    active   plugged   PLSx

udev Rule에 같이 동작할 systemd 의 service 설정
**system unit 과 system.service manual 참조
//상위 udev의 Rule에서 적용했던 부분이 동작할 경우 실행 (ttyACM0) 
//Unit의 BindTo 와 After를 *.service로만 한정지어 생각했는데, device를 비롯하여 mount 등 모두 가능
//Unit의 대상은 모든 systemd의 설정의 기본이며, service/socket/device/mount/등 모두 적용대상
$ vi /lib/systemd/system/my.service 
or 
$ vi /etc/systemd/system/my.service 
[Unit]
Description=TEST Service for ttyACM0
BindsTo=sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.0-tty-ttyACM0.device
After=sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1:1.0-tty-ttyACM0.device

# BindsTo 는 Requires 와 유사하게 dependencies를 요구하는 설정이며, Requres 보다 좀 더 강력하다고 하며, 
# After와 함께 같이 사용할때 최적이라고 한다.
# 주의 할 것은 Fail 될 경우, Skip되므로 이 부분 주의하며, 상위 Device가 연결될때 Timing을 기다림

[Service]
ExecStart=test start 

[Install]
WantedBy=multi-user.target

  1. udev에서 ttyACM0 상위정보의 uevent가 오면 이를 udev에 TAG를 사용하여 systemd에 노출하고 service로 연결
  2. 상위 service에서 AfterBindsTo는 systemd의 service에 연결하여 Timing을 조절(제대로 붙기전에는 실행 불가능) 

아래의 사이트에서 쉽게 찾아 연결했으며, 세부내용은 아래사이트 참조

systemd의 unit 과 service 설정정보
  https://www.freedesktop.org/software/systemd/man/systemd.unit.html
  https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Mapping%20of%20unit%20properties%20to%20their%20inverses
  https://www.freedesktop.org/software/systemd/man/systemd.service.html#


$ udevadm info /dev/ttyACM0 // 상위 실행 후 동작확인 
P: /devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1.1/1-1.1:1.0/tty/ttyACM0
N: ttyACM0
S: serial/by-id/usb-Cinterion_Wireless_Modules_PLSx-if00
S: serial/by-path/platform-ci_hdrc.1-usb-0:1.1:1.0
E: DEVLINKS=/dev/serial/by-path/platform-ci_hdrc.1-usb-0:1.1:1.0 /dev/serial/by-id/usb-Cinterion_Wireless_Modules_PLSx-if00
E: DEVNAME=/dev/ttyACM0
E: DEVPATH=/devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1.1/1-1.1:1.0/tty/ttyACM0
E: ID_BUS=usb
E: ID_MODEL=PLSx
E: ID_MODEL_ENC=PLSx
E: ID_MODEL_ID=005b
E: ID_PATH=platform-ci_hdrc.1-usb-0:1.1:1.0
E: ID_PATH_TAG=platform-ci_hdrc_1-usb-0_1_1_1_0
E: ID_REVISION=1730
E: ID_SERIAL=Cinterion_Wireless_Modules_PLSx
E: ID_TYPE=generic
E: ID_USB_CLASS_FROM_DATABASE=Miscellaneous Device
E: ID_USB_DRIVER=cdc_acm
E: ID_USB_INTERFACES=:020201:0a0000:020200:020600:
E: ID_USB_INTERFACE_NUM=00
E: ID_USB_PROTOCOL_FROM_DATABASE=Interface Association
E: ID_VENDOR=Cinterion_Wireless_Modules
E: ID_VENDOR_ENC=Cinterion\x20Wireless\x20Modules
E: ID_VENDOR_ID=1e2d
E: MAJOR=166
E: MINOR=0
E: SUBSYSTEM=tty
E: SYSTEMD_WANTS=my.service   // systemd service 확인 
E: TAGS=:systemd:             // TAG의 systemd 추가 확인 
E: USEC_INITIALIZED=19217285

udev 와 systemd 연결
  https://unix.stackexchange.com/questions/89691/how-do-i-connect-a-3g-dongle-using-systemd

systemd 기본사용법
  https://ahyuo79.blogspot.com/2020/01/systemd.html


4. udevadm test 와 trigger를 이용하여 테스트 

새로 만든 udev rule에 ACTION Event를 주어 SW로만 테스트 진행가능하며, 본인이 좀 더 세부 테스트를 한다면, 다양한 옵션설정도 가능.

아래의 두가지 방식으로 테스트 가능

  • udev 의 테스트 방식 

$ udevadm test -h
$ udevadm test [OPTIONS] DEVPATH

Test an event run.

  -h --help                            Show this help
  -V --version                         Show package version
  -a --action=ACTION                   Set action string
  -N --resolve-names=early|late|never  When to resolve names


  • udev에 uevent를 주어 테스트 진행 

 $ udevadm trigger  -h
udevadm trigger [OPTIONS] DEVPATH

Request events from the kernel.

  -h --help                         Show this help
  -V --version                      Show package version
  -v --verbose                      Print the list of devices while running
  -n --dry-run                      Do not actually trigger the events
  -t --type=                        Type of events to trigger
          devices                     sysfs devices (default)
          subsystems                  sysfs subsystems and drivers
  -c --action=ACTION                Event action value, default is "change"
  -s --subsystem-match=SUBSYSTEM    Trigger devices from a matching subsystem
  -S --subsystem-nomatch=SUBSYSTEM  Exclude devices from a matching subsystem
  -a --attr-match=FILE[=VALUE]      Trigger devices with a matching attribute
  -A --attr-nomatch=FILE[=VALUE]    Exclude devices with a matching attribute
  -p --property-match=KEY=VALUE     Trigger devices with a matching property
  -g --tag-match=KEY=VALUE          Trigger devices with a matching property
  -y --sysname-match=NAME           Trigger devices with this /sys path
     --name-match=NAME              Trigger devices with this /dev name
  -b --parent-match=NAME            Trigger devices with that parent device
  -w --settle                       Wait for the triggered events to complete


실제테스트 진행 
  • 상위 만들어진 rule에 SW로 테스트 진행 (문제발생)
$ udevadm test -a remove /dev/mmcblk2
or
$ udevadm test -a remove  /sys/block/mmcblk2
calling: test
version 239
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

Load module index
Skipping empty file: /etc/systemd/network/99-default.link
Created link configuration context.
Reading rules file: /etc/udev/rules.d/10-imx.rules
Reading rules file: /etc/udev/rules.d/30-mmc.rules
Reading rules file: /lib/udev/rules.d/50-firmware.rules
Reading rules file: /lib/udev/rules.d/50-udev-default.rules
Reading rules file: /lib/udev/rules.d/60-block.rules
Reading rules file: /lib/udev/rules.d/60-cdrom_id.rules
Reading rules file: /lib/udev/rules.d/60-drm.rules
Reading rules file: /lib/udev/rules.d/60-evdev.rules
Reading rules file: /lib/udev/rules.d/60-input-id.rules
Reading rules file: /lib/udev/rules.d/60-persistent-alsa.rules
Reading rules file: /lib/udev/rules.d/60-persistent-input.rules
Reading rules file: /lib/udev/rules.d/60-persistent-storage-tape.rules
Reading rules file: /lib/udev/rules.d/60-persistent-storage.rules
Reading rules file: /lib/udev/rules.d/60-persistent-v4l.rules
Reading rules file: /lib/udev/rules.d/60-sensor.rules
Reading rules file: /lib/udev/rules.d/60-serial.rules
Reading rules file: /lib/udev/rules.d/64-btrfs.rules
Reading rules file: /lib/udev/rules.d/70-joystick.rules
Reading rules file: /lib/udev/rules.d/70-mouse.rules
Reading rules file: /lib/udev/rules.d/70-power-switch.rules
Reading rules file: /lib/udev/rules.d/70-touchpad.rules
Reading rules file: /lib/udev/rules.d/70-uaccess.rules
Reading rules file: /lib/udev/rules.d/71-seat.rules
Reading rules file: /lib/udev/rules.d/73-seat-late.rules
Reading rules file: /lib/udev/rules.d/75-net-description.rules
Reading rules file: /lib/udev/rules.d/75-probe_mtd.rules
Reading rules file: /lib/udev/rules.d/78-sound-card.rules
Reading rules file: /lib/udev/rules.d/80-drivers.rules
Reading rules file: /lib/udev/rules.d/80-net-setup-link.rules
Reading rules file: /lib/udev/rules.d/90-alsa-restore.rules
Reading rules file: /lib/udev/rules.d/90-vconsole.rules
Reading rules file: /lib/udev/rules.d/97-hid2hci.rules
Reading rules file: /lib/udev/rules.d/99-systemd.rules
Reading rules file: /etc/udev/rules.d/touchscreen.rules
rules contain 24576 bytes tokens (2048 * 12 bytes), 11107 bytes strings
1602 strings (19400 bytes), 1040 de-duplicated (8856 bytes), 563 trie nodes used
unable to open device '/sys/dev/mmcblk2'   //문제발생 /sys/dev/의 구조가 다르며, /sys로 변경해도 동일, /dev/mmcblk2 현재없어서 인것 같음 
Unload module index
Unloaded link configuration context.

$ udevadm test -a add /dev/mmcblk2 
$ udevadm test -a add  /sys/block/mmcblk2

다시 trigger 기반으로 테스트진행시 문제없음 
  • 상위 만들어진 rule에 SW로 테스트 진행 (문제없음)
$ udevadm trigger -c add /dev/mmcblk2   // RUN 동작확인 
$ udevadm trigger -c remove /dev/mmcblk2 // RUN 동작확인

12/16/2014

Linux sys file system Simple 예제 (커널테스트용으로 작성)

1. Kernel 내부의 sys filesystem 로 Debug  

Kernel에서 내가 원하는 부분정보를 얻고,  설정을 변경하기 위해서 테스트용 sys filesystem을 추가구현해보도록 한다.

  • Kernel 의 sys file system module 의 예제 
링크된 sys file system module의 예제를 참고하여 기본구현
sysfs_create_group를 unregister 하기 위해서 sysfs_remove_group 써야한다고 하는데 이부분은 미확인
  http://www.linuxquestions.org/questions/linux-embedded-and-single-board-computer-78/sysfs-class-registration-942098/


상위소스와 같이 각각의 show_xx 함수와 store_xx 함수를 정의하여 attribute를 구성하여 추가한다.

  • device_attribute 로 sys file system 확장 (SDCard)
/sys/block/sdx/device/scsi_disk/xxx/cache_type
/sys/block/sdx/device/scsi_disk/xxx/FUA

/*
 *  /sys/device  이외에도 다양하게 제공 bus_attribute
 *
 *  sys filesystem의 portstate 추가 
 *      read  function : xx_show_xx   이미 이함수들이 추가되어있음 
 *      write function : xx_store_xx  이미 이함수들이 추가되어있음 
 */

static struct device_attribute sd_disk_attrs[] = {
 __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type),
 __ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
 __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, sd_store_allow_restart),
 __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, sd_store_manage_start_stop),
 __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL),
 __ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL),
 __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
 __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
 __ATTR_NULL,

};

/*
 *  상위구현 된 부분에 본인이 추가할 부분 추가  
 *  sd_show_cache_type  sd_store_cache_type
 *   
 */
.........
.........

static struct class sd_disk_class = {
 .name  = "scsi_disk",
 .owner  = THIS_MODULE,
 .dev_release = scsi_disk_release,
 .dev_attrs = sd_disk_attrs,
};


MMC_DEV_ATTR 와  DEVICE_ATTR 로 변경되어 사용됨
  https://elixir.bootlin.com/linux/v4.10.17/source/drivers/mmc
  https://elixir.bootlin.com/linux/v4.10.17/source/drivers/mmc/core/sd.c


  • class_attribute를 이용하여 sys filesytem 확장 
/sys/class/rtl8370m/portstate 추가

/*
 *  /sys/class/rtl8370m/portstate
 *
 *  sys filesystem의 portstate 추가 
 *      read  function : portstate_show
 *      write function : portstate_store
 */
static struct class_attribute class_attr[] = {
 __ATTR(portstate, S_IWUSR | S_IRUGO, portstate_show, portstate_store),
 __ATTR_NULL
 };

/*
 * 별도로 본인이 보고 싶고 설정하고 싶은 두 함수를 설정
 *
 */

static ssize_t portstate_show(struct class *cls, char *buf)
{
   char *x[] = {"Enabled", "Disabled"}; 
   printk("portstate_show\n");
   return sprintf(buf, "%s\n", x[0]);
}

static ssize_t portstate_store(struct class *cls, const char *buf, size_t count)
{
   printk("portstate_store \n");
   return 1;
}

.......

/*  /sys/class/rtl8370m    */

static struct class rtl8370m_drv = {
 .name = "rtl8370m",    
 .owner = THIS_MODULE,
 .class_attrs =(struct class_attribute *) &class_attr,
};



 
  • sys file 을 이용한 GPIO 
  https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
  http://infoarts.tistory.com/21
  https://www.kernel.org/doc/Documentation/i2c/dev-interface


  • 기본 CHARTER DRIVER 예제들
  http://parkjunehyun.tistory.com/m/post/248
  http://www.opensourceforu.com/2011/08/io-control-in-linux/


  • Udev Rule 관련설정
  https://kernel.googlesource.com/pub/scm/linux/hotplug/udev/+/1ed38f41749dde482e164e692255b60c38b5d876/etc/udev/rules.d/60-persistent-storage.rules
  http://www.troot.co.kr/tc/1958


9/13/2014

Linux 2.4 MMC/SD Interface 구조정리

1. DM320의 MMC/SD Driver 구현 및 관련설명정리

오래전에 Linux Kernel 2.4 기준으로 TI DM320 SD Card  와 SD-IO Spec 보고,직접 Linux Device Driver를 내 마음대로 만들어 본 경험이 있다.
물론 이 때는 Chip vendor들이 Device Driver를 제공 해주지 않으니, Chip Vendor 3rd Party에서 근무했던, 
내가 만들어 직접 개발하고 3rd Party에서 국내 각 회사에 공급했다. 

SDCard 뿐만아니라, HDMI를 비롯하여 각종 Device Drivers(Camera/LCD/Touch/Bus/등)들을 많이 만들었는데, 
우연히 예전에 정리했던 자료를 발견했으며, 그것을 오늘 간단히만 정리하려고 하며, 
현재 Linux Kernel과는 너무 많이 다르므로, 참조만 하도록하자. 

Device Driver 개발자 입장에서 생각해보면, 
USB/PCI/HPI 각 종 Bus Device Driver를 비롯하여, PATA도 만들어보고, Video MUX를 비롯하여 각종 여러 Device Driver를 개발해봤는데, 
가장 후회로 남는 것이 있다면, PCIe를 직접 개발 못해본게 좀 후회로 많이 남는다.

MMC/SD가 현재 와 많은 부분이 다를 것이며, MMC Interface 또한 많이 변경되어 왔다. 
또한 MMC Host에 따라 많이 다를 것으로 예상한다.

더불어 Linux Kernel 도 버전업 되면서 , 각 Device Driver가 Platform 화 되었으므로, 
이전과는 구조가 다르므로 주의하자.  


  • MMC&SD Card Driver 위치

 Kernel/driver/mmc 

1.1 SD/MMC Driver 기본전체구성

전체 TI의 MMC&SD Device Driver는 크게 3 부분으로 구분이 되고,Core 모듈과 MMC Block 모듈 그리고, 하드웨어에 종속적인 모듈로 구성이 된다.
만약 MMC&SD카드 Driver을 작성하고자 한다면, 전체 Driver를 작성할 필요 없이 mmc_hardware 부분 소스만 TI의 Datasheet를 보고 새로 작성을 하면된다.

  • MMC_CORE (MMC 공통사항)
Files: mmc.c mmc_queue.c mmc_sysfs.c
Description:
  mmc_block에서 등록이 된, Device들을 초기화 하고, MMC&SD Spec에 관한 Function 및 Hotplug에 관한 Function으로 구성이 되어있다.


  • MMC_BLOCK  ( block device driver)
Files: mmc_block.c
Description:
  mmc & sd card block device driver 함수들이 존재 한다. mmcblk의 block device 관련 함수들이 존재 한다.


  • mmc_hardware ( TI DM320 관련부분)
Files: dm320_mmc.c
Description:
  실제적인 MMC & SD Card Driver이며, Hardware에 종속적인 소스들로만 구성이 되어있다. 이 부분은 아래에서 자세히 다루겠다.


1.2 MMC & MMC_BLOCK 구성

MMC/SD Driver는 SD Card를 Hard disk Driver와 유사하게 인식을 하며, 그래서 기본적인 구성은 Hard disk의 Block Device Driver의 기본구조 유사하다.
이전에 FPGA관련 PATA Block Device driver도 직접 만들었 본 경험이 있어 볼 때마다 재미있다.
SD/MMC Block device driver의 구성은 다음과 같다

  • static int __init mmc_blk_init(void)
Module이 처음 올라갈 때, 실행이 되며, Block Device Driver를 등록한다.
중요함수: register_blkdev(major, "mmc");


  • static void __exit mmc_blk_exit(void)
Module이 내려 갈 때 실행이 되며, Block Device Driver를 해제한다.
중요함수: unregister_blkdev(major, "mmc");


  • static int mmc_blk_probe(struct mmc_card *card)
kerenl의 module이 올라가고 처음 block device driver가 잡힐 때
mmc_blk_alloc
  *alloc_disk
  *mmc_init_queue
     *blk_init_queue() (request 함수를 등록을 한다.)
     *mmc_queue_thread (mmc_queue thread 시작)
  *md->block_bits = 9; // 2G 이상 지원 (이 부분만 수정하면, 2G 이상 지원)
  *blk_queue_hardsect_size(Sector 크기 설정)
  *set_capacity (block 수 설정)
  *md->queue.prep_fn = mmc_blk_prep_rq;
  *md->queue.issue_fn = mmc_blk_issue_rq; (MMC Request 함수)

  • static void mmc_blk_remove(struct mmc_card *card)
block device driver가 제거될때

  • static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
block device driver가 suspend가 될 경우
  • static int mmc_blk_resume(struct mmc_card *card)
block device drver를 resume 할 때


이전에 MMC Device Driver (SD Card / SD IO)를 Linux에서 직접구현하면서 간단히 정리 한 후 만든 간단히 도표이며,
나의 경우는 아래와 같이 Polling 모드로 동작하는 구조구현을 했다.




  • DM320 MMC Block Device Driver 내부동작
상위의 함수 mmc_queue_thread 기준으로 다시 한번 Flow를 보며, MMC Interface가 CMD 방식으로 동작하기 때문에 이 관련부분이 중요.
mmc_queue_thread    (Block Device Request 함수)
  *mmc_blk_issue_rq (실제적인 Request 함수)
     blk_rq_map_sg (block driver의 make_request 함수)
        MMC_READ_MULTIPLE_BLOCK
            *mmc_wait_for_read_data()
               *read_from_card()
        MMC_WRITE_MULTIPLE_BLOCK
            *mmc_wait_for_write_data()
                *write_from_card()   

위에서 전체 Block Device Driver의 Flow을 보면 동작방식은 간단히 다음과 같다.
  1. Block Device Driver를 등록하고, blk_init_queue 함수를 이용하여 request 함수를 등록한다.
  2. Kernel Queue Thread를 생성하고 항시 mmc_request가 오기를 항상 대기한다.(무한 루프)
  3. 커널에서 mmc_request 요청이 오면, 멈춰 있던 Kernel Thread를 작동시킨다.
  4. 커널에서 요청한 Request Function을 수행을 한다( Read & Write)


1.3 DM320 MMC/SD Device Driver 

앞서 말한 것와 같이 MMC/SD Device Driver는 Hardrware 부분의 종속된 부분만 구현하면 되지만, 
이전에 Dm320는 다른부분(mmc.c 및 기타부분)도 같이 보완해서 구현했다.
그리고, 추후에 WIFI를 위해서 SDIO를 지원하기 위해서 다른부분도 넣고 수정했는데, 거의 10년 전일이라 정리를 못하겠다. 
이 부분은 문서는 Linux에서 제공하는 Platform에 맞추어 Porting하는 부분으로 구성하였다. 
추후 다시 구현하거나 수정할 기회가 있다면 그때 정리하자

  • Linux에서 구현해야 할 함수 및 설정

static struct mmc_host_ops<
   .request = mmc_request  //MMC Request 이 전체의 Block Device의 실제적인 Request
   .set_ios = mmc_set_ios //Hardware Setting Init혹은 Voltage 설정. Bus width설정. Power 설정. Busmode
   .get_ro = get_write_protect_status  //ReadOnly 지원할 경우 

static struct device_driver
   .bus     = &platform_bus_type,
   .probe   = mmc_probe,   //MMC Host 에 관련된 초기화 설정

   .remove  = mmc_remove,
   .suspend = NULL,

   .resume  = NULL,


Kernel에서 요청하는 Page 수를 크게 하고 싶다면, 아래의 Segments 값을 변경을 하면되지만, 
변경시 한번에 전송하는 사이즈 값이 커진다. (주의: DMA 크기문제)

 mmc->max_hw_segs = 64;  //DMA Size 주의 
  mmc->max_phys_segs = 64;

  mmc->max_sectors = 128; // MAX Segments 값



  • Linux에서 각 함수 동작순서

mmc_alloc_host
  mmc_rescan
     mmc_claim_host
     mmc_check_cards
     mmc_setup
        mmc_power_up
        mmc_idle_cards
        mmc_send_op_cond    //OCR Register Read , 아래 참조 
        mmc_discover_cards  //ALL_CID & SEND_RELATIVE_ADDRESS
        mmc_read_csds       // CSD Register Read
        mmc_read_scrs       // SCR Register Read
            src_read
               init_clocks   // 변경 25MHz , SDIO일 경우는 50MHz 
        mmc_calculate_clock
        mmc_release_host


세부 구현 내용은 다른 소스를 참고하며 각 Chip Maker마다 다르므로 Datasheet를 보고 동작원리를 파악하자


1.4 Kernel 설정 및 MMC device 설정

Kernel의 Config 생성 및 설정 및 설치 (Module설정시 변경)

>make menuconfig
Device Drivers->MMC/SD Card support->   MMC support
                         [*]  MMC debugging
                           MMC block device driver  
                         [*]   Write work-around for incompatible cards
                         [*]   Multi-block writes (EXPERIMENTAL) 
                               < >  Winbond W83L51xD SD/MMC Card Interface support
                            < >  TI DAVINCI Multimedia Card Interface support
                               TI DM320 Multimedia Card In
> make modules
> make modules_install


상위와 같이 Kernel을 update 한 후 Board에서 SD Card를 삽입을 하고, SD Card의 Partition Table을 확인한 후 Device file을 확인.
Linux는 SD Card를 Hard disk처럼 인식하기 때문에, 반드시 SD Disk내에 Partition Table이 존재.


  • Partition Table 확인
> cat /proc/partitions
  254  0  249856 mmcblk0
  254  1  249805 mmcblk0p1

>ls /dev/mmcblk*   //device node 확인 
//만약 없다면, Device File 없다면,새로 생성
> # mknod /dev/mmcblk0 b 254 0
> # mknod /dev/mmcblk0p1 b 254 1

//만약 Partition Table이 존재 하지 않는다면, 다음과 같이 fdisk를 이용하여 만들어 준다.
> fdisk /dev/mmcblk0

//FileSystem이 없다면, FAT 혹은 EXT2,3를 Format 
>mkefs /dev/mmcblk0p1
or mkfs.ext2

>mount /dev/mmcblk0p1 /mnt/sd0

1.5 TI DM320 관련설정 부분



  • /mmc/dm320_mmc.c/init_clocks 함수 (clock 설정 , SDCard 와 SDIO는 25MHz/50MHz)



  • Clock Controller - INV Register 설정.





  • Clock Controller - DIV3 Register



  • MMC/SD Interface - MMCCLK Register



  • MMC/SD Interface 와 Memory Stick Controller




  • Clock Controller – MOD2




2. 다른 MMC/SD Driver 구조  (drivers/mmc )

MMC interface는 card or sdio 같은 소스를 사용하기에, 크게 수정할 일 없었으나,Host쪽 설정과 인식문제를 부분이 있어 이를 해결을 해야 할 것 같다.
(추후 시간이 있을 경우 최신것을 보도록 하자)

  • host    (이외 HOST, MCU에 의존적인 소스이며 설정소스 )
dw_mmc.c, sdhci.c sdhci-s3c.c

각 vendor에서 제공을 하며, MCU에 의존적으로 설정

  • card  ( block device driver) 
queue.c block.c mmc_block.o

sd card의 독립적인 모듈로 block device driver 구조로 각 thread queue를 사용하여 sd disk를 운영

  • core  ( sd card, mmc card, sdio  interface 및 기본 interface)
sd.c sdio.c mmc.c core.c bus.c ....

각 bus 및 interface 관련소스들로 구성이 되어있다. (SDIO 및 SD 기본 interface)

  • 관련 headers 
         include/linux/mmc


2.1 MMC/SD 관련 함수

  • Core interface 주요 함수 및 구조체 
drivers/mmc/core/core.h

  struct mmc_bus_ops {   // 각 sd, mmc, sdio bus function
    int (*awake)(struct mmc_host *);
    int (*sleep)(struct mmc_host *);
    void (*remove)(struct mmc_host *);
    void (*detect)(struct mmc_host *);
    int (*suspend)(struct mmc_host *);
    int (*resume)(struct mmc_host *);
    int (*power_save)(struct mmc_host *);
    int (*power_restore)(struct mmc_host *);

};

mmc_wait_for_cmd() 함수  // SD Interface Command 함수  , 이 함수를 이용하여 host에서 command를 보낸다.


  • Host interface 주요 함수 및 구조체 

 ex) const struct mmc_host_ops

static const struct mmc_host_ops sdhci_ops = {
  .request = sdhci_request, // SD Card  Block Device의 Request 함수
  .set_ios = sdhci_set_ios,
// Hardware Setting Init혹은 Voltage 설정. Bus width설정. Power 설정. Busmode
  .get_ro = sdhci_get_ro, //ReadOnly 지원할 경우
  .hw_reset = sdhci_hw_reset,
  .enable_sdio_irq = sdhci_enable_sdio_irq,
  .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
  .execute_tuning   = sdhci_execute_tuning,
  .enable_preset_value  = sdhci_enable_preset_value,
};


static struct platform_driver sdhci_s3c_driver = {
  .probe =sdhci_s3c_probe,   // mmc_alloc_host 이 호출되며, Device 인식 및 등록이 되므로 중요.
  .remove  = __devexit_p(sdhci_s3c_remove),
  .suspend = sdhci_s3c_suspend,
  .resume  = sdhci_s3c_resume,
  .driver  = {
  .owner   = THIS_MODULE,
  .name = "s3c-sdhci",
  },

};

  • Host interface의 Probe 함수 SD Interface 인식
mmc_alloc_host       (host_ops 의 probe 에서 mmc_alloc_host 호출)
  >mmc_rescan
    >mmc_rescan_try_freq
     >mmc_power_up
      >mmc_hw_reset_for_init
      >sdio_reset
      >mmc_attach_sdio   (3 중 하나로 mmc_bus_ops  등록 )
      or mmc_attach_sd
      or mmc_attach_mmc
      or mmc_power_off


2.2 MMC/SD Register 구조

SD는 CMD로 Host와 Device와 통신을 하며, 아래와 같이 Host에 Registers 존재하며,Device에 역시 이에 관련된 Register들이 존재한다. 이부분은 Spec을 참조.

  • SD Host Controller Register Map





  • SD Device Registers (SD Card)



위 Register는 SDIO 로 갈 경우 조금씩 달라지며,  각각의 최신 Spec를 참조.



  1. OCR: Card의 Voltage Status 및 High Capacity or Standard Capacity 인지를 나타낸다. (Response)
  2. CID: Card의 관련 제조사의 정보가 있다.
  3. CSD: Card의 핵심 레지스터 군들이 모두 이곳에 있다. (자세한 내용은 Spec)  (Read &Write Block size, Transfer Speed , etc )
  4. SCR: Card의 Data bus width, SD Spec Version, Security 지원여부를 나타낸다.
  5. RCA: Card의 Relative Card Address. (Host가 설정.)
  6. SSR: Card의 Status (Card의 설정된 정보 Card Type, Speed Class, Data bus width)
  7. CSR: Card의 Status (Card의 Error Check & Card의 State)


9/12/2014

MMC/SD Interface 기본이해

1. SD Card Spec 관련내용  (ver 2.0)

SD Card Interface는 SD Card가 존재하며, SD Card를 읽고 쓰는 Reader가 존재한다.
Reader는 Host 기능을 하며, SD Card는 Device로 동작을 한다.
SD Card Spec는 지속적으로 업그레이드 되기때문에 관련내용은 아래의  사이트에서 찾아보자.

  https://www.sdcard.org

SD Host(SD Card Reader)는 SD Card 뿐만 아니라, SD IO를 이용하여 외부 Device와도 연결이 가능하다.
  1. SD Host (Card Reader)/ SD Card 
  2. SD Host / SD IO Device (e.g. WLAN)

  • SD Host  controller
  https://www.sdcard.org/developers/overview/host_controller/simple_spec/Simplified_SD_Host_Controller_Spec.pdf

  • SDIO
  https://www.sdcard.org/developers/overview/sdio/sdio_spec/Simplified_SDIO_Card_Spec.pdf

현재는 version 4.0도 있어, 이것으로는 이해

1.2. SD Card Pin 구조 

우선 SD Card의 Pin 구조 부터 알아보자.

  • SD Card의 구조 



  • SD Card Pin out 





  • Micro SD PinOut 







  • SD IO Pin out 







  • SDIO PIN 동작 

출처: http://www.smart-dv.com/vip/sdio.html

  • SD Card 및 IO 관련내용 
좀더 자세한 구조와 상세한 내용은 아래에서 파악해보자.

관련참고사항 사이트
  http://techblog.tistory.com/90


1.3 SD Card의 Speed 관련내용 

  • SD Card Bus Speed 
  https://www.sdcard.org/developers/overview/bus_speed/


2. MMC와 SD Card Bus Interface 

오래전에 Linux Kernel에서 SD Host Driver를 수정하고 이에 관련된 부분을 간단히 정리한다.
현재 SD Card가 많이 변했기 때문에 이부분은 추후 변경되어야 한다.

2.1 SD BUS 

SD Bus는 기본적으로 Command 방식으로 동작되어지며, Command는 CMD pin을 이용하고 Data는 DAT0 pin or DAT0,1,2,3 pin 으로 나누어 전송을 한다.

BUS라고 말한 것은 당연히 여러개의 Device를 지원을 하기때문에  말했을 것이라고 생각한다.
물론 나는 여러개의 Device를 연결해서 사용해본 적이 없다.


  • CMD와 DAT의 동작의 Flow

아래의 동작을 보면 쉽게 이해를 할수 있다.







2.2 Command 와 Response ( CMD Bus Pin) 

CMD Pin에서 사용되는 Command는 기본적으로 Command Token과 Response Token으로 구분되어지며,


  • Command Token  


  • Response Token 


2.3 Data Bus

SD Bus는 두가지 모드를 지원을 하고, Standard Bus(DAT0) 와 Wide Bus(DAT0,1,2,3) 그리고, Software적으로 Command에 따라
Data 전송 방식이 Usual Data (8Bit width)와 Wide Width Data(512Bit width)를 지원을 한다.
(8bit width와 512bit width는 Command에 의해 결정된다. 512 bit width ACMD13)


아래와 같이 간단히 PPT에서 정리해봤다.


SPI BUS는 생략

2.4 Hi Speed Mode

SD Card는 Default Mode 와 Hi speed Mode로 나누어지며, 아래와 같다.


  • Default Mode (Clock 25MHz)

Transfer Speed: 12.5MB/s (25MHz * 4 (Data Bus) / 8bit)


  • Hi Speed Mode (Clock 50MHz)

Transfer Speed: 25MB/s (50MHz * 4 (Data Bus) / 8bit)


이 속도는 SD Card Main Register인 CSD의 TRANS_SPEED의 값으로 알 수 있다.


2.5 Command 와 Response Tokens 정리 


  • Command Token (48bit with CRC) 



  • Response Token (48bit with CRC) : R1/R1b/R4/R5/R6/R7





  • Response Token (48bit with no CRC) : R3



  • Response Token (48bit with no CRC) : R3



2.6 SD Card 주요 Register




  • Main Register 
  1. OCR: Card의 Voltage 상태 및 High Capacity or Standard Capacity 인지를 나타낸다.
  2. CID: Card의 관련 제조사의 정보가 있다.
  3. CSD: Card의 핵심 레지스터 군들이 모두 이곳에 있다. (자세한 내용은 Spec)(Read &Write Block size, Transfer Speed , etc ) 
  4. SCR: Card의 Data bus width, SD Spec Version, Security 지원여부를 나타낸다.
  5. RCA: Card의 Relative Card Address. (Host가 설정.)
  6. SSR: Card의 Status (Card의 설정된 정보 Card Type, Speed Class, Data bus width)
  7. CSR: Card의 Status (Card의 Error Check & Card의 State)

  • SD Card State & Mode 



2.7  Initialize SD Card 


  • Identification Mode -> Data Transfer Mode



  1. 카드를 삽입하자마자, Card를 Reset을 해준다. (CMD0- GO_IDLE_STATE)
  2. Card의 OCR Register를 읽어온다. (Host의 Capacity 설정) (ACMD41-SD_SEND_OP_COND)
  3. Card의 CID Register를 읽어온다. (CMD2-ALL_SEND_CID)
  4. Card의 RCA Register를 처음에 읽어 올 때는 카드가 RCA 주소를 만든다. (CMD3-SEND_RELELATIVE_ADDRESS)
  5. Host가 RCA Register를 새로 설정해준다. (CMD3-SEND_RELELATIVE_ADDRESS)

*Operation Mode와 State를 혼동하지 말도록.

(자세한 내용은 Spec)


2.8 Data Transfer Mode


주요 Read & Write Command

  • CMD7-SELECT/DESELECT_CARD
  • CMD24-WRITE_BLOCK
  • CMD25-WRITE_MULTIPLE_BLOCK
  • CMD17-READ_SINGLE_BLOCK
  • CMD18-READ_MULTIPLE_BLOCK
  • CMD12-STOP_TRANSMISSION


자세한 Flow 및 부족한 정보들은 아래의 Spec 참조하도록하자.
상위내용들은 아래의 내용에 다 포함되어있다.


  • 참고자료

Physical Layer Simplified Specification Version 2.00