avr-fw-modules/usb/src/usb_device_avr.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 );
};
};
};
};