2015.04.10 22:47



디바이스는 하드웨어를 말한다. 

드라이버는 하드웨어를 다루는 소프트웨어를 말한다.

예를 들어보자.

UART 칩이 16개 달려있다고 했을 때 이를 제어하는 드라이버는 하나이다.

하지만 UART 칩이 16개 이니 디바이스는 16개 이다.

 

이제 리눅스 커널로 확장해 보자

arm 코아의 커널을 다루게 되면 항상 수정하거나 참고하는 파일이 있다.

EM-S5PV210  기준으로

arch/arm/mach-s5pv210/mach-ezs5pv210.c  파일이다.

 

이곳에서 보면 struct platform_device  구조체를 흔히 볼수 있다.

이 구조체의 몇몇 멤버를  보자

  • name           문자열 이름
  • id                 정수형 아이디
  • resource      리소스 구조체 포인터 (리소스 구조체는 하드웨의 주소나 인터럽트 정보가 나열된다.)   
  • num_resources    리소스 구조체 개수

다신한번 이 구조체의 이름이 struct platform_device 이다.   즉 디바이스인 것이다.

이 구조체는  아래의 함수를 통해 등록된다.

  • platform_add_devices()       여러개의 디바이스들을 한번에 등록
  • platform_device_register()  하나의 디바이스를 등록

 

 

이제  커널의 driver  디렉토리의 무수한 소스파일들을 보자 

모두다  struct platform_driver  구조체를 품고 있다.

이제 struct platform_driver 구조체의 주요한 멤버를 보자

  • probe         초기 실행함수
  • remove       드라이버 제거시 실행되는 함수
  • driver  =  {  .name       드라이버 이름

이 구조체는  platform_driver_register() 함수를 통해 등록된다.

 

 

이제 흐름을 따라가 보자

커널 시작시 디바이스들이 등록된다.  리소스가 등록되는 것이다.  UART칩이  16개 있다면 디바이스가 16 등록된다.

잠시후에 커널 드라이버가 등록된다.  이때 드라이버의 이름과 동일한 디바이스의 이름이 발견되면 probe() 함수가 호출된다.

동일한 이름의 디바이스가 16개 있다면 이 probe() 함수가 16번 호출된다.

 

참고해야 할것은 struct platform_device 구조체의 id 이다.

디바이스가 하나만 있다면 이값은 -1 로 설정한다.  하지만 2개 이상일 경우 id 는 0 부터 시작해서 각 디바이스마다  고유한 값을 넣는다.,

대게 1씩 순서대로 값을 넣는다.

 

struct platform_device 의 멤버 name 과  struct platform_driver 의  멤버 driver.name 은 동일한 값을 갖는다.

디바이스가 하나일 경우 디바이스의 이름과  드라이버의 이름은 같다.

하지만 디바이스가 여러개 일 경우  드라이버 이름은 보이는 대로의 이름이지만

디바이스의 경우   uart.0   uart.1  이렇게  숫자를 달고 나온다.   id 로 확장된 것이다.

아래의 매크로를 이용하여 디바이스 이름을 얻는다.

  • dev_name(&platform_device->dev)

이제 디바이스 드라이버가  한결 쉬워질 것이다.

신고


Posted by injunech
2015.04.10 22:08


함수포인터


포인터가 무엇인지는 다들 아실텐데요, 특정 변수에 대한 메모리 주소를 담을 수 있는 변수를 포인터 변수라고 합니다. 그렇다면 함수포인터란, 특정 함수에 대한 메모리 주소를 담을 수 있는 것 이라고 정의할 수 있겠습니다.


함수포인터를 쓰는 이유는 무엇일까요?

  1. 프로그램 코드가 간결해집니다.

  2. 함수포인터를 배열에 담아서도 사용할 수 있으므로 중복되는 코드를 줄일 수 있습니다.

  3. 상황에 따라 해당되는 함수를 호출할 수 있으므로 굉장히 유용합니다.

그 외에도 함수 포인터를 이용하여 콜백함수를 구현할 수 있게 되는 등 편리하고 유용한 코드를 작성할 수 있게 됩니다.



우선 함수포인터의 모양에 대해 알아보도록 하겠습니다.

int (*FuncPtr) (intint)


함수포인터는 위와 같은 모양을 띕니다. 함수의 프로토타입 선언과 모양이 비슷하죠?

함수의 프로토타입과 다른점이 있다면 함수 이름앞에 포인터를 가르키는 *이 붙는 다는 것인데요. 이렇게 선언이 되게 되면 FuncPtr 이라는 함수의 주소를 담을수 있는 '변수'가 생기는 것입니다. 

이 FuncPtr 함수포인터가 담을 수 있는 함수는 위와 같은 모양을 띄어야 합니다. 즉, 함수의 리턴형은 int 여야하고, int형 파라미터 2개를 받는 함수여야 하는 것입니다.


예를 들어,

1:  int add (int first, int second)

2: double div (double first, double second)

위의 보이는 두 함수가 있다고 가정할 때, 함수포인터의 선언 모양과 똑같이 생긴 add 라는 함수의 주소만을 담을 수 있는 것입니다. 


아래의 사용 예제를 한 번 더 보시겠습니다.

1
2
3
4
FuncPtr = add    (o)
FuncPtr = &add   (o)
FuncPtr = div    (x)
FuncPtr = add()  (x)


1, 2 :  2가지 방법 모두 괜찮은 사용 방법입니다. 어떤 것을 쓰셔도 무관합니다.
: div는 FuncPtr의 선언 모양과 프로토타입이 달라서 사용할 수 없습니다. 에러가 발생합니다.
4 : add() 처럼 함수를 호출할 때 처럼 쓰는 것은 결과값이 함수의 호출 이후 리턴 값이 되는 것입니다. 따라서 add() 는 int형을 가리키게 되는 것이므로 사용방법 자체가 잘 못 되었습니다. 에러가 발생합니다.



이렇듯 함수포인터는 담고 싶은 함수의 프로토타입을 따라 선언하여 사용하시면 됩니다. 하지만, 이 모양이 복잡하기 때문에 typedef를 이용하여 타입의 모양을 단순화 시키는 작업을 해 줄수도 있습니다.

typedef int (*FuncPtr)(intint)


프로그램 상단에 위와 같이 선언한 후, 실제 사용을 하실 때에는 FuncPtr 이라는 Type으로 새로운 변수를 사용하실 수 있습니다.


1
2
FuncPtr testFP = NULL;
testFP = add;


이렇게 말이죠. 아, 참고로 모든 변수 특히 포인터 변수를 선언해 주실 때, 초기화 해주는 습관은 정말 좋은 습관이십니다 :) 크리티컬 에러를 미리 예방할 수 있는 방법 중 하나입니다.



자 이제 마지막으로, 함수포인터를 이용해서 만든 실제 예제를 한 번 보여드리도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <stdio.h>
 
// 함수포인터 타입 정의
typedef int (*calcFuncPtr)(int, int);
 
 
// 덧셈 함수
int plus (int first, int second)
{
    return first + second;
}
// 뺄셈 함수
int minus (int first, int second)
{
    return first - second;
}
// 곱셈 함수
int multiple (int first, int second)
{
    return first * second;
}
// 나눗셈 함수
int division (int first, int second)
{
    return first / second;
}
 
// 매개변수로 함수포인터를 갖는 calculator 함수
int calculator (int first, int second, calcFuncPtr func)
{
    return func (first, second);     // 함수포인터의 사용
}
 
int main(int argc, char** argv)
{
    calcFuncPtr calc = NULL;
    int a = 0, b = 0;
    char op = 0;
    int result = 0;
     
    scanf ("%d %c %d", &a, &op, &b);
     
    switch (op)    // 함수포인터 calc에 op에 맞는 함수들의 주소를 담음
    {
        case '+' :
            calc = plus;
            break;
 
        case '-':
            calc = minus;
            break;
 
        case '*':
            calc = multiple;
            break;
 
        case '/':
            calc = division;
            break;
    }
     
    result = calculator (a, b, calc);
 
    printf ("result : %d", result);
     
    return 0;
}


실행결과는 다음과 같습니다.


간단한 소스코드라 어려운 점은 없을 겁니다. 혹시 코드에 이해 안가는 부분이 있다면 댓글 남겨주시면 바로 답변 드립니다.



신고


Posted by injunech
2015.04.07 05:11


MyRemote Ver 1.60



MyRemote_Install.exe


MyRemote.zip


신고

'Project > Remote' 카테고리의 다른 글

MyRemote Ver 1.75  (0) 2017.03.12
MyRemote Ver 1.70  (0) 2015.06.04
MyRemote Ver 1.60  (0) 2015.04.07
MyRemote Ver 1.50  (0) 2015.03.02
MyRemote Ver 1.41  (0) 2014.06.08
MyRemote_Install ver1.4  (0) 2014.05.13


Posted by injunech