mirror of
https://github.com/raphnet/gc_n64_usb-v3
synced 2024-12-21 23:08:53 -05:00
Dual controller now available as a configured flavor
This commit is contained in:
parent
4ecc3f571e
commit
f6e4281321
166
main.c
166
main.c
@ -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) {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user