Fork me on GitHub

Android Qcom USB Driver学习(七)

最近遇到了USB 插拔后,系统重启的问题,抓取串口log发现如下问题,log中查看trace分析就是空指针造成的panic

Unable to handle kernel read from unreadable memory at virtual address 0000000000000000
Mem abort info:
  ESR = 0x96000005
  Exception class = DABT (current EL), IL = 32 bits
  EA = 0, S1PTW = 0
Data abort info:
  ISV = 0, ISS = 0x00000005
  CM = 0, WnR = 0
user pgtable: 4k pages, 39-bit VAs, pgdp = 00000000dd92c597
...
Workqueue: usb_hub_wq hub_event
pstate: 60400005 (nZCv daif +PAN -UAO)
pc : hidown_disconnect+0x2c/0x98
lr : hidown_disconnect+0x24/0x98
sp : ffffff800808b840
x29: ffffff800808b840 x28: ffffff91017008f8
...
Call trace:

这里PC已经解析出了出错位置hidown_disconnect+0x2c/0x98,如果能得到对应的address的话可以通过add2line解析到对应函数和行数

./aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-addr2line -f -e vmlinux ffffff800808b820

在之前在USB系列四学习到了usb Interface的接口类型有很多,那接触到这个usb驱动,发现usb hid的功能也是有分类,有以下几种

/kernel/msm-4.19/include/linux/hid.h

#define HID_CLAIMED_INPUT	BIT(0)
#define HID_CLAIMED_HIDDEV	BIT(1)
#define HID_CLAIMED_HIDRAW	BIT(2)
#define HID_CLAIMED_DRIVER	BIT(3)

/*
* HID connect requests
*/

#define HID_CONNECT_HIDINPUT		BIT(0)
#define HID_CONNECT_HIDINPUT_FORCE	BIT(1)
#define HID_CONNECT_HIDRAW		BIT(2)
#define HID_CONNECT_HIDDEV		BIT(3)
#define HID_CONNECT_HIDDEV_FORCE	BIT(4)
#define HID_CONNECT_FF			BIT(5)
#define HID_CONNECT_DRIVER		BIT(6)
#define HID_CONNECT_DEFAULT	(HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
		HID_CONNECT_HIDDEV|HID_CONNECT_FF)

这里看到有clamied和connect_mask,感觉功能有重复,为什么会出现这样呢?

kernel/msm-4.19/drivers/hid/hid-own.c     hidraw不需要进行hid parse,可以直接传输raw原始数据
	hdev->claimed = HID_CLAIMED_HIDRAW;
	hdev->quirks = HID_QUIRK_NO_INIT_REPORTS;
	error = hid_hw_start(hdev, 0);           // mask = 0
	hdev->claimed = 0;

kernel/msm-4.19/drivers/hid/hid-multitouch.c
	hid_hw_start(hdev, HID_CONNECT_DEFAULT); // mask = HID_CONNECT_DEFAULT


int hid_hw_start(struct hid_device *hdev, unsigned int connect_mask)
	int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
		if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
                hdev->claimed |= HID_CLAIMED_HIDRAW;

		if (hdev->claimed & HID_CLAIMED_HIDRAW)
                len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
                                ((struct hidraw *)hdev->hidraw)->minor);


hid-input.c
	hidinput_connect + hidinput_configure_usage 注册输入设备,配置输入接口	
usbhid/hiddev.c
	hiddev_connect 将hid device连接到hiddev driver
hidraw_connect
	hidraw.c 接受所有的hid device设备,注册到/sys/class/hidraw/hidrawx

通过上述我个人理解的connect_mask与hdev->claimed应该功能区别不大,connect_mask最终也是决定claimed的内容。

posted @ 2024-08-23 14:06  yooooooo  阅读(11)  评论(0编辑  收藏  举报