e5de5e09c1
Rename STOP command to EXIT, introduce ATEXIT, this gives better control over the exit of the stub. Add stmp implementation. Change-Id: I45442c8b88b9330d12ef439417ca5ffa1520477a
175 lines
6.1 KiB
C
175 lines
6.1 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* 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);
|
|
}
|