|
|
|
@ -42,13 +42,19 @@
@@ -42,13 +42,19 @@
|
|
|
|
|
|
|
|
|
|
#define MAX_PLAYERS 2 |
|
|
|
|
|
|
|
|
|
#define GCN64_USB_PID 0x0038 |
|
|
|
|
#define N64_USB_PID 0x0039 |
|
|
|
|
#define GC_USB_PID 0x003A |
|
|
|
|
#define GCN64_USB_PID 0x0060 |
|
|
|
|
#define N64_USB_PID 0x0061 |
|
|
|
|
#define GC_USB_PID 0x0062 |
|
|
|
|
|
|
|
|
|
#define DUAL_GCN64_USB_PID 0x003B |
|
|
|
|
#define DUAL_N64_USB_PID 0x003C |
|
|
|
|
#define DUAL_GC_USB_PID 0x003D |
|
|
|
|
#define DUAL_GCN64_USB_PID 0x0063 |
|
|
|
|
#define DUAL_N64_USB_PID 0x0064 |
|
|
|
|
#define DUAL_GC_USB_PID 0x0065 |
|
|
|
|
|
|
|
|
|
#define KEYBOARD_PID 0x0066 |
|
|
|
|
#define KEYBOARD_PID2 0x0067 |
|
|
|
|
#define KEYBOARD_JS_PID 0x0068 |
|
|
|
|
|
|
|
|
|
int keyboard_main(void); |
|
|
|
|
|
|
|
|
|
/* Those .c files are included rather than linked for we
|
|
|
|
|
* want the sizeof() operator to work on the arrays */ |
|
|
|
@ -139,6 +145,77 @@ static const struct cfg0 cfg0 PROGMEM = {
@@ -139,6 +145,77 @@ static const struct cfg0 cfg0 PROGMEM = {
|
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const struct cfg0 cfg0_kb PROGMEM = { |
|
|
|
|
.configdesc = { |
|
|
|
|
.bLength = sizeof(struct usb_configuration_descriptor), |
|
|
|
|
.bDescriptorType = CONFIGURATION_DESCRIPTOR, |
|
|
|
|
.wTotalLength = sizeof(cfg0), // includes all descriptors returned together
|
|
|
|
|
.bNumInterfaces = 1 + 1, // one interface per player + one management interface
|
|
|
|
|
.bConfigurationValue = 1, |
|
|
|
|
.bmAttributes = CFG_DESC_ATTR_RESERVED, // set Self-powred and remote-wakeup here if needed.
|
|
|
|
|
.bMaxPower = 25, // for 50mA
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Main interface, HID Keyboard
|
|
|
|
|
.interface = { |
|
|
|
|
.bLength = sizeof(struct usb_interface_descriptor), |
|
|
|
|
.bDescriptorType = INTERFACE_DESCRIPTOR, |
|
|
|
|
.bInterfaceNumber = 0, |
|
|
|
|
.bAlternateSetting = 0, |
|
|
|
|
.bNumEndpoints = 1, |
|
|
|
|
.bInterfaceClass = USB_DEVICE_CLASS_HID, |
|
|
|
|
.bInterfaceSubClass = HID_SUBCLASS_NONE, |
|
|
|
|
.bInterfaceProtocol = HID_PROTOCOL_NONE, |
|
|
|
|
}, |
|
|
|
|
.hid = { |
|
|
|
|
.bLength = sizeof(struct usb_hid_descriptor), |
|
|
|
|
.bDescriptorType = HID_DESCRIPTOR, |
|
|
|
|
.bcdHid = 0x0101, |
|
|
|
|
.bCountryCode = HID_COUNTRY_NOT_SUPPORTED, |
|
|
|
|
.bNumDescriptors = 1, // Only a report descriptor
|
|
|
|
|
.bClassDescriptorType = REPORT_DESCRIPTOR, |
|
|
|
|
.wClassDescriptorLength = sizeof(gcKeyboardReport), |
|
|
|
|
}, |
|
|
|
|
.ep1_in = { |
|
|
|
|
.bLength = sizeof(struct usb_endpoint_descriptor), |
|
|
|
|
.bDescriptorType = ENDPOINT_DESCRIPTOR, |
|
|
|
|
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 1, // 0x81
|
|
|
|
|
.bmAttributes = TRANSFER_TYPE_INT, |
|
|
|
|
.wMaxPacketsize = 16, |
|
|
|
|
.bInterval = LS_FS_INTERVAL_MS(1), |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Second HID interface for config and update
|
|
|
|
|
.interface_admin = { |
|
|
|
|
.bLength = sizeof(struct usb_interface_descriptor), |
|
|
|
|
.bDescriptorType = INTERFACE_DESCRIPTOR, |
|
|
|
|
.bInterfaceNumber = 1, |
|
|
|
|
.bAlternateSetting = 0, |
|
|
|
|
.bNumEndpoints = 1, |
|
|
|
|
.bInterfaceClass = USB_DEVICE_CLASS_HID, |
|
|
|
|
.bInterfaceSubClass = HID_SUBCLASS_NONE, |
|
|
|
|
.bInterfaceProtocol = HID_PROTOCOL_NONE, |
|
|
|
|
}, |
|
|
|
|
.hid_data = { |
|
|
|
|
.bLength = sizeof(struct usb_hid_descriptor), |
|
|
|
|
.bDescriptorType = HID_DESCRIPTOR, |
|
|
|
|
.bcdHid = 0x0101, |
|
|
|
|
.bCountryCode = HID_COUNTRY_NOT_SUPPORTED, |
|
|
|
|
.bNumDescriptors = 1, // Only a report descriptor
|
|
|
|
|
.bClassDescriptorType = REPORT_DESCRIPTOR, |
|
|
|
|
.wClassDescriptorLength = sizeof(dataHidReport), |
|
|
|
|
}, |
|
|
|
|
.ep2_in = { |
|
|
|
|
.bLength = sizeof(struct usb_endpoint_descriptor), |
|
|
|
|
.bDescriptorType = ENDPOINT_DESCRIPTOR, |
|
|
|
|
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 2, // 0x82
|
|
|
|
|
.bmAttributes = TRANSFER_TYPE_INT, |
|
|
|
|
.wMaxPacketsize = 64, |
|
|
|
|
.bInterval = LS_FS_INTERVAL_MS(1), |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct cfg0_2p { |
|
|
|
|
struct usb_configuration_descriptor configdesc; |
|
|
|
|
struct usb_interface_descriptor interface; |
|
|
|
@ -253,6 +330,107 @@ static const struct cfg0_2p cfg0_2p PROGMEM = {
@@ -253,6 +330,107 @@ static const struct cfg0_2p cfg0_2p PROGMEM = {
|
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const struct cfg0_2p cfg0_2p_keyboard PROGMEM = { |
|
|
|
|
.configdesc = { |
|
|
|
|
.bLength = sizeof(struct usb_configuration_descriptor), |
|
|
|
|
.bDescriptorType = CONFIGURATION_DESCRIPTOR, |
|
|
|
|
.wTotalLength = sizeof(cfg0_2p), // includes all descriptors returned together
|
|
|
|
|
.bNumInterfaces = 2 + 1, // one interface per player + one management interface
|
|
|
|
|
.bConfigurationValue = 1, |
|
|
|
|
.bmAttributes = CFG_DESC_ATTR_RESERVED, // set Self-powred and remote-wakeup here if needed.
|
|
|
|
|
.bMaxPower = 25, // for 50mA
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Joystick interface
|
|
|
|
|
.interface = { |
|
|
|
|
.bLength = sizeof(struct usb_interface_descriptor), |
|
|
|
|
.bDescriptorType = INTERFACE_DESCRIPTOR, |
|
|
|
|
.bInterfaceNumber = 0, |
|
|
|
|
.bAlternateSetting = 0, |
|
|
|
|
.bNumEndpoints = 1, |
|
|
|
|
.bInterfaceClass = USB_DEVICE_CLASS_HID, |
|
|
|
|
.bInterfaceSubClass = HID_SUBCLASS_NONE, |
|
|
|
|
.bInterfaceProtocol = HID_PROTOCOL_NONE, |
|
|
|
|
}, |
|
|
|
|
.hid = { |
|
|
|
|
.bLength = sizeof(struct usb_hid_descriptor), |
|
|
|
|
.bDescriptorType = HID_DESCRIPTOR, |
|
|
|
|
.bcdHid = 0x0101, |
|
|
|
|
.bCountryCode = HID_COUNTRY_NOT_SUPPORTED, |
|
|
|
|
.bNumDescriptors = 1, // Only a report descriptor
|
|
|
|
|
.bClassDescriptorType = REPORT_DESCRIPTOR, |
|
|
|
|
.wClassDescriptorLength = sizeof(gcn64_usbHidReportDescriptor), |
|
|
|
|
}, |
|
|
|
|
.ep1_in = { |
|
|
|
|
.bLength = sizeof(struct usb_endpoint_descriptor), |
|
|
|
|
.bDescriptorType = ENDPOINT_DESCRIPTOR, |
|
|
|
|
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 1, // 0x81
|
|
|
|
|
.bmAttributes = TRANSFER_TYPE_INT, |
|
|
|
|
.wMaxPacketsize = 16, |
|
|
|
|
.bInterval = LS_FS_INTERVAL_MS(1), |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// HID Keyboard interface
|
|
|
|
|
.interface_p2 = { |
|
|
|
|
.bLength = sizeof(struct usb_interface_descriptor), |
|
|
|
|
.bDescriptorType = INTERFACE_DESCRIPTOR, |
|
|
|
|
.bInterfaceNumber = 1, |
|
|
|
|
.bAlternateSetting = 0, |
|
|
|
|
.bNumEndpoints = 1, |
|
|
|
|
.bInterfaceClass = USB_DEVICE_CLASS_HID, |
|
|
|
|
.bInterfaceSubClass = HID_SUBCLASS_NONE, |
|
|
|
|
.bInterfaceProtocol = HID_PROTOCOL_NONE, |
|
|
|
|
}, |
|
|
|
|
.hid_p2 = { |
|
|
|
|
.bLength = sizeof(struct usb_hid_descriptor), |
|
|
|
|
.bDescriptorType = HID_DESCRIPTOR, |
|
|
|
|
.bcdHid = 0x0101, |
|
|
|
|
.bCountryCode = HID_COUNTRY_NOT_SUPPORTED, |
|
|
|
|
.bNumDescriptors = 1, // Only a report descriptor
|
|
|
|
|
.bClassDescriptorType = REPORT_DESCRIPTOR, |
|
|
|
|
.wClassDescriptorLength = sizeof(gcKeyboardReport), |
|
|
|
|
}, |
|
|
|
|
.ep2_in = { |
|
|
|
|
.bLength = sizeof(struct usb_endpoint_descriptor), |
|
|
|
|
.bDescriptorType = ENDPOINT_DESCRIPTOR, |
|
|
|
|
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 2, // 0x82
|
|
|
|
|
.bmAttributes = TRANSFER_TYPE_INT, |
|
|
|
|
.wMaxPacketsize = 16, |
|
|
|
|
.bInterval = LS_FS_INTERVAL_MS(1), |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Second HID interface for config and update
|
|
|
|
|
.interface_admin = { |
|
|
|
|
.bLength = sizeof(struct usb_interface_descriptor), |
|
|
|
|
.bDescriptorType = INTERFACE_DESCRIPTOR, |
|
|
|
|
.bInterfaceNumber = 2, |
|
|
|
|
.bAlternateSetting = 0, |
|
|
|
|
.bNumEndpoints = 1, |
|
|
|
|
.bInterfaceClass = USB_DEVICE_CLASS_HID, |
|
|
|
|
.bInterfaceSubClass = HID_SUBCLASS_NONE, |
|
|
|
|
.bInterfaceProtocol = HID_PROTOCOL_NONE, |
|
|
|
|
}, |
|
|
|
|
.hid_data = { |
|
|
|
|
.bLength = sizeof(struct usb_hid_descriptor), |
|
|
|
|
.bDescriptorType = HID_DESCRIPTOR, |
|
|
|
|
.bcdHid = 0x0101, |
|
|
|
|
.bCountryCode = HID_COUNTRY_NOT_SUPPORTED, |
|
|
|
|
.bNumDescriptors = 1, // Only a report descriptor
|
|
|
|
|
.bClassDescriptorType = REPORT_DESCRIPTOR, |
|
|
|
|
.wClassDescriptorLength = sizeof(dataHidReport), |
|
|
|
|
}, |
|
|
|
|
.ep3_in = { |
|
|
|
|
.bLength = sizeof(struct usb_endpoint_descriptor), |
|
|
|
|
.bDescriptorType = ENDPOINT_DESCRIPTOR, |
|
|
|
|
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 3, // 0x83
|
|
|
|
|
.bmAttributes = TRANSFER_TYPE_INT, |
|
|
|
|
.wMaxPacketsize = 64, |
|
|
|
|
.bInterval = LS_FS_INTERVAL_MS(1), |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct usb_device_descriptor device_descriptor = { |
|
|
|
|
.bLength = sizeof(struct usb_device_descriptor), |
|
|
|
|
.bDescriptorType = DEVICE_DESCRIPTOR, |
|
|
|
@ -376,13 +554,13 @@ Gamepad *detectPad(unsigned char chn)
@@ -376,13 +554,13 @@ Gamepad *detectPad(unsigned char chn)
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
case CONTROLLER_IS_N64: |
|
|
|
|
printf("Detected N64 controller\n"); |
|
|
|
|
return n64GetGamepad(); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case CONTROLLER_IS_GC: |
|
|
|
|
printf("Detected GC controller\n"); |
|
|
|
|
return gamecubeGetGamepad(); |
|
|
|
|
|
|
|
|
|
case CONTROLLER_IS_GC_KEYBOARD: |
|
|
|
|
return gamecubeGetKeyboard(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
@ -418,13 +596,48 @@ static void forceVibration(uint8_t channel, uint8_t force)
@@ -418,13 +596,48 @@ static void forceVibration(uint8_t channel, uint8_t force)
|
|
|
|
|
|
|
|
|
|
static uint8_t getSupportedModes(uint8_t *dst) |
|
|
|
|
{ |
|
|
|
|
dst[0] = CFG_MODE_STANDARD; |
|
|
|
|
dst[1] = CFG_MODE_N64_ONLY; |
|
|
|
|
dst[2] = CFG_MODE_GC_ONLY; |
|
|
|
|
dst[3] = CFG_MODE_2P_STANDARD; |
|
|
|
|
dst[4] = CFG_MODE_2P_N64_ONLY; |
|
|
|
|
dst[5] = CFG_MODE_2P_GC_ONLY; |
|
|
|
|
return 6; |
|
|
|
|
uint8_t idx = 0; |
|
|
|
|
|
|
|
|
|
switch (g_eeprom_data.cfg.mode) |
|
|
|
|
{ |
|
|
|
|
// Allow toggling between keyboard and joystick modes on
|
|
|
|
|
// single-port gamecube adapter
|
|
|
|
|
case CFG_MODE_GC_ONLY: |
|
|
|
|
case CFG_MODE_KEYBOARD: |
|
|
|
|
dst[idx++] = CFG_MODE_GC_ONLY; |
|
|
|
|
dst[idx++] = CFG_MODE_KEYBOARD; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
// Allow toggling between two joysticks and joystick + keyboard modes
|
|
|
|
|
// on dual-port gamecube adapter
|
|
|
|
|
case CFG_MODE_2P_GC_ONLY: |
|
|
|
|
case CFG_MODE_KB_AND_JS: |
|
|
|
|
dst[idx++] = CFG_MODE_2P_GC_ONLY; |
|
|
|
|
dst[idx++] = CFG_MODE_KB_AND_JS; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
// On N64/GC adapters, there is a GC port so we should support
|
|
|
|
|
// keyboards there. Use KEYBOARD_2 config here to avoid mixup
|
|
|
|
|
// with the GC-only adapter variation.
|
|
|
|
|
case CFG_MODE_STANDARD: |
|
|
|
|
case CFG_MODE_KEYBOARD_2: |
|
|
|
|
dst[idx++] = CFG_MODE_STANDARD; |
|
|
|
|
dst[idx++] = CFG_MODE_KEYBOARD_2; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
dst[idx++] = CFG_MODE_STANDARD; |
|
|
|
|
dst[idx++] = CFG_MODE_N64_ONLY; |
|
|
|
|
dst[idx++] = CFG_MODE_GC_ONLY; |
|
|
|
|
dst[idx++] = CFG_MODE_2P_STANDARD; |
|
|
|
|
dst[idx++] = CFG_MODE_2P_N64_ONLY; |
|
|
|
|
dst[idx++] = CFG_MODE_2P_GC_ONLY; |
|
|
|
|
dst[idx++] = CFG_MODE_KEYBOARD; |
|
|
|
|
dst[idx++] = CFG_MODE_KB_AND_JS; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return idx; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct hiddata_ops hiddata_ops = { |
|
|
|
@ -491,6 +704,12 @@ int main(void)
@@ -491,6 +704,12 @@ int main(void)
|
|
|
|
|
device_descriptor.idProduct = DUAL_GC_USB_PID; |
|
|
|
|
num_players = 2; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case CFG_MODE_KB_AND_JS: |
|
|
|
|
case CFG_MODE_KEYBOARD: |
|
|
|
|
case CFG_MODE_KEYBOARD_2: |
|
|
|
|
keyboard_main(); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2-players common
|
|
|
|
@ -623,3 +842,204 @@ int main(void)
@@ -623,3 +842,204 @@ int main(void)
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int keyboard_main(void) |
|
|
|
|
{ |
|
|
|
|
Gamepad *pads[MAX_PLAYERS] = { }; |
|
|
|
|
gamepad_data pad_data; |
|
|
|
|
uint8_t gamepad_vibrate = 0; |
|
|
|
|
uint8_t state = STATE_WAIT_POLLTIME; |
|
|
|
|
uint8_t channel; |
|
|
|
|
uint8_t num_players = 1; |
|
|
|
|
uint8_t i; |
|
|
|
|
|
|
|
|
|
hwinit(); |
|
|
|
|
usart1_init(); |
|
|
|
|
eeprom_init(); |
|
|
|
|
intervaltimer_init(); |
|
|
|
|
intervaltimer2_init(); |
|
|
|
|
stkchk_init(); |
|
|
|
|
|
|
|
|
|
switch (g_eeprom_data.cfg.mode) |
|
|
|
|
{ |
|
|
|
|
default: |
|
|
|
|
case CFG_MODE_KEYBOARD_2: |
|
|
|
|
usbstrings_changeProductString_P(PSTR("KB to USB v"VERSIONSTR_SHORT)); |
|
|
|
|
device_descriptor.idProduct = KEYBOARD_PID2; |
|
|
|
|
|
|
|
|
|
usb_params.configdesc = (PGM_VOID_P)&cfg0_kb; |
|
|
|
|
usb_params.configdesc_ttllen = sizeof(cfg0_kb); |
|
|
|
|
|
|
|
|
|
// replace Joystick report descriptor by keyboard
|
|
|
|
|
usb_params.hid_params[0].reportdesc = gcKeyboardReport; |
|
|
|
|
usb_params.hid_params[0].reportdesc_len = sizeof(gcKeyboardReport); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case CFG_MODE_KEYBOARD: |
|
|
|
|
usbstrings_changeProductString_P(PSTR("GC KB to USB v"VERSIONSTR_SHORT)); |
|
|
|
|
device_descriptor.idProduct = KEYBOARD_PID; |
|
|
|
|
|
|
|
|
|
usb_params.configdesc = (PGM_VOID_P)&cfg0_kb; |
|
|
|
|
usb_params.configdesc_ttllen = sizeof(cfg0_kb); |
|
|
|
|
|
|
|
|
|
// replace Joystick report descriptor by keyboard
|
|
|
|
|
usb_params.hid_params[0].reportdesc = gcKeyboardReport; |
|
|
|
|
usb_params.hid_params[0].reportdesc_len = sizeof(gcKeyboardReport); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case CFG_MODE_KB_AND_JS: |
|
|
|
|
usbstrings_changeProductString_P(PSTR("GC KB+JS to USB v"VERSIONSTR_SHORT)); |
|
|
|
|
device_descriptor.idProduct = KEYBOARD_JS_PID; |
|
|
|
|
|
|
|
|
|
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p_keyboard; |
|
|
|
|
usb_params.configdesc_ttllen = sizeof(cfg0_2p_keyboard); |
|
|
|
|
|
|
|
|
|
// Move the management interface to the last position
|
|
|
|
|
memcpy(usb_params.hid_params + 2, usb_params.hid_params + 1, sizeof(struct usb_hid_parameters)); |
|
|
|
|
// Add a second player interface between them (still a joystick)
|
|
|
|
|
memcpy(usb_params.hid_params + 1, usb_params.hid_params + 0, sizeof(struct usb_hid_parameters)); |
|
|
|
|
// Convert second Joystick report descriptor to a keyboard
|
|
|
|
|
usb_params.hid_params[1].reportdesc = gcKeyboardReport; |
|
|
|
|
usb_params.hid_params[1].reportdesc_len = sizeof(gcKeyboardReport); |
|
|
|
|
|
|
|
|
|
usb_params.n_hid_interfaces = 3; |
|
|
|
|
num_players = 2; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i=0; i<num_players; i++) { |
|
|
|
|
usbpad_init(&usbpads[i]); |
|
|
|
|
usb_params.hid_params[i].ctx = &usbpads[i]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sei(); |
|
|
|
|
usb_init(&usb_params); |
|
|
|
|
|
|
|
|
|
// Timebase for force feedback 'loop count'
|
|
|
|
|
intervaltimer2_set16ms(); |
|
|
|
|
|
|
|
|
|
while (1) |
|
|
|
|
{ |
|
|
|
|
static char last_v[MAX_PLAYERS] = { }; |
|
|
|
|
|
|
|
|
|
if (stkchk_verify()) { |
|
|
|
|
enterBootLoader(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
usb_doTasks(); |
|
|
|
|
hiddata_doTask(&hiddata_ops); |
|
|
|
|
// Run vibration tasks
|
|
|
|
|
if (intervaltimer2_get()) { |
|
|
|
|
for (channel=0; channel < num_players; channel++) { |
|
|
|
|
usbpad_vibrationTask(&usbpads[channel]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch(state) |
|
|
|
|
{ |
|
|
|
|
case STATE_WAIT_POLLTIME: |
|
|
|
|
if (!g_polling_suspended) { |
|
|
|
|
intervaltimer_set(g_eeprom_data.cfg.poll_interval[0]); |
|
|
|
|
if (intervaltimer_get()) { |
|
|
|
|
state = STATE_POLL_PAD; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case STATE_POLL_PAD: |
|
|
|
|
for (channel=0; channel<num_players; channel++) |
|
|
|
|
{ |
|
|
|
|
/* Try to auto-detect controller if none*/ |
|
|
|
|
if (!pads[channel]) { |
|
|
|
|
pads[channel] = detectPad(channel); |
|
|
|
|
if (pads[channel] && (pads[channel]->hotplug)) { |
|
|
|
|
// For gamecube, this make sure the next
|
|
|
|
|
// analog values we read become the center
|
|
|
|
|
// reference.
|
|
|
|
|
pads[channel]->hotplug(channel); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Read from the pad by calling update */ |
|
|
|
|
if (pads[channel]) { |
|
|
|
|
if (pads[channel]->update(channel)) { |
|
|
|
|
error_count[channel]++; |
|
|
|
|
if (error_count[channel] > MAX_READ_ERRORS) { |
|
|
|
|
pads[channel] = NULL; |
|
|
|
|
error_count[channel] = 0; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
error_count[channel]=0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (pads[channel]->changed(channel)) |
|
|
|
|
{ |
|
|
|
|
pads[channel]->getReport(channel, &pad_data); |
|
|
|
|
|
|
|
|
|
if ((num_players == 1) && (channel == 0)) { |
|
|
|
|
// single-port adapter in keyboard mode (kb in port 1)
|
|
|
|
|
usbpad_update_kb(&usbpads[channel], &pad_data); |
|
|
|
|
} else if ((num_players == 2) && (channel == 1)) { |
|
|
|
|
// dual-port adapter in keyboard mode (kb in port 2)
|
|
|
|
|
usbpad_update_kb(&usbpads[channel], &pad_data); |
|
|
|
|
} else { |
|
|
|
|
usbpad_update(&usbpads[channel], &pad_data); |
|
|
|
|
} |
|
|
|
|
state = STATE_WAIT_INTERRUPT_READY; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* Just make sure the gamepad state holds valid data
|
|
|
|
|
* to appear inactive (no buttons and axes in neutral) */ |
|
|
|
|
usbpad_update(&usbpads[channel], NULL); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/* If there were change on any of the gamepads, state will
|
|
|
|
|
* be set to STATE_WAIT_INTERRUPT_READY. Otherwise, go back |
|
|
|
|
* to WAIT_POLLTIME. */ |
|
|
|
|
if (state == STATE_POLL_PAD) { |
|
|
|
|
state = STATE_WAIT_POLLTIME; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case STATE_WAIT_INTERRUPT_READY: |
|
|
|
|
/* Wait until one of the interrupt endpoint is ready */ |
|
|
|
|
if (usb_interruptReady_ep1() || (num_players>1 && usb_interruptReady_ep2())) { |
|
|
|
|
state = STATE_TRANSMIT; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case STATE_TRANSMIT: |
|
|
|
|
if (usb_interruptReady_ep1()) { |
|
|
|
|
if (num_players == 1) { |
|
|
|
|
// Single-port adapters have the keyboard in port 1
|
|
|
|
|
usb_interruptSend_ep1(usbpad_getReportBuffer(&usbpads[0]), usbpad_getReportSizeKB()); |
|
|
|
|
} else { |
|
|
|
|
usb_interruptSend_ep1(usbpad_getReportBuffer(&usbpads[0]), usbpad_getReportSize()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Keyboard is always in second port on dual port adapters
|
|
|
|
|
if (num_players>1 && usb_interruptReady_ep2()) { |
|
|
|
|
usb_interruptSend_ep2(usbpad_getReportBuffer(&usbpads[1]), usbpad_getReportSizeKB()); |
|
|
|
|
} |
|
|
|
|
state = STATE_WAIT_POLLTIME; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (channel=0; channel < num_players; channel++) { |
|
|
|
|
gamepad_vibrate = usbpad_mustVibrate(&usbpads[channel]); |
|
|
|
|
if (last_v[channel] != gamepad_vibrate) { |
|
|
|
|
if (pads[channel] && pads[channel]->setVibration) { |
|
|
|
|
pads[channel]->setVibration(channel, gamepad_vibrate); |
|
|
|
|
} |
|
|
|
|
last_v[channel] = gamepad_vibrate; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|