Permalink
Browse files

Add gadget mode for retro-bit GENERATIONS

  • Loading branch information...
toyoshim committed Aug 16, 2018
1 parent 15e7f38 commit f5d57a0c3db02273248b1e1fdcd5c48e9678c490
Showing with 159 additions and 1 deletion.
  1. +13 −1 gadget/hid_opg.c
  2. +2 −0 gadget/hid_opg_ngm.h
  3. +2 −0 gadget/hid_opg_ps4.h
  4. +142 −0 gadget/hid_opg_rbg.h
View
@@ -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)
View
@@ -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)
View
@@ -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)
View
@@ -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;
}

0 comments on commit f5d57a0

Please sign in to comment.