android hal 学习——编写android内核驱动

来源:互联网 发布:淘宝代发网 编辑:程序博客网 时间:2024/05/22 03:39

参考:http://blog.csdn.net/liuhaoyutz/article/details/9147877

1、代码准备
在下载的android内核的drivers目录下新建了example目录:
代码是拷贝参考文章里的。。。只是去掉了锁相关的内容:

exampe.h内容:

#ifndef _EXAMPLE_H_#define _EXAMPLE_H_#include <linux/cdev.h>#include <linux/semaphore.h>#define EXAMPLE_DEVICE_NODE_NAME "example"#define EXAMPLE_DEVICE_FILE_NAME "example"#define EXAMPLE_DEVICE_PROC_NAME "example"#define EXAMPLE_DEVICE_CLASS_NAME "example"#define EXAMPLE_MAJOR 0struct example_dev{    struct semaphore sem;    struct cdev cdev;    int val;};#endif

exampe.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 <asm/uaccess.h>#include "example.h"static int example_major=EXAMPLE_MAJOR;static int example_minor=0;static struct class* example_class=NULL;static struct example_dev* example_dev=NULL;module_param(example_major,int,S_IRUGO);module_param(example_minor,int,S_IRUGO);static int example_open(struct inode* inode,struct file* filp){    struct example_dev* dev;    dev=container_of(inode->i_cdev,struct example_dev,cdev);    filp->private_data=dev;    return 0;}static int example_release(struct inode* inode,struct file* filp){  return 0;}static ssize_t example_read(struct file* filp,char __user *buf,size_t count,loff_t * f_pos){    struct example_dev* dev = filp->private_data;      ssize_t retval = 0;      /*      * 加锁      */      //if(down_interruptible(&(dev->sem)))        //  return -ERESTARTSYS;      if(count < sizeof(dev->val))          goto out;      /*      * 读寄存器的值到用户空间。      */      if(copy_to_user(buf, &(dev->val), sizeof(dev->val)))      {          retval = -EFAULT;          goto out;      }      retval = sizeof(dev->val);  out:      /*      * 解锁      */     // up(&(dev->sem));      return retval;  }static ssize_t example_write(struct file* filp,const char __user *buf,size_t count,loff_t* f_pos){struct example_dev* dev = filp->private_data;      ssize_t retval = 0;      /*      * 加锁      */      //if(down_interruptible(&(dev->sem)))        //  return -ERESTARTSYS;      if(count != sizeof(dev->val))          goto out;      /*      * 从用户空间读取并给寄存器赋值。      */      if(copy_from_user(&(dev->val), buf, count))      {          retval = -EFAULT;          goto out;      }      retval = sizeof(dev->val);  out:      /*      * 解锁      */     // up(&(dev->sem));      return retval;  }static struct file_operations example_fops={    .owner=THIS_MODULE,    .open=example_open,    .release=example_release,    .read=example_read,    .write=example_write};static ssize_t __example_get_val(struct example_dev* dev,char* buf){    int val=0;//  if(down_interruptible(&(dev->sem))){//      return -ERESTARTSYS;//  }    val=dev->val;//  up(&(dev->sem));    return snprintf(buf,30,"%d\n",val);}static ssize_t __example_set_val(struct example_dev* dev,const char* buf,size_t count){    int val=0;    val=(int)simple_strtol(buf,NULL,10);//  if(down_interruptible(&(dev->sem)))//      return -ERESTARTSYS;    dev->val=val;//  up(&(dev->sem));    return count;}static ssize_t example_val_show(struct device* dev,struct device_attribute* attr,char* buf){     struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev);      return __example_get_val(hdev, buf);}static ssize_t example_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)  {      struct example_dev* hdev = (struct example_dev*)dev_get_drvdata(dev);      return __example_set_val(hdev, buf, count);  }  static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, example_val_show, example_val_store);static ssize_t example_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data)  {      if(off > 0)      {          *eof = 1;          return 0;      }      return __example_get_val(example_dev, page);  } /*  * /proc节点的写操作函数。  */  static ssize_t example_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("Failed to copy buff from user.\n");          err = -EFAULT;          goto out;      }      err = __example_set_val(example_dev, page, len);  out:      free_page((unsigned long)page);      return err;  }/*  * 创建/proc节点  */  static void example_create_proc(void)  {      struct proc_dir_entry* entry;      entry = create_proc_entry(EXAMPLE_DEVICE_PROC_NAME, 0, NULL);      if(entry)      {          //entry->owner = THIS_MODULE;          entry->read_proc = example_proc_read;          entry->write_proc = example_proc_write;      }  }  /*  * 删除/proc节点  */  static void example_remove_proc(void)  {      remove_proc_entry(EXAMPLE_DEVICE_PROC_NAME, NULL);  }static int __example_setup_dev(struct example_dev* dev){    int retval;    dev_t devno=MKDEV(example_major,example_minor);    memset(dev,0,sizeof(struct example_dev));    cdev_init(&(dev->cdev),&example_fops);    dev->cdev.owner=THIS_MODULE;    dev->cdev.ops=&example_fops;    retval=cdev_add(&(dev->cdev),devno,1);    if(retval){        return retval;    }    //sem_init(&(dev->sem), pshared, value);     //init_MUTEX(&(dev->sem));    dev->val=0;    return 0;}static int __init example_init(void){    int retval=-1;    dev_t dev=0;    struct device* device=NULL;    printk("Initializing example device.\n");    if(example_major){        dev=MKDEV(example_major,example_minor);        retval=register_chrdev_region(dev,1,EXAMPLE_DEVICE_NODE_NAME);    }else{        retval = alloc_chrdev_region(&dev, example_minor, 1, EXAMPLE_DEVICE_NODE_NAME);    }    if(retval<0){        printk("can't get example major %d\n",example_major);        goto fail;    }/*  * 取得主设备号和次设备号    */      example_major = MAJOR(dev);      example_minor = MINOR(dev);      /*      * 为设备结构体example_dev动态分配内存空间。      */      example_dev = kmalloc(sizeof(struct example_dev), GFP_KERNEL);      if(!example_dev)      {          retval = -ENOMEM;          printk(KERN_ALERT"Failed to alloc example_dev.\n");          goto unregister;      }      /*      * 调用__example_setup_dev函数对example_dev结构体进行初始化。      */      retval = __example_setup_dev(example_dev);      if(retval)      {          printk(KERN_ALERT"Failed to setup dev: %d.\n", retval);          goto cleanup;      }      /*      * 创建类example,class_create函数执行成功后,在/sys/class目录下      * 就会出现一个名为example的目录。      */      example_class = class_create(THIS_MODULE, EXAMPLE_DEVICE_CLASS_NAME);      if(IS_ERR(example_class))      {          retval = PTR_ERR(example_class);          printk(KERN_ALERT"Failed to create example class.\n");          goto destroy_cdev;      }      /*      * 创建设备,device_create函数执行成功后,会生成/dev/example文件      * 和/sys/class/example/example目录及相关文件。      * 注意device的类型是struct device,代表一个设备。      */      device = device_create(example_class, NULL, dev, "%s", EXAMPLE_DEVICE_FILE_NAME);      if(IS_ERR(device))      {          retval = PTR_ERR(device);          printk(KERN_ALERT"Failed to create example device.");          goto destroy_class;      }      /*      * 创建属性文件,对应的属性操作函数由dev_attr_val指定。      */      retval = device_create_file(device, &dev_attr_val);      if(retval < 0)      {          printk(KERN_ALERT"Failed to create attribute val.");          goto destroy_device;      }      /*      * 将example_dev保存在设备私有数据区中。      */      dev_set_drvdata(device, example_dev);      /*      * 创建proc节点。      */      example_create_proc();      printk(KERN_ALERT"Succedded to initialize example device.\n");      return 0;  destroy_device:      device_destroy(example_class, dev);  destroy_class:      class_destroy(example_class);  destroy_cdev:      cdev_del(&(example_dev->cdev));  cleanup:      kfree(example_dev);  unregister:      unregister_chrdev_region(MKDEV(example_major, example_minor), 1);  fail:      return retval;  }  /*  * 模块清理函数。  */  static void __exit example_exit(void)  {      dev_t dev = MKDEV(example_major, example_minor);      printk(KERN_ALERT"Destroy example device.\n");      example_remove_proc();      if(example_class)      {          device_destroy(example_class, MKDEV(example_major, example_minor));          class_destroy(example_class);      }      if(example_dev)      {          cdev_del(&(example_dev->cdev));          kfree(example_dev);      }      unregister_chrdev_region(dev, 1);  }  MODULE_LICENSE("GPL");  module_init(example_init);  module_exit(example_exit);

Makefile内容:

obj-y +=example.o

在drivers下的Makefile下也增加一行:
obj-y +=example/

2、编译
[zzz@localhost goldfish]$ make ARCH=arm CROSS_COMPILE=/home/zzz/opensource/android-src/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
CHK include/linux/version.h
CHK include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h’ is up to date.
CALL scripts/checksyscalls.sh
CHK include/generated/compile.h
CHK kernel/config_data.h
CC drivers/example/example.o
LD drivers/example/built-in.o
LD drivers/built-in.o
LD vmlinux.o

SYSMAP System.map
SYSMAP .tmp_System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy.gzip
AS arch/arm/boot/compressed/piggy.gzip.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready

后面再继续测试了。

0 0