URL
https://opencores.org/ocsvn/usb_device_core/usb_device_core/trunk
Subversion Repositories usb_device_core
Compare Revisions
- This comparison shows the changes necessary to convert path
/usb_device_core
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/trunk/sw/usb_defs.h
0,0 → 1,86
#ifndef __USB_DEFS_H__ |
#define __USB_DEFS_H__ |
|
//----------------------------------------------------------------- |
// Macros: |
//----------------------------------------------------------------- |
|
// For Big Endian CPUs |
#define USB_BYTE_SWAP16(n) ((((unsigned short)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8)) |
|
#define LO_BYTE(w) ((unsigned char)(w)) |
#define HI_BYTE(w) ((unsigned char)(((unsigned short)(w) >> 8) & 0xFF)) |
|
#define MIN(a,b) ((a)<=(b)?(a):(b)) |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
|
// Device class |
#define DEV_CLASS_RESERVED 0x00 |
#define DEV_CLASS_AUDIO 0x01 |
#define DEV_CLASS_COMMS 0x02 |
#define DEV_CLASS_HID 0x03 |
#define DEV_CLASS_MONITOR 0x04 |
#define DEV_CLASS_PHY_IF 0x05 |
#define DEV_CLASS_POWER 0x06 |
#define DEV_CLASS_PRINTER 0x07 |
#define DEV_CLASS_STORAGE 0x08 |
#define DEV_CLASS_HUB 0x09 |
#define DEV_CLASS_TMC 0xFE |
#define DEV_CLASS_VENDOR_CUSTOM 0xFF |
|
// Standard requests (via SETUP packets) |
#define REQ_GET_STATUS 0x00 |
#define REQ_CLEAR_FEATURE 0x01 |
#define REQ_SET_FEATURE 0x03 |
#define REQ_SET_ADDRESS 0x05 |
#define REQ_GET_DESCRIPTOR 0x06 |
#define REQ_SET_DESCRIPTOR 0x07 |
#define REQ_GET_CONFIGURATION 0x08 |
#define REQ_SET_CONFIGURATION 0x09 |
#define REQ_GET_INTERFACE 0x0A |
#define REQ_SET_INTERFACE 0x0B |
#define REQ_SYNC_FRAME 0x0C |
|
// Descriptor types |
#define DESC_DEVICE 0x01 |
#define DESC_CONFIGURATION 0x02 |
#define DESC_STRING 0x03 |
#define DESC_INTERFACE 0x04 |
#define DESC_ENDPOINT 0x05 |
#define DESC_DEV_QUALIFIER 0x06 |
#define DESC_OTHER_SPEED_CONF 0x07 |
#define DESC_IF_POWER 0x08 |
|
// Endpoints |
#define ENDPOINT_DIR_MASK (1 << 7) |
#define ENDPOINT_DIR_IN (1 << 7) |
#define ENDPOINT_DIR_OUT (0 << 7) |
#define ENDPOINT_ADDR_MASK (0x7F) |
#define ENDPOINT_TYPE_MASK (0x3) |
#define ENDPOINT_TYPE_CONTROL (0) |
#define ENDPOINT_TYPE_ISO (1) |
#define ENDPOINT_TYPE_BULK (2) |
#define ENDPOINT_TYPE_INTERRUPT (3) |
|
// Device Requests (bmRequestType) |
#define USB_RECIPIENT_MASK 0x1F |
#define USB_RECIPIENT_DEVICE 0x00 |
#define USB_RECIPIENT_INTERFACE 0x01 |
#define USB_RECIPIENT_ENDPOINT 0x02 |
#define USB_REQUEST_TYPE_MASK 0x60 |
#define USB_STANDARD_REQUEST 0x00 |
#define USB_CLASS_REQUEST 0x20 |
#define USB_VENDOR_REQUEST 0x40 |
|
// USB device addresses are 7-bits |
#define USB_ADDRESS_MASK 0x7F |
|
// USB Feature Selectors |
#define USB_FEATURE_ENDPOINT_STATE 0x0000 |
#define USB_FEATURE_REMOTE_WAKEUP 0x0001 |
#define USB_FEATURE_TEST_MODE 0x0002 |
|
#endif |
/trunk/sw/usb_log.h
0,0 → 1,28
#ifndef __USB_LOG_H__ |
#define __USB_LOG_H__ |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define USBLOG_HW_RESET 1 |
#define USBLOG_HW_CTRL 9 |
#define USBLOG_HW_DATA 7 |
#define USBLOG_CONTROL 9 |
#define USBLOG_SETUP_DATA 9 |
#define USBLOG_SETUP 8 |
#define USBLOG_SETUP_OUT 8 |
#define USBLOG_SETUP_IN 8 |
#define USBLOG_SETUP_IN_DBG 11 |
#define USBLOG_DESC 7 |
#define USBLOG_DESC_WARN 1 |
#define USBLOG_INFO 8 |
#define USBLOG_ERR 0 |
#define USBLOG_CDC_INFO 7 |
#define USBLOG_DFU_INFO 7 |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
static int log_printf(int level, const char* ctrl1, ... ) { return 0; } |
|
#endif |
/trunk/sw/usb_desc_cdc.c
0,0 → 1,257
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <string.h> |
#include <stdlib.h> |
#include "usb_defs.h" |
#include "usb_desc.h" |
#include "usb_log.h" |
|
//----------------------------------------------------------------- |
// PID/VID: |
//----------------------------------------------------------------- |
#ifndef USB_DEV_VID |
#define USB_DEV_VID 0x1234 |
#endif |
#ifndef USB_DEV_PID |
#define USB_DEV_PID 0x5678 |
#endif |
#define USB_DEV_VER 0x0101 |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
|
// Descriptor defs |
#define SIZE_OF_DEVICE_DESCR 18 |
#define EP0_MAX_PACKET_SIZE 8 |
|
// Configuration descriptor |
#define NB_INTERFACE 2 |
#define CONF_NB 1 |
#define CONF_INDEX 0 |
#define CONF_ATTRIBUTES 0x80 // Bit7 bus-powered Bit6 self-powered |
#define MAX_POWER 50 // Bus current = 100 mA |
|
// Interface 0 descriptor |
#define INTERFACE0_ID 0 |
#define ALTERNATE0 0 |
#define NB_ENDPOINT0 1 |
#define INTERFACE0_CLASS 0x02 |
#define INTERFACE0_SUB_CLASS 0x02 |
#define INTERFACE0_PROTOCOL 0x01 |
#define INTERFACE0_INDEX 0 |
|
// Endpoint 3 descriptor (INTR-IN) |
#define ENDPOINT_ID_3 0x83 |
#define EP_ATTRIBUTES_3 0x03 |
#define EP_SIZE_3 64 |
#define EP_INTERVAL_3 2 |
|
// Interface 1 descriptor |
#define INTERFACE1_ID 1 |
#define ALTERNATE1 0 |
#define NB_ENDPOINT1 2 |
#define INTERFACE1_CLASS 0x0A |
#define INTERFACE1_SUB_CLASS 0 |
#define INTERFACE1_PROTOCOL 0 |
#define INTERFACE1_INDEX 0 |
|
// Endpoint 1 descriptor |
#define ENDPOINT_ID_1 0x01 |
#define EP_ATTRIBUTES_1 0x02 |
#define EP_SIZE_1 64 |
#define EP_INTERVAL_1 0x00 |
|
// Endpoint 2 descriptor |
#define ENDPOINT_ID_2 0x82 |
#define EP_ATTRIBUTES_2 0x02 |
#define EP_SIZE_2 64 |
#define EP_INTERVAL_2 0x00 |
|
// String Descriptors |
#define UNICODE_LANGUAGE_STR_ID 0 |
#define MANUFACTURER_STR_ID 1 |
#define PRODUCT_NAME_STR_ID 2 |
#define SERIAL_NUM_STR_ID 3 |
#define UNICODE_ENGLISH 0x0409 |
|
//----------------------------------------------------------------- |
// Descriptors: |
//----------------------------------------------------------------- |
static const unsigned char _device_desc[18] = |
{ |
SIZE_OF_DEVICE_DESCR, // Descriptor size (18) |
DESC_DEVICE, // Descriptor type |
LO_BYTE(0x0200), // bcdUSB = 02.00 (BCD word) |
HI_BYTE(0x0200), |
DEV_CLASS_COMMS, // Device class |
0x00, // Device subclass |
0x00, // Device protocol |
EP0_MAX_PACKET_SIZE, // Max packet size for EP0 |
LO_BYTE(USB_DEV_VID), |
HI_BYTE(USB_DEV_VID), |
LO_BYTE(USB_DEV_PID), |
HI_BYTE(USB_DEV_PID), |
LO_BYTE(USB_DEV_VER), |
HI_BYTE(USB_DEV_VER), |
0, // MANUFACTURER_STR_ID, // manufacturer string index |
0, // PRODUCT_NAME_STR_ID, // product string index |
0, // SERIAL_NUM_STR_ID, // serial number string index |
1 // number of configurations |
}; |
|
static const unsigned char _config_desc[67] = |
{ |
/* Config. descriptor (short) */ |
9, DESC_CONFIGURATION, |
LO_BYTE( sizeof(_config_desc) ), HI_BYTE( sizeof(_config_desc) ), |
NB_INTERFACE, CONF_NB, CONF_INDEX, CONF_ATTRIBUTES, MAX_POWER, |
|
/* Interface #0 descriptor */ |
9, DESC_INTERFACE, INTERFACE0_ID, ALTERNATE0, NB_ENDPOINT0, |
INTERFACE0_CLASS, INTERFACE0_SUB_CLASS, INTERFACE0_PROTOCOL, INTERFACE0_INDEX, |
|
/* CDC-specific Functional Descriptors (type = 0x24) - Ref. USBCDC Spec. $5.2.3 */ |
0x05, 0x24, 0x00, 0x10, 0x01, // CDC-specific header |
0x05, 0x24, 0x01, 0x03, 0x01, // Call Management descriptor |
0x04, 0x24, 0x02, 0x06, // Abstract Control Management descriptor |
0x05, 0x24, 0x06, 0x00, 0x01, // Union functional descriptor |
|
/* Endpoint descriptor #3 */ |
7, DESC_ENDPOINT, ENDPOINT_ID_3, EP_ATTRIBUTES_3, |
LO_BYTE(EP_SIZE_3), HI_BYTE(EP_SIZE_3), EP_INTERVAL_3, |
|
/* Interface #1 descriptor */ |
9, DESC_INTERFACE, INTERFACE1_ID, ALTERNATE1, NB_ENDPOINT1, |
INTERFACE1_CLASS, INTERFACE1_SUB_CLASS, INTERFACE1_PROTOCOL, INTERFACE1_INDEX, |
|
/* Endpoint descriptor #1 */ |
7, DESC_ENDPOINT, ENDPOINT_ID_1, EP_ATTRIBUTES_1, |
LO_BYTE(EP_SIZE_1), HI_BYTE(EP_SIZE_1), EP_INTERVAL_1, |
|
/* Endpoint descriptor #2 */ |
7, DESC_ENDPOINT, ENDPOINT_ID_2, EP_ATTRIBUTES_2, |
LO_BYTE(EP_SIZE_2), HI_BYTE(EP_SIZE_2), EP_INTERVAL_2 |
}; |
|
static const unsigned char _string_desc_lang[] = |
{ |
(4), // Descriptor size |
DESC_STRING, |
LO_BYTE( UNICODE_ENGLISH ), |
HI_BYTE( UNICODE_ENGLISH ), |
}; |
|
static const unsigned char _string_desc_man[] = |
{ |
(2 + 28), |
DESC_STRING, |
'U',0,'L',0,'T',0,'R',0,'A',0,'-',0,'E',0,'M',0,'B',0,'E',0,'D',0,'D',0,'E',0,'D',0 |
}; |
|
static const unsigned char _string_desc_prod[] = |
{ |
(2 + 28), |
DESC_STRING, |
'U',0,'S',0,'B',0,' ',0,'D',0,'E',0,'M',0,'O',0,' ',0,' ',0,' ',0,' ',0,' ',0,' ',0 |
}; |
|
static const unsigned char _string_desc_serial[] = |
{ |
(2 + 12), |
DESC_STRING, |
'0',0,'0',0,'0',0,'0',0,'0',0,'0',0 |
}; |
|
//----------------------------------------------------------------- |
// usb_get_descriptor: |
//----------------------------------------------------------------- |
unsigned char *usb_get_descriptor( unsigned char bDescriptorType, unsigned char bDescriptorIndex, unsigned short wLength, unsigned char *pSize ) |
{ |
if ( bDescriptorType == DESC_DEVICE ) |
{ |
*pSize = MIN( wLength, SIZE_OF_DEVICE_DESCR ); |
log_printf(USBLOG_DESC, "USB: Get device descriptor %d\n", *pSize); |
|
return (unsigned char *)_device_desc; |
} |
else if ( bDescriptorType == DESC_CONFIGURATION ) |
{ |
*pSize = MIN( sizeof(_config_desc), wLength ); |
log_printf(USBLOG_DESC, "USB: Get conf descriptor %d\n", *pSize); |
|
return (unsigned char *)_config_desc; |
} |
else if ( bDescriptorType == DESC_STRING ) |
{ |
log_printf(USBLOG_DESC, "USB: Get string descriptor %x\n", bDescriptorIndex); |
|
switch( bDescriptorIndex ) |
{ |
case UNICODE_LANGUAGE_STR_ID: |
*pSize = MIN( sizeof(_string_desc_lang), wLength ); |
return (unsigned char *)_string_desc_lang; |
|
case MANUFACTURER_STR_ID: |
*pSize = MIN( sizeof(_string_desc_man), wLength ); |
return (unsigned char *)_string_desc_man; |
|
case PRODUCT_NAME_STR_ID: |
*pSize = MIN( sizeof(_string_desc_prod), wLength ); |
return (unsigned char *)_string_desc_prod; |
|
case SERIAL_NUM_STR_ID: |
*pSize = MIN( sizeof(_string_desc_serial), wLength ); |
return (unsigned char *)_string_desc_serial; |
|
default: |
log_printf(USBLOG_DESC_WARN, "USB: Unknown descriptor index %x, STALL\n", bDescriptorIndex); |
return NULL; |
} |
} |
else |
{ |
log_printf(USBLOG_DESC_WARN, "USB: Unknown descriptor type %x, STALL\n", bDescriptorType); |
return NULL; |
} |
} |
//----------------------------------------------------------------- |
// usb_is_bus_powered: |
//----------------------------------------------------------------- |
int usb_is_bus_powered(void) |
{ |
return (CONF_ATTRIBUTES & 0x80) ? 1 : 0; |
} |
/trunk/sw/hardware.h
0,0 → 1,17
#ifndef __HARDWARE_H__ |
#define __HARDWARE_H__ |
|
// NOTE: Update to match actual addresses in your system! |
|
#ifndef TIMER_HW_VAL |
// TODO: Update to match address of timer peripheral |
// Expected to return time in ms |
#define TIMER_HW_VAL (*((volatile unsigned int*) (0x12000100))) |
#endif |
|
#ifndef USB_FUNC_BASE |
// TODO: Update to match address of USB device core |
#define USB_FUNC_BASE 0x13000000 |
#endif |
|
#endif |
/trunk/sw/usb_cdc.c
0,0 → 1,150
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <string.h> |
#include <stdlib.h> |
#include "usb_defs.h" |
#include "usb_cdc.h" |
#include "usb_log.h" |
#include "usb_device.h" |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static unsigned char _line_coding[7]; |
|
//----------------------------------------------------------------- |
// cdc_set_line_coding: |
//----------------------------------------------------------------- |
static void cdc_set_line_coding(unsigned char *data) |
{ |
int i; |
|
for (i=0; i<7; i++) |
_line_coding[i] = data[i]; |
|
log_printf(USBLOG_CDC_INFO, "CDC: Set Line Coding\n"); |
} |
//----------------------------------------------------------------- |
// cdc_get_line_coding: |
//----------------------------------------------------------------- |
static void cdc_get_line_coding(void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Get Line Coding\n"); |
|
usb_control_send( _line_coding, sizeof(_line_coding) ); |
} |
//----------------------------------------------------------------- |
// cdc_set_control_line_state: |
//----------------------------------------------------------------- |
static void cdc_set_control_line_state(void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Set Control Line State\n"); |
usbhw_control_endpoint_ack(); |
} |
//----------------------------------------------------------------- |
// cdc_send_break: |
//----------------------------------------------------------------- |
static void cdc_send_break(void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Send Break\n"); |
usbhw_control_endpoint_ack(); |
} |
//----------------------------------------------------------------- |
// cdc_send_encapsulated_command: |
//----------------------------------------------------------------- |
static void cdc_send_encapsulated_command (void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Send encap\n"); |
} |
//----------------------------------------------------------------- |
// cdc_get_encapsulated_response: |
//----------------------------------------------------------------- |
static void cdc_get_encapsulated_response (void) |
{ |
log_printf(USBLOG_CDC_INFO, "CDC: Get encap\n"); |
|
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// cdc_process_request: |
//----------------------------------------------------------------- |
void cdc_process_request(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength) |
{ |
switch ( req ) |
{ |
case CDC_SEND_ENCAPSULATED_COMMAND: |
log_printf(USBLOG_CDC_INFO, "CDC: Send encap\n"); |
cdc_send_encapsulated_command(); |
break; |
case CDC_GET_ENCAPSULATED_RESPONSE: |
log_printf(USBLOG_CDC_INFO, "CDC: Get encap\n"); |
cdc_get_encapsulated_response(); |
break; |
case CDC_SET_LINE_CODING: |
log_printf(USBLOG_CDC_INFO, "CDC: Set line coding\n"); |
cdc_set_line_coding(data); |
break; |
case CDC_GET_LINE_CODING: |
log_printf(USBLOG_CDC_INFO, "CDC: Get line coding\n"); |
cdc_get_line_coding(); |
break; |
case CDC_SET_CONTROL_LINE_STATE: |
log_printf(USBLOG_CDC_INFO, "CDC: Set line state\n"); |
cdc_set_control_line_state(); |
break; |
case CDC_SEND_BREAK: |
log_printf(USBLOG_CDC_INFO, "CDC: Send break\n"); |
cdc_send_break(); |
break; |
default: |
log_printf(USBLOG_CDC_INFO, "CDC: Unknown command\n"); |
usbhw_control_endpoint_stall(); |
break; |
} |
} |
//----------------------------------------------------------------- |
// cdc_init: |
//----------------------------------------------------------------- |
void cdc_init(void) |
{ |
_line_coding[0] = 0x00; // UART baud rate (32-bit word, LSB first) |
_line_coding[1] = 0xC2; |
_line_coding[2] = 0x01; |
_line_coding[3] = 0x00; |
_line_coding[4] = 0; // stop bit #2 |
_line_coding[5] = 0; // parity |
_line_coding[6] = 8; // data bits |
} |
/trunk/sw/main.c
0,0 → 1,67
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <stdio.h> |
#include "usb_uart.h" |
#include "usb_cdc.h" |
#include "usb_hw.h" |
#include "timer.h" |
|
//----------------------------------------------------------------- |
// CDC serial demo |
//----------------------------------------------------------------- |
int main(void) |
{ |
// Force detach |
usbhw_attach(0); |
timer_sleep(100); |
|
// USB init |
usb_init(0, cdc_process_request); |
usb_uart_init(); |
|
usbhw_attach(1); |
|
while (1) |
{ |
usbhw_service(); |
|
// Loopback |
if (usb_uart_haschar()) |
usb_uart_putchar(usb_uart_getchar()); |
} |
|
return 0; |
} |
/trunk/sw/usb_uart.c
0,0 → 1,188
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include "usb_hw.h" |
#include "usb_cdc.h" |
#include "usb_device.h" |
#include "usb_uart.h" |
#include "usb_log.h" |
#include "timer.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define USB_UART_TX_TIMEOUT 100 |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static int _tx_count; |
static int _rx_count; |
|
//----------------------------------------------------------------- |
// usb_uart_init: |
//----------------------------------------------------------------- |
void usb_uart_init(void) |
{ |
_tx_count = 0; |
_rx_count = 0; |
|
cdc_init(); |
} |
//----------------------------------------------------------------- |
// usb_uart_haschar: |
//----------------------------------------------------------------- |
int usb_uart_haschar(void) |
{ |
if (_rx_count == 0) |
{ |
if (usbhw_is_rx_ready(CDC_ENDPOINT_BULK_OUT)) |
{ |
_rx_count = usbhw_get_rx_count(CDC_ENDPOINT_BULK_OUT); |
|
// ZLP received? Clear rx status |
if (_rx_count == 0) |
usbhw_clear_rx_ready(CDC_ENDPOINT_BULK_OUT); |
} |
} |
return (_rx_count != 0); |
} |
//----------------------------------------------------------------- |
// usb_uart_getchar: |
//----------------------------------------------------------------- |
int usb_uart_getchar(void) |
{ |
int data = -1; |
|
// Some data is ready? |
if (usb_uart_haschar()) |
{ |
// Get a byte |
data = (int)usbhw_get_rx_byte(CDC_ENDPOINT_BULK_OUT); |
_rx_count--; |
|
// All data received, clear rx status |
if (_rx_count == 0) |
usbhw_clear_rx_ready(CDC_ENDPOINT_BULK_OUT); |
} |
|
return data; |
} |
//----------------------------------------------------------------- |
// usb_uart_getblock: |
//----------------------------------------------------------------- |
int usb_uart_getblock(unsigned char *data, int max_length) |
{ |
int count; |
|
// Block until some data is ready |
while (!usb_uart_haschar()) |
; |
|
// Limit to buffer size or amount ready |
if (_rx_count > max_length) |
count = max_length; |
else |
count = _rx_count; |
|
usbhw_get_rx_data(CDC_ENDPOINT_BULK_OUT, data, count); |
_rx_count -= count; |
|
// All data received, clear rx status |
if (_rx_count == 0) |
usbhw_clear_rx_ready(CDC_ENDPOINT_BULK_OUT); |
|
return count; |
} |
//----------------------------------------------------------------- |
// usb_uart_putchar: |
//----------------------------------------------------------------- |
int usb_uart_putchar(char data) |
{ |
if (data == '\n') |
usb_uart_putchar('\r'); |
|
// Wait until space available (or timeout) |
t_time tS = timer_now(); |
while (!usbhw_has_tx_space(CDC_ENDPOINT_BULK_IN)) |
{ |
if (timer_diff(timer_now(), tS) > USB_UART_TX_TIMEOUT) |
return 0; |
} |
|
// Load byte into tx buffer |
usbhw_write_tx_byte(CDC_ENDPOINT_BULK_IN, data); |
_tx_count++; |
|
// Flush on buffer full or end of line |
if ( _tx_count >= EP2_MAX_PACKET_SIZE || data == '\n') |
usb_uart_flush(); |
|
return (int)data; |
} |
//----------------------------------------------------------------- |
// usb_uart_flush: |
//----------------------------------------------------------------- |
void usb_uart_flush(void) |
{ |
// If some data present in output buffer |
if (_tx_count) |
{ |
// Enable tx to start on next IN transfer |
usbhw_start_tx(CDC_ENDPOINT_BULK_IN); |
|
// If multiple of endpoint size, send ZLP |
if ( _tx_count == EP2_MAX_PACKET_SIZE ) |
{ |
t_time tS = timer_now(); |
|
// Wait for TX ready and then send ZLP |
while (!usbhw_has_tx_space(CDC_ENDPOINT_BULK_IN)) |
{ |
if (timer_diff(timer_now(), tS) > USB_UART_TX_TIMEOUT) |
{ |
log_printf(USBLOG_ERR, "UART: Flush timeout\n"); |
return ; |
} |
} |
|
usbhw_load_tx_buffer(CDC_ENDPOINT_BULK_IN, 0, 0); |
} |
|
_tx_count = 0; |
} |
} |
/trunk/sw/timer.h
0,0 → 1,24
#ifndef __TIMER_H__ |
#define __TIMER_H__ |
|
#include "hardware.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
typedef unsigned long t_time; |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
static t_time timer_now(void) { return TIMER_HW_VAL; } |
static long timer_diff(t_time a, t_time b) { return (long)(a - b); } |
static void timer_sleep(int timeMs) |
{ |
t_time t = timer_now(); |
|
while (timer_diff(timer_now(), t) < timeMs) |
; |
} |
|
#endif |
/trunk/sw/usb_cdc.h
0,0 → 1,24
#ifndef __USB_CDC_H__ |
#define __USB_CDC_H__ |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define CDC_ENDPOINT_BULK_OUT 1 |
#define CDC_ENDPOINT_BULK_IN 2 |
#define CDC_ENDPOINT_INTR_IN 3 |
|
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 |
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 |
#define CDC_GET_LINE_CODING 0x21 |
#define CDC_SET_LINE_CODING 0x20 |
#define CDC_SET_CONTROL_LINE_STATE 0x22 |
#define CDC_SEND_BREAK 0x23 |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
void cdc_init( void ); |
void cdc_process_request(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength); |
|
#endif |
/trunk/sw/usb_hw.c
0,0 → 1,376
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include "usb_hw.h" |
#include "usb_log.h" |
#include "hardware.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define USB_FUNC_CTRL (*((volatile unsigned int*) (USB_FUNC_BASE + 0x00))) |
#define USB_FUNC_CTRL_ADDR_SET (1 << 8) |
#define USB_FUNC_CTRL_ADDR_MASK (0x7F) |
#define USB_FUNC_CTRL_ADDR_SHIFT 0 |
#define USB_FUNC_CTRL_INT_EN_TX (1 << 9) |
#define USB_FUNC_CTRL_INT_EN_RX (1 << 10) |
#define USB_FUNC_CTRL_INT_EN_SOF (1 << 11) |
#define USB_FUNC_CTRL_PULLUP_EN (1 << 12) |
#define USB_FUNC_STAT (*((volatile unsigned int*) (USB_FUNC_BASE + 0x00))) |
#define USB_STAT_BUS_RST (1 << 18) |
#define USB_LINESTATE_RXN (1 << 17) |
#define USB_LINESTATE_RXP (1 << 16) |
#define USB_FUNC_FRAME_COUNT 0x07FF |
|
#define USB_FUNC_EP(x) (*((volatile unsigned int*) (USB_FUNC_BASE + 0x04 + (4 * x)))) |
#define USB_FUNC_EP0 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x04))) |
#define USB_FUNC_EP1 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x08))) |
#define USB_FUNC_EP2 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x0C))) |
#define USB_FUNC_EP3 (*((volatile unsigned int*) (USB_FUNC_BASE + 0x10))) |
#define USB_EP_TX_READY (1 << 16) |
#define USB_EP_COUNT_MASK 0xFFFF |
#define USB_EP_RX_AVAIL (1 << 17) |
#define USB_EP_RX_SETUP (1 << 18) |
#define USB_EP_RX_ACK (1 << 18) |
#define USB_EP_RX_CRC_ERR (1 << 19) |
#define USB_EP_STALL (1 << 20) |
#define USB_EP_TX_FLUSH (1 << 21) |
|
#define USB_FUNC_EP_DATA(x) (*((volatile unsigned int*) (USB_FUNC_BASE + 0x20 + (4 * x)))) |
#define USB_FUNC_EP0_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x20))) |
#define USB_FUNC_EP1_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x24))) |
#define USB_FUNC_EP2_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x28))) |
#define USB_FUNC_EP3_DATA (*((volatile unsigned int*) (USB_FUNC_BASE + 0x2C))) |
|
#define USB_FUNC_ENDPOINTS 4 |
|
#define MIN(a,b) ((a)<=(b)?(a):(b)) |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static unsigned int _tx_count[USB_FUNC_ENDPOINTS]; |
static int _configured; |
static int _attached; |
static int _endpoint_stalled[USB_FUNC_ENDPOINTS]; |
static FUNC_PTR _func_bus_reset; |
static FUNC_PTR _func_setup; |
static FUNC_PTR _func_ctrl_out; |
static unsigned int _pullup_enable; |
static unsigned int _ctrl_reg; |
|
//----------------------------------------------------------------- |
// usbhw_init: |
//----------------------------------------------------------------- |
void usbhw_init(FUNC_PTR bus_reset, FUNC_PTR on_setup, FUNC_PTR on_out) |
{ |
int i; |
|
for (i=0;i<USB_FUNC_ENDPOINTS;i++) |
{ |
_tx_count[i] = 0; |
_endpoint_stalled[i] = 0; |
} |
|
_configured = 0; |
_attached = 0; |
|
_ctrl_reg = 0; |
|
_func_bus_reset = bus_reset; |
_func_setup = on_setup; |
_func_ctrl_out = on_out; |
|
USB_FUNC_EP0 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
USB_FUNC_EP1 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
USB_FUNC_EP2 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
USB_FUNC_EP3 = USB_EP_RX_ACK | USB_EP_TX_FLUSH; |
} |
//----------------------------------------------------------------- |
// usbhw_service: |
//----------------------------------------------------------------- |
void usbhw_service(void) |
{ |
unsigned int status; |
|
// Bus reset event |
if (USB_FUNC_STAT & USB_STAT_BUS_RST) |
{ |
// Ack bus reset by writing to CTRL register |
USB_FUNC_CTRL = _ctrl_reg; |
|
_configured = 0; |
|
log_printf(USBLOG_HW_RESET, " DEVICE: BUS RESET\n"); |
|
if (_func_bus_reset) |
_func_bus_reset(); |
} |
|
status = USB_FUNC_EP0; |
|
// SETUP packet received (EP0) |
if (status & USB_EP_RX_SETUP) |
{ |
log_printf(USBLOG_HW_CTRL, "USB: SETUP packet received\n"); |
|
if (_func_setup) |
_func_setup(); |
|
log_printf(USBLOG_HW_CTRL, "USB: SETUP packet processed\n"); |
} |
// OUT data received on EP0 |
else if (status & USB_EP_RX_AVAIL) |
{ |
log_printf(USBLOG_HW_CTRL, "USB: OUT packet received on EP0\n"); |
|
if (_func_ctrl_out) |
_func_ctrl_out(); |
} |
} |
//----------------------------------------------------------------- |
// usbhw_attach: |
//----------------------------------------------------------------- |
void usbhw_attach(int state) |
{ |
// Pull up D+ to Vdd |
if ( state ) |
{ |
log_printf(USBLOG_HW_CTRL, " DEVICE: ATTACH\n"); |
_attached = 1; |
_ctrl_reg |= USB_FUNC_CTRL_PULLUP_EN; |
USB_FUNC_CTRL = _ctrl_reg; |
} |
// Disconnect pull-up to disconnect from bus |
else |
{ |
log_printf(USBLOG_HW_CTRL, " DEVICE: DETACH\n"); |
_attached = 0; |
_ctrl_reg &= ~USB_FUNC_CTRL_PULLUP_EN; |
USB_FUNC_CTRL = _ctrl_reg; |
} |
} |
//----------------------------------------------------------------- |
// usbhw_is_configured: |
//----------------------------------------------------------------- |
int usbhw_is_configured(void) |
{ |
return _configured; |
} |
//----------------------------------------------------------------- |
// usbhw_is_attached: |
//----------------------------------------------------------------- |
int usbhw_is_attached(void) |
{ |
return _attached; |
} |
//----------------------------------------------------------------- |
// usbhw_set_configured: |
//----------------------------------------------------------------- |
void usbhw_set_configured(int configured) |
{ |
_configured = configured; |
} |
//----------------------------------------------------------------- |
// usbhw_set_address: |
//----------------------------------------------------------------- |
void usbhw_set_address(unsigned char addr) |
{ |
USB_FUNC_CTRL = (_attached ? USB_FUNC_CTRL_PULLUP_EN : 0) | |
USB_FUNC_CTRL_ADDR_SET | ((addr & USB_FUNC_CTRL_ADDR_MASK) >> USB_FUNC_CTRL_ADDR_SHIFT); |
} |
//----------------------------------------------------------------- |
// usbhw_is_endpoint_stalled: |
//----------------------------------------------------------------- |
int usbhw_is_endpoint_stalled(unsigned char endpoint) |
{ |
return _endpoint_stalled[endpoint]; |
} |
//----------------------------------------------------------------- |
// usbhw_clear_endpoint_stall: |
//----------------------------------------------------------------- |
void usbhw_clear_endpoint_stall(unsigned char endpoint) |
{ |
_endpoint_stalled[endpoint] = 0; |
USB_FUNC_EP(endpoint) = 0; |
} |
//----------------------------------------------------------------- |
// usbhw_set_endpoint_stall: |
//----------------------------------------------------------------- |
void usbhw_set_endpoint_stall(unsigned char endpoint) |
{ |
_endpoint_stalled[endpoint] = 1; |
USB_FUNC_EP(endpoint) = USB_EP_STALL; |
} |
//----------------------------------------------------------------- |
// usbhw_is_rx_ready: Is some receive data ready on an endpoint? |
//----------------------------------------------------------------- |
int usbhw_is_rx_ready(unsigned char endpoint) |
{ |
return (USB_FUNC_EP(endpoint) & USB_EP_RX_AVAIL) ? 1 : 0; |
} |
//----------------------------------------------------------------- |
// usbhw_get_rx_count: Get amount of data waiting in endpoint |
//----------------------------------------------------------------- |
int usbhw_get_rx_count(unsigned char bEndp) |
{ |
int count = USB_FUNC_EP(bEndp) & USB_EP_COUNT_MASK; |
|
// Received data count includes CRC |
if (count >= 2) |
return count - 2; |
else |
return 0; |
} |
//----------------------------------------------------------------- |
// usbhw_get_rx_data: Read data from endpoint & clear full flag |
//----------------------------------------------------------------- |
int usbhw_get_rx_data(unsigned char endpoint, unsigned char *data, int max_len) |
{ |
int i; |
int bytes_ready; |
int bytes_read = 0; |
|
// Received data count includes CRC |
bytes_ready = USB_FUNC_EP(endpoint) & USB_EP_COUNT_MASK; |
if (bytes_ready >= 2) |
bytes_ready -= 2; |
|
// Limit data read to buffer size |
bytes_read = MIN(bytes_ready, max_len); |
|
for (i=0;i<bytes_read;i++) |
{ |
*data++ = (unsigned char) USB_FUNC_EP_DATA(endpoint); |
} |
|
// Allow more data to be received |
usbhw_clear_rx_ready( endpoint ); |
|
// Return number of bytes read |
return bytes_read; |
} |
//----------------------------------------------------------------- |
// usbhw_get_rx_byte: Read byte from endpoint |
//----------------------------------------------------------------- |
unsigned char usbhw_get_rx_byte(unsigned char endpoint) |
{ |
return (unsigned char)USB_FUNC_EP_DATA(endpoint); |
} |
//----------------------------------------------------------------- |
// usbhw_clear_rx_ready: Clear Rx data ready flag |
//----------------------------------------------------------------- |
void usbhw_clear_rx_ready(unsigned char endpoint) |
{ |
log_printf(USBLOG_HW_DATA, "USB: Clear endpoint buffer (Rx %d)\n", USB_FUNC_EP(endpoint) & USB_EP_COUNT_MASK); |
USB_FUNC_EP(endpoint) = USB_EP_RX_ACK; |
} |
//----------------------------------------------------------------- |
// usbhw_has_tx_space: Is there space in the tx buffer |
//----------------------------------------------------------------- |
int usbhw_has_tx_space(unsigned char endpoint) |
{ |
return (USB_FUNC_EP(endpoint) & USB_EP_TX_READY) ? 0 : 1; |
} |
//----------------------------------------------------------------- |
// usbhw_load_tx_buffer: Load tx buffer & start transfer (non-blocking) |
//----------------------------------------------------------------- |
int usbhw_load_tx_buffer(unsigned char endpoint, unsigned char *data, int count) |
{ |
int i; |
|
for (i=0;i<count;i++) |
USB_FUNC_EP_DATA(endpoint) = *data++; |
|
// Start transmit |
USB_FUNC_EP(endpoint) = USB_EP_TX_READY | count; |
|
log_printf(USBLOG_HW_DATA, " USB: Tx %d\n", count); |
|
return count; |
} |
//----------------------------------------------------------------- |
// usbhw_write_tx_byte: Write a byte to Tx buffer (don't send yet) |
//----------------------------------------------------------------- |
void usbhw_write_tx_byte(unsigned char endpoint, unsigned char data) |
{ |
// If FIFO should be empty |
if (_tx_count[endpoint] == 0 && |
!(USB_FUNC_EP(endpoint) & USB_EP_TX_READY)) |
{ |
// (Shouldn't need this) Flush Tx FIFO |
USB_FUNC_EP(endpoint) = USB_EP_TX_FLUSH; |
} |
|
USB_FUNC_EP_DATA(endpoint) = (unsigned int) data; |
_tx_count[endpoint]++; |
} |
//----------------------------------------------------------------- |
// usbhw_start_tx: Start a tx packet with data loaded into endpoint |
//----------------------------------------------------------------- |
void usbhw_start_tx(unsigned char endpoint) |
{ |
// Initiate TX |
USB_FUNC_EP(endpoint) = USB_EP_TX_READY | _tx_count[endpoint]; |
log_printf(USBLOG_HW_DATA, " USB: Tx %d\n", _tx_count[endpoint]); |
|
_tx_count[endpoint] = 0; |
} |
//----------------------------------------------------------------- |
// usbhw_control_endpoint_stall: |
//----------------------------------------------------------------- |
void usbhw_control_endpoint_stall(void) |
{ |
log_printf(USBLOG_HW_CTRL, " DEVICE: Error, send EP stall!\n"); |
USB_FUNC_EP0 = USB_EP_STALL; |
} |
//----------------------------------------------------------------- |
// usbhw_control_endpoint_ack: |
//----------------------------------------------------------------- |
void usbhw_control_endpoint_ack(void) |
{ |
USB_FUNC_EP0 = USB_EP_TX_READY; |
log_printf(USBLOG_HW_DATA, " USB: Tx [ZLP/ACK]\n"); |
|
while (!usbhw_has_tx_space(0)) |
; |
} |
//----------------------------------------------------------------- |
// usbhw_get_frame_number: |
//----------------------------------------------------------------- |
unsigned short usbhw_get_frame_number(void) |
{ |
return (unsigned short)(USB_FUNC_STAT & USB_FUNC_FRAME_COUNT); |
} |
/trunk/sw/usb_device.c
0,0 → 1,547
//----------------------------------------------------------------- |
// USB Device Core |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2014 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2013 - 2014 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#include <string.h> |
#include "usb_device.h" |
#include "usb_desc.h" |
#include "usb_log.h" |
#include "usb_defs.h" |
#include "usb_hw.h" |
#include "timer.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define USB_CTRL_TX_TIMEOUT 100 |
|
#ifndef MAX_CTRL_DATA_LENGTH |
#define MAX_CTRL_DATA_LENGTH 64 |
#endif |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
|
// SETUP packet data format |
struct device_request |
{ |
unsigned char bmRequestType; |
unsigned char bRequest; |
unsigned short wValue; |
unsigned short wIndex; |
unsigned short wLength; |
}; |
|
struct control_transfer |
{ |
// SETUP packet |
struct device_request request; |
|
// Data (OUT) stage expected? |
int data_expected; |
|
// Data buffer |
unsigned char data_buffer[MAX_CTRL_DATA_LENGTH]; |
|
// Data received index |
int data_idx; |
}; |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static struct control_transfer _ctrl_xfer; |
static int _remote_wake_enabled; |
static FP_CLASS_REQUEST _class_request; |
|
//----------------------------------------------------------------- |
// get_status: |
//----------------------------------------------------------------- |
static void get_status(struct device_request *request) |
{ |
unsigned char bRecipient = request->bmRequestType & USB_RECIPIENT_MASK; |
unsigned char data[2] = {0, 0}; |
|
log_printf(USBLOG_INFO, "USB: Get Status %x\n", bRecipient); |
|
if ( bRecipient == USB_RECIPIENT_DEVICE ) |
{ |
// Self-powered |
if (!usb_is_bus_powered()) |
data[0] |= (1 << 0); |
|
// Remote Wake-up enabled |
if (_remote_wake_enabled) |
data[0] |= (1 << 1); |
|
usb_control_send( data, 2 ); |
} |
else if ( bRecipient == USB_RECIPIENT_INTERFACE ) |
{ |
usb_control_send( data, 2 ); |
} |
else if ( bRecipient == USB_RECIPIENT_ENDPOINT ) |
{ |
if (usbhw_is_endpoint_stalled( request->wIndex & ENDPOINT_ADDR_MASK)) |
data[0] = 1; |
usb_control_send( data, 2 ); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// clear_feature: |
//----------------------------------------------------------------- |
static void clear_feature(struct device_request *request) |
{ |
unsigned char bRecipient = request->bmRequestType & USB_RECIPIENT_MASK; |
|
log_printf(USBLOG_INFO, "USB: Clear Feature %x\n", bRecipient); |
|
if ( bRecipient == USB_RECIPIENT_DEVICE ) |
{ |
if ( request->wValue == USB_FEATURE_REMOTE_WAKEUP ) |
{ |
log_printf(USBLOG_INFO, "USB: Disable remote wake\n"); |
_remote_wake_enabled = 0; |
usbhw_control_endpoint_ack(); |
} |
else if ( request->wValue == USB_FEATURE_TEST_MODE ) |
{ |
log_printf(USBLOG_INFO, "USB: Disable test mode\n"); |
usbhw_control_endpoint_ack(); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
else if ( bRecipient == USB_RECIPIENT_ENDPOINT && |
request->wValue == USB_FEATURE_ENDPOINT_STATE ) |
{ |
usbhw_control_endpoint_ack(); |
usbhw_clear_endpoint_stall( request->wIndex & ENDPOINT_ADDR_MASK ); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// set_feature: |
//----------------------------------------------------------------- |
static void set_feature(struct device_request *request) |
{ |
unsigned char bRecipient = request->bmRequestType & USB_RECIPIENT_MASK; |
|
log_printf(USBLOG_INFO, "USB: Set Feature %x\n", bRecipient); |
|
if ( bRecipient == USB_RECIPIENT_DEVICE ) |
{ |
if ( request->wValue == USB_FEATURE_REMOTE_WAKEUP ) |
{ |
log_printf(USBLOG_INFO, "USB: Enable remote wake\n"); |
_remote_wake_enabled = 1; |
usbhw_control_endpoint_ack(); |
} |
else if ( request->wValue == USB_FEATURE_TEST_MODE ) |
{ |
log_printf(USBLOG_INFO, "USB: Enable test mode\n"); |
usbhw_control_endpoint_ack(); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
else if ( bRecipient == USB_RECIPIENT_ENDPOINT && |
request->wValue == USB_FEATURE_ENDPOINT_STATE ) |
{ |
usbhw_control_endpoint_ack(); |
usbhw_set_endpoint_stall(request->wIndex & ENDPOINT_ADDR_MASK); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// set_address: |
//----------------------------------------------------------------- |
static void set_address(struct device_request *request) |
{ |
unsigned char addr = (LO_BYTE(request->wValue)) & USB_ADDRESS_MASK; |
|
usbhw_set_address(addr); |
usbhw_control_endpoint_ack(); |
|
log_printf(USBLOG_INFO, "USB: Set address %x\n", addr); |
} |
//----------------------------------------------------------------- |
// get_descriptor: |
//----------------------------------------------------------------- |
static void get_descriptor(struct device_request *request) |
{ |
unsigned char bDescriptorType = HI_BYTE(request->wValue); |
unsigned char bDescriptorIndex = LO_BYTE( request->wValue ); |
unsigned short wLength = request->wLength; |
unsigned char bCount = 0; |
unsigned char *desc_ptr; |
|
desc_ptr = usb_get_descriptor(bDescriptorType, bDescriptorIndex, wLength, &bCount); |
|
if (desc_ptr) |
usb_control_send(desc_ptr, bCount); |
else |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// get_configuration: |
//----------------------------------------------------------------- |
static void get_configuration(struct device_request *request) |
{ |
unsigned char conf = usbhw_is_configured() ? 1 : 0; |
|
log_printf(USBLOG_INFO, "USB: Get configuration %x\n", conf); |
|
usb_control_send( &conf, 1 ); |
} |
//----------------------------------------------------------------- |
// set_configuration: |
//----------------------------------------------------------------- |
static void set_configuration(struct device_request *request) |
{ |
log_printf(USBLOG_INFO, "USB: set_configuration %x\n", request->wValue); |
|
if ( request->wValue == 0 ) |
{ |
usbhw_control_endpoint_ack(); |
usbhw_set_configured(0); |
} |
// Only support one configuration for now |
else if ( request->wValue == 1 ) |
{ |
usbhw_control_endpoint_ack(); |
usbhw_set_configured(1); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// get_interface: |
//----------------------------------------------------------------- |
static void get_interface(struct device_request *request) |
{ |
log_printf(USBLOG_INFO, "USB: Get interface\n"); |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// set_interface: |
//----------------------------------------------------------------- |
static void set_interface(struct device_request *request) |
{ |
log_printf(USBLOG_INFO, "USB: set_interface %x %x\n", request->wValue, request->wIndex); |
|
if ( request->wValue == 0 && request->wIndex == 0 ) |
usbhw_control_endpoint_ack(); |
else |
usbhw_control_endpoint_stall(); |
} |
|
//----------------------------------------------------------------- |
// usb_process_request: |
//----------------------------------------------------------------- |
static void usb_process_request(struct device_request *request, unsigned char type, unsigned char req, unsigned char *data) |
{ |
if ( type == USB_STANDARD_REQUEST ) |
{ |
// Standard requests |
switch (req) |
{ |
case REQ_GET_STATUS: |
get_status(request); |
break; |
case REQ_CLEAR_FEATURE: |
clear_feature(request); |
break; |
case REQ_SET_FEATURE: |
set_feature(request); |
break; |
case REQ_SET_ADDRESS: |
set_address(request); |
break; |
case REQ_GET_DESCRIPTOR: |
get_descriptor(request); |
break; |
case REQ_GET_CONFIGURATION: |
get_configuration(request); |
break; |
case REQ_SET_CONFIGURATION: |
set_configuration(request); |
break; |
case REQ_GET_INTERFACE: |
get_interface(request); |
break; |
case REQ_SET_INTERFACE: |
set_interface(request); |
break; |
default: |
log_printf(USBLOG_ERR, "USB: Unknown standard request %x\n", req); |
usbhw_control_endpoint_stall(); |
break; |
} |
} |
else if ( type == USB_VENDOR_REQUEST ) |
{ |
log_printf(USBLOG_ERR, "Vendor: Unknown command\n"); |
|
// None supported |
usbhw_control_endpoint_stall(); |
} |
else if ( type == USB_CLASS_REQUEST && _class_request) |
{ |
_class_request(req, request->wValue, request->wIndex, data, request->wLength); |
} |
else |
usbhw_control_endpoint_stall(); |
} |
//----------------------------------------------------------------- |
// usb_process_setup: Process SETUP packet |
//----------------------------------------------------------------- |
static void usb_process_setup(void) |
{ |
unsigned char type, req; |
unsigned char setup_pkt[EP0_MAX_PACKET_SIZE]; |
|
usbhw_get_rx_data(ENDPOINT_CONTROL, setup_pkt, EP0_MAX_PACKET_SIZE); |
|
#if (LOG_LEVEL >= USBLOG_SETUP_DATA) |
{ |
int i; |
|
log_printf(USBLOG_SETUP_DATA, "USB: SETUP data %d\n", EP0_MAX_PACKET_SIZE); |
|
for (i=0;i<EP0_MAX_PACKET_SIZE;i++) |
log_printf(USBLOG_SETUP_DATA, "%02x ", setup_pkt[i]); |
|
log_printf(USBLOG_SETUP_DATA, "\n"); |
} |
#endif |
|
// Extract packet to local endian format |
_ctrl_xfer.request.bmRequestType = setup_pkt[0]; |
_ctrl_xfer.request.bRequest = setup_pkt[1]; |
_ctrl_xfer.request.wValue = setup_pkt[3]; |
_ctrl_xfer.request.wValue <<= 8; |
_ctrl_xfer.request.wValue |= setup_pkt[2]; |
_ctrl_xfer.request.wIndex = setup_pkt[5]; |
_ctrl_xfer.request.wIndex <<= 8; |
_ctrl_xfer.request.wIndex |= setup_pkt[4]; |
_ctrl_xfer.request.wLength = setup_pkt[7]; |
_ctrl_xfer.request.wLength <<= 8; |
_ctrl_xfer.request.wLength |= setup_pkt[6]; |
|
_ctrl_xfer.data_idx = 0; |
_ctrl_xfer.data_expected = 0; |
|
type = _ctrl_xfer.request.bmRequestType & USB_REQUEST_TYPE_MASK; |
req = _ctrl_xfer.request.bRequest; |
|
// SETUP - GET |
if (_ctrl_xfer.request.bmRequestType & ENDPOINT_DIR_IN) |
{ |
log_printf(USBLOG_SETUP, "USB: SETUP Get wValue=0x%x wIndex=0x%x wLength=%d\n", |
_ctrl_xfer.request.wValue, |
_ctrl_xfer.request.wIndex, |
_ctrl_xfer.request.wLength); |
|
usb_process_request(&_ctrl_xfer.request, type, req, _ctrl_xfer.data_buffer); |
} |
// SETUP - SET |
else |
{ |
// No data |
if ( _ctrl_xfer.request.wLength == 0 ) |
{ |
log_printf(USBLOG_SETUP, "USB: SETUP Set wValue=0x%x wIndex=0x%x wLength=%d\n", |
_ctrl_xfer.request.wValue, |
_ctrl_xfer.request.wIndex, |
_ctrl_xfer.request.wLength); |
usb_process_request(&_ctrl_xfer.request, type, req, _ctrl_xfer.data_buffer); |
} |
// Data expected |
else |
{ |
log_printf(USBLOG_SETUP, "USB: SETUP Set wValue=0x%x wIndex=0x%x wLength=%d [OUT expected]\n", |
_ctrl_xfer.request.wValue, |
_ctrl_xfer.request.wIndex, |
_ctrl_xfer.request.wLength); |
|
if ( _ctrl_xfer.request.wLength <= MAX_CTRL_DATA_LENGTH ) |
{ |
// OUT packets expected to follow containing data |
_ctrl_xfer.data_expected = 1; |
} |
// Error: Too much data! |
else |
{ |
log_printf(USBLOG_ERR, "USB: More data than max transfer size\n"); |
usbhw_control_endpoint_stall(); |
} |
} |
} |
} |
//----------------------------------------------------------------- |
// usb_process_out: Process OUT (on control EP0) |
//----------------------------------------------------------------- |
static void usb_process_out(void) |
{ |
unsigned short received; |
unsigned char type; |
unsigned char req; |
|
// Error: Not expecting DATA-OUT! |
if (!_ctrl_xfer.data_expected) |
{ |
log_printf(USBLOG_ERR, "USB: (EP0) OUT received but not expected, STALL\n"); |
usbhw_control_endpoint_stall(); |
} |
else |
{ |
received = usbhw_get_rx_count( ENDPOINT_CONTROL ); |
|
log_printf(USBLOG_SETUP_OUT, "USB: OUT received (%d bytes)\n", received); |
|
if ( (_ctrl_xfer.data_idx + received) > MAX_CTRL_DATA_LENGTH ) |
{ |
log_printf(USBLOG_ERR, "USB: Too much OUT EP0 data %d > %d, STALL\n", (_ctrl_xfer.data_idx + received), MAX_CTRL_DATA_LENGTH); |
usbhw_control_endpoint_stall(); |
} |
else |
{ |
usbhw_get_rx_data(ENDPOINT_CONTROL, &_ctrl_xfer.data_buffer[_ctrl_xfer.data_idx], received); |
_ctrl_xfer.data_idx += received; |
|
log_printf(USBLOG_SETUP_OUT, "USB: OUT packet re-assembled %d\n", _ctrl_xfer.data_idx); |
|
// End of transfer (short transfer received?) |
if (received < EP0_MAX_PACKET_SIZE || _ctrl_xfer.data_idx >= _ctrl_xfer.request.wLength) |
{ |
// Send ZLP (ACK for Status stage) |
log_printf(USBLOG_SETUP_OUT, "USB: Send ZLP status stage %d %d\n", _ctrl_xfer.data_idx, _ctrl_xfer.request.wLength); |
|
usbhw_load_tx_buffer( ENDPOINT_CONTROL, 0, 0); |
while (!usbhw_has_tx_space( ENDPOINT_CONTROL )) |
; |
_ctrl_xfer.data_expected = 0; |
|
type = _ctrl_xfer.request.bmRequestType & USB_REQUEST_TYPE_MASK; |
req = _ctrl_xfer.request.bRequest; |
|
usb_process_request(&_ctrl_xfer.request, type, req, _ctrl_xfer.data_buffer); |
} |
else |
log_printf(USBLOG_SETUP_OUT, "DEV: More data expected!\n"); |
} |
} |
} |
//----------------------------------------------------------------- |
// usb_control_send: Perform a transfer via IN |
//----------------------------------------------------------------- |
int usb_control_send(unsigned char *buf, int size) |
{ |
t_time tS; |
int send; |
int remain; |
int count = 0; |
int err = 0; |
|
log_printf(USBLOG_SETUP_IN, "USB: usb_control_send %d\n", size); |
|
// Loop until partial packet sent |
do |
{ |
remain = size - count; |
send = MIN(remain, EP0_MAX_PACKET_SIZE); |
|
log_printf(USBLOG_SETUP_IN_DBG, " Remain %d, Send %d\n", remain, send); |
|
usbhw_load_tx_buffer(ENDPOINT_CONTROL, buf, (unsigned char) send); |
|
buf += send; |
count += send; |
|
log_printf(USBLOG_SETUP_IN_DBG, " Sent %d, Remain %d\n", send, (size - count)); |
|
tS = timer_now(); |
while ( !usbhw_has_tx_space( ENDPOINT_CONTROL ) ) |
{ |
if (timer_diff(timer_now(), tS) > USB_CTRL_TX_TIMEOUT) |
{ |
log_printf(USBLOG_ERR, "USB: Timeout sending IN data\n"); |
err = 1; |
break; |
} |
} |
} |
while (send >= EP0_MAX_PACKET_SIZE); |
|
if (!err) |
{ |
log_printf(USBLOG_SETUP_IN, "USB: Sent total %d\n", count); |
|
// Wait for ACK from host |
tS = timer_now(); |
do |
{ |
if (timer_diff(timer_now(), tS) > USB_CTRL_TX_TIMEOUT) |
{ |
log_printf(USBLOG_ERR, "USB: ACK not received\n"); |
err = 1; |
break; |
} |
} |
while (!usbhw_is_rx_ready(ENDPOINT_CONTROL)); |
|
usbhw_clear_rx_ready(ENDPOINT_CONTROL); |
|
if (!err) |
{ |
log_printf(USBLOG_SETUP_IN, "USB: ACK received\n"); |
} |
} |
|
return !err; |
} |
//----------------------------------------------------------------- |
// usb_init: |
//----------------------------------------------------------------- |
void usb_init(FP_BUS_RESET bus_reset, FP_CLASS_REQUEST class_request) |
{ |
_class_request = class_request; |
usbhw_init(bus_reset, usb_process_setup, usb_process_out); |
} |
/trunk/sw/usb_uart.h
0,0 → 1,14
#ifndef __USB_UART_H__ |
#define __USB_UART_H__ |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
void usb_uart_init(void); |
int usb_uart_haschar(void); |
int usb_uart_getchar(void); |
int usb_uart_getblock(unsigned char *data, int max_length); |
int usb_uart_putchar(char txbyte); |
void usb_uart_flush(void); |
|
#endif |
/trunk/sw/usb_desc.h
0,0 → 1,10
#ifndef __USB_DESC_H__ |
#define __USB_DESC_H__ |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
unsigned char *usb_get_descriptor( unsigned char bDescriptorType, unsigned char bDescriptorIndex, unsigned short wLength, unsigned char *pSize ); |
int usb_is_bus_powered(void); |
|
#endif |
/trunk/sw/usb_hw.h
0,0 → 1,45
#ifndef __USB_HW_H__ |
#define __USB_HW_H__ |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#define ENDPOINT_CONTROL 0 |
|
#define EP0_MAX_PACKET_SIZE 8 |
#define EP1_MAX_PACKET_SIZE 64 |
#define EP2_MAX_PACKET_SIZE 64 |
#define EP3_MAX_PACKET_SIZE 64 |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
typedef void (*FUNC_PTR)(void); |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
void usbhw_init(FUNC_PTR bus_reset, FUNC_PTR on_setup, FUNC_PTR on_out); |
void usbhw_service(void); |
void usbhw_attach(int state); |
int usbhw_is_attached(void); |
int usbhw_is_configured(void); |
void usbhw_set_configured(int configured); |
void usbhw_set_address(unsigned char addr); |
int usbhw_is_endpoint_stalled(unsigned char endpoint); |
void usbhw_clear_endpoint_stall(unsigned char endpoint); |
void usbhw_set_endpoint_stall(unsigned char endpoint); |
int usbhw_is_rx_ready(unsigned char endpoint); |
int usbhw_get_rx_count(unsigned char endpoint); |
int usbhw_get_rx_data(unsigned char endpoint, unsigned char *data, int max_len); |
unsigned char usbhw_get_rx_byte(unsigned char endpoint); |
void usbhw_clear_rx_ready(unsigned char endpoint); |
int usbhw_has_tx_space(unsigned char endpoint); |
int usbhw_load_tx_buffer(unsigned char endpoint, unsigned char *data, int count); |
void usbhw_write_tx_byte(unsigned char endpoint, unsigned char data); |
void usbhw_start_tx(unsigned char endpoint); |
void usbhw_control_endpoint_stall(void); |
void usbhw_control_endpoint_ack(void); |
unsigned short usbhw_get_frame_number(void); |
|
#endif |
/trunk/sw/usb_device.h
0,0 → 1,16
#ifndef __USB_DEVICE_H__ |
#define __USB_DEVICE_H__ |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
typedef void (*FP_CLASS_REQUEST)(unsigned char req, unsigned short wValue, unsigned short WIndex, unsigned char *data, unsigned short wLength); |
typedef void (*FP_BUS_RESET)(void); |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
void usb_init(FP_BUS_RESET bus_reset, FP_CLASS_REQUEST class_request); |
int usb_control_send(unsigned char *buf, int size); |
|
#endif |