blob: 003a388385d6c7bdc3aca663056843b84022bb9d [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef _USBDEV_H_
#define _USBDEV_H_
#include <stddef.h>
#include <stdint.h>
// Hardware parameters
#define NUM_BUFS 32
#define BUF_LENGTH 64
#define NUM_ENDPOINTS 12
// USB buffers are held in the SRAM in the interface, referenced by ID
// Buffer IDs are 0 to NUM_BUFS
// Use negative buffer ID for error
typedef int usbbufid_t;
typedef struct usbdev_ctx usbdev_ctx_t;
// Note: this is only needed here because the caller of init needs it
struct usbdev_ctx {
// TODO: base_addr goes here once header files support using it
int can_wake;
uint8_t freebuf[NUM_BUFS];
uint32_t halted; // bit vector per endpoint
int nfree;
int flushed;
usbdev_ctx_t *ep_ctx[NUM_ENDPOINTS];
void (*tx_done_callback[NUM_ENDPOINTS])(void *);
void (*rx_callback[NUM_ENDPOINTS])(void *, usbbufid_t, int, int);
void (*flush[NUM_ENDPOINTS])(void *);
};
/**
* Allocate a buffer for the caller to use
*
* @param ctx usbdev context pointer
* @return buffer ID or negative for out of buffer error
*/
usbbufid_t usbdev_buf_allocate_byid(usbdev_ctx_t *ctx);
/**
* Free a buffer when caller no longer needs it
*
* @param ctx usbdev context pointer
* @param buf buffer ID being returned to free pool
* @return 0 or -1 if the free pool is full (shouldn't happen)
*/
int usbdev_buf_free_byid(usbdev_ctx_t *ctx, usbbufid_t buf);
/**
* Get memory address for accessing data in a buffer
*
* Hardware restriction: buffer can only be written with 32-bit words
* Ok to cast the return value to int8_t * for reading
*
* @param ctx usbdev context pointer
* @param buf buffer ID to access
* @return pointer to access the data of @p buf
*/
uint32_t *usbdev_buf_idtoaddr(usbdev_ctx_t *ctx, usbbufid_t buf);
/**
* Copy from memory into a buffer, referencing by buffer ID
*
* Implementation restriction: from must be 4-byte aligned
* TODO(mdhayer) remove restriction
*
* @param ctx usbdev context pointer
* @param buf buffer ID to copy to
* @param from source address for data
* @param len_bytes length in bytes of data to copy
*/
void usbdev_buf_copyto_byid(usbdev_ctx_t *ctx, usbbufid_t buf, const void *from,
size_t len_bytes);
/**
* Schedule a buffer for transmission on an endpoint
*
* Send happens on next IN request for that endpoint from the host.
* Once this call is made the buffer is owned by the hardware
*
* @param ctx usbdev context pointer
* @param buf buffer ID to send
* @param size length in bytes of data to send, zero is valid (used as ack)
* @param endpoint endpoint to send from
*/
void usbdev_sendbuf_byid(usbdev_ctx_t *ctx, usbbufid_t buf, size_t size,
int endpoint);
/**
* Call regularly to poll the usbdev interface
*
* @param ctx usbdev context pointer
*/
void usbdev_poll(usbdev_ctx_t *ctx);
/**
* Set the USB device ID
*
* Device ID must be zero at init. When the host assigns an ID
* with a SET_ADDRESS packet and the complete SETUP transaction is
* complete, this function should be called to set the new ID. Note
* on a reset the hardware will clear the device ID back to 0.
*
* @param usbdev context pointer
* @param new deviceid
*/
void usbdev_set_deviceid(usbdev_ctx_t *ctx, int deviceid);
/**
* Halt or release an endpoint
*
* By default endpoints are enabled, but they can be halted but the host
*
* @param usbdev context pointer
* @param endpoint number
* @param enable set/clear
*/
void usbdev_halt(usbdev_ctx_t *ctx, int endpoint, int enable);
/**
* Get halted status for an endpoint
*
* @param usbdev context pointer
* @return 1 if endpoint is halted else 0
*/
inline int usbdev_halted(usbdev_ctx_t *ctx, int endpoint) {
return (ctx->halted >> endpoint) & 0x1;
}
/**
* Enable or disable remote wake
*
* @param usbdev context pointer
* @param enable set/clear
*/
inline void usbdev_rem_wake_en(usbdev_ctx_t *ctx, int enable) {
ctx->can_wake = (enable) ? 1 : 0;
}
/**
* Get ability to wake the host
*
* @param usbdev context pointer
* @return 1 if remote wake is permitted else 0
*/
int usbdev_can_rem_wake(usbdev_ctx_t *ctx);
/**
* Call to setup an endpoint
*
* @param ctx usbdev context pointer
* @param ep endpoint number
* @param enableout boolean, true to enable OUT transactions on the endpoint
* (OUT means host->device, ie receive by us)
* @param ep_ctx context pointer for callee
* @param tx_done(void *ep_ctx) callback once send has been Acked
* @param rx(void *ep_ctx, usbbufid_t buf, int size, int setup)
called when a packet is received
* @param flush(void *ep_ctx) called every 16ms based USB host timebase
*/
void usbdev_endpoint_setup(usbdev_ctx_t *ctx, int ep, int enableout,
void *ep_ctx, void (*tx_done)(void *),
void (*rx)(void *, usbbufid_t, int, int),
void (*flush)(void *));
/**
* Initialize the usbdev interface
*
* @param ctx uninitialized usbdev context pointer
*/
void usbdev_init(usbdev_ctx_t *ctx);
// Used for tracing what is going on
#include "uart.h"
#define TRC_S(s) uart_send_str(s)
#define TRC_I(i, b) uart_send_uint(i, b)
#define TRC_C(c) uart_send_char(c)
#endif