257 lines
4.9 KiB
C
257 lines
4.9 KiB
C
#include <usb/usb.h>
|
|
#include <hwo/events.h>
|
|
#include <hwo/utils.h>
|
|
#include <sys/atomic.h>
|
|
#include <sys/systick.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/assert.h>
|
|
|
|
#include <sys/trace.h>
|
|
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
|
|
#include <usb/usb_defs.h>
|
|
|
|
struct __usb_pllcsr _usb_pllcsr[] = __USB_PLLCSR;
|
|
|
|
#ifdef USB_DEBUG_SETUP
|
|
|
|
#define USB_DEBUG_SETUP_SIZE 10
|
|
|
|
usb_debug_setup_t *usb_debug_setup;
|
|
int *usb_debug_index;
|
|
int *usb_debug_size;
|
|
|
|
#endif
|
|
|
|
int avr_usb_device_configure_pll(void)
|
|
{
|
|
struct __usb_pllcsr *pll = _usb_pllcsr;
|
|
int n;
|
|
|
|
// Disable PLL
|
|
PLLCSR = 0;
|
|
wait_ms(5);
|
|
|
|
// Configure PLL
|
|
/* PLL */
|
|
while ((pll)->fcpu)
|
|
{
|
|
if (pll->fcpu == __freq_cpu)
|
|
{
|
|
|
|
#ifdef __USB_PLLFRQ
|
|
PLLFRQ = __USB_PLLFRQ;
|
|
#endif
|
|
|
|
PLLCSR = pll->pllcsr;
|
|
|
|
break;
|
|
};
|
|
|
|
pll++;
|
|
};
|
|
if (!pll->fcpu)
|
|
return -EPARAM;
|
|
|
|
// Enable PLL
|
|
PLLCSR |= _BV(PLLE);
|
|
|
|
for (n=0;n<100;n++){
|
|
if (PLLCSR & _BV(PLOCK)){
|
|
break;
|
|
};
|
|
wait_ms(1);
|
|
};
|
|
|
|
if (!(PLLCSR & _BV(PLOCK))){
|
|
return -ETIMEOUT;
|
|
};
|
|
|
|
return ESUCCESS;
|
|
};
|
|
|
|
|
|
|
|
|
|
int usb_device_on(usb_device_setup_t *ddesc)
|
|
{
|
|
ATOMIC
|
|
|
|
usb_ll_disable_all_irq();
|
|
usb_device_off();
|
|
|
|
usb_device.descriptor = ddesc;
|
|
usb_device.ep0desc = (usb_standard_endpoint_descriptor_t){
|
|
bEndpointAddress: 0x00,
|
|
bmAttributes: 0,
|
|
wMaxPacketSize: ddesc->descriptor.bMaxPacketSize0
|
|
};
|
|
|
|
/* Start USB Hardware */
|
|
|
|
// UHWCON = 0;
|
|
// UDADDR = 0;
|
|
// UDCON = _BV(DETACH);
|
|
|
|
usb_device_freeze_clock();
|
|
|
|
usb_device_enable_padreg();
|
|
usb_device_disable_vbuspad();
|
|
usb_device_enable_vbuspad();
|
|
|
|
USBCON |= _BV(USBE);
|
|
|
|
assert(avr_usb_device_configure_pll());
|
|
|
|
usb_device_unfreeze_clock();
|
|
usb_device_mode();
|
|
|
|
usb_ll_setup_configuration( -1 );
|
|
|
|
usb_ll_enable_irq( USB_IRQ_ENDOFRESET );
|
|
|
|
usb_ll_disable_irq( USB_IRQ_SUSPEND );
|
|
usb_ll_disable_irq( USB_IRQ_WAKEUP );
|
|
|
|
#ifdef USB_DEBUG_SETUP
|
|
|
|
if (!usb_debug_setup){
|
|
usb_debug_setup = (void*)__malloc_heap_end;
|
|
usb_debug_setup -= (USB_DEBUG_SETUP_SIZE + 1);
|
|
usb_debug_index = (void*)usb_debug_setup;
|
|
usb_debug_index --;
|
|
usb_debug_size = (void*)usb_debug_index;
|
|
usb_debug_size --;
|
|
__malloc_heap_end = (void*)usb_debug_size;
|
|
|
|
*usb_debug_size = USB_DEBUG_SETUP_SIZE;
|
|
|
|
if (*usb_debug_index >= *usb_debug_size)
|
|
*usb_debug_index = 0;
|
|
if (*usb_debug_index < 0)
|
|
*usb_debug_index = 0;
|
|
};
|
|
|
|
#endif
|
|
|
|
usb_device.state = (usb_device_state_t){ HWEnabled: 1 };
|
|
|
|
return ESUCCESS;
|
|
};
|
|
|
|
int usb_device_wait_vbus(void){
|
|
while (!(USBSTA & _BV(VBUS))) {
|
|
wait_ms(1);
|
|
};
|
|
return ESUCCESS;
|
|
};
|
|
|
|
int usb_device_check_attachment(void){
|
|
if (USBCON & _BV(USBE)){
|
|
if ( (USBSTA & _BV(VBUS)) && (UDCON & _BV(DETACH)) ){
|
|
usb_device_attach();
|
|
};
|
|
if ( !(USBSTA & _BV(VBUS)) && !(UDCON & _BV(DETACH)) ){
|
|
usb_device_detach();
|
|
};
|
|
};
|
|
return 0;
|
|
};
|
|
|
|
void avr_usb_device_vbusti(void) {
|
|
if (USBCON & _BV(USBE)){
|
|
usb_ll_clear_irq( USB_IRQ_VBUST );
|
|
|
|
if (usb_device_bus_is_connected()) {
|
|
event_push(EV_SYS_USBCONNECT,0,0,NULL);
|
|
} else {
|
|
event_push(EV_SYS_USBDISCONNECT,0,0,NULL);
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
VECT(USB_GEN_vect)
|
|
{
|
|
inline void __restore_epnum(uint8_t *epnum) { UENUM = *epnum; };
|
|
uint8_t __epnum __attribute__((__cleanup__(__restore_epnum))) = UENUM;
|
|
|
|
if ((UDIEN & _BV(EORSTE)) && (UDINT & _BV(EORSTI)))
|
|
{
|
|
usb_ll_setup_configuration( -1 );
|
|
usb_ll_endpoint_enable( &(usb_device.ep0desc) );
|
|
|
|
usb_ll_clear_irq( USB_IRQ_ENDOFRESET );
|
|
|
|
usb_device.state.Default = 1;
|
|
usb_device.state.Address = 0;
|
|
usb_device.state.Configured = 0;
|
|
usb_device.state.Suspended = 0;
|
|
|
|
/* usb_ll_clear_irq( USB_IRQ_SUSPEND );
|
|
usb_ll_disable_irq( USB_IRQ_SUSPEND );
|
|
usb_ll_enable_irq( USB_IRQ_WAKEUP );
|
|
*/
|
|
};
|
|
|
|
/* if ((UDIEN & _BV(SUSPE)) && (UDINT & _BV(SUSPI)))
|
|
{
|
|
usb_ll_clear_irq( USB_IRQ_SUSPEND );
|
|
|
|
usb_ll_disable_irq( USB_IRQ_SUSPEND );
|
|
usb_ll_enable_irq( USB_IRQ_WAKEUP );
|
|
|
|
usb_device_freeze_clock();
|
|
};
|
|
|
|
if ((UDIEN & _BV(WAKEUPE)) && (UDINT & _BV(WAKEUPI)))
|
|
{
|
|
usb_device_unfreeze_clock();
|
|
|
|
usb_ll_clear_irq( USB_IRQ_WAKEUP );
|
|
|
|
usb_ll_disable_irq( USB_IRQ_WAKEUP );
|
|
usb_ll_enable_irq( USB_IRQ_SUSPEND );
|
|
|
|
};
|
|
*/
|
|
};
|
|
|
|
|
|
VECT(USB_COM_vect)
|
|
{
|
|
uint8_t nEP;
|
|
inline void __restore_epnum(uint8_t *epnum) { UENUM = *epnum; };
|
|
uint8_t __epnum __attribute__((__cleanup__(__restore_epnum))) = UENUM;
|
|
|
|
for (nEP = 0; nEP < 0x07; nEP++)
|
|
{
|
|
if (UEINT & _BV(nEP))
|
|
{
|
|
|
|
usb_ll_endpoint_select( nEP );
|
|
|
|
if ( (UEIENX & _BV(RXSTPE)) && (UEINTX & _BV(RXSTPI))){
|
|
usb_irq_endpoint_setup( nEP );
|
|
};
|
|
|
|
if ( (UEIENX & _BV(RXOUTE)) && (UEINTX & _BV(RXOUTI)) ){
|
|
usb_irq_endpoint_rxout( nEP );
|
|
};
|
|
|
|
if ( (UEIENX & _BV(TXINE)) && (UEINTX & _BV(TXINI)) ){
|
|
usb_irq_endpoint_txin( nEP );
|
|
};
|
|
|
|
if ( (UEIENX & _BV(NAKINE)) && (UEINTX & _BV(NAKINI)) ){
|
|
usb_irq_endpoint_nakin( nEP );
|
|
};
|
|
|
|
};
|
|
};
|
|
|
|
};
|
|
|