LED GPIO 드라이버 추가하기

Posted in 단체/ㄴKETI 연수생 by

### Flow Chart ###

ㅁㅁㅁ        하드웨어        ㅁㅁㅁ

ㅁㅁㅁ        커널              ㅁㅁㅁ

   - kernel/arch/arm/mach-s5pv210/mach-mango210.c : platform_data 및 platfom_device 생성

   - kernel/drivers/char/IR/ir-nec-encoder.c : driver를 통해 .name이 같은 device를 찾아 data 구조체를 갖고와서 컨트롤 

ㅁㅁㅁ        System call    ㅁㅁㅁ

   - System call을 이용하여 ir-nec-encoder에 정의되어 있는 함수를 호출

ㅁㅁㅁ        Application     ㅁㅁㅁ

   - App에서 System call을 호출하여 커널 디바이스 드라이버를 컨트롤


### 01. Platform data 및 device 생성하기 ###

1. 아래에서 생성할 Platform data 구조체를  : include/linux/myled.h

    → 2번에서 생성할 data 구조체를 정의해놓는다. (참고 : include/linux/smr210_ir_nec_encoder.h)

2. Data 및 Device 생성 : /kernel/arch/arm/mach-s5pv210/mach-mango210.c

    → mango210.c에서 CONFIG_SMR210_IR_NEC_ENCODER 심벌로 정의되어 있는 부분 참고(2부분)

    → 1부분 : Data 구조체와 Device 구조체 생성 // 2부분 *mango210_device[] __initdata에 생성한 Device 추가

    → 새로 정의하는 심벌이름은 CONFIG_MY_GPIO_LED로 하겠다

    → LED 주소값 설정 : (data구조체 변수).gpio_tx = S5PV210_GPH2(0)


### 02. LED 드라이버 추가 ###

1. 위에서 정의한 data와 device를 컨트롤할 드라이버 구현

    → drivers/leds/폴더명 (참조 : drivers/char/IR/Makefile, Kconfig, ir-nec-encoder.c 3파일 Modify)

    → ir-nec-encoder.c 파일이름을 변경 : mv ir-nec-encoder.c myled.c

    → Makefile 수정 : 심볼이름을 위에서 정의한 심볼(CONFIG_MY_GPIO_LED)로 바꾸고 오브젝트 파일을 myled.o로 바꾼다

    → KConfig 수정 : 기존 내용을 다 지우고 아래 내용을 추가해준다 (menuconfig가 CONFIG_라는 이름을 자동으로 붙여줌)

config MY_GPIO_LED

bool "GPH2[0] LED ADD SYMBOL"


2. 드라이버 기능을 myled.c 파일에 선언과 정의

     → 01번에서 정의한 Platform data 구조체를 사용해야 하니 #include <linux/myled.h>를 해준다

     → static struct platform_driver myled_device_driver을 정의해주고 구조체변수들을 입력

     → driver의 구조체변수 .probe, .remove 함수포인터 전달 & .driver = {.name="myled"}은 mach-mango210.c에서 

         "myled"와 같은 드라이버를 찾아서 그 디바이스 주소값을 넘겨준다.(이를 통해 접근하면서 디바이스를 컨트롤)

     → static int __init myled_init() 정의와 안에 platform_driver_register(&myled_device_driver)를 통해 드라이버 등록

     → static void __exit myled_exit() 정의와 안에 platform_driver_unregister(&myled_device_driver)를 통해 드라이버 해제

     → module_init(myled_init) 선언 - insmod로 불려지는 함수, module_exit(myled_exit) 선언 - rmmod로 불려지는 함수 


### 03. Makefile, Kconfig 의존성 해결(Menuconfig 추가하기) ###

1. Makefile 의존성 해결

    → myled의 Makefile이 실행되기 위해 상위 Makefile을 수정해줘야 한다

    → leds/Makefile에 obj-$(CONFIG_MY_GPIO_LED)    += myled/ 를 추가시켜준다

2. Kconfig 의존성 해결

    → make menuconfig 에서 CONFIG_MY_GPIO_LED을 체크하려는 창을 만들려면 myled의 Kconfig를 수정해야한다.

    → if NEW_LEDS 아래에 source "drivers/leds/myled/Kconfig"를 추가해준다

    → 그러면 make menuconfig에서 drivers-LED를 체크해주면 NEW_LEDS가 정의되어 있으니 Source 파일이 활성화되면서 

  우리가 추가해준 myled의 Kconfig가 보인다

    → MY_GPIO_LED 심볼을 활성화하여 CONFIG_MY_GPIO_LED 심볼이 활성화되도록 한다

    → kernel/.config 와 kernel/include/linux/autoconf.h 에서 CONFIG_MY_GPIO_LED 심볼이 추가됐는지 확인


### 04. System Call 추가하기 ###

1. System Call 번호 할당 : $ /kernel/arch/arm/include/asm/unistd.h (각 시스템 호출의 고유 번호가 정의되어 있음)

    → 새로 추가할 System call의 고유번호 정의 추가 : #define __NR_my_gpio_led                                [__NR_심볼명]

2. System Call 테이블에 처리 함수 등록 : $ /kernel/arch/arm/kernel/calls.S

    → System Call 처리함수 등록 : CALL(sys_my_gpio_led)                                                      [CALL(sys_심볼명)]

    → entry-common.S파일에서 ENTRY(sys_call_table)이 calls.S를 include하고 있기 때문에 calls.S를 수정하는 것

3. 처리 함수 구현 : /kernel/kernel/my_gpio_led.c                                                                                 [파일명.c]

    → System Call 이 발생했을 때 수행될 함수를 구현

    → asmlinkage 반환자료형 sys_my_gpio_led(...) { 내용 } : 2번에서 CALL로 등록한 이름과 동일해야 함 [sys_심볼명]

4. Makefile 수정 : /kernel/kernel/Makefile 에 3번에서 구현한 '파일명.c'의 오브젝트 파일을 생성할 수 있도록 조건 추가

    → obj-y    = ***.o ***.o my_gpio_led.o                                                                                           [파일명.o]

5. Kernel 컴파일 수행 및 커널 이미지 복사 : ./fastbuild ( make && cp zImage ../../sdboot/zImage )

6. Kernel 이미지 퓨징 : sudo ./sdwriter_maple210 sdb


### 05. Android App 추가하기 : System call Test ###

1. Application 작성 : Android_work/external/디렉토리

    → external에 새로운 작업 디렉토리를 만든다

    → 작업디렉토리에 소스파일(my_gpio_led.c)를 만들고 System call를 호출한다(syscall(__NR_my_gpio_led))

2. 안드로이드 어플 Makefile 작성 : Android_work/external/디렉토리/Android.mk

    → 파일명.c은 위에서 작성한 소스파일명과 동일, 모듈이름은 안드로이드 프롬프트에서 실행할 명령어

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_C_INCLUDES:= \

$(LOCAL_PATH)/include \

$(LOCAL_PATH)/android

LOCAL_SRC_FILES:= \

my_gpio_led.c                                                                                                          [파일명.c]

LOCAL_MODULE:= my_gpio_led                                                                                     [실행 명령어]

include $(BUILD_EXECUTABLE)

3. 컴파일 및 설치 : Android_work/

    → 컴파일 한 후 실행파일을 rootfs/system/bin에 복사

$ . build/envsetup.sh

$ chooseproduct sec_smdkv210

$ mmm external/디렉토리/

$ cp out/target/product/smdkv210/system/bin/my_gpio_led rootfs/system/bin

4. rootfs 를 묶어서 sdboot로 이동 : Android_work/rootfs/

    → rootfs 폴더에서 $ tar cvfz ../../sdboot/maple210_android210.tgz .

    → Kernel 이미지와 안드로이드 이미지 퓨징 $ sudo ./sdwrite_maple210 sdb

5. 테스트

    → sh-4.0 # 모듈명