Android上层APP利用sysfs调用底层驱动分析

时间:2021-05-26 05:48:13

            自从移植驱动以来一直对应用层调用底层驱动的过程很感兴趣,每次看到Android的系统架构图时总是会自然的觉得上层APP调用底层驱动的时候使一层一层往下调用,从APP到framwork再到HAL最后到驱动,然而我总觉得这样一层一层调用,每一次指令的跳转和压栈是不是都会影响到系统的效率呢?虽然高速CPU经常需要等待慢速IO操作能忽略掉一些调用的时间花费,但有没有一种方法能让JAVA直接调用到驱动呢?事实上是有的,比如说sysfs(系统文件系统,这样翻译是不是很别扭?)。

            什么是sysfs?Linux内核中有文档 "sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel data structures, their attributes, and the linkages between them to userspace.” --- documentation/filesystems/sysfs.txt,大致的翻译一下就是sysfs 是在ramfs基础上的一个基于内存的初始化文件系统,它提供了一个能导出内核数据结构,内核的一些属性,和在内核和用户空间建立一种链接的方法。也就是说它应该和同样是为了给上层调用而存在,那么上层要怎么来访问它呢?下面以一个摄像头的驱动为例,分析一下如何利用sysfs实现上层对驱动的调用(为了方便起见已删除和修改部分无关代码)。

            先看驱动层

static __init int init_sensor(void)
{
    int result;
    pr_err("Camera:%s,%s\n",__DATE__,__TIME__);
    camera_wq = create_singlethread_workqueue("camera_wq");
    if(!camera_wq) 
          pr_err("create camera_wq failed!\n");
    
    result = i2c_add_driver(&sensor_driver);   
    result = driver_create_file(&sensor_driver.driver, &driver_attr_camera);
    if(result<0) {
            return result;
    }
    printk("%s successful.\n",__FUNCTION__);
    return result;
}

static __exit void exit_sensor(void)
{
  driver_remove_file(&sensor_driver.driver, &driver_attr_camera);
  i2c_del_driver(&sensor_driver);

  if (camera_wq) destroy_workqueue(camera_wq);
}

module_init(init_sensor);
module_exit(exit_sensor);

这段初始化和退出代码比较简单,主要功能是系统加载驱动ko文件(卸载ko文件)的时候向i2c总线注册(卸载)一个驱动,并创建(卸载)一个工作队列,并在系统里创建(删除)一个驱动文件,而我们说的sysfs文件系统就从这个创建驱动文件开始,事实上这个文件最终就是 /sys/bus/i2c/drivers/camera/camera          

展开driver_creat_file函数

int driver_create_file(struct device_driver *drv,
		       const struct driver_attribute *attr)
{
	int error;
	if (drv)
		error = sysfs_create_file(&drv->p->kobj, &attr->attr);
	else
		error = -EINVAL;
	return error;
}
由于这个函数调用层次比较深,就不一一展开,但是我们知道上面传入的第一个参数是一个驱动driver,并且就是刚刚注册到i2c总线的驱动结构体,第二个参数是一个属性attr,也就是driver_attr_camera,但是它却在整个驱动代码文件中找不到,但是我们仍然能看到会有这样一句话
static DRIVER_ATTR(camera, 0777, get_camera, set_camera);
DRIVER_ATTR很明显是一个宏原型是
#define DRIVER_ATTR(_name, _mode, _show, _store) \
struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store)
这样就很明显了,调用那个宏的时候相当于定义一个结构体,结构体中保存了名字,访问权限,显示和存储,别问我怎么知道是显示和存储(其实就是上层读接口和上层写接口),因为我有看到下面两个函数
static ssize_t set_camera(struct device_driver *driver,const char *buf,size_t count) {
    char  tempx[9]={0};
    if( count>8 ) memcpy(tempx,buf,8);
    else    memcpy(tempx,buf,count);
    pr_err("set_camera %s\n",buf);
    int value=tempx[1]-'0';
    if('W'==tempx[0] ) {
        sensor_s_wb(camera_work_para.sd,value);
  } else if('E'==tempx[0])  {
    sensor_s_exp_bias(camera_work_para.sd,value);
  } else if('C'==tempx[0])  {
    sensor_s_colorfx(camera_work_para.sd,value);
  } else if('H'==tempx[0]  )    {
    int i=0;
    for(i=0;i<ARRAY_SIZE(sensor_720P_regs_30);i++) {
        if( 0x3022==sensor_720P_regs_30[i].addr) {
            pr_err("set hfilp %s\n",buf);
            sensor_720P_regs_30[i].data &=0xFD;
            sensor_720P_regs_30[i].data |=( ('1'==tempx[1]) ? 0x02:0x00 );
            break;
        }
    }
    //...此处省略N行相同或者类似代码...
   }
}

static ssize_t get_camera(struct device_driver *driver,char *buf) {
    pr_err("get_camera\n");
    int count=12;
    return count;
}
这样上层就可以通过对文件 /sys/bus/i2c/drivers/camera/camera写就可以对应的执行set_camera函数,例如
try { 
    FileOutputStream fops = new FileOutputStream(
                            "/sys/bus/i2c/drivers/camera/camera"); 
    fops.write("W1".getBytes()); //向驱动写入W1 
    fops.write("H".getBytes()); //向驱动写入H 
    fops.flush(); 
    fops.close();

    } catch (FileNotFoundException e) {
	    Log.d("err", "found error");
    } catch (IOException e) {
            Log.d("err", "IO error");
}
 同样读取 
/sys/bus/i2c/drivers/camera/camera执行get_camera 
try {
	FileInputStream fis = new FileInputStream(
			"/sys/bus/i2c/drivers/camera/camera");
	InputStreamReader isr = new InputStreamReader(fis);
	BufferedReader br = new BufferedReader(isr, 4096);
	int num = 0;
	while ((num = br.read()) != 0) {
		//do some thing;
		;
	}
	br.close();
	} catch (FileNotFoundException e) {
	        Log.d("err", "found error");
	} catch (IOException e) {
		Log.d("err", "IO error");
}

最后补充一下,除了有DRIVER_ATTR这个宏以外还有DEVICE_ATTR,不同的宏使用不同的配套函数,但基本用法是类似的,所以不进行过多赘述
参考文档:http://blog.csdn.net/skyflying2012/article/details/11783847