Dual controller now available as a configured flavor

This commit is contained in:
Raphael Assenat 2016-10-10 14:48:42 -04:00
parent 4ecc3f571e
commit f6e4281321
2 changed files with 135 additions and 35 deletions

166
main.c
View File

@ -38,12 +38,16 @@
#include "intervaltimer.h" #include "intervaltimer.h"
#include "requests.h" #include "requests.h"
#define NUM_PLAYERS 2 #define MAX_PLAYERS 2
#define GCN64_USB_PID 0x001D #define GCN64_USB_PID 0x001D
#define N64_USB_PID 0x0020 #define N64_USB_PID 0x0020
#define GC_USB_PID 0x0021 #define GC_USB_PID 0x0021
#define DUAL_GCN64_USB_PID 0x0022
#define DUAL_N64_USB_PID 0x0030
#define DUAL_GC_USB_PID 0x0031
/* Those .c files are included rather than linked for we /* Those .c files are included rather than linked for we
* want the sizeof() operator to work on the arrays */ * want the sizeof() operator to work on the arrays */
#include "reportdesc.c" #include "reportdesc.c"
@ -60,22 +64,6 @@ struct cfg0 {
struct usb_interface_descriptor interface_admin; struct usb_interface_descriptor interface_admin;
struct usb_hid_descriptor hid_data; struct usb_hid_descriptor hid_data;
struct usb_endpoint_descriptor ep2_in; struct usb_endpoint_descriptor ep2_in;
#if NUM_PLAYERS >= 2
struct usb_interface_descriptor interface_p2;
struct usb_hid_descriptor hid_p2;
struct usb_endpoint_descriptor ep3_in;
#endif
#if NUM_PLAYERS >= 3
struct usb_interface_descriptor interface_p3;
struct usb_hid_descriptor hid_p3;
struct usb_endpoint_descriptor ep4_in;
#endif
#if NUM_PLAYERS >= 4
struct usb_interface_descriptor interface_p4;
struct usb_hid_descriptor hid_p4;
struct usb_endpoint_descriptor ep5_in;
#endif
}; };
static const struct cfg0 cfg0 PROGMEM = { static const struct cfg0 cfg0 PROGMEM = {
@ -83,7 +71,92 @@ static const struct cfg0 cfg0 PROGMEM = {
.bLength = sizeof(struct usb_configuration_descriptor), .bLength = sizeof(struct usb_configuration_descriptor),
.bDescriptorType = CONFIGURATION_DESCRIPTOR, .bDescriptorType = CONFIGURATION_DESCRIPTOR,
.wTotalLength = sizeof(cfg0), // includes all descriptors returned together .wTotalLength = sizeof(cfg0), // includes all descriptors returned together
.bNumInterfaces = NUM_PLAYERS + 1, // one interface per player + one management interface .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 (player 1)
.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),
},
// 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;
struct usb_hid_descriptor hid;
struct usb_endpoint_descriptor ep1_in;
struct usb_interface_descriptor interface_admin;
struct usb_hid_descriptor hid_data;
struct usb_endpoint_descriptor ep2_in;
struct usb_interface_descriptor interface_p2;
struct usb_hid_descriptor hid_p2;
struct usb_endpoint_descriptor ep3_in;
};
static const struct cfg0_2p cfg0_2p 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, .bConfigurationValue = 1,
.bmAttributes = CFG_DESC_ATTR_RESERVED, // set Self-powred and remote-wakeup here if needed. .bmAttributes = CFG_DESC_ATTR_RESERVED, // set Self-powred and remote-wakeup here if needed.
.bMaxPower = 25, // for 50mA .bMaxPower = 25, // for 50mA
@ -147,7 +220,6 @@ static const struct cfg0 cfg0 PROGMEM = {
.bInterval = LS_FS_INTERVAL_MS(1), .bInterval = LS_FS_INTERVAL_MS(1),
}, },
#if NUM_PLAYERS >= 2
// Main interface, HID (player 2) // Main interface, HID (player 2)
.interface_p2 = { .interface_p2 = {
.bLength = sizeof(struct usb_interface_descriptor), .bLength = sizeof(struct usb_interface_descriptor),
@ -176,8 +248,6 @@ static const struct cfg0 cfg0 PROGMEM = {
.wMaxPacketsize = 16, .wMaxPacketsize = 16,
.bInterval = LS_FS_INTERVAL_MS(1), .bInterval = LS_FS_INTERVAL_MS(1),
}, },
#endif
}; };
struct usb_device_descriptor device_descriptor = { struct usb_device_descriptor device_descriptor = {
@ -213,12 +283,12 @@ static struct usb_parameters usb_params = {
.flags = USB_PARAM_FLAG_CONFDESC_PROGMEM | .flags = USB_PARAM_FLAG_CONFDESC_PROGMEM |
USB_PARAM_FLAG_REPORTDESC_PROGMEM, USB_PARAM_FLAG_REPORTDESC_PROGMEM,
.devdesc = (PGM_VOID_P)&device_descriptor, .devdesc = (PGM_VOID_P)&device_descriptor,
.configdesc = (PGM_VOID_P)&cfg0, .configdesc = (PGM_VOID_P)&cfg0, // Patched in main() for two players
.configdesc_ttllen = sizeof(cfg0), .configdesc_ttllen = sizeof(cfg0), // Patched in main() for two players
.num_strings = NUM_USB_STRINGS, .num_strings = NUM_USB_STRINGS,
.strings = g_usb_strings, .strings = g_usb_strings,
.n_hid_interfaces = 1 + NUM_PLAYERS, .n_hid_interfaces = 1 + 1, // One per player + one management interface (patched in main() for two players)
.hid_params = { .hid_params = {
[0] = { [0] = {
.reportdesc = gcn64_usbHidReportDescriptor, .reportdesc = gcn64_usbHidReportDescriptor,
@ -232,14 +302,12 @@ static struct usb_parameters usb_params = {
.getReport = hiddata_get_report, .getReport = hiddata_get_report,
.setReport = hiddata_set_report, .setReport = hiddata_set_report,
}, },
#if NUM_PLAYERS >= 2
[2] = { [2] = {
.reportdesc = gcn64_usbHidReportDescriptor, .reportdesc = gcn64_usbHidReportDescriptor,
.reportdesc_len = sizeof(gcn64_usbHidReportDescriptor), .reportdesc_len = sizeof(gcn64_usbHidReportDescriptor),
.getReport = _usbpad_hid_get_report, .getReport = _usbpad_hid_get_report,
.setReport = _usbpad_hid_set_report, .setReport = _usbpad_hid_set_report,
}, },
#endif
}, },
}; };
@ -343,7 +411,7 @@ void pollDelay(void)
} }
} }
static struct usbpad usbpads[NUM_PLAYERS]; static struct usbpad usbpads[MAX_PLAYERS];
static char g_polling_suspended = 0; static char g_polling_suspended = 0;
static void setSuspendPolling(uint8_t suspend) static void setSuspendPolling(uint8_t suspend)
@ -353,7 +421,7 @@ static void setSuspendPolling(uint8_t suspend)
static void forceVibration(uint8_t channel, uint8_t force) static void forceVibration(uint8_t channel, uint8_t force)
{ {
if (channel < NUM_PLAYERS) { if (channel < MAX_PLAYERS) {
usbpad_forceVibrate(&usbpads[channel], force); usbpad_forceVibrate(&usbpads[channel], force);
} }
} }
@ -372,20 +440,21 @@ static struct hiddata_ops hiddata_ops = {
int main(void) int main(void)
{ {
Gamepad *pads[NUM_PLAYERS] = { }; Gamepad *pads[MAX_PLAYERS] = { };
gamepad_data pad_data; gamepad_data pad_data;
unsigned char gamepad_vibrate = 0; unsigned char gamepad_vibrate = 0;
unsigned char state = STATE_WAIT_POLLTIME; unsigned char state = STATE_WAIT_POLLTIME;
int error_count[NUM_PLAYERS] = { }; int error_count[MAX_PLAYERS] = { };
int i; int i;
int channel; int channel;
int num_players = 1;
hwinit(); hwinit();
usart1_init(); usart1_init();
eeprom_init(); eeprom_init();
intervaltimer_init(); intervaltimer_init();
for (i=0; i<NUM_PLAYERS; i++) { for (i=0; i<num_players; i++) {
usbpad_init(&usbpads[i]); usbpad_init(&usbpads[i]);
} }
@ -404,6 +473,33 @@ int main(void)
usbstrings_changeProductString(L"Gamecube to USB v"VERSIONSTR_SHORT); usbstrings_changeProductString(L"Gamecube to USB v"VERSIONSTR_SHORT);
device_descriptor.idProduct = GC_USB_PID; device_descriptor.idProduct = GC_USB_PID;
break; break;
case CFG_MODE_2P_STANDARD:
usbstrings_changeProductString(L"Dual GC/N64 to USB v"VERSIONSTR_SHORT);
device_descriptor.idProduct = DUAL_GCN64_USB_PID;
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p;
usb_params.configdesc_ttllen = sizeof(cfg0_2p);
usb_params.n_hid_interfaces = 3;
num_players = 2;
break;
case CFG_MODE_2P_N64_ONLY:
usbstrings_changeProductString(L"Dual N64 to USB v"VERSIONSTR_SHORT);
device_descriptor.idProduct = DUAL_N64_USB_PID;
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p;
usb_params.configdesc_ttllen = sizeof(cfg0_2p);
usb_params.n_hid_interfaces = 3;
num_players = 2;
break;
case CFG_MODE_2P_GC_ONLY:
usbstrings_changeProductString(L"Dual Gamecube to USB v"VERSIONSTR_SHORT);
device_descriptor.idProduct = DUAL_GC_USB_PID;
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p;
usb_params.configdesc_ttllen = sizeof(cfg0_2p);
usb_params.n_hid_interfaces = 3;
num_players = 2;
break;
} }
sei(); sei();
@ -411,7 +507,7 @@ int main(void)
while (1) while (1)
{ {
static char last_v[NUM_PLAYERS] = { }; static char last_v[MAX_PLAYERS] = { };
usb_doTasks(); usb_doTasks();
hiddata_doTask(&hiddata_ops); hiddata_doTask(&hiddata_ops);
@ -428,7 +524,7 @@ int main(void)
break; break;
case STATE_POLL_PAD: case STATE_POLL_PAD:
for (channel=0; channel<NUM_PLAYERS; channel++) for (channel=0; channel<num_players; channel++)
{ {
/* Try to auto-detect controller if none*/ /* Try to auto-detect controller if none*/
if (!pads[channel]) { if (!pads[channel]) {
@ -483,7 +579,7 @@ int main(void)
case STATE_TRANSMIT: case STATE_TRANSMIT:
usb_interruptSend_ep1(usbpad_getReportBuffer(&usbpads[0]), usbpad_getReportSize()); usb_interruptSend_ep1(usbpad_getReportBuffer(&usbpads[0]), usbpad_getReportSize());
if (NUM_PLAYERS > 1) { if (num_players > 1) {
state = STATE_WAIT_INTERRUPT_READY_P2; state = STATE_WAIT_INTERRUPT_READY_P2;
} else { } else {
state = STATE_WAIT_POLLTIME; state = STATE_WAIT_POLLTIME;
@ -503,7 +599,7 @@ int main(void)
} }
for (channel=0; channel < NUM_PLAYERS; channel++) { for (channel=0; channel < num_players; channel++) {
gamepad_vibrate = usbpad_mustVibrate(&usbpads[channel]); gamepad_vibrate = usbpad_mustVibrate(&usbpads[channel]);
if (last_v[channel] != gamepad_vibrate) { if (last_v[channel] != gamepad_vibrate) {
if (pads[channel] && pads[channel]->setVibration) { if (pads[channel] && pads[channel]->setVibration) {

View File

@ -20,6 +20,10 @@
#define CFG_MODE_N64_ONLY 0x01 #define CFG_MODE_N64_ONLY 0x01
#define CFG_MODE_GC_ONLY 0x02 #define CFG_MODE_GC_ONLY 0x02
#define CFG_MODE_2P_STANDARD 0x10
#define CFG_MODE_2P_N64_ONLY 0x11
#define CFG_MODE_2P_GC_ONLY 0x12
#define CFG_PARAM_SERIAL 0x01 #define CFG_PARAM_SERIAL 0x01
#define CFG_PARAM_POLL_INTERVAL0 0x10 #define CFG_PARAM_POLL_INTERVAL0 0x10