#include #include #include #include #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 = UNCONNECTED; /* USB device status */ 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_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); /* Stop the interface */ for (i = 0; i < NUM_INTERFACES; i++) setup_endpoints_for_interface (dev, i, 1); /* Notify upper layer. */ chopstx_mutex_lock (&usb_mtx); bDeviceState = 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 = 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 = 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 INTR_REQ_USB SIGUSR1 #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); 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 = 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 = UNCONNECTED; usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB, usb_main, NULL); while (bDeviceState != CONFIGURED) chopstx_usec_wait (250*1000); fraucheky_main (); chopstx_cancel (usb_thd); chopstx_join (usb_thd, NULL); usb_lld_shutdown (); bDeviceState = UNCONNECTED; return 0; }