1/*
2  Copyright (c) 2015 Arduino LLC.  All right reserved.
3
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  See the GNU Lesser General Public License for more details.
13
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18
19#pragma once
20
21#include <Arduino.h>
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <stdint.h>
26
27typedef uint8_t ep_t;
28
29class USBDevice_SAMD21G18x {
30public:
31	USBDevice_SAMD21G18x() : usb(USB->DEVICE) {
32		// Empty
33	}
34
35	// USB Device function mapping
36	// ---------------------------
37
38	// Reset USB Device
39	inline void reset();
40
41	// Enable
42	inline void enable()  { usb.CTRLA.bit.ENABLE = 1; }
43	inline void disable() { usb.CTRLA.bit.ENABLE = 0; }
44
45	// USB mode (device/host)
46	inline void setUSBDeviceMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; }
47	inline void setUSBHostMode()   { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val;   }
48
49	inline void runInStandby()   { usb.CTRLA.bit.RUNSTDBY = 1; }
50	inline void noRunInStandby() { usb.CTRLA.bit.RUNSTDBY = 0; }
51	inline void wakeupHost()     { usb.CTRLB.bit.UPRSM = 1; }
52
53	// USB QoS
54	inline void setDataSensitiveQoS() { usb.QOSCTRL.bit.DQOS = 2; }
55	inline void setConfigSensitiveQoS() { usb.QOSCTRL.bit.CQOS = 2; }
56
57	// USB speed
58	inline void setFullSpeed()       { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val;   }
59	inline void setLowSpeed()        { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val;   }
60	inline void setHiSpeed()         { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HS_Val;   }
61	inline void setHiSpeedTestMode() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HSTM_Val; }
62
63	// Authorize attach if Vbus is present
64	inline void attach() { usb.CTRLB.bit.DETACH = 0; }
65	inline void detach() { usb.CTRLB.bit.DETACH = 1; }
66
67	// USB Interrupts
68	inline bool isEndOfResetInterrupt()        { return usb.INTFLAG.bit.EORST; }
69	inline void ackEndOfResetInterrupt()       { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; }
70	inline void enableEndOfResetInterrupt()    { usb.INTENSET.bit.EORST = 1; }
71	inline void disableEndOfResetInterrupt()   { usb.INTENCLR.bit.EORST = 1; }
72
73	inline bool isStartOfFrameInterrupt()      { return usb.INTFLAG.bit.SOF; }
74	inline void ackStartOfFrameInterrupt()     { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; }
75	inline void enableStartOfFrameInterrupt()  { usb.INTENSET.bit.SOF = 1; }
76	inline void disableStartOfFrameInterrupt() { usb.INTENCLR.bit.SOF = 1; }
77
78	// USB Address
79	inline void setAddress(uint32_t addr)   { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; }
80	inline void unsetAddress()              { usb.DADD.bit.DADD = 0;    usb.DADD.bit.ADDEN = 0; }
81
82	// Frame number
83	inline uint16_t frameNumber() { return usb.FNUM.bit.FNUM; }
84
85	// Load calibration values
86	inline void calibrate();
87
88	// USB Device Endpoints function mapping
89	// -------------------------------------
90
91	// Config
92	inline void epBank0SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE0 = type; }
93	inline void epBank1SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE1 = type; }
94
95	// Interrupts
96	inline uint16_t epInterruptSummary() { return usb.EPINTSMRY.reg; }
97
98	inline bool epHasPendingInterrupts(ep_t ep)     { return usb.DeviceEndpoint[ep].EPINTFLAG.reg != 0; }
99	inline bool epBank0IsSetupReceived(ep_t ep)     { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.RXSTP; }
100	inline bool epBank0IsStalled(ep_t ep)           { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL0; }
101	inline bool epBank1IsStalled(ep_t ep)           { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL1; }
102	inline bool epBank0IsTransferFailed(ep_t ep)    { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRFAIL0; }
103	inline bool epBank1IsTransferFailed(ep_t ep)    { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRFAIL1; }
104	inline bool epBank0IsTransferComplete(ep_t ep)  { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT0; }
105	inline bool epBank1IsTransferComplete(ep_t ep)  { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT1; }
106
107	inline void epAckPendingInterrupts(ep_t ep)     { usb.DeviceEndpoint[ep].EPINTFLAG.reg = 0x7F; }
108	inline void epBank0AckSetupReceived(ep_t ep)    { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; }
109	inline void epBank0AckStalled(ep_t ep)          { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(1); }
110	inline void epBank1AckStalled(ep_t ep)          { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2); }
111	inline void epBank0AckTransferFailed(ep_t ep)   { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL(1); }
112	inline void epBank1AckTransferFailed(ep_t ep)   { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL(2); }
113	inline void epBank0AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1); }
114	inline void epBank1AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2); }
115
116	inline void epBank0EnableSetupReceived(ep_t ep)    { usb.DeviceEndpoint[ep].EPINTENSET.bit.RXSTP = 1; }
117	inline void epBank0EnableStalled(ep_t ep)          { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL0 = 1; }
118	inline void epBank1EnableStalled(ep_t ep)          { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL1 = 1; }
119	inline void epBank0EnableTransferFailed(ep_t ep)   { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRFAIL0 = 1; }
120	inline void epBank1EnableTransferFailed(ep_t ep)   { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRFAIL1 = 1; }
121	inline void epBank0EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT0 = 1; }
122	inline void epBank1EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT1 = 1; }
123
124	inline void epBank0DisableSetupReceived(ep_t ep)    { usb.DeviceEndpoint[ep].EPINTENCLR.bit.RXSTP = 1; }
125	inline void epBank0DisableStalled(ep_t ep)          { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL0 = 1; }
126	inline void epBank1DisableStalled(ep_t ep)          { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL1 = 1; }
127	inline void epBank0DisableTransferFailed(ep_t ep)   { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRFAIL0 = 1; }
128	inline void epBank1DisableTransferFailed(ep_t ep)   { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRFAIL1 = 1; }
129	inline void epBank0DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT0 = 1; }
130	inline void epBank1DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT1 = 1; }
131
132	// Status
133	inline bool epBank0IsReady(ep_t ep)    { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK0RDY; }
134	inline bool epBank1IsReady(ep_t ep)    { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK1RDY; }
135	inline void epBank0SetReady(ep_t ep)   { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK0RDY = 1; }
136	inline void epBank1SetReady(ep_t ep)   { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK1RDY = 1; }
137	inline void epBank0ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK0RDY = 1; }
138	inline void epBank1ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK1RDY = 1; }
139
140	inline void epBank0SetStallReq(ep_t ep)   { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ0 = 1; }
141	inline void epBank1SetStallReq(ep_t ep)   { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ1 = 1; }
142	inline void epBank0ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ0 = 1; }
143	inline void epBank1ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ1 = 1; }
144
145	// Packet
146	inline uint16_t epBank0ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT; }
147	inline uint16_t epBank1ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT; }
148	inline void epBank0SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = bc; }
149	inline void epBank1SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = bc; }
150	inline void epBank0SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = s; }
151	inline void epBank1SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = s; }
152
153	inline void epBank0SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)addr; }
154	inline void epBank1SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)addr; }
155	inline void epBank0SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); }
156	inline void epBank1SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); }
157	inline uint8_t EP_PCKSIZE_SIZE(uint16_t size) {
158		switch (size) {
159		case 8:    return 0;
160		case 16:   return 1;
161		case 32:   return 2;
162		case 64:   return 3;
163		case 128:  return 4;
164		case 256:  return 5;
165		case 512:  return 6;
166		case 1023: return 7;
167		default:   return 0;
168		}
169	}
170
171	inline void epBank0DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 0; }
172	inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 0; }
173	inline void epBank0EnableAutoZLP(ep_t ep)  { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 1; }
174	inline void epBank1EnableAutoZLP(ep_t ep)  { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 1; }
175
176	// USB Device Endpoint transactions helpers
177	// ----------------------------------------
178
179	inline void epReleaseOutBank0(ep_t ep, uint16_t s) {
180		epBank0SetMultiPacketSize(ep, s);
181		epBank0SetByteCount(ep, 0);
182		epBank0ResetReady(ep);
183	}
184
185private:
186	// USB Device registers
187	UsbDevice &usb;
188
189	// Endpoints descriptors table
190	__attribute__((__aligned__(4)))	UsbDeviceDescriptor EP[USB_EPT_NUM];
191};
192
193void USBDevice_SAMD21G18x::reset() {
194	usb.CTRLA.bit.SWRST = 1;
195	memset(EP, 0, sizeof(EP));
196	while (usb.SYNCBUSY.bit.SWRST) {}
197	usb.DESCADD.reg = (uint32_t)(&EP);
198}
199
200void USBDevice_SAMD21G18x::calibrate() {
201	// Load Pad Calibration data from non-volatile memory
202	uint32_t *pad_transn_p = (uint32_t *) USB_FUSES_TRANSN_ADDR;
203	uint32_t *pad_transp_p = (uint32_t *) USB_FUSES_TRANSP_ADDR;
204	uint32_t *pad_trim_p   = (uint32_t *) USB_FUSES_TRIM_ADDR;
205
206	uint32_t pad_transn = (*pad_transn_p & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
207	uint32_t pad_transp = (*pad_transp_p & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
208	uint32_t pad_trim   = (*pad_trim_p   & USB_FUSES_TRIM_Msk  ) >> USB_FUSES_TRIM_Pos;
209
210	if (pad_transn == 0x1F)  // maximum value (31)
211		pad_transn = 5;
212	if (pad_transp == 0x1F)  // maximum value (31)
213		pad_transp = 29;
214	if (pad_trim == 0x7)     // maximum value (7)
215		pad_trim = 3;
216
217	usb.PADCAL.bit.TRANSN = pad_transn;
218	usb.PADCAL.bit.TRANSP = pad_transp;
219	usb.PADCAL.bit.TRIM   = pad_trim;
220}
221
222/*
223 * Synchronization primitives.
224 * TODO: Move into a separate header file and make an API out of it
225 */
226
227class __Guard {
228public:
229	__Guard() : primask(__get_PRIMASK()), loops(1) {
230		__disable_irq();
231	}
232	~__Guard() {
233		if (primask == 0) {
234			__enable_irq();
235			// http://infocenter.arm.com/help/topic/com.arm.doc.dai0321a/BIHBFEIB.html
236			__ISB();
237		}
238	}
239	uint32_t enter() { return loops--; }
240private:
241	uint32_t primask;
242	uint32_t loops;
243};
244
245#define synchronized for (__Guard __guard; __guard.enter(); )
246
247
248/*
249 * USB EP generic handlers.
250 */
251
252class EPHandler {
253public:
254	virtual void handleEndpoint() = 0;
255	virtual uint32_t recv(void *_data, uint32_t len) = 0;
256	virtual uint32_t available() = 0;
257	virtual int peek() = 0;
258};
259
260class DoubleBufferedEPOutHandler : public EPHandler {
261public:
262	enum { size = 64 };
263
264	DoubleBufferedEPOutHandler(USBDevice_SAMD21G18x &usbDev, uint32_t endPoint) :
265		usbd(usbDev),
266		ep(endPoint),
267		current(0), incoming(0),
268		first0(0), last0(0), ready0(false),
269		first1(0), last1(0), ready1(false),
270		notify(false)
271	{
272		usbd.epBank0SetSize(ep, 64);
273		usbd.epBank0SetType(ep, 3); // BULK OUT
274		usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data0));
275		usbd.epBank0EnableTransferComplete(ep);
276
277		release();
278	}
279
280	virtual ~DoubleBufferedEPOutHandler() {
281	}
282
283	uint32_t _recv()
284	{
285		uint32_t i = 0;
286		uint32_t len = 0;
287
288		synchronized {
289			len = _rx_buffer.availableForStore();
290		}
291
292		// R/W: current, first0/1, ready0/1, notify
293		// R  : last0/1, data0/1
294		if (current == 0) {
295			synchronized {
296				if (!ready0) {
297					return 0;
298				}
299			}
300			// when ready0==true the buffer is not being filled and last0 is constant
301			for (; i<len && first0 < last0; i++) {
302				_rx_buffer.store_char(data0[first0++]);
303			}
304			if (first0 == last0) {
305				first0 = 0;
306				current = 1;
307				synchronized {
308					ready0 = false;
309					if (notify) {
310						notify = false;
311						release();
312					}
313				}
314			}
315		} else {
316			synchronized {
317				if (!ready1) {
318					return 0;
319				}
320			}
321			// when ready1==true the buffer is not being filled and last1 is constant
322			for (; i<len && first1 < last1; i++) {
323				_rx_buffer.store_char(data1[first1++]);
324			}
325			if (first1 == last1) {
326				first1 = 0;
327				current = 0;
328				synchronized {
329					ready1 = false;
330					if (notify) {
331						notify = false;
332						release();
333					}
334				}
335			}
336		}
337		return i;
338	}
339
340	virtual uint32_t recv(void *_data, uint32_t len) {
341		_recv();
342		uint32_t i = 0;
343		uint8_t *data = reinterpret_cast<uint8_t *>(_data);
344		synchronized {
345			for (; i < len && _rx_buffer.available(); i++) {
346				data[i] = _rx_buffer.read_char();
347			}
348		}
349		return i;
350	}
351
352	virtual uint32_t _available() const {
353		if (current == 0) {
354			bool ready = ready0;
355			synchronized {
356				ready = ready0;
357			}
358			return ready ? (last0 - first0) : 0;
359		} else {
360			bool ready = false;
361			synchronized {
362				ready = ready1;
363			}
364			return ready ? (last1 - first1) : 0;
365		}
366	}
367
368	virtual void handleEndpoint()
369	{
370		// R/W : incoming, ready0/1
371		//   W : last0/1, notify
372		if (usbd.epBank0IsTransferComplete(ep))
373		{
374			uint32_t received = usbd.epBank0ByteCount(ep);
375			if (received == 0) {
376				release();
377			} else if (incoming == 0) {
378			// Update counters and swap banks for non-ZLP's
379				last0 = received;
380				incoming = 1;
381				usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data1));
382				synchronized {
383					ready0 = true;
384					notify = ready1;
385					if (!notify) {
386						release();
387					}
388				}
389			} else {
390				last1 = received;
391				incoming = 0;
392				usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data0));
393				synchronized {
394					ready1 = true;
395					notify = ready0;
396					if (!notify) {
397						release();
398					}
399				}
400			}
401			usbd.epAckPendingInterrupts(ep);
402		}
403	}
404
405	// Returns how many bytes are stored in the buffers
406	virtual uint32_t available() {
407		_recv();
408		return _rx_buffer.available();
409	}
410
411	virtual int peek() {
412		_recv();
413		return _rx_buffer.peek();
414	}
415
416	void release() {
417		usbd.epReleaseOutBank0(ep, size);
418	}
419
420private:
421	USBDevice_SAMD21G18x &usbd;
422
423	RingBuffer _rx_buffer;
424
425	const uint32_t ep;
426	volatile uint32_t current, incoming;
427
428	__attribute__((__aligned__(4)))	volatile uint8_t data0[size];
429	uint32_t first0;
430	volatile uint32_t last0;
431	volatile bool ready0;
432
433	__attribute__((__aligned__(4)))	volatile uint8_t data1[size];
434	uint32_t first1;
435	volatile uint32_t last1;
436	volatile bool ready1;
437
438	volatile bool notify;
439};
440
441