1
0
mirror of https://github.com/raphnet/gc_n64_usb-v3 synced 2024-11-15 21:55:06 -05:00

Support for an extra interrupt endpoint

- Reduced interrupt endpoint size (reports are 15 bytes so it fits in
   16)
This commit is contained in:
Raphael Assenat 2016-10-09 23:47:36 -04:00
parent fe3814f7d1
commit 90aae55470
2 changed files with 113 additions and 65 deletions

169
usb.c
View File

@ -1,5 +1,5 @@
/* gc_n64_usb : Gamecube or N64 controller to USB firmware
Copyright (C) 2007-2013 Raphael Assenat <raph@raphnet.net>
Copyright (C) 2007-2016 Raphael Assenat <raph@raphnet.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -37,6 +37,8 @@ static uint8_t g_device_state = STATE_DEFAULT;
static uint8_t g_current_config;
static void *interrupt_data;
static volatile int interrupt_data_len = -1;
static void *interrupt_data3;
static volatile int interrupt_data_len3 = -1;
#define CONTROL_WRITE_BUFSIZE 64
static struct usb_request control_write_rq;
@ -64,7 +66,7 @@ static int wcslen(const wchar_t *str)
return i;
}
static void setupEndpoints(void)
static void setupEndpoints()
{
/*** EP0 ***/
@ -89,7 +91,7 @@ static void setupEndpoints(void)
UECONX = 1<<EPEN; // activate endpoint
UECFG0X = (3<<6) | (1<<EPDIR); // Interrupt IN
UEIENX = (1<<TXINE);
UECFG1X |= (1<<EPSIZE1)|(1<<ALLOC); // 32 bytes, one bank, and allocate
UECFG1X = (1<<EPSIZE0)|(1<<ALLOC); // 16 bytes, one bank, and allocate
UEINTX = 0;
if (!(UESTA0X & (1<<CFGOK))) {
@ -110,6 +112,23 @@ static void setupEndpoints(void)
printf_P(PSTR("CFG EP2 fail\r\n"));
return;
}
if (g_params->n_hid_interfaces > 2) {
/*** EP3 ***/
UENUM = 0x03; // select endpoint
UECONX = 1<<EPEN; // activate endpoint
UECFG0X = (3<<6) | (1<<EPDIR); // Interrupt IN
UEIENX = (1<<TXINE);
UECFG1X = (1<<EPSIZE0)|(1<<ALLOC); // 16 bytes, one bank, and allocate
UEINTX = 0;
if (!(UESTA0X & (1<<CFGOK))) {
printf_P(PSTR("CFG EP3 fail\r\n"));
while(1);
return;
}
}
}
// Requires UENUM already set
@ -157,6 +176,33 @@ static void buf2EP(uint8_t epnum, const void *src, uint16_t len, uint16_t max_le
}
}
/**
*/
static void longDescriptorHelper(const uint8_t *data, uint16_t len, uint16_t rq_len, uint8_t progmem)
{
uint16_t todo = rq_len;
uint16_t pos = 0;
while(1)
{
if (todo > 64) {
buf2EP(0, data+pos, 64, 64, progmem);
UEINTX &= ~(1<<TXINI);
pos += 64;
todo -= 64;
while (!(UEINTX & (1<<TXINI)));
}
else {
buf2EP(0, data+pos, todo,
todo,
progmem);
// UEINTX &= ~(1<<TXINI);
// while (!(UEINTX & (1<<TXINI)));
break;
}
}
}
static void handleSetupPacket(struct usb_request *rq)
{
char unhandled = 0;
@ -279,8 +325,8 @@ static void handleSetupPacket(struct usb_request *rq)
g_params->flags & USB_PARAM_FLAG_DEVDESC_PROGMEM);
break;
case CONFIGURATION_DESCRIPTOR:
// Check index if more than 1 config
buf2EP(0, (unsigned char*)g_params->configdesc, g_params->configdesc_ttllen,
// Would need to check index if more than 1 configs...
longDescriptorHelper(g_params->configdesc, g_params->configdesc_ttllen,
rq->wLength, g_params->flags & USB_PARAM_FLAG_CONFDESC_PROGMEM);
break;
case STRING_DESCRIPTOR:
@ -352,51 +398,17 @@ static void handleSetupPacket(struct usb_request *rq)
{
case REPORT_DESCRIPTOR:
{
uint16_t rqlen = rq->wLength;
uint16_t todo = rqlen;
uint16_t pos = 0;
unsigned char *reportdesc;
// HID 1.1 : 7.1.1 Get_Descriptor request. wIndex is the interface number.
//
if (rq->wIndex > g_params->n_hid_interfaces)
if (rq->wIndex > g_params->n_hid_interfaces) {
unhandled = 1;
break;
reportdesc = (unsigned char*)g_params->hid_params[rq->wIndex].reportdesc;
if (rqlen > g_params->hid_params[rq->wIndex].reportdesc_len) {
// rqlen = g_params->hid_params[rq->wIndex].reportdesc_len;
};
// printf_P(PSTR("t: %02x, rq: 0x%02x, val: %04x, l: %d\r\n"), rq->bmRequestType, rq->bRequest, rq->wValue, rq->wLength);
while(1)
{
// printf_P(PSTR("pos %d todo %d\r\n"), pos, todo);
if (todo > 64) {
buf2EP(0, reportdesc+pos, 64,
64,
g_params->flags & USB_PARAM_FLAG_REPORTDESC_PROGMEM);
UEINTX &= ~(1<<TXINI);
pos += 64;
todo -= 64;
while (!(UEINTX & (1<<TXINI)));
} else {
buf2EP(0, reportdesc+pos, todo,
todo,
g_params->flags & USB_PARAM_FLAG_REPORTDESC_PROGMEM);
UEINTX &= ~(1<<TXINI);
while (!(UEINTX & (1<<TXINI)));
break;
}
}
while (1)
{
if (UEINTX & (1<<RXOUTI)) {
UEINTX &= ~(1<<RXOUTI); // ACK
return;
}
}
longDescriptorHelper(g_params->hid_params[rq->wIndex].reportdesc,
g_params->hid_params[rq->wIndex].reportdesc_len,
rq->wLength,
g_params->flags & USB_PARAM_FLAG_REPORTDESC_PROGMEM);
}
break;
@ -576,6 +588,28 @@ ISR(USB_GEN_vect)
}
}
static void handle_interrupt_xmit(uint8_t ep, void **interrupt_data, volatile int *interrupt_data_len)
{
uint8_t i;
UENUM = ep;
i = UEINTX;
if (i & (1<<TXINI)) {
if (*interrupt_data_len < 0) {
// If there's not already data waiting to be
// sent, disable the interrupt.
UEIENX &= ~(1<<TXINE);
} else {
UEINTX &= ~(1<<TXINI);
buf2EP(ep, (void*)*interrupt_data, *interrupt_data_len, *interrupt_data_len, 0);
*interrupt_data = NULL;
*interrupt_data_len = -1;
UEINTX &= ~(1<<FIFOCON);
}
}
}
// Endpoint interrupt
ISR(USB_COM_vect)
{
@ -619,22 +653,11 @@ ISR(USB_COM_vect)
}
if (ueint & (1<<EPINT1)) {
UENUM = 1;
i = UEINTX;
handle_interrupt_xmit(1, &interrupt_data, &interrupt_data_len);
}
if (i & (1<<TXINI)) {
if (interrupt_data_len < 0) {
// If there's not already data waiting to be
// sent, disable the interrupt.
UEIENX &= ~(1<<TXINE);
} else {
UEINTX &= ~(1<<TXINI);
buf2EP(1, interrupt_data, interrupt_data_len, interrupt_data_len, 0);
interrupt_data = NULL;
interrupt_data_len = -1;
UEINTX &= ~(1<<FIFOCON);
}
}
if (ueint & (1<<EPINT3)) {
handle_interrupt_xmit(3, &interrupt_data3, &interrupt_data_len3);
}
#if 0
@ -645,12 +668,34 @@ ISR(USB_COM_vect)
#endif
}
char usb_interruptReady(void)
char usb_interruptReady_ep3(void)
{
return interrupt_data_len3 == -1;
}
void usb_interruptSend_ep3(void *data, int len)
{
uint8_t sreg = SREG;
while (interrupt_data_len3 != -1) { }
cli();
interrupt_data3 = data;
interrupt_data_len3 = len;
UENUM = 3;
UEIENX |= (1<<TXINE);
SREG = sreg;
}
char usb_interruptReady_ep1(void)
{
return interrupt_data_len == -1;
}
void usb_interruptSend(void *data, int len)
void usb_interruptSend_ep1(void *data, int len)
{
uint8_t sreg = SREG;

9
usb.h
View File

@ -169,7 +169,7 @@ struct usb_hid_descriptor {
#define USB_PARAM_FLAG_CONFDESC_PROGMEM 2
#define USB_PARAM_FLAG_REPORTDESC_PROGMEM 4
#define MAX_HID_INTERFACES 2
#define MAX_HID_INTERFACES 5
struct usb_hid_parameters {
uint16_t reportdesc_len;
@ -198,8 +198,11 @@ struct usb_parameters {
struct usb_hid_parameters hid_params[MAX_HID_INTERFACES];
};
char usb_interruptReady(void);
void usb_interruptSend(void *data, int len); // EP1
char usb_interruptReady_ep1(void);
void usb_interruptSend_ep1(void *data, int len);
char usb_interruptReady_ep3(void);
void usb_interruptSend_ep3(void *data, int len);
void usb_init(const struct usb_parameters *params);
void usb_doTasks(void);
void usb_shutdown(void);