diff --git a/cpu/arm/common/usb/Makefile.usb b/cpu/arm/common/usb/Makefile.usb
new file mode 100644
index 000000000..b58b2a9a2
--- /dev/null
+++ b/cpu/arm/common/usb/Makefile.usb
@@ -0,0 +1,48 @@
+### Put generated sources in a separate directory
+BUILTSRCDIR = src_$(TARGET)
+ifeq (${wildcard $(BUILTSRCDIR)},)
+ DUMMY := ${shell mkdir $(BUILTSRCDIR)}
+endif
+
+PROJECTDIRS += $(BUILTSRCDIR)
+
+USB_STRING_DESCRIPTORS ?= $(CONTIKI_CPU_ARM)/common/usb/cdc-acm/string-descriptors.xml
+
+XMLDIRS=
+
+USB = usb-arch.c usb-core.c
+
+ifdef USB_CDC_ACM_CLASS
+CONTIKI_CPU_DIRS += ../common/usb/cdc-acm
+USB += cdc-acm.c cdc-acm-descriptors.c cdc-acm-string-descriptors.c
+XMLDIRS += $(CONTIKI_CPU_ARM)/common/usb/cdc-acm/
+endif
+
+ifdef USB_CDC_ETH_CLASS
+CONTIKI_CPU_DIRS += ../common/usb/cdc-eth
+USB += cdc-eth.c cdc-eth-descriptors.c cdc-eth-string-descriptors.c dhcps.c
+XMLDIRS += $(CONTIKI_CPU_ARM)/common/usb/cdc-eth/
+endif
+
+ifdef USB_MASS_STORAGE_CLASS
+CONTIKI_CPU_DIRS += ../common/usb/msc
+USB += usb-msc-bulk.c usb-rbc.c msc-descriptors.c msc-string-descriptors.c
+XMLDIRS += $(CONTIKI_CPU_ARM)/common/usb/msc
+endif
+
+ifdef USB_MSC_QIC157
+CONTIKI_CPU_DIRS += ../common/usb/msc
+USB += usb-msc-bulk.c usb-qic157.c msc-qic157-descriptors.c msc-qic157-string-descriptors.c
+XMLDIRS += $(CONTIKI_CPU_ARM)/common/usb/msc
+endif
+
+ifdef USB_MSC_STREAMING
+CONTIKI_CPU_DIRS += ../common/usb/msc
+USB += usb-msc-bulk.c usb-streaming.c msc-scsi-transparent-descriptors.c msc-streaming-string-descriptors.c
+XMLDIRS += $(CONTIKI_CPU_ARM)/common/usb/msc
+endif
+
+vpath %.xml $(XMLDIRS)
+
+%.c: %.xml
+ $(XSLTPROC) $(CONTIKI_CPU_ARM)/common/usb/string-descriptors.xslt $^ >$(BUILTSRCDIR)/$@
diff --git a/cpu/arm/common/usb/descriptors.h b/cpu/arm/common/usb/descriptors.h
new file mode 100644
index 000000000..c8bc72745
--- /dev/null
+++ b/cpu/arm/common/usb/descriptors.h
@@ -0,0 +1,8 @@
+#ifndef __DESCRIPTORS_H__RPFUB8O7OV__
+#define __DESCRIPTORS_H__RPFUB8O7OV__
+
+#include "usb.h"
+
+extern const struct usb_st_device_descriptor device_descriptor;
+extern const struct usb_st_configuration_descriptor const *configuration_head;
+#endif /* __DESCRIPTORS_H__RPFUB8O7OV__ */
diff --git a/cpu/arm/common/usb/string-descriptors.dtd b/cpu/arm/common/usb/string-descriptors.dtd
new file mode 100644
index 000000000..66f7469f3
--- /dev/null
+++ b/cpu/arm/common/usb/string-descriptors.dtd
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cpu/arm/common/usb/string-descriptors.h b/cpu/arm/common/usb/string-descriptors.h
new file mode 100644
index 000000000..6d0ffea5f
--- /dev/null
+++ b/cpu/arm/common/usb/string-descriptors.h
@@ -0,0 +1,16 @@
+#include "usb.h"
+struct usb_st_string_language_map
+{
+ Uint16 lang_id;
+ const struct usb_st_string_descriptor * const *descriptors;
+};
+
+struct usb_st_string_languages
+{
+ Uchar num_lang;
+ Uchar max_index;
+ const struct usb_st_language_descriptor *lang_descr;
+ const struct usb_st_string_language_map map[1];
+};
+
+extern const struct usb_st_string_languages * const string_languages;
diff --git a/cpu/arm/common/usb/string-descriptors.xslt b/cpu/arm/common/usb/string-descriptors.xslt
new file mode 100644
index 000000000..eab453326
--- /dev/null
+++ b/cpu/arm/common/usb/string-descriptors.xslt
@@ -0,0 +1,129 @@
+
+
+
+
+
+ #include "string-descriptors.h"
+
+
+
+ static const struct {
+ struct usb_st_string_descriptor base;
+ Uint16 chars[
+
+ ];
+ } string_descriptor_
+
+ _
+
+
+
+
+
+ all
+
+
+ = {{
+
+ , 3, {'
+
+ '}}, {
+
+
+
+ }};
+
+
+
+
+
+ static const struct usb_st_string_descriptor * string_table_
+
+ [] =
{
+
+ &string_descriptor_
+
+ _
+
+
+
+
+
+ all
+
+
+
+ No string found for index
+
+ and language
+
+
+
+
+ .base,
+
+ };
+
+
+
+ static const struct {
+ struct usb_st_language_descriptor base;
+ Uint16 langs[
+
+ ];
+ } language_descriptor =
{
+ {
+
+ , 3, {
+
+ }},
{
+
+
+ ,
+
+ }};
+
+
+ static const struct {
+ struct usb_st_string_languages base;
+ struct usb_st_string_language_map map[
+
+ ];
}
+ string_languages_full={{
+
+ ,
+
+ , &language_descriptor.base
+ ,
{{
+
+ , string_table_
+
+ }}}, {
+
+ {
+
+ , string_table_
+
+ },
+
+ }
};
+ const struct usb_st_string_languages * const string_languages = &string_languages_full.base;
+
+
+
+
+
+ '
+
+ '
+
+ ,
+
+
+
+
+
+
+
+
+
diff --git a/cpu/arm/common/usb/usb-api.h b/cpu/arm/common/usb/usb-api.h
new file mode 100644
index 000000000..45a67e29f
--- /dev/null
+++ b/cpu/arm/common/usb/usb-api.h
@@ -0,0 +1,142 @@
+#ifndef __USB_API_H__SYN81IFYBN__
+#define __USB_API_H__SYN81IFYBN__
+
+#include
+
+typedef struct _USBBuffer USBBuffer;
+
+struct _USBBuffer
+{
+ USBBuffer *next; /* Pointer to next buffer in chain */
+ uint8_t *data; /* Where to read/write data next */
+ uint16_t left; /* Remaining length of buffer. */
+ uint16_t flags;
+ uint32_t id; /* User data */
+};
+
+/* Buffer owned by the USB code, cleared when done */
+#define USB_BUFFER_SUBMITTED 0x01
+
+/* Write a short packet at end of buffer or release buffer when a
+ short packet is received. */
+#define USB_BUFFER_SHORT_END 0x02
+
+/* Release buffer as soon as any received data has been written in it. */
+#define USB_BUFFER_PACKET_END 0x04
+
+/* Notify the user when the buffer is released */
+#define USB_BUFFER_NOTIFY 0x08
+
+/* Packet should be sent to host. */
+#define USB_BUFFER_IN 0x40
+
+/* Used for receiving SETUP packets. If a SETUP packet is received and
+ the next buffers doesn't have this flag set, they will be skipped
+ until one is found. The associated buffer must be at least 8 bytes */
+#define USB_BUFFER_SETUP 0x20
+
+/* HALT the endpoint at this point. Only valid for bulk and interrupt
+ endpoints */
+#define USB_BUFFER_HALT 0x20
+
+/* Flags set by system */
+
+/* The last packet written to this buffer was short. */
+#define USB_BUFFER_SHORT_PACKET 0x10
+
+/* The operation associated with this buffer failed. I.e. it was discarded since it didn't match the received SETUP packet. */
+#define USB_BUFFER_FAILED 0x80
+
+/* Architecture specific flags */
+#define USB_BUFFER_ARCH_FLAG_1 0x1000
+#define USB_BUFFER_ARCH_FLAG_2 0x2000
+#define USB_BUFFER_ARCH_FLAG_3 0x4000
+#define USB_BUFFER_ARCH_FLAG_4 0x8000
+
+void
+usb_setup(void);
+
+
+/* Read only */
+struct USBRequestHandler
+{
+ uint8_t request_type;
+ uint8_t request_type_mask;
+ uint8_t request;
+ uint8_t request_mask;
+ /* Returns true if it handled the request, if false let another handler try*/
+ unsigned int (*handler_func)();
+};
+
+/* Must be writeable */
+struct USBRequestHandlerHook
+{
+ struct USBRequestHandlerHook *next;
+ const struct USBRequestHandler * const handler;
+};
+
+void
+usb_register_request_handler(struct USBRequestHandlerHook *hook);
+
+void
+usb_setup_bulk_endpoint(uint8_t addr);
+void
+usb_setup_interrupt_endpoint(uint8_t addr);
+
+/* Submit a chain of buffers to be filled with received data. Last
+ buffer must have next set to NULL. */
+void
+usb_submit_recv_buffer(uint8_t ep_addr, USBBuffer *buffer);
+
+/* Submit a chain of buffers to be sent. Last buffer must have next
+ set to NULL. When submitting packets to receive or send data in on
+ a control enpoint, all packets in the data stage must be submitted
+ at the same time. */
+void
+usb_submit_xmit_buffer(uint8_t ep_addr, USBBuffer *buffer);
+
+/* Return true if not all data has been sent to the host */
+int
+usb_send_pending(uint8_t ep_addr);
+
+/* Release all buffers submitted to the endpoint and discard any
+ buffered data. */
+void
+usb_discard_all_buffers(uint8_t ep_addr);
+
+void
+usb_disable_endpoint(uint8_t addr);
+
+/* Set or remove a HALT condition on an endpoint */
+void
+usb_halt_endpoint(uint8_t addr, int halt);
+
+/* Select what process should be polled when buffers with the
+ USB_BUFFER_NOTIFY flag set is released from the endpoint */
+void
+usb_set_ep_event_process(uint8_t addr, struct process *p);
+
+/* Select what process should be polled when a global event occurs */
+void
+usb_set_global_event_process(struct process *p);
+
+/* Global events */
+#define USB_EVENT_CONFIG 0x01
+#define USB_EVENT_SUSPEND 0x02
+#define USB_EVENT_RESUME 0x04
+#define USB_EVENT_RESET 0x08
+
+/* Returns global events that has occured since last time this
+ function was called */
+unsigned int
+usb_get_global_events(void);
+
+
+#define USB_EP_EVENT_NOTIFICATION 0x01
+unsigned int
+usb_get_ep_events(uint8_t addr);
+
+unsigned int
+usb_get_current_configuration(void);
+
+#endif /* __USB_API_H__SYN81IFYBN__ */
diff --git a/cpu/arm/common/usb/usb-arch.h b/cpu/arm/common/usb/usb-arch.h
new file mode 100644
index 000000000..d0969c004
--- /dev/null
+++ b/cpu/arm/common/usb/usb-arch.h
@@ -0,0 +1,92 @@
+#ifndef __USB_ARCH_H__0Z52ZDP0H6__
+#define __USB_ARCH_H__0Z52ZDP0H6__
+
+#include
+#include
+
+
+/* Includes control endpoint 0 */
+#ifndef USB_MAX_ENDPOINTS
+#define USB_MAX_ENDPOINTS 4
+#endif
+
+#ifndef CTRL_EP_SIZE
+#define CTRL_EP_SIZE 8
+#endif
+
+#ifndef USB_EP1_SIZE
+#define USB_EP1_SIZE 8
+#endif
+#ifndef USB_EP2_SIZE
+#define USB_EP2_SIZE 8
+#endif
+#ifndef USB_EP3_SIZE
+#define USB_EP3_SIZE 8
+#endif
+#ifndef USB_EP4_SIZE
+#define USB_EP4_SIZE 0
+#endif
+#ifndef USB_EP5_SIZE
+#define USB_EP5_SIZE 0
+#endif
+#ifndef USB_EP6_SIZE
+#define USB_EP6_SIZE 0
+#endif
+#ifndef USB_EP7_SIZE
+#define USB_EP7_SIZE 0
+#endif
+
+
+#ifndef MAX_CTRL_DATA
+#define MAX_CTRL_DATA 128
+#endif
+
+void
+usb_arch_setup(void);
+
+void
+usb_arch_setup_control_endpoint(uint8_t addr);
+
+void
+usb_arch_setup_bulk_endpoint(uint8_t addr);
+
+void
+usb_arch_setup_interrupt_endpoint(uint8_t addr);
+
+void
+usb_arch_disable_endpoint(uint8_t addr);
+
+void
+usb_arch_discard_all_buffers(uint8_t addr);
+
+/* Stall a control endpoint. The stall will be cleared when the next
+ SETUP token arrives. */
+void
+usb_arch_control_stall(uint8_t addr);
+
+/* Set or remove a HALT condition on an endpoint */
+void
+usb_arch_halt_endpoint(uint8_t addr, int halt);
+
+void
+usb_arch_set_configuration(uint8_t usb_configuration_value);
+
+uint16_t
+usb_arch_get_ep_status(uint8_t addr);
+
+void
+usb_arch_set_address(uint8_t addr);
+
+
+/* Select what process should be polled when a global event occurs. Intended for the protocol handler. Applications should use usb_set_global_event_process */
+void
+usb_arch_set_global_event_process(struct process *p);
+
+unsigned int
+usb_arch_get_global_events(void);
+
+/* Return true if not all data has been sent to the host */
+int
+usb_arch_send_pending(uint8_t ep_addr);
+
+#endif /* __USB_ARCH_H__0Z52ZDP0H6__ */
diff --git a/cpu/arm/common/usb/usb-core.c b/cpu/arm/common/usb/usb-core.c
new file mode 100644
index 000000000..4fae45aaa
--- /dev/null
+++ b/cpu/arm/common/usb/usb-core.c
@@ -0,0 +1,588 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* #define DEBUG */
+#ifdef DEBUG
+#define PRINTF(...) printf(__VA_ARGS__)
+#else
+#define PRINTF(...)
+#endif
+
+
+struct USB_request_st usb_setup_buffer;
+static USBBuffer ctrl_buffer;
+
+#define SETUP_ID 1
+#define OUT_ID 2
+#define IN_ID 3
+#define STATUS_OUT_ID 4
+#define STATUS_IN_ID 5
+
+static unsigned short usb_device_status;
+static unsigned char usb_configuration_value;
+
+static struct USBRequestHandlerHook *usb_request_handler_hooks = NULL;
+
+static const unsigned char zero_byte = 0;
+static const unsigned short zero_word = 0;
+
+static unsigned char usb_flags = 0;
+#define USB_FLAG_ADDRESS_PENDING 0x01
+#define USB_FLAG_RECEIVING_CTRL 0x04
+#define USB_FLAG_SEND_ZLP 0x08 /* If the last packet has max length,
+ then it needs to be followed by a
+ zero length packet to mark the
+ end. */
+
+static struct process *global_user_event_pocess = NULL;
+static unsigned int global_user_events = 0;
+
+void
+usb_set_global_event_process(struct process *p)
+{
+ global_user_event_pocess = p;
+}
+unsigned int
+usb_get_global_events(void)
+{
+ unsigned int e = global_user_events;
+ global_user_events = 0;
+ return e;
+}
+
+static void
+notify_user(unsigned int e)
+{
+ global_user_events |= e;
+ if (global_user_event_pocess) {
+ process_poll(global_user_event_pocess);
+ }
+}
+
+void
+usb_send_ctrl_response(const uint8_t *data, unsigned int len)
+{
+ if (ctrl_buffer.flags & USB_BUFFER_SUBMITTED) return;
+ if (len >= usb_setup_buffer.wLength) {
+ len = usb_setup_buffer.wLength; /* Truncate if too long */
+ }
+ ctrl_buffer.flags = USB_BUFFER_NOTIFY | USB_BUFFER_IN;
+ ctrl_buffer.next = NULL;
+ ctrl_buffer.data = (uint8_t*)data;
+ ctrl_buffer.left = len;
+ ctrl_buffer.id = IN_ID;
+ usb_submit_xmit_buffer(0,&ctrl_buffer);
+}
+
+void
+usb_error_stall()
+{
+ usb_arch_control_stall(0);
+}
+
+void
+usb_send_ctrl_status()
+{
+ if (ctrl_buffer.flags & USB_BUFFER_SUBMITTED) return;
+ ctrl_buffer.flags = USB_BUFFER_NOTIFY | USB_BUFFER_IN;
+ ctrl_buffer.next = NULL;
+ ctrl_buffer.data = NULL;
+ ctrl_buffer.left = 0;
+ ctrl_buffer.id = STATUS_IN_ID;
+ usb_submit_xmit_buffer(0,&ctrl_buffer);
+}
+
+static usb_ctrl_data_callback data_callback = NULL;
+static uint8_t *ctrl_data = NULL;
+static unsigned int ctrl_data_len = 0;
+void
+usb_get_ctrl_data(uint8_t *data, unsigned int length,
+ usb_ctrl_data_callback cb)
+{
+ if (ctrl_buffer.flags & USB_BUFFER_SUBMITTED) return;
+ PRINTF("usb_get_ctrl_data: %d\n",length);
+ data_callback = cb;
+ ctrl_data = data;
+ ctrl_data_len = length;
+ ctrl_buffer.flags = USB_BUFFER_NOTIFY;
+ ctrl_buffer.next = NULL;
+ ctrl_buffer.data = data;
+ ctrl_buffer.left = length;
+ ctrl_buffer.id = OUT_ID;
+ usb_submit_recv_buffer(0,&ctrl_buffer);
+}
+
+#if 0
+
+void
+usb_set_user_process(struct process *p)
+{
+ user_process = p;
+}
+#endif
+
+static void
+get_device_descriptor()
+{
+ usb_send_ctrl_response((unsigned char*)&device_descriptor, sizeof(device_descriptor));
+}
+
+static void
+get_string_descriptor()
+{
+ if (LOW_BYTE(usb_setup_buffer.wValue) == 0) {
+ usb_send_ctrl_response((const unsigned char*)string_languages->lang_descr,
+ string_languages->lang_descr->bLength);
+ } else {
+ unsigned char l;
+ const struct usb_st_string_descriptor *descriptor;
+ const struct usb_st_string_descriptor * const *table;
+ const struct usb_st_string_language_map *map;
+ if (LOW_BYTE(usb_setup_buffer.wValue) > string_languages->max_index) {
+ usb_error_stall();
+ return;
+ }
+ l = string_languages->num_lang;
+ map = string_languages->map;
+ table = map->descriptors; /* Use first table if language not found */
+ while (l > 0) {
+ if (map->lang_id == usb_setup_buffer.wIndex) {
+ table = map->descriptors;
+ break;
+ }
+ map++;
+ l--;
+ }
+ PRINTF("Lang id %04x = table %p\n", usb_setup_buffer.wIndex, (void*)table);
+ descriptor = table[LOW_BYTE(usb_setup_buffer.wValue) - 1];
+ usb_send_ctrl_response((const unsigned char*)descriptor,
+ descriptor->bLength);
+ }
+}
+
+static void
+get_configuration_descriptor()
+{
+ usb_send_ctrl_response((unsigned char*)configuration_head,
+ configuration_head->wTotalLength);
+}
+
+static void
+get_configuration()
+{
+ usb_send_ctrl_response((unsigned char*)&usb_configuration_value,
+ sizeof(usb_configuration_value));
+}
+
+/* Returns true if the configuration value changed */
+static int
+set_configuration()
+{
+ notify_user(USB_EVENT_CONFIG);
+ if (usb_configuration_value != LOW_BYTE(usb_setup_buffer.wValue)) {
+ usb_configuration_value = LOW_BYTE(usb_setup_buffer.wValue);
+ usb_arch_set_configuration(usb_configuration_value);
+ usb_send_ctrl_status();
+ return 1;
+ } else {
+ usb_send_ctrl_status();
+ return 0;
+ }
+}
+
+static void
+get_device_status()
+{
+ PRINTF("get_device_status\n");
+ usb_send_ctrl_response((const unsigned char*)&usb_device_status,
+ sizeof(usb_device_status));
+}
+
+static void
+get_endpoint_status()
+{
+ static uint16_t status;
+ PRINTF("get_endpoint_status\n");
+ if ((usb_setup_buffer.wIndex & 0x7f) == 0) {
+ usb_send_ctrl_response((const unsigned char*)&zero_word,
+ sizeof(zero_word));
+ } else {
+ status = usb_arch_get_ep_status(usb_setup_buffer.wIndex);
+ usb_send_ctrl_response((uint8_t*)&status, sizeof(status));
+ }
+}
+
+static void
+get_interface_status()
+{
+ PRINTF("get_interface_status\n");
+ usb_send_ctrl_response((const unsigned char*)&zero_word,
+ sizeof(zero_word));
+}
+
+static void
+get_interface()
+{
+ PRINTF("get_interface\n");
+ if (usb_configuration_value == 0) usb_error_stall();
+ else {
+ usb_send_ctrl_response(&zero_byte,
+ sizeof(zero_byte));
+ }
+}
+
+
+static unsigned int
+handle_standard_requests()
+{
+ switch(usb_setup_buffer.bmRequestType) {
+ case 0x80: /* standard device IN requests */
+ switch(usb_setup_buffer.bRequest) {
+ case GET_DESCRIPTOR:
+ switch (HIGH_BYTE(usb_setup_buffer.wValue)) {
+ case DEVICE:
+ get_device_descriptor();
+ break;
+ case CONFIGURATION:
+ get_configuration_descriptor();
+ break;
+ case STRING:
+ get_string_descriptor();
+ break;
+ default:
+ /* Unknown descriptor */
+ return 0;
+ }
+ break;
+ case GET_CONFIGURATION:
+ get_configuration();
+ break;
+ case GET_STATUS:
+ get_device_status();
+ break;
+ case GET_INTERFACE:
+ get_interface();
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case 0x81: /* standard interface IN requests */
+ switch(usb_setup_buffer.bRequest) {
+ case GET_STATUS:
+ get_interface_status();
+ break;
+#ifdef HID_ENABLED
+ case GET_DESCRIPTOR:
+ switch (USB_setup_buffer.wValue.byte.high) {
+ case REPORT:
+ get_report_descriptor();
+ break;
+ }
+ break;
+#endif
+ default:
+ return 0;
+ }
+ break;
+ case 0x82: /* standard endpoint IN requests */
+ switch(usb_setup_buffer.bRequest) {
+ case GET_STATUS:
+ get_endpoint_status();
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case 0x00: /* standard device OUT requests */
+ switch(usb_setup_buffer.bRequest) {
+ case SET_ADDRESS:
+ PRINTF("Address: %d\n", LOW_BYTE(usb_setup_buffer.wValue));
+ usb_flags |= USB_FLAG_ADDRESS_PENDING;
+ /* The actual setting of the address is done when the status packet
+ is sent. */
+ usb_send_ctrl_status();
+ break;
+#if SETABLE_STRING_DESCRIPTORS > 0
+ case SET_DESCRIPTOR:
+ if (usb_setup_buffer.wValue.byte.high == STRING) {
+ set_string_descriptor();
+ } else {
+ return 0;
+ }
+ break;
+#endif
+ case SET_CONFIGURATION:
+ if (set_configuration()) {
+#if 0
+ config_msg.data.config = LOW_BYTE(usb_setup_buffer.wValue);
+ notify_user(&config_msg);
+#endif
+ }
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case 0x01: /* standard interface OUT requests */
+ switch(usb_setup_buffer.bRequest) {
+ case SET_INTERFACE:
+ /* Change interface here if we support more than one */
+ usb_send_ctrl_status();
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case 0x02: /* standard endpoint OUT requests */
+ switch(usb_setup_buffer.bRequest) {
+ case SET_FEATURE:
+ case CLEAR_FEATURE:
+ if (usb_setup_buffer.wValue == ENDPOINT_HALT_FEATURE) {
+ usb_arch_halt_endpoint(usb_setup_buffer.wIndex, usb_setup_buffer.bRequest== SET_FEATURE);
+ usb_send_ctrl_status();
+ } else {
+ usb_error_stall();
+ }
+ break;
+ default:
+ return 0;
+ }
+ break;
+#ifdef HID_ENABLED
+ case 0xa1: /* class specific interface IN request*/
+ switch(USB_setup_buffer.bRequest) {
+ case GET_HID_REPORT:
+ PRINTF("Get report\n");
+ send_ctrl_response((code u_int8_t*)&zero_byte,
+ sizeof(zero_byte));
+ break;
+ case GET_HID_IDLE:
+ PRINTF("Get idle\n");
+ send_ctrl_response((code u_int8_t*)&zero_byte,
+ sizeof(zero_byte));
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case 0x21: /* class specific interface OUT request*/
+ switch(USB_setup_buffer.bRequest) {
+ case SET_HID_IDLE:
+ PRINTF("Set idle\n");
+ send_ctrl_status();
+ break;
+ default:
+ return 0;
+ }
+ break;
+#endif
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static const struct USBRequestHandler standard_request_handler =
+ {
+ 0x00, 0x60,
+ 0x00, 0x00,
+ handle_standard_requests
+ };
+
+static struct USBRequestHandlerHook standard_request_hook =
+ {
+ NULL,
+ &standard_request_handler
+ };
+
+static void
+submit_setup(void)
+{
+ ctrl_buffer.next = NULL;
+ ctrl_buffer.data = (uint8_t*)&usb_setup_buffer;
+ ctrl_buffer.left = sizeof(usb_setup_buffer);
+ ctrl_buffer.flags = (USB_BUFFER_PACKET_END | USB_BUFFER_SETUP
+ | USB_BUFFER_NOTIFY);
+ ctrl_buffer.id = SETUP_ID;
+ usb_submit_recv_buffer(0, &ctrl_buffer);
+}
+
+PROCESS(usb_process, "USB");
+
+PROCESS_THREAD(usb_process, ev , data)
+{
+ PROCESS_BEGIN();
+ PRINTF("USB process started\n");
+ while(1) {
+ PROCESS_WAIT_EVENT();
+ if (ev == PROCESS_EVENT_EXIT) break;
+ if (ev == PROCESS_EVENT_POLL) {
+ unsigned int events = usb_arch_get_global_events();
+ if (events) {
+ if (events & USB_EVENT_RESET) {
+ submit_setup();
+ usb_configuration_value = 0;
+ notify_user(USB_EVENT_RESET);
+ }
+ if (events & USB_EVENT_SUSPEND) {
+ notify_user(USB_EVENT_SUSPEND);
+ }
+ if (events & USB_EVENT_RESUME) {
+ notify_user(USB_EVENT_RESUME);
+ }
+
+ }
+ events = usb_get_ep_events(0);
+ if (events) {
+ if ((events & USB_EP_EVENT_NOTIFICATION)
+ && !(ctrl_buffer.flags & USB_BUFFER_SUBMITTED)) {
+ /* PRINTF("Endpoint 0\n"); */
+ if (ctrl_buffer.flags & USB_BUFFER_FAILED) {
+ /* Something went wrong with the buffer, just wait for a
+ new SETUP packet */
+ PRINTF("Discarded\n");
+ submit_setup();
+ } else if (ctrl_buffer.flags & USB_BUFFER_SETUP) {
+ struct USBRequestHandlerHook *hook = usb_request_handler_hooks;
+
+ PRINTF("Setup\n");
+ {
+ unsigned int i;
+ for (i = 0; i< 8; i++) PRINTF(" %02x", ((unsigned char*)&usb_setup_buffer)[i]);
+ PRINTF("\n");
+ }
+
+ while(hook) {
+ const struct USBRequestHandler *handler = hook->handler;
+ /* Check if the handler matches the request */
+ if (((handler->request_type ^ usb_setup_buffer.bmRequestType)
+ & handler->request_type_mask) == 0
+ && ((handler->request ^ usb_setup_buffer.bRequest)
+ & handler->request_mask) == 0) {
+ if (handler->handler_func()) break;
+ }
+ hook = hook->next;
+ }
+ if (!hook) {
+ /* No handler found */
+ usb_error_stall();
+ PRINTF("Unhandled setup: %02x %02x %04x %04x %04x\n",
+ usb_setup_buffer.bmRequestType, usb_setup_buffer.bRequest,
+ usb_setup_buffer.wValue, usb_setup_buffer.wIndex,
+ usb_setup_buffer.wLength);
+ submit_setup();
+ }
+ } else {
+ if (ctrl_buffer.id == IN_ID) {
+ /* Receive status stage */
+ PRINTF("Status OUT\n");
+ ctrl_buffer.flags = USB_BUFFER_NOTIFY;
+ ctrl_buffer.next = NULL;
+ ctrl_buffer.data = NULL;
+ ctrl_buffer.left = 0;
+ ctrl_buffer.id = STATUS_OUT_ID;
+ usb_submit_recv_buffer(0,&ctrl_buffer);
+ } else if (ctrl_buffer.id == STATUS_OUT_ID) {
+ PRINTF("Status OUT done\n");
+ submit_setup();
+ } else if (ctrl_buffer.id == STATUS_IN_ID) {
+ PRINTF("Status IN done\n");
+ if (usb_flags & USB_FLAG_ADDRESS_PENDING) {
+ while(usb_send_pending(0));
+ usb_arch_set_address(LOW_BYTE(usb_setup_buffer.wValue));
+ usb_flags &= ~USB_FLAG_ADDRESS_PENDING;
+ }
+ submit_setup();
+ } else if (ctrl_buffer.id == OUT_ID) {
+ PRINTF("OUT\n");
+ if (data_callback) {
+ data_callback(ctrl_data, ctrl_data_len- ctrl_buffer.left);
+ } else {
+ usb_send_ctrl_status();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ PROCESS_END();
+}
+
+
+void
+usb_setup(void)
+{
+ usb_arch_setup();
+ process_start(&usb_process, NULL);
+ usb_arch_set_global_event_process(&usb_process);
+ usb_set_ep_event_process(0, &usb_process);
+
+ usb_register_request_handler(&standard_request_hook);
+}
+
+void
+usb_register_request_handler(struct USBRequestHandlerHook *hook)
+{
+ struct USBRequestHandlerHook **prevp = &usb_request_handler_hooks;
+ /* Find last hook */
+ while(*prevp) {
+ prevp = &(*prevp)->next;
+ }
+ /* Add last */
+ *prevp = hook;
+ hook->next = NULL;
+}
+
+
+unsigned int
+usb_get_current_configuration(void)
+{
+ return usb_configuration_value;
+}
+
+void
+usb_setup_bulk_endpoint(unsigned char addr)
+{
+ usb_arch_setup_bulk_endpoint(addr);
+}
+
+void
+usb_setup_interrupt_endpoint(unsigned char addr)
+{
+ usb_arch_setup_interrupt_endpoint(addr);
+}
+
+void
+usb_disable_endpoint(uint8_t addr)
+{
+ usb_arch_discard_all_buffers(addr);
+ usb_arch_disable_endpoint(addr);
+}
+
+void
+usb_discard_all_buffers(uint8_t addr)
+{
+ usb_arch_discard_all_buffers(addr);
+}
+
+void
+usb_halt_endpoint(uint8_t addr, int halt)
+{
+ usb_arch_halt_endpoint(addr, halt);
+}
+
+int
+usb_send_pending(uint8_t addr)
+{
+ return usb_arch_send_pending(addr);
+}
+
diff --git a/cpu/arm/common/usb/usb-core.h b/cpu/arm/common/usb/usb-core.h
new file mode 100644
index 000000000..9baf5ab0e
--- /dev/null
+++ b/cpu/arm/common/usb/usb-core.h
@@ -0,0 +1,23 @@
+#ifndef __USB_CORE_H__YIKJDA7S1X__
+#define __USB_CORE_H__YIKJDA7S1X__
+
+#include
+
+struct USB_request_st usb_setup_buffer;
+
+void
+usb_send_ctrl_response(const uint8_t *data, unsigned int len);
+
+void
+usb_error_stall();
+
+void
+usb_send_ctrl_status();
+
+typedef void (*usb_ctrl_data_callback)(uint8_t *data, unsigned int length);
+
+void
+usb_get_ctrl_data(uint8_t *data, unsigned int length,
+ usb_ctrl_data_callback cb);
+
+#endif /* __USB_CORE_H__YIKJDA7S1X__ */
diff --git a/cpu/arm/common/usb/usb.h b/cpu/arm/common/usb/usb.h
new file mode 100644
index 000000000..86dc3419a
--- /dev/null
+++ b/cpu/arm/common/usb/usb.h
@@ -0,0 +1,185 @@
+#ifndef __USB_H__6PFTDPIMZM__
+#define __USB_H__6PFTDPIMZM__
+#include
+
+/* Adapted from usb_kbd_enum.h in c5131-usb-kbd-light-1_0_2 package from
+ Atmel */
+
+/* These definitions assume a little endian architecture */
+
+#ifdef __GNUC__
+#define BYTE_ALIGNED __attribute__ ((__packed__))
+#else
+#define BYTE_ALIGNED
+#endif
+
+#define LOW_BYTE(x) ((unsigned char)x)
+#define HIGH_BYTE(x) ((unsigned char)(x>>8))
+
+typedef uint8_t Uchar;
+typedef uint16_t Uint16;
+typedef uint32_t Uint32;
+
+/*_____ S T A N D A R D R E Q U E S T S __________________________________*/
+
+#define GET_STATUS 0x00
+#define GET_DEVICE 0x01
+#define CLEAR_FEATURE 0x01 /* see FEATURES below */
+#define GET_STRING 0x03
+#define SET_FEATURE 0x03 /* see FEATURES below */
+#define SET_ADDRESS 0x05
+#define GET_DESCRIPTOR 0x06
+#define SET_DESCRIPTOR 0x07
+#define GET_CONFIGURATION 0x08
+#define SET_CONFIGURATION 0x09
+#define GET_INTERFACE 0x0A
+#define SET_INTERFACE 0x0B
+#define SYNCH_FRAME 0x0C
+
+#define GET_DEVICE_DESCRIPTOR 1
+#define GET_CONFIGURATION_DESCRIPTOR 4
+
+#define REQUEST_DEVICE_STATUS 0x80
+#define REQUEST_INTERFACE_STATUS 0x81
+#define REQUEST_ENDPOINT_STATUS 0x82
+#define ZERO_TYPE 0x00
+#define INTERFACE_TYPE 0x01
+#define ENDPOINT_TYPE 0x02
+
+/*_____ D E S C R I P T O R T Y P E S ____________________________________*/
+
+#define DEVICE 0x01
+#define CONFIGURATION 0x02
+#define STRING 0x03
+#define INTERFACE 0x04
+#define ENDPOINT 0x05
+
+/* HID specific */
+#define HID 0x21
+#define REPORT 0x22
+/* *** */
+
+/*_____ S T A N D A R D F E A T U R E S __________________________________*/
+
+#define DEVICE_REMOTE_WAKEUP_FEATURE 0x01
+#define ENDPOINT_HALT_FEATURE 0x00
+
+/*_____ D E V I C E S T A T U S ___________________________________________*/
+
+#define SELF_POWERED 1
+
+/*_____ D E V I C E S T A T E _____________________________________________*/
+
+#define ATTACHED 0
+#define POWERED 1
+#define DEFAULT 2
+#define ADDRESSED 3
+#define CONFIGURED 4
+#define SUSPENDED 5
+
+#define USB_CONFIG_BUSPOWERED 0x80
+#define USB_CONFIG_SELFPOWERED 0x40
+#define USB_CONFIG_REMOTEWAKEUP 0x20
+
+/* Class specific */
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
+
+/*_________________________________________________________ S T R U C T _____*/
+/*_____ U S B D E V I C E R E Q U E S T _________________________________*/
+
+struct USB_request_st
+{
+ Uchar bmRequestType; /* Characteristics of the request */
+ Uchar bRequest; /* Specific request */
+ Uint16 wValue;
+ Uint16 wIndex; /* field that varies according to request */
+ Uint16 wLength; /* Number of bytes to transfer if Data */
+};
+
+
+/*_____ U S B D E V I C E D E S C R I P T O R ___________________________*/
+
+struct usb_st_device_descriptor
+{
+ Uchar bLength; /* Size of this descriptor in bytes */
+ Uchar bDescriptorType; /* DEVICE descriptor type */
+ Uint16 bscUSB; /* Binay Coded Decimal Spec. release */
+ Uchar bDeviceClass; /* Class code assigned by the USB */
+ Uchar bDeviceSubClass; /* Sub-class code assigned by the USB */
+ Uchar bDeviceProtocol; /* Protocol code assigned by the USB */
+ Uchar bMaxPacketSize0; /* Max packet size for EP0 */
+ Uint16 idVendor; /* Vendor ID. ATMEL = 0x03EB */
+ Uint16 idProduct; /* Product ID assigned by the manufacturer */
+ Uint16 bcdDevice; /* Device release number */
+ Uchar iManufacturer; /* Index of manu. string descriptor */
+ Uchar iProduct; /* Index of prod. string descriptor */
+ Uchar iSerialNumber; /* Index of S.N. string descriptor */
+ Uchar bNumConfigurations; /* Number of possible configurations */
+} BYTE_ALIGNED;
+
+
+/*_____ U S B C O N F I G U R A T I O N D E S C R I P T O R _____________*/
+
+struct usb_st_configuration_descriptor
+{
+ Uchar bLength; /* size of this descriptor in bytes */
+ Uchar bDescriptorType; /* CONFIGURATION descriptor type */
+ Uint16 wTotalLength; /* total length of data returned */
+ Uchar bNumInterfaces; /* number of interfaces for this conf. */
+ Uchar bConfigurationValue; /* value for SetConfiguration resquest */
+ Uchar iConfiguration; /* index of string descriptor */
+ Uchar bmAttibutes; /* Configuration characteristics */
+ Uchar MaxPower; /* maximum power consumption */
+} BYTE_ALIGNED;
+
+
+/*_____ U S B I N T E R F A C E D E S C R I P T O R _____________________*/
+
+struct usb_st_interface_descriptor
+{
+ Uchar bLength; /* size of this descriptor in bytes */
+ Uchar bDescriptorType; /* INTERFACE descriptor type */
+ Uchar bInterfaceNumber; /* Number of interface */
+ Uchar bAlternateSetting; /* value to select alternate setting */
+ Uchar bNumEndpoints; /* Number of EP except EP 0 */
+ Uchar bInterfaceClass; /* Class code assigned by the USB */
+ Uchar bInterfaceSubClass; /* Sub-class code assigned by the USB */
+ Uchar bInterfaceProtocol; /* Protocol code assigned by the USB */
+ Uchar iInterface; /* Index of string descriptor */
+} BYTE_ALIGNED;
+
+
+/*_____ U S B E N D P O I N T D E S C R I P T O R _______________________*/
+
+struct usb_st_endpoint_descriptor
+{
+ Uchar bLength; /* Size of this descriptor in bytes */
+ Uchar bDescriptorType; /* ENDPOINT descriptor type */
+ Uchar bEndpointAddress; /* Address of the endpoint */
+ Uchar bmAttributes; /* Endpoint's attributes */
+ Uint16 wMaxPacketSize; /* Maximum packet size for this EP */
+ Uchar bInterval; /* Interval for polling EP in ms */
+/* Uchar bRefresh; */
+/* Uchar bSynchAddress; */
+} BYTE_ALIGNED;
+
+
+/*_____ U S B S T R I N G D E S C R I P T O R _______________*/
+
+struct usb_st_string_descriptor
+{
+ Uchar bLength; /* size of this descriptor in bytes */
+ Uchar bDescriptorType; /* STRING descriptor type */
+ Uint16 wstring[1];/* unicode characters */
+} BYTE_ALIGNED;
+
+
+struct usb_st_language_descriptor
+{
+ Uchar bLength; /* size of this descriptor in bytes */
+ Uchar bDescriptorType; /* STRING descriptor type */
+ Uint16 wlangid[1]; /* language id */
+} BYTE_ALIGNED;
+
+#endif /* __USB_H__6PFTDPIMZM__ */