samd support suspend and resume. Though cannot distinguish between Suspend and Disconnect
should work with #47
This commit is contained in:
		@@ -38,19 +38,20 @@ static ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2];
 | 
			
		||||
static ATTR_ALIGNED(4) uint8_t _setup_packet[8];
 | 
			
		||||
 | 
			
		||||
// Setup the control endpoint 0.
 | 
			
		||||
static void bus_reset(void) {
 | 
			
		||||
    // Max size of packets is 64 bytes.
 | 
			
		||||
    UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
 | 
			
		||||
    bank_out->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
    UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
 | 
			
		||||
    bank_in->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
static void bus_reset(void)
 | 
			
		||||
{
 | 
			
		||||
  // Max size of packets is 64 bytes.
 | 
			
		||||
  UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
 | 
			
		||||
  bank_out->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
  UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
 | 
			
		||||
  bank_in->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
 | 
			
		||||
    UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
 | 
			
		||||
    ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
 | 
			
		||||
    ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
 | 
			
		||||
  ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
 | 
			
		||||
  ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
 | 
			
		||||
 | 
			
		||||
    // Prepare for setup packet
 | 
			
		||||
    dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
 | 
			
		||||
  // Prepare for setup packet
 | 
			
		||||
  dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -79,6 +80,7 @@ void dcd_init (uint8_t rhport)
 | 
			
		||||
  USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY;
 | 
			
		||||
  while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
 | 
			
		||||
  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -103,6 +105,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
 | 
			
		||||
  while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
 | 
			
		||||
 | 
			
		||||
  // Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
 | 
			
		||||
  USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
 | 
			
		||||
  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
 | 
			
		||||
@@ -111,17 +117,13 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
 | 
			
		||||
  (void) config_num;
 | 
			
		||||
  // Nothing to do
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
  // Enable suspend to detect disconnection
 | 
			
		||||
  // TODO need to distinguish Suspend vs Disconnect
 | 
			
		||||
  USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND;
 | 
			
		||||
  USB->DEVICE.INTENSET.reg |= USB_DEVICE_INTENSET_SUSPEND;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_remote_wakeup(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.CTRLB.bit.UPRSM = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
@@ -305,35 +307,44 @@ void maybe_transfer_complete(void) {
 | 
			
		||||
void USB_Handler(void)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
 | 
			
		||||
  USB->DEVICE.INTFLAG.reg = int_status; // clear interrupt
 | 
			
		||||
 | 
			
		||||
  /*------------- Interrupt Processing -------------*/
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_EORST )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST;
 | 
			
		||||
    bus_reset();
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_SOF )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
  // SAMD doesn't distinguish between Suspend and Disconnect state.
 | 
			
		||||
  // Both condition will cause SUSPEND interrupt triggered.
 | 
			
		||||
  // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
 | 
			
		||||
  // enabled when we received SET_ADDRESS request and cleared on Bus Reset
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_SUSPEND )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND;
 | 
			
		||||
    // Enable wakeup interrupt
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending
 | 
			
		||||
    USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP;
 | 
			
		||||
 | 
			
		||||
    // disable interrupt to prevent it continue to trigger
 | 
			
		||||
    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_SUSPEND;
 | 
			
		||||
 | 
			
		||||
    // TODO need to distinguish Suspend vs Disconnect
 | 
			
		||||
    // reset address to 0, force host to re-enumerate after resume
 | 
			
		||||
    USB->DEVICE.DADD.reg = 0;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Wakeup interrupt is only enabled when we got suspended.
 | 
			
		||||
  // Wakeup interrupt will disable itself
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_WAKEUP )
 | 
			
		||||
  {
 | 
			
		||||
    // disable wakeup interrupt itself
 | 
			
		||||
    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_EORST )
 | 
			
		||||
  {
 | 
			
		||||
    // Disable both suspend and wakeup interrupt
 | 
			
		||||
    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND;
 | 
			
		||||
 | 
			
		||||
    bus_reset();
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Setup packet received.
 | 
			
		||||
  maybe_handle_setup_packet();
 | 
			
		||||
 
 | 
			
		||||
@@ -38,19 +38,20 @@ static UsbDeviceDescBank sram_registers[8][2];
 | 
			
		||||
static ATTR_ALIGNED(4) uint8_t _setup_packet[8];
 | 
			
		||||
 | 
			
		||||
// Setup the control endpoint 0.
 | 
			
		||||
static void bus_reset(void) {
 | 
			
		||||
    // Max size of packets is 64 bytes.
 | 
			
		||||
    UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
 | 
			
		||||
    bank_out->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
    UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
 | 
			
		||||
    bank_in->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
static void bus_reset(void)
 | 
			
		||||
{
 | 
			
		||||
  // Max size of packets is 64 bytes.
 | 
			
		||||
  UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
 | 
			
		||||
  bank_out->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
  UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
 | 
			
		||||
  bank_in->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
 | 
			
		||||
    UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
 | 
			
		||||
    ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
 | 
			
		||||
    ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
 | 
			
		||||
  ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
 | 
			
		||||
  ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
 | 
			
		||||
 | 
			
		||||
    // Prepare for setup packet
 | 
			
		||||
    dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
 | 
			
		||||
  // Prepare for setup packet
 | 
			
		||||
  dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -78,6 +79,8 @@ void dcd_init (uint8_t rhport)
 | 
			
		||||
  USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS;
 | 
			
		||||
  USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY;
 | 
			
		||||
  while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
 | 
			
		||||
  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -108,6 +111,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
 | 
			
		||||
  while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
 | 
			
		||||
 | 
			
		||||
  // Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
 | 
			
		||||
  USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
 | 
			
		||||
  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
 | 
			
		||||
@@ -120,6 +127,8 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
 | 
			
		||||
void dcd_remote_wakeup(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.CTRLB.bit.UPRSM = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
@@ -270,12 +279,42 @@ USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2,
 | 
			
		||||
USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5,
 | 
			
		||||
USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */
 | 
			
		||||
void USB_0_Handler(void) {
 | 
			
		||||
  uint32_t int_status = USB->DEVICE.INTFLAG.reg;
 | 
			
		||||
  uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
 | 
			
		||||
 | 
			
		||||
  /*------------- Interrupt Processing -------------*/
 | 
			
		||||
  // SAMD doesn't distinguish between Suspend and Disconnect state.
 | 
			
		||||
  // Both condition will cause SUSPEND interrupt triggered.
 | 
			
		||||
  // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
 | 
			
		||||
  // enabled when we received SET_ADDRESS request and cleared on Bus Reset
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_SUSPEND )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND;
 | 
			
		||||
 | 
			
		||||
    // Enable wakeup interrupt
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending
 | 
			
		||||
    USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP;
 | 
			
		||||
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Wakeup interrupt is only enabled when we got suspended.
 | 
			
		||||
  // Wakeup interrupt will disable itself
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_WAKEUP )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP;
 | 
			
		||||
 | 
			
		||||
    // disable wakeup interrupt itself
 | 
			
		||||
    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_EORST )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST;
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST;
 | 
			
		||||
 | 
			
		||||
    // Disable both suspend and wakeup interrupt
 | 
			
		||||
    USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND;
 | 
			
		||||
 | 
			
		||||
    bus_reset();
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
 | 
			
		||||
  }
 | 
			
		||||
@@ -283,6 +322,7 @@ void USB_0_Handler(void) {
 | 
			
		||||
  // Setup packet received.
 | 
			
		||||
  maybe_handle_setup_packet();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* USB_SOF_HSOF */
 | 
			
		||||
void USB_1_Handler(void) {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user