vxKernel/kernel/src/drivers/mpu/sh/sh7305/usb/configuration.c
Yann MAGNIN c6aa4b5ac4 vxkernel - v0.7.0-4 : add USB request handling (WIP)
*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
2023-01-27 16:21:44 +01:00

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;
}