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
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
3 changed files with 61 additions and 69 deletions

View file

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

View file

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

View file

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