210 likes | 580 Views
ADC. 울산대 MCSL 김준수. 디바이스 드라이버란 ?. 운영체제는 사용자모드와 커널모드로 나뉨 . 사용자모드에서 필요시 System Call 을 이용해 커널모드 진입 가능 . 디바이스 드라이버는 디바이스를 제어하는 함수들의 모음 . 부팅이 된 후에 모듈로 적재되는 경우도 있기 때문에 일정한 구조로 되어있다 . 디바이스 드라이버는 사용자모드에서 하드웨어 제어를 하기위해 System Call 을 이용해 호출하는 파일. 2.6 Kernel. system call 에 의한 커널의 구체적인 동작
E N D
ADC 울산대 MCSL 김준수
디바이스 드라이버란? 운영체제는 사용자모드와 커널모드로 나뉨. 사용자모드에서 필요시System Call을 이용해 커널모드 진입 가능. 디바이스 드라이버는 디바이스를 제어하는 함수들의 모음. 부팅이 된 후에 모듈로 적재되는 경우도 있기 때문에 일정한 구조로 되어있다. 디바이스 드라이버는 사용자모드에서 하드웨어 제어를 하기위해System Call을 이용해 호출하는 파일
2.6 Kernel • system call에 의한 커널의 구체적인 동작 • Processor가 App을 수행하는 중에 system call 명령을 만나면 커널영역으로 뛰어 들어간다. • 커널 영역에서 device로부터 data 읽기를 요청 • 현재 수행중인 process 를 잠시 멈추기 위해 wait queue에 넣는다 • 새로운 process를 선택
2.6 Kernel Device Driver - 디바이스의 종류가 다양해짐에 따라 상호간의 연관성이 중요시되어 드라이버를 계층화 시켜 관리할 필요성이 점점 제기되었다. - 따라서 2.6커널에서는kobject라는 드라이버 객체 개념이 추가됨. 등록된 버스가 있고 버스에 새로운 디바이스가 장착되면 버스 드라이버가 디바이스를 탐지하고 이에 맞는 드라이버를 찾아 등록하게 된다. ADC는 여러 버스 형태 중 하나인 platform_bus_type라는 가상의 플랫폼 버스 상에 새로운 디바이스를 등록하는 방법이다. (이미 등록된 플랫폼 드라이버(Major)안에서 Device 등록(Minor)를 하는 방식)
ADC 디바이스 드라이버 동작 ADC디바이스 드라이버의 동작 순서는 다음과 같다. • platform_driver등록 • Probe함수 실행(ADC 필수 레지스터초기화) • Probe 과정에서 장치리소스를 확인 / 설정(Clock, platform_data) • Miscdevice등록 (Miscdevice name과 같은 platform_driver매칭) • file_operations등록(.fops name) • file_operations에서 원하는 동작 함수들이 존재 • User App에서 필요한 함수들을 System Call로 호출
알아두어야 할 구조체 Structdevice_driver Structplatform_device & driver Structmiscdevice Structfile_operations
structdevice_driver구조체 #include <linux/device.h> 기타 장치 파일을 등록하는데 필요한 함수를 포함 structdevice_driver { const char *name; //디바이스 드라이버의 이름(필수) structbus_type *bus; //버스 네임(필수) structkobjectkobj; //커널이 관리 structmodule *owner; // 보통 THIS_MODULE int (*probe) (struct device *dev); // 초기화 루틴 int(*remove) (struct device *dev); // 디바이스 제거 루틴 int(*suspend) (struct device *dev, pm_message_t state, u32 level); //절전모드 (필수) int(*resume) (struct device *dev, u32 level); //절전모드 off (필수) …. 생략 };
Structplatform_device #include <platform_device> structplatform_device { const char * name; //platform_driver에 정의된 이름과 같아야 한다. int id; struct device dev; u32 num_resources; struct resource * resource; structplatform_device_id *id_entry; /* arch specific additions */ structpdev_archdataarchdata; };
Miscdevice구조체 #include <linux/miscdevice.h> structmiscdevice { int minor; //Device driver minor number (지정하지 않을시커널이 동적으로 할당) const char *name; //device file Name const structfile_operations *fops; // 파일 연산을 할 때 호출될 함수 정의 … 생략 }
structfile_operations구조체 structfile_operations {structmodule *owner; //보통 THIS_MODULEssize_t(*read) (struct file *, char __user *, size_t, loff_t *);ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);int (*ioctl) (structinode *, struct file *, unsigned int, unsigned long); // Read와 Write만으로 구현하기 곤란한 입출력 처리 int(*open) (structinode *, struct file *); // 응용 프로그램에서 디바이스를 처음 사용하는 경우(필수)int(*release) (structinode *, struct file *); // 종료 …. 생략 };
ADC Platform_driver static structplatform_driver s3c_adc_driver = { .probe = s3c_adc_probe, .remove = s3c_adc_remove, .suspend = s3c_adc_suspend, .resume = s3c_adc_resume, .driver = { .owner = THIS_MODULE, .name = "s3c-adc", }, };
Device Dirver Init 어떤 디바이스 드라이버든지 최초는 Init 함수를 통한 등록이다. int __init s3c_adc_init(void){ printk(banner); return platform_driver_register(&s3c_adc_driver);} // Platform_driver등록 } module_init(s3c_adc_init);
Probe 함수가 호출되기 전에! • platform_driver_register() 함수가 call된 이후에 xxxx_probe()함수가 call이 되려면 선행되야하는 작업이 있다 먼저 platform_add_devices() 함수를 통해서 platform device가 등록이 되어 있어야 한다. 이때 platform_add_devices와 platform_driver_register에서 .name이 동일해야함을 주의 해야 한다.
Probe 함수가 호출되기 전에! /kernel/arch/arm/plat-s5p/devs.c static struct resource s3c_adc_resource[] = { [0] = { .start = S3C_PA_ADC, // ADC Register주소 .end = S3C_PA_ADC + SZ_4K - 1, // 주소 마지막 값 .flags = IORESOURCE_MEM, // resource type }, #include <mach/map.h> #define S3C_PA_ADC S3C_ADDR(0xE1700000) //주소값 정의
Probe 함수가 호출되기 전에! structplatform_device s3c_device_adc = { .name = "s3c-adc", //platform_driver와 이름이 같아야 한다. .id = -1, // 여러 개의 플랫폼 디바이스가 있을경우id로 구분 .num_resources = ARRAY_SIZE(s3c_adc_resource), //리소스 테이블 수 .resource = s3c_adc_resource, 리소스 테이블 시작 주소 };
Probe 함수가 호출되기 전에! /kernel/arch/arm/mach-s5pv210/mach-mango210.c static structplatform_device *mango210_devices[] __initdata = { &s3c_device_adc, // platform_device name 매칭 } static void __init mango210_machine_init(void){ s3c_adc_set_platdata(&s3c_adc_platform); platform_add_devices(mango210_devices, ARRAY_SIZE(mango210_devices)); // 플랫폼 등록 } 위와같이 최종적으로 Platform 디바이스 드라이버의 등록이 되고 Probe함수가 동작된다.
ADC Probe 조금더 상세하게 들어가서 Probe함수는 어떤 동작을 하는가 보자 static int __init s3c_adc_probe(structplatform_device *pdev) { struct resource *res; struct device *dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //리소스(디바이스에 할당된 자원 범위) 가져오기 dev = &pdev->dev; //// pdev라는 플랫폼 디바이스의 멤버들을 dev 의 멤버들로 cast 시킨다. 따라서 pdev는 dev를 가르키게 된다 <platform_device.h> extern struct resource *platform_get_resource (structplatform_device *, //플랫폼 디바이스 네임 unsigned int, // flags unsigned int);
ADC Probe static struct resource *adc_mem; // Global define static void __iomem *base_addr; // Global define ////static void __iomem변수명 선언을 하는 이유 Writel, readl같은 core register접근 함수에 위와같은데이터형으로 선언이 되어있기 때문이다. size = (res->end - res->start) + 1; //메모리 사이즈 설정 base_addr = ioremap(res->start, size); // 가상 메모리 번지 생성 adc_clock = clk_get(&pdev->dev, "adc"); // 클럭 생산자 생성 clk_enable(adc_clock); … 생략 (생략 내용 : prescaler, delay 등등 register init) ret = misc_register(&s3c_adc_miscdev); //miscdevice와 매칭을 한다.
Miscdevice static structmiscdevice s3c_adc_miscdev = { .minor = ADC_MINOR, .name = "adc", //device file name .fops = &s3c_adc_fops, }; Miscdev등록이 끝나면 FileSystem상에서 /dev/adc라는 디바이스 파일이 생성이 되어있다. 이것은 /etc/udev의 규칙파일에 의해서 자동적으로 된다.
User App에서 ADC Driver 사용 디바이스 드라이버의 File_operation구조체를 보면 Ioctl Read Open 등이 존재한다. 그 내용을 들여다 보면 IOCTL은 ADC PORT설정 READ는 buffer크기만큼 ADC 데이터 읽기 OPEN은 디바이스 드라이버를 쓰기위해 선행되야하는 필수 Call이다.