usb-wakeup

usb设备唤醒功能

drivers/hid/usbhid/hid-core.c

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
static int usbhid_start(struct hid_device *hid)
{
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_device *dev = interface_to_usbdev(intf);
struct usbhid_device *usbhid = hid->driver_data;
unsigned int n, insize = 0;
int ret;

mutex_lock(&usbhid->mutex);

clear_bit(HID_DISCONNECTED, &usbhid->iofl);

usbhid->bufsize = HID_MIN_BUFFER_SIZE;
hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);

if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
usbhid->bufsize = HID_MAX_BUFFER_SIZE;

hid_find_max_report(hid, HID_INPUT_REPORT, &insize);

if (insize > HID_MAX_BUFFER_SIZE)
insize = HID_MAX_BUFFER_SIZE;

if (hid_alloc_buffers(dev, hid)) {
ret = -ENOMEM;
goto fail;
}

for (n = 0; n < interface->desc.bNumEndpoints; n++) {
struct usb_endpoint_descriptor *endpoint;
int pipe;
int interval;

endpoint = &interface->endpoint[n].desc;
if (!usb_endpoint_xfer_int(endpoint))
continue;

interval = endpoint->bInterval;

/* Some vendors give fullspeed interval on highspeed devides */
if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
dev->speed == USB_SPEED_HIGH) {
interval = fls(endpoint->bInterval*8);
pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
hid->name, endpoint->bInterval, interval);
}

/* Change the polling interval of mice, joysticks
* and keyboards.
*/
switch (hid->collection->usage) {
case HID_GD_MOUSE:
if (hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval;
break;
case HID_GD_JOYSTICK:
if (hid_jspoll_interval > 0)
interval = hid_jspoll_interval;
break;
case HID_GD_KEYBOARD:
if (hid_kbpoll_interval > 0)
interval = hid_kbpoll_interval;
break;
}

ret = -ENOMEM;
if (usb_endpoint_dir_in(endpoint)) {
if (usbhid->urbin)
continue;
if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
hid_irq_in, hid, interval);
usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
} else {
if (usbhid->urbout)
continue;
if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
hid_irq_out, hid, interval);
usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
}
}

usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
if (!usbhid->urbctrl) {
ret = -ENOMEM;
goto fail;
}

usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
usbhid->ctrlbuf, 1, hid_ctrl, hid);
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

set_bit(HID_STARTED, &usbhid->iofl);

if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
ret = usb_autopm_get_interface(usbhid->intf);
if (ret)
goto fail;
set_bit(HID_IN_POLLING, &usbhid->iofl);
usbhid->intf->needs_remote_wakeup = 1;
ret = hid_start_in(hid);
if (ret) {
dev_err(&hid->dev,
"failed to start in urb: %d\n", ret);
}
usb_autopm_put_interface(usbhid->intf);
}

/* Some keyboards don't work until their LEDs have been set.
* Since BIOSes do set the LEDs, it must be safe for any device
* that supports the keyboard boot protocol.
* In addition, enable remote wakeup by default for all keyboard
* devices supporting the boot protocol.
*/
if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD) { //设置键盘默认唤醒功能
usbhid_set_leds(hid);
device_set_wakeup_enable(&dev->dev, 1);
}
else if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { //设置鼠标默认唤醒功能
//一般不建议开启鼠标唤醒功能,部分游戏鼠标,尤其是使用USB接收器的无线鼠标,每隔一段时间它们会定期发送信号给电脑,以确认设备的持续连接状态,并保持接收器的供电。
device_set_wakeup_enable(&dev->dev, 1);
}
}

mutex_unlock(&usbhid->mutex);
return 0;

fail:
usb_free_urb(usbhid->urbin);
usb_free_urb(usbhid->urbout);
usb_free_urb(usbhid->urbctrl);
usbhid->urbin = NULL;
usbhid->urbout = NULL;
usbhid->urbctrl = NULL;
hid_free_buffers(dev, hid);
mutex_unlock(&usbhid->mutex);
return ret;
}

查看usb设备唤醒功能脚本

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
47
48
49
#!/bin/bash
# author: TomWithKernel

fileName=""
productName=""

for file in /sys/bus/usb/devices/*/uevent; do
content=$(cat "$file")
if echo "$content" | grep -q "BUSNUM=$1" && echo "$content" | grep -q "DEVNUM=$2"; then
fileName="${file%/*}/power/wakeup"
productName="${file%/*}/product"

if [ -f "$fileName" ]; then
busnum=$(echo "$content" | grep -oE 'BUSNUM=([0-9]+)' | grep -oE '[0-9]+')
devnum=$(echo "$content" | grep -oE 'DEVNUM=([0-9]+)' | grep -oE '[0-9]+')

result=$(cat "$fileName")
productName=$(cat "$productName")
printf "Bus %3s Device %3s : %-30s power wakeup: %10s (路径: %s)\n" $busnum $devnum "$productName" $result "${file%/*}/product"
fi
fi
done

# 读取用户输入的设备节点和开关状态
read -p "请输入你要修改的设备的节点(例如 1-4.4.2 表示 BusNum-Port.Port.DevNum): " modify_device
read -p "请输入 enabled 或 disabled: " switch

# 检查用户输入的开关状态是否正确
if [[ "$switch" != "enabled" && "$switch" != "disabled" ]]; then
echo "无效输入。请输入 'enabled' 或 'disabled'。"
exit 1
fi

# 构造设备路径
device_path="/sys/bus/usb/devices/$modify_device/power/wakeup"

# 检查设备路径是否存在
if [ ! -f "$device_path" ]; then
echo "设备路径不存在或无效: $device_path"
exit 1
fi

# 修改设备的 power wakeup 状态
echo $switch | sudo tee "$device_path" > /dev/null

# 确认修改结果
new_result=$(cat "$device_path")
echo "设备 $modify_device 的 power wakeup 状态已设置为: $new_result"

效果如图,根据自行需要进行修改usb设备唤醒功能


usb-wakeup
https://tomwithkernel.github.io/usb/wakeup/
作者
Tom
发布于
2024年11月11日
更新于
2024年11月11日
许可协议