Added USB (specifically CDC-ACM) support

This commit is contained in:
ksb 2007-09-01 10:00:35 +00:00
parent 3af69d229a
commit 9d5a2aed80
18 changed files with 2079 additions and 4 deletions

View file

@ -5,7 +5,7 @@ CONTIKI_CPU=$(CONTIKI)/cpu/at91sam7s
### Define the source files we have in the AT91SAM7S port
CONTIKI_CPU_DIRS = . dbg-io loader
CONTIKI_CPU_DIRS = . dbg-io loader usb
AT91SAM7S = clock.c debug-uart.c interrupt-utils.c newlib-syscalls.c sys-interrupt.c rtimer-arch.c rtimer-arch-interrupt.c uip-log.c
@ -14,10 +14,12 @@ APPDIRS += $(CONTIKI)/cpu/at91sam7s/loader
ELFLOADER = elfloader-otf.c elfloader-arm.c symtab.c cfs-ram.c
USB = usb-proto.c usb-handler.c usb-interrupt.c cdc-acm.c descriptors.c string-descriptors.c
TARGETLIBS = random.c dbg-printf.c dbg-puts.c dbg-putchar.c dbg-sprintf.c strformat.c
CONTIKI_TARGET_SOURCEFILES += $(AT91SAM7S) $(SYSAPPS) $(ELFLOADER) \
$(TARGETLIBS) $(UIPDRIVERS)
$(TARGETLIBS) $(UIPDRIVERS) $(USB)
CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)
@ -33,6 +35,8 @@ NM = arm-elf-nm
OBJCOPY = arm-elf-objcopy
STRIP = arm-elf-strip
XSLTPROC=xsltproc
PROJECT_OBJECTFILES += ${addprefix $(OBJECTDIR)/,$(CONTIKI_TARGET_MAIN:.c=.o)}
LINKERSCRIPT = $(CONTIKI_CPU)/AT91SAM7S64-ROM.ld
@ -54,7 +58,7 @@ ARM_FLAGS=
CFLAGSNO = -I. -I$(CONTIKI)/core -I$(CONTIKI_CPU) -I$(CONTIKI_CPU)/loader \
-I$(CONTIKI_CPU)/dbg-io\
-I$(CONTIKI_CPU)/dbg-io \
-I$(CONTIKI)/platform/$(TARGET) \
${addprefix -I,$(APPDIRS)} \
-DWITH_UIP -DWITH_ASCII -DMCK=$(MCK) \
@ -94,6 +98,7 @@ $(OBJECTDIR)/interrupt-utils.o: interrupt-utils.c
$(OBJECTDIR)/%.o: %.c
$(CC) $(CFLAGS) $(THUMB_FLAGS) -c $< -o $@
CUSTOM_RULE_S_TO_OBJECTDIR_O = yes
%.o: %.S
$(CC) $(CFLAGS) $(ARM_FLAGS) $< -c
@ -150,6 +155,10 @@ endif
empty-symbols.c:
@${CONTIKI}/tools/make-empty-symbols
$(CONTIKI_CPU)/usb/string-descriptors.c: \
$(CONTIKI_CPU)/usb/string-descriptors.xml
$(XSLTPROC) $(CONTIKI_CPU)/usb/string-descriptors.xslt $^ >$@
upload_ocd_%: %.bin
cp $< /tmp/openocd_write.bin
# Clear lock bits
@ -170,4 +179,4 @@ ocd_reset:
$(OBJECTDIR)/elfloader.o:
echo -n >$@
.PRECIOUS: %-nosyms.$(TARGET)
.PRECIOUS: %-nosyms.$(TARGET)

View file

@ -0,0 +1,83 @@
#include <cdc-acm.h>
#include <cdc.h>
#include <usb-proto.h>
#include <stdio.h>
static unsigned int
handle_cdc_acm_requests()
{
printf("CDC request %02x %02x\n", usb_setup_buffer.bmRequestType, usb_setup_buffer.bRequest);
switch(usb_setup_buffer.bmRequestType) {
case 0x21: /* CDC interface OUT requests */
/* Check if it's the right interface */
if (usb_setup_buffer.wIndex != 0) return 0;
switch(usb_setup_buffer.bRequest) {
case SET_CONTROL_LINE_STATE:
if (usb_setup_buffer.wValue & 0x02) {
puts("Carrier on");
} else {
puts("Carrier off");
}
if (usb_setup_buffer.wValue & 0x01) {
puts("DTE on");
} else {
puts("DTE off");
}
usb_send_ctrl_status();
return 1;
case SEND_ENCAPSULATED_COMMAND:
printf("Got CDC command: length %d\n", usb_ctrl_data_len);
usb_send_ctrl_status();
return 1;
case SET_LINE_CODING:
if (usb_ctrl_data_len == 7) {
static const char parity_char[] = {'N', 'O', 'E', 'M', 'S'};
static const char *stop_bits_str[] = {"1","1.5","2"};
const struct usb_cdc_line_coding *coding =
(const struct usb_cdc_line_coding *)usb_ctrl_data_buffer;
char parity = ((coding->bParityType > 4)
? '?' : parity_char[coding->bParityType]);
const char *stop_bits = ((coding->bCharFormat > 2)
? "?" : stop_bits_str[coding->bCharFormat]);
printf("Got CDC line coding: %ld/%d/%c/%s\n",
coding->dwDTERate, coding->bDataBits, parity, stop_bits);
usb_send_ctrl_status();
} else {
return 0;
}
return 1;
}
break;
case 0xa1: /* CDC interface IN requests */
if (usb_setup_buffer.wIndex != 0) return 0;
switch(usb_setup_buffer.bRequest) {
case GET_ENCAPSULATED_RESPONSE:
printf("CDC response");
usb_send_ctrl_status();
return 1;
}
}
return 0;
}
static const struct USBRequestHandler cdc_acm_request_handler =
{
0x21, 0x7f,
0x00, 0x00,
handle_cdc_acm_requests
};
static struct USBRequestHandlerHook cdc_acm_request_hook =
{
NULL,
&cdc_acm_request_handler
};
void
usb_cdc_acm_setup()
{
usb_register_request_handler(&cdc_acm_request_hook);
}

View file

@ -0,0 +1,7 @@
#ifndef __CDC_ACM_H__UFV6K50827__
#define __CDC_ACM_H__UFV6K50827__
void
usb_cdc_acm_setup();
#endif /* __CDC_ACM_H__UFV6K50827__ */

202
cpu/at91sam7s/usb/cdc.h Normal file
View file

@ -0,0 +1,202 @@
#ifndef __CDC_H__K1Q26ESJOC__
#define __CDC_H__K1Q26ESJOC__
#include <usb.h>
/* Communication Class */
/* Class code */
#define CDC 0x02
/* Interface subclass codes */
#define CDC_RESERVED 0x00
#define DIRECT_LINE_CONTROL_MODEL 0x01
#define ABSTRACT_CONTROL_MODEL 0x02
#define TELEPHONE_CONTROL_MODEL 0x03
#define MULTI_CHANNEL_CONTROL_MODEL 0x04
#define CAPI_CONTROL_MODEL 0x05
#define ETHERNET_NETWORKING_CONTROL_MODEL 0x06
#define ATM_NETWORKING_CONTROL_MODEL 0x07
/* Protocols */
#define V_25TER_PROTOCOL 0x01
/* Requests */
#define SEND_ENCAPSULATED_COMMAND 0x00
#define GET_ENCAPSULATED_RESPONSE 0x01
#define SET_COMM_FEATURE 0x02
#define GET_COMM_FEATURE 0x03
#define CLEAR_COMM_FEATURE 0x04
#define SET_AUX_LINE_STATE 0x10
#define SET_HOOK_STATE 0x11
#define PULSE_SETUP 0x12
#define SEND_PULSE 0x13
#define SET_PULSE_TIME 0x14
#define RING_AUX_JACK 0x15
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define SEND_BREAK 0x23
#define SET_RINGER_PARMS 0x30
#define GET_RINGER_PARMS 0x31
#define SET_OPERATION_PARMS 0x32
#define GET_OPERATION_PARMS 0x33
#define SET_LINE_PARMS 0x34
#define GET_LINE_PARMS 0x35
#define DIAL_DIGITS 0x36
#define SET_UNIT_PARAMETER 0x37
#define GET_UNIT_PARAMETER 0x38
#define CLEAR_UNIT_PARAMETER 0x39
#define GET_PROFILE 0x3a
#define SET_ETHERNET_MULTICAST_FILTERS 0x40
#define GET_ETHERNET_MULTICAST_FILTERS 0x41
#define GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x42
#define SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x43
#define GET_ETHERNET_STATISTIC 0x44
#define SET_ATM_D ATA_FORMAT 0x50
#define GET_ATM_DEVICE_STATISTICS 0x51
#define SET_ATM_DEFAULT_VC 0x52
#define GET_ATM_VC_STATISTICS 0x53
/* Notifications */
#define NETWORK_CONNECTION 0x00
#define RESPONSE_AVAILABLE 0x01
#define AUX_JACK_HOOK_STATE 0x08
#define RING_DETECT 0x09
#define SERIAL_STATE 0x20
#define CALL_STATE_CHANGE 0x28
#define LINE_STATE_CHANGE 0x29
#define CONNECTION_SPEED_CHANGE 0x2a
/* Data interface */
/* Class code */
#define CDC_DATA 0x0a
/* Protocols */
#define I_430_PROTOCOL 0x30
#define ISO_IEC_3_1993_PROTOCOL 0x31
#define TRANSPARENT_PROTOCOL 0x32
#define Q_921M_PROTOCOL 0x50
#define Q_921_PROTOCOL 0x51
#define Q_921TM_PROTOCOL 0x52
#define V_42BIS_PROTOCOL 0x90
#define Q_931_PROTOCOL 0x91
#define V_120_PROTOCOL 0x93
#define CDC_PROTOCOL 0xfe
/* Descriptor subtypes */
#define CDC_FUNC_DESCR_HEADER 0x00
#define CDC_FUNC_DESCR_CALL_MGMNT 0x01
#define CDC_FUNC_DESCR_ABSTRACT_CTRL_MGMNT 0x02
#define CDC_FUNC_DESCR_DIRECT_LINE_MGMNT 0x03
#define CDC_FUNC_DESCR_RINGER_MGMNT 0x04
#define CDC_FUNC_DESCR_TEL_STATE 0x05
#define CDC_FUNC_DESCR_UNION 0x06
#define CDC_FUNC_DESCR_COUNTRY 0x07
#define CDC_FUNC_DESCR_TEL_MODE 0x08
#define CDC_FUNC_DESCR_USB_TERM 0x09
#define CDC_FUNC_DESCR_NET_TERM 0x0a
#define CDC_FUNC_DESCR_PROTOCOL_UNIT 0x0b
#define CDC_FUNC_DESCR_EXTENSION_UNIT 0x0c
#define CDC_FUNC_DESCR_MULTICH_MGMNT 0x0d
#define CDC_FUNC_DESCR_CAPI_MGMNT 0x0e
#define CDC_FUNC_DESCR_ETHERNET 0x0f
#define CDC_FUNC_DESCR_ATM 0x10
struct usb_cdc_header_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_HEADER subtype */
Uint16 bcdCDC; /* Revision of class specification */
} BYTE_ALIGNED;
struct usb_cdc_call_mgmnt_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_CALL_MGMNT subtype */
Uchar bmCapabilities; /* Capabilities */
Uchar bDataInterface; /* Management data interface */
} BYTE_ALIGNED;
struct usb_cdc_abstract_ctrl_mgmnt_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_ABSTRACT_CTRL_MGMNT subtype*/
Uchar bmCapabilities; /* Capabilities */
} BYTE_ALIGNED;
struct usb_cdc_direct_line_mgmnt_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_DIRECT_LINE_MGMNT subtype*/
Uchar bmCapabilities; /* Capabilities */
} BYTE_ALIGNED;
struct usb_cdc_ringer_mgmnt_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_RINGER_MGMNT subtype*/
Uchar bRingerVolSteps; /* Ringer volume steps */
Uchar bNumRingerPatterns; /* Number of ringer patterns supported */
} BYTE_ALIGNED;
struct usb_cdc_tel_mode_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_TEL_MODE subtype*/
Uchar bmCapabilities; /* Capabilities */
} BYTE_ALIGNED;
struct usb_cdc_tel_state_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_TEL_STATE subtype*/
Uchar bmCapabilities; /* Capabilities */
} BYTE_ALIGNED;
struct usb_cdc_union_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_UNION subtype*/
Uchar bMasterInterface; /* Master interface for union */
Uchar bSlaveInterface[1]; /* Slave interfaces in union */
} BYTE_ALIGNED;
struct usb_cdc_country_func_descriptor
{
Uchar bLength; /* Size of this descriptor in bytes */
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_COUNTRY subtype*/
Uchar iCountryCodeRelDate; /* Release date for country codes */
Uint16 wCountryCode[1]; /* Country codes */
} BYTE_ALIGNED;
struct usb_cdc_line_coding
{
Uint32 dwDTERate;
Uchar bCharFormat;
Uchar bParityType;
Uchar bDataBits;
} BYTE_ALIGNED;
#endif /* __CDC_H__K1Q26ESJOC__ */

View file

@ -0,0 +1,124 @@
#include "descriptors.h"
#include <cdc.h>
const struct usb_st_device_descriptor device_descriptor =
{
sizeof(struct usb_st_device_descriptor),
DEVICE,
0x0210,
CDC,
0,
0,
CTRL_EP_SIZE,
0xffff,
0xffff,
0x0030,
2,
1,
3,
1
};
const struct configuration_st {
struct usb_st_configuration_descriptor configuration;
struct usb_st_interface_descriptor comm;
struct usb_cdc_header_func_descriptor header;
struct usb_cdc_abstract_ctrl_mgmnt_func_descriptor abstract_ctrl;
struct usb_cdc_union_func_descriptor union_descr;
struct usb_cdc_call_mgmnt_func_descriptor call_mgmt;
#if 1
struct usb_st_endpoint_descriptor ep_notification;
#endif
struct usb_st_interface_descriptor data;
struct usb_st_endpoint_descriptor ep_in;
struct usb_st_endpoint_descriptor ep_out;
} BYTE_ALIGNED configuration_block =
{
/* Configuration */
{
sizeof(configuration_block.configuration),
CONFIGURATION,
sizeof(configuration_block),
2,
1,
0,
0x80,
50
},
{
sizeof(configuration_block.comm),
INTERFACE,
0,
0,
1,
CDC,
ABSTRACT_CONTROL_MODEL,
V_25TER_PROTOCOL,
0
},
{
sizeof(configuration_block.header),
CS_INTERFACE,
CDC_FUNC_DESCR_HEADER,
0x0110
},
{
sizeof(configuration_block.abstract_ctrl),
CS_INTERFACE,
CDC_FUNC_DESCR_ABSTRACT_CTRL_MGMNT,
0
},
{
sizeof(configuration_block.union_descr),
CS_INTERFACE,
CDC_FUNC_DESCR_UNION,
0, /* Master */
{1} /* Slave */
},
{
sizeof(configuration_block.call_mgmt),
CS_INTERFACE,
CDC_FUNC_DESCR_CALL_MGMNT,
0x02,
1 /* data interface */
},
{
sizeof(configuration_block.ep_notification),
ENDPOINT,
0x83,
0x03,
8,
100
},
{
sizeof(configuration_block.data),
INTERFACE,
1,
0,
2,
CDC_DATA,
0,
TRANSPARENT_PROTOCOL,
0
},
{
sizeof(configuration_block.ep_in),
ENDPOINT,
0x81,
0x02,
64,
0
},
{
sizeof(configuration_block.ep_out),
ENDPOINT,
0x02,
0x02,
64,
0
}
};
const struct usb_st_configuration_descriptor const *configuration_head =
(struct usb_st_configuration_descriptor const*)&configuration_block;

View file

@ -0,0 +1,9 @@
#ifndef __DESCRIPTORS_H__RPFUB8O7OV__
#define __DESCRIPTORS_H__RPFUB8O7OV__
#include "usb.h"
#include <usb-config.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,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<descriptors>
<languages>
<lang id="en">0x0409</lang>
<lang id="sv">0x041d</lang>
</languages>
<strings>
<string> <!-- 1 -->
<lang id="en">Serial interface</lang>
<lang id="sv">Serieport</lang>
</string>
<string> <!-- 2 -->
<lang>Fluffware</lang>
</string>
<string> <!-- 3 -->
<lang>0.01</lang>
</string>
</strings>
</descriptors>

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,60 @@
#ifndef __USB_API_H__SYN81IFYBN__
#define __USB_API_H__SYN81IFYBN__
#include <sys/process.h>
void
usb_setup(void);
void
usb_set_user_process(struct process *p);
void
usb_setup_bulk_endpoint(unsigned char addr,
unsigned char *buffer, unsigned int buf_size);
void
usb_setup_interrupt_endpoint(unsigned char addr,
unsigned char *buffer, unsigned int buf_size);
/* Get a pointer to a buffer dat of length lenp.
To which USB data can be written. */
void
usb_send_buffer_get(unsigned char ep_addr, unsigned int offset,
unsigned char **dat, unsigned int *lenp);
/* Notify the USB subsystem that data has been written to the buffer returned
by usb_send_buffer_get. */
void
usb_send_buffer_commit(unsigned char ep_addr, unsigned int len);
unsigned int
usb_send_data(unsigned char ep_addr,
const unsigned char *dat, unsigned int len);
unsigned int
usb_recv_data(unsigned char ep_addr, unsigned char *dat, unsigned int len);
void
usb_disable_endpoint(unsigned char addr);
/* Asynchronous */
#define USB_USER_MSG_TYPE_CONFIG 0x01
#define USB_USER_MSG_TYPE_SUSPEND 0x02
#define USB_USER_MSG_TYPE_RESUME 0x03
/* Synchronous, the supplied data is only valid during the event */
#define USB_USER_MSG_TYPE_EP_OUT(ep_addr) ((((ep_addr) & 0x7f)<<4) | 0x01)
#define USB_USER_MSG_TYPE_EP_IN(ep_addr) ((((ep_addr) & 0x7f)<<4) | 0x02)
struct usb_user_msg {
unsigned int type;
union {
/* For EPx_OUT */
unsigned short length;
/* For CONFIG */
unsigned char config;
} data;
};
#endif /* __USB_API_H__SYN81IFYBN__ */

View file

@ -0,0 +1,16 @@
#ifndef __USB_CONFIG_H__LEIURX7H18__
#define __USB_CONFIG_H__LEIURX7H18__
#ifndef CTRL_EP_SIZE
#define CTRL_EP_SIZE 8
#endif
#ifndef NON_CTRL_XFER_SIZE
#define NON_CTRL_XFER_SIZE 64
#endif
#ifndef MAX_CTRL_DATA
#define MAX_CTRL_DATA 128
#endif
#endif /* __USB_CONFIG_H__LEIURX7H18__ */

View file

@ -0,0 +1,424 @@
#include <AT91SAM7S64.h>
#include <interrupt-utils.h>
#include <usb-interrupt.h>
#include <usb-proto.h>
#include <usb-api.h>
#include <stdio.h>
#include <sys/process.h>
#include <stdio.h>
#include <descriptors.h>
#include <string-descriptors.h>
#define USB_PULLUP_PIN AT91C_PIO_PA16
static unsigned short usb_device_status;
static unsigned char usb_configuration_value;
static struct process * user_process = NULL;
static struct USBRequestHandlerHook *usb_request_handler_hooks = NULL;
static const unsigned char zero_byte = 0;
static const unsigned short zero_word = 0;
static void
notify_user(struct usb_user_msg* msg)
{
if (user_process) {
process_post(user_process, PROCESS_EVENT_MSG, msg);
}
}
void
usb_set_user_process(struct process *p)
{
user_process = p;
}
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()
{
if (usb_configuration_value != LOW_BYTE(usb_setup_buffer.wValue)) {
usb_configuration_value = LOW_BYTE(usb_setup_buffer.wValue);
if (usb_configuration_value > 0) {
*AT91C_UDP_GLBSTATE |= AT91C_UDP_CONFG;
} else {
*AT91C_UDP_GLBSTATE &= ~AT91C_UDP_CONFG;
}
usb_send_ctrl_status();
return 1;
} else {
usb_send_ctrl_status();
return 0;
}
}
static void
get_device_status()
{
puts("get_device_status");
usb_send_ctrl_response((const unsigned char*)&usb_device_status,
sizeof(usb_device_status));
}
static void
get_endpoint_status()
{
puts("get_endpoint_status");
if ((usb_setup_buffer.wIndex & 0x7f) == 0) {
usb_send_ctrl_response((const unsigned char*)&zero_word,
sizeof(zero_word));
} else {
volatile USBEndpoint *ec;
ec = usb_find_endpoint(usb_setup_buffer.wIndex);
if (ec) {
usb_send_ctrl_response((const unsigned char*)&ec->status, sizeof(ec->status));
} else {
usb_error_stall();
}
}
}
static void
get_interface_status()
{
puts("get_interface_status");
usb_send_ctrl_response((const unsigned char*)&zero_word,
sizeof(zero_word));
}
static void
get_interface()
{
puts("get_interface");
if (usb_configuration_value == 0) usb_error_stall();
else {
usb_send_ctrl_response(&zero_byte,
sizeof(zero_byte));
}
}
static struct usb_user_msg config_msg = {USB_USER_MSG_TYPE_CONFIG};
static struct usb_user_msg io_msg[3];
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_set_address();
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()) {
config_msg.data.config = LOW_BYTE(usb_setup_buffer.wValue);
notify_user(&config_msg);
}
break;
default:
return 0;
}
break;
case 0x02:
switch(usb_setup_buffer.bRequest) {
case SET_FEATURE:
case CLEAR_FEATURE:
if (usb_setup_buffer.wValue == ENDPOINT_HALT_FEATURE) {
volatile USBEndpoint *ep = usb_find_endpoint(usb_setup_buffer.wIndex);
if (ep) {
usb_halt_endpoint(ep->addr, usb_setup_buffer.bRequest== SET_FEATURE);
usb_send_ctrl_status();
} else {
usb_error_stall();
}
} 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:
puts("Get report\n");
send_ctrl_response((code u_int8_t*)&zero_byte,
sizeof(zero_byte));
break;
case GET_HID_IDLE:
puts("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:
puts("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
};
PROCESS(usb_process, "USB process");
PROCESS_THREAD(usb_process, ev , data)
{
PROCESS_BEGIN();
puts("USB process started");
while(1) {
PROCESS_WAIT_EVENT();
if (ev == PROCESS_EVENT_EXIT) break;
if (ev == PROCESS_EVENT_POLL) {
if (usb_events & USB_EVENT_RESET) {
printf("Reset\n");
usb_clear_events(USB_EVENT_RESET);
}
if (usb_events & USB_EVENT_EP(0)) {
/* puts("Endpoint 0"); */
if (usb_endpoint_events[0] & USB_EP_EVENT_SETUP) {
struct USBRequestHandlerHook *hook = usb_request_handler_hooks;
#if 0
puts("Setup");
{
unsigned int i;
for (i = 0; i< 8; i++) printf(" %02x", ((unsigned char*)&usb_setup_buffer)[i]);
putchar('\n');
}
#endif
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();
}
usb_clear_ep_events(0, USB_EP_EVENT_SETUP);
}
usb_clear_events(USB_EVENT_EP(0));
}
{
unsigned int e;
for (e = 1; e <= 3; e++) {
if (usb_events & USB_EVENT_EP(e)) {
if (usb_endpoint_events[e] & (USB_EP_EVENT_OUT|USB_EP_EVENT_IN)) {
volatile USBEndpoint *ep = usb_find_endpoint(e);
struct usb_user_msg *msg = &io_msg[e-1];
if (usb_endpoint_events[e] & USB_EP_EVENT_OUT) {
msg->type = USB_USER_MSG_TYPE_EP_OUT(e);
msg->data.length = ep->buf_len;
} else {
msg->type = USB_USER_MSG_TYPE_EP_IN(e);
msg->data.length = ep->buf_size_mask + 1 - ep->buf_len;
}
notify_user(msg);
usb_clear_ep_events(e, USB_EP_EVENT_OUT|USB_EP_EVENT_IN);
usb_clear_events(USB_EVENT_EP(ep->addr));
}
}
}
}
}
}
PROCESS_END();
}
void
usb_setup(void)
{
/* Assume 96MHz PLL frequency */
*AT91C_CKGR_PLLR = ((*AT91C_CKGR_PLLR & ~AT91C_CKGR_USBDIV)
| AT91C_CKGR_USBDIV_1);
/* Enable 48MHz USB clock */
*AT91C_PMC_SCER = AT91C_PMC_UDP;
/* Enable USB main clock */
*AT91C_PMC_PCER = (1 << AT91C_ID_UDP);
/* Enable pullup */
*AT91C_PIOA_PER = USB_PULLUP_PIN;
*AT91C_PIOA_OER = USB_PULLUP_PIN;
*AT91C_PIOA_CODR = USB_PULLUP_PIN;
usb_register_request_handler(&standard_request_hook);
process_start(&usb_process, NULL);
usb_handler_process = &usb_process;
/* Enable usb_interrupt */
AT91C_AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4;
AT91C_AIC_SVR[AT91C_ID_UDP] = (unsigned long) usb_int;
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
usb_init_endpoints();
}
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;
}

View file

@ -0,0 +1,52 @@
#include <AT91SAM7S64.h>
#include <interrupt-utils.h>
#include <usb-interrupt.h>
#include <usb-proto.h>
#include <stdio.h>
static void
usb_int_safe (void) __attribute__((noinline));
static void
usb_int_safe (void)
{
unsigned int int_status;
/* putchar('*'); */
int_status = *AT91C_UDP_ISR & *AT91C_UDP_IMR;
if (int_status & (AT91C_UDP_EP1 | AT91C_UDP_EP2 | AT91C_UDP_EP3)) {
usb_epx_int();
} else if (int_status & AT91C_UDP_ENDBUSRES) {
usb_reset();
*AT91C_UDP_ICR = AT91C_UDP_ENDBUSRES;
} else if (int_status & AT91C_UDP_RXSUSP) {
/* puts("Suspend"); */
*AT91C_UDP_ICR = AT91C_UDP_RXSUSP;
} else if (int_status & AT91C_UDP_RXRSM) {
/* puts("Resume"); */
*AT91C_UDP_ICR = AT91C_UDP_RXRSM;
} else if (int_status & AT91C_UDP_SOFINT) {
/* puts("SOF"); */
*AT91C_UDP_ICR = AT91C_UDP_SOFINT;
} else if (int_status & AT91C_UDP_WAKEUP) {
/* puts("Wakeup"); */
*AT91C_UDP_ICR = AT91C_UDP_WAKEUP;
} else if (int_status & AT91C_UDP_EP0) {
usb_ep0_int();
} else {
puts("Other USB interrupt");
}
/* putchar('<'); */
}
void NACKEDFUNC
usb_int (void)
{
ISR_STORE();
ISR_ENABLE_NEST();
usb_int_safe();
ISR_DISABLE_NEST();
*AT91C_AIC_EOICR = 0;
ISR_RESTORE();
}

View file

@ -0,0 +1,7 @@
#ifndef __USB_INTERRUPT_H__Z1DQCUBTAL__
#define __USB_INTERRUPT_H__Z1DQCUBTAL__
void
usb_int (void);
#endif /* __USB_INTERRUPT_H__Z1DQCUBTAL__ */

View file

@ -0,0 +1,600 @@
#include <AT91SAM7S64.h>
#include <usb-api.h>
#include <usb-proto.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/process.h>
#include<interrupt-utils.h>
#ifndef AT91C_UDP_STALLSENT
#define AT91C_UDP_STALLSENT AT91C_UDP_ISOERROR
#endif
/* Bits that won't effect the state if they're written at a specific level.
*/
/* Bits that should be written as 1 */
#define NO_EFFECT_BITS (AT91C_UDP_TXCOMP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP \
| AT91C_UDP_ISOERROR | AT91C_UDP_RX_DATA_BK1)
/* Also includes bits that should be written as 0 */
#define NO_EFFECT_MASK (NO_EFFECT_BITS | AT91C_UDP_TXPKTRDY)
#define RXBYTECNT(s) (((s)>>16)&0x7ff)
/* Index in endpoint array */
#define EP_INDEX(addr) (((addr) & 0x7f) - 1)
/* Number of hardware endpoint */
#define EP_HW_NUM(addr) ((addr) & 0x7f)
static inline void
udp_set_ep_ctrl_flags(AT91_REG *reg, unsigned int flags,
unsigned int write_mask, unsigned int check_mask)
{
while ( (*reg & check_mask) != (flags & check_mask)) {
*reg = (*reg & ~write_mask) | flags;
}
}
#define UDP_SET_EP_CTRL_FLAGS(reg, flags, mask) \
udp_set_ep_ctrl_flags((reg), \
(NO_EFFECT_BITS & ~(mask)) | ((flags) & (mask)), (mask) | NO_EFFECT_MASK,\
(mask))
void
usb_error_stall()
{
/* Disable all USB events */
*AT91C_AIC_IDCR = (1 << AT91C_ID_UDP);
/* Set stall state */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
/* Reenable interrupt */
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
puts("Stalled");
}
volatile unsigned char usb_events = 0;
struct process *usb_handler_process = NULL;
#define NUM_EP 4
volatile unsigned char usb_endpoint_events[NUM_EP] = {0,0,0,0};
static volatile USBEndpoint usb_endpoints[NUM_EP - 1];
volatile 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 unsigned short usb_ctrl_send_len = 0;
static const unsigned char *usb_ctrl_send_pos = NULL;
unsigned char usb_ctrl_data_buffer[MAX_CTRL_DATA];
unsigned short usb_ctrl_data_len = 0;
static void
write_endpoint(unsigned int hw_ep,
const unsigned char *buffer, unsigned short len)
{
AT91_REG *fdr = &AT91C_UDP_FDR[hw_ep];
{
#if 0
unsigned int i;
printf("Sending: ");
for (i = 0; i< len; i++) printf(" %02x", buffer[i]);
putchar('\n');
#endif
}
while(len > 0) {
*fdr = *buffer++;
len--;
}
/* Start transmission */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
}
static void
write_ctrl()
{
if (usb_ctrl_send_pos) {
unsigned int xfer_len = usb_ctrl_send_len;
/* Check if FIFO is ready */
if (AT91C_UDP_CSR[0] & AT91C_UDP_TXPKTRDY) return;
if (xfer_len > CTRL_EP_SIZE) xfer_len = CTRL_EP_SIZE;
write_endpoint(0, usb_ctrl_send_pos, xfer_len);
if (xfer_len < CTRL_EP_SIZE) {
/* Last packet, stop sending */
usb_ctrl_send_pos = NULL;
} else {
usb_ctrl_send_pos += xfer_len;
usb_ctrl_send_len -= xfer_len;
if (usb_ctrl_send_len == 0 && !(usb_flags & USB_FLAG_SEND_ZLP)) {
usb_ctrl_send_pos = NULL;
}
}
}
}
static unsigned char
read_buffered_endpoint(volatile USBEndpoint *ep)
{
unsigned char len;
unsigned char mask = ep->buf_size_mask;
unsigned char *buffer = ep->buffer;
unsigned char pos = (ep->buf_pos + ep->buf_len) & mask;
AT91_REG *fdr = &AT91C_UDP_FDR[EP_HW_NUM(ep->addr)];
len = RXBYTECNT(AT91C_UDP_CSR[EP_HW_NUM(ep->addr)]);
if (mask + 1 - ep->buf_len < len) return 0;
ep->buf_len += len;
while(len-- > 0) {
buffer[pos] = *fdr;
pos = (pos + 1) & mask;
}
return 1;
}
unsigned int
usb_recv_data(unsigned char ep_addr, unsigned char *dat, unsigned int len)
{
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
unsigned char mask = ep->buf_size_mask;
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
{
unsigned char l;
unsigned char *to = ep->buffer;
unsigned char pos = ep->buf_pos;
if (ep->buf_len < len) len = ep->buf_len;
ep->buf_len -= len;
l = len;
while(l-- > 0) {
*dat++ = to[pos];
pos = (pos + 1) & mask;
}
ep->buf_pos = pos;
}
ep->flags &= ~USB_EP_FLAGS_RECV_BLOCKED;
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
return len;
}
void
write_buffered_endpoint(volatile USBEndpoint *ep)
{
unsigned int irq = disableIRQ();
{
unsigned int pos = ep->buf_pos;
unsigned int xfer_len = ep->buf_len;
unsigned int mask = ep->buf_size_mask;
const unsigned char *buf_tmp = ep->buffer;
AT91_REG *fdr = &AT91C_UDP_FDR[EP_HW_NUM(ep->addr)];
if (!(ep->flags & USB_EP_FLAGS_TRANSMITTING)
&& !(AT91C_UDP_CSR[EP_HW_NUM(ep->addr)] & AT91C_UDP_TXPKTRDY)) {
if (xfer_len > NON_CTRL_XFER_SIZE) xfer_len = NON_CTRL_XFER_SIZE;
ep->buf_len -= xfer_len;
/* printf("Writing %d to 0x%02x\n", xfer_len, ep->addr); */
while(xfer_len > 0) {
*fdr = buf_tmp[pos];
pos = (pos + 1) & mask;
xfer_len--;
}
ep->flags |= USB_EP_FLAGS_TRANSMITTING;
/* Start transmission */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep->addr)],
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
ep->buf_pos = pos;
}
}
restoreIRQ(irq);
}
static void
write_send_buffer(unsigned char *buffer, const unsigned char *dat,
unsigned int len)
{
while(len-- > 0) {
*buffer++ = *dat++;
}
}
void
usb_send_buffer_get(unsigned char ep_addr, unsigned int offset,
unsigned char **dat, unsigned int *lenp)
{
unsigned int pos;
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
unsigned int size = ep->buf_size_mask + 1;
unsigned int len;
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
len = size - ep->buf_len;
pos = (ep->buf_pos + offset + ep->buf_len) & (size - 1);
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
if (offset >= len) {
len = 0;
} else {
len -= offset;
}
if (pos + len > size) len = size - pos;
*dat = &ep->buffer[pos];
*lenp = len;
}
void
usb_send_buffer_commit(unsigned char ep_addr, unsigned int len)
{
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
ep->buf_len += len;
write_buffered_endpoint(ep);
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
}
unsigned int
usb_send_data(unsigned char ep_addr, const unsigned char *dat, unsigned int len)
{
unsigned char *write_pos;
unsigned int write_len;
unsigned int full_len = len;
/* printf("usb_send_data %02x: IMR=%08x\n",ep_addr, *AT91C_UDP_IMR); */
while(len > 0) {
usb_send_buffer_get(ep_addr, 0, &write_pos, &write_len);
if (write_len == 0) break;
if (write_len > len) write_len = len;
write_send_buffer(write_pos, dat, write_len);
/* printf("Pos: %p, len %d\n", write_pos, write_len); */
usb_send_buffer_commit(ep_addr, write_len);
dat += write_len;
len -= write_len;
}
return full_len - len;
}
void
usb_send_ctrl_response(const unsigned char *buffer, unsigned short len)
{
if (AT91C_UDP_CSR[0] & AT91C_UDP_TXPKTRDY) return;
*AT91C_UDP_IDR = AT91C_UDP_EP0;
if (len >= usb_setup_buffer.wLength) {
len = usb_setup_buffer.wLength; /* Truncate if too long */
usb_flags &= ~USB_FLAG_SEND_ZLP;
} else {
/* Send ZLP if the response is shorter than requested */
usb_flags |= USB_FLAG_SEND_ZLP;
}
usb_ctrl_send_pos = buffer;
usb_ctrl_send_len = len;
write_ctrl();
*AT91C_UDP_IER = AT91C_UDP_EP0;
}
void
usb_send_ctrl_status()
{
*AT91C_UDP_IDR = AT91C_UDP_EP0;
/* Start transmission */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
*AT91C_UDP_IER = AT91C_UDP_EP0;
}
static void
notify_process(unsigned char events)
{
usb_events |= events;
if (usb_handler_process) {
process_poll(usb_handler_process);
}
}
void
usb_reset()
{
/* Setup endpoint 0 */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
AT91C_UDP_EPTYPE_CTRL | AT91C_UDP_EPEDS,
AT91C_UDP_EPTYPE | AT91C_UDP_EPEDS);
/* Enable interrupt for control endpoint */
*AT91C_UDP_IER = AT91C_UDP_EP0;
notify_process(USB_EVENT_RESET);
}
struct USB_request_st usb_setup_buffer;
static void
read_fifo0(unsigned char *buffer, unsigned int length)
{
unsigned int r;
for (r = 0; r < length; r++) {
*buffer++ = AT91C_UDP_FDR[0];
}
}
void
usb_ep0_int()
{
unsigned int status;
status = AT91C_UDP_CSR[0];
#if 0
printf("status: %08x\n", status);
#endif
if (status & AT91C_UDP_STALLSENT) {
/* Acknowledge */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0, AT91C_UDP_STALLSENT);
}
if (status & AT91C_UDP_RXSETUP) {
usb_ctrl_send_pos = NULL; /* Cancel any pending control data
transmission */
if (RXBYTECNT(status) == 8) {
read_fifo0((unsigned char*)&usb_setup_buffer, 8);
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
((usb_setup_buffer.bmRequestType & 0x80)
? AT91C_UDP_DIR : 0),
AT91C_UDP_DIR);
usb_ctrl_data_len = 0;
if ((usb_setup_buffer.bmRequestType & 0x80) != 0
|| usb_setup_buffer.wLength == 0) {
usb_endpoint_events[0] |= USB_EP_EVENT_SETUP;
notify_process(USB_EVENT_EP(0));
} else {
if (usb_setup_buffer.wLength > MAX_CTRL_DATA) {
/* stall */
usb_error_stall();
} else {
usb_flags |= USB_FLAG_RECEIVING_CTRL;
}
}
} else {
usb_error_stall();
}
/* Acknowledge SETUP */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0, AT91C_UDP_RXSETUP);
} else if (status & (AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RX_DATA_BK0)) {
puts("IN");
if (usb_flags & USB_FLAG_RECEIVING_CTRL) {
unsigned int len;
unsigned int left = MAX_CTRL_DATA - usb_ctrl_data_len;
len = RXBYTECNT(status);
if (len > left) {
/* stall */
usb_error_stall();
} else {
unsigned char *buf_tmp = usb_ctrl_data_buffer + usb_ctrl_data_len;
usb_ctrl_data_len += len;
if (usb_ctrl_data_len == usb_setup_buffer.wLength
|| len < CTRL_EP_SIZE) {
usb_flags &= ~USB_FLAG_RECEIVING_CTRL;
usb_endpoint_events[0] |= USB_EP_EVENT_SETUP;
notify_process(USB_EVENT_EP(0));
}
while(len-- > 0) *buf_tmp++ = AT91C_UDP_FDR[0];
}
} else {
if (RXBYTECNT(status) > 0) {
puts("Discarded input");
}
}
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0,
AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RX_DATA_BK0);
}
if (status & AT91C_UDP_TXCOMP) {
/* puts("TX complete"); */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0, AT91C_UDP_TXCOMP);
if (usb_flags & USB_FLAG_ADDRESS_PENDING) {
*AT91C_UDP_FADDR = AT91C_UDP_FEN | LOW_BYTE(usb_setup_buffer.wValue);
*AT91C_UDP_GLBSTATE |= AT91C_UDP_FADDEN;
usb_flags &= ~USB_FLAG_ADDRESS_PENDING;
printf("Address changed: %d\n", *AT91C_UDP_FADDR & 0x7f);
} else {
if(usb_ctrl_send_pos) {
write_ctrl();
}
}
}
}
void
usb_epx_int()
{
unsigned int ep_index;
/* Handle enabled interrupts */
unsigned int int_status = *AT91C_UDP_ISR & *AT91C_UDP_IMR;
for (ep_index = 0; ep_index < NUM_EP-1; ep_index++) {
volatile USBEndpoint *ep = &usb_endpoints[ep_index];
unsigned int ep_num = EP_HW_NUM(ep->addr);
unsigned int ep_mask;
if (ep->addr != 0) { /* skip if not configured */
ep_mask = 1<<ep_num;
if (int_status & ep_mask) {
unsigned int status;
status = AT91C_UDP_CSR[ep_num];
#if 0
printf("EP %d status: %08x\n", ep->addr, status);
#endif
if (status & AT91C_UDP_STALLSENT) {
/* Acknowledge */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0, AT91C_UDP_STALLSENT);
}
if (status & AT91C_UDP_TXCOMP) {
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0, AT91C_UDP_TXCOMP);
ep->flags &= ~USB_EP_FLAGS_TRANSMITTING;
if (ep->buf_len > 0) {
write_buffered_endpoint(ep);
/* Tell the application that there's more room in the buffer */
usb_endpoint_events[ep_num] |= USB_EP_EVENT_IN;
notify_process(USB_EVENT_EP(ep_num));
}
}
if (status & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
unsigned char read_cnt;
read_cnt = read_buffered_endpoint(ep);
if (read_cnt == 0) {
*AT91C_UDP_IDR = 1<<ep_num;
ep->flags |= USB_EP_FLAGS_RECV_BLOCKED;
} else {
if (status & AT91C_UDP_RX_DATA_BK1) {
/* Ping-pong */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0,
(ep->flags & USB_EP_FLAGS_BANK_1_RECV_NEXT)
? AT91C_UDP_RX_DATA_BK1
: AT91C_UDP_RX_DATA_BK0);
ep->flags ^= USB_EP_FLAGS_BANK_1_RECV_NEXT;
} else {
/* Ping-pong or single buffer */
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0,
AT91C_UDP_RX_DATA_BK0);
ep->flags |= USB_EP_FLAGS_BANK_1_RECV_NEXT;
}
}
usb_endpoint_events[ep_num] |= USB_EP_EVENT_OUT;
notify_process(ep_mask);
}
}
}
}
}
/* Clear usb events from non-interrupt code */
void
usb_clear_events(unsigned events)
{
/* Disable allUSB events */
*AT91C_AIC_IDCR = (1 << AT91C_ID_UDP);
usb_events &= ~events;
/* Reenable interrupt */
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
}
void
usb_clear_ep_events(unsigned int ep, unsigned int events)
{
/* Disable all USB events */
*AT91C_AIC_IDCR = (1 << AT91C_ID_UDP);
usb_endpoint_events[ep] &= ~events;
/* Reenable interrupt */
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
}
void
usb_set_address()
{
usb_flags |= USB_FLAG_ADDRESS_PENDING;
/* The actual setting of the address is done when the status packet
is sent. */
}
static void
setup_endpoint(unsigned char addr,
unsigned char *buffer, unsigned int buf_size,
unsigned int type)
{
volatile USBEndpoint *ep;
/* Check if the address points to an existing endpoint */
if (EP_INDEX(addr) >= (sizeof(usb_endpoints)/sizeof(usb_endpoints[0]))) {
return;
}
ep = &usb_endpoints[EP_INDEX(addr)];
ep->addr = addr;
ep->buf_size_mask = buf_size - 1;
ep->buffer = buffer;
ep->buf_len = 0;
ep->buf_pos = 0;
ep->status = 0;
*AT91C_UDP_IDR = 1<<EP_HW_NUM(addr);
{
unsigned int ep_num = EP_HW_NUM(addr);
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],
type | AT91C_UDP_EPEDS,
AT91C_UDP_EPTYPE | AT91C_UDP_EPEDS);
}
*AT91C_UDP_IER = 1<<EP_HW_NUM(addr);
}
void
usb_setup_bulk_endpoint(unsigned char addr,
unsigned char *buffer, unsigned int buf_size)
{
setup_endpoint(addr, buffer, buf_size,
(addr & 0x80) ? AT91C_UDP_EPTYPE_BULK_IN
:AT91C_UDP_EPTYPE_BULK_OUT);
}
void
usb_setup_interrupt_endpoint(unsigned char addr,
unsigned char *buffer, unsigned int buf_size)
{
setup_endpoint(addr, buffer, buf_size,
(addr & 0x80) ? AT91C_UDP_EPTYPE_INT_IN
:AT91C_UDP_EPTYPE_INT_OUT);
}
void
usb_disable_endpoint(unsigned char addr)
{
/* Check if the address points to an existing endpoint */
if (EP_INDEX(addr) >= (sizeof(usb_endpoints)/sizeof(usb_endpoints[0]))) {
return;
}
*AT91C_UDP_IDR = 1<<EP_HW_NUM(addr);
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(addr)], 0, AT91C_UDP_EPEDS);
usb_endpoints[EP_INDEX(addr)].addr = 0;
}
static void
init_ep(volatile USBEndpoint *ctxt)
{
ctxt->addr = 0;
ctxt->buf_size_mask = 0;
ctxt->buf_len = 0;
ctxt->buf_pos = 0;
ctxt->buffer = 0;
ctxt->status = 0;
ctxt->flags = 0;
}
void
usb_init_endpoints()
{
unsigned int i;
for (i = 0; i < NUM_EP-1; i++) {
init_ep(&usb_endpoints[i]);
}
}
volatile USBEndpoint*
usb_find_endpoint(unsigned char epaddr)
{
if (EP_INDEX(epaddr) >= NUM_EP - 1) return 0;
return &usb_endpoints[EP_INDEX(epaddr)];
}
void
usb_halt_endpoint(unsigned char ep_addr, unsigned int halt)
{
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
if (halt) {
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep_addr)],
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
usb_endpoints[EP_INDEX(ep_addr)].status |= 0x01;
} else {
*AT91C_UDP_RSTEP = 1<<EP_HW_NUM(ep_addr);
usb_endpoints[EP_INDEX(ep_addr)].status &= ~0x01;
}
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
}

View file

@ -0,0 +1,118 @@
#ifndef __USB_PROTO_H__RVJQ2JAGM4__
#define __USB_PROTO_H__RVJQ2JAGM4__
#include <usb.h>
#include <usb-config.h>
#ifndef NULL
#define NULL 0
#endif
typedef struct _USBEndpoint USBEndpoint;
struct _USBEndpoint
{
unsigned char addr;
unsigned char buf_size_mask; /* mask for the buffer index. This implies
that the buffer size must be a power of
2 */
unsigned char buf_len;
unsigned char buf_pos;
unsigned char* buffer;
unsigned short status;
unsigned short flags;
};
#define USB_EP_FLAGS_BANK_1_RECV_NEXT 0x01 /* The next packet received
should be read from bank 1
if possible */
#define USB_EP_FLAGS_RECV_BLOCKED 0x02 /* Recetpion is blocked.
Interrupt turned off */
#define USB_EP_FLAGS_TRANSMITTING 0x04 /* Waiting for TXCOMP before sending
more data */
/* Read only */
struct USBRequestHandler
{
unsigned char request_type;
unsigned char request_type_mask;
unsigned char request;
unsigned char 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_reset();
void
usb_ep0_int();
void
usb_epx_int();
void
usb_clear_events(unsigned events);
void
usb_clear_ep_events(unsigned int ep, unsigned int events);
void
usb_error_stall();
void
usb_send_ctrl_response(const unsigned char *buffer, unsigned short len);
void
usb_send_ctrl_status();
void
usb_set_address();
void
usb_set_configuration_value(unsigned char c);
unsigned char
usb_get_configuration_value();
void
usb_init_endpoints();
volatile USBEndpoint*
usb_find_endpoint(unsigned char epaddr);
void
usb_halt_endpoint(unsigned char ep_addr, unsigned int halt);
extern volatile unsigned char usb_events;
extern struct process *usb_handler_process;
extern struct USB_request_st usb_setup_buffer;
extern unsigned char usb_ctrl_data_buffer[];
extern unsigned short usb_ctrl_data_len;
#define USB_EVENT_EP(ep) (0x01<<(ep))
#define USB_EVENT_RESET 0x10
#define USB_EVENT_SUPEND 0x20
#define USB_EVENT_RESUME 0x40
#define USB_EVENT_CONFIG 0x08
extern volatile unsigned char usb_endpoint_events[];
#define USB_EP_EVENT_SETUP 0x01
#define USB_EP_EVENT_OUT 0x02
#define USB_EP_EVENT_IN 0x04
#endif /* __USB_PROTO_H__RVJQ2JAGM4__ */

185
cpu/at91sam7s/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__ */