Android 驱动跟系统开发 1. 一个简单的例子
2012-11-09 01:39
926 查看
http://blog.csdn.net/zhangjie201412/article/details/7703855
首先,边学习边记录点自己的代码,希望看了我写的代码觉得不怎么样的,多多提出来,让我也学习学习,我一定会虚心接受大家的指导。
这里我们是来学习android 驱动和android系统框架的,这里我只针对于整个android设备驱动的一个流程,从上到下的调用,而且在这里我们去使用android源码环境,原因是我使用的电脑比较破,编译android会挂,而且android BSP太大了,git下来很麻烦,所以这里我只是选用了ubuntu的环境来学习android 底层和系统层的开发,那么有人会问,没有源代码,如何去学习呢,又如何来演示出来呢?不急,慢慢道来,首先还是来谈一下android的底层和系统层,下图供参考,基本每个设计android的工程师都知道这张图
![](http://my.csdn.net/uploads/201207/02/1341207543_3158.gif)
android使用的是Linux 内核,虽然说稍微改了点东西,增加了些移动嵌入式设备的特性,比如说early suspend、进程间通信(bind)、特有的log机制(logcat)等,但是Linux主流的一些东西都没有改变,所以,这里我们还是使用Linux下得驱动作为底层来学习,具体的android的特性,之后的博客中会做深入。
Linux内核驱动之上应该是android的HAL层,也就是传说中得硬件抽象层,我把这玩意一直理解成是Linux 应用层,虽然,有的厂家的代码写的比较庞大,比较好得还是使用C++的类来封装,典型的设备是传感器模块,一般都会有一个HAL层来衔接,这里我们使用Linux 的应用层编程 c/c++来实现调用驱动来收发数据等操作。
在上面应该是JNI层啦,在我们的学习中,JNI的基础知识在我的另外一个博客专栏中有提到,在这里我们也是使用JNI来实现接口。
然后是framework,我们还是使用java代码封装JNI,然后写一些java的测试代码,当然了,没有android的UI,对于java的UI编程,我也是没玩过,对于java我只是一个初学者,写测试代码还凑合,一般都是一边google一边写的 ^0^
接下来就开始行动吧,首先是我们的驱动部分,这些代码都是我自己写的,所以难免会有很多写的不对的地方,希望大家觉得我哪边写的不好的多提些意见,毕竟我也只是一个小菜鸟。
这个驱动完成的主要任务是从内核空间向用户空间发送一个坐标信息(模拟鼠标的动作),当然了,我们的驱动是虚拟的,当然不会主动的向用户空间poll数据,所以,我们要先自己往文件系统中写数据,然后驱动会通过input 子系统向user space发送数据。
下面是我驱动的一个结构图,一般我写个驱动都会先考虑很多,然后再着手去做,三思而后行嘛,驱动的整体架构如果出了问题,到最后是很难再修正的,只有重新写。
![](http://my.csdn.net/uploads/201207/03/1341301015_4761.jpg)
可以看到,我们的思路很清晰,初始化的时候开一个线程,注意这个线程是一个死循环,但是在循环当中有一个试图获得信号量的动作,如果得不到,就会进入休眠,如下是thread的代码:
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">static
int work_thread(void *data)
{
int x, y, ret;
struct virtual_dev *pvdev = (struct virtual_dev *)data;
struct semaphore sema = pvdev->sem;
// poll the data into user space
printk(KERN_INFO "work thread running!!");
while(pvdev->running) {
do{
ret = down_interruptible(&sema);
} while(ret == -EINTR);
//printk("done!\n");
//poll the x and y data into user space
x = pvdev->x;
y = pvdev->y;
input_report_abs(pvdev->input, ABS_X, x);
input_report_abs(pvdev->input, ABS_Y, y);
input_sync(pvdev->input);
printk("position: %d | %d\n", x, y);
}
return 0;
}</span>
唤醒这个线程的地方,就是调用up的地方:
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">static ssize_t write_position(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
vdev->x = x;
vdev->y = y;
//do something with x and y ===> poll the data;
up(&vdev->sem);
return count;
}</span>
可以看到,这个write_position是被注册当position文件被执行写操作的时候执行的。
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">/* attach the sysfs */
DEVICE_ATTR(position, 0666, read_position, write_position);
DEVICE_ATTR(color, 0666, read_color, write_color);
DEVICE_ATTR(bcolor, 0666, read_bcolor, write_bcolor);</span>
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">/*
* This driver is named virtual touch, which can send some message into user space from kernel space,
* for this driver just for study Linux device driver...
* Jay Zhang
* mail: zhangjie201412@live.com
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/hwmon.h>
#include <linux/kthread.h>
#include <linux/platform_device.h>
#include <linux/semaphore.h>
#include <linux/slab.h>
struct virtual_dev {
struct platform_device *vt_dev;
struct task_struct *run_thread;
struct input_dev *input;
struct semaphore sem;
int x,y;
//point position
int color; //line color
int bcolor;
//background color
int size; //line size
int running;
};
struct virtual_dev *vdev = NULL;
/* position read/write function */
static ssize_t read_position (struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "(%d, %d)\n", vdev->x, vdev->y);
}
static ssize_t write_position(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
vdev->x = x;
vdev->y = y;
//do something with x and y ===> poll the data;
up(&vdev->sem);
return count;
}
/* color read/write function */
static ssize_t read_color(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf,
"line color is %d\n", vdev->color);
}
static ssize_t write_color(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int color;
sscanf(buffer, "%d", &color);
vdev->color = color;
return count;
}
/* bcolor read/write function */
static ssize_t read_bcolor(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf,
"background color is %d\n", vdev->bcolor);
}
static ssize_t write_bcolor(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int bcolor;
sscanf(buffer, "%d", &bcolor);
vdev->bcolor = bcolor;
return count;
}
/* attach the sysfs */
DEVICE_ATTR(position, 0666, read_position, write_position);
DEVICE_ATTR(color, 0666, read_color, write_color);
DEVICE_ATTR(bcolor, 0666, read_bcolor, write_bcolor);
//DEVICE_ATTR(size, 0666, read_size, write_size);
/* attribute description */
static struct attribute *vdev_attrs[] = {
&dev_attr_position.attr,
&dev_attr_color.attr,
&dev_attr_bcolor.attr,
// &dev_attr,size,
NULL
};
/* attribute group */
static struct attribute_group vdev_attr_group = {
.attrs = vdev_attrs,
};
static int work_thread(void *data)
{
int x, y, ret;
struct virtual_dev *pvdev = (struct virtual_dev *)data;
struct semaphore sema = pvdev->sem;
// poll the data into user space
printk(KERN_INFO "work thread running!!");
while(pvdev->running) {
do{
ret = down_interruptible(&sema);
} while(ret == -EINTR);
//printk("done!\n");
//poll the x and y data into user space
x = pvdev->x;
y = pvdev->y;
input_report_abs(pvdev->input, ABS_X, x);
input_report_abs(pvdev->input, ABS_Y, y);
input_sync(pvdev->input);
printk("position: %d | %d\n", x, y);
}
return 0;
}
/*
static int virtual_probe(struct platform_device *pdev)
{
int ret;
//malloc for vdev
vdev = kzalloc(sizeof(struct virtual_dev), GFP_KERNEL);
if(!vdev) {
vdev = NULL;
printk(KERN_INFO "kzalloc for vdev failed.\n");
ret = -ENOMEM;
goto kzalloc_failed;
}
//initialized for semaphore
sema_init(&(vdev->sem), 0);
//initialized for input subsystem
vdev->input = input_allocate_device();
if(!(vdev->input)) {
vdev->input = NULL;
printk(KERN_INFO "allocate input device failed.\n");
ret = -ENOMEM;
goto allocate_input_failed;
}
set_bit(EV_ABS, vdev->input->evbit);
//for x
input_set_abs_params(vdev->input, ABS_X, -1024, 1024, 0, 0);
//for y
input_set_abs_params(vdev->input, ABS_Y, -1024, 1024, 0, 0);
//set name
vdev->input->name = "virtual-touch";
ret = input_register_device(vdev->input);
if(ret) {
printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, vdev->input->name);
goto input_register_failed;
//return ret;
}
//initialized for sysfs of our virtual driver
vdev->vt_dev = pdev;
sysfs_create_group(&vdev->vt_dev->dev.kobj, &vdev_attr_group);
//run thread to poll data
vdev->run_thread = kthread_run(work_thread, vdev, "vt_thread");
vdev->running = 1;
platform_set_drvdata(pdev, vdev);
printk(KERN_INFO "virtual touch device probe successful.\n");
return 0;
input_register_failed:
input_free_device(vdev->input);
allocate_input_failed:
kfree(vdev);
kzalloc_failed:
return ret;
}
static struct platform_driver virtual_driver = {
.probe = virtual_probe,
.driver = {
.name = "virtual touch",
},
};
*/
static int virtual_init(void)
{
int ret;
//malloc for vdev
vdev = kzalloc(sizeof(struct virtual_dev), GFP_KERNEL);
if(!vdev) {
vdev = NULL;
printk(KERN_INFO "kzalloc for vdev failed.\n");
ret = -ENOMEM;
goto kzalloc_failed;
}
//register a platform device
vdev->vt_dev = platform_device_register_simple("virtual-touch", -1, NULL, 0);
if(IS_ERR(vdev->vt_dev)) {
PTR_ERR(vdev->vt_dev);
printk("register device failed.\n");
}
//initialized for semaphore
sema_init(&(vdev->sem), 0);
//initialized for input subsystem
vdev->input = input_allocate_device();
if(!(vdev->input)) {
vdev->input = NULL;
printk(KERN_INFO "allocate input device failed.\n");
ret = -ENOMEM;
goto allocate_input_failed;
}
set_bit(EV_ABS, vdev->input->evbit);
//for x
input_set_abs_params(vdev->input, ABS_X, -1024, 1024, 0, 0);
//for y
input_set_abs_params(vdev->input, ABS_Y, -1024, 1024, 0, 0);
//set name
vdev->input->name = "virtual-touch";
ret = input_register_device(vdev->input);
if(ret) {
printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, vdev->input->name);
goto input_register_failed;
//return ret;
}
//initialized for sysfs of our virtual driver
// vdev->vt_dev = pdev;
sysfs_create_group(&vdev->vt_dev->dev.kobj, &vdev_attr_group);
//run thread to poll data
vdev->run_thread = kthread_run(work_thread, vdev,
"vt_thread");
vdev->running = 1;
// platform_set_drvdata(pdev, vdev);
printk(KERN_INFO "virtual touch device probe successful.\n");
return 0;
input_register_failed:
input_free_device(vdev->input);
allocate_input_failed:
kfree(vdev);
kzalloc_failed:
return ret;
}
static void virtual_exit(void)
{
vdev->running = 0;
sysfs_remove_group(&(vdev->vt_dev->dev.kobj), &vdev_attr_group);
input_unregister_device(vdev->input);
platform_device_unregister(vdev->vt_dev);
}
module_init(virtual_init);
module_exit(virtual_exit);
MODULE_LICENSE("GPL");</span>
下面是Makefile
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">obj-m := virtualtouch.o
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
clean:
rm *.o *.ko *.mod.c *.symvers modules.order</span>
然后我们来编译模块再加载
# make
# insmod virtualtouch.ko
然后看下我们生成的文件系统
root@jay-Vbox:/sys/devices/platform/virtual-touch# pwd
/sys/devices/platform/virtual-touch
root@jay-Vbox:/sys/devices/platform/virtual-touch# tree
.
├── bcolor
├── color
├── modalias
├── position
├── power
│ ├── async
│ ├── autosuspend_delay_ms
│ ├── control
│ ├── runtime_active_kids
│ ├── runtime_active_time
│ ├── runtime_enabled
│ ├── runtime_status
│ ├── runtime_suspended_time
│ └── runtime_usage
├── subsystem -> ../../../bus/platform
└── uevent
2 directories, 14 files
还有我们的input subsystem的文件系统,使用dmesg查看
[ 413.650710] input: virtual-touch as /devices/virtual/input/input6
[ 413.662695] virtual touch device probe successful.
[ 413.663616] work thread running!!
按照log可以知道,我们生成的event6
root@jay-Vbox:/dev/input# pwd
/dev/input
root@jay-Vbox:/dev/input# ls -l event6
crw-r----- 1 root root 13, 70 Jul 2 22:07 event6
OK,了解了我们生成的文件系统之后,我们写一个测试程序来测试下,嘿嘿 ^0^
贴代码如下:
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>
int main(void)
{
struct input_event ev_temp;
int fd = open("/dev/input/event6", O_RDWR);
if(fd < 0) {
printf("open device failed.\n");
return 0;
}
printf("open done!\n");
//return 0;
int count, x, y;
while(1) {
printf("read!\n");
count = read(fd, &ev_temp, sizeof(struct input_event)) ;
if(EV_ABS == ev_temp.type) {
if(ev_temp.code == ABS_X)
x = ev_temp.value;
else
if(ev_temp.code == ABS_Y)
y = ev_temp.value;
printf("position : (%d, %d)\n", x, y);
} else if(EV_SYN == ev_temp.type) {
printf("sync!\n");
}
}
return 0;
}</span>
这个。。。这个小测试程序就不多说了,open ----> read ----> show
测试程序的编写一般是参考驱动中report出去的到底是什么类型的数据。
# gcc main -o virtual-touch.c
root@jay-Vbox:/home/jay/workspace/virtual/main# ./main
open done!
read!
这个时候被阻塞在read函数这边,因为没有数据被读出,所以会阻塞在那边得不到返回,当然了,我们也可以使用非阻塞的去读(open的时候标志设置成 | NOBLOCK),接着接着,咱们来出发input 设备
root@jay-Vbox:/home/jay/workspace/virtual/main# echo 1 2 > /sys/devices/platform/virtual-touch/position
root@jay-Vbox:/home/jay/workspace/virtual/main# position : (1, 32767)
read!
position : (1, 2)
read!
sync!
read!
看到没,看到没,数据已经打印出来了,具体的流程大家可以自己分析驱动代码,最主要的还是那张驱动架构图。
好了,现在,我们来写一个jni来封装下read函数
。。。等等,咱们还是先看我们的java代码,一般jni是提供接口的,但是接口到底是怎么样的还是取决于java中的需要。
这里我写了一个class来封装open,read等函数。
GetPosition.java
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">class GetPosition
{
private int x;
private int y;
private native
int readEvent();
private native void openEvent(String path);
private native
void closeEvent();
GetPosition(String path) {
x = 0;
y = 0;
openEvent(path);
}
public void close()
{
closeEvent();
}
public void setXY(int x,
int y) {
this.x = x;
this.y = y;
}
public int getX()
{
return this.x;
}
public int getY()
{
return this.y;
}
public void read()
{
int retVal = readEvent();
setXY(retVal/256, retVal%256);
}
static {
System.loadLibrary("virtouch");
}
}</span>
我承认,我写的java代码很烂,好吧,咱不多看了,只要看这里的native函数,这里封装了open、read、close函数,
好,然后咱们使用javah来生成jni的头文件。
# javah -jni GetPosition
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class GetPosition */
#ifndef _Included_GetPosition
#define _Included_GetPosition
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: GetPosition
* Method: readEvent
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_GetPosition_readEvent
(JNIEnv *, jobject);
/*
* Class: GetPosition
* Method: openEvent
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_GetPosition_openEvent
(JNIEnv *, jobject, jstring);
/*
* Class: GetPosition
* Method: closeEvent
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_GetPosition_closeEvent
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif</span>
然后我们按照这个头文件来完成我们的jni
virtual-touch.c
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">#include <stdio.h>
#include "GetPosition.h"
#include <stdlib.h>
#include <linux/input.h>
#include <fcntl.h>
int fd;
JNIEXPORT jint JNICALL
Java_GetPosition_readEvent(JNIEnv *env, jobject obj)
{
static int x, y;
int count;
struct input_event ev_temp;
count = read(fd, &ev_temp, sizeof(struct input_event));
//AGAIN:
if(EV_ABS == ev_temp.type) {
if(ev_temp.code == ABS_X) {
x = ev_temp.value;
} else if(ev_temp.code == ABS_Y) {
y = ev_temp.value;
}
printf("x: %d, y: %d\n", x, y);
}
//else if(EV_SYN == ev_temp.type) {
return (x*256 + y);
//}
//goto AGAIN;
}
JNIEXPORT void JNICALL
Java_GetPosition_openEvent(JNIEnv *env, jobject obj, jstring prompt)
{
char path[64];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if(str == NULL) {
printf("error: str is NULL!\n");
return ;
}
sprintf(path, "%s", str);
fd = open(path, O_RDWR);
if(fd < 0) {
printf("open %s failed...\n", path);
}
(*env)->ReleaseStringUTFChars(env, prompt, str);
}
JNIEXPORT void JNICALL
Java_GetPosition_closeEvent(JNIEnv *env, jobject obj)
{
close(fd);
}</span>
jni的基础知识,大家可以参考我的一个博客专栏,嘻嘻~~~打广告了
http://blog.csdn.net/column/details/jnijni.html
用命令来生成动态库
这里给大家提供一个shell脚本来使用
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">#/bin/bash
if [ $# != 2 ]
then
echo "input argument error!"
else
cc -I /usr/lib/jvm/java-6-sun/include/linux -I /usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o $1lib$2.so $2.c
fi
</span>
好了,最后是我们的java测试程序
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">class Test {
// private native int openEvent(String path);
// private native int closeEvent();
// private int getPosition();
public static
void main(String[] args)
{
GetPosition getPosition = new GetPosition("/dev/input/event5");
//openEvent("/dev/input/event5");
while(true) {
getPosition.read();
System.out.println("[ " + getPosition.getX() +
" , " + getPosition.getY() + "]");
}
//getPosition.close();
//System.out.println()
}
/*
static {
System.loadLibrary("virtouch");
}
*/
}</span>
继续测试下
可以得到跟之前一样的结果。
OK,现在我们可以再Linux下学习 Linux 驱动还有jni了。
参考:
在Linux下如何使用GCC编译程序、简单生成静态库及动态库。
http://blog.csdn.net/clozxy/article/details/5716227
首先,边学习边记录点自己的代码,希望看了我写的代码觉得不怎么样的,多多提出来,让我也学习学习,我一定会虚心接受大家的指导。
这里我们是来学习android 驱动和android系统框架的,这里我只针对于整个android设备驱动的一个流程,从上到下的调用,而且在这里我们去使用android源码环境,原因是我使用的电脑比较破,编译android会挂,而且android BSP太大了,git下来很麻烦,所以这里我只是选用了ubuntu的环境来学习android 底层和系统层的开发,那么有人会问,没有源代码,如何去学习呢,又如何来演示出来呢?不急,慢慢道来,首先还是来谈一下android的底层和系统层,下图供参考,基本每个设计android的工程师都知道这张图
![](http://my.csdn.net/uploads/201207/02/1341207543_3158.gif)
android使用的是Linux 内核,虽然说稍微改了点东西,增加了些移动嵌入式设备的特性,比如说early suspend、进程间通信(bind)、特有的log机制(logcat)等,但是Linux主流的一些东西都没有改变,所以,这里我们还是使用Linux下得驱动作为底层来学习,具体的android的特性,之后的博客中会做深入。
Linux内核驱动之上应该是android的HAL层,也就是传说中得硬件抽象层,我把这玩意一直理解成是Linux 应用层,虽然,有的厂家的代码写的比较庞大,比较好得还是使用C++的类来封装,典型的设备是传感器模块,一般都会有一个HAL层来衔接,这里我们使用Linux 的应用层编程 c/c++来实现调用驱动来收发数据等操作。
在上面应该是JNI层啦,在我们的学习中,JNI的基础知识在我的另外一个博客专栏中有提到,在这里我们也是使用JNI来实现接口。
然后是framework,我们还是使用java代码封装JNI,然后写一些java的测试代码,当然了,没有android的UI,对于java的UI编程,我也是没玩过,对于java我只是一个初学者,写测试代码还凑合,一般都是一边google一边写的 ^0^
接下来就开始行动吧,首先是我们的驱动部分,这些代码都是我自己写的,所以难免会有很多写的不对的地方,希望大家觉得我哪边写的不好的多提些意见,毕竟我也只是一个小菜鸟。
这个驱动完成的主要任务是从内核空间向用户空间发送一个坐标信息(模拟鼠标的动作),当然了,我们的驱动是虚拟的,当然不会主动的向用户空间poll数据,所以,我们要先自己往文件系统中写数据,然后驱动会通过input 子系统向user space发送数据。
下面是我驱动的一个结构图,一般我写个驱动都会先考虑很多,然后再着手去做,三思而后行嘛,驱动的整体架构如果出了问题,到最后是很难再修正的,只有重新写。
![](http://my.csdn.net/uploads/201207/03/1341301015_4761.jpg)
可以看到,我们的思路很清晰,初始化的时候开一个线程,注意这个线程是一个死循环,但是在循环当中有一个试图获得信号量的动作,如果得不到,就会进入休眠,如下是thread的代码:
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">static
int work_thread(void *data)
{
int x, y, ret;
struct virtual_dev *pvdev = (struct virtual_dev *)data;
struct semaphore sema = pvdev->sem;
// poll the data into user space
printk(KERN_INFO "work thread running!!");
while(pvdev->running) {
do{
ret = down_interruptible(&sema);
} while(ret == -EINTR);
//printk("done!\n");
//poll the x and y data into user space
x = pvdev->x;
y = pvdev->y;
input_report_abs(pvdev->input, ABS_X, x);
input_report_abs(pvdev->input, ABS_Y, y);
input_sync(pvdev->input);
printk("position: %d | %d\n", x, y);
}
return 0;
}</span>
static int work_thread(void *data) { int x, y, ret; struct virtual_dev *pvdev = (struct virtual_dev *)data; struct semaphore sema = pvdev->sem; // poll the data into user space printk(KERN_INFO "work thread running!!"); while(pvdev->running) { do{ ret = down_interruptible(&sema); } while(ret == -EINTR); //printk("done!\n"); //poll the x and y data into user space x = pvdev->x; y = pvdev->y; input_report_abs(pvdev->input, ABS_X, x); input_report_abs(pvdev->input, ABS_Y, y); input_sync(pvdev->input); printk("position: %d | %d\n", x, y); } return 0; }
唤醒这个线程的地方,就是调用up的地方:
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">static ssize_t write_position(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
vdev->x = x;
vdev->y = y;
//do something with x and y ===> poll the data;
up(&vdev->sem);
return count;
}</span>
static ssize_t write_position(struct device *dev, struct device_attribute *attr, const char *buffer, ssize_t count) { int x,y; sscanf(buffer, "%d%d", &x, &y); vdev->x = x; vdev->y = y; //do something with x and y ===> poll the data; up(&vdev->sem); return count; }
可以看到,这个write_position是被注册当position文件被执行写操作的时候执行的。
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">/* attach the sysfs */
DEVICE_ATTR(position, 0666, read_position, write_position);
DEVICE_ATTR(color, 0666, read_color, write_color);
DEVICE_ATTR(bcolor, 0666, read_bcolor, write_bcolor);</span>
/* attach the sysfs */ DEVICE_ATTR(position, 0666, read_position, write_position); DEVICE_ATTR(color, 0666, read_color, write_color); DEVICE_ATTR(bcolor, 0666, read_bcolor, write_bcolor);相信看了结构图就知道我们的代码是如何写的吧,这个驱动比较简单,看下完整的代码
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">/*
* This driver is named virtual touch, which can send some message into user space from kernel space,
* for this driver just for study Linux device driver...
* Jay Zhang
* mail: zhangjie201412@live.com
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/hwmon.h>
#include <linux/kthread.h>
#include <linux/platform_device.h>
#include <linux/semaphore.h>
#include <linux/slab.h>
struct virtual_dev {
struct platform_device *vt_dev;
struct task_struct *run_thread;
struct input_dev *input;
struct semaphore sem;
int x,y;
//point position
int color; //line color
int bcolor;
//background color
int size; //line size
int running;
};
struct virtual_dev *vdev = NULL;
/* position read/write function */
static ssize_t read_position (struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "(%d, %d)\n", vdev->x, vdev->y);
}
static ssize_t write_position(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int x,y;
sscanf(buffer, "%d%d", &x, &y);
vdev->x = x;
vdev->y = y;
//do something with x and y ===> poll the data;
up(&vdev->sem);
return count;
}
/* color read/write function */
static ssize_t read_color(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf,
"line color is %d\n", vdev->color);
}
static ssize_t write_color(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int color;
sscanf(buffer, "%d", &color);
vdev->color = color;
return count;
}
/* bcolor read/write function */
static ssize_t read_bcolor(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf,
"background color is %d\n", vdev->bcolor);
}
static ssize_t write_bcolor(struct device *dev,
struct device_attribute *attr,
const char *buffer, ssize_t count)
{
int bcolor;
sscanf(buffer, "%d", &bcolor);
vdev->bcolor = bcolor;
return count;
}
/* attach the sysfs */
DEVICE_ATTR(position, 0666, read_position, write_position);
DEVICE_ATTR(color, 0666, read_color, write_color);
DEVICE_ATTR(bcolor, 0666, read_bcolor, write_bcolor);
//DEVICE_ATTR(size, 0666, read_size, write_size);
/* attribute description */
static struct attribute *vdev_attrs[] = {
&dev_attr_position.attr,
&dev_attr_color.attr,
&dev_attr_bcolor.attr,
// &dev_attr,size,
NULL
};
/* attribute group */
static struct attribute_group vdev_attr_group = {
.attrs = vdev_attrs,
};
static int work_thread(void *data)
{
int x, y, ret;
struct virtual_dev *pvdev = (struct virtual_dev *)data;
struct semaphore sema = pvdev->sem;
// poll the data into user space
printk(KERN_INFO "work thread running!!");
while(pvdev->running) {
do{
ret = down_interruptible(&sema);
} while(ret == -EINTR);
//printk("done!\n");
//poll the x and y data into user space
x = pvdev->x;
y = pvdev->y;
input_report_abs(pvdev->input, ABS_X, x);
input_report_abs(pvdev->input, ABS_Y, y);
input_sync(pvdev->input);
printk("position: %d | %d\n", x, y);
}
return 0;
}
/*
static int virtual_probe(struct platform_device *pdev)
{
int ret;
//malloc for vdev
vdev = kzalloc(sizeof(struct virtual_dev), GFP_KERNEL);
if(!vdev) {
vdev = NULL;
printk(KERN_INFO "kzalloc for vdev failed.\n");
ret = -ENOMEM;
goto kzalloc_failed;
}
//initialized for semaphore
sema_init(&(vdev->sem), 0);
//initialized for input subsystem
vdev->input = input_allocate_device();
if(!(vdev->input)) {
vdev->input = NULL;
printk(KERN_INFO "allocate input device failed.\n");
ret = -ENOMEM;
goto allocate_input_failed;
}
set_bit(EV_ABS, vdev->input->evbit);
//for x
input_set_abs_params(vdev->input, ABS_X, -1024, 1024, 0, 0);
//for y
input_set_abs_params(vdev->input, ABS_Y, -1024, 1024, 0, 0);
//set name
vdev->input->name = "virtual-touch";
ret = input_register_device(vdev->input);
if(ret) {
printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, vdev->input->name);
goto input_register_failed;
//return ret;
}
//initialized for sysfs of our virtual driver
vdev->vt_dev = pdev;
sysfs_create_group(&vdev->vt_dev->dev.kobj, &vdev_attr_group);
//run thread to poll data
vdev->run_thread = kthread_run(work_thread, vdev, "vt_thread");
vdev->running = 1;
platform_set_drvdata(pdev, vdev);
printk(KERN_INFO "virtual touch device probe successful.\n");
return 0;
input_register_failed:
input_free_device(vdev->input);
allocate_input_failed:
kfree(vdev);
kzalloc_failed:
return ret;
}
static struct platform_driver virtual_driver = {
.probe = virtual_probe,
.driver = {
.name = "virtual touch",
},
};
*/
static int virtual_init(void)
{
int ret;
//malloc for vdev
vdev = kzalloc(sizeof(struct virtual_dev), GFP_KERNEL);
if(!vdev) {
vdev = NULL;
printk(KERN_INFO "kzalloc for vdev failed.\n");
ret = -ENOMEM;
goto kzalloc_failed;
}
//register a platform device
vdev->vt_dev = platform_device_register_simple("virtual-touch", -1, NULL, 0);
if(IS_ERR(vdev->vt_dev)) {
PTR_ERR(vdev->vt_dev);
printk("register device failed.\n");
}
//initialized for semaphore
sema_init(&(vdev->sem), 0);
//initialized for input subsystem
vdev->input = input_allocate_device();
if(!(vdev->input)) {
vdev->input = NULL;
printk(KERN_INFO "allocate input device failed.\n");
ret = -ENOMEM;
goto allocate_input_failed;
}
set_bit(EV_ABS, vdev->input->evbit);
//for x
input_set_abs_params(vdev->input, ABS_X, -1024, 1024, 0, 0);
//for y
input_set_abs_params(vdev->input, ABS_Y, -1024, 1024, 0, 0);
//set name
vdev->input->name = "virtual-touch";
ret = input_register_device(vdev->input);
if(ret) {
printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, vdev->input->name);
goto input_register_failed;
//return ret;
}
//initialized for sysfs of our virtual driver
// vdev->vt_dev = pdev;
sysfs_create_group(&vdev->vt_dev->dev.kobj, &vdev_attr_group);
//run thread to poll data
vdev->run_thread = kthread_run(work_thread, vdev,
"vt_thread");
vdev->running = 1;
// platform_set_drvdata(pdev, vdev);
printk(KERN_INFO "virtual touch device probe successful.\n");
return 0;
input_register_failed:
input_free_device(vdev->input);
allocate_input_failed:
kfree(vdev);
kzalloc_failed:
return ret;
}
static void virtual_exit(void)
{
vdev->running = 0;
sysfs_remove_group(&(vdev->vt_dev->dev.kobj), &vdev_attr_group);
input_unregister_device(vdev->input);
platform_device_unregister(vdev->vt_dev);
}
module_init(virtual_init);
module_exit(virtual_exit);
MODULE_LICENSE("GPL");</span>
/*
* This driver is named virtual touch, which can send some message into user space from kernel space,
* for this driver just for study Linux device driver...
* Jay Zhang
* mail: zhangjie201412@live.com
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/hwmon.h>
#include <linux/kthread.h>
#include <linux/platform_device.h>
#include <linux/semaphore.h>
#include <linux/slab.h>
struct virtual_dev {
struct platform_device *vt_dev;
struct task_struct *run_thread;
struct input_dev *input;
struct semaphore sem;
int x,y; //point position
int color; //line color
int bcolor; //background color
int size; //line size
int running;
};
struct virtual_dev *vdev = NULL;
/* position read/write function */
static ssize_t read_position (struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "(%d, %d)\n", vdev->x, vdev->y);
}
static ssize_t write_position(struct device *dev, struct device_attribute *attr, const char *buffer, ssize_t count) { int x,y; sscanf(buffer, "%d%d", &x, &y); vdev->x = x; vdev->y = y; //do something with x and y ===> poll the data; up(&vdev->sem); return count; }
/* color read/write function */
static ssize_t read_color(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "line color is %d\n", vdev->color);
}
static ssize_t write_color(struct device *dev,
struct device_attribute *attr, const char *buffer, ssize_t count)
{
int color;
sscanf(buffer, "%d", &color);
vdev->color = color;
return count;
}
/* bcolor read/write function */
static ssize_t read_bcolor(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "background color is %d\n", vdev->bcolor);
}
static ssize_t write_bcolor(struct device *dev,
struct device_attribute *attr, const char *buffer, ssize_t count)
{
int bcolor;
sscanf(buffer, "%d", &bcolor);
vdev->bcolor = bcolor;
return count;
}
/* attach the sysfs */ DEVICE_ATTR(position, 0666, read_position, write_position); DEVICE_ATTR(color, 0666, read_color, write_color); DEVICE_ATTR(bcolor, 0666, read_bcolor, write_bcolor);
//DEVICE_ATTR(size, 0666, read_size, write_size);
/* attribute description */
static struct attribute *vdev_attrs[] = {
&dev_attr_position.attr,
&dev_attr_color.attr,
&dev_attr_bcolor.attr,
// &dev_attr,size,
NULL
};
/* attribute group */
static struct attribute_group vdev_attr_group = {
.attrs = vdev_attrs,
};
static int work_thread(void *data) { int x, y, ret; struct virtual_dev *pvdev = (struct virtual_dev *)data; struct semaphore sema = pvdev->sem; // poll the data into user space printk(KERN_INFO "work thread running!!"); while(pvdev->running) { do{ ret = down_interruptible(&sema); } while(ret == -EINTR); //printk("done!\n"); //poll the x and y data into user space x = pvdev->x; y = pvdev->y; input_report_abs(pvdev->input, ABS_X, x); input_report_abs(pvdev->input, ABS_Y, y); input_sync(pvdev->input); printk("position: %d | %d\n", x, y); } return 0; }
/*
static int virtual_probe(struct platform_device *pdev)
{
int ret;
//malloc for vdev
vdev = kzalloc(sizeof(struct virtual_dev), GFP_KERNEL);
if(!vdev) {
vdev = NULL;
printk(KERN_INFO "kzalloc for vdev failed.\n");
ret = -ENOMEM;
goto kzalloc_failed;
}
//initialized for semaphore
sema_init(&(vdev->sem), 0);
//initialized for input subsystem
vdev->input = input_allocate_device();
if(!(vdev->input)) {
vdev->input = NULL;
printk(KERN_INFO "allocate input device failed.\n");
ret = -ENOMEM;
goto allocate_input_failed;
}
set_bit(EV_ABS, vdev->input->evbit);
//for x
input_set_abs_params(vdev->input, ABS_X, -1024, 1024, 0, 0);
//for y
input_set_abs_params(vdev->input, ABS_Y, -1024, 1024, 0, 0);
//set name
vdev->input->name = "virtual-touch";
ret = input_register_device(vdev->input);
if(ret) {
printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, vdev->input->name);
goto input_register_failed;
//return ret;
}
//initialized for sysfs of our virtual driver
vdev->vt_dev = pdev;
sysfs_create_group(&vdev->vt_dev->dev.kobj, &vdev_attr_group);
//run thread to poll data
vdev->run_thread = kthread_run(work_thread, vdev, "vt_thread");
vdev->running = 1;
platform_set_drvdata(pdev, vdev);
printk(KERN_INFO "virtual touch device probe successful.\n");
return 0;
input_register_failed:
input_free_device(vdev->input);
allocate_input_failed:
kfree(vdev);
kzalloc_failed:
return ret;
}
static struct platform_driver virtual_driver = {
.probe = virtual_probe,
.driver = {
.name = "virtual touch",
},
};
*/
static int virtual_init(void)
{
int ret;
//malloc for vdev
vdev = kzalloc(sizeof(struct virtual_dev), GFP_KERNEL);
if(!vdev) {
vdev = NULL;
printk(KERN_INFO "kzalloc for vdev failed.\n");
ret = -ENOMEM;
goto kzalloc_failed;
}
//register a platform device
vdev->vt_dev = platform_device_register_simple("virtual-touch", -1, NULL, 0);
if(IS_ERR(vdev->vt_dev)) {
PTR_ERR(vdev->vt_dev);
printk("register device failed.\n");
}
//initialized for semaphore
sema_init(&(vdev->sem), 0);
//initialized for input subsystem
vdev->input = input_allocate_device();
if(!(vdev->input)) {
vdev->input = NULL;
printk(KERN_INFO "allocate input device failed.\n");
ret = -ENOMEM;
goto allocate_input_failed;
}
set_bit(EV_ABS, vdev->input->evbit);
//for x
input_set_abs_params(vdev->input, ABS_X, -1024, 1024, 0, 0);
//for y
input_set_abs_params(vdev->input, ABS_Y, -1024, 1024, 0, 0);
//set name
vdev->input->name = "virtual-touch";
ret = input_register_device(vdev->input);
if(ret) {
printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, vdev->input->name);
goto input_register_failed;
//return ret;
}
//initialized for sysfs of our virtual driver
// vdev->vt_dev = pdev;
sysfs_create_group(&vdev->vt_dev->dev.kobj, &vdev_attr_group);
//run thread to poll data
vdev->run_thread = kthread_run(work_thread, vdev, "vt_thread");
vdev->running = 1;
// platform_set_drvdata(pdev, vdev);
printk(KERN_INFO "virtual touch device probe successful.\n");
return 0;
input_register_failed:
input_free_device(vdev->input);
allocate_input_failed:
kfree(vdev);
kzalloc_failed:
return ret;
}
static void virtual_exit(void)
{
vdev->running = 0;
sysfs_remove_group(&(vdev->vt_dev->dev.kobj), &vdev_attr_group);
input_unregister_device(vdev->input);
platform_device_unregister(vdev->vt_dev);
}
module_init(virtual_init);
module_exit(virtual_exit);
MODULE_LICENSE("GPL");
下面是Makefile
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">obj-m := virtualtouch.o
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
clean:
rm *.o *.ko *.mod.c *.symvers modules.order</span>
obj-m := virtualtouch.o KERNEL_DIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules clean: rm *.o *.ko *.mod.c *.symvers modules.order
然后我们来编译模块再加载
# make
# insmod virtualtouch.ko
然后看下我们生成的文件系统
root@jay-Vbox:/sys/devices/platform/virtual-touch# pwd
/sys/devices/platform/virtual-touch
root@jay-Vbox:/sys/devices/platform/virtual-touch# tree
.
├── bcolor
├── color
├── modalias
├── position
├── power
│ ├── async
│ ├── autosuspend_delay_ms
│ ├── control
│ ├── runtime_active_kids
│ ├── runtime_active_time
│ ├── runtime_enabled
│ ├── runtime_status
│ ├── runtime_suspended_time
│ └── runtime_usage
├── subsystem -> ../../../bus/platform
└── uevent
2 directories, 14 files
还有我们的input subsystem的文件系统,使用dmesg查看
[ 413.650710] input: virtual-touch as /devices/virtual/input/input6
[ 413.662695] virtual touch device probe successful.
[ 413.663616] work thread running!!
按照log可以知道,我们生成的event6
root@jay-Vbox:/dev/input# pwd
/dev/input
root@jay-Vbox:/dev/input# ls -l event6
crw-r----- 1 root root 13, 70 Jul 2 22:07 event6
OK,了解了我们生成的文件系统之后,我们写一个测试程序来测试下,嘿嘿 ^0^
贴代码如下:
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>
int main(void)
{
struct input_event ev_temp;
int fd = open("/dev/input/event6", O_RDWR);
if(fd < 0) {
printf("open device failed.\n");
return 0;
}
printf("open done!\n");
//return 0;
int count, x, y;
while(1) {
printf("read!\n");
count = read(fd, &ev_temp, sizeof(struct input_event)) ;
if(EV_ABS == ev_temp.type) {
if(ev_temp.code == ABS_X)
x = ev_temp.value;
else
if(ev_temp.code == ABS_Y)
y = ev_temp.value;
printf("position : (%d, %d)\n", x, y);
} else if(EV_SYN == ev_temp.type) {
printf("sync!\n");
}
}
return 0;
}</span>
include <stdlib.h> #include <fcntl.h> #include <linux/input.h> int main(void) { struct input_event ev_temp; int fd = open("/dev/input/event6", O_RDWR); if(fd < 0) { printf("open device failed.\n"); return 0; } printf("open done!\n"); //return 0; int count, x, y; while(1) { printf("read!\n"); count = read(fd, &ev_temp, sizeof(struct input_event)) ; if(EV_ABS == ev_temp.type) { if(ev_temp.code == ABS_X) x = ev_temp.value; else if(ev_temp.code == ABS_Y) y = ev_temp.value; printf("position : (%d, %d)\n", x, y); } else if(EV_SYN == ev_temp.type) { printf("sync!\n"); } } return 0; }
这个。。。这个小测试程序就不多说了,open ----> read ----> show
测试程序的编写一般是参考驱动中report出去的到底是什么类型的数据。
# gcc main -o virtual-touch.c
root@jay-Vbox:/home/jay/workspace/virtual/main# ./main
open done!
read!
这个时候被阻塞在read函数这边,因为没有数据被读出,所以会阻塞在那边得不到返回,当然了,我们也可以使用非阻塞的去读(open的时候标志设置成 | NOBLOCK),接着接着,咱们来出发input 设备
root@jay-Vbox:/home/jay/workspace/virtual/main# echo 1 2 > /sys/devices/platform/virtual-touch/position
root@jay-Vbox:/home/jay/workspace/virtual/main# position : (1, 32767)
read!
position : (1, 2)
read!
sync!
read!
看到没,看到没,数据已经打印出来了,具体的流程大家可以自己分析驱动代码,最主要的还是那张驱动架构图。
好了,现在,我们来写一个jni来封装下read函数
。。。等等,咱们还是先看我们的java代码,一般jni是提供接口的,但是接口到底是怎么样的还是取决于java中的需要。
这里我写了一个class来封装open,read等函数。
GetPosition.java
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">class GetPosition
{
private int x;
private int y;
private native
int readEvent();
private native void openEvent(String path);
private native
void closeEvent();
GetPosition(String path) {
x = 0;
y = 0;
openEvent(path);
}
public void close()
{
closeEvent();
}
public void setXY(int x,
int y) {
this.x = x;
this.y = y;
}
public int getX()
{
return this.x;
}
public int getY()
{
return this.y;
}
public void read()
{
int retVal = readEvent();
setXY(retVal/256, retVal%256);
}
static {
System.loadLibrary("virtouch");
}
}</span>
class GetPosition { private int x; private int y; private native int readEvent(); private native void openEvent(String path); private native void closeEvent(); GetPosition(String path) { x = 0; y = 0; openEvent(path); } public void close() { closeEvent(); } public void setXY(int x, int y) { this.x = x; this.y = y; } public int getX() { return this.x; } public int getY() { return this.y; } public void read() { int retVal = readEvent(); setXY(retVal/256, retVal%256); } static { System.loadLibrary("virtouch"); } }
我承认,我写的java代码很烂,好吧,咱不多看了,只要看这里的native函数,这里封装了open、read、close函数,
好,然后咱们使用javah来生成jni的头文件。
# javah -jni GetPosition
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class GetPosition */
#ifndef _Included_GetPosition
#define _Included_GetPosition
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: GetPosition
* Method: readEvent
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_GetPosition_readEvent
(JNIEnv *, jobject);
/*
* Class: GetPosition
* Method: openEvent
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_GetPosition_openEvent
(JNIEnv *, jobject, jstring);
/*
* Class: GetPosition
* Method: closeEvent
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_GetPosition_closeEvent
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif</span>
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class GetPosition */ #ifndef _Included_GetPosition #define _Included_GetPosition #ifdef __cplusplus extern "C" { #endif /* * Class: GetPosition * Method: readEvent * Signature: ()I */ JNIEXPORT jint JNICALL Java_GetPosition_readEvent (JNIEnv *, jobject); /* * Class: GetPosition * Method: openEvent * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_GetPosition_openEvent (JNIEnv *, jobject, jstring); /* * Class: GetPosition * Method: closeEvent * Signature: ()V */ JNIEXPORT void JNICALL Java_GetPosition_closeEvent (JNIEnv *, jobject); #ifdef __cplusplus } #endif
然后我们按照这个头文件来完成我们的jni
virtual-touch.c
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">#include <stdio.h>
#include "GetPosition.h"
#include <stdlib.h>
#include <linux/input.h>
#include <fcntl.h>
int fd;
JNIEXPORT jint JNICALL
Java_GetPosition_readEvent(JNIEnv *env, jobject obj)
{
static int x, y;
int count;
struct input_event ev_temp;
count = read(fd, &ev_temp, sizeof(struct input_event));
//AGAIN:
if(EV_ABS == ev_temp.type) {
if(ev_temp.code == ABS_X) {
x = ev_temp.value;
} else if(ev_temp.code == ABS_Y) {
y = ev_temp.value;
}
printf("x: %d, y: %d\n", x, y);
}
//else if(EV_SYN == ev_temp.type) {
return (x*256 + y);
//}
//goto AGAIN;
}
JNIEXPORT void JNICALL
Java_GetPosition_openEvent(JNIEnv *env, jobject obj, jstring prompt)
{
char path[64];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if(str == NULL) {
printf("error: str is NULL!\n");
return ;
}
sprintf(path, "%s", str);
fd = open(path, O_RDWR);
if(fd < 0) {
printf("open %s failed...\n", path);
}
(*env)->ReleaseStringUTFChars(env, prompt, str);
}
JNIEXPORT void JNICALL
Java_GetPosition_closeEvent(JNIEnv *env, jobject obj)
{
close(fd);
}</span>
#include <stdio.h> #include "GetPosition.h" #include <stdlib.h> #include <linux/input.h> #include <fcntl.h> int fd; JNIEXPORT jint JNICALL Java_GetPosition_readEvent(JNIEnv *env, jobject obj) { static int x, y; int count; struct input_event ev_temp; count = read(fd, &ev_temp, sizeof(struct input_event)); //AGAIN: if(EV_ABS == ev_temp.type) { if(ev_temp.code == ABS_X) { x = ev_temp.value; } else if(ev_temp.code == ABS_Y) { y = ev_temp.value; } printf("x: %d, y: %d\n", x, y); } //else if(EV_SYN == ev_temp.type) { return (x*256 + y); //} //goto AGAIN; } JNIEXPORT void JNICALL Java_GetPosition_openEvent(JNIEnv *env, jobject obj, jstring prompt) { char path[64]; const jbyte *str; str = (*env)->GetStringUTFChars(env, prompt, NULL); if(str == NULL) { printf("error: str is NULL!\n"); return ; } sprintf(path, "%s", str); fd = open(path, O_RDWR); if(fd < 0) { printf("open %s failed...\n", path); } (*env)->ReleaseStringUTFChars(env, prompt, str); } JNIEXPORT void JNICALL Java_GetPosition_closeEvent(JNIEnv *env, jobject obj) { close(fd); }
jni的基础知识,大家可以参考我的一个博客专栏,嘻嘻~~~打广告了
http://blog.csdn.net/column/details/jnijni.html
用命令来生成动态库
这里给大家提供一个shell脚本来使用
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">#/bin/bash
if [ $# != 2 ]
then
echo "input argument error!"
else
cc -I /usr/lib/jvm/java-6-sun/include/linux -I /usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o $1lib$2.so $2.c
fi
</span>
#/bin/bash if [ $# != 2 ] then echo "input argument error!" else cc -I /usr/lib/jvm/java-6-sun/include/linux -I /usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o $1lib$2.so $2.c fi
好了,最后是我们的java测试程序
[cpp]
view plaincopyprint?
<span style="font-size: 16px;">class Test {
// private native int openEvent(String path);
// private native int closeEvent();
// private int getPosition();
public static
void main(String[] args)
{
GetPosition getPosition = new GetPosition("/dev/input/event5");
//openEvent("/dev/input/event5");
while(true) {
getPosition.read();
System.out.println("[ " + getPosition.getX() +
" , " + getPosition.getY() + "]");
}
//getPosition.close();
//System.out.println()
}
/*
static {
System.loadLibrary("virtouch");
}
*/
}</span>
class Test { // private native int openEvent(String path); // private native int closeEvent(); // private int getPosition(); public static void main(String[] args) { GetPosition getPosition = new GetPosition("/dev/input/event5"); //openEvent("/dev/input/event5"); while(true) { getPosition.read(); System.out.println("[ " + getPosition.getX() + " , " + getPosition.getY() + "]"); } //getPosition.close(); //System.out.println() } /* static { System.loadLibrary("virtouch"); } */ }
继续测试下
可以得到跟之前一样的结果。
OK,现在我们可以再Linux下学习 Linux 驱动还有jni了。
参考:
在Linux下如何使用GCC编译程序、简单生成静态库及动态库。
http://blog.csdn.net/clozxy/article/details/5716227
Linux下JNI实现
http://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/13/2349775.html相关文章推荐
- Android 驱动和系统开发 1. 一个简单的例子(原创)
- Android 驱动和系统开发. 一个简单的例子
- Kotlin开发android:一个简单的登陆例子
- 驱动开发之 一个简单的截取键盘按键的驱动
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- 一个简单的Intent的android程序例子
- 【unity3d游戏开发之基础篇】unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0)
- [参考] Android 系统核心或驱动的开发之Android repo 魔法
- 开发一个好项目:九、android奔溃日记记录系统
- [转][MEF插件式开发] 一个简单的例子
- Android系统开发中log的使用方法及简单的原理
- Android开发从入门到放弃(8)使用ListView显示一个简单的列表
- Android开发做一个简单的音乐播放器
- Android开发之ButterKnife,GreenDao简单运用,以及推荐并使用一个好用的开源库BaseRecyclerViewAdapterHelper。
- Android高效的应用程序开发工具集1---ant构建一个简单的Android工程
- Android系统驱动开发琐碎——解决spidev读写过程没有时钟信号的问题
- 测试驱动开发随笔------一个最简单的例子
- Android的NDK开发(2)————利用Android NDK编写一个简单的HelloWorld
- Android的一个Relative Layout的简单例子