linux内核模拟按键,linux下使用gadget模拟hid键盘

1. 环境

linux内核版本

1Linux (none) 3.10.14 #4 PREEMPT Wed May 2 16:42:10 CST 2018 mips GNU/Linux

2. 使用linux下的gadget来实现模拟hid键盘输入

修改linux内核配置选项开启”HID Gadget”功能

1

2

3

4

5

6

7root@dong-VirtualBox:~/opt/ingenic-linux-kernel3.10.14# make menuconfig

Device Drivers --->

[*] USB support --->

USB Gadget Support --->

USB Gadget Drivers (HID Gadget) --->

(X) HID Gadget

3. 修改linux内核代码 “kernel/drivers/usb/gadget/hid.c”

在文件中增加以下代码后,重新编译内核,将内核镜像下载到设备中,在/dev目录下我们会看到设备节点”/dev/hidg0”,这个新的设备节点名就是我们刚刚加入的hid模拟键盘设备节点,接下来我们就可以针对该节点进行读写,就可以模拟HID键盘输出了。

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//add

/* hid descriptor for a keyboard */

static struct hidg_func_descriptor my_hid_data = {

.subclass = 0, /* No subclass */

.protocol = 1, /* Keyboard */

.report_length = 8,

.report_desc_length = 63,

.report_desc = {

0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */

0x09, 0x06, /* USAGE (Keyboard) */

0xa1, 0x01, /* COLLECTION (Application) */

0x05, 0x07, /* USAGE_PAGE (Keyboard) */

0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */

0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */

0x15, 0x00, /* LOGICAL_MINIMUM (0) */

0x25, 0x01, /* LOGICAL_MAXIMUM (1) */

0x75, 0x01, /* REPORT_SIZE (1) */

0x95, 0x08, /* REPORT_COUNT (8) */

0x81, 0x02, /* INPUT (Data,Var,Abs) */

0x95, 0x01, /* REPORT_COUNT (1) */

0x75, 0x08, /* REPORT_SIZE (8) */

0x81, 0x03, /* INPUT (Cnst,Var,Abs) */

0x95, 0x05, /* REPORT_COUNT (5) */

0x75, 0x01, /* REPORT_SIZE (1) */

0x05, 0x08, /* USAGE_PAGE (LEDs) */

0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */

0x29, 0x05, /* USAGE_MAXIMUM (Kana) */

0x91, 0x02, /* OUTPUT (Data,Var,Abs) */

0x95, 0x01, /* REPORT_COUNT (1) */

0x75, 0x03, /* REPORT_SIZE (3) */

0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */

0x95, 0x06, /* REPORT_COUNT (6) */

0x75, 0x08, /* REPORT_SIZE (8) */

0x15, 0x00, /* LOGICAL_MINIMUM (0) */

0x25, 0x65, /* LOGICAL_MAXIMUM (101) */

0x05, 0x07, /* USAGE_PAGE (Keyboard) */

0x19, 0x00, /* USAGE_MINIMUM (Reserved) */

0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */

0x81, 0x00, /* INPUT (Data,Ary,Abs) */

0xc0 /* END_COLLECTION */

}

};

...

/****************************** Some noise ******************************/

//add

static struct platform_device my_hid = {

.name = "hidg",

.id = 0,

.num_resources = 0,

.resource = 0,

.dev.platform_data = &my_hid_data,

};

......

static int __init hidg_init(void)

{

//add

status = platform_device_register(&my_hid);

if (status < 0)

{

platform_driver_unregister(&my_hid);

return status;

}

...

return status;

}

static void __exit hidg_cleanup(void)

{

//add

platform_device_unregister(&my_hid);

...

}

4. Demo1

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#include "virtual_keyboard.h"

#include

int main(int argc, const char *argv[])

{

int ret = 0;

unsigned char keyboardChar[]= "1234567890abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWSYZ"

"`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>?\n";

ret = virtual_keyboard_open("/dev/hidg0");

if(ret < 0)

{

return -1;

}

while(1)

{

ret = virtual_keyboard_write(keyboardChar, 95);

if(ret < 0)

{

break;

}

sleep(5);

}

virtual_keyboard_close();

return 0;

}

5. 完整源码: 点击下载

下载后hid.c文件可直接替换内核源码中”kernel/drivers/usb/gadget/hid.c”文件。

未处理的hid setup指令:

在上面步骤修改完成后,把设备插入到usb接口,在PC的设备管理器就可以识别出来人体输入学设备,基本上我们可以使用了。 但是我们为使设备在不同系统下使用均无问题。我们使用Bus Hound 6.01软件观察设备上电枚举数据,发现有”USTS c0000004”问题,使用USB分析仪跟踪USB上电枚举数据发现usb setupt包中Class request Out(0x0A)指令未处理。

分析

Bus Hound数据:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20Device Length Phase Data Description

------ -------- ----- -------------------------------------------------- ----------------

18.0 CTL 80 06 00 01 00 00 12 00 GET DESCRIPTOR

18.0 18 IN 12 01 00 02 00 00 00 40 c1 22 02 0e 10 03 01 02 .......@."......

00 01 ..

18.0 CTL 80 06 00 02 00 00 09 00 GET DESCRIPTOR

18.0 9 IN 09 02 2c 00 01 01 00 e0 01 ..,......

18.0 CTL 80 06 00 02 00 00 2c 00 GET DESCRIPTOR

18.0 44 IN 09 02 2c 00 01 01 00 e0 01 03 09 03 09 04 00 00 ..,.............

02 03 00 01 04 09 21 01 01 00 01 22 3f 00 07 05 ......!...."?...

81 03 08 00 04 07 05 01 03 08 00 04 ............

18.0 CTL 00 09 01 00 00 00 00 00 SET CONFIG

18.0 CTL 21 0a 00 00 00 00 00 00 SET IDLE

18.0 USTS c0000004 stall pid

18.0 CTL 81 06 00 22 00 00 7f 00 GET DESCRIPTOR

18.0 63 IN 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 ..........)...%.

75 01 95 08 81 02 95 01 75 08 81 03 95 05 75 01 u.......u.....u.

05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 06 ....).....u.....

75 08 15 00 25 65 05 07 19 00 29 65 81 00 c0 u...%e....)e...

18.1 1 OUT 00 .

USB分析仪数据:

f5368501ae5faf2067e4e4fb658c21a4.png

Class request Out (0x0A)

主控制器发出包:21 0A 00 00 00 00 00 00

从设备应答包:No data

Setup request:

Name

Value

Dec

Hex

bmRequestType.Recipient

Interface

1

0x01

bmRequestType.Type

Class

1

0x1

bmRequestType.Direction

Host-to-device

0

0x0

bRequest

Class: 0x0A (Findout moren online)

10

0x0A

wValue

0x0000

0

0x0000

wIndex

0x0000

0

0x0000

wLength

0

0

0x0000

解决

经过分析发现设备在上电枚举过程中的setup包处理有问题,没有处理”Class request Out (0x0A)”指令。既然问题找到了,那么接下来就好办了。修改linux内核文件”kernel/drivers/usb/gadget/f_hid.c”

在最后的default分支前加入以下代码:

1

2

3

4

5

6

7

8//add

case((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8

| USB_REQ_GET_INTERFACE):

VDBG(cdev, "get_interface\n");

length = min_t(unsigned short, length, hidg->report_length);

memset(req->buf, 0x0, length);

goto respond;

break;

代码结构如下:

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

42static int hidg_setup(struct usb_function *f,

const struct usb_ctrlrequest *ctrl)

{

...

switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {

...

case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8

| USB_REQ_GET_DESCRIPTOR):

switch (value >> 8) {

...

default:

VDBG(cdev, "Unknown descriptor request 0x%x\n",

value >> 8);

goto stall;

break;

}

break;

//add

case((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8

| USB_REQ_GET_INTERFACE):

VDBG(cdev, "get_interface\n");

length = min_t(unsigned short, length, hidg->report_length);

memset(req->buf, 0x0, length);

goto respond;

break;

default:

VDBG(cdev, "Unknown request 0x%x\n",

ctrl->bRequest);

goto stall;

break;

}

...

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值