在Ubuntu上为Android系统编写Linux内核驱动程序(学习老罗的)
首先提出2个问题1. 驱动程序的作用是什么?答:驱动程序的作用主要是向上层提供访问设备寄存器的一个接口,包括读和写。2. 访问设备驱动程序的方法?答:a. 通过proc文件系统来访问;b. 通过传统的设备文件的方法来访问;c.通过devfs文件系统来访问。他定义的hello.h在最新goldfish路径应该为:~/Android_4.2.2_SourceCode/kerne
1. 驱动程序的作用是什么?
答:驱动程序的作用主要是向上层提供访问设备寄存器的一个接口,包括读和写。
2. 访问设备驱动程序的方法?
答:a. 通过proc文件系统来访问;b. 通过传统的设备文件的方法来访问;c. 通过devfs文件系统来访问。
他定义的hello.h在最新goldfish路径应该为:~/Android_4.2.2_SourceCode/kernel/goldfish/drivers/hello中
内容为:结构体hello_android_dev来表示虚拟的硬件设备
#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_PROC_NAME "hello"
#define HELLO_DEVICE_CLASS_NAME "hello"
// 字符设备结构体
// 也是我们定义的虚拟的硬件设备
struct hello_android_dev {
int val; // 设备里面的寄存器
struct semaphore sem; // sem成员变量是一个信号量,是用同步访问寄存器val的
struct cdev dev; // 一个内嵌的字符设备
};
#endif
并且这样的写法是标准的Linux驱动程序自定义字符设备结构体方法。
下面是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 <asm/uaccess.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;
/*传统的设备文件操作方法*/
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);
/*设备文件操作方法表。即 -- proc文件系统访问方法 */
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
};
/*访问设置属性方法*/
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);
/
// part_函数实现
/*打开设备方法*/
static int hello_open(struct inode* inode, struct file* filp) {
struct hello_android_dev* dev;
/*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/
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;
}
/*读取设备的寄存器val的值*/
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;
/*同步访问*/
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 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 != 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 __hello_get_val(struct hello_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 __hello_set_val(struct hello_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 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);
return __hello_get_val(hdev, buf);
}
/*写设备属性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);
return __hello_set_val(hdev, buf, count);
}
/*读取设备寄存器val的值,保存在page缓冲区中*/
static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {
if(off > 0) {
*eof = 1;
return 0;
}
return __hello_get_val(hello_dev, page);
}
/*把缓冲区的值buff保存到设备寄存器val中去*/
static ssize_t hello_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 = __hello_set_val(hello_dev, page, len);
out:
free_page((unsigned long)page);
return err;
}
/*创建/proc/hello文件*/
static void hello_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 = hello_proc_read;
entry->write_proc = hello_proc_write;
}
}
/*删除/proc/hello文件*/
static void hello_remove_proc(void) {
remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
}
/*初始化设备*/
static int __hello_setup_dev(struct hello_android_dev* dev) {
int err;
dev_t devno = MKDEV(hello_major, hello_minor);
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;
}
/*初始化信号量和寄存器val的值*/
init_MUTEX(&(dev->sem));
dev->val = 0;
return 0;
}
/*模块加载方法*/
static int __init hello_init(void){
int err = -1;
dev_t dev = 0;
struct device* temp = NULL;
printk(KERN_ALERT"Initializing hello 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;
}
hello_major = MAJOR(dev);
hello_minor = MINOR(dev);
/*分配helo设备结构体变量*/
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;
}
/*在/sys/class/目录下创建设备类别目录hello*/
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;
}
/*在/dev/目录和/sys/class/hello目录下分别创建设备文件hello*/
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;
}
/*在/sys/class/hello/hello目录下创建属性文件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, hello_dev);
/*创建/proc/hello文件*/
hello_create_proc();
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"Destroy hello device.\n");
/*删除/proc/hello文件*/
hello_remove_proc();
/*销毁设备类别和设备*/
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);
}
/*释放设备号*/
unregister_chrdev_region(devno, 1);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("First Android Driver");
module_init(hello_init);
module_exit(hello_exit);
///
转自:http://blog.csdn.net/luoshengyang/article/details/6568411
在智能手机时代,每个品牌的手机都有自己的个性特点。正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非iphone莫属了。据统计,截止2011年5月,AppStore的应用软件数量达381062个,位居第一,而Android Market的应用软件数量达294738,紧随AppStore后面,并有望在8月份越过AppStore。随着Android系统逐步扩大市场占有率,终端设备的多样性亟需更多的移动开发人员的参与。据业内统计,Android研发人才缺口至少30万。目前,对Android人才需求一类是偏向硬件驱动的Android人才需求,一类是偏向软件应用的Android人才需求。总的来说,对有志于从事Android硬件驱动的开发工程师来说,现在是一个大展拳脚的机会。那么,就让我们一起来看看如何为Android系统编写内核驱动程序吧。
这里,我们不会为真实的硬件设备编写内核驱动程序。为了方便描述为Android系统编写内核驱动程序的过程,我们使用一个虚拟的硬件设备,这个设备只有一个4字节的寄存器,它可读可写。想起我们第一次学习程序语言时,都喜欢用“Hello, World”作为例子,这里,我们就把这个虚拟的设备命名为“hello”,而这个内核驱动程序也命名为hello驱动程序。其实,Android内核驱动程序和一般Linux内核驱动程序的编写方法是一样的,都是以Linux模块的形式实现的,具体可参考前面Android学习启动篇一文中提到的Linux Device Drivers一书。不过,这里我们还是从Android系统的角度来描述Android内核驱动程序的编写和编译过程。
一. 参照前面两篇文章在Ubuntu上下载、编译和安装Android最新源代码和在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)准备好Android内核驱动程序开发环境。
二. 进入到kernel/common/drivers目录,新建hello目录:
USER-NAME@MACHINE-NAME:~/Android$ cd kernel/common/drivers
USER-NAME@MACHINE-NAME:~/Android/kernel/common/drivers$ mkdir hello
三. 在hello目录中增加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_PROC_NAME "hello"
- #define HELLO_DEVICE_CLASS_NAME "hello"
- struct hello_android_dev {
- int val;
- struct semaphore sem;
- struct cdev dev;
- };
- #endif
这个头文件定义了一些字符串常量宏,在后面我们要用到。此外,还定义了一个字符设备结构体hello_android_dev,这个就是我们虚拟的硬件设备了,val成员变量就代表设备里面的寄存器,它的类型为int,sem成员变量是一个信号量,是用同步访问寄存器val的,dev成员变量是一个内嵌的字符设备,这个Linux驱动程序自定义字符设备结构体的标准方法。
四.在hello目录中增加hello.c文件,这是驱动程序的实现部分。驱动程序的功能主要是向上层提供访问设备的寄存器的值,包括读和写。这里,提供了三种访问设备寄存器的方法,一是通过proc文件系统来访问,二是通过传统的设备文件的方法来访问,三是通过devfs文件系统来访问。下面分段描述该驱动程序的实现。
首先是包含必要的头文件和定义三种访问设备的方法:
- #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 "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;
- /*传统的设备文件操作方法*/
- 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,
- };
- /*访问设置属性方法*/
- 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);
定义传统的设备文件访问方法,主要是定义hello_open、hello_release、hello_read和hello_write这四个打开、释放、读和写设备文件的方法:
- /*打开设备方法*/
- static int hello_open(struct inode* inode, struct file* filp) {
- struct hello_android_dev* dev;
- /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/
- 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;
- }
- /*读取设备的寄存器val的值*/
- 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;
- /*同步访问*/
- 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 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 != 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;
- }
定义通过devfs文件系统访问方法,这里把设备的寄存器val看成是设备的一个属性,通过读写这个属性来对设备进行访问,主要是实现hello_val_show和hello_val_store两个方法,同时定义了两个内部使用的访问val值的方法__hello_get_val和__hello_set_val:
- /*读取寄存器val的值到缓冲区buf中,内部使用*/
- static ssize_t __hello_get_val(struct hello_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 __hello_set_val(struct hello_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 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);
- return __hello_get_val(hdev, buf);
- }
- /*写设备属性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);
- return __hello_set_val(hdev, buf, count);
- }
定义通过proc文件系统访问方法,主要实现了hello_proc_read和hello_proc_write两个方法,同时定义了在proc文件系统创建和删除文件的方法hello_create_proc和hello_remove_proc:
- /*读取设备寄存器val的值,保存在page缓冲区中*/
- static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {
- if(off > 0) {
- *eof = 1;
- return 0;
- }
- return __hello_get_val(hello_dev, page);
- }
- /*把缓冲区的值buff保存到设备寄存器val中去*/
- static ssize_t hello_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 = __hello_set_val(hello_dev, page, len);
- out:
- free_page((unsigned long)page);
- return err;
- }
- /*创建/proc/hello文件*/
- static void hello_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 = hello_proc_read;
- entry->write_proc = hello_proc_write;
- }
- }
- /*删除/proc/hello文件*/
- static void hello_remove_proc(void) {
- remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
- }
最后,定义模块加载和卸载方法,这里只要是执行设备注册和初始化操作:
- /*初始化设备*/
- static int __hello_setup_dev(struct hello_android_dev* dev) {
- int err;
- dev_t devno = MKDEV(hello_major, hello_minor);
- 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;
- }
- /*初始化信号量和寄存器val的值*/
- init_MUTEX(&(dev->sem));
- dev->val = 0;
- return 0;
- }
- /*模块加载方法*/
- static int __init hello_init(void){
- int err = -1;
- dev_t dev = 0;
- struct device* temp = NULL;
- printk(KERN_ALERT"Initializing hello 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;
- }
- hello_major = MAJOR(dev);
- hello_minor = MINOR(dev);
- /*分配helo设备结构体变量*/
- 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;
- }
- /*在/sys/class/目录下创建设备类别目录hello*/
- 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;
- }
- /*在/dev/目录和/sys/class/hello目录下分别创建设备文件hello*/
- 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;
- }
- /*在/sys/class/hello/hello目录下创建属性文件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, hello_dev);
- /*创建/proc/hello文件*/
- hello_create_proc();
- 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"Destroy hello device.\n");
- /*删除/proc/hello文件*/
- hello_remove_proc();
- /*销毁设备类别和设备*/
- 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);
- }
- /*释放设备号*/
- unregister_chrdev_region(devno, 1);
- }
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("First Android Driver");
- module_init(hello_init);
- module_exit(hello_exit);
五.在hello目录中新增Kconfig和Makefile两个文件,其中Kconfig是在编译前执行配置命令make menuconfig时用到的,而Makefile是执行编译命令make是用到的:
Kconfig文件的内容
-
顶
- 67
-
踩
- 0
-
60楼
顾小林 2013-05-15 13:17发表 [回复]
-
老罗:
您好,关于在hello_open()这个函数里面我有点疑惑
我想知道 当调用这个函数传进来的这个 inode* inode
inode->i_cdev 这个怎么理解呢
我通过一些资料了解到 这个container_of 大概是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址 是否正确呢?
如果上面的那个解释正确 那那个inode->i_cdev理解为哪个成员地址呢?
菜鸟一枚,请帮忙指点一下,谢谢!
-
59楼
ajige 2013-05-09 10:49发表 [回复]
-
博主,/sys/class/hello/hello
为什么这个文件 我用 echo cat 去测试 结果是正确的,
但是用C语言的read和write去测试的时候,结果却很怪,
这两者有区别吗?
-
58楼
u010493203 2013-05-03 15:12发表 [回复]
-
老罗,我一个有一个问题想问,就是HAL、Overlay、Opengl、Omx(Openmax)之间的联系是什么。个人感觉,overlay是Hal的一种,opengl和omx(openmax)是两个独立的体系,在显示图像的时候Opengl应该是调用openmax的,openmax则和HAL没有关系。不知道是不是这样,望解答,不胜感激~
-
Re:
罗升阳 2013-05-03 18:30发表 [回复]
-
回复u010493203:你问到我的痛处了,我也正想搞清楚它们的关系,过阵子就去研究。
-
Re:
u010493203 2013-05-03 23:11发表 [回复]
- 回复Luoshengyang:恩, 我也在研究,等有了结果在和你讨论一下吧
-
57楼
hgd_dingjun 2013-04-08 16:46发表 [回复]
-
- #define DBGLCDS_IOCTL_RESET _IO(DBGLCDS_IOC_MAGIC, 0)
- #define DBGLCDS_IOCTL_INIT _IO(DBGLCDS_IOC_MAGIC, 1)
- #define DBGLCDS_IOCTL_SLEEP _IO(DBGLCDS_IOC_MAGIC, 2)
- #define DBGLCDS_IOCTL_WAKEUP _IO(DBGLCDS_IOC_MAGIC, 3)
- #define DBGLCDS_IOCTL_OPENBL _IO(DBGLCDS_IOC_MAGIC, 4)
- #define DBGLCDS_IOCTL_CLOSEBL _IO(DBGLCDS_IOC_MAGIC, 5)
-
56楼
hgd_dingjun 2013-04-08 16:44发表 [回复]
-
- switch( id )
- {
- ......
- case 3:
- {
- struct dbglcds_setting_table param =
- {
- 0,
- 0,
- {0,},
- };
- ret = ioctl(fd, DBGLCDS_IOCTL_OPENBL, ¶m);
- if(ret)
- {
- TEST_LOG("dbglcds fail SLEEP!!\n");
- return TEST_FAIL;
- }
- TEST_LOG("dbglcds SLEEP successfully!!\n");
- return TEST_SUCCESS;
- }
- break;
- ......
- }
-
Re:
hgd_dingjun 2013-04-08 16:47发表 [回复]
- 回复hgd_dingjun:这个是应用程序的代码片段
-
55楼
hgd_dingjun 2013-04-08 16:41发表 [回复]
- 评论区怎么贴源代码,好像代码超出字数限制?!
-
54楼
hgd_dingjun 2013-04-08 16:40发表 [回复]
-
- static int dbglcds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- {
- int ret = 0;
- struct dbglcds_android_dev* dev;
- dev = container_of(inode->i_cdev, struct dbglcds_android_dev, c_dev);
- switch(cmd)
- {
- case DBGLCDS_IOCTL_RESET:
- {
- }
- break;
- case DBGLCDS_IOCTL_INIT:
- {
- lcm_init();
- }
- break;
- case DBGLCDS_IOCTL_SLEEP:
- {
- lcm_suspend();
- }
- break;
- case DBGLCDS_IOCTL_WAKEUP:
- {
- lcm_resume();
- }
- break;
- case DBGLCDS_IOCTL_OPENBL:
- {
- lcm_suspend();
- }
- break;
- case DBGLCDS_IOCTL_CLOSEBL:
- {
- lcm_suspend();
- }
- break;
- }
- return ret;
- }
-
Re:
hgd_dingjun 2013-04-08 16:47发表 [回复]
- 回复hgd_dingjun:这个是驱动文件的代码片段
-
53楼
hgd_dingjun 2013-04-08 16:34发表 [回复]
-
罗老师,您好!
我参照您的Android系统源代码情景分析一书写了一个dbglcdsdrv.c驱动文件和dbglcds_test.c的应用测试文件,功能就是应用程序通过ioctl直接写lcd寄存器以控制lcd进入睡眠和退出睡眠的两项简单功能,但目前遇到一旦测试进入睡眠的功能时,屏就变白,这可以认为控制到了吗?但接着就出现重启,重启信息(Unable to handle kernel NULL pointer dereference at virtual address 00000000 ):
[ 225.912845] DBGLCDSDRV dbglcds_ioctl
[ 225.913280] *******************dbglcds lcm_suspend *******************
[ 225.914113] [DSI] [DISP] - kernel - DSI_set_cmdq_V2. DSI_CMDQ+0000 : 0x00281500
[ 225.915063] [DSI] [DISP] - kernel - DSI_set_cmdq_V2. DSI_CMDQ+0000 : 0x00101500
[ 225.915978] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 225.916993] pgd = ced48000
[ 225.917316] [00000000] *pgd=0974a031, *pte=00000000, *ppte=00000000
[ 225.918189] Internal error: Oops: 80000007 [#1] PREEMPT
[ 225.938389]
[ 225.938392] SP: 0xc83b3e20:
......
......
......
罗老师是否能够帮忙分析下?稍后我贴出源代码-
Re:
罗升阳 2013-04-08 17:55发表 [回复]
-
回复hgd_dingjun:lcm_suspend有个空指针,应该是没初始化好。
-
Re:
hgd_dingjun 2013-04-08 19:23发表 [回复]
-
回复Luoshengyang:罗老师,您好!
表面上我未看出哪里存在空指针,由于字数的限制,未能贴出完整代码,只能说到哪贴到哪,请见谅!如果您有高见,请不吝赐教,谢谢!
-
Re:
hgd_dingjun 2013-04-08 19:19发表 [回复]
-
- /*dbglcds_setting_table结构体定义如下:*/
- static struct dbglcds_setting_table {
- unsigned reg;
- unsigned char cnt;
- unsigned char dat_list[64];
- };
- struct dbglcds_android_dev {
- struct dbglcds_setting_table val;
- struct semaphore sem;
- struct cdev c_dev;
- };
-
Re:
hgd_dingjun 2013-04-08 19:12发表 [回复]
-
- /*罗老师,您好!*/
- /*lcm_suspend实现如下:*/
- static void push_table(struct dbglcds_setting_table *table, unsigned int count, unsigned char force_update)
- {unsigned int i;
- for(i = 0; i < count; i++) {
- unsigned cmd;
- cmd = table[i].reg;
- switch (cmd) {
- case REGFLAG_DELAY :
- MDELAY(table[i].cnt);
- break;
- case REGFLAG_END_OF_TABLE :
- break;
- default:
- DSI_set_cmdq_V2(cmd, table[i].cnt, table[i].dat_list, force_update);
- }
- }
- }
- static struct dbglcds_setting_table lcm_deep_sleep_mode_in_setting[] = {
- // Display off sequence
- {0x28, 1, {0x00}},
- // Sleep Mode On
- {0x10, 1, {0x00}},
- {REGFLAG_DELAY, 10, {}},//{REGFLAG_DELAY, 150, {}},
- {REGFLAG_END_OF_TABLE, 0x00, {}}
- };
- static void lcm_suspend(void)
- {
- printk("*******************dbglcds lcm_suspend ******************* \n");
- push_table(lcm_deep_sleep_mode_in_setting, sizeof(lcm_deep_sleep_mode_in_setting) / sizeof(struct dbglcds_setting_table), 1);
- }
-
52楼
hgd_dingjun 2013-03-27 16:12发表 [回复]
-
罗老师,您好!
我现在需求是写一个应用,该应用需要将lcd的初始化代码放到T卡上,通过上层java应用读取该文件的参数,然后又通过java应用直接写回屏的寄存器中,重新初始化lcd,看了您的例子是通过读取或者写入一个参数,那么,我现在是需要写入很多的参数,例如屏的init代码如下:
//part I reset pin
SET_RESET_PIN(1);
SET_RESET_PIN(0);
MDELAY(1);
SET_RESET_PIN(1);
MDELAY(120);
//part II set register code
{
。。。。。。
{0x00,1,{0x00}},
{0x00,1,{0xc7}},//Address shift
{0xCf,1,{0x00}},
{0xCE,14,{0x30,0x02,0x03,0x5e,0x00,0x00,0x00,0x30,0x03,0x03,0x5f,0x00,0x00,0x00}},
{0x00,1,{0xc9}},//Address shift
{0xCf,1,{0x00}},
。。。。。。
{REGFLAG_END_OF_TABLE, 0x00, {}}
请问这种情况用什么方法实现比较好?!期待您的回复,谢谢!-
Re:
罗升阳 2013-03-27 16:26发表 [回复]
-
回复hgd_dingjun:你可以在你的驱动里面实现一个ioctl接口,然后定义一个结构体来接收数据,这个结构体随便你定义,要接收多少个参数都可以。
-
Re:
hgd_dingjun 2013-03-27 17:28发表 [回复]
-
回复Luoshengyang:罗老师,您好!
由于我刚刚接触android驱动开发,所以很多地方还不太明白,您说在驱动里面实现一个ioctl接口,我是否可以将这个接口直接写在现有的lcd驱动里,还是需要另外建立一个新文件来写?还有关于ioctl接口实现的细节是否有可参考的实例?谢谢!
-
51楼
livagain1988 2013-03-26 15:37发表 [回复]
- 您好,我copy您的代码直接编译成功,有hello.o,但是最后在虚拟机上面没有看到hello设备,能给些建议吗?不知到哪里除了问题
-
50楼
nexttake 2013-03-18 11:04发表 [回复]
-
老罗你好:hello.o 与在unbuntu 平台编译出了的hello.ko的关系是什么呢?
在android srouce ,如果不想全编整个kernel而单独编译某一个驱动如何编译呢?
-
49楼
xuexingyang 2013-03-04 15:06发表 [回复]
- 建议老罗把每篇文章的后面“下一篇”链接修改成正确的文章,不要都是指到第一篇,方便大家阅读,谢谢。
-
48楼
hao1056531028 2013-02-25 20:49发表 [回复]
- 我在android中照着你这个写一个字符设备驱动测试程序时,我已经注册读和写函数在struct file_operations结构中,但是在我open这个字符设备完之后,我调用read和write函数,只有read函数能够调用,我在注册到struct file_operations中的写函数最前面打印log发现:调用write函数并没有调用这个注册写函数,请问这是什么情况?现在只有读函数可以使用
-
47楼
ch_jason 2013-02-25 17:45发表 [回复]
- 修改的应该是drivers/Kconfig,drivers/Makefile,arch/arm/Kconfig,才能编译出hello.o
-
45楼
zero_create 2012-12-26 19:08发表 [回复]
-
谢谢!
根据这个实践下来,很有收获
-
43楼
insoonior 2012-11-14 23:25发表 [回复]
-
罗老师,我看一下device_create的定义:struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata,const char *fmt, ...)
temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
应该是这样的吧:
temp = device_create(hello_class, NULL, dev, NULL, "%s", HELLO_DEVICE_FILE_NAME);
另外请问一下老师:
cat /dev/hello 时出现了无限调用驱动的hello_read,这是为什么呢?打印出来发现传入hello_read的count值为4096
echo 1 > /dev/hello 时出现11次调用hello_write,传入hello_write的count值为2。-
Re:
罗升阳 2012-11-15 02:47发表 [回复]
-
回复insoonior:是的,你说的没错,这里写错了,不过之所以能正常工作,是因为函数device_create有一个可变参数列表,下面这种写法:
temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
参数drvdata等于“%s”,fmt等于HELLO_DEVICE_FILE_NAME,即“hello”,由于里面没有%s或者%d之类的格式化符号,因此,就能正常工作,不过是歪打正着了。多谢你的指出,新出的书《Android系统源代码情景分析》也有同样的错误,已经列在勘误表中:http://blog.csdn.net/luoshengyang/article/details/8116866。
设备文件/dev/hello不能用cat或者echo命令来读写,读写它只能用API函数read或者write来进行,具体可以参考:http://blog.csdn.net/luoshengyang/article/details/6571210。
-
42楼
dfshk 2012-09-20 09:46发表 [回复]
- 老师,请问一下开发android底层或是内核程序的时候,一定需要下载android源码吗?可以用其他工具或是其他开发平台进行开发编译吗?(现在想开发android的一些底层的应用程序,尽量支持大部分现有的android手机,也就是一些底层的app,提供给手机下载、安装和使用)
-
41楼
herodie 2012-09-05 19:49发表 [回复]
- 呵呵~~今天把楼主的code复制到自己的kernel里试了一把,稍微改了点就很顺利地编译并运行了。仔细看了下insmod和rmmod时的打印和调用顺序。太谢谢楼主了~~~还是直接实践下印象最深。
-
40楼
tomew 2012-08-22 10:39发表 [回复]
- 请问err = device_create_file(temp, &dev_attr_val);这句里面的dev_attr_val在哪里定义的
-
39楼
qq258711519 2012-07-26 17:53发表 [回复]
- 有种豁然开朗的感觉!真心谢谢老罗老师!!!
-
38楼
doom66151 2012-07-26 14:50发表 [回复]
-
写的好,谢谢分享。其实使用ldd里面例子就挺好的。
信号量的初始化应该是sema_init (&(dev->sem), 1) ;不过这里用mutex会更简单吧
-
37楼
sunjianli2007 2012-07-26 10:43发表 [回复]
- 你好,我已经可以再自己编译的内核模拟器上加载简单的内核模块了,但是,在将.ko模块加载到默认模拟器时就报错了insmod: init_module 'hello.ko' failed (Function not implemented),有人说模拟器默认的内核未开启模块加载功能,要进行设置后在重新编译内核,我想知道除了这种方法还有其他方法么?还有在android手机上也是和模拟器一样默认不允许加载内核模块么?
-
36楼
dongshengzou95 2012-07-20 10:33发表 [回复]
- 请问楼主,我编译正常完成,但是命令行运行模拟器时,不能弹出qemu界面,不知为何?命令是./out/host/linux-x86/bin/emulator -system ./out/target/product/generic/system.img -data ./out/target/product/generic/userdata.img -ramdisk ./out/target/product/generic/ramdisk.img -kernel ./kernel/arch/arm/boot/uImage -skin /jingda/temp/TI_Android_GingerBread_2_3_Sources/sdk/emulator/skins/WVGA800 @android_1
-
35楼
baoyu512 2012-05-14 17:31发表 [回复]
- 为什么我执行了emulator命令后,模拟器是出来了,但是命令行去卡在那儿了,输入adb shell命令没反应?? 楼主帮忙啊
-
34楼
Rickbeyond 2012-05-14 12:34发表 [回复]
-
麻烦楼主大人帮忙看看:
drivers/built-in.o:(.data+0x20f5c): undefined reference to `hello_write'
drivers/built-in.o:(.data+0x20fc4): undefined reference to `hello_val_store'
make: *** [.tmp_vmlinux1] 错误 1
这错误怎么跟built-in扯上了,我是新手,不知道如何修改-
Re:
Rickbeyond 2012-05-14 13:51发表 [回复]
- 回复Rickbeyond:抱歉,找到原因了,代码拷贝少了这两部分...
-
33楼
memorysense 2012-04-25 14:19发表 [回复]
-
编译内核时出现:
drivers/char/goldfish_tty.c: In function 'goldfish_tty_probe':
drivers/char/goldfish_tty.c:233: error: 'IO_START' undeclared (first use in this function)
drivers/char/goldfish_tty.c:233: error: (Each undeclared identifier is reported only once
drivers/char/goldfish_tty.c:233: error: for each function it appears in.)
make[2]: *** [drivers/char/goldfish_tty.o] 错误 1
make[1]: *** [drivers/char] 错误 2
make: *** [drivers] 错误 2
make: *** 正在等待未完成的任务....
-
31楼
z1w2p32012 2012-04-07 16:40发表 [回复]
-
楼主辛苦了,写的非常棒。但是我遇到一个问题,能帮你忙解答一下吗?问题是:我下到真机了面 dev 、proc、class 下面的文件都能看到,就是echo 和 cat 命令都不能正常执行。执行情况如下:
# cd /sys/class/hello
cd /sys/class/hello
# cd hello
cd hello
# cat val
cat val
然后就停在那了,没有返回,我也不能重新敲命令。我也没看到任何log,有没有遇到同样问题的,帮忙解答一下。
十分谢谢!-
Re:
z1w2p32012 2012-04-14 18:21发表 [回复]
-
前一段时间忙别的了,这个问题我后来调试了一下找到原因了,所以写出来,原因就是:init_MUTEX这个函数在我的平台没有,我用的是sema_init(&dev->sem,0);初始值不对,要改成sema_init(&dev->sem,1);就OK了,好像初始为0,在down_interruptible(&(dev->sem))) ;时睡眠在里面了,具体原因不是很理解,如果有懂得帮忙解析一下。谢谢!
-
Re:
Rickbeyond 2012-05-17 16:38发表 [回复]
- 回复z1w2p32012:我也碰到了这个问题,init_MUTEX编译报错,改成sema_init(&dev->sem,0)可以通过编译,但在adb shell中cat hello就卡死。我连的是真机,不是在模拟器环境下。找不到解决方法。
-
30楼
yefei089 2012-03-23 11:35发表 [回复]
-
楼主你好!我接触android有差不多一个月了,看了你的文章受益菲浅。
我在android2.2下按照你的步骤,make menuconfig出来了那个hello驱动的选项,但是选‘y’时,然后make,并没有编译hello模块。hello.o文件没有生成,这是什么原因呢?请教下!
-
29楼
thrill007 2012-03-09 10:07发表 [回复]
-
罗老师,
我的hello驱动写进去和读出来不一样,所以我着手开始调试hello driver,但是发现我添加的printk(KERN_ALERT。。。)语句无输出。
在hello_init()里面添加的printk都可以输出(随着kernel启动输出到串口终端,dmesg也可以看到), 但是在运行hello后,__hello_set_val()和__hello_get_val()里添加的printk都没有输出,为何?
-
28楼
jqyp324 2012-02-25 13:21发表 [回复]
-
楼主,我是编译的goldfish内核,也是4.0.3最新的代码,所以和你上面些的有些不一样,但是这些都没有关系,我照着你的博客顺序做到了这篇,在编译的时候出现了In file included from fs/coda/psdev.c:44:
include/linux/coda.h:223: error: expected specifier-qualifier-list before 'u_quad_t'
make[2]: *** [fs/coda/psdev.o] 错误 1
make[1]: *** [fs/coda] 错误 2
make: *** [fs] 错误 2
这样的错误,希望楼主能帮助解决-
Re:
chenlong12580 2012-02-28 16:58发表 [回复]
- 回复jqyp324:可见看看http://blog.csdn.net/livingpark/article/details/5929071
-
25楼
Righthek 2011-11-11 09:08发表 [回复]
- 佩服,罗博主写得很好呀!谢谢分享!针对有的博友说在结构体proc_dir_entry里没有owner成员,在linux2.6.29及之前的内核版本都有owner成员。在linux2.6.30以上的内核里,就没有了ower成员,而多了一个struct list_head pde_openers; /* who did ->open, but not ->release */ 。 博主,这个问题能否解决呢?
-
23楼
floweriswho 2011-11-02 23:38发表 [回复]
-
罗老师 我卡住了
在编译内核时提示 错误 。。。以前是好使的。。。
帮我看看 。。。
li@li-HP-ProBook-4421s:/usr/android_src/kernel/common$ make
make: arm-eabi-gcc:命令未找到
CHK include/linux/version.h
make[1]: “include/asm-arm/mach-types.h”是最新的。
CHK include/linux/utsrelease.h
SYMLINK include/asm -> include/asm-arm
CC kernel/bounds.s
/bin/sh: arm-eabi-gcc: not found
make[1]: *** [kernel/bounds.s] 错误 127
make: *** [prepare0] 错误 2
li@li-HP-ProBook-4421s:/usr/android_src/kernel/common$-
Re:
罗升阳 2011-11-03 21:26发表 [回复]
-
回复floweriswho:交叉编译工具没设置好~~回到前面一篇文章《在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)》去看看
-
Re:
floweriswho 2011-11-03 23:19发表 [回复]
-
回复Luoshengyang:哦!原来是 环境变量没配。。。
:-)
希望早日看到 java实现部分
C语言 不懂阿。。。
-
22楼
chenlingwx 2011-11-02 17:22发表 [回复]
-
罗老师您好:
因为这个“hello”是你虚拟的设备,所以想问下,如果有个真实的设备,怎么写核心层的驱动呢?
我这里的情况是这样的:
我有一台三星P7510的pad,在pad上面插上U盘能识别也能复制U盘里的东西,对应该U盘的是/dev/sg0设备文件(因为不插U盘没有sg0,插了U盘只增加1个sg0,所以我想就是这个对应了)。
好下面头疼的问题来了,我把U盘拔掉,换我自己的一个USB接口的小型设备(不是U盘)插上,pad能向这个小型设备供电(因为小型设备亮灯了),但是在/dev目录下没有看见增加任何设备文件与这个小型设备对应,这样我就无法操作这个小型设备了。
所以想请您指导下,在这个时候如何能让/dev目录下增加那个对应的设备文件呢?求罗老师指导下思路,或者罗老师说说您自己的看法也可以。
如有指导,万分感谢!-
Re:
chenlingwx 2011-11-02 17:24发表 [回复]
- 回复chenlingwx:总之,就是想通过/dev下的设备文件去操作自己的这个小型USB设备,但现在貌似找不到对应的设备文件。
-
20楼
jxgtalent 2011-10-26 15:41发表 [回复]
-
报告以下错误,求教了
root@flyingfisher-virtual-machine:/Work/ABC/prettyboy/linux_kernel/kernel.git# make
HOSTLD scripts/kconfig/conf
scripts/kconfig/conf -s arch/arm/Kconfig
drivers/video/Kconfig:1897:warning: multi-line strings not supported
CHK include/linux/version.h
SYMLINK include/asm-arm/arch -> include/asm-arm/arch-goldfish
make[1]: `include/asm-arm/mach-types.h' is up to date.
CHK include/linux/utsrelease.h
CALL scripts/checksyscalls.sh
<stdin>:1097:2: warning: #warning syscall fadvise64 not implemented
~~~~~中间略去~~~~~~~~~
CHK include/linux/compile.h
LD drivers/built-in.o
arm-eabi-ld: error: cannot open drivers/hello/built-in.o: No such file or directory
make[1]: *** [drivers/built-in.o] Error 1
make: *** [drivers] Error 2
-
19楼
stephen318tao 2011-10-25 14:32发表 [回复]
-
楼主
我在arch/arm/Kconfig中找不到menu “Device Drivers”
然后make menuconfig就报出
make: *** No rule to make target `menuconfig'. Stop.-
Re:
罗升阳 2011-10-25 21:38发表 [回复]
- 回复stephen318tao:你看看这篇文章《在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)》,make menuconfig之前要配置一下
-
17楼
ThinkZhang 2011-10-14 11:00发表 [回复]
-
编译可以,hello.o也生成了,可就是在dev下找不到hello,这是什么原因。。。
-
Re:
ThinkZhang 2011-10-14 16:23发表 [回复]
- 回复s762888517:可以了。版本错了
-
16楼
wantianpei 2011-09-28 16:05发表 [回复]
-
楼主:
"六. 修改arch/arm/Kconfig和drivers/kconfig两个文件"
修改drivers/kconfig 这个文件可以理解, 可是为什么要修改arch/arm/Kconfig这个文件呢? 不理解.
而且我发现并不是所有的驱动都会在arch/arm/Kconfig里添加一份拷贝的. 所以不是很明白.请多多指教!-
Re:
罗升阳 2011-09-28 23:06发表 [回复]
-
回复wantianpei:实际上执行make menuconfig命令时,首先是会去读取arch/$(ARCH)/Kconfig,$(ARCH)就是你要在哪个体系架构上编译这个内核。
一般各体系架构下的Kconfig文件会通过命令soruce "drivers/Kconfig"把drivers目录下的Kconfig目录包含进来,例如x86体系架构,但是arm体系架构比较特殊,它没有把drivers/Kconfig文件包含进去,因此,它把drivers/Kconfig文件的内容都拷贝进去。
事实上,对于arm体系架构,这里我们不在drivers/Kconfig文件加上我们自己的Kconfig也可以,但是为了兼容其它体系架构,就需要在drivers/Kconfig文件也加上自己的Kconfig了。
-
15楼
kevinacc 2011-09-20 14:59发表 [回复]
-
$ echo '5' > hello
cannot create hello: permission denied
出现了权限的问题。请问博主有没遇到这样的问题。
-
14楼
wantianpei 2011-09-07 00:39发表 [回复]
-
楼主得把这几行代码顺序改成这样:
/*访问设置属性方法*/
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);
反正我按照你上面那样编译是会报错的,根据提示改成这样就OK通过了。
-
12楼
shcalm 2011-08-26 10:23发表 [回复]
- 您好,问您个问题,我编译内核的时候,把根目录makefile里面把arch修改为arm以后,修改drivers下面的kconfig,然后make menuconfig,修改的没有起作用,如果我把根目录下面的makefile恢复原状,再make menuconfig,drivers下面kconfig的修改就显示出来了,您知道这是什么原因造成的吗?多谢了
-
11楼
mjk19871208ioy 2011-08-21 16:37发表 [回复]
-
楼主:编译上面写的Hello源码时会出现以下的错误,求解释啊!!/kernel/drivers/hello/hello.c: In function 'hello_create_proc':
/kernel/drivers/hello/hello.c:205: error: 'struct proc_dir_entry' has no member named 'owner'
即9楼的问题啊!-
Re:
罗升阳 2011-08-21 16:51发表 [回复]
-
回复mjk19871208ioy:1. struct proc_dir_entry定义在<linux/proc_fs.h>文件里面,你去看看它的定义有没有owner成员变量
2. 看看你的hello.c文件有没有#inculde <linux/proc_fs.h>
3. 再不行就检查一下代码哪些不小心写错了-
Re:
guidian103 2012-02-16 14:29发表 [回复]
- 检查过来,android4.0的结构体没有那个 成员变量,不知道可以用什么替代掉,或者干脆不要。
-
10楼
bychen_19851208 2011-08-02 15:16发表 [回复]
-
LZ,android2.3源码,根目录没有kernel目录啊
-
Re:
罗升阳 2011-08-02 15:23发表 [回复]
-
回复bychen_19851208:------------------------------------------------------------------------------
一. 参照前面两篇文章在Ubuntu上下载、编译和安装Android最新源代码和在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)准备好Android内核驱动程序开发环境。
------------------------------------------------------------------------------
-
9楼
navycsu 2011-07-28 22:38发表 [回复]
-
楼主,有个问题,内核make的时候提示:hello_val_show, hello_val_store
declare static,but never defined!
把定义该变量的语句放前面后不报错了
之后又说proc_dir_entry没有owner这个变量,然后把
entry->owner = THIS_MODULE;注释掉后,编译通过。不知道会有什么影响...
-
8楼
hui05504 2011-07-28 20:30发表 [回复]
-
回复hui05504:你的模拟器内核是不是把这篇文章所说的驱动程序编译进去了?如果界面是一个黑窗口的话?估计是驱动程序哪个地方有问题了。你可以试一下把驱动程序编译成可加载模块,等模拟器跑起来之后,再通过adb push命令把主机上的驱动模块上传到模拟器中,然后再用insmod命令来加载,这样就可以一步步调试,找出问题。
---谢谢,驱动我编译进去了,没有出现黑窗口,emulator好像就是起不来,奇怪,我用的是英码开发板的代码,都编译通过并且可以在板子上跑了,但是最近想试试模拟器,来调下HAL:)
-
7楼
hui05504 2011-07-28 15:51发表 [回复]
- 楼主,有个问题,就是我运行了emulator后,运行adb shell命令提示device off,运行了好几次都是这个错误,看了任务管理器,发现emulator启动了,但是sleep状态,可以指导下么
-
6楼
asdadasdasd111 2011-07-28 11:35发表 [回复]
- 对于毫无C++经验的人来说,楼主能否给点建议,不胜感激
-
3楼
vlone836 2011-07-16 14:45发表 [回复]
-
再加入hello驱动重新编译内核时,出现以下错误drivers/hello/hello.c : file not recognized: File format not recognized
是什么原因造成的?-
Re:
罗升阳 2011-07-16 15:12发表 [回复]
-
回复vlone836:不好意思,我这里有一处笔误,Makefile内容应该是:
obj-$(CONFIG_HELLO) += hello.o
不是hello.c-
Re:
guidian103 2012-02-16 13:40发表 [回复]
-
回复Luoshengyang:
drivers/hello/hello.c: In function 'hello_create_proc':
drivers/hello/hello.c:204: error: 'struct proc_dir_entry' has no member named 'owner'
drivers/hello/hello.c: In function '__hello_setup_dev':
drivers/hello/hello.c:233: error: implicit declaration of function 'init_MUTEX'
是不是那个头文件没有添加?
-
1楼
zhuanghuahui 2011-07-09 09:22发表 [回复]
- 非常好的android字符驱动入门
更多推荐
所有评论(0)