Android驱动开发-第一个安卓驱动程序
程序员文章站
2022-03-11 16:29:13
1.驱动程序frist_driver.c#include #include static int __init first_drv_init(void){ printk("first_drv_init\n"); return 0;}static void __exit first_drv_exit(void){ printk("first_drv_exit\n");} m...
1.驱动程序
frist_driver.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define HELLOON 1
#define HELLOOFF 0
#define HELLO_CNT 1
#define HELLO_NAME "hello driver"
static char readbuf[100];
static char writebuf[100];
static char kerneldata[] = {"hello my first driver"};
static char mybuf[100] ="1234";
struct hello_driver
{
dev_t devid; /*设备号*/
struct cdev cdev; /*cdev*/
struct class *class; /*类*/
struct device *device; /*设备*/
int major; /*主设备号*/
int minor; /*次设备号*/
atomic_t atomic_lock; /*原子变量*/
};
struct hello_driver hello_driver_dev;
static ssize_t show_my_device(struct device *dev,struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", mybuf);
}
static ssize_t set_my_device(struct device *dev,struct device_attribute *attr, const char *buf, size_t len)//echo命令时,将会调用该函数
{
sprintf(mybuf, "%s", buf);
return len;
}
static DEVICE_ATTR(my_device_test, S_IWUSR|S_IRUSR, show_my_device, set_my_device);
//定义一个名字为my_device_test的设备属性文件
static int hello_driver_open(struct inode *inode, struct file *filp)
{
if(!atomic_dec_and_test(&hello_driver_dev.atomic_lock))
{
atomic_inc(&hello_driver_dev.atomic_lock);
return -EBUSY;
}
filp->private_data = &hello_driver_dev;
return 0;
}
static ssize_t hello_driver_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
int ret = 0;
memcpy(readbuf,kerneldata,sizeof(kerneldata));
ret = copy_to_user(buf,readbuf,cnt);
if(ret == 0)
{
printk("kernel senddata ok!\n");
}else
{
printk("kernel senddata failed\n");
}
return 0;
}
static ssize_t hello_driver_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int ret = 0;
ret = copy_from_user(writebuf,buf,cnt);
if(ret == 0)
{
printk("kernel recvdata %s\n",writebuf);
}else
{
printk("kernel recvdata failed\n");
}
return 0;
}
static long hello_driver_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case HELLOON:
printk("Open hello driver\n");
break;
case HELLOOFF:
printk("Close hello driver\n");
break;
default:
break;
}
return 0;
}
static int hello_driver_release(struct inode *inode, struct file *filp)
{
struct hello_driver *dev = filp->private_data;
atomic_inc(&dev->atomic_lock);
return 0;
}
static struct file_operations hello_driver_fops= {
.owner = THIS_MODULE,
.open = hello_driver_open,
.read = hello_driver_read,
.write = hello_driver_write,
.unlocked_ioctl = hello_driver_unlocked_ioctl,
.release = hello_driver_release,
};
static int __init hello_driver_init(void)
{
int ret;
/*1.设置原子变量,保证同一时刻只能有一个应用程序使用该驱动*/
atomic_set(&hello_driver_dev.atomic_lock,1);
/*2.分配设备号*/
/*2.1 之前分配了主设备号*/
if(hello_driver_dev.major)
{
/*注册设备号*/
hello_driver_dev.devid = MKDEV(hello_driver_dev.major,0);
ret = register_chrdev_region(hello_driver_dev.devid, HELLO_CNT, HELLO_NAME);
if(ret < 0)
{
printk("can't register major\n");
return ret;
}
}else/*2.2 之前未分配设备号,向内核申请设备号*/
{
alloc_chrdev_region(&hello_driver_dev.devid, 0, HELLO_CNT, HELLO_NAME);
}
printk(KERN_ERR"hello_driver_dev major = %d, minor = %d\n", hello_driver_dev.major,
hello_driver_dev.minor);
hello_driver_dev.cdev.owner = THIS_MODULE;
cdev_init(&hello_driver_dev.cdev,&hello_driver_fops);
ret = cdev_add(&hello_driver_dev.cdev, hello_driver_dev.devid,HELLO_CNT);
if(ret)
{
printk("Error cdev_add\n");
goto fail_to_cdev_add;
}
hello_driver_dev.class = class_create(THIS_MODULE,HELLO_NAME);
if(IS_ERR(hello_driver_dev.class))
{
goto fail_to_class_create;
}
hello_driver_dev.device = device_create(hello_driver_dev.class , NULL, hello_driver_dev.devid, NULL, HELLO_NAME);
if(IS_ERR(hello_driver_dev.device))
{
goto fail_to_device_create;
}
if(sysfs_create_file(&hello_driver_dev.device ->kobj), &dev_attr_my_device_test.attr))
{
//在mytest_device设备目录下创建一个my_device_test属性文件
return -1;
}
return 0;
fail_to_cdev_add:
unregister_chrdev_region(hello_driver_dev.devid, HELLO_CNT);
return -1;
fail_to_class_create:
cdev_del(&hello_driver_dev.cdev);
unregister_chrdev_region(hello_driver_dev.devid, HELLO_CNT);
return -1;
fail_to_device_create:
cdev_del(&hello_driver_dev.cdev);
unregister_chrdev_region(hello_driver_dev.devid, HELLO_CNT);
class_destroy(hello_driver_dev.class);
return -1;
}
static void __exit hello_driver_exit(void)
{
cdev_del(&hello_driver_dev.cdev);
unregister_chrdev_region(hello_driver_dev.devid, HELLO_CNT);
device_destroy(hello_driver_dev.class, hello_driver_dev.devid);
class_destroy(hello_driver_dev.class);
}
module_init(hello_driver_init);
module_exit(hello_driver_exit);
MODULE_DESCRIPTION("my hello driver");
MODULE_AUTHOR("Kong Lingze");
MODULE_LICENSE("GPL");
2.加载驱动程序编译到内核
添加文件夹
在kernel/driver目录下添加新的文件夹frist_driver,在frist_driver中添加文件Kconfig,Makefile,frist_driver.c
frist_driver/Kconfig中的内容:
frist_driver/Makefile中的内容:
在driver/Kconfig添加内容:
在driver/Makefile添加内容:
- 在kernel/driver下执行make menuconfig,选择First Android Driver
- 在安卓源码目录目录下source build/envsetup.sh
- lunch xx xxxx (可选择)
- make bootimage -j32
测试:
执行fastboot flash boot boot.img将内核烧写到开发板,在开发板目录找到sys/class/hello driver/hello driver或者下图目录,执行如图的命令
测试成功
3.用c程序进行测试
首先在android源码的packages目录下新建一个helloapp目录,该目录下新建hello_app.c和Android.mk两个文件。
hello_app.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#define READ 3
#define WRITE 4
#define HELLO_ON 1
#define HELLO_OFF 0
// ./app /dev/hello\driver <cmd>
static unsigned char cUserData[] = {"User data"};
int main(int argc, char **argv)
{
int iFd;
int iRet;
char *cFilename;
unsigned int arg = 0;
unsigned char cReadBuf[100];
unsigned char cWriteBuf[100];
if(argc!=3)
{
Printf(“Usage:%s <file inode> <cmd>”,argv[0]);
}
//打开设备结点
cFilename = argv[1];
iFd = open(cFilename, O_RDWR);
if(iFd < 0)
{
printf(" open %s failed\n", cFilename);
return -1;
}
/*读取驱动中的数据*/
if(atoi(argv[2]) == READ)
{
memset(cReadBuf,sizeof(cReadBuf),sizeof(cReadBuf));
iRet = read(iFd,cReadBuf,sizeof(cReadBuf));
if(iRet < 0)
{
printf("read %s data failed\n",cFilename);
return -1;
}else
{
printf("read data is:%s\n",cReadBuf);
}
}else if(atoi(argv[2]) == WRITE)//向驱动中写数据
{
memset(cWriteBuf,sizeof(cWriteBuf),sizeof(cWriteBuf));
memcpy(cWriteBuf,cUserData,sizeof(cUserData));
iRet = write(iFd,cWriteBuf,sizeof(cWriteBuf));
if(iRet < 0)
{
printf("write %s data failed\n",cFilename);
return -1;
}
}else if(atoi(argv[2]) == HELLO_ON)//给驱动发送HELLO_ON命令
{
ioctl(iFd,HELLO_ON,arg);
}else if(atoi(argv[2]) == HELLO_OFF)//给驱动发送HELLO_OFF命令
{
ioctl(iFd,HELLO_OFF,arg);
}
iRet = close(iFd);
if(iFd < 0)
{
printf("close %s failed",cFilename);
return -1;
}
return 0;
}
Andoird.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := hellotest
LOCAL_SRC_FILES := $(call all-subdir-c-files)
include $(BUILD_EXECUTABLE)
编译
完成之后在安卓源码目录,输入source build\envser.up.sh,再进入packages/helloapp目录执行mm命令,生成可执行文件,编译后的文件在out/target/product/xxx/obj/EXECUTABLES/hellotapp_intermediates/中
测试
adb shell
adb push hello_app /data把hello_app推送到android设备的data目录下,
chmod +x helloapp添加可执行权限。
执行./helloapp /dev/hello driver 1
打印如下:
Open hello driver
可见测试成功。
本文地址:https://blog.csdn.net/weixin_43824344/article/details/107915758
上一篇: 工作零散知识点
下一篇: linux——ln建立连接档
推荐阅读
-
安卓开发环境搭建过程,android开发环境是什么
-
安卓开发环境搭建过程,android开发环境是什么
-
使用Win10+Android+夜神安卓模拟器,搭建ReactNative开发环境
-
安卓开发环境配置有哪些方法,android开发环境的搭建步骤
-
安卓开发环境配置有哪些方法,android开发环境的搭建步骤
-
最新版安卓应用(android)开发环境搭建图解教程(带Andriod NDK)
-
搭建Android开发环境 以及 ionic 编译安卓app步骤
-
安卓开发笔记(三十三):Android仿写微信发现
-
最新版安卓应用(android)开发环境搭建图解教程(带Andriod NDK)
-
Android开发教程—安卓四大组件解析