usb: clarify functions used to access endpoint configuration

The previous scheme was really unclear. Now, an endpoint_t carries all
of the endpoint info (instead of the global address being implicitly
its array index, which couldn't be returned).

An _endpoint address_ is the 8-bit value consisting of an endpoint
number (bits 0x0f) and a direction (bit 0x80).

The _global address_ of an endpoint is the address used to communicate
with the host, and it is unique. The _local address_ of an endpoint is
the interface-specific numbering that gint provides to allow interfaces
to compose without risks of address collisions.

The complete data for an endpoint can be queried with the new functions
usb_get_endpoint_by_*() which accept global addresses, local addresses,
and pipe numbers.
This commit is contained in:
Lephe 2023-03-04 10:58:07 +01:00
parent aee67a76f3
commit 911691461f
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
3 changed files with 61 additions and 69 deletions

View File

@ -1,6 +1,7 @@
#include <gint/usb.h>
#include "usb_private.h"
#include <stdlib.h>
#include <string.h>
//---
// Endpoint assignment
@ -15,32 +16,37 @@ GCONSTRUCTOR static void usb_alloc(void)
conf_ep = malloc(32 * sizeof *conf_ep);
}
/* usb_configure_endpoint(): Get endpoint data for a concrete address */
endpoint_t *usb_configure_endpoint(int endpoint)
endpoint_t *usb_get_endpoint_by_global_address(int global_address)
{
/* Refuse access to endpoint 0, which is for the DCP */
if(endpoint < 0 || ((endpoint & 0x0f) == 0)) return NULL;
global_address = (uint8_t)global_address;
int dir = (endpoint & 0x80) ? 0x10 : 0;
endpoint &= 0x7f;
/* Accept only valid non-DCP endpoints */
if((global_address & 0x70) || !(global_address & 0x0f))
return NULL;
if(endpoint <= 0 || endpoint > 15) return NULL;
return &conf_ep[dir + endpoint];
int dir = (global_address & 0x80) ? 0x10 : 0;
return &conf_ep[dir + (global_address & 0x0f)];
}
/* usb_configure_address(): Get the concrete endpoint address */
int usb_configure_address(usb_interface_t const *intf, int address)
endpoint_t *usb_get_endpoint_by_local_address(usb_interface_t const *intf,
int local_address)
{
int dir = address & 0x80;
int base = address & 0x0f;
for(int i = 0; i < 32; i++)
{
if(conf_ep[i].intf != intf) continue;
if((conf_ep[i].dc->bEndpointAddress & 0x0f) != base) continue;
return (i & 0x0f) | dir;
endpoint_t *ep = &conf_ep[i];
if(ep->intf == intf && ep->dc->bEndpointAddress == local_address)
return ep;
}
return -1;
return NULL;
}
endpoint_t *usb_get_endpoint_by_pipe(int pipe)
{
for(int i = 0; i < 32; i++) {
if(conf_ep[i].pipe == pipe)
return &conf_ep[i];
}
return NULL;
}
//---
@ -80,18 +86,8 @@ static int find_pipe(int type)
int usb_configure_solve(usb_interface_t const **interfaces)
{
/* Reset the previous configuration */
for(int i = 0; i < 16; i++)
{
conf_if[i] = NULL;
}
for(int i = 0; i < 32; i++)
{
conf_ep[i].intf = NULL;
conf_ep[i].dc = NULL;
conf_ep[i].pipe = 0;
conf_ep[i].bufnmb = 0;
conf_ep[i].bufsize = 0;
}
memset(conf_if, 0, 16 * sizeof *conf_if);
memset(conf_ep, 0, 32 * sizeof *conf_ep);
/* Next interface number to assign */
int next_interface = 0;
@ -112,22 +108,26 @@ int usb_configure_solve(usb_interface_t const **interfaces)
uint8_t const *dc = intf->dc[k];
if(dc[1] != USB_DC_ENDPOINT) continue;
/* If the same endpoint with a different direction has
already been assigned, use that */
int address = usb_configure_address(intf, dc[2]);
if(address == -1)
{
if(next_endpoint >= 16)
return USB_OPEN_TOO_MANY_ENDPOINTS;
/* If the endpoint number has already been assigned in the other
direction, keep the same global endpoint number. */
endpoint_t *dual_ep = usb_get_endpoint_by_local_address(intf,
dc[2] ^ 0x80);
int address;
if(dual_ep)
address = dual_ep->global_address ^ 0x80;
else if(next_endpoint >= 16)
return USB_OPEN_TOO_MANY_ENDPOINTS;
else
address = (next_endpoint++) | (dc[2] & 0x80);
}
int pipe = find_pipe(dc[3] & 0x03);
if(pipe < 0) return USB_OPEN_TOO_MANY_ENDPOINTS;
endpoint_t *ep = usb_configure_endpoint(address);
endpoint_t *ep = usb_get_endpoint_by_global_address(address);
ep->intf = intf;
ep->dc = (void *)dc;
ep->global_address = address;
ep->pipe = pipe;
ep->bufnmb = 0;
ep->bufsize = 0;
@ -144,8 +144,8 @@ int usb_configure_solve(usb_interface_t const **interfaces)
{
usb_interface_endpoint_t *params = &intf->params[k];
int a = usb_configure_address(intf, params->endpoint);
endpoint_t *ep = usb_configure_endpoint(a);
endpoint_t *ep = usb_get_endpoint_by_local_address(intf,
params->endpoint);
if(!ep) return USB_OPEN_INVALID_PARAMS;
uint bufsize = params->buffer_size >> 6;
@ -217,11 +217,8 @@ usb_interface_t const * const *usb_configure_interfaces(void)
// API for interfaces
//---
int usb_interface_pipe(usb_interface_t const *interface, int endpoint)
int usb_interface_pipe(usb_interface_t const *intf, int address)
{
int concrete_address = usb_configure_address(interface, endpoint);
endpoint_t const *ep = usb_configure_endpoint(concrete_address);
if(!ep) return -1;
return ep->pipe;
endpoint_t const *ep = usb_get_endpoint_by_local_address(intf, address);
return ep ? ep->pipe : -1;
}

View File

@ -113,8 +113,9 @@ static void write_configuration_descriptor(int wLength)
else if(dc[1] == USB_DC_ENDPOINT)
{
usb_dc_endpoint_t edc = *(usb_dc_endpoint_t *)dc;
edc.bEndpointAddress =
usb_configure_address(interfaces[i], dc[2]);
endpoint_t *e = usb_get_endpoint_by_local_address(interfaces[i],
edc.bEndpointAddress);
edc.bEndpointAddress = e->global_address;
dcp_write(&edc, edc.bLength);
}
/* Forward other descriptors */

View File

@ -52,15 +52,16 @@ void usb_configure(void);
void usb_configure_clear_pipes(void);
/* endpoint_t: Driver information for each open endpoint in the device
There is one such structure for all 16 configurable endpoints, for each
direction (totaling 32). endpoint_get() is used to query the structure by
endpoint number (including the IN/OUT bit). */
direction (totaling 32). use_get_endpoint_*() is used to query the
structure by endpoint address (including the IN/OUT bit). */
typedef struct {
/* Which interface this endpoint belongs to */
usb_interface_t const *intf;
/* Associated endpoint descriptor */
/* Associated endpoint descriptor. This contains the local address. */
usb_dc_endpoint_t const *dc;
/* Global address (endpoint number + direction) */
uint8_t global_address;
/* Associated pipe, must be a number from 1..9 */
uint8_t pipe;
/* Allocated pipe buffer area; this is valid for pipes 1..5. The
@ -74,25 +75,18 @@ typedef struct {
/* usb_configure_interfaces(): List configured interfaces */
usb_interface_t const * const *usb_configure_interfaces(void);
/* usb_configure_address(): Get the concrete endpoint address
/* Returns the endpoint information structure for the endpoint identified by a
global address. Returns NULL if the address is unused. */
endpoint_t *usb_get_endpoint_by_global_address(int global_address);
This function returns the endpoint address associated with the provided
interface-numbered endpoint. The value is defined if an interface-provided
endpoint descriptor with bEndpointAddress equal to either (address) or
(address ^ 0x80) has been processed.
/* Returns the endpoint information structure for the endpoint identified by a
local (interface) address, NULL if the address is unused. */
endpoint_t *usb_get_endpoint_by_local_address(usb_interface_t const *intf,
int local_address);
This function is used both to access endpoint data for an interface-provided
endpoint number, and to ensure that two interface-provided enpoint numbers
with same base and opposing directions are assigned the same concrete
endpoint number with its two opposing directions.
@intf Interface that provided the address
@address Endpoint address (as numbered by the interaface)
-> Returns the assigned endpoint address, or -1 if unassigned. */
int usb_configure_address(usb_interface_t const *intf, int address);
/* usb_configure_endpoint(): Get endpoint data for a concrete address */
endpoint_t *usb_configure_endpoint(int endpoint);
/* Returns the endpoint information structure for the endpoint identified by a
bound pipe. Returns NULL if the pipe is unused. */
endpoint_t *usb_get_endpoint_by_pipe(int pipe);
//---
// Pipe operations