参考老罗的文章,由于老罗的文章比较老,还有版本差异,整理一些坑记录
内核代码获取编译 https://source.android.google.cn/setup/build/building-kernels?hl=zh-cn
## 编译
build/build.sh
cp kernel/out/android-msm-floral-4.14/dist/* pixel/device/google/coral-kernel
重启后发现touch失效,因为内核编译出来的touch等驱动的ko文件都在vendor.img,而我们只刷入了boot.img,需要将ko文件push到特定目录下
adb disable-verify adb root adb remount adb push kernel/out/android-msm-floral-4.14/dist/*.ko /vendor/lib/modules/kernel/private/msm-google/drivers
cd freg #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 <asm/uaccess.h> #include "freg.h" /*主设备和从设备号变量*/ static int freg_major = 0; static int freg_minor = 0; /*设备类别和设备变量*/ static struct class* freg_class = NULL; static struct freg_android_dev* freg_dev = NULL; /*传统的设备文件操作方法*/ static int freg_open(struct inode* inode, struct file* filp); static int freg_release(struct inode* inode, struct file* filp); static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos); static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos); /*设备文件操作方法表*/ static struct file_operations freg_fops = { .owner = THIS_MODULE, .open = freg_open, .release = freg_release, .read = freg_read, .write = freg_write, }; /*访问设置属性方法*/ static ssize_t freg_val_show(struct device* dev, struct device_attribute* attr, char* buf); static ssize_t freg_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count); /*定义设备属性*/ static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, freg_val_show, freg_val_store); /*打开设备方法*/ static int freg_open(struct inode* inode, struct file* filp) { struct freg_android_dev* dev; /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/ dev = container_of(inode->i_cdev, struct freg_android_dev, dev); filp->private_data = dev; return 0; } /*设备文件释放时调用,空实现*/ static int freg_release(struct inode* inode, struct file* filp) { return 0; } /*读取设备的寄存器val的值*/ static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) { ssize_t err = 0; struct freg_android_dev* dev = filp->private_data; /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count < sizeof(dev->val)) { goto out; } /*将寄存器val的值拷贝到用户提供的缓冲区*/ if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } /*写设备的寄存器值val*/ static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) { struct freg_android_dev* dev = filp->private_data; ssize_t err = 0; /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count != sizeof(dev->val)) { goto out; } /*将用户提供的缓冲区的值写到设备寄存器去*/ if(copy_from_user(&(dev->val), buf, count)) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } /*读取寄存器val的值到缓冲区buf中,内部使用*/ static ssize_t __freg_get_val(struct freg_android_dev* dev, char* buf) { int val = 0; /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } val = dev->val; up(&(dev->sem)); return snprintf(buf, PAGE_SIZE, "%d\n", val); } /*把缓冲区buf的值写到设备寄存器val中去,内部使用*/ static ssize_t __freg_set_val(struct freg_android_dev* dev, const char* buf, size_t count) { int val = 0; /*将字符串转换成数字*/ val = simple_strtol(buf, NULL, 10); /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } dev->val = val; up(&(dev->sem)); return count; } /*读取设备属性val*/ static ssize_t freg_val_show(struct device* dev, struct device_attribute* attr, char* buf) { struct freg_android_dev* hdev = (struct freg_android_dev*)dev_get_drvdata(dev); return __freg_get_val(hdev, buf); } /*写设备属性val*/ static ssize_t freg_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { struct freg_android_dev* hdev = (struct freg_android_dev*)dev_get_drvdata(dev); return __freg_set_val(hdev, buf, count); } /*读取设备寄存器val的值,保存在page缓冲区中*/ static ssize_t freg_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) { if(off > 0) { *eof = 1; return 0; } return __freg_get_val(freg_dev, page); } /*把缓冲区的值buff保存到设备寄存器val中去*/ static ssize_t freg_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) { int err = 0; char* page = NULL; if(len > PAGE_SIZE) { printk(KERN_ALERT"The buff is too large: %lu.\n", len); return -EFAULT; } page = (char*)__get_free_page(GFP_KERNEL); if(!page) { printk(KERN_ALERT"Failed to alloc page.\n"); return -ENOMEM; } /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/ if(copy_from_user(page, buff, len)) { printk(KERN_ALERT"Failed to copy buff from user.\n"); err = -EFAULT; goto out; } err = __freg_set_val(freg_dev, page, len); out: free_page((unsigned long)page); return err; } /*创建/proc/freg文件*/ static void freg_create_proc(void) { struct proc_dir_entry* entry; entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL); if(entry) { entry->owner = THIS_MODULE; entry->read_proc = freg_proc_read; entry->write_proc = freg_proc_write; } } /*删除/proc/freg文件*/ static void freg_remove_proc(void) { remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL); } /*初始化设备*/ static int __freg_setup_dev(struct freg_android_dev* dev) { int err; dev_t devno = MKDEV(freg_major, freg_minor); memset(dev, 0, sizeof(struct freg_android_dev)); cdev_init(&(dev->dev), &freg_fops); dev->dev.owner = THIS_MODULE; dev->dev.ops = &freg_fops; /*注册字符设备*/ err = cdev_add(&(dev->dev),devno, 1); if(err) { return err; } /*初始化信号量和寄存器val的值*/ init_MUTEX(&(dev->sem)); dev->val = 0; return 0; } /*模块加载方法*/ static int __init freg_init(void){ int err = -1; dev_t dev = 0; struct device* temp = NULL; printk(KERN_ALERT"Initializing freg device.\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; } freg_major = MAJOR(dev); freg_minor = MINOR(dev); /*分配helo设备结构体变量*/ freg_dev = kmalloc(sizeof(struct freg_android_dev), GFP_KERNEL); if(!freg_dev) { err = -ENOMEM; printk(KERN_ALERT"Failed to alloc freg_dev.\n"); goto unregister; } /*初始化设备*/ err = __freg_setup_dev(freg_dev); if(err) { printk(KERN_ALERT"Failed to setup dev: %d.\n", err); goto cleanup; } /*在/sys/class/目录下创建设备类别目录freg*/ freg_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME); if(IS_ERR(freg_class)) { err = PTR_ERR(freg_class); printk(KERN_ALERT"Failed to create freg class.\n"); goto destroy_cdev; } /*在/dev/目录和/sys/class/freg目录下分别创建设备文件freg*/ temp = device_create(freg_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME); if(IS_ERR(temp)) { err = PTR_ERR(temp); printk(KERN_ALERT"Failed to create freg device."); goto destroy_class; } /*在/sys/class/freg/freg目录下创建属性文件val*/ 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, freg_dev); /*创建/proc/freg文件*/ freg_create_proc(); printk(KERN_ALERT"Succedded to initialize freg device.\n"); return 0; destroy_device: device_destroy(freg_class, dev); destroy_class: class_destroy(freg_class); destroy_cdev: cdev_del(&(freg_dev->dev)); cleanup: kfree(freg_dev); unregister: unregister_chrdev_region(MKDEV(freg_major, freg_minor), 1); fail: return err; } /*模块卸载方法*/ static void __exit freg_exit(void) { dev_t devno = MKDEV(freg_major, freg_minor); printk(KERN_ALERT"Destroy freg device.\n"); /*删除/proc/freg文件*/ freg_remove_proc(); /*销毁设备类别和设备*/ if(freg_class) { device_destroy(freg_class, MKDEV(freg_major, freg_minor)); class_destroy(freg_class); } /*删除字符设备和释放设备内存*/ if(freg_dev) { cdev_del(&(freg_dev->dev)); kfree(freg_dev); } /*释放设备号*/ unregister_chrdev_region(devno, 1); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("First Android Driver"); module_init(freg_init); module_exit(freg_exit); #ifndef _FAKE_REG_H_ #define _FAKE_REG_H_ #include <linux/cdev.h> #include <linux/semaphore.h> #define FREG_DEVICE_NODE_NAME "freg" #define FREG_DEVICE_FILE_NAME "freg" #define FREG_DEVICE_PROC_NAME "freg" #define FREG_DEVICE_CLASS_NAME "freg" struct fake_reg_dev { int val; struct semaphore sem; struct cdev dev; }; #endif替换了一些老旧的头文件,
driver目录下配置Makefile obj-y += freg/ private/msm-google/drivers/freg下新建Makefile obj-y +=freg.o
Android/external目录新建freg目录。新建freg.c和Android.bp两个文件
freg.c
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #define FREG_DEVICE_NAME "/dev/freg" int main(int argc, char** argv){ int fd = -1; int val = 0; if (argc == 0 || argv == NULL) {} fd = open(FREG_DEVICE_NAME, O_RDWR); if(fd == -1){ printf("Failed to open device %s.\n", FREG_DEVICE_NAME); return -1; } printf("Read original value:\n"); read(fd, &val, sizeof(val)); printf("%d.\n\n", val); val = 5; printf("Write value %d to %s.\n\n", val, FREG_DEVICE_NAME); write(fd, &val, sizeof(val)); printf("Read the value again:\n"); read(fd, &val, sizeof(val)); printf("%d.\n\n", val); close(fd); return 0; }Android.bp
cc_binary { name: "freg", srcs: [ "freg.c" ], }mm单编后,out/target/product/coral/system/bin生成可执行文件freg,push到system/bin下面会有结果打印。
