리눅스 임베디드 개발기록 (2) 디바이스 드라이버

        이전 섹션에서는 드라이버를 컴파일하는 방법을 주로 설명했습니다. 이 섹션에서는 개발을 주도하는 프로세스를 주로 설명합니다.

        1. 드라이버가 왜 필요한가요?

        디바이스 드라이버는 이름에서 알 수 있듯이 반드시 사용해야 하는 장치인데, 리눅스에서는 애플리케이션 계층이 하드웨어 장치를 직접 조작할 수 없기 때문에 애플리케이션 계층이 호출할 수 있도록 제공하기 위해 구체적으로 장치를 조작하는 프로그램이 필요하다. 이러한 프로그램을 드라이버라고 합니다. 글쎄요, 사실은 장비를 다루어야 하는 프로그램입니다.

        2. 개발을 주도하는 프로세스는 무엇입니까?

        버전 2.6 이전 드라이버의 경우 기본적으로 지금은 신경 쓸 필요가 없으며 주로 버전 2.6 이후의 드라이버에 중점을 둡니다. 크게 4가지 프로세스로 나누어보겠습니다. 다음은 주로 문자 장치 드라이버를 예로 들어 설명합니다.

        드라이버에 대해 이야기하기 전에 먼저 애플리케이션 계층이 장치를 사용하는 방법을 살펴보겠습니다. 기본 단계는 먼저 장치를 열고 open("/dev/led")한 다음 쓰기, 읽기, ioctl 및 기타 메서드를 호출하여 장치를 작동하는 것입니다. 마지막으로 작업이 끝나면 close()를 사용하여 장치를 끄십시오. 그렇다면 애플리케이션 레이어에서 가장 주의해야 할 점은 무엇일까요? dev 아래에 있는 노드입니다. 이 노드는 어디에서 왔습니까? 이를 생성하는 방법에는 두 가지가 있는데, 하나는 드라이버에서 udev 장치 관리 방법을 사용하는 것이고, 다른 하나는 mknod 명령을 사용하는 것입니다. 장치 드라이버가 장치 노드 자동 생성을 지원하지 않는 경우 드라이버 사용자가 장치 노드를 생성해야 합니다. 이 장치의 이름이 주도되고, 메이저 장치 번호는 240, 마이너 장치 번호는 0이라고 가정해보자. 장치 노드를 생성하는 명령은 #mknod /dev/led c 240 0이다. 이렇게 하면 노드/ led는 /dev/ 아래에 생성됩니다. udev를 사용하여 장치 노드를 만드는 방법은 무엇입니까? 주로 두 가지 고정 함수를 호출합니다. 먼저, class_create()를 호출하여 장치에 대한 클래스를 생성한 다음, device_create를 다시 호출하여 장치에 해당하는 장치 노드를 생성합니다. 다음은 udev에서 노드를 생성하는 코드입니다.

///sys/class 아래에 led_class 디렉토리를 생성합니다.

led_class = class_create(THIS_MODULE,"led_class");

///dev/led%d 노드 파일을 생성합니다.

device_create(led_class,NULL,devno,NULL,"led","%d",MINOR(devno));

여기에 devno MINOR(devno)가 나타납니다. 이것들은 무엇입니까? 돌아가서 mknod를 사용하여 노드를 생성하는 방법을 살펴보겠습니다. mknod를 사용하여 노드를 생성할 때 세 가지 매개 변수, 이름 및 주요 장치 번호를 알아야 합니다. , 마이너 장치 번호. 네임 LED는 우리가 쉽게 추측할 수 있어서 메이저 장치 번호 하나, 마이너 장치 번호 하나 총 2개만 남았는데, 마스터는 누구일까요? devno는 주 장치이고 MINOR(devno)는 주 장치 번호를 기준으로 부 장치 번호를 찾습니다.

위에서부터 드라이버가 완성된 후 우리에게 어떤 것을 제공해야 하는지 쉽게 알 수 있습니까? 첫 번째 메이저 장치 번호, 두 번째 마이너 장치 번호, 세 번째 장치 이름, 네 번째 장치 작동을 위한 인터페이스입니다. 글쎄, 드라이버는 그렇게 간단합니다. 위의 네 가지 질문을 완료하면 드라이버가 준비된 것입니다! 자, 아래에서 이 네 가지 질문이 완료되었는지 살펴보겠습니다. 그러면 드라이버가 완성됩니다.

 1. 기존 문자 장치 드라이버.

1. 보조 장치 번호

static int major = 0; // 마이너 장치 번호를 0으로 설정합니다.

2. 본체번호

dev_t devno;

ret = alloc_chrdev_region(&devno,minor,1,"led"); //시스템에서 주요 장치 번호를 가져옵니다.

major = MAJOR(devno);//주요 장치 번호를 가져옵니다.

major = MINOR(devno); //마이너 장치 번호를 가져옵니다.

3. 작동 장치 인터페이스.

구조체 파일_작업 led_cdev_fops = {

        .소유자 = THIS_MODULE,

        .read = led_cdev_read,

        .write = led_cdev_write,

        .open = led_cdev_open,

        .ioctl = led_cdev_ioctl

}; //장치 작동 인터페이스

struct cdev *led_dev; //cdev 데이터 구조

led_dev = cdev_alloc(); //led_dev 구조체를 할당합니다.

cdev_init(led_dev,&led_cdev_fops ); //led_dev 구조를 초기화합니다. 이 구조는 장치 작업과 연관되어 있습니다.

cdev_add(led_dev,devno,1); //led_dev를 시스템에 추가합니다. 여기에 작업을 주요 장치 번호와 연결하는 devno가 도입되었습니다. ,

4. /dev/ 아래에 장치를 생성합니다.

led_class = class_create(THIS_MODULE,"led_class");

device_create(led_class,NULL,devno,NULL,"led",NULL); 

이쯤 되면 기존의 디바이스 드라이버가 완성되는데, 이를 module_init();에 로딩하고, 해당 컴파일 툴을 이용해 컴파일한 뒤 Arm 보드에 넣어 적용하면 된다.

 2. 장치 드라이버 모델의 캐릭터 드라이버.

        장치 드라이버 모델은 주로 커널에 의한 장치, 드라이버 및 버스 관리입니다. 그리고 이러한 관리 정보를 위에서 언급한 udev 생성 장치와 같은 애플리케이션 계층에 노출합니다. 이는 장치 드라이버 모델의 일부입니다. /dev/led를 사용자에게 노출시켜 사용자가 이해하고 사용할 수 있도록 합니다. 관리는 kobject, kset 및 subsys를 통해 Linux 커널에서 수행됩니다. 드라이버 작성은 이러한 관리 메커니즘의 특정 구현을 무시할 수 있지만 사용자에게 노출되는 정보가 무엇인지, 이 정보가 무엇을 나타내는지 알아야 합니다. 다음은 주로 노출되는 정보와 해당 정보 간의 관계에 대해 설명합니다.

1. 드라이버 모델 정보는 sysfs 파일 시스템을 통해 노출됩니다. 1. 디바이스 드라이버 모델의 상위-하위 관계는 sysfs의 상위 디렉터리와 하위 디렉터리를 통해 구현됩니다. 2. 디바이스 드라이버 모델의 수평적 관계는 sysfs의 디렉토리 심볼릭 링크를 통해 구현됩니다. 3. 드라이버 모델의 속성은 sysfs 파일 시스템의 파일 내용을 통해 구현됩니다. 4. 장치 드라이버 모델 데이터 구조의 kobject는 sysfs 파일 시스템의 디렉터리에 해당하고 데이터 구조의 struct 속성 멤버는 sysfs 파일 시스템의 파일에 해당합니다. sysfs 파일 시스템은 /sys 아래에 마운트됩니다.

2. 장치, 드라이버, 버스. 새 장치나 드라이버가 버스에 추가되면 해당 장치나 드라이버에 일치하는 드라이버나 장치를 찾기 위해 버스의 match 메서드가 호출됩니다.

3. 클래스는 Linux 장치 드라이버 모델의 상위 수준 추상화로, 사용자 공간에 장치에 대한 상위 수준 보기를 제공합니다. sysfs에서 클래스는 일반적으로 /sys/class 디렉토리에 배치됩니다. 클래스 하위 시스템에서는 정보를 사용자 공간으로 내보낼 수 있으며, 사용자 공간은 이 정보를 통해 커널과 상호 작용할 수 있습니다. 가장 일반적인 것은 앞서 이야기한 udev입니다. udev는 ./sys/class 디렉터리의 dev 파일을 기반으로 장치 노드를 생성하는 사용자 공간 프로그램입니다. 클래스 디렉터리의 노드는 ./dev 아래에 노드가 있는 것으로 이해될 수 있습니다.

4. 실제 파일 노드는 /sys/devices/에 생성됩니다. 버스 아래의 장치 클래스 및 하위 디렉터리와 같은 다른 디렉터리에 나타나는 장치는 기호 링크를 사용하여 /sys/devices/ 디렉터리의 파일을 가리킵니다.

3. 플랫폼 장치 및 드라이버용 문자 드라이버.

        플랫폼 장치는 platform_device와 platform_driver의 두 가지 핵심 개념을 추상화합니다. 이와 관련된 또 다른 중요한 개념은 자원입니다.

        구조체 리소스{

                resource_size_t start; //CPU 리소스의 시작 주소

                resource_size_t end; //CPU 리소스의 물리적 끝 주소

                const char *name; //리소스 이름

                unsigned long flags; //리소스 플래그

                struct Resource *parent, *sibing,*child; //리소스의 아버지, 형제 및 자식 리소스

        }; //리소스의 경우 구조에 주의를 기울여 리소스에 어떤 콘텐츠가 포함되어 있는지 확인해야 합니다.

장치는 여러 리소스를 점유할 수 있습니다.

1. 플랫폼 장비. 어떤 장치도 platform_device로 추상화될 수 없습니다. platform_device는 시스템에서 독립적인 개체로 나타나는 장치입니다. 이러한 장치의 공통점 중 하나는 CPU가 버스를 통해 직접 액세스할 수 있다는 것입니다. 먼저 플랫폼 장치에 무엇이 포함되어 있는지 살펴보겠습니다.

 스트럿 플랫폼_장치{

        const char *name; //디바이스 이름

        int id; //장치 ID

        struct device dev; //디바이스 데이터 구조

        u32 num_resources; //리소스 개수

        struct resources *resources; //디바이스 리소스

        const struct platform_device_id *id_entry; //장치 ID 항목

        struct pdev_archdata archdata; //아키텍처 관련 데이터

};

        name은 장치의 이름으로 platform_driver와 일치하고 바인딩하는 데 사용되며, 리소스는 주소, IRQ 등과 같은 장치의 리소스를 설명하는 데 사용됩니다. 장치의 경우 주로 이름과 리소스에 중점을 둡니다.

2. 플랫폼 드라이버 platform_driver는 device_driver의 캡슐화이며 드라이버의 검색 및 제거 방법을 제공합니다. 전원 관리와 관련된 종료, 정지 등의 방법도 제공됩니다.

구조체 플랫폼_드라이버{

        int (*probe)(struct platform_device *) // 프로브 방법

        int (*remove)(struct platform_device *) // 제거 방법

        void (*shutdown)(struct platform_device *); //종료 방법

        int (*일시중단)(struct platform_device*, pm_message_t state); //일시 중지 방법

        int (*resume)(struct platform_device *); //재개 방법

        struct device_drive 드라이버; //장치 드라이버

        const struct platform_device_id *id_table; //장치 ID 테이블

};

3. 일반 드라이버와 플랫폼 드라이버의 차이점. 일반 드라이버와 플랫폼 드라이버의 차이점은 프레임워크 구조의 변화와 리소스 적용 및 릴리스 위치의 변화에 ​​있습니다. 1. 리소스 적용, 장치 등록 등이 일반 캐릭터 드라이버의 모듈 초기화 부분에서 플랫폼 드라이버의 프로브 방식으로 이동됩니다. 2. 장비의 취소. 리소스 릴리스 및 기타 측면이 일반 문자 기반 모듈 종료 코드에서 플랫폼 기반 제거 방법으로 이동되었습니다. 3. 플랫폼 드라이버는 리소스 정의 및 초기화, 플랫폼 장치 및 드라이버 정의 및 초기화도 추가합니다.

4. 플랫폼 드라이버 예:

       1. 플랫폼 장비.

        플랫폼 장치의 경우 세 가지 작업만 수행하면 됩니다. 1. 이 장치에는 어떤 리소스가 있습니까? 2. 이 장치 데이터 구조입니다. 3. 플랫폼 장비를 등록합니다.

        (1) 자원을 정의합니다.

        정적 구조체 리소스 led_resource[]={

        [0]={

                .start = GPIO_LED_PIN,

                .end = GPIO_LED_PIN,

                .flags = IORESOURCE_IO,

                },

        };

        (2), 장치 데이터 구조

        정적 구조체 platform_device *led_platform_device = {

                .name = "led", //드라이버의 이름은 이 이름과 동일해야 합니다.

                .id = -1,

                .num_resources = ARRAY_SIZE(led_resource); 

                .resource = led_resource,

                

                

        };

        (3) 플랫폼 장비를 등록합니다.

        platform_device_register(&lef_platform_device);

        두 개의 플랫폼 드라이버.

        플랫폼 드라이버의 경우 일반 드라이버에 필요한 4단계 외에도 플랫폼 장치에서 리소스를 얻은 다음 플랫폼 드라이버를 등록해야 합니다.

        1. 플랫폼 장치에서 리소스를 얻습니다.

        구조체 리소스 *res_io;

        res_io = platform_get_resource(pdev,IORESOURCE_IO,0);

        int led_io = res_io.start; //GPIO 핀을 가져옵니다.

        2. 보조 장치 번호를 정의합니다.

       정적 int 마이너 = 0;

        3. 본체번호

        ret = alloc_chrdrv_region(&devno,minor,1,"led");

        메이저 = MAJOR(devno);

       4. 작동 장치 인터페이스.

        struct cdev *led_dev; //cdev 데이터 구조

        구조체 파일_작업 led_fops = {

                .소유자 = THIS_MODULE,

                .open = led_open, //led_open은 일반적으로 하드웨어를 사용 가능하게 만들기 위해 직접 구현해야 하는 함수입니다.

                .write = led_write,

                .read = led_read,

                .ioctl = led_ioctl

        };

        led_dev = cdev_alloc(); //

        cdev_init(led_dev,&led_fops); //초기화, 이 위치에 연산 함수가 추가되어 있으니 참고하세요

        cdev_add(led_dev,devno,1); //시스템에 LED 추가

        5. /dev 아래에 장치를 생성합니다.

        led_class = class_create(THIS_MODULE,"led_class");

        device_create(led_class,deno,NULL,"led");

        6. 플랫폼 드라이버에 등록합니다.

        구조체 platform_driver led_platform_driver = {

                .probe = led_probe,

                .remove = led_remove,

                .드라이브={

                        .name = "주도",

                        .소유자 = THIS_MODULE,

                }

        };

        platform_driver_register(&led_platform_driver);

 4. 디바이스 트리의 캐릭터 드라이버에 대하여.

        장치 트리의 문자 드라이버는 현재까지 드라이버 개발의 최신 프로세스입니다. 일반 장치 드라이버 및 플랫폼 장치 드라이버와 어떻게 다른가요? 가장 큰 차이점은 하드웨어를 설명하는 데 사용되는 추가 장치 트리가 있다는 점입니다. 돌아보면 일반 장치 드라이버와 플랫폼 드라이버에서 하드웨어를 설명하는 위치를 살펴보겠습니다. 일반 장치 드라이버에서는 초기화 과정에서 하드웨어 정보를 초기화하고 설명하고, 플랫폼 드라이버에서는 하드웨어 리소스 정보를 플랫폼 장치에 넣습니다. 그렇다면 이 하드웨어 정보는 장치 트리의 드라이버에서 어떻게 보일까요? 먼저, 커널에 진입한 후 최종적으로 디바이스 트리가 어떤 모습인지 살펴보겠습니다. Linux 소스 코드를 추적하면 장치 트리가 구문 분석된 후 of_device_add()가 마침내 해당 장치 트리 노드에 의해 생성된 device_node 노드를 platform_device의 dev.of_node에 연결한다는 것을 알 수 있습니다. 맞습니다. 결국 장치 트리의 각 장치는 플랫폼 장치로 구문 분석됩니다. 시스템은 이미 장치 트리를 읽어 플랫폼 장치를 작성했으므로 장치 드라이버만 구현하면 됩니다. 나머지는 플랫폼 장치 드라이버 작성과 동일합니다. 드라이버의 하드웨어 정보를 얻으려면 of 함수가 호출됩니다.

Supongo que te gusta

Origin blog.csdn.net/dreamliweiming/article/details/126990229
Recomendado
Clasificación