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:
parent
fe3814f7d1
commit
90aae55470
169
usb.c
169
usb.c
@ -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
9
usb.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user