有人说现代社会,计算机锁住了人类的双手,为什么呢?因为基本上一个人一天上班8小时手是不断的在键盘鼠标上面工作的。我们能不能让电脑更智 能一些,例如电脑放弃人类的双手 ,更智能的工作,这里pcDuino跟你提过一个建议。让兼容arduino的各种传感器去采集信号,让pcDuino帮你实现鼠标键盘的各种工作。
一,修改内核
vim vim linux-sunxi/drivers/usb/gadget/hid.c #在里面添加几个结构体和几行代码
static LIST_HEAD(hidg_func_list);
/* hid descriptor for a keyboard */
static struct hidg_func_descriptor pcduino_keyboard_date = {
.subclass = 0, /* No subclass */
.protocol = 1, /* Keyboard */
.report_length = 8,
.report_desc_length = 63,
.report_desc = {
0×05, 0×01, /* USAGE_PAGE (Generic Desktop) */
0×09, 0×06, /* USAGE (Keyboard) */
0xa1, 0×01, /* COLLECTION (Application) */
0×05, 0×07, /* USAGE_PAGE (Keyboard) */
0×19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0×29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0×15, 0×00, /* LOGICAL_MINIMUM (0) */
0×25, 0×01, /* LOGICAL_MAXIMUM (1) */
0×75, 0×01, /* REPORT_SIZE (1) */
0×95, 0×08, /* REPORT_COUNT (8) */
0×81, 0×02, /* INPUT (Data,Var,Abs) */
0×95, 0×01, /* REPORT_COUNT (1) */
0×75, 0×08, /* REPORT_SIZE (8) */
0×81, 0×03, /* INPUT (Cnst,Var,Abs) */
0×95, 0×05, /* REPORT_COUNT (5) */
0×75, 0×01, /* REPORT_SIZE (1) */
0×05, 0×08, /* USAGE_PAGE (LEDs) */
0×19, 0×01, /* USAGE_MINIMUM (Num Lock) */
0×29, 0×05, /* USAGE_MAXIMUM (Kana) */
0×91, 0×02, /* OUTPUT (Data,Var,Abs) */
0×95, 0×01, /* REPORT_COUNT (1) */
0×75, 0×03, /* REPORT_SIZE (3) */
0×91, 0×03, /* OUTPUT (Cnst,Var,Abs) */
0×95, 0×06, /* REPORT_COUNT (6) */
0×75, 0×08, /* REPORT_SIZE (8) */
0×15, 0×00, /* LOGICAL_MINIMUM (0) */
0×25, 0×65, /* LOGICAL_MAXIMUM (101) */
0×05, 0×07, /* USAGE_PAGE (Keyboard) */
0×19, 0×00, /* USAGE_MINIMUM (Reserved) */
0×29, 0×65, /* USAGE_MAXIMUM (Keyboard Application) */
0×81, 0×00, /* INPUT (Data,Ary,Abs) */
0xc0 /* END_COLLECTION */
}
};
static struct platform_device pcduino_hid_keyboard = {
.name = “hidg”,
.id = 0,
.num_resources = 0,
.resource = 0,
.dev.platform_data = &pcduino_keyboard_date,
};
/* hid descriptor for a mouse */
static struct hidg_func_descriptor pcduino_mouse_data = {
.subclass = 0, //No SubClass
.protocol = 2, //Mouse
.report_length = 4,
.report_desc_length = 52,
.report_desc = {
0×05, 0×01, //Usage Page(Generic Desktop Controls)
0×09, 0×02, //Usage (Mouse)
0xa1, 0×01, //Collction (Application)
0×09, 0×01, //Usage (pointer)
0xa1, 0×00, //Collction (Physical)
0×05, 0×09, //Usage Page (Button)
0×19, 0×01, //Usage Minimum(1)
0×29, 0×05, //Usage Maximum(5)
0×15, 0×00, //Logical Minimum(1)
0×25, 0×01, //Logical Maximum(1)
0×95, 0×05, //Report Count(5)
0×75, 0×01, //Report Size(1)
0×81, 0×02, //Input(Data,Variable,Absolute,BitField)
0×95, 0×01, //Report Count(1)
0×75, 0×03, //Report Size(3)
0×81, 0×01, //Input(Constant,Array,Absolute,BitField)
0×05, 0×01, //Usage Page(Generic Desktop Controls)
0×09, 0×30, //Usage(x)
0×09, 0×31, //Usage(y)
0×09, 0×38, //Usage(Wheel)
0×15, 0×81, //Logical Minimum(-127)
0×25, 0x7F, //Logical Maximum(127)
0×75, 0×08, //Report Size(8)
0×95, 0×03, //Report Count(3)
0×81, 0×06, //Input(Data,Variable,Relative,BitField)
0xc0, //End Collection
0xc0 //End Collection
}
};
static struct platform_device pcduino_hid_mouse = {
.name = “hidg”,
.id = 1,
.num_resources = 0,
.resource = 0,
.dev.platform_data = &pcduino_mouse_data,
};
static int __init hidg_init(void)
{
int status;
status = platform_device_register(&pcduino_hid_keyboard);
if (status < 0) {
printk(“hid keyboard reg failed\n”);
platform_device_unregister(&pcduino_hid_keyboard);
return status;
}
status = platform_device_register(&pcduino_hid_mouse);
if (status < 0) {
printk(“hid mouse reg failed\n”);
platform_device_unregister(&pcduino_hid_mouse);
return status;
}
status = platform_driver_probe(&hidg_plat_driver,
hidg_plat_driver_probe);
if (status < 0)
return status;
status = usb_composite_probe(&hidg_driver, hid_bind);
if (status < 0)
platform_driver_unregister(&hidg_plat_driver);
return status;
}
module_init(hidg_init);
static void __exit hidg_cleanup(void)
{
platform_driver_unregister(&hidg_plat_driver);
platform_device_unregister(&pcduino_hid_keyboard);
platform_device_unregister(&pcduino_hid_mouse);
usb_composite_unregister(&hidg_driver);
}
结构体是需要添加的,后面两个函数里面要加上结构注册。这里说明一下,根据usb协议,每一个设备都要有描述符,两个结构体就是hid 鼠标键盘的描述符。下面配置内核。
Device Drivers —>
USB support —>
<M> USB Gadget Support —>
<M> SoftWinner SUN4I USB Peripheral Controller
< > Dummy HCD (DEVELOPMENT)
USB Gadget Drivers
< > Gadget Zero (DEVELOPMENT)
< > Audio Gadget (EXPERIMENTAL)
<M> Ethernet Gadget (with CDC Ethernet support)
RNDIS support
[ ] Ethernet Emulation Model (EEM) support
< > Network Control Model (NCM) support
< > Gadget Filesystem (EXPERIMENTAL)
< > Function Filesystem (EXPERIMENTAL)
< > File-backed Storage Gadget (DEPRECATED)
< > Mass Storage Gadget
<M> Serial Gadget (with CDC ACM and CDC OBEX support)
<M> MIDI Gadget (EXPERIMENTAL)
<M> Printer Gadget
< > CDC Composite Device (Ethernet and ACM)
< > CDC Composite Device (ACM and mass storage)
< > Multifunction Composite Gadget (EXPERIMENTAL)
<M> HID Gadget
< > EHCI Debug Device Gadget
< > USB Webcam Gadget
二,加载内核 关于怎么使用编译生成的内核,已经写过好多文章了。这里大致提一下。
sudo mount /dev/nanda /mnt
tar xvf pcduino_a10_hwpack_20131129.tar.xz
cp kernel/* /mnt -f
cp rootfs/lib/modules/3.4.29+ /lib/modules/
vim /etc/modules #添加下面内容
sw_usb_udc
g_hid
三,测试驱动
这里测试用到的是linux-sunxi/Documentation/usb里面的测试程序。
1 /* hid_gadget_test */
2
3 #include <pthread.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12
13 #define BUF_LEN 512
14
15 struct options {
16 const char *opt;
17 unsigned char val;
18 };
19
20 static struct options kmod[] = {
21 {.opt = “–left-ctrl”, .val = 0×01},
22 {.opt = “–right-ctrl”, .val = 0×10},
23 {.opt = “–left-shift”, .val = 0×02},
24 {.opt = “–right-shift”, .val = 0×20},
25 {.opt = “–left-alt”, .val = 0×04},
26 {.opt = “–right-alt”, .val = 0×40},
27 {.opt = “–left-meta”, .val = 0×08},
28 {.opt = “–right-meta”, .val = 0×80},
29 {.opt = NULL}
30 };
31
32 static struct options kval[] = {
33 {.opt = “–return”, .val = 0×28},
34 {.opt = “–esc”, .val = 0×29},
35 {.opt = “–bckspc”, .val = 0x2a},
36 {.opt = “–tab”, .val = 0x2b},
37 {.opt = “–spacebar”, .val = 0x2c},
38 {.opt = “–caps-lock”, .val = 0×39},
39 {.opt = “–f1″, .val = 0x3a},
40 {.opt = “–f2″, .val = 0x3b},
41 {.opt = “–f3″, .val = 0x3c},
42 {.opt = “–f4″, .val = 0x3d},
43 {.opt = “–f5″, .val = 0x3e},
44 {.opt = “–f6″, .val = 0x3f},
45 {.opt = “–f7″, .val = 0×40},
46 {.opt = “–f8″, .val = 0×41},
47 {.opt = “–f9″, .val = 0×42},
48 {.opt = “–f10″, .val = 0×43},
49 {.opt = “–f11″, .val = 0×44},
50 {.opt = “–f12″, .val = 0×45},
51 {.opt = “–insert”, .val = 0×49},
52 {.opt = “–home”, .val = 0x4a},
53 {.opt = “–pageup”, .val = 0x4b},
54 {.opt = “–del”, .val = 0x4c},
55 {.opt = “–end”, .val = 0x4d},
56 {.opt = “–pagedown”, .val = 0x4e},
57 {.opt = “–right”, .val = 0x4f},
58 {.opt = “–left”, .val = 0×50},
59 {.opt = “–down”, .val = 0×51},
60 {.opt = “–kp-enter”, .val = 0×58},
61 {.opt = “–up”, .val = 0×52},
62 {.opt = “–num-lock”, .val = 0×53},
63 {.opt = NULL}
64 };
65
66 int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
67 {
68 char *tok = strtok(buf, ” “);
69 int key = 0;
70 int i = 0;
71
72 for (; tok != NULL; tok = strtok(NULL, ” “)) {
73
74 if (strcmp(tok, “–quit”) == 0)
75 return -1;
76
77 if (strcmp(tok, “–hold”) == 0) {
78 *hold = 1;
79 continue;
80 }
81
82 if (key < 6) {
83 for (i = 0; kval.opt != NULL; i++)
84 if (strcmp(tok, kval.opt) == 0) {
85 report[2 + key++] = kval.val;
86 break;
87 }
88 if (kval.opt != NULL)
89 continue;
90 }
91
92 if (key < 6)
93 if (islower(tok[0])) {
94 report[2 + key++] = (tok[0] – (‘a’ – 0×04));
95 continue;
96 }
97
98 for (i = 0; kmod.opt != NULL; i++)
99 if (strcmp(tok, kmod.opt) == 0) {
100 report[0] = report[0] | kmod.val;
101 break;
102 }
103 if (kmod.opt != NULL)
104 continue;
105
106 if (key < 6)
107 fprintf(stderr, “unknown option: %s\n”, tok);
108 }
109 return 8;
110 }
111
112 static struct options mmod[] = {
113 {.opt = “–b1″, .val = 0×01},
114 {.opt = “–b2″, .val = 0×02},
115 {.opt = “–b3″, .val = 0×04},
116 {.opt = NULL}
117 };
118
119 int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
120 {
121 char *tok = strtok(buf, ” “);
122 int mvt = 0;
123 int i = 0;
124 for (; tok != NULL; tok = strtok(NULL, ” “)) {
125
126 if (strcmp(tok, “–quit”) == 0)
127 return -1;
128
129 if (strcmp(tok, “–hold”) == 0) {
130 *hold = 1;
131 continue;
132 }
133
134 for (i = 0; mmod.opt != NULL; i++)
135 if (strcmp(tok, mmod.opt) == 0) {
136 report[0] = report[0] | mmod.val;
137 break;
138 }
139 if (mmod.opt != NULL)
140 continue;
141
142 if (!(tok[0] == ‘-’ && tok[1] == ‘-’) && mvt < 2) {
143 errno = 0;
144 report[1 + mvt++] = (char)strtol(tok, NULL, 0);
145 if (errno != 0) {
146 fprintf(stderr, “Bad value:’%s’\n”, tok);
147 report[1 + mvt--] = 0;
148 }
149 continue;
150 }
151
152 fprintf(stderr, “unknown option: %s\n”, tok);
153 }
154 return 3;
155 }
156
157 static struct options jmod[] = {
158 {.opt = “–b1″, .val = 0×10},
159 {.opt = “–b2″, .val = 0×20},
160 {.opt = “–b3″, .val = 0×40},
161 {.opt = “–b4″, .val = 0×80},
162 {.opt = “–hat1″, .val = 0×00},
163 {.opt = “–hat2″, .val = 0×01},
164 {.opt = “–hat3″, .val = 0×02},
165 {.opt = “–hat4″, .val = 0×03},
166 {.opt = “–hatneutral”, .val = 0×04},
167 {.opt = NULL}
168 };
169
170 int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
171 {
172 char *tok = strtok(buf, ” “);
173 int mvt = 0;
174 int i = 0;
175
176 *hold = 1;
177
178 /* set default hat position: neutral */
179 report[3] = 0×04;
180
181 for (; tok != NULL; tok = strtok(NULL, ” “)) {
182
183 if (strcmp(tok, “–quit”) == 0)
184 return -1;
185
186 for (i = 0; jmod.opt != NULL; i++)
187 if (strcmp(tok, jmod.opt) == 0) {
188 report[3] = (report[3] & 0xF0) | jmod.val;
189 break;
190 }
191 if (jmod.opt != NULL)
192 continue;
193
194 if (!(tok[0] == ‘-’ && tok[1] == ‘-’) && mvt < 3) {
195 errno = 0;
196 report[mvt++] = (char)strtol(tok, NULL, 0);
197 if (errno != 0) {
198 fprintf(stderr, “Bad value:’%s’\n”, tok);
199 report[mvt--] = 0;
200 }
201 continue;
202 }
203
204 fprintf(stderr, “unknown option: %s\n”, tok);
205 }
206 return 4;
207 }
208
209 void print_options(char c)
210 {
211 int i = 0;
212
213 if (c == ‘k’) {
214 printf(“ keyboard options:\n”
215 “ –hold\n”);
216 for (i = 0; kmod.opt != NULL; i++)
217 printf(“\t\t%s\n”, kmod.opt);
218 printf(“\n keyboard values:\n”
219 “ [a-z] or\n”);
220 for (i = 0; kval.opt != NULL; i++)
221 printf(“\t\t%-8s%s”, kval.opt, i % 2 ? “\n” : “”);
222 printf(“\n”);
223 } else if (c == ‘m’) {
224 printf(“ mouse options:\n”
225 “ –hold\n”);
226 for (i = 0; mmod.opt != NULL; i++)
227 printf(“\t\t%s\n”, mmod.opt);
228 printf(“\n mouse values:\n”
229 ” Two signed numbers\n”
230 “–quit to close\n”);
231 } else {
232 printf(“ joystick options:\n”);
233 for (i = 0; jmod.opt != NULL; i++)
234 printf(“\t\t%s\n”, jmod.opt);
235 printf(“\n joystick values:\n”
236 “ three signed numbers\n”
237 “–quit to close\n”);
238 }
239 }
240
241 int main(int argc, const char *argv[])
242 {
243 const char *filename = NULL;
244 int fd = 0;
245 char buf[BUF_LEN];
246 int cmd_len;
247 char report[8];
248 int to_send = 8;
249 int hold = 0;
250 fd_set rfds;
251 int retval, i;
252
253 if (argc < 3) {
254 fprintf(stderr, “Usage: %s devname mouse|keyboard|joystick\n”,
255 argv[0]);
256 return 1;
257 }
258
259 if (argv[2][0] != ‘k’ && argv[2][0] != ‘m’ && argv[2][0] != ‘j’)
260 return 2;
261
262 filename = argv[1];
263
264 if ((fd = open(filename, O_RDWR, 0666)) == -1) {
265 perror(filename);
266 return 3;
267 }
268
269 print_options(argv[2][0]);
270
271 while (42) {
272
273 FD_ZERO(&rfds);
274 FD_SET(STDIN_FILENO, &rfds);
275 FD_SET(fd, &rfds);
276
277 retval = select(fd + 1, &rfds, NULL, NULL, NULL);
278 if (retval == -1 && errno == EINTR)
279 continue;
280 if (retval < 0) {
281 perror(“select()”);
282 return 4;
283 }
284
285 if (FD_ISSET(fd, &rfds)) {
286 cmd_len = read(fd, buf, BUF_LEN – 1);
287 printf(“recv report:”);
288 for (i = 0; i < cmd_len; i++)
289 printf(” %02x”, buf);
290 printf(“\n”);
291 }
292
293 if (FD_ISSET(STDIN_FILENO, &rfds)) {
294 memset(report, 0×0, sizeof(report));
295 cmd_len = read(STDIN_FILENO, buf, BUF_LEN – 1);
296
297 if (cmd_len == 0)
298 break;
299
300 buf[cmd_len - 1] = ‘\0′;
301 hold = 0;
302
303 memset(report, 0×0, sizeof(report));
304 if (argv[2][0] == ‘k’)
305 to_send = keyboard_fill_report(report, buf, &hold);
306 else if (argv[2][0] == ‘m’)
307 to_send = mouse_fill_report(report, buf, &hold);
308 else
309 to_send = joystick_fill_report(report, buf, &hold);
310
311 if (to_send == -1)
312 break;
313
314 if (write(fd, report, to_send) != to_send) {
315 perror(filename);
316 return 5;
317 }
318 if (!hold) {
319 memset(report, 0×0, sizeof(report));
320 if (write(fd, report, to_send) != to_send) {
321 perror(filename);
322 return 6;
323 }
324 }
325 }
326 }
327
328 close(fd);
329 return 0;
330 }
编译:gcc gadget_hid.c
运行:
root@ubuntu:/home/ubuntu# ./a.out /dev/hidg0 k # 键盘
keyboard options:
–hold
–left-ctrl
–right-ctrl
–left-shift
–right-shift
–left-alt
–right-alt
–left-meta
–right-meta
keyboard values:
[a-z] or
–return –esc
–bckspc –tab
–spacebar –caps-lock
–f1 –f2
–f3 –f4
–f5 –f6
–f7 –f8
–f9 –f10
–f11 –f12
–insert –home
–pageup –del
–end –pagedown
–right –left
–down –kp-enter
–up –num-lock
根据提示输入: a b c d e f
你电脑上可以看到已经有显示了。
root@ubuntu:/home/ubuntu# ./a.out /dev/hidg1 m #鼠标
mouse options:
–hold
–b1
–b2
–b3
mouse values:
Two signed numbers
–quit to close
说明一下
–b1 10 10
执行这个的时候,相当于鼠标左键。
–b2 1
执行这个的时候,相等于鼠标右键
–b3 -10 100
这个相当于移动鼠标。
四,用joystick做鼠标 这里代码太多了,今天写了一天,我就不贴,你可以到
https://github.com/Pillar1989/arduino
我git上面下载,直接运行output/test/usb
joystick接的是pcDuino的A4和A5,由于里面有个delay(500)。所有移动的时候桌面有些卡顿。具体的演示,就看你自己的了。
五,补充USB协议 下面是自己整理的鼠标键盘的通信格式,如果你有兴趣可以研究一下。
鼠标发送给PC的数据每次4个字节
BYTE1 BYTE2 BYTE3 BYTE4
定义分别是:
BYTE1 –
|–bit7: 1 表示 Y 坐标的变化量超出-256 ~ 255的范围,0表示没有溢出
|–bit6: 1 表示 X 坐标的变化量超出-256 ~ 255的范围,0表示没有溢出
|–bit5: Y 坐标变化的符号位,1表示负数,即鼠标向下移动
|–bit4: X 坐标变化的符号位,1表示负数,即鼠标向左移动
|–bit3: 恒为1
|–bit2: 1表示中键按下
|–bit1: 1表示右键按下
|–bit0: 1表示左键按下
BYTE2 — X坐标变化量,与byte的bit4组成9位符号数,负数表示向左移,正数表右移。用补码表示变化量
BYTE3 — Y坐标变化量,与byte的bit5组成9位符号数,负数表示向下移,正数表上移。用补码表示变化量
BYTE4 — 滚轮变化。
由于手上没有USB鼠标,对BYTE1的4-7位没有测试,对于BYTE2 BYTE3做个测试,BYTE1的4-7全为0的时候,BYTE2 BYTE3的正负表示鼠标移动方向
键盘发送给PC的数据每次8个字节
BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
定义分别是:
BYTE1 –
|–bit0: Left Control是否按下,按下为1
|–bit1: Left Shift 是否按下,按下为1
|–bit2: Left Alt 是否按下,按下为1
|–bit3: Left GUI 是否按下,按下为1
|–bit4: Right Control是否按下,按下为1
|–bit5: Right Shift 是否按下,按下为1
|–bit6: Right Alt 是否按下,按下为1
|–bit7: Right GUI 是否按下,按下为1
BYTE2 — 暂不清楚,有的地方说是保留位
BYTE3–BYTE8 — 这六个为普通按键
键盘经过测试。
例如:键盘发送一帧数据 02 00 0×04 0×05 00 00 00 00
表示同时按下了Left Shift + ‘a’+‘b’三个键
附件里面是usb协议中文版,喜欢折腾的可以看看。USB1.1协议中文版
帖子出自:http://cnlearn.linksprite.com/?p=1531
|