从底层把值传给上层有很多种方法,sysfs就是很简单的一个:
提到sysfs,就不得不提函数宏 DEVICE_ATTR
DEVICE_ATTR的原型:
#define DEVICE_ATTR(_name,_mode,_show,_store)\
struct device_atttribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) //名称,权限位,读函数,写函数
其中_show表示读方法 --- 对应于adb的cat
_store表示写方法 --- 对应于adb的echo.
_ATTR宏有很多,例如设备使用的是DEVICE_ATTR,总线使用的是BUS_ATTR,驱动使用的是DRIVER_ATTR,类别(class)使用的是CLASS_ATTR, 这四个宏定义在<inlude/linux/device.h>中.
#include <linux/module.h> #include <linux/slab.h> #include <linux/kobject.h> #include <linux/platform_device.h> struct att_dev{ struct platform_device *pdev; struct kobject *kobj; }; static ssize_t att_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { printk("echo debug buf\n"); return count; } static ssize_t att_show(struct device *dev, struct device_attribute *attr, char *buf) { printk("cat debug buf\n"); return 0; } static DEVICE_ATTR(test,0777,att_show,att_store); static struct att_dev *dev = NULL; static __devinit int att_probe(struct platform_device *ppdev){ int ret; dev->kobj = kobject_create_and_add("attkobj", NULL); if(dev->kobj == NULL){ ret = -ENOMEM; goto kobj_err; } ret = sysfs_create_file(&dev->pdev->dev.kobj,&dev_attr_test.attr); if(ret < 0){ goto file_err; } return 0; file_err: kobject_del(dev->kobj); kobj_err: return ret; } static struct platform_driver att_driver = { .probe = att_probe, .driver = { .owner = THIS_MODULE, .name = "att_test", }, }; static int __init att_init(void) { int ret; dev = kzalloc(sizeof(struct att_dev),GFP_KERNEL); if(dev == NULL){ printk("%s get dev memory error\n",__func__); return -ENOMEM; } dev->pdev = platform_device_register_simple("att_test", -1, NULL, 0); if(IS_ERR(dev->pdev)){ PTR_ERR(dev->pdev); printk("%s pdev error\n",__func__); return -1; } ret = platform_driver_register(&att_driver); if(ret < 0){ printk("%s register driver error\n",__func__); return ret; } return 0; } static void __exit att_exit(void) { sysfs_remove_file(&dev->pdev->dev.kobj,&dev_attr_test.attr); kobject_del(dev->kobj); platform_device_unregister(dev->pdev); platform_driver_unregister(&att_driver); if(dev != NULL) kfree(dev); } module_init(att_init); module_exit(att_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("driverSir");
安装之后/sys/devices/platform/att_test/test
echo 1 > test
cat test
dmesg之后会看到内核打印出
[ 424.793357] echo debug buf
[ 427.122139] cat debug buf
说明在echo 1 > test 时调用了att_store,cat test 的时候调用了att_show
具体例子:
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP, sensor_delay_show, sensor_delay_store);
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, sensor_enable_show, sensor_enable_store);
static DEVICE_ATTR(data, S_IRUGO, sensor_data_show, NULL);
static DEVICE_ATTR(status, S_IRUGO, sensor_status_show, NULL);
static struct attribute *sensor_attributes[] = {
&dev_attr_delay.attr,
&dev_attr_enable.attr,
&dev_attr_data.attr,
&dev_attr_status.attr,
NULL
};
如果你想实现的接口名字是data的时候,需要实现static struct attribute *sensor_attribute[] = { &dev_attr_data.attr}
将sensor_attribute封装为:static struct attribute_group sensor_attribute_group = {
.attrs = sensor_attributes
};
只要利用sysfs_create_group(&input_data->dev.kobj, &sensor_attribute_group);创建接口.
通过以上三个步骤,就可以在adb shell终端查看到接口了.
当我们在shell中输入:echo "1" > enable时,在上层实际上完成了一次写操作,对应到kernel,就会调用驱动中的sensor_enable_store.
当我们在shell中输入:cat enable时,在上层实际上完成了一次读操作,对应到kernel,就会调用驱动中的sensor_enable_show.
这样android和kernel就建立起了桥梁,可以根据不同的操作,在store和show函数中完成对应的硬件操作
driver例子:
#include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/kthread.h> #include <linux/semaphore.h> struct v_dev{ struct platform_device *p_dev; struct input_dev *input; int x; int y; struct task_struct *run_thread; struct semaphore sem; }; struct v_dev *vmouse_dev = NULL; static ssize_t write_pos(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int x,y; sscanf(buf,"%d%d",&x,&y); vmouse_dev->x = x; vmouse_dev->y =y; //post 信号量 up(&vmouse_dev->sem); return count; } static ssize_t show_pos(struct device *dev, struct device_attribute *attr, char *buf){ return sprintf(buf,"(%d,%d)\n",vmouse_dev->x,vmouse_dev->y); } DEVICE_ATTR(pos,0644,show_pos,write_pos); static int vmouse_thread(void *data) { int x,y; struct v_dev *vmouse_dev = (struct v_dev*)data; struct semaphore *sema = &(vmouse_dev->sem); printk(KERN_INFO "vmouse thread running\n"); while(1){ //等待信号量 while((down_interruptible(sema)) == -EINTR){} ; x = vmouse_dev->x; y = vmouse_dev->y; input_report_abs(vmouse_dev->input,ABS_X,x); input_report_abs(vmouse_dev->input,ABS_Y,y); input_sync(vmouse_dev->input); printk("vmouse thread report\n"); } return 0; } static int vmouse_probe(struct platform_device *pdev) { int ret = -1; printk("%s debug \n",__func__); if(vmouse_dev->p_dev == pdev){ printk("platform device is same\n"); } vmouse_dev->input = input_allocate_device(); if(!(vmouse_dev->input)){ printk("%s request input deivce error\n",__func__); goto alloc_input; } vmouse_dev->input->name = "vmouse"; set_bit(EV_ABS,vmouse_dev->input->evbit); input_set_abs_params(vmouse_dev->input, ABS_X, -1024, 1024, 0, 0); input_set_abs_params(vmouse_dev->input, ABS_Y, -1024, 1024, 0, 0); ret = input_register_device(vmouse_dev->input); if(ret < 0){ printk("%s register input device error\n",__func__); goto input_register; } device_create_file(&pdev->dev,&dev_attr_pos); //初始化信号量,在线程中要用到 sema_init(&(vmouse_dev->sem),0); vmouse_dev->run_thread = kthread_run(vmouse_thread,vmouse_dev,"vmouse_thread"); return 0; input_register: input_free_device(vmouse_dev->input); alloc_input: kfree(vmouse_dev); return ret; } static struct platform_driver vmouse_driver = { .probe = vmouse_probe, .driver = { .owner = THIS_MODULE, .name = "v_mouse", }, }; static int __init vmouse_init(void) { int ret =-1; printk("%s\n", __func__); vmouse_dev = kzalloc(sizeof(struct v_dev),GFP_KERNEL); if(vmouse_dev == NULL){ printk("%s alloc memory error\n",__func__); return -ENOMEM; } vmouse_dev->p_dev= platform_device_register_simple("v_mouse",-1,NULL,0); if(!(vmouse_dev->p_dev)){ printk("%s register platform device error\n",__func__); return ret; } ret = platform_driver_register(&vmouse_driver); if(ret < 0){ printk("%s register driver error\n",__func__); return ret; } return 0; } static void __exit vmouse_exit(void) { printk("%s\n", __func__); if(vmouse_dev->input != NULL){ input_unregister_device(vmouse_dev->input); } printk("%s debug__1\n",__func__); if(vmouse_dev != NULL){ platform_device_unregister(vmouse_dev->p_dev); } printk("%s debug__2\n",__func__); platform_driver_unregister(&vmouse_driver); printk("%s debug__3\n",__func__); kfree(vmouse_dev); printk("%s debug__4\n",__func__); } module_init(vmouse_init); module_exit(vmouse_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("WEED<[email protected]>");
#include <fcntl.h> #include <linux/input.h> #include <stdio.h> //要看自己的节点了 #define EVENT_DEV "/dev/input/event5" int main(void) { struct input_event ev; int count,x,y; int fd = open(EVENT_DEV, O_RDWR); if(fd < 0){ printf("open %s failed\n",EVENT_DEV); return 0; } while(1){ count = read(fd, &ev,sizeof(struct input_event)); if(EV_ABS == ev.type){ if(ev.code == ABS_X){ x = ev.value; }else if(ev.code == ABS_Y){ y = ev.value; } printf("position: x=%d, y=%d\n",x,y); }else if(EV_SYN == ev.type){ puts("sync!"); } } return 0; }
你就会看到你input设备上报的坐标,打印信息如下:
position: x=90, y=0