内核中对sensor的抽象:drivers/sensors/sensors_class.c
模块初始化函数:
复制代码
创建sensor的类class,通过sensors_class->dev_attrs = sensors_class_attrs;在sysfs文件系统下面创建设备节点,上层调用读写函数往文件节点读写数据时,相应的show和store函数就会被调用。sensors_class_attrs的定义如下:
1
2
3
4
5
6
7
8static int __init sensors_init(void) { sensors_class = class_create(THIS_MODULE, "sensors"); if (IS_ERR(sensors_class)) return PTR_ERR(sensors_class); sensors_class->dev_attrs = sensors_class_attrs; return 0; }
复制代码
具体的sensor驱动程序会调用sensors_classdev_register函数注册自己,以地磁传感器mmc3524为例,在驱动的proble函数中,有如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26static struct device_attribute sensors_class_attrs[] = { __ATTR(name, 0444, sensors_name_show, NULL), __ATTR(vendor, 0444, sensors_vendor_show, NULL), __ATTR(version, 0444, sensors_version_show, NULL), __ATTR(handle, 0444, sensors_handle_show, NULL), __ATTR(type, 0444, sensors_type_show, NULL), __ATTR(max_range, 0444, sensors_max_range_show, NULL), __ATTR(resolution, 0444, sensors_resolution_show, NULL), __ATTR(sensor_power, 0444, sensors_power_show, NULL), __ATTR(min_delay, 0444, sensors_min_delay_show, NULL), __ATTR(fifo_reserved_event_count, 0444, sensors_fifo_event_show, NULL), __ATTR(fifo_max_event_count, 0444, sensors_fifo_max_show, NULL), __ATTR(max_delay, 0444, sensors_max_delay_show, NULL), __ATTR(flags, 0444, sensors_flags_show, NULL), __ATTR(enable, 0664, sensors_enable_show, sensors_enable_store), __ATTR(enable_wakeup, 0664, sensors_enable_wakeup_show, sensors_enable_wakeup_store), __ATTR(poll_delay, 0664, sensors_delay_show, sensors_delay_store), __ATTR(self_test, 0440, sensors_test_show, NULL), __ATTR(max_latency, 0660, sensors_max_latency_show, sensors_max_latency_store), __ATTR(flush, 0660, sensors_flush_show, sensors_flush_store), __ATTR(calibrate, 0664, sensors_calibrate_show, sensors_calibrate_store), __ATTR_NULL, };
复制代码
1
2
3
4memsic->cdev = sensors_cdev; memsic->cdev.sensors_enable = mmc3524x_set_enable; memsic->cdev.sensors_poll_delay = mmc3524x_set_poll_delay; res = sensors_classdev_register(&memsic->idev->dev, &memsic->cdev);
mmc3524的数据结构如下,里面有个struct sensors_classdev cdev;成员,上面的代码设置cdev的enable和poll_delay函数指针指向驱动程序的函数,供sensor的HAL层调用。
复制代码
sensors_classdev_register函数是sensor的核心,该函数根据之前创建的sensors_class,在类下面创建设备,前面调用sensors_classdev_register(&memsic->idev->dev, &memsic->cdev);时,将memsic->cdev成员的地址作为device_create函数的第四个参数传入,然后将sensors_cdev放入sensors_list链表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21struct mmc3524x_data { struct mutex ecompass_lock; struct mutex ops_lock; struct workqueue_struct *data_wq; struct delayed_work dwork; struct sensors_classdev cdev; struct mmc3524x_vec last; struct i2c_client *i2c; struct input_dev *idev; struct regulator *vdd; struct regulator *vio; struct regmap *regmap; int dir; int auto_report; int enable; int poll_interval; int power_enabled; unsigned long timeout;
复制代码
在device_create函数中,调用device_create_vargs将之前传入的&memsic->cdev传入device_create_vargs函数中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16int sensors_classdev_register(struct device *parent, struct sensors_classdev *sensors_cdev) { sensors_cdev->dev = device_create(sensors_class, parent, 0, sensors_cdev, "%s", sensors_cdev->name); if (IS_ERR(sensors_cdev->dev)) return PTR_ERR(sensors_cdev->dev); down_write(&sensors_list_lock); list_add_tail(&sensors_cdev->node, &sensors_list); up_write(&sensors_list_lock); pr_debug("Registered sensors device: %sn", sensors_cdev->name); return 0; }
复制代码
在device_create_vargs函数中,会调用dev_set_drvdata(dev, drvdata);
1
2
3
4
5
6
7
8
9
10
11struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) { va_list vargs; struct device *dev; va_start(vargs, fmt); dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); va_end(vargs); return dev; }
复制代码
在dev_set_drvdata函数中,会调用dev->p->driver_data = data;这样dev->p->driver_data就指向了&memsic->cdev。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36struct device *device_create_vargs(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, va_list args) { struct device *dev = NULL; int retval = -ENODEV; if (class == NULL || IS_ERR(class)) goto error; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { retval = -ENOMEM; goto error; } dev->devt = devt; dev->class = class; dev->parent = parent; dev->release = device_create_release; dev_set_drvdata(dev, drvdata); retval = kobject_set_name_vargs(&dev->kobj, fmt, args); if (retval) goto error; retval = device_register(dev); if (retval) goto error; return dev; error: put_device(dev); return ERR_PTR(retval); }dev_set_drvdata
复制代码
在sensors_enable_store和sensors_enable_show函数中,会调用dev_get_drvdata函数:
1
2
3
4
5
6
7
8
9
10
11
12int dev_set_drvdata(struct device *dev, void *data) { int error; if (!dev->p) { error = device_private_init(dev); if (error) return error; } dev->p->driver_data = data; return 0; }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34static ssize_t sensors_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev); ssize_t ret = -EINVAL; unsigned long data = 0; ret = kstrtoul(buf, 10, &data); if (ret) return ret; if (data > 1) { dev_err(dev, "Invalid value of input, input=%ldn", data); return -EINVAL; } if (sensors_cdev->sensors_enable == NULL) { dev_err(dev, "Invalid sensor class enable handlen"); return -EINVAL; } ret = sensors_cdev->sensors_enable(sensors_cdev, data); if (ret) return ret; sensors_cdev->enabled = data; return size; } static ssize_t sensors_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%un", sensors_cdev->enabled); }
复制代码
dev_get_drvdata函数会返回之前在dev_set_drvdata函数中设置的指针dev->p->driver_data。
1
复制代码
之前在驱动的probe函数中设置了memsic->cdev.sensors_enable = mmc3524x_set_enable;sensors_enable_store函数通过ret = sensors_cdev->sensors_enable(sensors_cdev, data);来调用驱动程序中的enable函数。HAL层会根据sensor的设备节点来找到sensor,调用enable,delay等函数来调用sensor驱动中对应的函数,本例子中对应的文件是:hardware/qcom/sensors/CompassSensor.cpp:
1
2
3
4
5
6void *dev_get_drvdata(const struct device *dev) { if (dev && dev->p) return dev->p->driver_data; return NULL; }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46int CompassSensor::enable(int32_t, int en) { int flags = en ? 1 : 0; compass_algo_args arg; arg.common.enable = flags; char propBuf[PROPERTY_VALUE_MAX]; property_get("sensors.compass.loopback", propBuf, "0"); if (strcmp(propBuf, "1") == 0) { ALOGE("sensors.compass.loopback is set"); mEnabled = flags; mEnabledTime = 0; return 0; } if (flags != mEnabled) { int fd; if ((algo != NULL) && (algo->methods->config != NULL)) { if (algo->methods->config(CMD_ENABLE, (sensor_algo_args*)&arg)) { ALOGW("Calling enable config failed for compass"); } } strlcpy(&input_sysfs_path[input_sysfs_path_len], SYSFS_ENABLE, SYSFS_MAXLEN); fd = open(input_sysfs_path, O_RDWR); if (fd >= 0) { char buf[2]; int err; buf[1] = 0; if (flags) { buf[0] = '1'; mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME; } else { buf[0] = '0'; } err = write(fd, buf, sizeof(buf)); close(fd); mEnabled = flags; return 0; } ALOGE("CompassSensor: failed to open %s", input_sysfs_path); return -1; } return 0; }
复制代码
HAL层的enable函数中,通过write系统调用来调用内核的enable函数,内核的enable函数首先会打开设备的电源,然后通过工作队列函数queue_delayed_work(memsic->data_wq,&memsic->dwork,msecs_to_jiffies(memsic->poll_interval));来调用sensor的mmc3524x_poll函数。
1
复制代码
mmc3524x_poll函数通过I2C接口获取数据,上报数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47static int mmc3524x_set_enable(struct sensors_classdev *sensors_cdev, unsigned int enable) { int rc = 0; struct mmc3524x_data *memsic = container_of(sensors_cdev, struct mmc3524x_data, cdev); mutex_lock(&memsic->ops_lock); if (enable && (!memsic->enable)) { rc = mmc3524x_power_set(memsic, true); if (rc) { dev_err(&memsic->i2c->dev, "Power up failedn"); goto exit; } /* send TM cmd before read */ rc = regmap_write(memsic->regmap, MMC3524X_REG_CTRL, MMC3524X_CTRL_TM); if (rc) { dev_err(&memsic->i2c->dev, "write reg %d failed.(%d)n", MMC3524X_REG_CTRL, rc); goto exit; } memsic->timeout = jiffies; if (memsic->auto_report) queue_delayed_work(memsic->data_wq, &memsic->dwork, msecs_to_jiffies(memsic->poll_interval)); } else if ((!enable) && memsic->enable) { if (memsic->auto_report) cancel_delayed_work_sync(&memsic->dwork); if (mmc3524x_power_set(memsic, false)) dev_warn(&memsic->i2c->dev, "Power off failedn"); } else { dev_warn(&memsic->i2c->dev, "ignore enable state change from %d to %dn", memsic->enable, enable); } memsic->enable = enable; exit: mutex_unlock(&memsic->ops_lock); return rc;
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40static void mmc3524x_poll(struct work_struct *work) { int ret; s8 *tmp; struct mmc3524x_vec vec; struct mmc3524x_vec report; struct mmc3524x_data *memsic = container_of((struct delayed_work *)work, struct mmc3524x_data, dwork); ktime_t timestamp; vec.x = vec.y = vec.z = 0; ret = mmc3524x_read_xyz(memsic, &vec); if (ret) { dev_warn(&memsic->i2c->dev, "read xyz failedn"); goto exit; } tmp = &mmc3524x_rotation_matrix[memsic->dir][0]; report.x = tmp[0] * vec.x + tmp[1] * vec.y + tmp[2] * vec.z; report.y = tmp[3] * vec.x + tmp[4] * vec.y + tmp[5] * vec.z; report.z = tmp[6] * vec.x + tmp[7] * vec.y + tmp[8] * vec.z; timestamp = ktime_get_boottime(); input_report_abs(memsic->idev, ABS_X, report.x); input_report_abs(memsic->idev, ABS_Y, report.y); input_report_abs(memsic->idev, ABS_Z, report.z); input_event(memsic->idev, EV_SYN, SYN_TIME_SEC, ktime_to_timespec(timestamp).tv_sec); input_event(memsic->idev, EV_SYN, SYN_TIME_NSEC, ktime_to_timespec(timestamp).tv_nsec); input_sync(memsic->idev); exit: queue_delayed_work(memsic->data_wq, &memsic->dwork, msecs_to_jiffies(memsic->poll_interval)); }
最后
以上就是高大小土豆最近收集整理的关于Sensor在Linux内核中的驱动分析的全部内容,更多相关Sensor在Linux内核中内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复