c6aa4b5ac4
*add* > [vhex/display] | [text] add va_list version of dtext() and dprint() > [vhex/defs] | [types] add x_union_alone > [vhex/usb] | [request] add USB request (WIP) | [pipe] add USB pipe API (WIP) | [dcp] add USB DCP API (WIP) | [macros] add interrupt clearing helper | [descriptor] add main USB descriptors *update* > [vhex/defs] | [attributes] rename VPACKEDENUM -> VPACKED_ALONE > [vhex/usb] | [interrupt] enable setup interruptions | [open] perform USB device configuration check *fix* > [vhex/defs] | [call] fix last argument injection > [vhex/usb] | [macros] fix delay for register sync. | [open] force-clear interrupt flags befor enabling interruption
151 lines
4.2 KiB
C
151 lines
4.2 KiB
C
#include <vhex/driver/mpu/sh/sh7305/usb.h>
|
|
#include <vhex/driver/cpu.h>
|
|
#include <vhex/usb.h>
|
|
|
|
#include <string.h>
|
|
|
|
//---
|
|
// Internals
|
|
//---
|
|
|
|
/* abitrary USB configuration limit (TODO : update me?) */
|
|
#define __SH7305_USB_MAX_DC_CONF 2
|
|
#define __SH7305_USB_MAX_DC_INTR 4
|
|
#define __SH7305_USB_MAX_DC_ENDP 9
|
|
|
|
/* internal copy of each descriptor (TODO : update me?) */
|
|
struct usb_descriptor_device __sh7305_usb_dc_device;
|
|
struct usb_descriptor_configuration __sh7305_usb_dc_conf[__SH7305_USB_MAX_DC_CONF];
|
|
struct usb_descriptor_interface __sh7305_usb_dc_interf[__SH7305_USB_MAX_DC_INTR];
|
|
struct usb_descriptor_endpoint __sh7305_usb_dc_endpoint[__SH7305_USB_MAX_DC_ENDP];
|
|
|
|
/* sh7305_conf_check_conf() : check and patch interface desc. */
|
|
static int sh7305_conf_check_endpoint(
|
|
struct usb_descriptor_endpoint **endpoint,
|
|
size_t *total
|
|
) {
|
|
int pipe_id;
|
|
int i;
|
|
|
|
if (endpoint == NULL)
|
|
return -3;
|
|
for (i = 0 ; endpoint[i] != NULL ; ++i)
|
|
{
|
|
if (i >= __SH7305_USB_MAX_DC_ENDP) {
|
|
usb_logger_write("- too many endpoint (%d)\n", i);
|
|
return -4;
|
|
}
|
|
*total += sizeof(struct usb_descriptor_endpoint);
|
|
pipe_id = sh7305_usb_pipe_find(endpoint[i]->bmAttributes.trans);
|
|
if (pipe_id < 0)
|
|
return pipe_id;
|
|
endpoint[i]->bEndpointAddress.number = pipe_id;
|
|
memcpy(
|
|
&__sh7305_usb_dc_endpoint[i],
|
|
endpoint[i],
|
|
sizeof(struct usb_descriptor_endpoint)
|
|
);
|
|
usb_logger_write("- use pipe %d\n", pipe_id);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* sh7305_conf_check_conf() : check and patch interface desc. */
|
|
static int sh7305_conf_check_interface(
|
|
struct usb_full_interface **interface,
|
|
size_t *total
|
|
) {
|
|
int nbendpoint;
|
|
int i;
|
|
|
|
if (interface == NULL)
|
|
return -3;
|
|
for (i = 0 ; interface[i] != NULL ; ++i)
|
|
{
|
|
if (i >= __SH7305_USB_MAX_DC_INTR) {
|
|
usb_logger_write("- too many interface (%d)\n", i);
|
|
return -4;
|
|
}
|
|
//FIXME : check strings
|
|
*total += sizeof(struct usb_descriptor_interface);
|
|
nbendpoint = sh7305_conf_check_endpoint(interface[i]->endpoint, total);
|
|
if (nbendpoint < 0)
|
|
return nbendpoint;
|
|
interface[i]->descriptor->bInterfaceNumber = i + 1;
|
|
interface[i]->descriptor->bNumEndpoints = nbendpoint;
|
|
memcpy(
|
|
&__sh7305_usb_dc_interf[i],
|
|
interface[i],
|
|
sizeof(struct usb_descriptor_interface)
|
|
);
|
|
usb_logger_write("- use interface %d\n", i + 1);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* sh7305_conf_check_conf() : check and patch configuration desc. */
|
|
static int sh7305_conf_check_conf(struct usb_full_config **config)
|
|
{
|
|
int nbinterf;
|
|
size_t total;
|
|
int i;
|
|
|
|
if (config == NULL)
|
|
return -2;
|
|
for (i = 0 ; config[i] != NULL ; ++i)
|
|
{
|
|
if (i >= __SH7305_USB_MAX_DC_CONF) {
|
|
usb_logger_write("- too many configuration (%d)\n", i);
|
|
return -4;
|
|
}
|
|
//FIXME : check strings
|
|
total = sizeof(struct usb_descriptor_configuration);
|
|
nbinterf = sh7305_conf_check_interface(config[i]->interface, &total);
|
|
if (nbinterf < 0)
|
|
return nbinterf;
|
|
config[i]->descriptor->wTotalLengh = total;
|
|
config[i]->descriptor->bNumInterfaces = nbinterf;
|
|
config[i]->descriptor->bConfigurationValue = i + 1;
|
|
memcpy(
|
|
&__sh7305_usb_dc_conf[i],
|
|
config[i],
|
|
sizeof(struct usb_descriptor_configuration)
|
|
);
|
|
usb_logger_write("- use configuration %d\n", i + 1);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
//---
|
|
// Public API
|
|
//---
|
|
|
|
/* sh7305_usb_configuration_resolve() : check and resolve USB configuration */
|
|
int sh7305_usb_configuration_resolve(struct usb_full_device *device)
|
|
{
|
|
int nbconf;
|
|
|
|
if (device == NULL)
|
|
return -1;
|
|
|
|
//FIXME : check string validity
|
|
|
|
cpu_atomic_start();
|
|
|
|
/* patch configuration descriptors */
|
|
nbconf = sh7305_conf_check_conf(device->config);
|
|
if (nbconf < 0)
|
|
return nbconf;
|
|
|
|
/* patch device descriptor */
|
|
device->descriptor->bNumConfigurations = nbconf;
|
|
memcpy(
|
|
&__sh7305_usb_dc_device,
|
|
device->descriptor,
|
|
sizeof(struct usb_descriptor_device)
|
|
);
|
|
|
|
cpu_atomic_end();
|
|
return 0;
|
|
}
|