OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.