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

参考: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 0

struct 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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值