#include #include "timer.h" #include "usb.h" #include "debug.h" static usb_device_t dev[USB_NUMDEVICES]; usb_device_t *usb_get_devices() { return dev; } void usb_init() { puts(__FUNCTION__); uint8_t i; for(i=0;ibAddress = 0; d->parent = parent; d->lowspeed = lowspeed; d->port = port; d->class = NULL; d->vid = d->pid = 0; // setup endpoint 0 d->ep0.epAddr = 0; d->ep0.maxPktSize = 8; d->ep0.epAttribs = 0; d->ep0.bmNakPower = USB_NAK_MAX_POWER; if(rcode = usb_get_dev_descr( d, 8, &dev_desc )) return rcode; d->ep0.maxPktSize = dev_desc.bMaxPacketSize0; usb_debugf("EP0 max packet size: %d", d->ep0.maxPktSize); // Assign new address to the device // (address is simply the number of the free slot + 1) iprintf("Setting addr %x\n", i+1); rcode = usb_set_addr(d, i+1); if(rcode) { iprintf("failed to assign address (rcode=%d)", rcode); return rcode; } uint32_t timer = timer_get_msec(); do { rcode = usb_get_dev_descr( d, 8, &dev_desc ); } while (rcode && !timer_check(timer, 5)); // Some recovery interval (2 ms as USB 2.0 9.2.6.3) if(rcode) return rcode; // --- enumerate device --- if(rcode = usb_get_dev_descr( d, sizeof(usb_device_descriptor_t), &dev_desc )) return rcode; usb_dump_device_descriptor(&dev_desc); iprintf("USB vendor ID: %04X, product ID: %04X\n", dev_desc.idVendor, dev_desc.idProduct); // save vid/pid d->vid = dev_desc.idVendor; d->pid = dev_desc.idProduct; // The Retroflag Classic USB Gamepad doesn't report movement until the string descriptors are read, // so read all of them here (and show them on the console) if (!usb_get_string_descr(d, sizeof(str), 0, 0, &str.str_desc)) { // supported languages descriptor uint16_t wLangId = str.str0_desc.wLANGID[0]; iprintf("wLangId: %04X\n", wLangId); // Some gamepads (Retrobit) breaks if its strings are queried like below, so don't do it until it can be done safely. #if 0 if (dev_desc.iManufacturer && !usb_get_string_descr(d, sizeof(str), dev_desc.iManufacturer, wLangId, &str.str_desc)) { for (i=0; i<((str.str_desc.bLength-2)/2); i++) { s[i] = ff_uni2oem(str.str_desc.bString[i], FF_CODE_PAGE); } s[i] = 0; iprintf("Manufacturer: %s\n", s); } if (dev_desc.iProduct && !usb_get_string_descr(d, sizeof(str), dev_desc.iProduct, wLangId, &str.str_desc)) { for (i=0; i<((str.str_desc.bLength-2)/2); i++) { s[i] = ff_uni2oem(str.str_desc.bString[i], FF_CODE_PAGE); } s[i] = 0; iprintf("Product: %s\n", s); } if (dev_desc.iSerialNumber && !usb_get_string_descr(d, sizeof(str), dev_desc.iSerialNumber, wLangId, &str.str_desc)) { for (i=0; i<((str.str_desc.bLength-2)/2); i++) { s[i] = ff_uni2oem(str.str_desc.bString[i], FF_CODE_PAGE); } s[i] = 0; iprintf("Serial no.: %s\n", s); } #endif } // try to connect device to one of the supported classes uint8_t c; for(c=0;class_list[c];c++) { iprintf("trying to init class %d\n", c); rcode = class_list[c]->init(d, &dev_desc); if (!rcode) { d->class = class_list[c]; puts(" -> accepted :-)"); // ok, device accepted by class return 0; } puts(" -> not accepted :-("); } } else iprintf("no more free entries\n"); iprintf("unsupported device\n"); return 0; } uint8_t usb_release_device(uint8_t parent, uint8_t port) { iprintf("%s(parent=%x, port=%d\n", __FUNCTION__, parent, port); uint8_t i; for(i=0; i device with address %x\n", dev[i].bAddress); // check if this is a hub (parent of some other device) // and release its kids first uint8_t j; for(j=0; jrelease(dev+i); dev[i].bAddress = 0; return rcode; } } // this should never happen ... return 0; } uint8_t usb_get_dev_descr( usb_device_t *dev, uint16_t nbytes, usb_device_descriptor_t* p ) { return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, (uint8_t*)p)); } uint8_t usb_get_dev_qualifier_descr( usb_device_t *dev, uint16_t nbytes, usb_device_qualifier_descriptor_t* p ) { return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE_QUALIFIER, 0x0000, nbytes, (uint8_t*)p)); } //get configuration descriptor uint8_t usb_get_conf_descr( usb_device_t *dev, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* p ) { return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, (uint8_t*)p)); } uint8_t usb_get_other_speed_descr( usb_device_t *dev, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* p ) { return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_OTHER_SPEED, 0x0000, nbytes, (uint8_t*)p)); } uint8_t usb_set_addr( usb_device_t *dev, uint8_t newaddr ) { iprintf("%s(new=%x)\n", __FUNCTION__, newaddr); uint8_t rcode = usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL); if(!rcode) dev->bAddress = newaddr; return rcode; } //get configuration uint8_t usb_get_conf( usb_device_t *dev, uint8_t *conf_value ) { return( usb_ctrl_req( dev, USB_REQ_GET, USB_REQUEST_GET_CONFIGURATION, 0x00, 0x00, 0x0000, 1, conf_value)); } //set configuration uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value ) { return( usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL)); } uint8_t usb_get_string_descr( usb_device_t *dev, uint16_t nbytes, uint8_t index, uint16_t lang_id, usb_string_descriptor_t* dataptr ) { return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, lang_id, nbytes, (uint8_t*)dataptr)); }