diff --git a/gadget/hid_opg.c b/gadget/hid_opg.c index 330f512..a264235 100644 --- a/gadget/hid_opg.c +++ b/gadget/hid_opg.c @@ -49,7 +49,8 @@ struct driver_data { //#include "hid_opg_ps4.h" //#include "hid_opg_xbo.h" -#include "hid_opg_ngm.h" +//#include "hid_opg_ngm.h" +#include "hid_opg_rbg.h" MODULE_LICENSE("Dual BSD/GPL"); @@ -229,9 +230,11 @@ static void in_report_complete(struct usb_ep* ep, struct usb_request* r) { printk("%s: failed to queue an in-data report\n", opg_driver_name); } +#if defined(USE_EP_OUT) static void out_report_complete(struct usb_ep* ep, struct usb_request* r) { printk("%s: not impl, out_report_complete\n", opg_driver_name); } +#endif static int setup(struct usb_gadget* gadget, const struct usb_ctrlrequest* r) { struct driver_data* data = get_gadget_data(gadget); @@ -261,6 +264,7 @@ static int setup(struct usb_gadget* gadget, const struct usb_ctrlrequest* r) { } } +#if defined(USE_EP_OUT) if (data->ep_out && !data->ep_out_request) { data->ep_out_request = usb_ep_alloc_request(data->ep_out, GFP_KERNEL); if (data->ep_out_request) { @@ -270,6 +274,7 @@ static int setup(struct usb_gadget* gadget, const struct usb_ctrlrequest* r) { usb_ep_enable(data->ep_out); } } +#endif if (data->ep_in_request && data->ep_in_request->buf) { data->ep_in_request->status = 0; @@ -282,6 +287,8 @@ static int setup(struct usb_gadget* gadget, const struct usb_ctrlrequest* r) { value = -ENOMEM; break; } + +#if defined(USE_EP_OUT) if (data->ep_out_request && data->ep_out_request->buf) { data->ep_out_request->status = 0; data->ep_out_request->zero = 0; @@ -292,6 +299,7 @@ static int setup(struct usb_gadget* gadget, const struct usb_ctrlrequest* r) { value = -ENOMEM; break; } +#endif value = w_length; break; default: @@ -377,6 +385,7 @@ static int bind(struct usb_gadget* gadget) { printk("%s: failed to allocate ep-in\n", opg_driver_name); return -EOPNOTSUPP; } +#if defined(USE_EP_OUT) data->ep_out = find_int_ep(gadget, opg_config_desc.ep_out.wMaxPacketSize, 0); if (data->ep_out) { data->ep_out->driver_data = data; @@ -386,6 +395,7 @@ static int bind(struct usb_gadget* gadget) { } else { printk("%s: failed to allocate ep-out, ignoring\n", opg_driver_name); } +#endif return 0; } @@ -404,6 +414,7 @@ static void unbind(struct usb_gadget* gadget) { usb_ep_free_request(data->ep_in, data->ep_in_request); } } +#if defined(USE_EP_OUT) if (data->ep_out) { usb_ep_disable(data->ep_out); data->ep_out->driver_data = NULL; @@ -414,6 +425,7 @@ static void unbind(struct usb_gadget* gadget) { usb_ep_free_request(data->ep_out, data->ep_out_request); } } +#endif if (data->ep0_request) { if (data->ep0_request->buf) diff --git a/gadget/hid_opg_ngm.h b/gadget/hid_opg_ngm.h index 019c61c..a963362 100644 --- a/gadget/hid_opg_ngm.h +++ b/gadget/hid_opg_ngm.h @@ -11,6 +11,8 @@ static char opg_driver_name[] = "OPiPad Gadget HID Driver for NEOGEO mini"; #define NO_IDX_PRODUCT 1 #define NO_IDX_SERIAL 1 +#define USE_EP_OUT + static char opg_hid_report[] = { 0x05, 0x01, // usage page (desktop) 0x09, 0x05, // usage (gamepad) diff --git a/gadget/hid_opg_ps4.h b/gadget/hid_opg_ps4.h index 4867708..ed5bef7 100644 --- a/gadget/hid_opg_ps4.h +++ b/gadget/hid_opg_ps4.h @@ -8,6 +8,8 @@ static char opg_driver_name[] = "OPiPad Gadget HID Driver for PS4"; #define OPG_VENDOR_ID 0x6666 #define OPG_PRODUCT_ID 0x0884 +#define USE_EP_OUT + static char opg_hid_report[] = { 0x05, 0x01, // usage page (desktop) 0x09, 0x05, // usage (gamepad) diff --git a/gadget/hid_opg_rbg.h b/gadget/hid_opg_rbg.h new file mode 100644 index 0000000..266eca0 --- /dev/null +++ b/gadget/hid_opg_rbg.h @@ -0,0 +1,142 @@ +static char opg_driver_name[] = + "OPiPad Gadget HID Driver for retro-bit GENERATIONS"; + +#define OPG_USB_VERSION cpu_to_le16(0x200) +#define OPG_DEVICE_CLASS USB_CLASS_PER_INTERFACE +#define OPG_DEVICE_SUB_CLASS 0 +#define OPG_DEVICE_PROTOCOL 0 + +#define OPG_VENDOR_ID 0x6666 +#define OPG_PRODUCT_ID 0x0880 + +static char opg_hid_report[] = { + 0x05, 0x01, // usage page (desktop) + 0x09, 0x04, // usage (sport control) + 0xa1, 0x01, // collection (application) + 0x75, 0x04, // report size (4) + 0x95, 0x02, // report count (2) + 0x15, 0x00, // logical minimum (0) + 0x25, 0x0f, // logical maximum (15) + 0x35, 0x00, // physical minimum (0) + 0x45, 0xff, // physical maximum (255) + 0x09, 0x30, // usage (x) + 0x09, 0x31, // usage (y) + 0x81, 0x02, // input (variable) + 0x75, 0x01, // report size (1) + 0x95, 0x06, // report count (6) + 0x25, 0x01, // logical maximum (1) + 0x45, 0x01, // physical maximum (1) + 0x05, 0x09, // usage page (button) + 0x19, 0x01, // usage minimum (1) + 0x29, 0x06, // usage maximum (6) + 0x81, 0x02, // input (variable) + 0x95, 0x02, // report count (2) + 0x19, 0x09, // usage minimum (9) + 0x29, 0x0a, // usage maximum (10) + 0x81, 0x02, // input (variable) + 0xc0, // end collection +}; + +struct opg_config_descriptor { + struct usb_config_descriptor config; + struct usb_interface_descriptor interface; + struct usb_hid_descriptor hid; + struct usb_short_endpoint_descriptor ep_in; +} __attribute__ ((packed)) opg_config_desc = { + .config = { + .bLength = USB_DT_CONFIG_SIZE, + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = cpu_to_le16(sizeof(struct opg_config_descriptor)), + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = IDX_NULL, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 250, // x 2mA + }, + .interface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0x00, + .bInterfaceProtocol = 0x00, + .iInterface = IDX_NULL, + }, + .hid = { + .bLength = sizeof(struct usb_hid_descriptor), + .bDescriptorType = USB_DT_HID, + .bcdHID = cpu_to_le16(0x0110), + .bCountryCode = 0, + .bNumReports = 1, + .bReportType = USB_DT_HID_REPORT, + .wReportLength = cpu_to_le16(sizeof(opg_hid_report)), + }, + .ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN | 4, // will be overriden + .bmAttributes = + USB_ENDPOINT_XFER_INT | USB_ENDPOINT_SYNC_NONE | USB_ENDPOINT_USAGE_DATA, + .wMaxPacketSize = 8, + .bInterval = 5, + }, +}; + +static __u8 opg_report[] = { + //XY start mode C Z X A B Y + 0x88, 0x00, +}; + +static const char* opg_get_string(int idx) { + switch (idx) { + case IDX_MANUFACTURER: + return "TOYOSHIMA-HOUSE"; + case IDX_PRODUCT: + return "OPiPad retro-bit GENERATIONS Adaptor"; + case IDX_SERIAL: + return "0"; + default: + break; + } + return NULL; +} + +static void opg_update_report(void) { + const struct gpio_hid_state* state = gpio_get_state(); + opg_report[0] = + (!state->left ? 0 : !state->right ? 0x0f: 0x08) | + (!state->up ? 0 : !state->down ? 0xf0: 0x80); + opg_report[1] = + (state->x ? 0 : 0x01) | + (state->lt ? 0 : 0x02) | + (state->a ? 0 : 0x04) | + (state->b ? 0 : 0x08) | + (state->y ? 0 : 0x10) | + (state->rt ? 0 : 0x20) | + (state->back ? 0 : 0x40) | + (state->start ? 0 : 0x80); +} + +static int opg_setup( + struct usb_gadget* gadget, const struct usb_ctrlrequest* r) { + struct driver_data* data = get_gadget_data(gadget); + int type = r->bRequestType & USB_TYPE_MASK; + printk("%s: bRequestType: %02x, bRequest: %02x, wValue: %04x, " + "wIndex: %04x, wLendth: %04x\n", + opg_driver_name, r->bRequestType, r->bRequest, r->wValue, r->wIndex, + r->wLength); + if (type == USB_TYPE_CLASS && r->bRequest == HID_REQ_GET_REPORT) { + switch(le16_to_cpu(r->wValue)) { + case 0x0100: + opg_update_report(); + memcpy(data->ep0_request->buf, opg_report, sizeof(opg_report)); + return sizeof(opg_report); + default: + printk("%s: report type/id: %04x\n", opg_driver_name, r->wValue); + break; + } + } + return -EOPNOTSUPP; +}