Android 구조 분석의 Android 드라이버 개발

14565 단어 Android 구조 분석
저자: 유 호 욱 
블 로그:http://blog.csdn.net/liuhaoyutz
Android 버 전: 2.3.7r1
Linux 커 널 버 전: android - goldfish - 2.6.29
 
본 고 는 어떻게 안 드 로 이 드 드라이버 를 개발 하고 테스트 하 는 지 를 소개 한다.
 
1. Android 드라이버 개발
Android 는 Linux 기반 이기 때문에 Android 드라이버 개발 방법 은 Linux 드라이버 개발 방법 과 같 습 니 다.
다음은 하나의 예 프로그램 을 통 해 안 드 로 이 드 드라이버 의 개발 을 익 혀 보 겠 습 니 다. 여 기 는 간단 한 설명 일 뿐 입 니 다. 만약 에 리 눅 스 드라이버 개발 에 대해 서도 잘 모 르 면 리 눅 스 Device Driver 나 참고 한 제 블 로그 의 시리즈 문장 을 배 울 수 있 습 니 다.
우선 Android 커 널 소스 의 drivers 디 렉 터 리 에 새 디 렉 터 리 example 를 만 듭 니 다. 드라이버 소스 코드 는 이 디 렉 터 리 에 놓 여 있 습 니 다.
# mkdir drivers/example
# cd drivers/example
 
example. h 파일 을 만 듭 니 다. 그 내용 은 다음 과 같 습 니 다. 
 1#ifndef _EXAMPLE_H_
 2#define _EXAMPLE_H_
 3
 4#include 
 5#include 
 6
 7#define EXAMPLE_DEVICE_NODE_NAME  "example"
 8#define EXAMPLE_DEVICE_FILE_NAME  "example"
 9#define EXAMPLE_DEVICE_PROC_NAME  "example"
10#define EXAMPLE_DEVICE_CLASS_NAME "example"
11#define EXAMPLE_MAJOR 0
12
13struct example_dev {
14    struct semaphore sem;
15    struct cdev cdev;
16    int val;
17};
18
19#endif

이 헤더 파일 은 드라이버 에 사용 할 매크로 를 정의 하고 장치 구조 체 example 을 정의 합 니 다.dev, 이 구조 체 의 구성원 sem 은 장치 에 대한 동기 화 접근 을 보장 하 는 데 사 용 됩 니 다. cdev 는 이 장 치 는 Linux 장치 구동 의 문자 장치 이 고, val 은 이 장치 의 레지스터 를 대표 합 니 다. 이 드라이버 의 역할 은 사용자 층 응용 프로그램 에 이 val 레지스터 를 읽 고 쓰 는 방법 을 제공 하 는 것 입 니 다.
 
example. c 파일 을 만 듭 니 다. 그 내용 은 다음 과 같 습 니 다.
  1#include 
  2#include 
  3#include 
  4#include 
  5#include 
  6#include 
  7#include 
  8
  9#include "example.h"
 10
 11static int example_major = EXAMPLE_MAJOR;
 12static int example_minor = 0;
 13
 14static struct class* example_class = NULL;
 15static struct example_dev* example_dev = NULL;
 16
 17module_param(example_major, int, S_IRUGO);
 18module_param(example_minor, int, S_IRUGO);
 19
 20static int example_open(struct inode* inode, struct file* filp)
 21{
 22    struct example_dev* dev;
 23
 24    /*
 25     *        example_dev,   filp      ,         。
 26     */
 27    dev = container_of(inode->i_cdev, struct example_dev, cdev);
 28    filp->private_data = dev;
 29
 30    return 0;
 31}
 32
 33static int example_release(struct inode* inode, struct file* filp)
 34{
 35    return 0;
 36}
 37
 38static ssize_t example_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos)
 39{
 40    struct example_dev* dev = filp->private_data;
 41    ssize_t retval = 0;
 42
 43    /*
 44     *   
 45     */
 46    if(down_interruptible(&(dev->sem)))
 47        return -ERESTARTSYS;
 48
 49    if(count < sizeof(dev->val))
 50        goto out;
 51
 52    /*
 53     *            。
 54     */
 55    if(copy_to_user(buf, &(dev->val), sizeof(dev->val)))
 56    {
 57        retval = -EFAULT;
 58        goto out;
 59    }
 60
 61    retval = sizeof(dev->val);
 62
 63out:
 64    /*
 65     *   
 66     */
 67    up(&(dev->sem));
 68    return retval;
 69}
 70
 71static ssize_t example_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos)
 72{
 73    struct example_dev* dev = filp->private_data;
 74    ssize_t retval = 0;
 75
 76    /*
 77     *   
 78     */
 79    if(down_interruptible(&(dev->sem)))
 80        return -ERESTARTSYS;
 81
 82    if(count != sizeof(dev->val))
 83        goto out;
 84
 85    /*
 86     *               。
 87     */
 88    if(copy_from_user(&(dev->val), buf, count))
 89    {
 90        retval = -EFAULT;
 91        goto out;
 92    }
 93
 94    retval = sizeof(dev->val);
 95
 96out:
 97    /*
 98     *   
 99     */
100    up(&(dev->sem));
101    return retval;
102}
103
104/*
105 *        
106 */
107static struct file_operations example_fops =
108{
109    .owner = THIS_MODULE,
110    .open = example_open,
111    .release = example_release,
112    .read = example_read,
113    .write = example_write,
114};
115
116
117/*
118 *              。
119 */
120static ssize_t __example_get_val(struct example_dev* dev, char* buf)
121{
122    int val = 0;
123
124    if(down_interruptible(&(dev->sem)))
125        return -ERESTARTSYS;
126
127    val = dev->val;
128    up(&(dev->sem));
129
130    return snprintf(buf, 30, "%d
", val); 131} 132 133/* 134 * 。 135 */ 136static ssize_t __example_set_val(struct example_dev* dev, const char* buf, size_t count) 137{ 138 int val = 0; 139 140 val = (int)simple_strtol(buf, NULL, 10); 141 142 if(down_interruptible(&(dev->sem))) 143 return -ERESTARTSYS; 144 145 dev->val = val; 146 up(&(dev->sem)); 147 148 return count; 149} 150 151/* 152 * 。 153 */ 154static ssize_t example_val_show(struct device* dev, struct device_attribute* attr, char* buf) 155{ 156 struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev); 157 158 return __example_get_val(hdev, buf); 159} 160 161/* 162 * 。 163 */ 164static ssize_t example_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) 165{ 166 struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev); 167 168 return __example_set_val(hdev, buf, count); 169} 170 171/* 172 * DEVICE_ATTR dev_attr_val。 173 * "val“, example_val_show example_val_store。 174 */ 175static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, example_val_show, example_val_store); 176 177/* 178 * /proc 。 179 */ 180static ssize_t example_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) 181{ 182 if(off > 0) 183 { 184 *eof = 1; 185 return 0; 186 } 187 188 return __example_get_val(example_dev, page); 189} 190 191/* 192 * /proc 。 193 */ 194static ssize_t example_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) 195{ 196 int err = 0; 197 char* page = NULL; 198 199 if(len > PAGE_SIZE) 200 { 201 printk(KERN_ALERT"The buff is too large: %lu.
", len); 202 return -EFAULT; 203 } 204 205 page = (char*)__get_free_page(GFP_KERNEL); 206 if(!page) 207 { 208 printk(KERN_ALERT"Failed to alloc page.
"); 209 return -ENOMEM; 210 } 211 212 if(copy_from_user(page, buff, len)) 213 { 214 printk(KERN_ALERT"Failed to copy buff from user.
"); 215 err = -EFAULT; 216 goto out; 217 } 218 219 err = __example_set_val(example_dev, page, len); 220 221out: 222 free_page((unsigned long)page); 223 return err; 224} 225 226/* 227 * /proc 228 */ 229static void example_create_proc(void) 230{ 231 struct proc_dir_entry* entry; 232 233 entry = create_proc_entry(EXAMPLE_DEVICE_PROC_NAME, 0, NULL); 234 if(entry) 235 { 236 entry->owner = THIS_MODULE; 237 entry->read_proc = example_proc_read; 238 entry->write_proc = example_proc_write; 239 } 240} 241 242/* 243 * /proc 244 */ 245static void example_remove_proc(void) 246{ 247 remove_proc_entry(EXAMPLE_DEVICE_PROC_NAME, NULL); 248} 249 250/* 251 * example_dev。 252 */ 253static int __example_setup_dev(struct example_dev* dev) 254{ 255 int retval; 256 257 /* 258 * 259 */ 260 dev_t devno = MKDEV(example_major, example_minor); 261 262 /* 263 * 0。 264 */ 265 memset(dev, 0, sizeof(struct example_dev)); 266 267 /* 268 * cdev , owner 。 269 */ 270 cdev_init(&(dev->cdev), &example_fops); 271 dev->cdev.owner = THIS_MODULE; 272 dev->cdev.ops = &example_fops; 273 274 /* 275 * cdev_add, 。 276 */ 277 retval = cdev_add(&(dev->cdev),devno, 1); 278 if(retval) 279 { 280 return retval; 281 } 282 283 /* 284 * 285 */ 286 init_MUTEX(&(dev->sem)); 287 288 /* 289 * val 0 290 */ 291 dev->val = 0; 292 293 return 0; 294} 295 296/* 297 * 。 298 */ 299static int __init example_init(void) 300{ 301 int retval = -1; 302 dev_t dev = 0; 303 struct device* device = NULL; 304 305 printk(KERN_ALERT"Initializing example device.
"); 306 307 /* 308 * , example_major 0, 309 * register_chrdev_region 。 310 * , example_major 0, 311 * alloc_chrdev_region 。 312 */ 313 if (example_major) { 314 dev = MKDEV(example_major, example_minor); 315 retval = register_chrdev_region(dev, 1, EXAMPLE_DEVICE_NODE_NAME); 316 } else { 317 retval = alloc_chrdev_region(&dev, example_minor, 1, EXAMPLE_DEVICE_NODE_NAME); 318 } 319 if (retval < 0) { 320 printk(KERN_WARNING "can't get example_major %d
", example_major); 321 goto fail; 322 } 323 324 /* 325 * 326 */ 327 example_major = MAJOR(dev); 328 example_minor = MINOR(dev); 329 330 /* 331 * example_dev 。 332 */ 333 example_dev = kmalloc(sizeof(struct example_dev), GFP_KERNEL); 334 if(!example_dev) 335 { 336 retval = -ENOMEM; 337 printk(KERN_ALERT"Failed to alloc example_dev.
"); 338 goto unregister; 339 } 340 341 /* 342 * __example_setup_dev example_dev 。 343 */ 344 retval = __example_setup_dev(example_dev); 345 if(retval) 346 { 347 printk(KERN_ALERT"Failed to setup dev: %d.
", retval); 348 goto cleanup; 349 } 350 351 /* 352 * example,class_create , /sys/class 353 * example 。 354 */ 355 example_class = class_create(THIS_MODULE, EXAMPLE_DEVICE_CLASS_NAME); 356 if(IS_ERR(example_class)) 357 { 358 retval = PTR_ERR(example_class); 359 printk(KERN_ALERT"Failed to create example class.
"); 360 goto destroy_cdev; 361 } 362 363 /* 364 * ,device_create , /dev/example 365 * /sys/class/example/example 。 366 * device struct device, 。 367 */ 368 device = device_create(example_class, NULL, dev, "%s", EXAMPLE_DEVICE_FILE_NAME); 369 if(IS_ERR(device)) 370 { 371 retval = PTR_ERR(device); 372 printk(KERN_ALERT"Failed to create example device."); 373 goto destroy_class; 374 } 375 376 /* 377 * , dev_attr_val 。 378 */ 379 retval = device_create_file(device, &dev_attr_val); 380 if(retval < 0) 381 { 382 printk(KERN_ALERT"Failed to create attribute val."); 383 goto destroy_device; 384 } 385 386 /* 387 * example_dev 。 388 */ 389 dev_set_drvdata(device, example_dev); 390 391 /* 392 * proc 。 393 */ 394 example_create_proc(); 395 396 printk(KERN_ALERT"Succedded to initialize example device.
"); 397 return 0; 398 399destroy_device: 400 device_destroy(example_class, dev); 401 402destroy_class: 403 class_destroy(example_class); 404 405destroy_cdev: 406 cdev_del(&(example_dev->cdev)); 407 408cleanup: 409 kfree(example_dev); 410 411unregister: 412 unregister_chrdev_region(MKDEV(example_major, example_minor), 1); 413 414fail: 415 return retval; 416} 417 418/* 419 * 。 420 */ 421static void __exit example_exit(void) 422{ 423 dev_t dev = MKDEV(example_major, example_minor); 424 425 printk(KERN_ALERT"Destroy example device.
"); 426 427 example_remove_proc(); 428 429 if(example_class) 430 { 431 device_destroy(example_class, MKDEV(example_major, example_minor)); 432 class_destroy(example_class); 433 } 434 435 if(example_dev) 436 { 437 cdev_del(&(example_dev->cdev)); 438 kfree(example_dev); 439 } 440 441 unregister_chrdev_region(dev, 1); 442} 443 444MODULE_LICENSE("GPL"); 445 446module_init(example_init); 447module_exit(example_exit);  

코드 에 있 는 주석 이 상세 합 니 다. 여기 서 간단하게 말씀 드 리 겠 습 니 다.
20 - 114 줄, example 정의open、example_release、example_read、example_write 이 4 개의 함수, 그리고 이 4 개의 함 수 를 file 에 할당 합 니 다.operations 구조 체 변수 examplefops, 응용 프로그램 이 / dev / example 장치 노드 를 통 해 장 치 를 방문 할 때 이 몇 가지 함수 로 호출 됩 니 다.
117 - 175 줄 은 / sys / class / example / example / val 을 통 해 장 치 를 방문 할 때 호출 되 는 함 수 를 정의 합 니 다.
177 - 248 줄 은 / proc / example 를 통 해 장 치 를 방문 할 때 호출 해 야 할 함 수 를 정의 합 니 다.
 
원본 코드 가 있 습 니 다. 이 원본 코드 를 컴 파일 하 는 Makefile 을 만들어 야 합 니 다.
Makefile 내용 은 다음 과 같 습 니 다.
obj-y += example.o

왜 Makefile 은 이 줄 만 있 을 수 있 습 니까? LDD 3 29 페이지 의 소 개 를 참고 하 실 수 있 습 니 다. 또한 제 블 로그 글 인 LDD 3 소스 코드 분석의 hello. c 와 Makefile 템 플 릿 도 참고 하 실 수 있 습 니 다.
커 널 을 컴 파일 할 때 example 를 컴 파일 할 수 있 도록 커 널 에 새로운 드라이버 example 를 추가 했다 는 것 을 알려 야 합 니 다.커 널 을 알 리 는 방법 은 커 널 drivers 디 렉 터 리 의 Makefile 을 수정 하 는 것 입 니 다. 이 파일 의 마지막 에 한 마디 를 추가 하 는 것 입 니 다.
obj-y               += example/

왜 이 한 마디 를 늘 리 면 커 널 에 알 릴 수 있 습 니까?이것 은 Linux 커 널 컴 파일 체제 가 결정 한 것 입 니 다. 분석 을 전개 하면 많은 내용 을 포함 할 것 입 니 다. 여기 서 자세히 설명 하지 않 겠 습 니 다.다 들 알 고 이렇게 고치 면 돼.
이상 의 작업 이 끝 난 후에 우 리 는 리 눅 스 커 널 을 다시 컴 파일 할 수 있 습 니 다. 커 널 루트 디 렉 터 리 로 돌아 가 다음 과 같은 명령 을 수행 할 수 있 습 니 다.
make
컴 파일 에 성공 한 후 얻 은 커 널 미 러 에는 우리 가 가입 한 example 드라이브 가 포함 되 어 있 습 니 다.
새로 추 가 된 example 드라이버 가 정상적으로 작 동 하 는 지 테스트 해 보 겠 습 니 다.
먼저 새로 컴 파일 된 Linux 커 널 로 Android 시 뮬 레이 터 를 시작 합 니 다.
# source build/envsetup.sh
# lunch
# emulator -kernel kernel/goldfish/arch/arm/boot/zImage
# adb shell
시스템 에 들 어가 면 example 드라이버 가 만 든 장치 노드: / dev / example, / proc / example 및 / sys / devices / virtual / example / example 디 렉 터 리 를 볼 수 있 습 니 다.
다음 명령 을 실행 합 니 다:
# cat /proc/example
0
# echo 5 > /proc/example
# cat /proc/example
5
볼 수 있 습 니 다. 우 리 는 / proc / example 노드 를 통 해 장치 레지스터 에 접근 할 수 있 습 니 다.
# cat /sys/class/example/example/val
5
# echo 6 > /sys/class/example/example/val
# cat /sys/class/example/example/val
6
볼 수 있 습 니 다. / sys / class / example / example / val 노드 를 통 해 장치 레지스터 에 접근 할 수 있 습 니 다.
또한 / dev / example 노드 를 통 해 장치 레지스터 에 접근 할 수 있 습 니 다. 다음 블 로그 에 서 는 C 프로그램 이 / dev / example 노드 를 통 해 장치 레지스터 에 접근 하 는 동시에 안 드 로 이 드 시스템 에서 C 프로그램 을 개발 하 는 절 차 를 보 여 줍 니 다.

좋은 웹페이지 즐겨찾기