树莓派(Linux 系统)触摸屏翻转显示以及触摸翻转

树莓派(Linux 系统)触摸屏翻转显示以及触摸翻转,第1张

树莓派(Linux 系统)触摸屏翻转显示以及触摸翻转 问题:未使用的Pi官方屏幕,所以使用HDMI屏幕显示的时候,显示旋转的同时,触摸没有旋转 目的:旋转屏幕显示的同时,使得触摸也跟随旋转 *** 作总流程:     旋转90度 *** 作 翻转显示: 1.sudo nano /boot/config.txt 2.在文件末尾加入 display_rotate=0 display_rotate=1   //90° display_rotate=2   //180° display_rotate=3   //270° ctrl + o 保存文档 重启即可。 注:以下 *** 作皆为SSH *** 作,所以每条指令前都加了DISPLAY=:0,如果本机 *** 作删掉即可。 1.安装xinput sudo apt-get install xinput 2.列出所有输入设备信息 远程 *** 作时,使用xinput指令需要加入DISPLAY=:0 DISPLAY=:0 xinput --list 3.列出目标设备属性 DISPLAY=:0 xinput --list-props 7 4.旋转触摸的坐标轴 1)所以先交换x、y轴 DISPLAY=:0 xinput --set-prop '7' 'Evdev Axes Swap' 1 2)然后反转y轴 DISPLAY=:0 xinput --set-prop '7' 'Evdev Axis Inversion' 0 1 显示旋转修改之后需要重启。而触摸旋转不需要重启。 详细 *** 作方法:  1.安装xinput sudo apt-get install xinput 描述: xinput - utility to configure and test X input devices   xinput-用于配置和测试X输入设备的实用程序 xinput is a utility to list available input devices, xinput是一个实用程序,可以列出可用的输入设备、 query information about a device and change input device settings. 关于设备的查询信息和更改输入设备设置 2.列出所有输入设备信息 xinput --list 如果远程 *** 作记得在命令前加DISPLAY=:0 得到以下信息: pi@NTGAGE:~ $ DISPLAY=:0 xinput --list ⎡ Virtual core pointer                          id=2    [master pointer  (3)] ⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)] ⎜   ↳ Logitech USB Optical Mouse                id=6    [slave  pointer  (2)] ⎜   ↳ WaveShare WaveShare Touchscreen           id=7    [slave  pointer  (2)] ⎣ Virtual core keyboard                         id=3    [master keyboard (2)]     ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]     ↳ Logitech USB Keyboard                     id=8    [slave  keyboard (3)]     ↳ Logitech USB Keyboard                     id=9    [slave  keyboard (3)] 3.列出目标设备属性 由于所使用的触摸屏幕是微雪7寸屏幕,由以上信息可以得到微雪的触摸屏对应的ID为7 所以,接下来看这款输入设备的属性, pi@NTGAGE:~ $ DISPLAY=:0 xinput --list-props 7 Device 'WaveShare WaveShare Touchscreen':         Device Enabled (115):   1         Coordinate Transformation Matrix (116): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000         Device Accel Profile (240):     0         Device Accel Constant Deceleration (241):       1.000000         Device Accel Adaptive Deceleration (242):       1.000000         Device Accel Velocity Scaling (243):    10.000000         Device Product ID (244):        3823, 5         Device Node (245):      "/dev/input/event3"         Evdev Axis Inversion (246):     0, 0         Evdev Axis Calibration (247):   <no items>         Evdev Axes Swap (248):  0         Axis Labels (249):      "Abs MT Position X" (267), "Abs MT Position Y" (268), "Abs MT Pressure" (269), "None" (0), "None" (0), "None" (0)         Button Labels (250):    "Button Unknown" (233), "Button Unknown" (233), "Button Unknown" (233), "Button Wheel Up" (121), "Button Wheel Down" (122)         Evdev Scrolling Distance (251): 0, 0, 0         Evdev Middle Button Emulation (252):    0         Evdev Middle Button Timeout (253):      50         Evdev Third Button Emulation (254):     0         Evdev Third Button Emulation Timeout (255):     1000         Evdev Third Button Emulation Button (256):      3         Evdev Third Button Emulation Threshold (257):   20         Evdev Wheel Emulation (258):    0         Evdev Wheel Emulation Axes (259):       0, 0, 4, 5         Evdev Wheel Emulation Inertia (260):    10         Evdev Wheel Emulation Timeout (261):    200         Evdev Wheel Emulation Button (262):     4         Evdev Drag Lock Buttons (263):  0 这块屏幕正常显示和触摸的信息如上。 如果执行到这一步,发现并没有以上的Evdev等属性项,请跳转第2种方法。 现在需要达到的目的是在屏幕显示反转的同时,使得触摸也随显示翻转。 屏幕显示为翻转90度。/boot/config.txt设置为display_rotate=1 上述信息中Evdev Axis Inversion 项是每条轴的旋转设置项,后面第一个参数是x,第二个参数是y. Evdev Axes Swap项对应的是两条轴的交换。 0为不翻转,1为翻转  例如。x轴原本是朝向右的,当把Evdev Axis Inversion的第一个参数 设置为1,即x轴朝向左。 4.旋转触摸的坐标轴 现在目的是要触摸旋转90度,从坐标轴理解: 即目的x轴正向为初始y轴的反向。目的y轴的正方向为初始x轴的正向。 1)所以先交换x、y轴 DISPLAY=:0 xinput --set-prop '7' 'Evdev Axes Swap' 1 2)然后反转y轴 DISPLAY=:0 xinput --set-prop '7' 'Evdev Axis Inversion' 0 1 这样即可完成触摸旋转90度。若要旋转其他角度,推理一下即可。 显示旋转修改之后需要重启。而触摸旋转不需要重启。 第二种方法 如果查询到的信息如下 DISPLAY=:0 xinput --list-props 6 Device 'WaveShare WaveShare Touchscreen':         Device Enabled (114):   1         Coordinate Transformation Matrix (115): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000         libinput Calibration Matrix (246):      0.000000, 1.000000, 0.000000, -1.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000         libinput Calibration Matrix Default (247):      1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000         libinput Send Events Modes Available (248):     1, 0         libinput Send Events Mode Enabled (249):        0, 0         libinput Send Events Mode Enabled Default (250):        0, 0         Device Node (251):      "/dev/input/event0"         Device Product ID (252):        3823, 5 可以看到该驱动方式采用的是libinput, 查看/usr/share/X11/xorg.conf.d/目录下是否有40-libinput.conf这个文件。 无 则需要安装  sudo apt-get install xserver-xorg-input-libinput  下一步安装完成后ls一下,就可以看到在/usr/share/X11/xorg.conf.d/目录下存在该文件, 下一步复制该文件到/etc/X11/xorg.conf.d/目录下。 一开始xorg.conf.d这个目录在/etc/X11可能没有,需要自己创建。 sudo mkdir xorg.conf.d 下一步复制到xorg.conf.d 目录下即可。 sudo cp /usr/share/X11/xorg.conf.d/40-libinput.conf /etc/X11/xorg.conf.d/ 下一步进入/etc/X11/xorg.conf.d/目录下修改40-libinput.conf 文件 cd /etc/X11/xorg.conf.d/ sudo nano 40-libinput.conf 找到touchscreen section Section "InputClass"         Identifier "libinput touchscreen catchall"         MatchIsTouchscreen "on"         MatchDevicePath "/dev/input/event*"         Driver "libinput" EndSection 添加一行  Option "CalibrationMatrix" "0 1 0 -1 0 1 0 0 1  结果为 Section "InputClass"         Identifier "libinput touchscreen catchall"         Option "CalibrationMatrix" "0 1 0 -1 0 1 0 0 1         MatchIsTouchscreen "on"         MatchDevicePath "/dev/input/event*"         Driver "libinput"EndSection然后重启生效 这样的修改也是同样修改为翻转90度,如果需要修改为其他角度,请参考libinput的算法  https://wayland.freedesktop.org/libinput/doc/latest/absolute_axes.html

android系统摁下电源键后会让系统进入休眠以达到节电的目的。内核驱动中和休眠相关的就是suspend和resume函数

suspend函数用于休眠,resume函数用于唤醒。下面分析驱动中的这两个函数是如何被调用到的。

驱动部分:

首先需要分析驱动的注册过程,较新的内核都是采用DTS方式来取代在内核中直接定义platform_device数据结构的注册方式,本文是基于DTS机制的内核来分析。

product对应的dts文件在编译时被编译为dtb文件,uboot在启动时候会将其地址传给内核,内核在启动过程中会去解析,具体解析是在start_kernel()->setup_arch() -->unflatten_device_tree()中具体分析可以参考网上,解析的最终结果会存放在allnodes地址处,这个allnodes随后在machine的init函数

中被使用,init函数中会根据allnodes中的节点数据组合成platform_device数据结构,然后将其注册到platform总线上,下面简要分析一下并重点关注这些初始化过程中和

pm相关的初始化。

我参与的项目中machine的init函数就是via_init_machine函数,在这个函数中就是调用了of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)这个函数来解析allnodes的。of_platform_populate是系统提供的接口。下面分析这个接口的实现:

[html] view plain copy

int of_platform_populate(struct device_node *root,

const struct of_device_id *matches,

const struct of_dev_auxdata *lookup,

struct device *parent)

{

struct device_node *child

int rc = 0

root = root ? of_node_get(root) : of_find_node_by_path("/")

if (!root)

return -EINVAL

for_each_child_of_node(root, child) {

rc = of_platform_bus_create(child, matches, lookup, parent, true)

if (rc)

break

}

of_node_put(root)

return rc

}

root最后就是取到的根节点,然后其作为参数传递给of_platform_bus_create,of_platform_device_create_pdata的实现如下:

[html] view plain copy

static int of_platform_bus_create(struct device_node *bus,

const struct of_device_id *matches,

const struct of_dev_auxdata *lookup,

struct device *parent, bool strict)

{

const struct of_dev_auxdata *auxdata

struct device_node *child

struct platform_device *dev

const char *bus_id = NULL

void *platform_data = NULL

int rc = 0

/* Make sure it has a compatible property */

if (strict &&(!of_get_property(bus, "compatible", NULL))) {

pr_debug("%s() - skipping %s, no compatible prop\n",

__func__, bus->full_name)

return 0

}

auxdata = of_dev_lookup(lookup, bus)

if (auxdata) {

bus_id = auxdata->name

platform_data = auxdata->platform_data

}

if (of_device_is_compatible(bus, "arm,primecell")) {

of_amba_device_create(bus, bus_id, platform_data, parent)

return 0

}

dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent)

if (!dev || !of_match_node(matches, bus))

return 0

for_each_child_of_node(bus, child) {

pr_debug(" create child: %s\n", child->full_name)

rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict)

if (rc) {

of_node_put(child)

break

}

}

return rc

}

根据传入参数,我们这里直接分析of_platform_device_create_padate函数,如下:

[html] view plain copy

struct platform_device *of_platform_device_create_pdata(

struct device_node *np,

const char *bus_id,

void *platform_data,

struct device *parent)

{

struct platform_device *dev

if (!of_device_is_available(np))

return NULL

dev = of_device_alloc(np, bus_id, parent)

if (!dev)

return NULL

#if defined(CONFIG_MICROBLAZE)

dev->archdata.dma_mask = 0xffffffffUL

#endif

dev->dev.coherent_dma_mask = DMA_BIT_MASK(32)

dev->dev.bus = &platform_bus_type

dev->dev.platform_data = platform_data

/* We do not fill the DMA ops for platform devices by default.

* This is currently the responsibility of the platform code

* to do such, possibly using a device notifier

*/

if (of_device_add(dev) != 0) {

platform_device_put(dev)

return NULL

}

return dev

}

of_platform_device_create_padate->of_device_alloc->platform_device_alloc

便在platform_device_alloc函数中进行进行alloc和初始化了,实现如下:

[html] view plain copy

struct platform_device *platform_device_alloc(const char *name, int id)

{

struct platform_object *pa

pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL)

if (pa) {

strcpy(pa->name, name)

pa->pdev.name = pa->name

pa->pdev.id = id

device_initialize(&pa->pdev.dev)

pa->pdev.dev.release = platform_device_release

arch_setup_pdev_archdata(&pa->pdev)

}

return pa ? &pa->pdev : NULL

}

可以看到有个device_initialize,这里面对pdev.dev做一些列的初始化,其中有一个函数就是device_pm_init,这个函数就是我们一直关心的device相关的pm函数,具体实现如下:

[html] view plain copy

void device_pm_init(struct device *dev)

{

dev->power.is_prepared = false

dev->power.is_suspended = false

init_completion(&dev->power.completion)

complete_all(&dev->power.completion)

dev->power.wakeup = NULL

spin_lock_init(&dev->power.lock)

pm_runtime_init(dev)

INIT_LIST_HEAD(&dev->power.entry)

dev->power.power_state = PMSG_INVALID

}

可以看见它对device和功耗相关的数据做了一些初始化,我们这里先重点关注下dev->power.entry,初始化一个链表头,所以他/它很有可能会在后面加到某个链表里面去,而那个链表应该是用来保存所有的device用的。系统中所有的platform_device都是通过这种方式注册到系统中的,那么应该所有的platform_device都会初始化一个dev->power.entry,如果到时候把所有的dev->power.entry都添加到某个链表上去,那么系统到时候查询的时候只要找到这个list head就可以找到所有的platform_device了。嗯,不过这是我们的猜测。我们接下去分析来验证下。

platform_device通过alloc之后已经初始化好了,那么接下去就可以添加到系统中了,所以我们再回头看of_platform_device_create_pdata的实现。

函数在of_device_alloc之后把dev->dev.bus赋值给了platform_bus_type,接着就调用了of_device_add函数,在of_device_add函数中最后通过device_add添加到了bus上,但是device_add中有个函数需要我们关系,就是device_pm_add(dev),实现如下:

[html] view plain copy

void device_pm_add(struct device *dev)

{

pr_debug("PM: Adding info for %s:%s\n",

dev->bus ? dev->bus->name : "No Bus", dev_name(dev))

mutex_lock(&dpm_list_mtx)

if (dev->parent &&dev->parent->power.is_prepared)

dev_warn(dev, "parent %s should not be sleeping\n",

dev_name(dev->parent))

list_add_tail(&dev->power.entry, &dpm_list)

dev_pm_qos_constraints_init(dev)

mutex_unlock(&dpm_list_mtx)

}

可以看到这里list_add_tail(&dev->power.entry, &dpm_list)这就验证了我们之前的猜测。所有注册到系统中的设备,最终都是会添加到dpm_list这条链表上。

那么系统在休眠的时候是如何通过dmp_list这表链表来suspend设备的呢?接下去就是我们要分析的电源管理部分内容。

系统电源部分:

电源管理相关文件在kernel/power目录下,前面已经分析到。系统中注册的设备都是会添加到dmp_list这条链表上的。那么睡眠的时候系统应该是会查找dmp_list这条链表,

然后通过这条链表依次去查到对应的driver,然后调用driver中的suspend方法。下面我们来验证。

2.在suspend会轮询bus下的driver,然后一次调用到driver->pm->suspend方法,然后进入休眠。

3.state_store->pm_suspend->enter_state->suspend_devices_and_enter->dpm_suspend_start->dpm_suspend->device_suspend->__device_suspend->pm_op->(ops->suspend)


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/6173742.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-17
下一篇2023-03-17

发表评论

登录后才能评论

评论列表(0条)

    保存