vxKernel/kernel/src/modules/usb/configuration.c

287 lines
7.0 KiB
C

#include <vhex/usb/configuration.h>
#include <vhex/usb/descriptor.h>
#include <vhex/driver/cpu.h>
#include <vhex/usb/utils.h>
#include <vhex/usb/pipe.h>
#include <vhex/usb.h>
#include <string.h>
//---
// Internals
// @TODO
// - strict descriptor check
// - proper return code error
// - check if the USB connection is already setup
// - configuration selector (SET_CONFIGURATION)
//---
/* internal copy of each descriptor */
static usb_dc_device_t usb_dc_device;
static usb_dc_config_t usb_dc_config[__USB_MAX_DC_CONF];
static usb_dc_interf_t usb_dc_interf[__USB_MAX_DC_INTR];
static usb_dc_endpnt_t usb_dc_endpnt[__USB_MAX_DC_ENDP];
/* internals descriptor counter (used in request interrupt handler) */
static int usb_dc_device_nb = 0;
static int usb_dc_config_nb = 0;
static int usb_dc_interf_nb = 0;
static int usb_dc_endpnt_nb = 0;
/* usb_conf_check_conf() : check and patch interface desc. */
static int usb_conf_check_endpoint(usb_dc_endpnt_t **endpoint, size_t *total)
{
int pipe_id;
int i;
if (endpoint == NULL)
return -3;
for (i = 0 ; endpoint[i] != NULL ; ++i)
{
if (i >= __USB_MAX_DC_ENDP) {
usb_logger_write("- too many endpoint (%d)\n", i);
return -4;
}
*total += sizeof(usb_dc_endpnt_t);
pipe_id = usb_pipe_find(endpoint[i]->bmAttributes.trans);
if (pipe_id < 0)
return pipe_id;
endpoint[i]->bEndpointAddress.number = pipe_id;
memcpy(
&usb_dc_endpnt[usb_dc_endpnt_nb],
endpoint[i],
sizeof(usb_dc_endpnt_t)
);
usb_logger_write("- use pipe %d\n", pipe_id);
usb_dc_endpnt_nb += 1;
}
return i;
}
/* usb_conf_check_conf() : check and patch interface desc. */
static int usb_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 >= __USB_MAX_DC_INTR) {
usb_logger_write("- too many interface (%d)\n", i);
return -4;
}
//FIXME : check strings
*total += sizeof(usb_dc_interf_t);
nbendpoint = usb_conf_check_endpoint(interface[i]->endpoint, total);
if (nbendpoint < 0)
return nbendpoint;
interface[i]->descriptor->bInterfaceNumber = i;
interface[i]->descriptor->bNumEndpoints = nbendpoint;
memcpy(
&usb_dc_interf[usb_dc_interf_nb],
interface[i]->descriptor,
sizeof(usb_dc_interf_t)
);
usb_logger_write("- use interface %d\n", usb_dc_interf_nb);
usb_dc_interf_nb += 1;
}
return i;
}
/* usb_conf_check_conf() : check and patch configuration desc. */
static int usb_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 >= __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 = usb_conf_check_interface(config[i]->interface, &total);
if (nbinterf < 0)
return nbinterf;
config[i]->descriptor->wTotalLengh = USB_WORD_TO(total);
config[i]->descriptor->bConfigurationValue = i;
config[i]->descriptor->bNumInterfaces = nbinterf;
memcpy(
&usb_dc_config[usb_dc_config_nb],
config[i]->descriptor,
sizeof(usb_dc_config_t)
);
usb_logger_write(
"- use configuration %d with %d interface\n",
usb_dc_config_nb,
nbinterf
);
usb_dc_config_nb += 1;
}
return i;
}
//---
// Public API
//---
/* usb_config_resolve() : check and resolve USB configuration */
int usb_config_resolve(struct usb_full_device *device)
{
int nbconf;
if (device == NULL)
return -1;
//FIXME : check if the USB connection is already set
//FIXME : check string validity
cpu_atomic_start();
/* USB descriptor counter reset */
usb_dc_device_nb = 1;
usb_dc_config_nb = 0;
usb_dc_interf_nb = 0;
usb_dc_endpnt_nb = 0;
/* patch configuration descriptors */
nbconf = usb_conf_check_conf(device->config);
if (nbconf < 0)
return nbconf;
/* patch device descriptor */
device->descriptor->bNumConfigurations = nbconf;
memcpy(&usb_dc_device, device->descriptor, sizeof(usb_dc_device_t));
cpu_atomic_end();
return 0;
}
/* usb_config_select_config() : try to selecte a configuration */
int usb_config_select_config(int idx)
{
int ret;
if (idx < 0)
return -1;
cpu_atomic_start();
ret = (idx < usb_dc_config_nb) ? 0 : -2;
//TODO : real configuration selection
cpu_atomic_end();
return ret;
}
/* usb_config_get_dc_device() : get device descriptor */
int usb_config_get_dc_device(usb_dc_device_t **dc_device, int idx)
{
if (dc_device == NULL)
return -1;
if (idx != 0) {
*dc_device = NULL;
return -2;
}
*dc_device = &usb_dc_device;
return 0;
}
/* usb_config_get_dc_config() : get config descriptor */
int usb_config_get_dc_config(
usb_dc_config_t **dc_config,
int idx,
int *isidx,
int *ieidx
) {
int ret;
int start;
int end;
if (dc_config == NULL)
return -1;
if (idx < 0)
return -2;
cpu_atomic_start();
ret = -3;
*dc_config = NULL;
if (idx < usb_dc_config_nb) {
start = 0;
for (int i = 0 ; i < idx ; ++i) {
start += usb_dc_config[i].bNumInterfaces;
}
end = start + usb_dc_config[idx].bNumInterfaces;
*dc_config = &usb_dc_config[idx];
if (isidx != NULL) *isidx = start;
if (ieidx != NULL) *ieidx = end;
ret = 0;
}
cpu_atomic_end();
return ret;
}
/* usb_config_get_dc_interf() : get interface descriptor */
int usb_config_get_dc_interf(
usb_dc_interf_t **dc_interf,
int idx,
int *esidx,
int *eeidx
) {
int ret;
int start;
int end;
if (dc_interf == NULL)
return -1;
if (idx < 0)
return -2;
cpu_atomic_start();
ret = -3;
*dc_interf = NULL;
if (idx < usb_dc_interf_nb) {
start = 0;
for (int i = 0 ; i < idx ; ++i) {
start += usb_dc_interf[i].bNumEndpoints;
}
end = start + usb_dc_interf[idx].bNumEndpoints;
*dc_interf = &usb_dc_interf[idx];
if (esidx != NULL) *esidx = start;
if (eeidx != NULL) *eeidx = end;
ret = 0;
}
cpu_atomic_end();
return ret;
}
/* usb_config_get_dc_endpoint() : get endpoint descriptor */
int usb_config_get_dc_endpnt(usb_dc_endpnt_t **dc_endpnt, int idx)
{
int ret;
if (dc_endpnt == NULL)
return -1;
cpu_atomic_start();
ret = -2;
*dc_endpnt = NULL;
if (idx < usb_dc_endpnt_nb) {
*dc_endpnt = &usb_dc_endpnt[idx];
ret = 0;
}
cpu_atomic_end();
return ret;
}