Blame view

epsilon-master/ion/src/device/usb/stack/device.cpp 5.24 KB
6663b6c9   adorian   projet complet av...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  #include "device.h"
  #include <ion/src/device/regs/regs.h>
  
  namespace Ion {
  namespace USB {
  namespace Device {
  
  static inline uint16_t min(uint16_t x, uint16_t y) { return (x<y ? x : y); }
  
  void Device::poll() {
    // Read the interrupts
    class OTG::GINTSTS intsts(OTG.GINTSTS()->get());
  
    /* SETUP or OUT transaction
     * If the Rx FIFO is not empty, there is a SETUP or OUT transaction.
     * The interrupt is done AFTER THE HANSDHAKE of the transaction. */
    if (intsts.getRXFLVL()) {
      class OTG::GRXSTSP grxstsp(OTG.GRXSTSP()->get());
  
      // Store the packet status
      OTG::GRXSTSP::PKTSTS pktsts = grxstsp.getPKTSTS();
  
      // We only use endpoint 0
      assert(grxstsp.getEPNUM() == 0);
  
      if (pktsts == OTG::GRXSTSP::PKTSTS::OutTransferCompleted || pktsts == OTG::GRXSTSP::PKTSTS::SetupTransactionCompleted) {
        // There is no data associated with this interrupt.
        return;
      }
  
      assert(pktsts != OTG::GRXSTSP::PKTSTS::GlobalOutNAK);
      /* We did not enable the GONAKEFFM (Global OUT NAK effective mask) bit in
       * GINTSTS, so we should never get this interrupt. */
  
      assert(pktsts == OTG::GRXSTSP::PKTSTS::OutReceived || pktsts == OTG::GRXSTSP::PKTSTS::SetupReceived);
  
      TransactionType type = (pktsts == OTG::GRXSTSP::PKTSTS::OutReceived) ? TransactionType::Out : TransactionType::Setup;
  
      if (type == TransactionType::Setup && OTG.DIEPTSIZ0()->getPKTCNT()) {
        // SETUP received but there is a packet in the Tx FIFO. Flush it.
        m_ep0.flushTxFifo();
      }
  
      // Save the received packet byte count
      m_ep0.setReceivedPacketSize(grxstsp.getBCNT());
  
      if (type == TransactionType::Setup) {
        m_ep0.readAndDispatchSetupPacket();
      } else {
        assert(type == TransactionType::Out);
        m_ep0.processOUTpacket();
      }
  
      m_ep0.discardUnreadData();
    }
  
    /* IN transactions.
     * The interrupt is done AFTER THE HANSDHAKE of the transaction. */
    if (OTG.DIEPINT(0)->getXFRC()) { // We only check endpoint 0.
      m_ep0.processINpacket();
      // Clear the Transfer Completed Interrupt
      OTG.DIEPINT(0)->setXFRC(true);
    }
  
    // Handle USB RESET. ENUMDNE = **SPEED** Enumeration Done
    if (intsts.getENUMDNE()) {
      // Clear the ENUMDNE bit
      OTG.GINTSTS()->setENUMDNE(true);
      /* After a USB reset, the host talks to the device by sending messages to
       * address 0; */
      setAddress(0);
      // Flush the FIFOs
      m_ep0.reset();
      m_ep0.setup();
      /* In setup(), we should set the MPSIZ field in OTG_DIEPCTL0 to the maximum
       * packet size depending on the enumeration speed (found in OTG_DSTS). We
       * should always get FullSpeed, so we set the packet size accordingly. */
    }
  }
  
  bool Device::isSoftDisconnected() const {
    return OTG.DCTL()->getSDIS();
  }
  
  void Device::detach() {
    // Get in soft-disconnected state
    OTG.DCTL()->setSDIS(true);
  }
  
  bool Device::processSetupInRequest(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) {
    // Device only handles standard requests.
    if (request->requestType() != SetupPacket::RequestType::Standard) {
      return false;
    }
    switch (request->bRequest()) {
      case (int) Request::GetStatus:
        return getStatus(transferBuffer, transferBufferLength, transferBufferMaxLength);
      case (int) Request::SetAddress:
        // Make sure the request is adress is valid.
        assert(request->wValue() < 128);
        /* According to the reference manual, the address should be set after the
         * Status stage of the current transaction, but this is not true.
         * It should be set here, after the Data stage. */
        setAddress(request->wValue());
        *transferBufferLength = 0;
        return true;
      case (int) Request::GetDescriptor:
        return getDescriptor(request, transferBuffer, transferBufferLength, transferBufferMaxLength);
      case (int) Request::SetConfiguration:
        *transferBufferLength = 0;
        return setConfiguration(request);
      case (int) Request::GetConfiguration:
        return getConfiguration(transferBuffer, transferBufferLength);
    }
    return false;
  }
  
  bool Device::getStatus(uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) {
    *transferBufferLength = min(2, transferBufferMaxLength);
    for (int i = 0; i<*transferBufferLength; i++) {
      transferBuffer[i] = 0; // No remote wakeup, not self-powered.
    }
    return true;
  }
  
  void Device::setAddress(uint8_t address) {
    OTG.DCFG()->setDAD(address);
  }
  
  bool Device::getDescriptor(SetupPacket * request, uint8_t * transferBuffer, uint16_t * transferBufferLength, uint16_t transferBufferMaxLength) {
    Descriptor * wantedDescriptor = descriptor(request->descriptorType(), request->descriptorIndex());
    if (wantedDescriptor == nullptr) {
      return false;
    }
    *transferBufferLength = wantedDescriptor->copy(transferBuffer, transferBufferMaxLength);
    return true;
  }
  
  bool Device::getConfiguration(uint8_t * transferBuffer, uint16_t * transferBufferLength) {
    *transferBufferLength = 1;
    transferBuffer[0] = getActiveConfiguration();
    return true;
  }
  
  bool Device::setConfiguration(SetupPacket * request) {
    // We support one configuration only
    setActiveConfiguration(request->wValue());
    /* There is one configuration only, we no need to set it again, just reset the
     * endpoint. */
    m_ep0.reset();
    return true;
  }
  
  }
  }
  }