usb hid gadget模拟鼠标键盘

以下所有的内容我是参考内核文档来的,位置:lichee/linux-3.3/Documentation/usb/gadget_hid.txt


1、修改lichee/linux-3.3/drivers/usb/gadget/hid.c文件

添加内容如下:

#include <linux/platform_device.h>
#include <linux/usb/g_hid.h>

/* 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                         */
	} 
};

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)
{
	int status;

	status = platform_device_register(&my_hid);
	if (status < 0) {
		printk("my hid device register failed!\n");
		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);
	usb_composite_unregister(&hidg_driver);

	platform_device_unregister(&my_hid);
}

2、要产生hid的功能涉及两个文件hid.c和f_hid.c

内核配置如下:

usb hid gadget模拟鼠标键盘_第1张图片


3、编译内核: lichee$./buildroot/build_linux.sh -p sun7i

打包内核: lichee$./buildroot/build_linux.sh pack

将镜像烧入内核发现在/dev/目录下长出设备节点:/dev/hidg0


4、另外,hid给应用层提供字符设备操作接口,需要应用程序配合才能产生hid的功能。

应用程序:

/* hid_gadget_test */
#include <pthread.h>
#include <string.h> 
#include <stdio.h> 
#include <ctype.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h>

#define BUF_LEN 512

struct options { 
	const char    *opt;
	unsigned char val; 
};

static struct options kmod[] = { 
	{.opt = "--left-ctrl",		.val = 0x01},
	{.opt = "--right-ctrl",		.val = 0x10},
	{.opt = "--left-shift",		.val = 0x02},
	{.opt = "--right-shift",	.val = 0x20},
	{.opt = "--left-alt",		.val = 0x04},
	{.opt = "--right-alt",		.val = 0x40},
	{.opt = "--left-meta",		.val = 0x08},
	{.opt = "--right-meta",		.val = 0x80},
	{.opt = NULL} 
};

static struct options kval[] = { 
	{.opt = "--return",	.val = 0x28},
	{.opt = "--esc",	.val = 0x29},
	{.opt = "--bckspc",	.val = 0x2a},
	{.opt = "--tab",	.val = 0x2b},
	{.opt = "--spacebar",	.val = 0x2c},
	{.opt = "--caps-lock",	.val = 0x39},
	{.opt = "--f1",		.val = 0x3a},
	{.opt = "--f2",		.val = 0x3b},
	{.opt = "--f3",		.val = 0x3c},
	{.opt = "--f4",		.val = 0x3d},
	{.opt = "--f5",		.val = 0x3e},
	{.opt = "--f6",		.val = 0x3f},
	{.opt = "--f7",		.val = 0x40},
	{.opt = "--f8",		.val = 0x41},
	{.opt = "--f9",		.val = 0x42},
	{.opt = "--f10",	.val = 0x43},
	{.opt = "--f11",	.val = 0x44},
	{.opt = "--f12",	.val = 0x45},
	{.opt = "--insert",	.val = 0x49},
	{.opt = "--home",	.val = 0x4a},
	{.opt = "--pageup",	.val = 0x4b},
	{.opt = "--del",	.val = 0x4c},
	{.opt = "--end",	.val = 0x4d},
	{.opt = "--pagedown",	.val = 0x4e},
	{.opt = "--right",	.val = 0x4f},
	{.opt = "--left",	.val = 0x50},
	{.opt = "--down",	.val = 0x51},
	{.opt = "--kp-enter",	.val = 0x58},
	{.opt = "--up",		.val = 0x52},
	{.opt = "--num-lock",	.val = 0x53},
	{.opt = NULL} 
};

int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
{ 
	char *tok = strtok(buf, " ");
	int key = 0;
	int i = 0;
	for (; tok != NULL; tok = strtok(NULL, " ")) {
		if (strcmp(tok, "--quit") == 0) 
			return -1;
		
		if (strcmp(tok, "--hold") == 0) {
			*hold = 1;
			continue; 
		}
		
		if (key < 6) { 
			for (i = 0; kval[i].opt != NULL; i++) 
				if (strcmp(tok, kval[i].opt) == 0) { 
					report[2 + key++] = kval[i].val;
					break; 
				} 
			if (kval[i].opt != NULL) 
				continue;
		}
		
		if (key < 6) if (islower(tok[0])) { 
			report[2 + key++] = (tok[0] - ('a' - 0x04));
			continue; 
		}
		
		for (i = 0; kmod[i].opt != NULL; i++) 
			if (strcmp(tok, kmod[i].opt) == 0) { 
				report[0] = report[0] | kmod[i].val;
				break; 
			} 
			
		if (kmod[i].opt != NULL) 
			continue;
		
		if (key < 6) 
			fprintf(stderr, "unknown option: %s\n", tok); 
	}

	return 8; 
}

static struct options mmod[] = { 
	{.opt = "--b1", .val = 0x01},
	{.opt = "--b2", .val = 0x02},
	{.opt = "--b3", .val = 0x04},
	{.opt = NULL} 
};

int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
{ 
	char *tok = strtok(buf, " ");
	int mvt = 0;
	int i = 0;
	
	for (; tok != NULL; tok = strtok(NULL, " ")) 
	{
		if (strcmp(tok, "--quit") == 0) 
			return -1;
		
		if (strcmp(tok, "--hold") == 0) {
			*hold = 1;
			continue; 
		}
		
		for (i = 0; mmod[i].opt != NULL; i++) 
			if (strcmp(tok, mmod[i].opt) == 0) { 
				report[0] = report[0] | mmod[i].val;
				break; 
			}
			
		if (mmod[i].opt != NULL) 
			continue;
		
		if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) { 
			errno = 0;
			report[1 + mvt++] = (char)strtol(tok, NULL, 0);
			if (errno != 0) { 
				fprintf(stderr, "Bad value:'%s'\n", tok);
				report[1 + mvt--] = 0; 
			}
			continue; 
		}
		
		fprintf(stderr, "unknown option: %s\n", tok); 
	}

	return 3; 
}

static struct options jmod[] = { 
	{.opt = "--b1",		.val = 0x10},
	{.opt = "--b2",		.val = 0x20},
	{.opt = "--b3",		.val = 0x40},
	{.opt = "--b4",		.val = 0x80},
	{.opt = "--hat1",	.val = 0x00},
	{.opt = "--hat2",	.val = 0x01},
	{.opt = "--hat3",	.val = 0x02},
	{.opt = "--hat4",	.val = 0x03},
	{.opt = "--hatneutral",	.val = 0x04},
	{.opt = NULL} 
};

int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) 
{ 
	char *tok = strtok(buf, " ");
	int mvt = 0;
	int i = 0;
	*hold = 1;
	/* set default hat position: neutral */
	report[3] = 0x04;
	
	for (; tok != NULL; tok = strtok(NULL, " ")) {
		if (strcmp(tok, "--quit") == 0) 
			return -1;
		
		for (i = 0; jmod[i].opt != NULL; i++) 
			if (strcmp(tok, jmod[i].opt) == 0) { 
				report[3] = (report[3] & 0xF0) | jmod[i].val;
				break; 
			}
			
		if (jmod[i].opt != NULL) 
			continue;
		
		if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) { 
			errno = 0;
			report[mvt++] = (char)strtol(tok, NULL, 0);
			
			if (errno != 0) { 
				fprintf(stderr, "Bad value:'%s'\n", tok);
				report[mvt--] = 0; 
			}
			continue; 
		}
		
		fprintf(stderr, "unknown option: %s\n", tok); 
	}

	return 4; 
}

void print_options(char c) 
{ 	
	int i = 0;
	if (c == 'k') { 
		printf("	keyboard options:\n" "		--hold\n"); 
		for (i = 0; kmod[i].opt != NULL; i++) 
			printf("\t\t%s\n", kmod[i].opt); 
		printf("\n	keyboard values:\n" "		[a-z] or\n"); 
		for (i = 0; kval[i].opt != NULL; i++) 
			printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : ""); 
		printf("\n"); 
	} else if (c == 'm') { 
		printf("	mouse options:\n" "		--hold\n"); 
		for (i = 0; mmod[i].opt != NULL; i++) 
			printf("\t\t%s\n", mmod[i].opt); 
		printf("\n	mouse values:\n" "		Two signed numbers\n"
		       "--quit to close\n"); 
	} else { 
		printf("	joystick options:\n");
		for (i = 0; jmod[i].opt != NULL; i++) 
			printf("\t\t%s\n", jmod[i].opt); 
		printf("\n	joystick values:\n" "		three signed numbers\n"
		       "--quit to close\n"); 
	} 
}

int main(int argc, const char *argv[]) 
{ 	
	const char *filename = NULL;
	int fd = 0;
	char buf[BUF_LEN];
	int cmd_len;
	char report[8];
	int to_send = 8;
	int hold = 0;
	fd_set rfds;
	int retval, i;
	
	if (argc < 3) { 
		fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n", argv[0]); 
		return 1; 
	}
	
	if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j') 
		return 2;
	
	filename = argv[1];
	if ((fd = open(filename, O_RDWR, 0666)) == -1) { 
		perror(filename);
		return 3; 
	}
	
	print_options(argv[2][0]);
	while (42) {
		FD_ZERO(&rfds);
		FD_SET(STDIN_FILENO, &rfds);
		FD_SET(fd, &rfds);
		retval = select(fd + 1, &rfds, NULL, NULL, NULL);
		if (retval == -1 && errno == EINTR) continue; if (retval < 0) { 
			perror("select()");
			return 4; 
		}
		if (FD_ISSET(fd, &rfds)) { 
			cmd_len = read(fd, buf, BUF_LEN - 1);
			printf("recv report:");
			for (i = 0; i < cmd_len; i++)
				printf(" %02x", buf[i]); printf("\n"); 
		}
		if (FD_ISSET(STDIN_FILENO, &rfds)) { 
			memset(report, 0x0, sizeof(report));
			cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
			if (cmd_len == 0) 
				break;
			buf[cmd_len - 1] = '\0';
			hold = 0;
			memset(report, 0x0, sizeof(report));
			if (argv[2][0] == 'k') 
				to_send = keyboard_fill_report(report, buf, &hold); 
			else if (argv[2][0] == 'm') 
				to_send = mouse_fill_report(report, buf, &hold); 
			else 
				to_send = joystick_fill_report(report, buf, &hold);
			if (to_send == -1) 
				break;
			if (write(fd, report, to_send) != to_send) { 
				perror(filename);
				return 5; 
			}
			if (!hold) { 
				memset(report, 0x0, sizeof(report));
				if (write(fd, report, to_send) != to_send) { 
					perror(filename);
					return 6; 
				} 
			}
		} 
	}
	close(fd);
	return 0; 
} 


5、编译应用程序

arm-linux-gnueabi-gcc hid_gadget_test.c -o hid_gadget_test

执行如下:




部分参考自:

http://www.oschina.net/question/1174645_135969

http://blog.chinaunix.net/uid-27661165-id-3330346.html

你可能感兴趣的:(usb hid gadget模拟鼠标键盘)