Common USB functionality

This commit is contained in:
ksb 2009-07-11 14:44:27 +00:00
parent 44a83a12cd
commit 2c029597a1
10 changed files with 1246 additions and 0 deletions

View file

@ -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)/$@

View file

@ -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__ */

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<!ELEMENT descriptors (languages, strings)>
<!ELEMENT languages (lang+) >
<!ELEMENT lang (#PCDATA) >
<!ATTLIST lang
id CDATA "all"
>
<!ELEMENT strings (string+) >
<!ELEMENT string (lang+) >

View file

@ -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;

View file

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:template match="descriptors">
<xsl:variable name="num_lang" select="count(languages/lang)"/>
<xsl:text>#include "string-descriptors.h"&#10;</xsl:text>
<!-- string descriptors -->
<xsl:for-each select="strings/string/lang">
<xsl:text>static const struct {&#10;</xsl:text>
<xsl:text> struct usb_st_string_descriptor base;&#10;</xsl:text>
<xsl:text> Uint16 chars[</xsl:text>
<xsl:value-of select="string-length(text()) -1"/>
<xsl:text>];&#10;</xsl:text>
<xsl:text>} string_descriptor_</xsl:text>
<xsl:number count="/descriptors/strings/string" format="1"/>
<xsl:text>_</xsl:text>
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>all</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>= {{</xsl:text>
<xsl:value-of select="string-length(text())*2 + 2"/>
<xsl:text>, 3, {'</xsl:text>
<xsl:value-of select="substring(text(), 1,1)"/>
<xsl:text>'}}, {&#10;</xsl:text>
<xsl:call-template name="output-UCS2">
<xsl:with-param name="string" select="substring(text(), 2)"/>
</xsl:call-template>
<xsl:text>}};&#10;</xsl:text>
</xsl:for-each>
<!-- string tables -->
<xsl:for-each select="/descriptors/languages/lang">
<xsl:variable name="id" select="@id"/>
<xsl:text>static const struct usb_st_string_descriptor * string_table_</xsl:text>
<xsl:value-of select="$id"/>
<xsl:text>[] =&#10;{&#10;</xsl:text>
<xsl:for-each select="/descriptors/strings/string">
<xsl:text> &amp;string_descriptor_</xsl:text>
<xsl:number count="/descriptors/strings/string" format="1"/>
<xsl:text>_</xsl:text>
<xsl:choose>
<xsl:when test="lang[@id = $id]">
<xsl:value-of select="$id"/>
</xsl:when>
<xsl:when test="lang[@id = 'all' or count(@id) = 0]">
<xsl:text>all</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">
<xsl:text>No string found for index </xsl:text>
<xsl:number count="/descriptors/strings/string" format="1"/>
<xsl:text> and language </xsl:text>
<xsl:value-of select="$id"/>
</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:text>.base,&#10;</xsl:text>
</xsl:for-each>
<xsl:text>};&#10;</xsl:text>
</xsl:for-each>
<!-- language descriptor -->
<xsl:text>static const struct {&#10;</xsl:text>
<xsl:text> struct usb_st_language_descriptor base;&#10;</xsl:text>
<xsl:text> Uint16 langs[</xsl:text>
<xsl:value-of select="$num_lang -1"/>
<xsl:text>];&#10;</xsl:text>
<xsl:text>} language_descriptor =&#10;{&#10;</xsl:text>
<xsl:text> {</xsl:text>
<xsl:value-of select="$num_lang*2 + 2"/>
<xsl:text>, 3, {</xsl:text>
<xsl:value-of select="languages/lang[1]/text()"/>
<xsl:text>}},&#10; {</xsl:text>
<xsl:for-each select="languages/lang[position() > 1]">
<xsl:value-of select="text()"/>
<xsl:text>, </xsl:text>
</xsl:for-each>
<xsl:text>}};&#10;</xsl:text>
<!-- language lookup table -->
<xsl:text>static const struct {&#10;</xsl:text>
<xsl:text> struct usb_st_string_languages base;&#10;</xsl:text>
<xsl:text> struct usb_st_string_language_map map[</xsl:text>
<xsl:value-of select="$num_lang - 1"/>
<xsl:text>];&#10;} </xsl:text>
<xsl:text>string_languages_full={{</xsl:text>
<xsl:value-of select="$num_lang"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="count(strings/string)"/>
<xsl:text>, &amp;language_descriptor.base</xsl:text>
<xsl:text>, &#10; {{</xsl:text>
<xsl:value-of select="languages/lang[1]/text()"/>
<xsl:text>, string_table_</xsl:text>
<xsl:value-of select="languages/lang[1]/@id"/>
<xsl:text>}}}, {&#10;</xsl:text>
<xsl:for-each select="languages/lang[position() > 1]">
<xsl:text> {</xsl:text>
<xsl:value-of select="text()"/>
<xsl:text>, string_table_</xsl:text>
<xsl:value-of select="@id"/>
<xsl:text>},&#10;</xsl:text>
</xsl:for-each>
<xsl:text> }&#10;};&#10;</xsl:text>
<xsl:text>const struct usb_st_string_languages * const string_languages = &amp;string_languages_full.base;&#10;</xsl:text>
</xsl:template>
<xsl:template name="output-UCS2">
<xsl:param name="string"/>
<xsl:if test="string-length($string) &gt; 0">
<xsl:text>'</xsl:text>
<xsl:value-of select="substring($string, 1,1)"/>
<xsl:text>'</xsl:text>
<xsl:if test="string-length($string) &gt; 1">
<xsl:text>, </xsl:text>
</xsl:if>
<xsl:call-template name="output-UCS2">
<xsl:with-param name="string" select="substring($string, 2)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,142 @@
#ifndef __USB_API_H__SYN81IFYBN__
#define __USB_API_H__SYN81IFYBN__
#include <sys/process.h>
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__ */

View file

@ -0,0 +1,92 @@
#ifndef __USB_ARCH_H__0Z52ZDP0H6__
#define __USB_ARCH_H__0Z52ZDP0H6__
#include <contiki-conf.h>
#include <usb-api.h>
/* 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__ */

View file

@ -0,0 +1,588 @@
#include <usb-core.h>
#include <usb.h>
#include <usb-arch.h>
#include <usb-api.h>
#include <stdio.h>
#include <sys/process.h>
#include <stdio.h>
#include <descriptors.h>
#include <string-descriptors.h>
/* #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);
}

View file

@ -0,0 +1,23 @@
#ifndef __USB_CORE_H__YIKJDA7S1X__
#define __USB_CORE_H__YIKJDA7S1X__
#include <stdint.h>
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__ */

185
cpu/arm/common/usb/usb.h Normal file
View file

@ -0,0 +1,185 @@
#ifndef __USB_H__6PFTDPIMZM__
#define __USB_H__6PFTDPIMZM__
#include <stdint.h>
/* 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__ */