/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2012 by Amaury Pouly * * 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 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "hwstub.h" #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif /* requires then ->handle field only */ int hwstub_probe(struct hwstub_device_t *dev) { libusb_device *mydev = libusb_get_device(dev->handle); int config_id; libusb_get_configuration(dev->handle, &config_id); struct libusb_config_descriptor *config; libusb_get_active_config_descriptor(mydev, &config); const struct libusb_endpoint_descriptor *endp = NULL; int intf; for(intf = 0; intf < config->bNumInterfaces; intf++) { if(config->interface[intf].num_altsetting != 1) continue; const struct libusb_interface_descriptor *interface = &config->interface[intf].altsetting[0]; if(interface->bNumEndpoints != 3 || interface->bInterfaceClass != HWSTUB_CLASS || interface->bInterfaceSubClass != HWSTUB_SUBCLASS || interface->bInterfaceProtocol != HWSTUB_PROTOCOL) continue; dev->intf = intf; dev->bulk_in = dev->bulk_out = dev->int_in = -1; for(int ep = 0; ep < interface->bNumEndpoints; ep++) { endp = &interface->endpoint[ep]; if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT && (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) dev->int_in = endp->bEndpointAddress; if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK && (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) dev->bulk_in = endp->bEndpointAddress; if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK && (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) dev->bulk_out = endp->bEndpointAddress; } if(dev->bulk_in == -1 || dev->bulk_out == -1 || dev->int_in == -1) continue; break; } if(intf == config->bNumInterfaces) return 1; return libusb_claim_interface(dev->handle, intf); } int hwstub_release(struct hwstub_device_t *dev) { return libusb_release_interface(dev->handle, dev->intf); } int hwstub_get_info(struct hwstub_device_t *dev, uint16_t idx, void *info, size_t sz) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, HWSTUB_GET_INFO, 0, idx, info, sz, 1000); } int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, HWSTUB_GET_LOG, 0, 0, buf, sz, 1000); } int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) { size_t tot_sz = 0; while(sz) { uint16_t xfer = MIN(1 * 1024, sz); int ret = libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | (read ? LIBUSB_ENDPOINT_IN : LIBUSB_ENDPOINT_OUT), HWSTUB_RW_MEM, addr & 0xffff, addr >> 16, buf, xfer, 1000); if(ret != xfer) return ret; sz -= xfer; addr += xfer; buf += xfer; tot_sz += xfer; } return tot_sz; } int hwstub_call(struct hwstub_device_t *dev, uint32_t addr) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, HWSTUB_CALL, addr & 0xffff, addr >> 16, NULL, 0, 1000); } int hwstub_jump(struct hwstub_device_t *dev, uint32_t addr) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, HWSTUB_JUMP, addr & 0xffff, addr >> 16, NULL, 0, 1000); } const char *hwstub_get_product_string(struct usb_resp_info_stmp_t *stmp) { switch(stmp->chipid) { case 0x3700: return "STMP 3700"; case 0x37b0: return "STMP 3770"; case 0x3780: return "STMP 3780 / i.MX233"; default: return "unknown"; } } const char *hwstub_get_rev_string(struct usb_resp_info_stmp_t *stmp) { switch(stmp->chipid) { case 0x37b0: case 0x3780: switch(stmp->rev) { case 0: return "TA1"; case 1: return "TA2"; case 2: return "TA3"; case 3: return "TA4"; default: return "unknown"; } break; default: return "unknown"; } } int hwstub_atexit(struct hwstub_device_t *dev, int method) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, HWSTUB_ATEXIT, 0, method, NULL, 0, 1000); } int hwstub_exit(struct hwstub_device_t *dev) { return libusb_control_transfer(dev->handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, HWSTUB_EXIT, 0, 0, NULL, 0, 1000); }