/* gc_n64_usb : Gamecube or N64 controller to USB firmware Copyright (C) 2007-2016 Raphael Assenat 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 the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "usb.h" #undef VERBOSE #define STATE_POWERED 0 #define STATE_DEFAULT 1 #define STATE_ADDRESS 2 #define STATE_CONFIGURED 3 static volatile uint8_t g_usb_suspend; static uint8_t g_ep0_buf[64]; 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_data2; static volatile int interrupt_data_len2 = -1; static void *interrupt_data3; static volatile int interrupt_data_len3 = -1; #define CONTROL_WRITE_BUFSIZE 64 static struct usb_request control_write_rq; static volatile uint16_t control_write_len; static volatile uint8_t control_write_in_progress; static uint8_t control_write_buf[CONTROL_WRITE_BUFSIZE]; static const struct usb_parameters *g_params; static void initControlWrite(const struct usb_request *rq) { memcpy(&control_write_rq, rq, sizeof(struct usb_request)); control_write_len = 0; control_write_in_progress = 1; // printf_P(PSTR("Init cw\r\n")); } static int wcslen(const wchar_t *str) { int i=0; while (*str) { str++; i++; } return i; } /** Return the values for the UECFG1X register * * \return The EPSIZE bits if supported, 0xFF if invalid. **/ static uint8_t getEPsizebits(int epsize) { switch(epsize) { case 64: return (1<n_hid_interfaces; i++) { UENUM = 0x01 + i; // select endpoint UECONX = 1<hid_params[i].endpoint_size); if (epsize == 0xff) { printf_P(PSTR("Invalid ep size\r\n")); return; } UECFG1X = epsize|(1< max_len) { len = max_len; } if (progmem) { const unsigned char *s = src; for (i=0; i len ? len : rq_len; uint16_t pos = 0; while(1) { if (todo > 64) { buf2EP(0, data+pos, 64, 64, progmem); UEINTX &= ~(1<bmRequestType, rq->bRequest, rq->wValue, rq->wLength); #endif if (USB_RQT_IS_HOST_TO_DEVICE(rq->bmRequestType)) { switch (rq->bmRequestType & USB_RQT_RECIPIENT_MASK) { case USB_RQT_RECIPIENT_DEVICE: switch (rq->bRequest) { case USB_RQ_SET_ADDRESS: UDADDR = rq->wValue; while (!(UEINTX & (1<wValue); #endif if (!rq->wValue) { g_device_state = STATE_DEFAULT; } else { g_device_state = STATE_ADDRESS; } break; case USB_RQ_SET_CONFIGURATION: g_current_config = rq->wValue; if (!g_current_config) { g_device_state = STATE_ADDRESS; } else { g_device_state = STATE_CONFIGURED; } while (!(UEINTX & (1<bmRequestType & (USB_RQT_TYPE_MASK)) { case USB_RQT_CLASS: switch(rq->bRequest) { // case HID_CLSRQ_SET_IDLE: // while (!(UEINTX & (1<bRequest); unhandled = 1; } break; default: unhandled = 1; } break; case USB_RQT_RECIPIENT_ENDPOINT: case USB_RQT_RECIPIENT_OTHER: default: break; } } // Request where we send data to the host. Handlers // simply load the endpoint buffer and transmission // is handled automatically. if (USB_RQT_IS_DEVICE_TO_HOST(rq->bmRequestType)) { switch (rq->bmRequestType & USB_RQT_RECIPIENT_MASK) { case USB_RQT_RECIPIENT_DEVICE: switch (rq->bRequest) { case USB_RQ_GET_STATUS: { unsigned char status[2] = { 0x00, 0x00 }; // status[0] & 0x01 : Self powered // status[1] & 0x02 : Remote wakeup buf2EP(0, status, 2, rq->wLength, 0); } break; case USB_RQ_GET_CONFIGURATION: { if (g_device_state != STATE_CONFIGURED) { unsigned char zero = 0; buf2EP(0, &zero, 1, rq->wLength, 0); } else { buf2EP(0, &g_current_config, 1, rq->wLength, 0); } } break; case USB_RQ_GET_DESCRIPTOR: switch (rq->wValue >> 8) { case DEVICE_DESCRIPTOR: buf2EP(0, (unsigned char*)g_params->devdesc, sizeof(struct usb_device_descriptor), rq->wLength, g_params->flags & USB_PARAM_FLAG_DEVDESC_PROGMEM); break; case CONFIGURATION_DESCRIPTOR: // 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: { int id, len, slen; struct usb_string_descriptor_header hdr; id = (rq->wValue & 0xff); if (id > 0 && id <= g_params->num_strings) { id -= 1; // Our string table is zero-based len = rq->wLength; slen = wcslen(g_params->strings[id]) << 1; hdr.bLength = sizeof(hdr) + slen; hdr.bDescriptorType = STRING_DESCRIPTOR; buf2EP(0, (unsigned char*)&hdr, 2, len, 0); len -= 2; buf2EP(0, (unsigned char*)g_params->strings[id], slen, len, 0); } else if (id == 0) // Table of supported languages (string id 0) { unsigned char languages[4] = { 4, STRING_DESCRIPTOR, 0x09, 0x10 // English (Canadian) }; buf2EP(0, languages, 4, rq->wLength, 0); } else { printf_P(PSTR("Unknown string id\r\n")); } } break; case DEVICE_QUALIFIER_DESCRIPTOR: // Full speed devices must respond with a request error. unhandled = 1; break; default: // printf_P(PSTR("Unhandled descriptor 0x%02x\n"), rq->wValue>>8); unhandled = 1; } break; default: unhandled = 1; } break; case USB_RQT_RECIPIENT_INTERFACE: switch(rq->bmRequestType & (USB_RQT_TYPE_MASK)) { case USB_RQT_STANDARD: switch (rq->bRequest) { case USB_RQ_GET_STATUS: { // 9.4.5 Get Status, Figure 9-5. Reserved (0) unsigned char status[2] = { 0x00, 0x00 }; buf2EP(0, status, 2, rq->wLength, 0); } break; case USB_RQ_GET_DESCRIPTOR: switch (rq->wValue >> 8) { case REPORT_DESCRIPTOR: { // HID 1.1 : 7.1.1 Get_Descriptor request. wIndex is the interface number. // if (rq->wIndex > g_params->n_hid_interfaces) { unhandled = 1; break; } 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; default: unhandled = 1; } break; default: unhandled = 1; } break; case USB_RQT_CLASS: switch (rq->bRequest) { case HID_CLSRQ_GET_REPORT: { // HID 1.1 : 7.2.1 Get_Report request. wIndex is the interface number. if (rq->wIndex > g_params->n_hid_interfaces) break; if (g_params->hid_params[rq->wIndex].getReport) { const unsigned char *data; uint16_t len; len = g_params->hid_params[rq->wIndex].getReport( g_params->hid_params[rq->wIndex].ctx, rq, &data); if (len) { buf2EP(0, data, len, rq->wLength, 0); } } else { // Treat as not-supported (i.e. STALL endpoint) unhandled = 1; } } break; default: unhandled = 1; } break; default: unhandled = 1; } break; case USB_RQT_RECIPIENT_ENDPOINT: switch (rq->bRequest) { case USB_RQ_GET_STATUS: { // 9.4.5 Get Status, Figure 0-6 unsigned char status[2] = { 0x00, 0x00 }; // status[0] & 0x01 : Halt buf2EP(0, status, 2, rq->wLength, 0); } break; default: unhandled = 1; } break; case USB_RQT_RECIPIENT_OTHER: default: unhandled = 1; } if (!unhandled) { // Handle transmission now UEINTX &= ~(1<bmRequestType, rq->bRequest, rq->wValue); UECONX |= (1<bmRequestType & (USB_RQT_TYPE_MASK)) == USB_RQT_CLASS) { // TODO : Cechk for HID_CLSRQ_SET_REPORT in rq->bRequest // HID 1.1 : 7.2.2 Set_Report request. wIndex is the interface number. if (rq->wIndex > g_params->n_hid_interfaces) return; if (g_params->hid_params[rq->wIndex].setReport) { if (g_params->hid_params[rq->wIndex].setReport( g_params->hid_params[rq->wIndex].ctx, rq, dat, len)) { UECONX |= (1<