aboutsummaryrefslogtreecommitdiff
path: root/example-fraucheky/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'example-fraucheky/main.c')
-rw-r--r--example-fraucheky/main.c326
1 files changed, 326 insertions, 0 deletions
diff --git a/example-fraucheky/main.c b/example-fraucheky/main.c
new file mode 100644
index 0000000..efad8e1
--- /dev/null
+++ b/example-fraucheky/main.c
@@ -0,0 +1,326 @@
+#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 = 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
+
+void
+usb_lld_write (uint8_t ep_num, const void *buf, size_t len)
+{
+ usb_lld_tx_enable_buf (ep_num, buf, len);
+}
+
+/*
+ * 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;
+}