mirror of
https://github.com/im-tomu/foboot.git
synced 2024-09-20 02:40:09 +00:00
booster: foboot-2 compatibility
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
95e6e8c211
commit
ea04c290eb
File diff suppressed because it is too large
Load Diff
244
booster/include/usb-eptri.h
Normal file
244
booster/include/usb-eptri.h
Normal file
@ -0,0 +1,244 @@
|
||||
#ifndef __USB_EPTRI_H_
|
||||
#define __USB_EPTRI_H_
|
||||
|
||||
#ifdef CSR_ACCESSORS_DEFINED
|
||||
extern void csr_writeb(uint8_t value, unsigned long addr);
|
||||
extern uint8_t csr_readb(unsigned long addr);
|
||||
extern void csr_writew(uint16_t value, unsigned long addr);
|
||||
extern uint16_t csr_readw(unsigned long addr);
|
||||
extern void csr_writel(uint32_t value, unsigned long addr);
|
||||
extern uint32_t csr_readl(unsigned long addr);
|
||||
#else /* ! CSR_ACCESSORS_DEFINED */
|
||||
#include <hw/common.h>
|
||||
#endif /* ! CSR_ACCESSORS_DEFINED */
|
||||
|
||||
#define CSR_USB_BASE 0xe0004800L
|
||||
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800L
|
||||
#define CSR_USB_PULLUP_OUT_SIZE 1
|
||||
static inline unsigned char usb_pullup_out_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004800L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_pullup_out_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004800L);
|
||||
}
|
||||
#define CSR_USB_ADDRESS_ADDR 0xe0004804L
|
||||
#define CSR_USB_ADDRESS_SIZE 1
|
||||
static inline unsigned char usb_address_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004804L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_address_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004804L);
|
||||
}
|
||||
#define CSR_USB_ADDRESS_ADDR_OFFSET 0
|
||||
#define CSR_USB_ADDRESS_ADDR_SIZE 7
|
||||
#define CSR_USB_NEXT_EV_ADDR 0xe0004808L
|
||||
#define CSR_USB_NEXT_EV_SIZE 1
|
||||
static inline unsigned char usb_next_ev_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004808L);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_NEXT_EV_IN_OFFSET 0
|
||||
#define CSR_USB_NEXT_EV_IN_SIZE 1
|
||||
#define CSR_USB_NEXT_EV_OUT_OFFSET 1
|
||||
#define CSR_USB_NEXT_EV_OUT_SIZE 1
|
||||
#define CSR_USB_NEXT_EV_SETUP_OFFSET 2
|
||||
#define CSR_USB_NEXT_EV_SETUP_SIZE 1
|
||||
#define CSR_USB_NEXT_EV_RESET_OFFSET 3
|
||||
#define CSR_USB_NEXT_EV_RESET_SIZE 1
|
||||
#define CSR_USB_SETUP_DATA_ADDR 0xe000480cL
|
||||
#define CSR_USB_SETUP_DATA_SIZE 1
|
||||
static inline unsigned char usb_setup_data_read(void) {
|
||||
unsigned char r = csr_readl(0xe000480cL);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_SETUP_DATA_DATA_OFFSET 0
|
||||
#define CSR_USB_SETUP_DATA_DATA_SIZE 8
|
||||
#define CSR_USB_SETUP_CTRL_ADDR 0xe0004810L
|
||||
#define CSR_USB_SETUP_CTRL_SIZE 1
|
||||
static inline unsigned char usb_setup_ctrl_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004810L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_setup_ctrl_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004810L);
|
||||
}
|
||||
#define CSR_USB_SETUP_CTRL_RESET_OFFSET 5
|
||||
#define CSR_USB_SETUP_CTRL_RESET_SIZE 1
|
||||
#define CSR_USB_SETUP_STATUS_ADDR 0xe0004814L
|
||||
#define CSR_USB_SETUP_STATUS_SIZE 1
|
||||
static inline unsigned char usb_setup_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004814L);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_SETUP_STATUS_EPNO_OFFSET 0
|
||||
#define CSR_USB_SETUP_STATUS_EPNO_SIZE 4
|
||||
#define CSR_USB_SETUP_STATUS_HAVE_OFFSET 4
|
||||
#define CSR_USB_SETUP_STATUS_HAVE_SIZE 1
|
||||
#define CSR_USB_SETUP_STATUS_PEND_OFFSET 5
|
||||
#define CSR_USB_SETUP_STATUS_PEND_SIZE 1
|
||||
#define CSR_USB_SETUP_STATUS_IS_IN_OFFSET 6
|
||||
#define CSR_USB_SETUP_STATUS_IS_IN_SIZE 1
|
||||
#define CSR_USB_SETUP_STATUS_DATA_OFFSET 7
|
||||
#define CSR_USB_SETUP_STATUS_DATA_SIZE 1
|
||||
#define CSR_USB_SETUP_EV_STATUS_ADDR 0xe0004818L
|
||||
#define CSR_USB_SETUP_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_setup_ev_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004818L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_setup_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004818L);
|
||||
}
|
||||
#define CSR_USB_SETUP_EV_PENDING_ADDR 0xe000481cL
|
||||
#define CSR_USB_SETUP_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_setup_ev_pending_read(void) {
|
||||
unsigned char r = csr_readl(0xe000481cL);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_setup_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000481cL);
|
||||
}
|
||||
#define CSR_USB_SETUP_EV_ENABLE_ADDR 0xe0004820L
|
||||
#define CSR_USB_SETUP_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_setup_ev_enable_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004820L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_setup_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004820L);
|
||||
}
|
||||
#define CSR_USB_IN_DATA_ADDR 0xe0004824L
|
||||
#define CSR_USB_IN_DATA_SIZE 1
|
||||
static inline unsigned char usb_in_data_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004824L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_in_data_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004824L);
|
||||
}
|
||||
#define CSR_USB_IN_DATA_DATA_OFFSET 0
|
||||
#define CSR_USB_IN_DATA_DATA_SIZE 8
|
||||
#define CSR_USB_IN_CTRL_ADDR 0xe0004828L
|
||||
#define CSR_USB_IN_CTRL_SIZE 1
|
||||
static inline unsigned char usb_in_ctrl_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004828L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_in_ctrl_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004828L);
|
||||
}
|
||||
#define CSR_USB_IN_CTRL_EPNO_OFFSET 0
|
||||
#define CSR_USB_IN_CTRL_EPNO_SIZE 4
|
||||
#define CSR_USB_IN_CTRL_RESET_OFFSET 5
|
||||
#define CSR_USB_IN_CTRL_RESET_SIZE 1
|
||||
#define CSR_USB_IN_CTRL_STALL_OFFSET 6
|
||||
#define CSR_USB_IN_CTRL_STALL_SIZE 1
|
||||
#define CSR_USB_IN_STATUS_ADDR 0xe000482cL
|
||||
#define CSR_USB_IN_STATUS_SIZE 1
|
||||
static inline unsigned char usb_in_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe000482cL);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_IN_STATUS_IDLE_OFFSET 0
|
||||
#define CSR_USB_IN_STATUS_IDLE_SIZE 1
|
||||
#define CSR_USB_IN_STATUS_HAVE_OFFSET 4
|
||||
#define CSR_USB_IN_STATUS_HAVE_SIZE 1
|
||||
#define CSR_USB_IN_STATUS_PEND_OFFSET 5
|
||||
#define CSR_USB_IN_STATUS_PEND_SIZE 1
|
||||
#define CSR_USB_IN_EV_STATUS_ADDR 0xe0004830L
|
||||
#define CSR_USB_IN_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_in_ev_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004830L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_in_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004830L);
|
||||
}
|
||||
#define CSR_USB_IN_EV_PENDING_ADDR 0xe0004834L
|
||||
#define CSR_USB_IN_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_in_ev_pending_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004834L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_in_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004834L);
|
||||
}
|
||||
#define CSR_USB_IN_EV_ENABLE_ADDR 0xe0004838L
|
||||
#define CSR_USB_IN_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_in_ev_enable_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004838L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_in_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004838L);
|
||||
}
|
||||
#define CSR_USB_OUT_DATA_ADDR 0xe000483cL
|
||||
#define CSR_USB_OUT_DATA_SIZE 1
|
||||
static inline unsigned char usb_out_data_read(void) {
|
||||
unsigned char r = csr_readl(0xe000483cL);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_OUT_DATA_DATA_OFFSET 0
|
||||
#define CSR_USB_OUT_DATA_DATA_SIZE 8
|
||||
#define CSR_USB_OUT_CTRL_ADDR 0xe0004840L
|
||||
#define CSR_USB_OUT_CTRL_SIZE 1
|
||||
static inline unsigned char usb_out_ctrl_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004840L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_out_ctrl_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004840L);
|
||||
}
|
||||
#define CSR_USB_OUT_CTRL_EPNO_OFFSET 0
|
||||
#define CSR_USB_OUT_CTRL_EPNO_SIZE 4
|
||||
#define CSR_USB_OUT_CTRL_ENABLE_OFFSET 4
|
||||
#define CSR_USB_OUT_CTRL_ENABLE_SIZE 1
|
||||
#define CSR_USB_OUT_CTRL_RESET_OFFSET 5
|
||||
#define CSR_USB_OUT_CTRL_RESET_SIZE 1
|
||||
#define CSR_USB_OUT_CTRL_STALL_OFFSET 6
|
||||
#define CSR_USB_OUT_CTRL_STALL_SIZE 1
|
||||
#define CSR_USB_OUT_STATUS_ADDR 0xe0004844L
|
||||
#define CSR_USB_OUT_STATUS_SIZE 1
|
||||
static inline unsigned char usb_out_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004844L);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_OUT_STATUS_EPNO_OFFSET 0
|
||||
#define CSR_USB_OUT_STATUS_EPNO_SIZE 4
|
||||
#define CSR_USB_OUT_STATUS_HAVE_OFFSET 4
|
||||
#define CSR_USB_OUT_STATUS_HAVE_SIZE 1
|
||||
#define CSR_USB_OUT_STATUS_PEND_OFFSET 5
|
||||
#define CSR_USB_OUT_STATUS_PEND_SIZE 1
|
||||
#define CSR_USB_OUT_EV_STATUS_ADDR 0xe0004848L
|
||||
#define CSR_USB_OUT_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_out_ev_status_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004848L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_out_ev_status_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004848L);
|
||||
}
|
||||
#define CSR_USB_OUT_EV_PENDING_ADDR 0xe000484cL
|
||||
#define CSR_USB_OUT_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_out_ev_pending_read(void) {
|
||||
unsigned char r = csr_readl(0xe000484cL);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_out_ev_pending_write(unsigned char value) {
|
||||
csr_writel(value, 0xe000484cL);
|
||||
}
|
||||
#define CSR_USB_OUT_EV_ENABLE_ADDR 0xe0004850L
|
||||
#define CSR_USB_OUT_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_out_ev_enable_read(void) {
|
||||
unsigned char r = csr_readl(0xe0004850L);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_out_ev_enable_write(unsigned char value) {
|
||||
csr_writel(value, 0xe0004850L);
|
||||
}
|
||||
|
||||
#define USB_INTERRUPT 3
|
||||
|
||||
#endif /* __USB_EPTRI_H_ */
|
@ -15,14 +15,17 @@ void usb_connect(void);
|
||||
void usb_idle(void);
|
||||
void usb_disconnect(void);
|
||||
void usb_setup(const struct usb_setup_request *setup, uint32_t size);
|
||||
void usb_set_address(uint8_t address);
|
||||
|
||||
void usb_ack_in(uint8_t epno);
|
||||
void usb_ack_out(uint8_t epno);
|
||||
void usb_err_in(uint8_t epno);
|
||||
void usb_err_out(uint8_t epno);
|
||||
|
||||
void usb_ack_in(void);
|
||||
void usb_ack_out(void);
|
||||
void usb_err(void);
|
||||
void usb_send(const void *data, int total_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
30
booster/src/accessors.c
Normal file
30
booster/src/accessors.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <stdint.h>
|
||||
void csr_writeb(uint8_t value, uint32_t addr)
|
||||
{
|
||||
*((volatile uint8_t *)addr) = value;
|
||||
}
|
||||
|
||||
uint8_t csr_readb(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint8_t *)addr;
|
||||
}
|
||||
|
||||
void csr_writew(uint16_t value, uint32_t addr)
|
||||
{
|
||||
*((volatile uint16_t *)addr) = value;
|
||||
}
|
||||
|
||||
uint16_t csr_readw(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint16_t *)addr;
|
||||
}
|
||||
|
||||
void csr_writel(uint32_t value, uint32_t addr)
|
||||
{
|
||||
*((volatile uint32_t *)addr) = value;
|
||||
}
|
||||
|
||||
uint32_t csr_readl(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint32_t *)addr;
|
||||
}
|
@ -1,131 +1,145 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <csr.h>
|
||||
|
||||
#define SP_MOSI_PIN 0
|
||||
#define SP_MISO_PIN 1
|
||||
#define SP_WP_PIN 2
|
||||
#define SP_HOLD_PIN 3
|
||||
#define SP_CLK_PIN 4
|
||||
#define SP_CS_PIN 5
|
||||
#define SP_D0_PIN 0
|
||||
#define SP_D1_PIN 1
|
||||
#define SP_D2_PIN 2
|
||||
#define SP_D3_PIN 3
|
||||
#include "spi.h"
|
||||
|
||||
#define PI_OUTPUT 1
|
||||
#define PI_INPUT 0
|
||||
|
||||
static void gpioWrite(int pin, int val) {
|
||||
static uint8_t do_mirror;
|
||||
if (val)
|
||||
do_mirror |= 1 << pin;
|
||||
else
|
||||
do_mirror &= ~(1 << pin);
|
||||
picorvspi_cfg1_write(do_mirror);
|
||||
}
|
||||
|
||||
static int gpioRead(int pin) {
|
||||
return !!(picorvspi_stat1_read() & (1 << pin));
|
||||
}
|
||||
enum pin {
|
||||
PIN_MOSI = 0,
|
||||
PIN_CLK = 1,
|
||||
PIN_CS = 2,
|
||||
PIN_MISO_EN = 3,
|
||||
PIN_MISO = 4, // Value is ignored
|
||||
};
|
||||
|
||||
void spiBegin(void) {
|
||||
gpioWrite(SP_WP_PIN, 1);
|
||||
gpioWrite(SP_HOLD_PIN, 1);
|
||||
gpioWrite(SP_CS_PIN, 0);
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (0 << PIN_CS));
|
||||
}
|
||||
|
||||
void spiEnd(void) {
|
||||
gpioWrite(SP_CS_PIN, 1);
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_CS));
|
||||
}
|
||||
|
||||
void spiPause(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t spiXfer(uint8_t out) {
|
||||
static void spi_single_tx(uint8_t out) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
if (out & (1 << bit)) {
|
||||
gpioWrite(SP_MOSI_PIN, 1);
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_MOSI));
|
||||
lxspi_bitbang_write((1 << PIN_CLK) | (1 << PIN_MOSI));
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_MOSI));
|
||||
} else {
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (0 << PIN_MOSI));
|
||||
lxspi_bitbang_write((1 << PIN_CLK) | (0 << PIN_MOSI));
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (0 << PIN_MOSI));
|
||||
}
|
||||
else {
|
||||
gpioWrite(SP_MOSI_PIN, 0);
|
||||
}
|
||||
gpioWrite(SP_CLK_PIN, 1);
|
||||
spiPause();
|
||||
in |= ((!!gpioRead(SP_MISO_PIN)) << bit);
|
||||
gpioWrite(SP_CLK_PIN, 0);
|
||||
spiPause();
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t spi_single_rx(void) {
|
||||
int bit = 0;
|
||||
uint8_t in = 0;
|
||||
|
||||
lxspi_bitbang_write((1 << PIN_MISO_EN) | (0 << PIN_CLK));
|
||||
|
||||
while (bit++ < 8) {
|
||||
lxspi_bitbang_write((1 << PIN_MISO_EN) | (1 << PIN_CLK));
|
||||
in = (in << 1) | lxspi_miso_read();
|
||||
lxspi_bitbang_write((1 << PIN_MISO_EN) | (0 << PIN_CLK));
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
void spiCommand(uint8_t cmd) {
|
||||
spiXfer(cmd);
|
||||
static uint8_t spi_read_status(void) {
|
||||
uint8_t val;
|
||||
|
||||
spiBegin();
|
||||
spi_single_tx(0x05);
|
||||
val = spi_single_rx();
|
||||
spiEnd();
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t spiCommandRx(void) {
|
||||
return spiXfer(0xff);
|
||||
int spiIsBusy(void) {
|
||||
return spi_read_status() & (1 << 0);
|
||||
}
|
||||
|
||||
uint8_t spiReadStatus(void) {
|
||||
uint8_t val = 0xff;
|
||||
spiBegin();
|
||||
spiCommand(0x05);
|
||||
val = spiCommandRx();
|
||||
spiEnd();
|
||||
return val;
|
||||
__attribute__((used))
|
||||
uint32_t spi_id;
|
||||
|
||||
__attribute__((used))
|
||||
uint32_t spiId(void) {
|
||||
spi_id = 0;
|
||||
|
||||
spiBegin();
|
||||
spi_single_tx(0x90); // Read manufacturer ID
|
||||
spi_single_tx(0x00); // Dummy byte 1
|
||||
spi_single_tx(0x00); // Dummy byte 2
|
||||
spi_single_tx(0x00); // Dummy byte 3
|
||||
spi_id = (spi_id << 8) | spi_single_rx(); // Manufacturer ID
|
||||
spi_id = (spi_id << 8) | spi_single_rx(); // Device ID
|
||||
spiEnd();
|
||||
|
||||
spiBegin();
|
||||
spi_single_tx(0x9f); // Read device id
|
||||
(void)spi_single_rx(); // Manufacturer ID (again)
|
||||
spi_id = (spi_id << 8) | spi_single_rx(); // Memory Type
|
||||
spi_id = (spi_id << 8) | spi_single_rx(); // Memory Size
|
||||
spiEnd();
|
||||
|
||||
return spi_id;
|
||||
}
|
||||
|
||||
void spiBeginErase4(uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin();
|
||||
spiCommand(0x06);
|
||||
spi_single_tx(0x06);
|
||||
spiEnd();
|
||||
|
||||
spiBegin();
|
||||
spiCommand(0x20);
|
||||
spiCommand(erase_addr >> 16);
|
||||
spiCommand(erase_addr >> 8);
|
||||
spiCommand(erase_addr >> 0);
|
||||
spi_single_tx(0x20);
|
||||
spi_single_tx(erase_addr >> 16);
|
||||
spi_single_tx(erase_addr >> 8);
|
||||
spi_single_tx(erase_addr >> 0);
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
void spiBeginErase32(uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin();
|
||||
spiCommand(0x06);
|
||||
spi_single_tx(0x06);
|
||||
spiEnd();
|
||||
|
||||
spiBegin();
|
||||
spiCommand(0x52);
|
||||
spiCommand(erase_addr >> 16);
|
||||
spiCommand(erase_addr >> 8);
|
||||
spiCommand(erase_addr >> 0);
|
||||
spi_single_tx(0x52);
|
||||
spi_single_tx(erase_addr >> 16);
|
||||
spi_single_tx(erase_addr >> 8);
|
||||
spi_single_tx(erase_addr >> 0);
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
void spiBeginErase64(uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin();
|
||||
spiCommand(0x06);
|
||||
spi_single_tx(0x06);
|
||||
spiEnd();
|
||||
|
||||
spiBegin();
|
||||
spiCommand(0xD8);
|
||||
spiCommand(erase_addr >> 16);
|
||||
spiCommand(erase_addr >> 8);
|
||||
spiCommand(erase_addr >> 0);
|
||||
spi_single_tx(0xD8);
|
||||
spi_single_tx(erase_addr >> 16);
|
||||
spi_single_tx(erase_addr >> 8);
|
||||
spi_single_tx(erase_addr >> 0);
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
int spiIsBusy(void) {
|
||||
return spiReadStatus() & (1 << 0);
|
||||
}
|
||||
|
||||
void spiBeginWrite(uint32_t addr, const void *v_data, unsigned int count) {
|
||||
const uint8_t write_cmd = 0x02;
|
||||
const uint8_t *data = v_data;
|
||||
@ -133,37 +147,67 @@ void spiBeginWrite(uint32_t addr, const void *v_data, unsigned int count) {
|
||||
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin();
|
||||
spiCommand(0x06);
|
||||
spi_single_tx(0x06);
|
||||
spiEnd();
|
||||
|
||||
spiBegin();
|
||||
spiCommand(write_cmd);
|
||||
spiCommand(addr >> 16);
|
||||
spiCommand(addr >> 8);
|
||||
spiCommand(addr >> 0);
|
||||
spi_single_tx(write_cmd);
|
||||
spi_single_tx(addr >> 16);
|
||||
spi_single_tx(addr >> 8);
|
||||
spi_single_tx(addr >> 0);
|
||||
for (i = 0; (i < count) && (i < 256); i++)
|
||||
spiCommand(*data++);
|
||||
spi_single_tx(*data++);
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
uint32_t spiId(void) {
|
||||
uint32_t id = 0;
|
||||
|
||||
uint8_t spiReset(void) {
|
||||
// Writing 0xff eight times is equivalent to exiting QPI mode,
|
||||
// or if CFM mode is enabled it will terminate CFM and return
|
||||
// to idle.
|
||||
unsigned int i;
|
||||
spiBegin();
|
||||
spiCommand(0x90); // Read manufacturer ID
|
||||
spiCommand(0x00); // Dummy byte 1
|
||||
spiCommand(0x00); // Dummy byte 2
|
||||
spiCommand(0x00); // Dummy byte 3
|
||||
id = (id << 8) | spiCommandRx(); // Manufacturer ID
|
||||
id = (id << 8) | spiCommandRx(); // Device ID
|
||||
for (i = 0; i < 8; i++)
|
||||
spi_single_tx(0xff);
|
||||
spiEnd();
|
||||
|
||||
// Some SPI parts require this to wake up
|
||||
spiBegin();
|
||||
spiCommand(0x9f); // Read device id
|
||||
(void)spiCommandRx(); // Manufacturer ID (again)
|
||||
id = (id << 8) | spiCommandRx(); // Memory Type
|
||||
id = (id << 8) | spiCommandRx(); // Memory Size
|
||||
spi_single_tx(0xab); // Read electronic signature
|
||||
spiEnd();
|
||||
|
||||
return id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiInit(void) {
|
||||
|
||||
// Ensure CS is deasserted and the clock is high
|
||||
lxspi_bitbang_write((0 << PIN_CLK) | (1 << PIN_CS));
|
||||
|
||||
// Disable memory-mapped mode and enable bit-bang mode
|
||||
lxspi_bitbang_en_write(1);
|
||||
|
||||
// Reset the SPI flash, which will return it to SPI mode even
|
||||
// if it's in QPI mode, and ensure the chip is accepting commands.
|
||||
spiReset();
|
||||
|
||||
spiId();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spiHold(void) {
|
||||
spiBegin();
|
||||
spi_single_tx(0xb9);
|
||||
spiEnd();
|
||||
|
||||
}
|
||||
void spiUnhold(void) {
|
||||
spiBegin();
|
||||
spi_single_tx(0xab);
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
void spiFree(void) {
|
||||
// Re-enable memory-mapped mode
|
||||
lxspi_bitbang_en_write(0);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <usb.h>
|
||||
|
||||
struct usb_setup_request {
|
||||
@ -67,16 +68,23 @@ static const uint8_t usb_string_microsoft[18] = {
|
||||
|
||||
static uint8_t reply_buffer[8];
|
||||
static uint8_t usb_configuration = 0;
|
||||
static uint8_t data_buffer[64];
|
||||
|
||||
__attribute__((section(".ramtext")))
|
||||
void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
{
|
||||
const uint8_t *data = NULL;
|
||||
uint32_t datalen = 0;
|
||||
uint8_t ep_dir_is_in = setup->bmRequestType >> 7;
|
||||
|
||||
(void)size;
|
||||
|
||||
switch (setup->wRequestAndType)
|
||||
{
|
||||
case 0x0500: // SET_ADDRESS
|
||||
usb_set_address(setup->wValue);
|
||||
break;
|
||||
|
||||
case 0x0b01: // SET_INTERFACE
|
||||
break;
|
||||
|
||||
@ -100,7 +108,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
case 0x0082: // GET_STATUS (endpoint)
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
usb_err_in(0);
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = 0;
|
||||
@ -112,8 +120,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
case 0x0102: // CLEAR_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
usb_err_out(0);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -121,8 +128,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
case 0x0302: // SET_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
usb_err_out(0);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -138,7 +144,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
CASE_VALUE(0x0302, usb_string2_descriptor);
|
||||
CASE_VALUE(0x03ee, usb_string_microsoft);
|
||||
CASE_VALUE(0x0f00, usb_bos_descriptor);
|
||||
default: usb_err(); return;
|
||||
default: usb_err_in(0); return;
|
||||
}
|
||||
#undef CASE_VALUE
|
||||
goto send;
|
||||
@ -152,7 +158,7 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
datalen = sizeof(usb_ms_compat_id_descriptor);
|
||||
break;
|
||||
}
|
||||
usb_err();
|
||||
usb_err_in(0);
|
||||
return;
|
||||
|
||||
#ifdef LANDING_PAGE_URL
|
||||
@ -165,12 +171,12 @@ void usb_setup(const struct usb_setup_request *setup, uint32_t size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
usb_err();
|
||||
usb_err_in(0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
default:
|
||||
usb_err();
|
||||
usb_err_in(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -178,9 +184,18 @@ send:
|
||||
if (data && datalen) {
|
||||
if (datalen > setup->wLength)
|
||||
datalen = setup->wLength;
|
||||
usb_send(data, datalen);
|
||||
if (datalen > sizeof(data_buffer))
|
||||
datalen = sizeof(data_buffer);
|
||||
memcpy(data_buffer, data, datalen);
|
||||
usb_send(data_buffer, datalen);
|
||||
usb_ack_out(0);
|
||||
}
|
||||
else {
|
||||
// Ack the opposite endpoint type
|
||||
if (ep_dir_is_in)
|
||||
usb_ack_out(0);
|
||||
else
|
||||
usb_ack_in(0);
|
||||
}
|
||||
else
|
||||
usb_ack_in();
|
||||
return;
|
||||
}
|
||||
|
@ -1,237 +0,0 @@
|
||||
#include <csr.h>
|
||||
#include <irq.h>
|
||||
#include <string.h>
|
||||
#include <usb.h>
|
||||
|
||||
// #ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
||||
#if 1
|
||||
|
||||
#define EP0OUT_BUFFERS 8
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][128];
|
||||
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
||||
static volatile uint8_t usb_ep0out_wr_ptr;
|
||||
static volatile uint8_t usb_ep0out_rd_ptr;
|
||||
static const int max_byte_length = 64;
|
||||
|
||||
static const uint8_t * volatile current_data;
|
||||
static volatile int current_length;
|
||||
static volatile int data_offset;
|
||||
static volatile int data_to_send;
|
||||
static int next_packet_is_empty;
|
||||
|
||||
// Note that our PIDs are only bits 2 and 3 of the token,
|
||||
// since all other bits are effectively redundant at this point.
|
||||
enum USB_PID {
|
||||
USB_PID_OUT = 0,
|
||||
USB_PID_SOF = 1,
|
||||
USB_PID_IN = 2,
|
||||
USB_PID_SETUP = 3,
|
||||
};
|
||||
|
||||
enum epfifo_response {
|
||||
EPF_ACK = 0,
|
||||
EPF_NAK = 1,
|
||||
EPF_NONE = 2,
|
||||
EPF_STALL = 3,
|
||||
};
|
||||
|
||||
#define USB_EV_ERROR 1
|
||||
#define USB_EV_PACKET 2
|
||||
|
||||
void usb_idle(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
|
||||
// Reject all incoming data, since there is no handler anymore
|
||||
usb_ep_0_out_respond_write(EPF_NAK);
|
||||
|
||||
// Reject outgoing data, since we don't have any to give.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_disconnect(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
|
||||
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
|
||||
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
|
||||
usb_ep_0_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
usb_ep_0_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
|
||||
// Accept incoming data by default.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
|
||||
// Reject outgoing data, since we have none to give yet.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
usb_ep0out_wr_ptr = 0;
|
||||
usb_ep0out_rd_ptr = 0;
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
static void process_tx(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if we're
|
||||
// currently set up to respond NAK.
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent us from double-filling the buffer.
|
||||
if (!usb_ep_0_in_ibuf_empty_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_data || !current_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_offset += data_to_send;
|
||||
|
||||
data_to_send = current_length - data_offset;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send > max_byte_length) {
|
||||
data_to_send = max_byte_length;
|
||||
next_packet_is_empty = 0;
|
||||
}
|
||||
else if (data_to_send == max_byte_length) {
|
||||
next_packet_is_empty = 1;
|
||||
}
|
||||
else if (next_packet_is_empty) {
|
||||
next_packet_is_empty = 0;
|
||||
data_to_send = 0;
|
||||
}
|
||||
else if (current_data == NULL || data_to_send <= 0) {
|
||||
next_packet_is_empty = 0;
|
||||
current_data = NULL;
|
||||
current_length = 0;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int this_offset;
|
||||
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
|
||||
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_send(const void *data, int total_count) {
|
||||
|
||||
while ((current_length || current_data))// && usb_ep_0_in_respond_read() != EPF_NAK)
|
||||
;
|
||||
current_data = (uint8_t *)data;
|
||||
current_length = total_count;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
process_tx();
|
||||
}
|
||||
|
||||
void usb_wait_for_send_done(void) {
|
||||
while (current_data && current_length)
|
||||
;
|
||||
while ((usb_ep_0_in_dtb_read() & 1) == 1)
|
||||
;
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep0o_pending) {
|
||||
uint8_t last_tok = usb_ep_0_out_last_tok_read();
|
||||
uint32_t obuf_len = 0;
|
||||
static uint8_t obuf[128];
|
||||
if (!usb_ep_0_out_obuf_empty_read()) {
|
||||
while (!usb_ep_0_out_obuf_empty_read()) {
|
||||
obuf[obuf_len++] = usb_ep_0_out_obuf_head_read();
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (obuf_len >= 2)
|
||||
obuf_len -= 2 /* Strip off CRC16 */;
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_ep_0_in_dtb_write(1);
|
||||
data_offset = 0;
|
||||
current_length = 0;
|
||||
current_data = NULL;
|
||||
usb_setup((const void *)obuf, obuf_len);
|
||||
}
|
||||
|
||||
usb_ep_0_out_ev_pending_write(ep0o_pending);
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep0i_pending) {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_ack_in(void) {
|
||||
while (usb_ep_0_in_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_ack_out(void) {
|
||||
while (usb_ep_0_out_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_err(void) {
|
||||
usb_ep_0_out_respond_write(EPF_STALL);
|
||||
usb_ep_0_in_respond_write(EPF_STALL);
|
||||
}
|
||||
|
||||
int usb_recv(void *buffer, unsigned int buffer_len) {
|
||||
|
||||
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
while (1) {
|
||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
|
||||
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
if (ep0_buffer_len < buffer_len)
|
||||
buffer_len = ep0_buffer_len;
|
||||
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
memcpy(buffer, (void *)&usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
return buffer_len;
|
||||
}
|
||||
else if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_SETUP) {
|
||||
return -1;
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
314
booster/src/usb-eptri.c
Normal file
314
booster/src/usb-eptri.c
Normal file
@ -0,0 +1,314 @@
|
||||
#include <usb.h>
|
||||
#include <irq.h>
|
||||
#include <string.h>
|
||||
#include <usb.h>
|
||||
#include <usb-eptri.h>
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
|
||||
//__attribute__((used, aligned(4)))
|
||||
//static uint8_t volatile previous_setup_packet[10];
|
||||
//__attribute__((used))
|
||||
//volatile uint32_t previous_setup_length;
|
||||
|
||||
static uint8_t volatile out_buffer_length;
|
||||
static uint8_t volatile out_buffer[128];
|
||||
static uint8_t volatile out_ep;
|
||||
static uint8_t volatile out_have;
|
||||
static const int max_byte_length = 64;
|
||||
|
||||
static const uint8_t * volatile current_data;
|
||||
static volatile int current_length;
|
||||
static volatile uint8_t current_epno;
|
||||
static volatile int data_offset;
|
||||
static volatile int data_to_send;
|
||||
static int next_packet_is_empty;
|
||||
|
||||
__attribute__((used))
|
||||
const uint8_t * last_data;
|
||||
__attribute__((used))
|
||||
int last_length;
|
||||
__attribute__((used))
|
||||
int last_epno;
|
||||
__attribute__((used))
|
||||
int last_data_offset;
|
||||
__attribute__((used))
|
||||
int last_data_to_send;
|
||||
__attribute__((used))
|
||||
int last_packet_was_empty;
|
||||
|
||||
static uint8_t next_address = 0;
|
||||
|
||||
#define USB_EV_ERROR 1
|
||||
#define USB_EV_PACKET 2
|
||||
|
||||
void eptri_usb_idle(void) {
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void eptri_usb_disconnect(void) {
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
usb_setup_ev_pending_write(usb_setup_ev_pending_read());
|
||||
usb_in_ev_pending_write(usb_in_ev_pending_read());
|
||||
usb_out_ev_pending_write(usb_out_ev_pending_read());
|
||||
usb_setup_ev_enable_write(3);
|
||||
usb_in_ev_enable_write(1);
|
||||
usb_out_ev_enable_write(1);
|
||||
|
||||
// Reset the IN handler
|
||||
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
|
||||
|
||||
// Reset the SETUP handler
|
||||
usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
|
||||
|
||||
// Reset the OUT handler
|
||||
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
|
||||
|
||||
// Accept incoming data by default.
|
||||
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET);
|
||||
|
||||
usb_address_write(0);
|
||||
|
||||
// Turn on the external pullup
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
// Unmask the interrupt so we can respond to interrupts
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
out_buffer_length = 0;
|
||||
usb_pullup_out_write(0);
|
||||
usb_address_write(0);
|
||||
usb_out_ctrl_write(0);
|
||||
|
||||
usb_setup_ev_enable_write(0);
|
||||
usb_in_ev_enable_write(0);
|
||||
usb_out_ev_enable_write(0);
|
||||
|
||||
// Reset the IN handler
|
||||
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
|
||||
|
||||
// Reset the SETUP handler
|
||||
usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
|
||||
|
||||
// Reset the OUT handler
|
||||
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_tx(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if the system is idle.
|
||||
if (!(usb_in_status_read() & (1 << CSR_USB_IN_STATUS_IDLE_OFFSET))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't send empty data
|
||||
if (!current_data || !current_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_data_offset = data_offset;
|
||||
data_offset += data_to_send;
|
||||
|
||||
last_data_to_send = data_to_send;
|
||||
data_to_send = current_length - data_offset;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send > max_byte_length) {
|
||||
last_data_to_send = data_to_send;
|
||||
data_to_send = max_byte_length;
|
||||
last_packet_was_empty = next_packet_is_empty;
|
||||
next_packet_is_empty = 0;
|
||||
}
|
||||
else if (data_to_send == max_byte_length) {
|
||||
last_packet_was_empty = next_packet_is_empty;
|
||||
next_packet_is_empty = 1;
|
||||
}
|
||||
else if (next_packet_is_empty) {
|
||||
last_packet_was_empty = next_packet_is_empty;
|
||||
next_packet_is_empty = 0;
|
||||
|
||||
last_data_to_send = data_to_send;
|
||||
data_to_send = 0;
|
||||
}
|
||||
else if (current_data == NULL || data_to_send <= 0) {
|
||||
last_packet_was_empty = next_packet_is_empty;
|
||||
next_packet_is_empty = 0;
|
||||
|
||||
last_data = current_data;
|
||||
last_length = current_length;
|
||||
last_data_offset = data_offset;
|
||||
last_data_to_send = data_to_send;
|
||||
|
||||
current_data = NULL;
|
||||
current_length = 0;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// We have more data to send, so fill the buffer
|
||||
int this_offset;
|
||||
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
|
||||
usb_in_data_write(current_data[this_offset]);
|
||||
}
|
||||
|
||||
// Updating the epno queues the data
|
||||
usb_in_ctrl_write(current_epno & 0xf);
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_rx(void) {
|
||||
// If we already have data in our buffer, don't do anything.
|
||||
if (out_have)
|
||||
return;
|
||||
|
||||
// If there isn't any data in the FIFO, don't do anything.
|
||||
if (!(usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)))
|
||||
return;
|
||||
|
||||
out_have = 1;
|
||||
out_ep = (usb_out_status_read() >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf;
|
||||
out_buffer_length = 0;
|
||||
while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) {
|
||||
out_buffer[out_buffer_length++] = usb_out_data_read();
|
||||
}
|
||||
|
||||
// Strip off the CRC16 that's at the end of the buffer
|
||||
if (out_buffer_length >= 2)
|
||||
out_buffer_length -= 2;
|
||||
}
|
||||
|
||||
void usb_send(const void *data, int total_count) {
|
||||
uint8_t epno = 0;
|
||||
while ((current_length || current_data) && !(usb_in_status_read() & 2))
|
||||
process_tx();
|
||||
last_epno = current_epno;
|
||||
|
||||
current_data = (uint8_t *)data;
|
||||
current_length = total_count;
|
||||
current_epno = epno;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
process_tx();
|
||||
}
|
||||
|
||||
void eptri_usb_wait_for_send_done(void) {
|
||||
while (current_data && current_length)
|
||||
;
|
||||
while (usb_in_status_read() & (1 << CSR_USB_IN_STATUS_HAVE_OFFSET))
|
||||
;
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t setup_packet[10];
|
||||
uint32_t setup_length;
|
||||
uint8_t setup_pending = usb_setup_ev_pending_read();
|
||||
uint8_t in_pending = usb_in_ev_pending_read();
|
||||
uint8_t out_pending = usb_out_ev_pending_read();
|
||||
|
||||
// Clear all interrupts before we handle them
|
||||
usb_setup_ev_pending_write(setup_pending);
|
||||
usb_in_ev_pending_write(in_pending);
|
||||
usb_out_ev_pending_write(out_pending);
|
||||
|
||||
// USB reset event
|
||||
if (setup_pending & 2) {
|
||||
out_buffer_length = 0;
|
||||
out_have = 0;
|
||||
current_data = NULL;
|
||||
current_length = 0;
|
||||
usb_connect();
|
||||
return;
|
||||
}
|
||||
|
||||
// We got a SETUP packet. Copy it to the setup buffer and clear
|
||||
// the "pending" bit.
|
||||
if (setup_pending & 1) {
|
||||
// previous_setup_length = setup_length;
|
||||
// memcpy((void *)previous_setup_packet, (void *)setup_packet, sizeof(setup_packet));
|
||||
|
||||
setup_length = 0;
|
||||
memset((void *)setup_packet, 0, sizeof(setup_packet));
|
||||
while (usb_setup_status_read() & (1 << CSR_USB_SETUP_STATUS_HAVE_OFFSET)) {
|
||||
setup_packet[setup_length++] = usb_setup_data_read();
|
||||
}
|
||||
|
||||
// If we have 8 bytes, that's a full SETUP packet.
|
||||
// Otherwise, it was an RX error.
|
||||
if (setup_length == 10) {
|
||||
usb_setup((const struct usb_setup_request *)setup_packet, 8);
|
||||
}
|
||||
}
|
||||
|
||||
// An "IN" transaction just completed.
|
||||
if (in_pending) {
|
||||
// Process more data to send, if we have any.
|
||||
process_tx();
|
||||
|
||||
// If next_address is nonzero, then this is the completion of
|
||||
// the IN packet that follows as the final ACK. This means
|
||||
// we're free to set our address now.
|
||||
if (next_address) {
|
||||
usb_address_write(next_address);
|
||||
next_address = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// An "OUT" transaction just completed so we have new data.
|
||||
// (But only if we can accept the data)
|
||||
if (out_pending) {
|
||||
process_rx();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_ack_in(uint8_t ep) {
|
||||
(void)ep;
|
||||
// Writing to this register queues a transfer
|
||||
usb_in_ctrl_write(0);
|
||||
}
|
||||
|
||||
void usb_ack_out(uint8_t ep) {
|
||||
(void)ep;
|
||||
out_have = 0;
|
||||
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET);
|
||||
}
|
||||
|
||||
void usb_err_in(uint8_t ep) {
|
||||
(void)ep;
|
||||
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_STALL_OFFSET);
|
||||
}
|
||||
|
||||
void usb_err_out(uint8_t ep) {
|
||||
(void)ep;
|
||||
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_STALL_OFFSET);
|
||||
}
|
||||
|
||||
int eptri_usb_recv(void *buffer, int buffer_len) {
|
||||
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||
if (out_have) {
|
||||
usb_ack_out(0);
|
||||
}
|
||||
while (1) {
|
||||
if (out_have) {
|
||||
if (buffer_len > out_buffer_length)
|
||||
buffer_len = out_buffer_length;
|
||||
memcpy(buffer, (void *)out_buffer, buffer_len);
|
||||
usb_ack_out(0);
|
||||
return buffer_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usb_set_address(uint8_t new_address) {
|
||||
next_address = new_address;
|
||||
}
|
Loading…
Reference in New Issue
Block a user