mirror of
https://github.com/oliverschmidt/contiki.git
synced 2024-12-23 01:29:33 +00:00
Added USB (specifically CDC-ACM) support
This commit is contained in:
parent
3af69d229a
commit
9d5a2aed80
@ -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
|
||||
|
83
cpu/at91sam7s/usb/cdc-acm.c
Normal file
83
cpu/at91sam7s/usb/cdc-acm.c
Normal 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);
|
||||
}
|
7
cpu/at91sam7s/usb/cdc-acm.h
Normal file
7
cpu/at91sam7s/usb/cdc-acm.h
Normal 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
202
cpu/at91sam7s/usb/cdc.h
Normal 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__ */
|
124
cpu/at91sam7s/usb/descriptors.c
Normal file
124
cpu/at91sam7s/usb/descriptors.c
Normal 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;
|
9
cpu/at91sam7s/usb/descriptors.h
Normal file
9
cpu/at91sam7s/usb/descriptors.h
Normal 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__ */
|
15
cpu/at91sam7s/usb/string-descriptors.dtd
Normal file
15
cpu/at91sam7s/usb/string-descriptors.dtd
Normal 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+) >
|
||||
|
16
cpu/at91sam7s/usb/string-descriptors.h
Normal file
16
cpu/at91sam7s/usb/string-descriptors.h
Normal 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;
|
19
cpu/at91sam7s/usb/string-descriptors.xml
Normal file
19
cpu/at91sam7s/usb/string-descriptors.xml
Normal 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>
|
129
cpu/at91sam7s/usb/string-descriptors.xslt
Normal file
129
cpu/at91sam7s/usb/string-descriptors.xslt
Normal 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" </xsl:text>
|
||||
|
||||
<!-- string descriptors -->
|
||||
<xsl:for-each select="strings/string/lang">
|
||||
<xsl:text>static const struct { </xsl:text>
|
||||
<xsl:text> struct usb_st_string_descriptor base; </xsl:text>
|
||||
<xsl:text> Uint16 chars[</xsl:text>
|
||||
<xsl:value-of select="string-length(text()) -1"/>
|
||||
<xsl:text>]; </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>'}}, { </xsl:text>
|
||||
<xsl:call-template name="output-UCS2">
|
||||
<xsl:with-param name="string" select="substring(text(), 2)"/>
|
||||
</xsl:call-template>
|
||||
<xsl:text>}}; </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>[] = { </xsl:text>
|
||||
<xsl:for-each select="/descriptors/strings/string">
|
||||
<xsl:text> &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, </xsl:text>
|
||||
</xsl:for-each>
|
||||
<xsl:text>}; </xsl:text>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- language descriptor -->
|
||||
<xsl:text>static const struct { </xsl:text>
|
||||
<xsl:text> struct usb_st_language_descriptor base; </xsl:text>
|
||||
<xsl:text> Uint16 langs[</xsl:text>
|
||||
<xsl:value-of select="$num_lang -1"/>
|
||||
<xsl:text>]; </xsl:text>
|
||||
<xsl:text>} language_descriptor = { </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>}}, {</xsl:text>
|
||||
<xsl:for-each select="languages/lang[position() > 1]">
|
||||
<xsl:value-of select="text()"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
</xsl:for-each>
|
||||
<xsl:text>}}; </xsl:text>
|
||||
|
||||
<!-- language lookup table -->
|
||||
<xsl:text>static const struct { </xsl:text>
|
||||
<xsl:text> struct usb_st_string_languages base; </xsl:text>
|
||||
<xsl:text> struct usb_st_string_language_map map[</xsl:text>
|
||||
<xsl:value-of select="$num_lang - 1"/>
|
||||
<xsl:text>]; } </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>, &language_descriptor.base</xsl:text>
|
||||
<xsl:text>, {{</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>}}}, { </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>}, </xsl:text>
|
||||
</xsl:for-each>
|
||||
<xsl:text> } }; </xsl:text>
|
||||
<xsl:text>const struct usb_st_string_languages * const string_languages = &string_languages_full.base; </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="output-UCS2">
|
||||
<xsl:param name="string"/>
|
||||
<xsl:if test="string-length($string) > 0">
|
||||
<xsl:text>'</xsl:text>
|
||||
<xsl:value-of select="substring($string, 1,1)"/>
|
||||
<xsl:text>'</xsl:text>
|
||||
<xsl:if test="string-length($string) > 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>
|
||||
|
||||
|
60
cpu/at91sam7s/usb/usb-api.h
Normal file
60
cpu/at91sam7s/usb/usb-api.h
Normal 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__ */
|
16
cpu/at91sam7s/usb/usb-config.h
Normal file
16
cpu/at91sam7s/usb/usb-config.h
Normal 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__ */
|
424
cpu/at91sam7s/usb/usb-handler.c
Normal file
424
cpu/at91sam7s/usb/usb-handler.c
Normal 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;
|
||||
}
|
52
cpu/at91sam7s/usb/usb-interrupt.c
Normal file
52
cpu/at91sam7s/usb/usb-interrupt.c
Normal 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();
|
||||
}
|
7
cpu/at91sam7s/usb/usb-interrupt.h
Normal file
7
cpu/at91sam7s/usb/usb-interrupt.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef __USB_INTERRUPT_H__Z1DQCUBTAL__
|
||||
#define __USB_INTERRUPT_H__Z1DQCUBTAL__
|
||||
|
||||
void
|
||||
usb_int (void);
|
||||
|
||||
#endif /* __USB_INTERRUPT_H__Z1DQCUBTAL__ */
|
600
cpu/at91sam7s/usb/usb-proto.c
Normal file
600
cpu/at91sam7s/usb/usb-proto.c
Normal 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);
|
||||
}
|
118
cpu/at91sam7s/usb/usb-proto.h
Normal file
118
cpu/at91sam7s/usb/usb-proto.h
Normal 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
185
cpu/at91sam7s/usb/usb.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user