mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-12 02:05:54 +00:00
319 lines
7.0 KiB
C
319 lines
7.0 KiB
C
|
#include <stdint.h>
|
|||
|
#include <string.h>
|
|||
|
#include <signal.h>
|
|||
|
#include <chopstx.h>
|
|||
|
|
|||
|
#include "config.h"
|
|||
|
#include "usb_lld.h"
|
|||
|
|
|||
|
#define NUM_INTERFACES 1
|
|||
|
#define FEATURE_BUS_POWERED 0x80
|
|||
|
|
|||
|
static chopstx_mutex_t usb_mtx;
|
|||
|
static chopstx_cond_t usb_cnd;
|
|||
|
static uint32_t bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
|||
|
|
|||
|
extern void EP6_IN_Callback (uint16_t len);
|
|||
|
extern void EP6_OUT_Callback (uint16_t len);
|
|||
|
|
|||
|
#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
|
|||
|
extern int fraucheky_enabled (void);
|
|||
|
extern void fraucheky_init (void);
|
|||
|
extern void fraucheky_main (void);
|
|||
|
|
|||
|
extern void fraucheky_setup_endpoints_for_interface (struct usb_dev *dev, int stop);
|
|||
|
extern int fraucheky_setup (struct usb_dev *dev);
|
|||
|
extern int fraucheky_get_descriptor (struct usb_dev *dev);
|
|||
|
|
|||
|
static void
|
|||
|
setup_endpoints_for_interface (struct usb_dev *dev, uint16_t interface, int stop)
|
|||
|
{
|
|||
|
if (interface == 0)
|
|||
|
fraucheky_setup_endpoints_for_interface (dev, stop);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
usb_device_reset (struct usb_dev *dev)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
usb_lld_reset (dev, FEATURE_BUS_POWERED);
|
|||
|
|
|||
|
/* Initialize Endpoint 0. */
|
|||
|
usb_lld_setup_endp (dev, ENDP0, 1, 1);
|
|||
|
|
|||
|
/* Notify upper layer. */
|
|||
|
chopstx_mutex_lock (&usb_mtx);
|
|||
|
bDeviceState = USB_DEVICE_STATE_ATTACHED;
|
|||
|
chopstx_cond_signal (&usb_cnd);
|
|||
|
chopstx_mutex_unlock (&usb_mtx);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
usb_ctrl_write_finish (struct usb_dev *dev)
|
|||
|
{
|
|||
|
struct device_req *arg = &dev->dev_req;
|
|||
|
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
|||
|
|
|||
|
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
|
|||
|
&& USB_SETUP_SET (arg->type))
|
|||
|
{
|
|||
|
if (arg->request == MSC_MASS_STORAGE_RESET_COMMAND)
|
|||
|
fraucheky_setup_endpoints_for_interface (dev, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static int
|
|||
|
usb_setup (struct usb_dev *dev)
|
|||
|
{
|
|||
|
struct device_req *arg = &dev->dev_req;
|
|||
|
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
|||
|
|
|||
|
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
|
|||
|
&& arg->index == 0)
|
|||
|
return fraucheky_setup (dev);
|
|||
|
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
static int
|
|||
|
usb_set_configuration (struct usb_dev *dev)
|
|||
|
{
|
|||
|
int i;
|
|||
|
uint8_t current_conf;
|
|||
|
|
|||
|
current_conf = usb_lld_current_configuration (dev);
|
|||
|
if (current_conf == 0)
|
|||
|
{
|
|||
|
if (dev->dev_req.value != 1)
|
|||
|
return -1;
|
|||
|
|
|||
|
usb_lld_set_configuration (dev, 1);
|
|||
|
for (i = 0; i < NUM_INTERFACES; i++)
|
|||
|
setup_endpoints_for_interface (dev, i, 0);
|
|||
|
chopstx_mutex_lock (&usb_mtx);
|
|||
|
bDeviceState = USB_DEVICE_STATE_CONFIGURED;
|
|||
|
chopstx_mutex_unlock (&usb_mtx);
|
|||
|
}
|
|||
|
else if (current_conf != dev->dev_req.value)
|
|||
|
{
|
|||
|
if (dev->dev_req.value != 0)
|
|||
|
return -1;
|
|||
|
|
|||
|
usb_lld_set_configuration (dev, 0);
|
|||
|
for (i = 0; i < NUM_INTERFACES; i++)
|
|||
|
setup_endpoints_for_interface (dev, i, 1);
|
|||
|
chopstx_mutex_lock (&usb_mtx);
|
|||
|
bDeviceState = USB_DEVICE_STATE_ADDRESSED;
|
|||
|
chopstx_cond_signal (&usb_cnd);
|
|||
|
chopstx_mutex_unlock (&usb_mtx);
|
|||
|
}
|
|||
|
|
|||
|
/* Do nothing when current_conf == value */
|
|||
|
return usb_lld_ctrl_ack (dev);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static int
|
|||
|
usb_set_interface (struct usb_dev *dev)
|
|||
|
{
|
|||
|
uint16_t interface = dev->dev_req.index;
|
|||
|
uint16_t alt = dev->dev_req.value;
|
|||
|
|
|||
|
if (interface >= NUM_INTERFACES)
|
|||
|
return -1;
|
|||
|
|
|||
|
if (alt != 0)
|
|||
|
return -1;
|
|||
|
else
|
|||
|
{
|
|||
|
setup_endpoints_for_interface (dev, interface, 0);
|
|||
|
return usb_lld_ctrl_ack (dev);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static int
|
|||
|
usb_get_interface (struct usb_dev *dev)
|
|||
|
{
|
|||
|
const uint8_t zero = 0;
|
|||
|
uint16_t interface = dev->dev_req.index;
|
|||
|
|
|||
|
if (interface >= NUM_INTERFACES)
|
|||
|
return -1;
|
|||
|
|
|||
|
return usb_lld_ctrl_send (dev, &zero, 1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static int
|
|||
|
usb_get_status_interface (struct usb_dev *dev)
|
|||
|
{
|
|||
|
const uint16_t status_info = 0;
|
|||
|
uint16_t interface = dev->dev_req.index;
|
|||
|
|
|||
|
if (interface >= NUM_INTERFACES)
|
|||
|
return -1;
|
|||
|
|
|||
|
return usb_lld_ctrl_send (dev, &status_info, 2);
|
|||
|
}
|
|||
|
|
|||
|
static void usb_tx_done (uint8_t ep_num, uint16_t len);
|
|||
|
static void usb_rx_ready (uint8_t ep_num, uint16_t len);
|
|||
|
|
|||
|
|
|||
|
#define PRIO_USB 3
|
|||
|
|
|||
|
static void *
|
|||
|
usb_main (void *arg)
|
|||
|
{
|
|||
|
chopstx_intr_t interrupt;
|
|||
|
struct usb_dev dev;
|
|||
|
int e;
|
|||
|
|
|||
|
(void)arg;
|
|||
|
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
|||
|
usb_lld_init (&dev, FEATURE_BUS_POWERED);
|
|||
|
goto event_handle; /* For old SYS < 3.0 */
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
chopstx_intr_wait (&interrupt);
|
|||
|
|
|||
|
if (interrupt.ready)
|
|||
|
{
|
|||
|
uint8_t ep_num;
|
|||
|
|
|||
|
event_handle:
|
|||
|
e = usb_lld_event_handler (&dev);
|
|||
|
chopstx_intr_done (&interrupt);
|
|||
|
ep_num = USB_EVENT_ENDP (e);
|
|||
|
|
|||
|
if (ep_num != 0)
|
|||
|
{
|
|||
|
if (USB_EVENT_TXRX (e))
|
|||
|
usb_tx_done (ep_num, USB_EVENT_LEN (e));
|
|||
|
else
|
|||
|
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
|
|||
|
}
|
|||
|
else
|
|||
|
switch (USB_EVENT_ID (e))
|
|||
|
{
|
|||
|
case USB_EVENT_DEVICE_RESET:
|
|||
|
usb_device_reset (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_DEVICE_ADDRESSED:
|
|||
|
chopstx_mutex_lock (&usb_mtx);
|
|||
|
bDeviceState = USB_DEVICE_STATE_ADDRESSED;
|
|||
|
chopstx_cond_signal (&usb_cnd);
|
|||
|
chopstx_mutex_unlock (&usb_mtx);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_GET_DESCRIPTOR:
|
|||
|
if (fraucheky_get_descriptor (&dev) < 0)
|
|||
|
usb_lld_ctrl_error (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_SET_CONFIGURATION:
|
|||
|
if (usb_set_configuration (&dev) < 0)
|
|||
|
usb_lld_ctrl_error (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_SET_INTERFACE:
|
|||
|
if (usb_set_interface (&dev) < 0)
|
|||
|
usb_lld_ctrl_error (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_CTRL_REQUEST:
|
|||
|
/* Device specific device request. */
|
|||
|
if (usb_setup (&dev) < 0)
|
|||
|
usb_lld_ctrl_error (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_GET_STATUS_INTERFACE:
|
|||
|
if (usb_get_status_interface (&dev) < 0)
|
|||
|
usb_lld_ctrl_error (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_GET_INTERFACE:
|
|||
|
if (usb_get_interface (&dev) < 0)
|
|||
|
usb_lld_ctrl_error (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_SET_FEATURE_DEVICE:
|
|||
|
case USB_EVENT_SET_FEATURE_ENDPOINT:
|
|||
|
case USB_EVENT_CLEAR_FEATURE_DEVICE:
|
|||
|
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
|
|||
|
usb_lld_ctrl_ack (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_CTRL_WRITE_FINISH:
|
|||
|
/* Control WRITE transfer finished. */
|
|||
|
usb_ctrl_write_finish (&dev);
|
|||
|
continue;
|
|||
|
|
|||
|
case USB_EVENT_OK:
|
|||
|
case USB_EVENT_DEVICE_SUSPEND:
|
|||
|
default:
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
usb_tx_done (uint8_t ep_num, uint16_t len)
|
|||
|
{
|
|||
|
if (ep_num == ENDP6)
|
|||
|
EP6_IN_Callback (len);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
usb_rx_ready (uint8_t ep_num, uint16_t len)
|
|||
|
{
|
|||
|
if (ep_num == ENDP6)
|
|||
|
EP6_OUT_Callback (len);
|
|||
|
}
|
|||
|
|
|||
|
static char __process3_stack_base__[4096];
|
|||
|
|
|||
|
#define STACK_ADDR_USB ((uintptr_t)__process3_stack_base__)
|
|||
|
#define STACK_SIZE_USB (sizeof __process3_stack_base__)
|
|||
|
|
|||
|
#ifdef GNU_LINUX_EMULATION
|
|||
|
#define main emulated_main
|
|||
|
#endif
|
|||
|
|
|||
|
/*
|
|||
|
* Entry point.
|
|||
|
*
|
|||
|
* NOTE: the main function is already a thread in the system on entry.
|
|||
|
*/
|
|||
|
int
|
|||
|
main (int argc, char **argv)
|
|||
|
{
|
|||
|
chopstx_t usb_thd;
|
|||
|
|
|||
|
(void)argc;
|
|||
|
(void)argv;
|
|||
|
|
|||
|
chopstx_mutex_init (&usb_mtx);
|
|||
|
chopstx_cond_init (&usb_cnd);
|
|||
|
|
|||
|
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
|||
|
usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB,
|
|||
|
usb_main, NULL);
|
|||
|
fraucheky_init ();
|
|||
|
while (bDeviceState != USB_DEVICE_STATE_CONFIGURED)
|
|||
|
chopstx_usec_wait (250*1000);
|
|||
|
fraucheky_main ();
|
|||
|
chopstx_cancel (usb_thd);
|
|||
|
chopstx_join (usb_thd, NULL);
|
|||
|
usb_lld_shutdown ();
|
|||
|
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|