1 /*
2  * Copyright 2012 Jared Boone
3  *
4  * This file is part of HackRF.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; see the file COPYING.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #include <stdint.h>
23 #include <stdbool.h>
24 
25 #include "usb.h"
26 #include "usb_type.h"
27 #include "usb_queue.h"
28 #include "usb_standard_request.h"
29 
30 #include <libopencm3/lpc43xx/creg.h>
31 #include <libopencm3/lpc43xx/m4/nvic.h>
32 #include <libopencm3/lpc43xx/rgu.h>
33 #include <libopencm3/lpc43xx/usb.h>
34 
35 usb_device_t* usb_device_usb0 = 0;
36 
37 usb_queue_head_t usb_qh[12] ATTR_ALIGNED(2048);
38 
39 #define USB_QH_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
40 
usb_queue_head(const uint_fast8_t endpoint_address)41 usb_queue_head_t* usb_queue_head(
42 	const uint_fast8_t endpoint_address
43 ) {
44 	return &usb_qh[USB_QH_INDEX(endpoint_address)];
45 }
46 
usb_endpoint_from_address(const uint_fast8_t endpoint_address)47 static usb_endpoint_t* usb_endpoint_from_address(
48 	const uint_fast8_t endpoint_address
49 ) {
50 	return (usb_endpoint_t*)usb_queue_head(endpoint_address)->_reserved_0;
51 }
52 
usb_endpoint_address(const usb_transfer_direction_t direction,const uint_fast8_t number)53 static uint_fast8_t usb_endpoint_address(
54 	const usb_transfer_direction_t direction,
55 	const uint_fast8_t number
56 ) {
57 	return ((direction == USB_TRANSFER_DIRECTION_IN) ? 0x80 : 0x00) + number;
58 }
59 
usb_endpoint_is_in(const uint_fast8_t endpoint_address)60 static bool usb_endpoint_is_in(const uint_fast8_t endpoint_address) {
61 	return (endpoint_address & 0x80) ? true : false;
62 }
63 
usb_endpoint_number(const uint_fast8_t endpoint_address)64 static uint_fast8_t usb_endpoint_number(const uint_fast8_t endpoint_address) {
65 	return (endpoint_address & 0xF);
66 }
67 
usb_peripheral_reset()68 void usb_peripheral_reset() {
69 	RESET_CTRL0 = RESET_CTRL0_USB0_RST;
70 	RESET_CTRL0 = 0;
71 
72 	while( (RESET_ACTIVE_STATUS0 & RESET_CTRL0_USB0_RST) == 0 );
73 }
74 
usb_phy_enable()75 void usb_phy_enable() {
76 	CREG_CREG0 &= ~CREG_CREG0_USB0PHY;
77 }
78 
usb_clear_pending_interrupts(const uint32_t mask)79 static void usb_clear_pending_interrupts(const uint32_t mask) {
80 	USB0_ENDPTNAK = mask;
81 	USB0_ENDPTNAKEN = mask;
82 	USB0_USBSTS_D = mask;
83 	USB0_ENDPTSETUPSTAT = USB0_ENDPTSETUPSTAT & mask;
84 	USB0_ENDPTCOMPLETE = USB0_ENDPTCOMPLETE & mask;
85 }
86 
usb_clear_all_pending_interrupts()87 static void usb_clear_all_pending_interrupts() {
88 	usb_clear_pending_interrupts(0xFFFFFFFF);
89 }
90 
usb_wait_for_endpoint_priming_to_finish(const uint32_t mask)91 static void usb_wait_for_endpoint_priming_to_finish(const uint32_t mask) {
92 	// Wait until controller has parsed new transfer descriptors and prepared
93 	// receive buffers.
94 	while( USB0_ENDPTPRIME & mask );
95 }
96 
usb_flush_endpoints(const uint32_t mask)97 static void usb_flush_endpoints(const uint32_t mask) {
98 	// Clear any primed buffers. If a packet is in progress, that transfer
99 	// will continue until completion.
100 	USB0_ENDPTFLUSH = mask;
101 }
102 
usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask)103 static void usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask) {
104 	// Wait until controller has flushed all endpoints / cleared any primed
105 	// buffers.
106 	while( USB0_ENDPTFLUSH & mask );
107 }
108 
usb_flush_primed_endpoints(const uint32_t mask)109 static void usb_flush_primed_endpoints(const uint32_t mask) {
110 	usb_wait_for_endpoint_priming_to_finish(mask);
111 	usb_flush_endpoints(mask);
112 	usb_wait_for_endpoint_flushing_to_finish(mask);
113 }
114 
usb_flush_all_primed_endpoints()115 static void usb_flush_all_primed_endpoints() {
116 	usb_flush_primed_endpoints(0xFFFFFFFF);
117 }
118 
usb_endpoint_set_type(const usb_endpoint_t * const endpoint,const usb_transfer_type_t transfer_type)119 static void usb_endpoint_set_type(
120 	const usb_endpoint_t* const endpoint,
121 	const usb_transfer_type_t transfer_type
122 ) {
123 	// NOTE: UM10503 section 23.6.24 "Endpoint 1 to 5 control registers" says
124 	// that the disabled side of an endpoint must be set to a non-control type
125 	// (e.g. bulk, interrupt, or iso).
126 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
127 	USB0_ENDPTCTRL(endpoint_number)
128 		= ( USB0_ENDPTCTRL(endpoint_number)
129 		  & ~(USB0_ENDPTCTRL_TXT1_0_MASK | USB0_ENDPTCTRL_RXT_MASK)
130 		  )
131 		| ( USB0_ENDPTCTRL_TXT1_0(transfer_type)
132 		  | USB0_ENDPTCTRL_RXT(transfer_type)
133 		  );
134 }
135 
usb_endpoint_enable(const usb_endpoint_t * const endpoint)136 static void usb_endpoint_enable(
137 	const usb_endpoint_t* const endpoint
138 ) {
139 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
140 	if( usb_endpoint_is_in(endpoint->address) ) {
141 		USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_TXE | USB0_ENDPTCTRL_TXR);
142 	} else {
143 		USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXE | USB0_ENDPTCTRL_RXR);
144 	}
145 }
146 
usb_endpoint_clear_pending_interrupts(const usb_endpoint_t * const endpoint)147 static void usb_endpoint_clear_pending_interrupts(
148 	const usb_endpoint_t* const endpoint
149 ) {
150 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
151 	if( usb_endpoint_is_in(endpoint->address) ) {
152 		usb_clear_pending_interrupts(USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number));
153 	} else {
154 		usb_clear_pending_interrupts(USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number));
155 	}
156 }
157 
usb_endpoint_disable(const usb_endpoint_t * const endpoint)158 void usb_endpoint_disable(
159 	const usb_endpoint_t* const endpoint
160 ) {
161 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
162 	if( usb_endpoint_is_in(endpoint->address) ) {
163 		USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_TXE);
164 	} else {
165 		USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE);
166 	}
167         usb_queue_flush_endpoint(endpoint);
168 	usb_endpoint_clear_pending_interrupts(endpoint);
169 	usb_endpoint_flush(endpoint);
170 }
171 
usb_endpoint_prime(const usb_endpoint_t * const endpoint,usb_transfer_descriptor_t * const first_td)172 void usb_endpoint_prime(
173 	const usb_endpoint_t* const endpoint,
174 	usb_transfer_descriptor_t* const first_td
175 ) {
176 	usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
177 
178 	qh->next_dtd_pointer = first_td;
179 	qh->total_bytes
180 		&= ~( USB_TD_DTD_TOKEN_STATUS_ACTIVE
181 		    | USB_TD_DTD_TOKEN_STATUS_HALTED
182 			)
183 		;
184 
185 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
186 	if( usb_endpoint_is_in(endpoint->address) ) {
187 		USB0_ENDPTPRIME = USB0_ENDPTPRIME_PETB(1 << endpoint_number);
188 	} else {
189 		USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number);
190 	}
191 }
192 
usb_endpoint_is_priming(const usb_endpoint_t * const endpoint)193 static bool usb_endpoint_is_priming(
194 	const usb_endpoint_t* const endpoint
195 ) {
196 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
197 	if( usb_endpoint_is_in(endpoint->address) ) {
198 		return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number);
199 	} else {
200 		return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number);
201 	}
202 }
203 
204 // Schedule an already filled-in transfer descriptor for execution on
205 // the given endpoint, waiting until the endpoint has finished.
usb_endpoint_schedule_wait(const usb_endpoint_t * const endpoint,usb_transfer_descriptor_t * const td)206 void usb_endpoint_schedule_wait(
207 	const usb_endpoint_t* const endpoint,
208 	usb_transfer_descriptor_t* const td
209 ) {
210 	// Ensure that endpoint is ready to be primed.
211 	// It may have been flushed due to an aborted transaction.
212 	// TODO: This should be preceded by a flush?
213 	while( usb_endpoint_is_ready(endpoint) );
214 
215 	td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
216 
217 	usb_endpoint_prime(endpoint, td);
218 }
219 
220 // Schedule an already filled-in transfer descriptor for execution on
221 // the given endpoint, appending to the end of the endpoint's queue if
222 // there are pending TDs. Note that this requires that one knows the
223 // tail of the endpoint's TD queue. Moreover, the user is responsible
224 // for setting the TERMINATE bit of next_dtd_pointer if needed.
usb_endpoint_schedule_append(const usb_endpoint_t * const endpoint,usb_transfer_descriptor_t * const tail_td,usb_transfer_descriptor_t * const new_td)225 void usb_endpoint_schedule_append(
226 	const usb_endpoint_t* const endpoint,
227 	usb_transfer_descriptor_t* const tail_td,
228 	usb_transfer_descriptor_t* const new_td
229 ) {
230 	bool done;
231 
232 	tail_td->next_dtd_pointer = new_td;
233 
234 	if (usb_endpoint_is_priming(endpoint)) {
235 		return;
236 	}
237 
238 	do {
239 		USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW;
240 		done = usb_endpoint_is_ready(endpoint);
241 	} while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW));
242 
243 	USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW;
244 	if(!done) {
245 		usb_endpoint_prime(endpoint, new_td);
246 	}
247 }
248 
usb_endpoint_flush(const usb_endpoint_t * const endpoint)249 void usb_endpoint_flush(
250 	const usb_endpoint_t* const endpoint
251 ) {
252 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
253 	usb_queue_flush_endpoint(endpoint);
254 	if( usb_endpoint_is_in(endpoint->address) ) {
255 		usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number));
256 	} else {
257 		usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FERB(1 << endpoint_number));
258 	}
259 }
260 /*
261 static bool usb_endpoint_is_flushing(
262 	const usb_endpoint_t* const endpoint
263 ) {
264 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
265 	if( usb_endpoint_is_in(endpoint->address) ) {
266 		return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FETB(1 << endpoint_number);
267 	} else {
268 		return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FERB(1 << endpoint_number);
269 	}
270 }
271 */
usb_endpoint_is_ready(const usb_endpoint_t * const endpoint)272 bool usb_endpoint_is_ready(
273 	const usb_endpoint_t* const endpoint
274 ) {
275 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
276 	if( usb_endpoint_is_in(endpoint->address) ) {
277 		return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ETBR(1 << endpoint_number);
278 	} else {
279 		return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ERBR(1 << endpoint_number);
280 	}
281 }
282 
usb_endpoint_is_complete(const usb_endpoint_t * const endpoint)283 bool usb_endpoint_is_complete(
284 	const usb_endpoint_t* const endpoint
285 ) {
286 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
287 	if( usb_endpoint_is_in(endpoint->address) ) {
288 		return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number);
289 	} else {
290 		return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number);
291 	}
292 }
293 
usb_endpoint_stall(const usb_endpoint_t * const endpoint)294 void usb_endpoint_stall(
295 	const usb_endpoint_t* const endpoint
296 ) {
297 	// Endpoint is to be stalled as a pair -- both OUT and IN.
298 	// See UM10503 section 23.10.5.2 "Stalling"
299 	const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
300 	USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXS | USB0_ENDPTCTRL_TXS);
301 
302 	// TODO: Also need to reset data toggle in both directions?
303 }
304 
usb_controller_run()305 static void usb_controller_run() {
306 	USB0_USBCMD_D |= USB0_USBCMD_D_RS;
307 }
308 
usb_controller_stop()309 static void usb_controller_stop() {
310 	USB0_USBCMD_D &= ~USB0_USBCMD_D_RS;
311 }
312 
usb_controller_is_resetting()313 static uint_fast8_t usb_controller_is_resetting() {
314 	return (USB0_USBCMD_D & USB0_USBCMD_D_RST) != 0;
315 }
316 
usb_controller_set_device_mode()317 static void usb_controller_set_device_mode() {
318 	// Set USB0 peripheral mode
319 	USB0_USBMODE_D = USB0_USBMODE_D_CM1_0(2);
320 
321 	// Set device-related OTG flags
322 	// OTG termination: controls pull-down on USB_DM
323 	USB0_OTGSC = USB0_OTGSC_OT;
324 }
325 
usb_speed(const usb_device_t * const device)326 usb_speed_t usb_speed(
327 	const usb_device_t* const device
328 ) {
329 	if( device == usb_device_usb0 ) {
330 		switch( USB0_PORTSC1_D & USB0_PORTSC1_D_PSPD_MASK ) {
331 		case USB0_PORTSC1_D_PSPD(0):
332 			return USB_SPEED_FULL;
333 
334 		case USB0_PORTSC1_D_PSPD(2):
335 			return USB_SPEED_HIGH;
336 
337 		default:
338 			// TODO: What to do/return here? Is this even possible?
339 			return USB_SPEED_FULL;
340 		}
341 	} else {
342 		// TODO: This should not be possible with a more class-like
343 		// implementation.
344 		return USB_SPEED_FULL;
345 	}
346 }
347 
usb_clear_status(const uint32_t status)348 static void usb_clear_status(const uint32_t status) {
349 	USB0_USBSTS_D = status;
350 }
351 
usb_get_status()352 static uint32_t usb_get_status() {
353     // Mask status flags with enabled flag interrupts.
354 	const uint32_t status = USB0_USBSTS_D & USB0_USBINTR_D;
355 
356     // Clear flags that were just read, leaving alone any flags that
357     // were just set (after the read). It's important to read and
358     // reset flags atomically! :-)
359 	usb_clear_status(status);
360 
361 	return status;
362 }
363 
usb_clear_endpoint_setup_status(const uint32_t endpoint_setup_status)364 static void usb_clear_endpoint_setup_status(const uint32_t endpoint_setup_status) {
365 	USB0_ENDPTSETUPSTAT = endpoint_setup_status;
366 }
367 
usb_get_endpoint_setup_status()368 static uint32_t usb_get_endpoint_setup_status() {
369  	return USB0_ENDPTSETUPSTAT;
370 }
371 
usb_clear_endpoint_complete(const uint32_t endpoint_complete)372 static void usb_clear_endpoint_complete(const uint32_t endpoint_complete) {
373 	USB0_ENDPTCOMPLETE = endpoint_complete;
374 }
375 
usb_get_endpoint_complete()376 static uint32_t usb_get_endpoint_complete() {
377 	return USB0_ENDPTCOMPLETE;
378 }
379 
usb_disable_all_endpoints()380 static void usb_disable_all_endpoints() {
381 	// Endpoint 0 is always enabled. TODO: So why set ENDPTCTRL0?
382 	USB0_ENDPTCTRL0 &= ~(USB0_ENDPTCTRL0_RXE | USB0_ENDPTCTRL0_TXE);
383 	USB0_ENDPTCTRL1 &= ~(USB0_ENDPTCTRL1_RXE | USB0_ENDPTCTRL1_TXE);
384 	USB0_ENDPTCTRL2 &= ~(USB0_ENDPTCTRL2_RXE | USB0_ENDPTCTRL2_TXE);
385 	USB0_ENDPTCTRL3 &= ~(USB0_ENDPTCTRL3_RXE | USB0_ENDPTCTRL3_TXE);
386 	USB0_ENDPTCTRL4 &= ~(USB0_ENDPTCTRL4_RXE | USB0_ENDPTCTRL4_TXE);
387 	USB0_ENDPTCTRL5 &= ~(USB0_ENDPTCTRL5_RXE | USB0_ENDPTCTRL5_TXE);
388 }
389 
usb_set_address_immediate(const usb_device_t * const device,const uint_fast8_t address)390 void usb_set_address_immediate(
391 	const usb_device_t* const device,
392 	const uint_fast8_t address
393 ) {
394 	if( device == usb_device_usb0 ) {
395 		USB0_DEVICEADDR = USB0_DEVICEADDR_USBADR(address);
396 	}
397 }
398 
usb_set_address_deferred(const usb_device_t * const device,const uint_fast8_t address)399 void usb_set_address_deferred(
400 	const usb_device_t* const device,
401 	const uint_fast8_t address
402 ) {
403 	if( device == usb_device_usb0 ) {
404 		USB0_DEVICEADDR
405 			= USB0_DEVICEADDR_USBADR(address)
406 		    | USB0_DEVICEADDR_USBADRA
407 			;
408 	}
409 }
410 
usb_reset_all_endpoints()411 static void usb_reset_all_endpoints() {
412 	usb_disable_all_endpoints();
413 	usb_clear_all_pending_interrupts();
414 	usb_flush_all_primed_endpoints();
415 }
416 
usb_controller_reset()417 static void usb_controller_reset() {
418 	// TODO: Good to disable some USB interrupts to avoid priming new
419 	// new endpoints before the controller is reset?
420 	usb_reset_all_endpoints();
421 	usb_controller_stop();
422 
423 	// Reset controller. Resets internal pipelines, timers, counters, state
424 	// machines to initial values. Not recommended when device is in attached
425 	// state -- effect on attached host is undefined. Detach first by flushing
426 	// all primed endpoints and stopping controller.
427 	USB0_USBCMD_D = USB0_USBCMD_D_RST;
428 
429 	while( usb_controller_is_resetting() );
430 }
431 
usb_bus_reset(usb_device_t * const device)432 static void usb_bus_reset(usb_device_t* const device) {
433 	// According to UM10503 v1.4 section 23.10.3 "Bus reset":
434 	usb_reset_all_endpoints();
435 	usb_set_address_immediate(device, 0);
436 	usb_set_configuration(device, 0);
437 
438 	// TODO: Enable endpoint 0, which might not actually be necessary,
439 	// as the datasheet claims it can't be disabled.
440 
441 	//wait_ms(3);
442 	//
443 	//if( USB0_PORTSC1 & USB0_PORTSC1_PR ) {
444 	//	// Port still is in the reset state.
445 	//} else {
446 	//	usb_hardware_reset();
447 	//}
448 }
449 
usb_interrupt_enable(usb_device_t * const device)450 static void usb_interrupt_enable(
451 	usb_device_t* const device
452 ) {
453 	if( device == usb_device_usb0 ) {
454 		nvic_enable_irq(NVIC_USB0_IRQ);
455 	}
456 }
457 
usb_device_init(const uint_fast8_t device_ordinal,usb_device_t * const device)458 void usb_device_init(
459 	const uint_fast8_t device_ordinal,
460 	usb_device_t* const device
461 ) {
462 	if( device_ordinal == 0 ) {
463 		usb_device_usb0 = device;
464 
465 		usb_phy_enable();
466 		usb_controller_reset();
467 		usb_controller_set_device_mode();
468 
469 		// Set interrupt threshold interval to 0
470 		USB0_USBCMD_D &= ~USB0_USBCMD_D_ITC_MASK;
471 
472 		// Configure endpoint list address
473 		USB0_ENDPOINTLISTADDR = (uint32_t)usb_qh;
474 
475 		// Enable interrupts
476 		USB0_USBINTR_D =
477 			  USB0_USBINTR_D_UE
478 			| USB0_USBINTR_D_UEE
479 			| USB0_USBINTR_D_PCE
480 			| USB0_USBINTR_D_URE
481 			//| USB0_USBINTR_D_SRE
482 			| USB0_USBINTR_D_SLE
483 			//| USB0_USBINTR_D_NAKE
484 			;
485 	}
486 }
487 
usb_run(usb_device_t * const device)488 void usb_run(
489 	usb_device_t* const device
490 ) {
491 	usb_interrupt_enable(device);
492 	usb_controller_run(device);
493 }
494 
copy_setup(usb_setup_t * const dst,const volatile uint8_t * const src)495 static void copy_setup(usb_setup_t* const dst, const volatile uint8_t* const src) {
496 	dst->request_type = src[0];
497 	dst->request = src[1];
498 	dst->value_l = src[2];
499 	dst->value_h = src[3];
500 	dst->index_l = src[4];
501 	dst->index_h = src[5];
502 	dst->length_l = src[6];
503 	dst->length_h = src[7];
504 }
505 
usb_endpoint_init(const usb_endpoint_t * const endpoint)506 void usb_endpoint_init(
507 	const usb_endpoint_t* const endpoint
508 ) {
509 	usb_endpoint_flush(endpoint);
510 
511 	uint_fast16_t max_packet_size = endpoint->device->descriptor[7];
512 	usb_transfer_type_t transfer_type = USB_TRANSFER_TYPE_CONTROL;
513 	const uint8_t* const endpoint_descriptor = usb_endpoint_descriptor(endpoint);
514 	if( endpoint_descriptor ) {
515 		max_packet_size = usb_endpoint_descriptor_max_packet_size(endpoint_descriptor);
516 		transfer_type = usb_endpoint_descriptor_transfer_type(endpoint_descriptor);
517 	}
518 
519 	// TODO: There are more capabilities to adjust based on the endpoint
520 	// descriptor.
521 	usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
522 	qh->capabilities
523 		= USB_QH_CAPABILITIES_MULT(0)
524 		| USB_QH_CAPABILITIES_ZLT
525 		| USB_QH_CAPABILITIES_MPL(max_packet_size)
526 		| ((transfer_type == USB_TRANSFER_TYPE_CONTROL) ? USB_QH_CAPABILITIES_IOS : 0)
527 		;
528 	qh->current_dtd_pointer = 0;
529 	qh->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
530 	qh->total_bytes
531 		= USB_TD_DTD_TOKEN_TOTAL_BYTES(0)
532 		| USB_TD_DTD_TOKEN_MULTO(0)
533 		;
534 	qh->buffer_pointer_page[0] = 0;
535 	qh->buffer_pointer_page[1] = 0;
536 	qh->buffer_pointer_page[2] = 0;
537 	qh->buffer_pointer_page[3] = 0;
538 	qh->buffer_pointer_page[4] = 0;
539 
540 	// This is how we look up an endpoint structure from an endpoint address:
541 	qh->_reserved_0 = (uint32_t)endpoint;
542 
543 	// TODO: Should NAK be enabled? I'm kinda squishy on this...
544 	//USB0_ENDPTNAKEN |=
545 	//	USB0_ENDPTNAKEN_EPRNE(1 << endpoint_out->number);
546 
547 	usb_endpoint_set_type(endpoint, transfer_type);
548 
549 	usb_endpoint_enable(endpoint);
550 }
551 
usb_check_for_setup_events()552 static void usb_check_for_setup_events() {
553 	const uint32_t endptsetupstat = usb_get_endpoint_setup_status();
554 	if( endptsetupstat ) {
555 		for( uint_fast8_t i=0; i<6; i++ ) {
556 			const uint32_t endptsetupstat_bit = USB0_ENDPTSETUPSTAT_ENDPTSETUPSTAT(1 << i);
557 			if( endptsetupstat & endptsetupstat_bit ) {
558 				usb_endpoint_t* const endpoint =
559 					usb_endpoint_from_address(
560 						usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
561 					);
562 				if( endpoint && endpoint->setup_complete ) {
563 					copy_setup(&endpoint->setup, usb_queue_head(endpoint->address)->setup);
564 					// TODO: Clean up this duplicated effort by providing
565 					// a cleaner way to get the SETUP data.
566 					copy_setup(&endpoint->in->setup, usb_queue_head(endpoint->address)->setup);
567 					usb_clear_endpoint_setup_status(endptsetupstat_bit);
568 					endpoint->setup_complete(endpoint);
569 				} else {
570 					usb_clear_endpoint_setup_status(endptsetupstat_bit);
571 				}
572 			}
573 		}
574 	}
575 }
576 
usb_check_for_transfer_events()577 static void usb_check_for_transfer_events() {
578 	const uint32_t endptcomplete = usb_get_endpoint_complete();
579 	if( endptcomplete ) {
580 		for( uint_fast8_t i=0; i<6; i++ ) {
581 
582 			const uint32_t endptcomplete_out_bit = USB0_ENDPTCOMPLETE_ERCE(1 << i);
583 			if( endptcomplete & endptcomplete_out_bit ) {
584 				usb_clear_endpoint_complete(endptcomplete_out_bit);
585 			 	usb_endpoint_t* const endpoint =
586 					usb_endpoint_from_address(
587 						usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
588 					);
589 				if( endpoint && endpoint->transfer_complete ) {
590 					endpoint->transfer_complete(endpoint);
591 				}
592 			}
593 
594 			const uint32_t endptcomplete_in_bit = USB0_ENDPTCOMPLETE_ETCE(1 << i);
595 			if( endptcomplete & endptcomplete_in_bit ) {
596 				usb_clear_endpoint_complete(endptcomplete_in_bit);
597 				usb_endpoint_t* const endpoint =
598 					usb_endpoint_from_address(
599 						usb_endpoint_address(USB_TRANSFER_DIRECTION_IN, i)
600 					);
601 				if( endpoint && endpoint->transfer_complete ) {
602 					endpoint->transfer_complete(endpoint);
603 				}
604 			}
605 		}
606 	}
607 }
608 
usb0_isr()609 void usb0_isr() {
610 	const uint32_t status = usb_get_status();
611 
612 	if( status == 0 ) {
613 		// Nothing to do.
614 		return;
615 	}
616 
617 	if( status & USB0_USBSTS_D_UI ) {
618 		// USB:
619 		// - Completed transaction transfer descriptor has IOC set.
620 		// - Short packet detected.
621 		// - SETUP packet received.
622 
623 		usb_check_for_setup_events();
624 		usb_check_for_transfer_events();
625 
626 		// TODO: Reset ignored ENDPTSETUPSTAT and ENDPTCOMPLETE flags?
627 	}
628 
629 	if( status & USB0_USBSTS_D_SRI ) {
630 		// Start Of Frame received.
631 	}
632 
633 	if( status & USB0_USBSTS_D_PCI ) {
634 		// Port change detect:
635 		// Port controller entered full- or high-speed operational state.
636 	}
637 
638 	if( status & USB0_USBSTS_D_SLI ) {
639 		// Device controller suspend.
640 	}
641 
642 	if( status & USB0_USBSTS_D_URI ) {
643 		// USB reset received.
644 		usb_bus_reset(usb_device_usb0);
645 	}
646 
647 	if( status & USB0_USBSTS_D_UEI ) {
648 		// USB error:
649 		// Completion of a USB transaction resulted in an error condition.
650 		// Set along with USBINT if the TD on which the error interrupt
651 		// occurred also had its interrupt on complete (IOC) bit set.
652 		// The device controller detects resume signalling only.
653 	}
654 
655 	if( status & USB0_USBSTS_D_NAKI ) {
656 		// Both the TX/RX endpoint NAK bit and corresponding TX/RX endpoint
657 		// NAK enable bit are set.
658 	}
659 }
660