当前位置:   article > 正文

3. 编写linux内核驱动程序(Android 10)_android 内核驱动linux下编译

android 内核驱动linux下编译

本文是在上文2. 编译安卓内核(pixel 2,Android 10)的基础上进行的,虚拟机环境就是上文结束时的环境。

1)首先安装vscode,方便编辑代码。

linux驱动程序简介

2)

在Linux系统中,一切皆文件。
所以在Linux中,设备也被作为一种文件来操作。而实现这些操作的,就叫做设备驱动。
在Linux中,设备被分为三类:
    - 字符设备(如,鼠标,键盘==)
    - 块设备(如硬盘)
    - 网络设备(这里指网络接口,如常见的eth0,wlan0,lo)

我们都知道,Linux一切皆文件,且,Linux具有两个空间——用户与内核.那么具体到用户态的表现就是,我们Open某个设备后,我们就会得到一个在系统中唯一的文件描述符号fd。我们所有关于设备的操作,都是以fd为依据进行操作。
本文使用一个虚拟的设备,即一个字符串指针(即struct hello_android_dev中的val,可读可写)作为示例,在安卓内核中增加一个名为hello驱动程序来操作这个虚拟设备(open、release、read、write)。

增加hello驱动

3)

在drivers目录下新建hello文件夹 

在hello文件夹里新建四个文件,文件具体内容如下。

 Kconfig

  1. config HELLO
  2. tristate "Hello Android Driver"
  3. default n
  4. help
  5. This is the hello android driver.

Makefile

obj-y +=hello.o

hello.h

  1. #ifndef _HELLO_ANDROID_H_
  2. #define _HELLO_ANDROID_H_
  3. #include <linux/cdev.h>
  4. #include <linux/semaphore.h>
  5. #define HELLO_DEVICE_NODE_NAME "hello"
  6. #define HELLO_DEVICE_FILE_NAME "hello"
  7. #define HELLO_DEVICE_CLASS_NAME "hello"
  8. #define VAL_LENGTH 100
  9. struct hello_android_dev {
  10. char *val;
  11. struct semaphore sem;
  12. struct cdev dev;
  13. };
  14. #endif

 hello.c

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <linux/fs.h>
  5. #include <linux/proc_fs.h>
  6. #include <linux/device.h>
  7. #include <linux/sched.h>
  8. #include <linux/errno.h>
  9. #include <linux/fcntl.h>
  10. #include <linux/poll.h>
  11. #include <linux/seq_file.h>
  12. #include <linux/mutex.h>
  13. #include <linux/workqueue.h>
  14. #include <asm/uaccess.h>
  15. #include <linux/slab.h>
  16. #include "hello.h"
  17. static int hello_major = 0;
  18. static int hello_minor = 0;
  19. static struct class* hello_class = NULL;
  20. static struct hello_android_dev* hello_dev = NULL;
  21. // 这四个函数供hal层调用
  22. // 分别对应hal层打开,关闭,写入,读取操作
  23. static int hello_open(struct inode* inode, struct file* filp);
  24. static int hello_release(struct inode* inode, struct file* filp);
  25. static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
  26. static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
  27. static struct file_operations hello_fops = {
  28. .owner = THIS_MODULE,
  29. .open = hello_open,
  30. .release = hello_release,
  31. .read = hello_read,
  32. .write = hello_write,
  33. };
  34. // 这两个函数用于处理 DEVICE_ATTR 这个宏定义的处理
  35. // 这个宏主要是在 /sys/devices/virtual/ 目录下生成对应的文件,使得开发人员可以通过 cat和echo 来进行操作
  36. // 可以参考 https://www.cnblogs.com/lifexy/p/9799778.html 了解详情
  37. static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf);
  38. static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
  39. static DEVICE_ATTR(val, S_IRUGO|S_IWUSR, hello_val_show, hello_val_store);
  40. static int hello_open(struct inode* inode, struct file* filp) {
  41. struct hello_android_dev* dev;
  42. printk(KERN_ALERT"hello_open.\n");
  43. dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
  44. filp->private_data = dev;
  45. return 0;
  46. }
  47. static int hello_release(struct inode* inode, struct file* filp) {
  48. return 0;
  49. }
  50. static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {
  51. ssize_t err = 0;
  52. struct hello_android_dev* dev = filp->private_data;
  53. printk(KERN_ALERT"hello_read.\n");
  54. if(down_interruptible(&(dev->sem))) {
  55. return -ERESTARTSYS;
  56. }
  57. if(count >= VAL_LENGTH) {
  58. goto out;
  59. }
  60. printk(KERN_ALERT"hello_read %s.\n", dev->val);
  61. printk(KERN_ALERT"hello_read %d.\n", (int)strlen(dev->val)+1);
  62. if(copy_to_user(buf, dev->val, count)) {
  63. err = -EFAULT;
  64. goto out;
  65. }
  66. err = count;
  67. out:
  68. up(&(dev->sem));
  69. return err;
  70. }
  71. static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {
  72. struct hello_android_dev* dev = filp->private_data;
  73. ssize_t err = 0;
  74. if(down_interruptible(&(dev->sem))) {
  75. return -ERESTARTSYS;
  76. }
  77. if(count >= VAL_LENGTH) {
  78. goto out;
  79. }
  80. if(copy_from_user(dev->val, buf, count)) {
  81. err = -EFAULT;
  82. goto out;
  83. }
  84. err = count;
  85. out:
  86. up(&(dev->sem));
  87. return err;
  88. }
  89. static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {
  90. printk(KERN_ALERT"__hello_set_val.\n");
  91. if(down_interruptible(&(dev->sem))) {
  92. return -ERESTARTSYS;
  93. }
  94. printk(KERN_ALERT"__hello_set_val.buf: %s count:%d\n",buf,(int)count);
  95. printk(KERN_ALERT"__hello_set_val.dev->val: %s count:%d\n",dev->val,(int)count);
  96. strncpy(dev->val,buf, count);
  97. printk(KERN_ALERT"__hello_set_val.dev->val: %s count:%d\n",dev->val,(int)count);
  98. up(&(dev->sem));
  99. return count;
  100. }
  101. static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
  102. struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
  103. printk(KERN_ALERT"hello_val_show.\n");
  104. printk(KERN_ALERT"%s\n",hdev->val);
  105. return sprintf(buf,"%s\n",hdev->val);
  106. }
  107. static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
  108. struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
  109. printk(KERN_ALERT"hello_val_store.buf: %s count:%d\n",buf,(int)count);
  110. return __hello_set_val(hdev, buf, count+1);
  111. }
  112. static int __hello_setup_dev(struct hello_android_dev* dev) {
  113. int err;
  114. dev_t devno = MKDEV(hello_major, hello_minor);
  115. printk(KERN_ALERT"__hello_setup_dev.\n");
  116. memset(dev, 0, sizeof(struct hello_android_dev));
  117. cdev_init(&(dev->dev), &hello_fops);
  118. dev->dev.owner = THIS_MODULE;
  119. dev->dev.ops = &hello_fops;
  120. err = cdev_add(&(dev->dev),devno, 1);
  121. if(err) {
  122. return err;
  123. }
  124. sema_init(&(dev->sem), 1);
  125. // 给val变量开辟空间,这里只有100个字节,如果设置的字符串长度超过,后面的会被丢弃
  126. dev->val = kmalloc(VAL_LENGTH,GFP_KERNEL);
  127. // Dev的默认值是 hello_device
  128. strncpy(dev->val,"hello_device",strlen("hello_device")+1);
  129. return 0;
  130. }
  131. // 驱动初始化函数
  132. static int __init hello_init(void){
  133. int err = -1;
  134. dev_t dev = 0;
  135. struct device* temp = NULL;
  136. printk(KERN_ALERT"hello_init.\n");
  137. err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);
  138. if(err < 0) {
  139. printk(KERN_ALERT"Failed to alloc char dev region.\n");
  140. goto fail;
  141. }
  142. hello_major = MAJOR(dev);
  143. hello_minor = MINOR(dev);
  144. hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
  145. if(!hello_dev) {
  146. err = -ENOMEM;
  147. printk(KERN_ALERT"Failed to alloc hello_dev.\n");
  148. goto unregister;
  149. }
  150. err = __hello_setup_dev(hello_dev);
  151. if(err) {
  152. printk(KERN_ALERT"Failed to setup dev: %d.\n", err);
  153. goto cleanup;
  154. }
  155. hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
  156. if(IS_ERR(hello_class)) {
  157. err = PTR_ERR(hello_class);
  158. printk(KERN_ALERT"Failed to create hello class.\n");
  159. goto destroy_cdev;
  160. }
  161. temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
  162. if(IS_ERR(temp)) {
  163. err = PTR_ERR(temp);
  164. printk(KERN_ALERT"Failed to create hello device.");
  165. goto destroy_class;
  166. }
  167. err = device_create_file(temp, &dev_attr_val);
  168. if(err < 0) {
  169. printk(KERN_ALERT"Failed to create attribute val.");
  170. goto destroy_device;
  171. }
  172. dev_set_drvdata(temp, hello_dev);
  173. printk(KERN_ALERT"Succedded to initialize hello device.\n");
  174. return 0;
  175. destroy_device:
  176. device_destroy(hello_class, dev);
  177. destroy_class:
  178. class_destroy(hello_class);
  179. destroy_cdev:
  180. cdev_del(&(hello_dev->dev));
  181. cleanup:
  182. kfree(hello_dev);
  183. unregister:
  184. unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);
  185. fail:
  186. return err;
  187. }
  188. // 驱动卸载函数
  189. static void __exit hello_exit(void) {
  190. dev_t devno = MKDEV(hello_major, hello_minor);
  191. printk(KERN_ALERT"hello_exit\n");
  192. if(hello_class) {
  193. device_destroy(hello_class, MKDEV(hello_major, hello_minor));
  194. class_destroy(hello_class);
  195. }
  196. if(hello_dev) {
  197. cdev_del(&(hello_dev->dev));
  198. kfree(hello_dev);
  199. }
  200. if(hello_dev->val != NULL){
  201. kfree(hello_dev->val);
  202. }
  203. unregister_chrdev_region(devno, 1);
  204. }
  205. MODULE_LICENSE("GPL");
  206. MODULE_DESCRIPTION("Hello Driver");
  207. module_init(hello_init);
  208. module_exit(hello_exit);

修改drivers/Kconfig,加一行

source "drivers/hello/Kconfig"

修改drivers/Makefile,加一行

obj-y                   += hello/

 

编译

4)编译

  1. cd ~/Documents/msm
  2. export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin
  3. export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
  4. export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/misc/linux-x86/dtc
  5. export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/misc/linux-x86/libufdt
  6. export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/misc/linux-x86/lz4
  7. export ARCH=arm64
  8. export CROSS_COMPILE=/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
  9. export CROSS_COMPILE_ARM32=/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
  10. export CC=/home/test/Documents/aosp10/prebuilts/clang/host/linux-x86/clang-3289846/bin/clang
  11. make wahoo_defconfig
  12. make clean
  13. make -j16

 编译成功

打包并刷入手机 

5)打包,新开一个terminal

  1. cd ~/Documents/aosp10
  2. export TARGET_PREBUILT_KERNEL=/home/test/Documents/msm/arch/arm64/boot/Image.lz4-dtb
  3. source build/envsetup.sh
  4. lunch
  5. aosp_walleye-userdebug
  6. time make bootimage

6)刷入手机

新开一个terminal

  1. cd ~/Documents/aosp10
  2. sudo su
  3. source build/envsetup.sh
  4. lunch
  5. aosp_walleye-userdebug
  6. adb reboot bootloader
  7. cd out/target/product/walleye/
  8. fastboot flash boot boot.img
  9. fastboot reboot

测试

7)

  1. adb shell
  2. su
  3. ls -l /dev/hello
  4. ls -l /sys/devices/virtual/hello/hello/
  5. cd /sys/devices/virtual/hello/hello/
  6. cat val
  7. echo "my_driver\0" > val
  8. cat val

本文涉及到的知识主要和Android架构中的linux内核层相关

参考

AndroidQ 从app到驱动 第一章 编写Linux内核驱动程序_长乐居士-CSDN博客

在Ubuntu上为Android系统编写Linux内核驱动程序_老罗的Android之旅-CSDN博客

Linux Char-Driver (字符驱动 摘要)(一)_Sky的专栏-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/327173
推荐阅读
相关标签
  

闽ICP备14008679号