opipad/gadget/hid_opg_ngm.h
2018-08-17 01:54:09 +09:00

183 lines
5.6 KiB
C

static char opg_driver_name[] = "OPiPad Gadget HID Driver for NEOGEO mini";
#define OPG_USB_VERSION cpu_to_le16(0x110)
#define OPG_DEVICE_CLASS USB_CLASS_PER_INTERFACE
#define OPG_DEVICE_SUB_CLASS 0
#define OPG_DEVICE_PROTOCOL 0
#define OPG_VENDOR_ID 0x20bc
#define OPG_PRODUCT_ID 0x5500
#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)
0xa1, 0x01, // collection (application)
0x15, 0x00, // logical minimum (0)
0x25, 0x01, // logical maximum (1)
0x35, 0x00, // physical minimum (0)
0x45, 0x01, // physical minimum (1)
0x75, 0x01, // report size (1)
0x95, 0x0f, // report count (15)
0x05, 0x09, // usage page (button)
0x19, 0x01, // usage minimum (1)
0x29, 0x0f, // usage maximum (15)
0x81, 0x02, // input (variable)
0x95, 0x01, // report count (1)
0x81, 0x01, // input (constant)
0x05, 0x01, // usage page (desktop)
0x25, 0x07, // logical maximum (7)
0x45, 0x07, // physical maximum (7)
0x75, 0x04, // report size (4)
0x95, 0x01, // report count (1)
0x65, 0x14, // unit (degrees)
0x09, 0x39, // usage (hat switch)
0x81, 0x42, // input (variable, null state)
0x65, 0x00, // unit
0x95, 0x01, // report count (1)
0x81, 0x01, // input (constant)
0x26, 0xff, 0x00, // logical maximum (255)
0x46, 0xff, 0x00, // physical maximum (255)
0x09, 0x30, // usage (x)
0x09, 0x31, // usage (y)
0x09, 0x32, // usage (z)
0x09, 0x35, // usage (rz)
0x75, 0x08, // report size (8)
0x95, 0x04, // report count (4)
0x81, 0x02, // input (variable)
0x05, 0x02, // usage page (simulation)
0x15, 0x00, // logical minimum (0)
0x25, 0x01, // logical maximum (1)
0x45, 0x01, // physical maximum (1)
0x09, 0xc5, // usage (c5h)
0x09, 0xc4, // usage (c4h)
0x09, 0x02, // usage (02h)
0x75, 0x01, // report size (1)
0x95, 0x03, // report count (3)
0x81, 0x02, // input (variable)
0x95, 0x05, // report count (5)
0x81, 0x01, // input (constant)
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_out;
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 = 2,
.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_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT | 3, // will be overriden
.bmAttributes =
USB_ENDPOINT_XFER_INT | USB_ENDPOINT_SYNC_NONE | USB_ENDPOINT_USAGE_DATA,
.wMaxPacketSize = 32,
.bInterval = 10,
},
.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 = 32,
.bInterval = 10,
},
};
static __u8 opg_report[] = {
// _ _ _ D | C _ B A | _ _ _ _ | START SELECT _ _
0x00, 0x00,
// Hat
// 7 0 1
// 6 f 2
// 5 4 3
0x0f,
0x00, 0x00, 0x00, 0x00, 0x00,
};
static const char* opg_get_string(int idx) {
switch (idx) {
case IDX_MANUFACTURER:
return "JJ";
default:
break;
}
return NULL;
}
static void opg_update_report(void) {
const struct gpio_hid_state* state = gpio_get_state();
opg_report[0] =
(!state->a ? 0x01 : 0) |
(!state->b ? 0x02 : 0) |
(!state->x ? 0x08 : 0) |
(!state->y ? 0x10 : 0);
opg_report[1] =
(!state->back ? 0x04 : 0) | (!state->start ? 0x08 : 0);
opg_report[2] =
!state->up ? (!state->left ? 7 : !state->right ? 1 : 0) :
!state->down ? (!state->left ? 5 : !state->right ? 3: 4) :
(!state->left ? 6 : !state->right ? 2 : 15);
}
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:
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;
}