打通驱动层到应用层

编程入门 行业动态 更新时间:2024-10-06 17:24:48

打通驱动层到<a href=https://www.elefans.com/category/jswz/34/1754998.html style=应用层"/>

打通驱动层到应用层

前言

本节为添加内核驱动程序。

一、添加

我们添加的驱动为虚拟字符设备,一般使用hello来命名该驱动,因为我使用的工程源码中已经存在了test驱动,注册为hello。因此我的驱动命名为helloxjq。
编译方式为静态编译,将驱动编入内核。
在kernel/msm-4.9/drivers/目录下创建helloxjq文件夹,在helloxjq文件夹下创建helloxjq.c、Makefile、Kconfig三个文件。
Kconfig代码如下:

config HELLOXJQ
tristate "helloxjq Android test Driver"
default y
help
It is a Android test driver.
obj-$(CONFIG_HELLOXJQ) += helloxjq.o

helloxjq.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 "helloxjq.h"  /*定义主设备和从设备号变量*/  
static int helloxjq_major = 0;  
static int helloxjq_minor = 0;  /*设备类别和设备变量*/  
static struct class* helloxjq_class = NULL;  
static struct helloxjq_dev* helloxjq_dev = NULL;  /*传统的设备文件操作方法*/  
static int helloxjq_open(struct inode* inode, struct file* filp);  
static int helloxjq_release(struct inode* inode, struct file* filp);  
static ssize_t helloxjq_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);  
static ssize_t helloxjq_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);  /*设备文件操作方法表*/  
static struct file_operations helloxjq_fops = {  .owner = THIS_MODULE,  .open = helloxjq_open,  .release = helloxjq_release,  .read = helloxjq_read,  .write = helloxjq_write,   
};  /*访问设置属性方法*/  
static ssize_t helloxjq_val_show(struct device* dev, struct device_attribute* attr,  char* buf);  
static ssize_t helloxjq_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);  /*定义设备属性*/  
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, helloxjq_val_show, helloxjq_val_store); /*打开设备方法*/  
static int helloxjq_open(struct inode* inode, struct file* filp) {  struct helloxjq_dev* dev;          /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/  dev = container_of(inode->i_cdev, struct helloxjq_dev, dev);  filp->private_data = dev;  return 0;  
}  /*设备文件释放时调用,空实现*/  
static int helloxjq_release(struct inode* inode, struct file* filp) {  return 0;  
}  /*读内存*/  
static ssize_t helloxjq_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {  ssize_t err = 0;  struct helloxjq_dev* dev = filp->private_data;          /*同步访问*/  if(down_interruptible(&(dev->sem))) {  return -ERESTARTSYS;  }  if(count < sizeof(dev->val)) {  goto out;  }          /*读字符串*/  if(copy_to_user(buf, dev->val, sizeof(dev->val))) {  err = -EFAULT;  goto out;  }  err = sizeof(dev->val);  out:  up(&(dev->sem));  return err;  
}  /*写字符串*/  
static ssize_t helloxjq_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {  struct helloxjq_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;  
}  /*写字符串到内存*/  
static ssize_t __helloxjq_set_val(struct helloxjq_dev* dev, const char* buf, size_t count) {       /*同步访问*/          if(down_interruptible(&(dev->sem))) {                  return -ERESTARTSYS;          }          printk(KERN_ALERT"__helloxjq_set_val.buf: %s  count:%d\n",buf,count);printk(KERN_ALERT"__helloxjq_set_val.dev->val: %s  count:%d\n",dev->val,count);strncpy(dev->val,buf, count);printk(KERN_ALERT"__helloxjq_set_val.dev->val: %s  count:%d\n",dev->val,count);up(&(dev->sem));  return count;  
}  /*读取设备属性val*/  
static ssize_t helloxjq_val_show(struct device* dev, struct device_attribute* attr, char* buf) {  struct helloxjq_dev* hdev = (struct helloxjq_dev*)dev_get_drvdata(dev);          printk(KERN_ALERT"helloxjq_val_show.\n");printk(KERN_ALERT"%s\n",hdev->val);return 0;
}  /*写设备属性val*/  
static ssize_t helloxjq_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {   struct helloxjq_dev* hdev = (struct helloxjq_dev*)dev_get_drvdata(dev);    printk(KERN_ALERT"helloxjq_val_store.buf: %s  count:%d\n",buf,count);return __helloxjq_set_val(hdev, buf, count);  
}  /*初始化设备*/  
static int  __helloxjq_setup_dev(struct helloxjq_dev* dev) {  int err;  dev_t devno = MKDEV(helloxjq_major, helloxjq_minor);  memset(dev, 0, sizeof(struct helloxjq_dev));  cdev_init(&(dev->dev), &helloxjq_fops);  dev->dev.owner = THIS_MODULE;  dev->dev.ops = &helloxjq_fops;          /*注册字符设备*/  err = cdev_add(&(dev->dev),devno, 1);  if(err) {  return err;  }          /*初始化信号量和寄存器val的值*/  sema_init(&(dev->sem),1);dev->val = kmalloc(10,GFP_KERNEL);  strncpy(dev->val,"helloxjq",sizeof("helloxjq"));return 0;  
}  /*模块加载方法*/  
static int __init helloxjq_init(void){   int err = -1;  dev_t dev = 0;  struct device* temp = NULL;  printk(KERN_ALERT"helloxjq_init.\n");          /*动态分配主设备和从设备号*/  err = alloc_chrdev_region(&dev, 0, HELLOXJQ_DEVICE_NUM, HELLOXJQ_DEVICE_NODE_NAME);  if(err < 0) {  printk(KERN_ALERT"Failed to alloc char dev region.\n");  goto fail;  }  helloxjq_major = MAJOR(dev);  helloxjq_minor = MINOR(dev);          /*分配helo设备结构体变量*/  helloxjq_dev = kmalloc(sizeof(struct helloxjq_dev), GFP_KERNEL);  if(!helloxjq_dev) {  err = -ENOMEM;  printk(KERN_ALERT"Failed to alloc helloxjq_dev.\n");  goto unregister;  }          /*初始化设备*/  err = __helloxjq_setup_dev(helloxjq_dev);  if(err) {  printk(KERN_ALERT"Failed to setup dev: %d.\n", err);  goto cleanup;  }          /*在/sys/class/目录下创建设备类别目录helloxjq*/  helloxjq_class = class_create(THIS_MODULE, HELLOXJQ_DEVICE_CLASS_NAME);  if(IS_ERR(helloxjq_class)) {  err = PTR_ERR(helloxjq_class);  printk(KERN_ALERT"Failed to create helloxjq class.\n");  goto destroy_cdev;  }          /*在/dev/目录和/sys/class/helloxjq目录下分别创建设备文件helloxjq*/  temp = device_create(helloxjq_class, NULL, dev, "%s", HELLOXJQ_DEVICE_FILE_NAME);  if(IS_ERR(temp)) {  err = PTR_ERR(temp);  printk(KERN_ALERT"Failed to create helloxjq device.");  goto destroy_class;  }          /*在/sys/class/helloxjq/helloxjq目录下创建属性文件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, helloxjq_dev);          printk(KERN_ALERT"Succedded to initialize helloxjq device.\n");  return 0;  destroy_device:  device_destroy(helloxjq_class, dev);  destroy_class:  class_destroy(helloxjq_class);  destroy_cdev:  cdev_del(&(helloxjq_dev->dev));  cleanup:  kfree(helloxjq_dev);  unregister:  unregister_chrdev_region(MKDEV(helloxjq_major, helloxjq_minor), 1);  fail:  return err;  
}  /*模块卸载方法*/  
static void __exit helloxjq_exit(void) {  dev_t devno = MKDEV(helloxjq_major, helloxjq_minor);  printk(KERN_ALERT"helloxjq_exit\n");          /*销毁设备类别和设备*/  if(helloxjq_class) {  device_destroy(helloxjq_class, MKDEV(helloxjq_major, helloxjq_minor));  class_destroy(helloxjq_class);  }          /*删除字符设备和释放设备内存*/  if(helloxjq_dev) {  cdev_del(&(helloxjq_dev->dev));  kfree(helloxjq_dev);  }          if(helloxjq_dev->val != NULL){kfree(helloxjq_dev->val);}/*释放设备号*/  unregister_chrdev_region(devno, 1);  
}  MODULE_LICENSE("GPL");  
MODULE_DESCRIPTION("Test Driver");  module_init(helloxjq_init);  
module_exit(helloxjq_exit);  

二、修改

  1. 修改arch/arm/Kconfig和drivers/kconfig两个文件,在menu "Device Drivers"和endmenu之间添加一行:
    source "drivers/helloxjq/Kconfig"
    这样,执行make menuconfig时,就可以配置helloxjq模块的编译选项了,而我们在配置Kconfig时写了default y,默认加载驱动模块,因此不用去menuconfig中配置编译选项。

  2. 修改drivers/Makefile文件,添加一行:
    obj-$(CONFIG_HELLOXJQ) += helloxjq/

  3. 在kernel/arch/arm/configs文件夹中的spyro_defconfig和spyro-perf_defconfig中添加
    CONFIG_HELLOXJQ=y
    一般教程没有这最后一步,但是我这个工程必须添加后才能编入内核。

三、编译

在源码主目录(HLOS)下编译。

source ./build/envsetup.sh
lunch 
make -j32 (也可以使用make -j32 make -j32 2>&1 | tee build.log,会在主目
录下生成build.log日志文件,便于查找错误)

四、验证

将代码工程烧录进安卓设备,通过ADB连接设备,
1、通过cd dev 查看是否有helloxjq文件夹
2、通过cat /proc/devices查看是否存在设备和对应的设备号
3、进入到sys/class目录,查看是否有helloxjq目录

更多推荐

打通驱动层到应用层

本文发布于:2024-02-28 02:19:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1767742.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:应用层

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!