From 6fb6f786548710f0a5d457624438c793d2fe4f5b Mon Sep 17 00:00:00 2001 From: HandsomeYingyan Date: Thu, 20 Jan 2022 16:52:55 +0800 Subject: [PATCH] initial commit --- CMakeLists.txt | 37 ++++++ gc_acm.c | 57 +++++++++ gc_acm.h | 21 ++++ gc_config.h | 43 +++++++ gc_config.h.in | 43 +++++++ gc_ecm.c | 57 +++++++++ gc_ecm.h | 21 ++++ gc_ffs.c | 59 +++++++++ gc_ffs.h | 23 ++++ gc_generic.c | 251 ++++++++++++++++++++++++++++++++++++++ gc_generic.h | 62 ++++++++++ gc_hid.c | 103 ++++++++++++++++ gc_hid.h | 23 ++++ gc_list.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++ gc_list.h | 35 ++++++ gc_midi.c | 68 +++++++++++ gc_midi.h | 21 ++++ gc_printer.c | 58 +++++++++ gc_printer.h | 22 ++++ gc_rndis.c | 82 +++++++++++++ gc_rndis.h | 21 ++++ gc_serial.c | 58 +++++++++ gc_serial.h | 21 ++++ gc_storage.c | 88 ++++++++++++++ gc_storage.h | 23 ++++ gc_uvc.c | 125 +++++++++++++++++++ gc_uvc.h | 24 ++++ main.c | 153 +++++++++++++++++++++++ readme.md | 45 +++++++ 29 files changed, 1968 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 gc_acm.c create mode 100644 gc_acm.h create mode 100644 gc_config.h create mode 100644 gc_config.h.in create mode 100644 gc_ecm.c create mode 100644 gc_ecm.h create mode 100644 gc_ffs.c create mode 100644 gc_ffs.h create mode 100644 gc_generic.c create mode 100644 gc_generic.h create mode 100644 gc_hid.c create mode 100644 gc_hid.h create mode 100644 gc_list.c create mode 100644 gc_list.h create mode 100644 gc_midi.c create mode 100644 gc_midi.h create mode 100644 gc_printer.c create mode 100644 gc_printer.h create mode 100644 gc_rndis.c create mode 100644 gc_rndis.h create mode 100644 gc_serial.c create mode 100644 gc_serial.h create mode 100644 gc_storage.c create mode 100644 gc_storage.h create mode 100644 gc_uvc.c create mode 100644 gc_uvc.h create mode 100644 main.c create mode 100644 readme.md diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5830f00 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,37 @@ +# +# Copyright (C) 2021 HandsomeMod Project +# +# GC (Gadget Controller) is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +cmake_minimum_required(VERSION 3.10) +project(GC C) + +set(CMAKE_C_STANDARD 11)#C11 +set(CMAKE_CXX_STANDARD 17)#C17 +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INSTALL_PREFIX /usr) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}) +#file(GLOB_RECURSE INCLUDES "gc_*.h") +file(GLOB_RECURSE SOURCES "main.c" "gc_*.c") +SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) + + +# Core Dependency +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBUSBGX REQUIRED libusbgx) +list(APPEND EXTRA_LIBS ${LIBUSBGX_LIBRARIES}) +list(APPEND EXTRA_INCLUDES ${LIBUSBGX_INCLUDE_DIRS}) + +# generated headers +configure_file ( + "gc_config.h.in" + "${PROJECT_SOURCE_DIR}/gc_config.h" +) + +include_directories(${EXTRA_INCLUDES} ${INCLUDES}) +add_executable(gc ${SOURCES}) +target_link_libraries(gc PRIVATE ${EXTRA_LIBS}) +install(FILES ${PROJECT_SOURCE_DIR}/bin/gc DESTINATION bin) diff --git a/gc_acm.c b/gc_acm.c new file mode 100644 index 0000000..fe35477 --- /dev/null +++ b/gc_acm.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include "gc_acm.h" + +int gc_acm_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_acm; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_ACM); + + if(id == NULL) + return GC_FAILED; + + usbg_ret = usbg_create_function(gadget,USBG_F_ACM,id,NULL,&f_acm); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create acm function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_acm); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind ecm config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} diff --git a/gc_acm.h b/gc_acm.h new file mode 100644 index 0000000..58b9176 --- /dev/null +++ b/gc_acm.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_ACM_H +#define GC_ACM_H + +#include "gc_generic.h" + +int gc_acm_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_ACM_H diff --git a/gc_config.h b/gc_config.h new file mode 100644 index 0000000..5d0b2ce --- /dev/null +++ b/gc_config.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_CONFIG_H +#define GC_CONFIG_H + +/* #undef SERIAL_NUMBER */ +/* #undef MANUFACTURER */ +/* #undef PRODUCT */ +/* #undef ID_VENDOR */ +/* #undef ID_PRODUCT */ + +#ifndef SERIAL_NUMBER +#define SERIAL_NUMBER "0123456789" +#endif + +#ifndef MANUFACTURER +#define MANUFACTURER "HandsomeTech" +#endif + +#ifndef PRODUCT +#define PRODUCT "HandsomeMod Device" +#endif + +#ifndef ID_VENDOR +#define ID_VENDOR "0x18d1" +#endif + +#ifndef ID_PRODUCT +#define ID_PRODUCT "0xd001" +#endif + +#endif //GC_CONFIG_H diff --git a/gc_config.h.in b/gc_config.h.in new file mode 100644 index 0000000..02b28ef --- /dev/null +++ b/gc_config.h.in @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_CONFIG_H +#define GC_CONFIG_H + +#cmakedefine SERIAL_NUMBER @SERIAL_NUMBER@ +#cmakedefine MANUFACTURER @MANUFACTURER@ +#cmakedefine PRODUCT @PRODUCT@ +#cmakedefine ID_VENDOR @ID_VENDOR@ +#cmakedefine ID_PRODUCT @ID_PRODUCT@ + +#ifndef SERIAL_NUMBER +#define SERIAL_NUMBER "0123456789" +#endif + +#ifndef MANUFACTURER +#define MANUFACTURER "HandsomeTech" +#endif + +#ifndef PRODUCT +#define PRODUCT "HandsomeMod Device" +#endif + +#ifndef ID_VENDOR +#define ID_VENDOR "0x18d1" +#endif + +#ifndef ID_PRODUCT +#define ID_PRODUCT "0xd001" +#endif + +#endif //GC_CONFIG_H diff --git a/gc_ecm.c b/gc_ecm.c new file mode 100644 index 0000000..62daea6 --- /dev/null +++ b/gc_ecm.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include "gc_ecm.h" + +int gc_ecm_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_ecm; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_ECM); + + if(id == NULL) + return GC_FAILED; + + usbg_ret = usbg_create_function(gadget,USBG_F_ECM,id,NULL,&f_ecm); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create ecm function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_ecm); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind ecm config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} diff --git a/gc_ecm.h b/gc_ecm.h new file mode 100644 index 0000000..4b34b71 --- /dev/null +++ b/gc_ecm.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_ECM_H +#define GC_ECM_H + +#include "gc_generic.h" + +int gc_ecm_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_ECM_H diff --git a/gc_ffs.c b/gc_ffs.c new file mode 100644 index 0000000..7f18e78 --- /dev/null +++ b/gc_ffs.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#include "gc_ffs.h" + +int gc_ffs_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_ffs; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_FFS); + + if(id == NULL) + return GC_FAILED; + + usbg_ret = usbg_create_function(gadget,USBG_F_FFS,id,NULL,&f_ffs); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create ffs function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + + usbg_ret = usbg_add_config_function(config,id,f_ffs); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind ffs config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} diff --git a/gc_ffs.h b/gc_ffs.h new file mode 100644 index 0000000..03691d9 --- /dev/null +++ b/gc_ffs.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * + */ + + +#ifndef GC_FFS_H +#define GC_FFS_H + +#include "gc_generic.h" + +int gc_ffs_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_FFS_H diff --git a/gc_generic.c b/gc_generic.c new file mode 100644 index 0000000..2f44042 --- /dev/null +++ b/gc_generic.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#include "gc_generic.h" +static usbg_state *state = NULL; + +#define LUGX_CALL(c) \ +{ \ + int usbg_ret; \ + usbg_ret = c; \ + if (usbg_ret != USBG_SUCCESS) { \ + fprintf(stderr, "In: %s (Function: %s)\n", #c, __func__); \ + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), \ + usbg_strerror(usbg_ret)); \ + return GC_FAILED; \ + } \ +} + + +usbg_gadget * gc_init(gc_generic_info info) +{ + usbg_gadget *g; + int usbg_ret; + + struct usbg_gadget_attrs g_attrs = { + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 64, /* Max allowed ep0 packet size */ + .idVendor = info.id_vendor, + .idProduct = info.id_product, + .bcdDevice = 0x0001, /* Verson of device */ + }; + + struct usbg_gadget_strs g_strs = { + .serial = info.serial_number, /* Serial number */ + .manufacturer = info.manufacturer, /* Manufacturer */ + .product = info.product /* Product string */ + }; + + usbg_ret = usbg_init(GC_CONFIG_PATH, &state); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to init gadget. \n"); + state = NULL; + return NULL; + } + + /* Now we just support one otg controller */ + /* if one gadget been created just use it */ + g = usbg_get_first_gadget(state); + if(g == NULL){ + usbg_ret = usbg_create_gadget(state, "g1", &g_attrs, &g_strs, &g); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr,"failed to create gadget. \n"); + state = NULL; + return NULL; + } + } + + /* disable gadget for now to apply new config */ + usbg_disable_gadget(g); + + return g; +} + +int gc_delete_function(gc_generic_info info,char *target) +{ + usbg_gadget *g; + gc_init(info); + g = usbg_get_first_gadget(state); + if(g == NULL || target == NULL) + return GC_FAILED; + + usbg_function *f = usbg_get_first_function(g); + while (f != NULL) { + usbg_function *next = usbg_get_next_function(f); + if(strcmp(usbg_get_function_instance(f),target) == 0){ + usbg_rm_function(f,USBG_RM_RECURSE); + return GC_SUCCESS; + } + f = next; + } + return GC_FAILED; +} + +static int remove_gadget(usbg_gadget *g) +{ + usbg_udc *u; + + u = usbg_get_gadget_udc(g); + if (u) + LUGX_CALL(usbg_disable_gadget(g)); + + LUGX_CALL(usbg_rm_gadget(g, USBG_RM_RECURSE)); + + return 0; +} + +int gc_remove_all_gadgets(gc_generic_info info) +{ + if(gc_init(info) == NULL) + return GC_FAILED; + usbg_gadget *g; + g = usbg_get_first_gadget(state); + while (g != NULL) { + usbg_gadget *next = usbg_get_next_gadget(g); + LUGX_CALL(remove_gadget(g)); + g = next; + } + + return GC_SUCCESS; +} + +/* id generate helper */ +static int gc_get_functions() +{ + if(state == NULL) + return -1; + + usbg_gadget *gadget = usbg_get_first_gadget(state); + + if(gadget == NULL) + return -1; + + usbg_function *last_function = usbg_get_first_function(gadget); + int ci = 0; + if(last_function == NULL){ + return 0; + }else{ + while(last_function != NULL){ + if(usbg_get_next_function(last_function) == NULL) + break; + last_function = usbg_get_next_function(last_function); + ci++; + } + } + + return ci; + +} + +/* get first config from gadget */ +/* if not find create a new one */ +usbg_config *gc_get_config(usbg_gadget *gadget) +{ + if(gadget == NULL) + return NULL; + + /* default config */ + struct usbg_config_strs config_strs = { + .configuration = "c1" + }; + + usbg_config *result = usbg_get_first_config(gadget); + + if(result == NULL){ + int usbg_ret = usbg_create_config(gadget,1,"c1",NULL,&config_strs,&result); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to get config! \n"); + gc_clean(); + return NULL; + } + } + + return result; +} + + + +char *gc_generate_id(usbg_function_type type) +{ + /* + * FORMAT : {function}.{number} + * the number not order by the number of same function + * by number of all exist usb gadgets function. + * if gc -l result like this. + * ffs.1 + * ffs.2 + * mass.4 + * + * And you add a new ffs function you will get this. + * ffs.4 + * if some gadget function had been deleted. id will be the number of functions +1. + */ + + char *result = malloc(sizeof(char) * 20); + int id = gc_get_functions() + 1; + + if(id < 1){ + fprintf(stderr,"failed to get gadgets. \n"); + return NULL; + } + + if(type == USBG_F_HID){ + sprintf(result,"hid.%d",id); + }else if(type == USBG_F_ACM){ + sprintf(result,"acm.%d",id); + }else if(type == USBG_F_ECM){ + sprintf(result,"ecm.%d",id); + }else if(type == USBG_F_EEM){ + sprintf(result,"eem.%d",id); + }else if(type == USBG_F_FFS){ + sprintf(result,"ffs.%d",id); + }else if(type == USBG_F_LOOPBACK){ + sprintf(result,"loopback.%d",id); + }else if(type == USBG_F_MASS_STORAGE){ + sprintf(result,"mass.%d",id); + }else if(type == USBG_F_MIDI){ + sprintf(result,"midi.%d",id); + }else if(type == USBG_F_NCM){ + sprintf(result,"ncm.%d",id); + }else if(type == USBG_F_OBEX){ + sprintf(result,"obex.%d",id); + }else if(type == USBG_F_PHONET){ + sprintf(result,"hid.%d",id); + }else if(type == USBG_F_PRINTER){ + sprintf(result,"printer.%d",id); + }else if(type == USBG_F_RNDIS){ + sprintf(result,"rndis.%d",id); + }else if(type == USBG_F_SERIAL){ + sprintf(result,"serial.%d",id); + }else if(type == USBG_F_SUBSET){ + sprintf(result,"subset.%d",id); + }else if(type == USBG_F_UAC2){ + sprintf(result,"uac.%d",id); + }else if(type == USBG_F_UVC){ + sprintf(result,"uvc.%d",id); + }else{ + return NULL; + } + + return result; +} + +void gc_clean() +{ + usbg_cleanup(state); +} + diff --git a/gc_generic.h b/gc_generic.h new file mode 100644 index 0000000..5aed116 --- /dev/null +++ b/gc_generic.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_GENERIC_H +#define GC_GENERIC_H + +#include +#include +#include +#include +#include + +#define GC_SUCCESS 0 +#define GC_FAILED -1 +#define GC_CONFIG_PATH "/sys/kernel/config" + +typedef enum { + USB_HOST, + USB_GADGET +}gc_usb_mode; + +// generic info passed by cmake +typedef struct { + char *serial_number; + char *manufacturer; + char *product; + unsigned int id_vendor; + unsigned int id_product; +}gc_generic_info; + + +usbg_gadget * gc_init(gc_generic_info info); + +/* 获取usb模式 */ +gc_usb_mode gc_get_mode(); + +/* 生成id */ +char *gc_generate_id(usbg_function_type type); + +/* 删除特定的function */ +int gc_delete_function(gc_generic_info info,char *target); + +/* 清除所有的gadget */ +int gc_remove_all_gadgets(gc_generic_info info); + +/* 销毁usb gadget */ +void gc_clean(); + +/* 得到config */ +usbg_config *gc_get_config(usbg_gadget *gadget); + +#endif //GC_GENERIC_H diff --git a/gc_hid.c b/gc_hid.c new file mode 100644 index 0000000..46a409f --- /dev/null +++ b/gc_hid.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#include "gc_hid.h" + +static char 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 */ +}; + +int gc_hid_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_hid; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_HID); + + if(id == NULL) + return GC_FAILED; + + struct usbg_f_hid_attrs f_attrs = { + .protocol = 1, + .report_desc = { + .desc = report_desc, + .len = sizeof(report_desc), + }, + .report_length = 8, + .subclass = 0, + }; + + usbg_ret = usbg_create_function(gadget,USBG_F_HID,id,&f_attrs,&f_hid); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create hid function! (maybe kernel module not loaded?)\n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file in */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_hid); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind hid config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} diff --git a/gc_hid.h b/gc_hid.h new file mode 100644 index 0000000..d334936 --- /dev/null +++ b/gc_hid.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#ifndef GC_HID_H +#define GC_HID_H + +#include "gc_generic.h" +#include + +int gc_hid_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_GC_HID_H diff --git a/gc_list.c b/gc_list.c new file mode 100644 index 0000000..fd154fd --- /dev/null +++ b/gc_list.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include "gc_list.h" + +static void show_gadget_strs(usbg_gadget *g, int lang) +{ + int usbg_ret; + struct usbg_gadget_strs g_strs; + + usbg_ret = usbg_get_gadget_strs(g, lang, &g_strs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + fprintf(stdout, " Language: \t0x%x\n", lang); + fprintf(stdout, " Manufacturer\t%s\n", g_strs.manufacturer); + fprintf(stdout, " Product\t\t%s\n", g_strs.product); + fprintf(stdout, " Serial Number\t%s\n", g_strs.serial); + + usbg_free_gadget_strs(&g_strs); +} + +static void show_gadget(usbg_gadget *g) +{ + const char *name, *udc; + usbg_udc *u; + int usbg_ret; + struct usbg_gadget_attrs g_attrs; + int *langs; + int i; + + name = usbg_get_gadget_name(g); + if (!name) { + fprintf(stderr, "Unable to get gadget name\n"); + return; + } + + usbg_ret = usbg_get_gadget_attrs(g, &g_attrs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + fprintf(stdout, "ID %04x:%04x '%s'\n", + g_attrs.idVendor, g_attrs.idProduct, name); + + u = usbg_get_gadget_udc(g); + if (u) + /* gadget is enabled */ + udc = usbg_get_udc_name(u); + else + /* gadget is disabled */ + udc = "\0"; + + fprintf(stdout, " UDC\t\t\t%s\n", udc); + + fprintf(stdout, " bcdUSB\t\t%x.%02x\n", + g_attrs.bcdUSB >> 8, + g_attrs.bcdUSB & 0x00ff); + + fprintf(stdout, " bDeviceClass\t\t0x%02x\n", g_attrs.bDeviceClass); + fprintf(stdout, " bDeviceSubClass\t0x%02x\n", g_attrs.bDeviceSubClass); + fprintf(stdout, " bDeviceProtocol\t0x%02x\n", g_attrs.bDeviceProtocol); + fprintf(stdout, " bMaxPacketSize0\t%d\n", g_attrs.bMaxPacketSize0); + fprintf(stdout, " idVendor\t\t0x%04x\n", g_attrs.idVendor); + fprintf(stdout, " idProduct\t\t0x%04x\n", g_attrs.idProduct); + fprintf(stdout, " bcdDevice\t\t%x.%02x\n", + g_attrs.bcdDevice >> 8, + g_attrs.bcdDevice & 0x00ff); + + usbg_ret = usbg_get_gadget_strs_langs(g, &langs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + for (i = 0; langs[i]; ++i) + show_gadget_strs(g, langs[i]); +} + +static void show_function(usbg_function *f) +{ + const char *instance; + usbg_function_type type; + int usbg_ret; + union { + struct usbg_f_net_attrs net; + char *ffs_dev_name; + struct usbg_f_ms_attrs ms; + struct usbg_f_midi_attrs midi; + int serial_port_num; + char *phonet_ifname; + struct usbg_f_hid_attrs hid; + struct usbg_f_uac2_attrs uac2; + } f_attrs; + + instance = usbg_get_function_instance(f); + if (!instance) { + fprintf(stderr, "Unable to get function instance name\n"); + return; + } + + type = usbg_get_function_type(f); + usbg_ret = usbg_get_function_attrs(f, &f_attrs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + fprintf(stdout, " Function, type: %s instance: %s\n", + usbg_get_function_type_str(type), instance); + + switch (type) { + case USBG_F_ACM: + case USBG_F_OBEX: + case USBG_F_SERIAL: + fprintf(stdout, " port_num\t\t%d\n", + f_attrs.serial_port_num); + break; + + case USBG_F_ECM: + case USBG_F_SUBSET: + case USBG_F_NCM: + case USBG_F_EEM: + case USBG_F_RNDIS: + { + struct usbg_f_net_attrs *f_net_attrs = &f_attrs.net; + + fprintf(stdout, " dev_addr\t\t%s\n", + ether_ntoa(&f_net_attrs->dev_addr)); + fprintf(stdout, " host_addr\t\t%s\n", + ether_ntoa(&f_net_attrs->host_addr)); + fprintf(stdout, " ifname\t\t%s\n", f_net_attrs->ifname); + fprintf(stdout, " qmult\t\t%d\n", f_net_attrs->qmult); + break; + } + + case USBG_F_PHONET: + fprintf(stdout, " ifname\t\t%s\n", f_attrs.phonet_ifname); + break; + + case USBG_F_FFS: + fprintf(stdout, " dev_name\t\t%s\n", f_attrs.ffs_dev_name); + break; + + case USBG_F_MASS_STORAGE: + { + struct usbg_f_ms_attrs *attrs = &f_attrs.ms; + int i; + + fprintf(stdout, " stall\t\t%d\n", attrs->stall); + fprintf(stdout, " nluns\t\t%d\n", attrs->nluns); + for (i = 0; i < attrs->nluns; ++i) { + fprintf(stdout, " lun %d:\n", attrs->luns[i]->id); + fprintf(stdout, " cdrom\t\t%d\n", attrs->luns[i]->cdrom); + fprintf(stdout, " ro\t\t%d\n", attrs->luns[i]->ro); + fprintf(stdout, " nofua\t\t%d\n", attrs->luns[i]->nofua); + fprintf(stdout, " removable\t\t%d\n", attrs->luns[i]->removable); + fprintf(stdout, " file\t\t%s\n", attrs->luns[i]->file); + } + break; + } + + case USBG_F_MIDI: + { + struct usbg_f_midi_attrs *attrs = &f_attrs.midi; + + fprintf(stdout, " index\t\t%d\n", attrs->index); + fprintf(stdout, " id\t\t\t%s\n", attrs->id); + fprintf(stdout, " in_ports\t\t%d\n", attrs->in_ports); + fprintf(stdout, " out_ports\t\t%d\n", attrs->out_ports); + fprintf(stdout, " buflen\t\t%d\n", attrs->buflen); + fprintf(stdout, " qlen\t\t%d\n", attrs->qlen); + break; + } + case USBG_F_HID: + { + struct usbg_f_hid_attrs *attrs = &f_attrs.hid; + int i; + + fprintf(stdout, " dev\t\t\t%d:%d\n", + major(attrs->dev), minor(attrs->dev)); + fprintf(stdout, " protocol\t\t%d\n", attrs->protocol); + fprintf(stdout, " report_desc\t"); + for (i = 0; i < attrs->report_desc.len; ++i) + fprintf(stdout, "%x", attrs->report_desc.desc[i]); + fprintf(stdout, "\n"); + fprintf(stdout, " report_length\t%d\n", + attrs->report_length); + fprintf(stdout, " subclass\t\t%d\n", attrs->subclass); + break; + } + + case USBG_F_UAC2: + { + struct usbg_f_uac2_attrs *attrs = &f_attrs.uac2; + + fprintf(stdout, " c_chmask\t\t%d\n", attrs->c_chmask); + fprintf(stdout, " c_srate\t\t%d\n", attrs->c_srate); + fprintf(stdout, " c_ssize\t\t%d\n", attrs->c_ssize); + fprintf(stdout, " p_chmask\t\t%d\n", attrs->p_chmask); + fprintf(stdout, " p_srate\t\t%d\n", attrs->p_srate); + fprintf(stdout, " p_ssize\t\t%d\n", attrs->p_ssize); + break; + } + + default: + fprintf(stdout, " UNKNOWN\n"); + } + + usbg_cleanup_function_attrs(f, &f_attrs); +} + +static void show_config_strs(usbg_config *c, int lang) +{ + struct usbg_config_strs c_strs; + int usbg_ret; + + usbg_ret = usbg_get_config_strs(c, lang, &c_strs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + fprintf(stdout, " Language: \t0x%x\n", lang); + fprintf(stdout, " configuration\t%s\n", c_strs.configuration); + + usbg_free_config_strs(&c_strs); +} + +static void show_config(usbg_config *c) +{ + usbg_binding *b; + usbg_function *f; + const char *label, *instance, *bname; + usbg_function_type type; + struct usbg_config_attrs c_attrs; + int *langs; + int usbg_ret, id, i; + + label = usbg_get_config_label(c); + if (!label) { + fprintf(stderr, "Unable to get config label\n"); + return; + } + + id = usbg_get_config_id(c); + fprintf(stdout, " Configuration: '%s' ID: %d\n", label, id); + + usbg_ret = usbg_get_config_attrs(c, &c_attrs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + fprintf(stdout, " MaxPower\t\t%d\n", c_attrs.bMaxPower); + fprintf(stdout, " bmAttributes\t0x%02x\n", c_attrs.bmAttributes); + + usbg_ret = usbg_get_config_strs_langs(c, &langs); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + for (i = 0; langs[i]; ++i) + show_config_strs(c, langs[i]); + + usbg_for_each_binding(b, c) { + bname = usbg_get_binding_name(b); + f = usbg_get_binding_target(b); + instance = usbg_get_function_instance(f); + type = usbg_get_function_type(f); + if (!bname || !instance) { + fprintf(stderr, "Unable to get binding details\n"); + return; + } + fprintf(stdout, " %s -> %s %s\n", bname, + usbg_get_function_type_str(type), instance); + } +} + +void gc_show_list() +{ + usbg_state *s; + usbg_gadget *g; + usbg_function *f; + usbg_config *c; + int usbg_ret; + usbg_ret = usbg_init(GC_CONFIG_PATH, &s); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error on USB gadget init\n"); + fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret), + usbg_strerror(usbg_ret)); + return; + } + + usbg_for_each_gadget(g, s) { + show_gadget(g); + usbg_for_each_function(f, g) + show_function(f); + usbg_for_each_config(c, g) + show_config(c); + } + + usbg_cleanup(s); +}; diff --git a/gc_list.h b/gc_list.h new file mode 100644 index 0000000..aa6d801 --- /dev/null +++ b/gc_list.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_LIST_H +#define GC_LIST_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gc_generic.h" + +void gc_show_list(); + +#endif //GC_LIST_H diff --git a/gc_midi.c b/gc_midi.c new file mode 100644 index 0000000..3356b9e --- /dev/null +++ b/gc_midi.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#include "gc_midi.h" + +int gc_midi_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_midi; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_MIDI); + + if(id == NULL) + return GC_FAILED; + + struct usbg_f_midi_attrs f_attrs = { + .index = 0, + .id = id, + .buflen = 128, + .qlen = 16, + .in_ports = 2, + .out_ports = 3, + }; + + usbg_ret = usbg_create_function(gadget,USBG_F_MIDI,id,&f_attrs,&f_midi); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create midi function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_midi); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind midi config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} \ No newline at end of file diff --git a/gc_midi.h b/gc_midi.h new file mode 100644 index 0000000..fa4a071 --- /dev/null +++ b/gc_midi.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#ifndef GC_MIDI_H +#define GC_MIDI_H +#include "gc_generic.h" +#include + +int gc_midi_create(int argc,char *argv[],gc_generic_info info); +#endif //GC_MIDI_H diff --git a/gc_printer.c b/gc_printer.c new file mode 100644 index 0000000..2295b70 --- /dev/null +++ b/gc_printer.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#include "gc_printer.h" + +int gc_printer_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_printer; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_PRINTER); + + if(id == NULL) + return GC_FAILED; + + usbg_ret = usbg_create_function(gadget,USBG_F_PRINTER,id,NULL,&f_printer); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create printer function! (maybe kernel module not loaded?)\n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_printer); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind printer config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS) { + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} diff --git a/gc_printer.h b/gc_printer.h new file mode 100644 index 0000000..0e8ecc7 --- /dev/null +++ b/gc_printer.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#ifndef GC_PRINTER_H +#define GC_PRINTER_H + +#include "gc_generic.h" + +int gc_printer_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_GC_PRINTER_H diff --git a/gc_rndis.c b/gc_rndis.c new file mode 100644 index 0000000..5b23223 --- /dev/null +++ b/gc_rndis.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include "gc_rndis.h" +int gc_rndis_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_rndis; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_RNDIS); + + if(id == NULL) + return GC_FAILED; + + struct usbg_gadget_os_descs g_os_desc = { + .use = true, + .b_vendor_code = 0xBC, + .qw_sign = "MSFT100", + }; + + struct usbg_function_os_desc f_os_desc = { + .compatible_id = "RNDIS", + .sub_compatible_id = "5162001", + }; + + usbg_ret = usbg_create_function(gadget,USBG_F_RNDIS,id,NULL,&f_rndis); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create rndis function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_rndis); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind rndis config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_set_gadget_os_descs(gadget, &g_os_desc); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error setting gadget OS desc\n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_set_os_desc_config(gadget, config); + if (usbg_ret != USBG_SUCCESS) { + fprintf(stderr, "Error setting gadget OS desc config\n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} + diff --git a/gc_rndis.h b/gc_rndis.h new file mode 100644 index 0000000..c2f83b9 --- /dev/null +++ b/gc_rndis.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#ifndef GC_RNDIS_H +#define GC_RNDIS_H +#include "gc_generic.h" + +int gc_rndis_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_GC_RNDIS_H diff --git a/gc_serial.c b/gc_serial.c new file mode 100644 index 0000000..3475ef3 --- /dev/null +++ b/gc_serial.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include "gc_serial.h" + +int gc_serial_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_serial; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_SERIAL); + + if(id == NULL) + return GC_FAILED; + + usbg_ret = usbg_create_function(gadget,USBG_F_SERIAL,id,NULL,&f_serial); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create serial function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_serial); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind serial config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} + diff --git a/gc_serial.h b/gc_serial.h new file mode 100644 index 0000000..9cf8d0e --- /dev/null +++ b/gc_serial.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#ifndef GC_SERIAL_H +#define GC_SERIAL_H + +#include "gc_generic.h" + +int gc_serial_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_SERIAL_H diff --git a/gc_storage.c b/gc_storage.c new file mode 100644 index 0000000..6dc5e4f --- /dev/null +++ b/gc_storage.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include "gc_storage.h" + +int gc_storage_create(int argc,char *argv[],gc_generic_info info){ + if(argc < 4){ + fprintf(stderr,"chose a directory to mount! \n"); + return GC_FAILED; + } + + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_mass; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_MASS_STORAGE); + + if(id == NULL) + return GC_FAILED; + + struct usbg_f_ms_lun_attrs f_ms_luns_array[] = { + { + .id = -1, /* allows to place in any position */ + .cdrom = 0, + .ro = 0, + .nofua = 0, + .removable = 1, + .file = argv[3], + } + }; + + struct usbg_f_ms_lun_attrs *f_ms_luns[] = { + /* + * When id in lun structure is below 0 we can place it in any + * arbitrary position + */ + &f_ms_luns_array[0], + NULL, + }; + + struct usbg_f_ms_attrs f_attrs = { + .stall = 0, + .nluns = 1, + .luns = f_ms_luns, + }; + + + usbg_ret = usbg_create_function(gadget,USBG_F_MASS_STORAGE,id,&f_attrs,&f_mass); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create mass storage function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_mass); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind mass storage config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} \ No newline at end of file diff --git a/gc_storage.h b/gc_storage.h new file mode 100644 index 0000000..8331e1e --- /dev/null +++ b/gc_storage.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#ifndef GC_STORAGE_H +#define GC_STORAGE_H + +#include "gc_generic.h" +#include + +int gc_storage_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_GC_STORAGE_H diff --git a/gc_uvc.c b/gc_uvc.c new file mode 100644 index 0000000..c6063bf --- /dev/null +++ b/gc_uvc.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + + +#include "gc_uvc.h" + +int gc_uvc_create(int argc,char *argv[],gc_generic_info info) +{ + usbg_gadget *gadget = gc_init(info); + + if(gadget == NULL) + return GC_FAILED; + + usbg_function *f_uvc; + int usbg_ret; + + char *id = gc_generate_id(USBG_F_UVC); + + if(id == NULL) + return GC_FAILED; + + struct usbg_f_uvc_frame_attrs uvc_frame_attrs_array[] = { + { + .bFrameIndex = 1, + .dwFrameInterval = 2000000, + .wHeight = 480, + .wWidth = 640, + }, { + .bFrameIndex = 2, + .dwFrameInterval = 2000000, + .wHeight = 1080, + .wWidth = 1920, + }, { + .bFrameIndex = 3, + .dwFrameInterval = 333333, + .wHeight = 1080, + .wWidth = 1920, + }, { + .bFrameIndex = 4, + .dwFrameInterval = 333333, + .wHeight = 2160, + .wWidth = 3840, + } + }; + + struct usbg_f_uvc_frame_attrs *uvc_frame_mjpeg_attrs[] = { + &uvc_frame_attrs_array[0], + &uvc_frame_attrs_array[1], + &uvc_frame_attrs_array[2], + &uvc_frame_attrs_array[3], + NULL, + }; + + struct usbg_f_uvc_frame_attrs *uvc_frame_uncompressed_attrs[] = { + &uvc_frame_attrs_array[0], + &uvc_frame_attrs_array[1], + &uvc_frame_attrs_array[2], + &uvc_frame_attrs_array[3], + NULL, + }; + + struct usbg_f_uvc_format_attrs uvc_format_attrs_array[] = { + { + .frames = uvc_frame_mjpeg_attrs, + .format = "mjpeg/m", + .bDefaultFrameIndex = 3, + }, { + .frames = uvc_frame_uncompressed_attrs, + .format = "uncompressed/u", + .bDefaultFrameIndex = 2, + } + }; + + struct usbg_f_uvc_format_attrs *uvc_format_attrs[] = { + &uvc_format_attrs_array[0], + &uvc_format_attrs_array[1], + NULL, + }; + + struct usbg_f_uvc_attrs uvc_attrs = { + .formats = uvc_format_attrs, + }; + + struct usbg_config_strs config_strs = { + .configuration = id + }; + + usbg_ret = usbg_create_function(gadget,USBG_F_UVC,id,&uvc_attrs,&f_uvc); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to create uvc function! (maybe kernel module not loaded?) \n"); + gc_clean(); + return GC_FAILED; + } + + /* for now we only create one config file */ + usbg_config *config = gc_get_config(gadget); + + usbg_ret = usbg_add_config_function(config,id,f_uvc); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to bind uvc config to function! \n"); + gc_clean(); + return GC_FAILED; + } + + usbg_ret = usbg_enable_gadget(gadget, DEFAULT_UDC); + if(usbg_ret != USBG_SUCCESS){ + fprintf(stderr,"failed to enable gadget! \n"); + gc_clean(); + return GC_FAILED; + } + + gc_clean(); + return GC_SUCCESS; +} + diff --git a/gc_uvc.h b/gc_uvc.h new file mode 100644 index 0000000..7888296 --- /dev/null +++ b/gc_uvc.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * + */ + + +#ifndef GC_UVC_H +#define GC_UVC_H + +#include "gc_generic.h" +#include + +int gc_uvc_create(int argc,char *argv[],gc_generic_info info); + +#endif //GC_UVC_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..e2bd2cd --- /dev/null +++ b/main.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 HandsomeMod Project + * + * Handsomeyingyan + * + * GC(Gadget Controller) is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include + +#include "gc_config.h" +#include "gc_generic.h" +#include "gc_ffs.h" +#include "gc_hid.h" +#include "gc_midi.h" +#include "gc_printer.h" +#include "gc_serial.h" +#include "gc_uvc.h" +#include "gc_storage.h" +#include "gc_rndis.h" +#include "gc_list.h" +#include "gc_ecm.h" +#include "gc_acm.h" + +static int is_root(){ + if(getuid() == 0){ + return 1; + }else{ + return 0; + } +} +static void print_help() +{ + printf("Usage : gc [options....] \n"); + printf("-h Show this help. \n"); + printf("-l Show active gadget functions. \n"); + printf("-c Clean all active gadget. \n"); + printf("-a [configs ...] Add a gadget function. \n"); + printf("-d Delete a gadget function by name in list (-l). \n"); +} + +int main(int argc,char *argv[]) +{ + + if(argc < 2) { + print_help(); + return 0; + } + + /* generate vendor info */ + gc_generic_info info; + info.id_product = strtoul(ID_PRODUCT,0,16); + info.id_vendor = strtoul(ID_VENDOR,0,16); + info.manufacturer = MANUFACTURER; + info.product = PRODUCT; + info.serial_number = SERIAL_NUMBER; + + /* deal with args */ + if(strcmp(argv[1],"-h") == 0) { + /* help */ + print_help(); + } else if(strcmp(argv[1],"-l") == 0) { + /* list gadget functions */ + gc_show_list(); + } else if(strcmp(argv[1],"-a") == 0) { + /* add a gadget function */ + if(!is_root()){ + printf("you need root to set usb gadget!\n"); + return -1; + } + + if(argc < 3) { + printf("You need a function to add ! \n"); + return -1; + } + + if(strcmp(argv[2],"ffs") == 0){ + if(gc_ffs_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"hid") == 0){ + if(gc_hid_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"midi") == 0){ + if(gc_midi_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"printer") == 0){ + if(gc_printer_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"serial") == 0){ + if(gc_serial_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"uvc") == 0){ + if(gc_uvc_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"mass") == 0){ + if(gc_storage_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"rndis") == 0){ + if(gc_rndis_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"ecm") == 0){ + if(gc_ecm_create(argc,argv,info) == GC_FAILED) + return -1; + }else if(strcmp(argv[2],"acm") == 0){ + if(gc_acm_create(argc,argv,info) == GC_FAILED) + return -1; + } + } else if(strcmp(argv[1],"-d") == 0) { + /* delete a gadget function */ + if(argc < 3) { + printf("You need a gadget to remove ! \n"); + return -1; + } + + if(gc_delete_function(info,argv[2]) == GC_FAILED){ + fprintf(stderr,"failed to remove gadget function!\n"); + return -1; + } + + if(!is_root()){ + printf("you need root to delete usb gadget!\n"); + return -1; + } + } else if(strcmp(argv[1],"-c") == 0){ + if(!is_root()){ + printf("you need root to clear usb gadget!\n"); + return -1; + } + + if(gc_remove_all_gadgets(info) != GC_SUCCESS) { + fprintf(stderr,"failed to remove all gadgets. \n"); + return -1; + } + + } else if(strcmp(argv[1],"playing") == 0 ){ + /* eastern egg :p */ + /* 'gc playing' is a command in bhuman simrobot */ + printf("Hi ! I'm XBMUAttila1. \n"); + } else{ + fprintf(stderr,"Invalid Argument!\n"); + return -1; + } + + return 0; +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..97a7d23 --- /dev/null +++ b/readme.md @@ -0,0 +1,45 @@ +# Gadget Controller + +### A Simple Tool To Control Usb Gadget + +## Dependency + +* Cmake +* libusbgx + +## Compile + +``` shell +git clone https://github.com/HandsomeMod/gc.git +cd gc +mkdir build +cd build +cmake .. +make +``` + +## Usage + +``` shell +Usage : gc [options....] +-h Show this help. +-l Show active gadget functions. +-c Clean all active gadget. +-a [configs ...] Add a gadget function. +-d Delete a gadget function by name in list (-l). +``` + +## Examples + +``` shell +# Add a rndis function to gadget +gc -a rndis +# Show Gadget Status +gc -l +# Add a mass storage function to gadget +gc -a mass /home/user +``` + +## License + +Gadget Controller is licensed under GPL-2.0. \ No newline at end of file