gint/src/usb/usb_private.h

245 lines
9.2 KiB
C

//---
// gint:usb:usb-private - Private definitions for the USB driver
//---
#ifndef GINT_USB_USB_PRIVATE
#define GINT_USB_USB_PRIVATE
#include <gint/defs/attributes.h>
#include <gint/timer.h>
#include <gint/gint.h>
//---
// Configuration of the communication surface between module and host
//---
/* usb_configure_solve(): Find a configuration that can open these interfaces
This function determines a way to share USB resources (endpoint numbers,
pipes, and FIFO memory) between the provided interfaces, in order to open
the connection with all of these interfaces enabled.
This function must only be called when the USB connection is closed. It
returns 0 on success and one of the USB_* error codes otherwise.
@interfaces NULL-terminated list of interfaces to open
Returns an USB_* error code. */
int usb_configure_solve(usb_interface_t const **interfaces);
/* usb_configure_log(): Print configuration results in the usb_log()
This function can be called even if usb_configure_solve() fails. */
void usb_configure_log(void);
/* usb_configure(): Load the generated configuration to the USB module
This function configures the USB module's pipes and FIFO memory to prepare
handling requests to the interfaces activated in usb_configure_solve(). This
configuration step is un-done by either another configuration through a
successful usb_open(), or a context restore in the USB driver. */
void usb_configure(void);
/* Error codes for USB functions */
enum {
/* There are no interfaces */
USB_OPEN_NO_INTERFACE = 1,
/* There are more interfaces than supported (16) */
USB_OPEN_TOO_MANY_INTERFACES,
/* There are not enough endpoint numbers for every interface, or there
are not enough pipes to set them up */
USB_OPEN_TOO_MANY_ENDPOINTS,
/* There is not enough FIFO memory to use the requested buffer sizes */
USB_OPEN_NOT_ENOUGH_MEMORY,
/* Information is missing, such as buffer size for some endpoints */
USB_OPEN_MISSING_DATA,
/* Invalid parameters: bad endpoint numbers, bad buffer sizes... */
USB_OPEN_INVALID_PARAMS,
/* A write is already pending on this pipe */
USB_WRITE_BUSY,
};
/* 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). */
typedef struct {
/* Which interface this endpoint belongs to */
usb_interface_t const *intf;
/* Associated endpoint descriptor */
usb_dc_endpoint_t const *dc;
/* Associated pipe, must be a number from 1..9 */
uint8_t pipe;
/* Allocated pipe buffer area; this is valid for pipes 1..5. The
bufsize here is in range 1..32, as opposed to the field in PIPEBUF
which is in range 0..31. */
uint8_t bufnmb;
uint8_t bufsize;
} endpoint_t;
/* usb_configure_interfaces(): List configured interfaces */
usb_interface_t const * const *usb_configure_interfaces(void);
/* usb_configure_address(): Get the concrete endpoint 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.
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);
//---
// Pipe operations
//---
/* usb_pipe_configure(): Configure a pipe when opening the connection */
void usb_pipe_configure(int address, endpoint_t const *ep);
/* usb_pipe_clear(): Clear all data in the pipe */
void usb_pipe_clear(int pipe);
/* usb_pipe_mode_read(): Set a pipe in read mode */
void usb_pipe_mode_read(int pipe, int read_size);
/* usb_pipe_mode_write(): Set a pipe in write mode */
void usb_pipe_mode_write(int pipe, int write_size);
/* usb_write_sync(): Synchronously write to a USB pipe
This functions writes (size) bytes of (data) into the specified pipe, by
units of (unit_size) bytes. The unit size must be 1, 2 or 4, and both (data)
and (size) must be multiples of the unit size. In general, you should try to
use the largest possible unit size, as it will be much faster. In a sequence
of writes that concludes with a commit, all the writes must use the same
unit size.
If the data fits into the pipe, this function returns right away, and the
data is *not* transmitted. Otherwise, data is written until the pipe is
full, at which point it is automatically transmitted. After the transfer,
this function resumes writing, returning only once everything is written.
Even then the last bytes will still not have been transmitted, to allow for
other writes to follow. After the last write in a sequence, use
usb_commit_sync() or usb_commit_async() to transmit the last bytes.
If (use_dma=true), the write is performed wita the DMA instead of the CPU,
which is generally faster.
If the pipe is busy due to a previous asynchronous write, this function
waits for the previous write to finish before proceeding normally.
@pipe Pipe to write into
@data Source data (unit_size-aligned)
@size Size of source (multiple of unit_size)
@unit_size FIFO access size (must be 1, 2, or 4)
@dma Whether to use the DMA to perform the write
-> Returns an error code (0 on success). */
int usb_write_sync(int pipe, void const *data, int size, int unit_size,
bool use_dma);
/* usb_write_async(): Asynchronously write to a USB pipe
This function is similar to usb_write_sync(), but it only starts the writing
and returns immediately without ever waiting. The writing then occurs in the
background of the calling code, and the caller is notified through a
callback when it completes. Use GINT_CALL() to create a callback or pass
GINT_CALL_NULL.
If the pipe is busy due to a previous asynchronous write, this function
returns USB_PIPE_BUSY. When called with (use_dma=true), it returns as soon
as the DMA starts, without even a guarantee that the first few bytes have
been written.
There is no guarantee that the write is complete until the callback is
called, however calling again with data=NULL and size=0 can be used to
determine whether the write has finished, since it will return 0 if the pipe
is idle and USB_PIPE_BUSY otherwise.
@pipe Pipe to write into
@data Source data (unit_size-aligned)
@size Size of source (multiple of unit_size)
@unit_size FIFO access size (must be 1, 2, or 4)
@dma Whether to use the DMA to perform the write
@callback Optional callback to invoke when the write completes
-> Returns an error code (0 on success). */
int usb_write_async(int pipe, void const *data, int size, int unit_size,
bool use_dma, gint_call_t callback);
/* usb_commit_sync(): Synchronously commit a write
This function waits for any pending write on the pipe to finish, then
transfers whatever data is left, and returns when the transfer completes.
@pipe Pipe that has been used in previous usb_write_*() calls */
void usb_commit_sync(int pipe);
/* usb_commit_async(): Asynchronously commit a write
This function commits the specified pipe, causing the pipe to transfer
written data as soon as all the writes complete. It returns immediately and
instead the specified callback is invoked when the transfer completes. */
void usb_commit_async(int pipe, gint_call_t callback);
/* usb_pipe_write_bemp(): Callback for the BEMP interrupt on a pipe */
void usb_pipe_write_bemp(int pipe);
/* usb_pipe_init_transfers(): Initialize transfer information */
void usb_pipe_init_transfers(void);
//---
// Timout waits
//---
/* usb_while(): A while loop with a timeout */
#define usb_while(condition) ({ \
volatile int __f = 0; \
int __t = timer_configure(TIMER_ANY, 100000 /*µs*/, \
GINT_CALL_SET_STOP(&__f)); \
if(__t >= 0) timer_start(__t); \
while((condition) && __f == 0) {} \
if(__f) usb_log("%s: %d: (" #condition ") holds\n", \
__FUNCTION__, __LINE__); \
if(__t >= 0) timer_stop(__t); \
__f != 0; \
})
//---
// SETUP requests
//---
/* Standard SETUP requests */
enum {
GET_STATUS = 0,
CLEAR_FEATURE = 1,
SET_FEATURE = 3,
SET_ADDRESS = 5,
GET_DESCRIPTOR = 6,
SET_DESCRIPTOR = 7,
GET_CONFIGURATION = 8,
SET_CONFIGURATION = 9,
GET_INTERFACE = 10,
SET_INTERFACE = 11,
SYNCH_FRAME = 12,
};
/* usb_req_setup(): Answer a SETUP request from the userspace handler
THis function handles a SETUP request from the host, detected with the VALID
bit in the INTSTS0 register. The inputs are the USBREQ, USBVAL, USBINDX and
USBLENG registers, along with the DCP FIFO. */
void usb_req_setup(void);
#endif /* GINT_USB_USB_PRIVATE */