赞
踩
本文是在上文2. 编译安卓内核(pixel 2,Android 10)的基础上进行的,虚拟机环境就是上文结束时的环境。
1)首先安装vscode,方便编辑代码。
2)
在Linux系统中,一切皆文件。
所以在Linux中,设备也被作为一种文件来操作。而实现这些操作的,就叫做设备驱动。
在Linux中,设备被分为三类:
- 字符设备(如,鼠标,键盘==)
- 块设备(如硬盘)
- 网络设备(这里指网络接口,如常见的eth0,wlan0,lo)
我们都知道,Linux一切皆文件,且,Linux具有两个空间——用户与内核.那么具体到用户态的表现就是,我们Open某个设备后,我们就会得到一个在系统中唯一的文件描述符号fd。我们所有关于设备的操作,都是以fd为依据进行操作。
本文使用一个虚拟的设备,即一个字符串指针(即struct hello_android_dev中的val,可读可写)作为示例,在安卓内核中增加一个名为hello驱动程序来操作这个虚拟设备(open、release、read、write)。
3)
在drivers目录下新建hello文件夹
在hello文件夹里新建四个文件,文件具体内容如下。
Kconfig
- config HELLO
- tristate "Hello Android Driver"
- default n
- help
- This is the hello android driver.
obj-y +=hello.o
hello.h
- #ifndef _HELLO_ANDROID_H_
- #define _HELLO_ANDROID_H_
-
- #include <linux/cdev.h>
- #include <linux/semaphore.h>
-
- #define HELLO_DEVICE_NODE_NAME "hello"
- #define HELLO_DEVICE_FILE_NAME "hello"
- #define HELLO_DEVICE_CLASS_NAME "hello"
- #define VAL_LENGTH 100
-
- struct hello_android_dev {
- char *val;
- struct semaphore sem;
- struct cdev dev;
- };
-
- #endif
hello.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/proc_fs.h>
- #include <linux/device.h>
-
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/fcntl.h>
-
- #include <linux/poll.h>
- #include <linux/seq_file.h>
- #include <linux/mutex.h>
- #include <linux/workqueue.h>
-
- #include <asm/uaccess.h>
- #include <linux/slab.h>
-
-
- #include "hello.h"
-
- static int hello_major = 0;
- static int hello_minor = 0;
-
- static struct class* hello_class = NULL;
- static struct hello_android_dev* hello_dev = NULL;
-
-
- // 这四个函数供hal层调用
- // 分别对应hal层打开,关闭,写入,读取操作
-
- static int hello_open(struct inode* inode, struct file* filp);
- static int hello_release(struct inode* inode, struct file* filp);
- static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
- static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
-
- static struct file_operations hello_fops = {
- .owner = THIS_MODULE,
- .open = hello_open,
- .release = hello_release,
- .read = hello_read,
- .write = hello_write,
- };
-
-
- // 这两个函数用于处理 DEVICE_ATTR 这个宏定义的处理
- // 这个宏主要是在 /sys/devices/virtual/ 目录下生成对应的文件,使得开发人员可以通过 cat和echo 来进行操作
- // 可以参考 https://www.cnblogs.com/lifexy/p/9799778.html 了解详情
- static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf);
- static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
-
- static DEVICE_ATTR(val, S_IRUGO|S_IWUSR, hello_val_show, hello_val_store);
-
- static int hello_open(struct inode* inode, struct file* filp) {
- struct hello_android_dev* dev;
- printk(KERN_ALERT"hello_open.\n");
- dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
- filp->private_data = dev;
- return 0;
- }
-
-
- static int hello_release(struct inode* inode, struct file* filp) {
- return 0;
- }
-
-
- static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {
-
- ssize_t err = 0;
- struct hello_android_dev* dev = filp->private_data;
- printk(KERN_ALERT"hello_read.\n");
-
- if(down_interruptible(&(dev->sem))) {
- return -ERESTARTSYS;
- }
-
- if(count >= VAL_LENGTH) {
- goto out;
- }
-
- printk(KERN_ALERT"hello_read %s.\n", dev->val);
- printk(KERN_ALERT"hello_read %d.\n", (int)strlen(dev->val)+1);
-
- if(copy_to_user(buf, dev->val, count)) {
- err = -EFAULT;
- goto out;
- }
-
- err = count;
-
- out:
- up(&(dev->sem));
- return err;
- }
-
- static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {
-
- struct hello_android_dev* dev = filp->private_data;
- ssize_t err = 0;
-
- if(down_interruptible(&(dev->sem))) {
- return -ERESTARTSYS;
- }
-
- if(count >= VAL_LENGTH) {
- goto out;
- }
-
- if(copy_from_user(dev->val, buf, count)) {
- err = -EFAULT;
- goto out;
- }
- err = count;
-
- out:
- up(&(dev->sem));
- return err;
- }
-
-
- static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {
- printk(KERN_ALERT"__hello_set_val.\n");
- if(down_interruptible(&(dev->sem))) {
- return -ERESTARTSYS;
- }
- printk(KERN_ALERT"__hello_set_val.buf: %s count:%d\n",buf,(int)count);
- printk(KERN_ALERT"__hello_set_val.dev->val: %s count:%d\n",dev->val,(int)count);
- strncpy(dev->val,buf, count);
- printk(KERN_ALERT"__hello_set_val.dev->val: %s count:%d\n",dev->val,(int)count);
- up(&(dev->sem));
-
- return count;
- }
-
- static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
- struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
- printk(KERN_ALERT"hello_val_show.\n");
- printk(KERN_ALERT"%s\n",hdev->val);
- return sprintf(buf,"%s\n",hdev->val);
- }
-
- static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
- struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
- printk(KERN_ALERT"hello_val_store.buf: %s count:%d\n",buf,(int)count);
- return __hello_set_val(hdev, buf, count+1);
- }
-
- static int __hello_setup_dev(struct hello_android_dev* dev) {
-
- int err;
- dev_t devno = MKDEV(hello_major, hello_minor);
- printk(KERN_ALERT"__hello_setup_dev.\n");
- memset(dev, 0, sizeof(struct hello_android_dev));
-
- cdev_init(&(dev->dev), &hello_fops);
- dev->dev.owner = THIS_MODULE;
- dev->dev.ops = &hello_fops;
-
- err = cdev_add(&(dev->dev),devno, 1);
- if(err) {
- return err;
- }
-
- sema_init(&(dev->sem), 1);
- // 给val变量开辟空间,这里只有100个字节,如果设置的字符串长度超过,后面的会被丢弃
- dev->val = kmalloc(VAL_LENGTH,GFP_KERNEL);
- // Dev的默认值是 hello_device
- strncpy(dev->val,"hello_device",strlen("hello_device")+1);
- return 0;
- }
-
- // 驱动初始化函数
- static int __init hello_init(void){
- int err = -1;
- dev_t dev = 0;
- struct device* temp = NULL;
-
- printk(KERN_ALERT"hello_init.\n");
-
- err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);
- if(err < 0) {
- printk(KERN_ALERT"Failed to alloc char dev region.\n");
- goto fail;
- }
-
- hello_major = MAJOR(dev);
- hello_minor = MINOR(dev);
-
- hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
- if(!hello_dev) {
- err = -ENOMEM;
- printk(KERN_ALERT"Failed to alloc hello_dev.\n");
- goto unregister;
- }
-
- err = __hello_setup_dev(hello_dev);
- if(err) {
- printk(KERN_ALERT"Failed to setup dev: %d.\n", err);
- goto cleanup;
- }
-
- hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
- if(IS_ERR(hello_class)) {
- err = PTR_ERR(hello_class);
- printk(KERN_ALERT"Failed to create hello class.\n");
- goto destroy_cdev;
- }
-
- temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
- if(IS_ERR(temp)) {
- err = PTR_ERR(temp);
- printk(KERN_ALERT"Failed to create hello device.");
- goto destroy_class;
- }
-
- err = device_create_file(temp, &dev_attr_val);
- if(err < 0) {
- printk(KERN_ALERT"Failed to create attribute val.");
- goto destroy_device;
- }
-
- dev_set_drvdata(temp, hello_dev);
-
- printk(KERN_ALERT"Succedded to initialize hello device.\n");
- return 0;
-
- destroy_device:
- device_destroy(hello_class, dev);
-
- destroy_class:
- class_destroy(hello_class);
-
- destroy_cdev:
- cdev_del(&(hello_dev->dev));
-
- cleanup:
- kfree(hello_dev);
-
- unregister:
- unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);
-
- fail:
- return err;
- }
-
- // 驱动卸载函数
- static void __exit hello_exit(void) {
- dev_t devno = MKDEV(hello_major, hello_minor);
-
- printk(KERN_ALERT"hello_exit\n");
-
- if(hello_class) {
- device_destroy(hello_class, MKDEV(hello_major, hello_minor));
- class_destroy(hello_class);
- }
-
- if(hello_dev) {
- cdev_del(&(hello_dev->dev));
- kfree(hello_dev);
- }
- if(hello_dev->val != NULL){
- kfree(hello_dev->val);
- }
- unregister_chrdev_region(devno, 1);
- }
-
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("Hello Driver");
-
- module_init(hello_init);
- module_exit(hello_exit);
修改drivers/Kconfig,加一行
source "drivers/hello/Kconfig"
修改drivers/Makefile,加一行
obj-y += hello/
4)编译
- cd ~/Documents/msm
- export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin
- export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
- export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/misc/linux-x86/dtc
- export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/misc/linux-x86/libufdt
- export PATH=$PATH:/home/test/Documents/aosp10/prebuilts/misc/linux-x86/lz4
- export ARCH=arm64
- export CROSS_COMPILE=/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
- export CROSS_COMPILE_ARM32=/home/test/Documents/aosp10/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
- export CC=/home/test/Documents/aosp10/prebuilts/clang/host/linux-x86/clang-3289846/bin/clang
- make wahoo_defconfig
- make clean
- make -j16
编译成功
5)打包,新开一个terminal
- cd ~/Documents/aosp10
- export TARGET_PREBUILT_KERNEL=/home/test/Documents/msm/arch/arm64/boot/Image.lz4-dtb
- source build/envsetup.sh
- lunch
- aosp_walleye-userdebug
- time make bootimage
6)刷入手机
新开一个terminal
- cd ~/Documents/aosp10
- sudo su
- source build/envsetup.sh
- lunch
- aosp_walleye-userdebug
- adb reboot bootloader
- cd out/target/product/walleye/
- fastboot flash boot boot.img
- fastboot reboot
7)
- adb shell
- su
- ls -l /dev/hello
- ls -l /sys/devices/virtual/hello/hello/
- cd /sys/devices/virtual/hello/hello/
- cat val
- echo "my_driver\0" > val
- cat val
本文涉及到的知识主要和Android架构中的linux内核层相关
AndroidQ 从app到驱动 第一章 编写Linux内核驱动程序_长乐居士-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。