【USB开发 】用pcDuino的otg做鼠标键盘

pc朵拉 发布于 2013/12/04 14:07
阅读 2K+
收藏 2

有人说现代社会,计算机锁住了人类的双手,为什么呢?因为基本上一个人一天上班8小时手是不断的在键盘鼠标上面工作的。我们能不能让电脑更智 能一些,例如电脑放弃人类的双手 ,更智能的工作,这里pcDuino跟你提过一个建议。让兼容arduino的各种传感器去采集信号,让pcDuino帮你实现鼠标键盘的各种工作。


QQ图片20131022100317

一,修改内核

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[i].opt != NULL; i++)

 84                 if (strcmp(tok, kval[i].opt) == 0) {

 85                     report[2 + key++] = kval[i].val;

 86                     break;

 87                 }

 88             if (kval[i].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[i].opt != NULL; i++)

 99             if (strcmp(tok, kmod[i].opt) == 0) {

100                 report[0] = report[0] | kmod[i].val;

101                 break;

102             }

103         if (kmod[i].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[i].opt != NULL; i++)

135             if (strcmp(tok, mmod[i].opt) == 0) {

136                 report[0] = report[0] | mmod[i].val;

137                 break;

138             }

139         if (mmod[i].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[i].opt != NULL; i++)

187             if (strcmp(tok, jmod[i].opt) == 0) {

188                 report[3] = (report[3] & 0xF0) | jmod[i].val;

189                 break;

190             }

191         if (jmod[i].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[i].opt != NULL; i++)

217             printf(“\t\t%s\n”, kmod[i].opt);

218         printf(“\n  keyboard values:\n”

219                “        [a-z] or\n”);

220         for (i = 0; kval[i].opt != NULL; i++)

221             printf(“\t\t%-8s%s”, kval[i].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[i].opt != NULL; i++)

227             printf(“\t\t%s\n”, mmod[i].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[i].opt != NULL; i++)

234             printf(“\t\t%s\n”, jmod[i].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[i]);

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
加载中
返回顶部
顶部