Open FFBoard
Open source force feedback firmware
ohci.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI)
30
31#ifndef TUP_OHCI_RHPORTS
32#error OHCI is enabled, but TUP_OHCI_RHPORTS is not defined.
33#endif
34
35//--------------------------------------------------------------------+
36// INCLUDE
37//--------------------------------------------------------------------+
38#include "osal/osal.h"
39
40#include "host/hcd.h"
41#include "ohci.h"
42
43// TODO remove
44#include "chip.h"
45
46//--------------------------------------------------------------------+
47// MACRO CONSTANT TYPEDEF
48//--------------------------------------------------------------------+
49#define OHCI_REG ((ohci_registers_t *) LPC_USB_BASE)
50
51enum {
56};
57
58enum {
64};
65
66enum {
67 OHCI_FMINTERVAL_FI = 0x2EDF, // 7.3.1 nominal (reset) value
68 OHCI_FMINTERVAL_FSMPS = (6*(OHCI_FMINTERVAL_FI-210)) / 7, // 5.4 calculated based on maximum overhead + bit stuffing
69};
70
71enum {
72 OHCI_PERIODIC_START = 0x3E67
73};
74
75enum {
78 OHCI_INT_SOF_MASK = TU_BIT(2),
83
86};
87
88enum {
94
97
103
107
108enum {
122};
123
124enum {
126 OHCI_INT_ON_COMPLETE_NO = TU_BIN8(111)
128
129enum {
131 GTD_DT_DATA0 = TU_BIT(1) | 0,
132 GTD_DT_DATA1 = TU_BIT(1) | 1,
133};
134
135enum {
139};
140
141enum {
143};
144
145//--------------------------------------------------------------------+
146// INTERNAL OBJECT & FUNCTION DECLARATION
147//--------------------------------------------------------------------+
148CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(256) static ohci_data_t ohci_data;
149
150static ohci_ed_t * const p_ed_head[] =
151{
152 [TUSB_XFER_CONTROL] = &ohci_data.control[0].ed,
153 [TUSB_XFER_BULK ] = &ohci_data.bulk_head_ed,
154 [TUSB_XFER_INTERRUPT] = &ohci_data.period_head_ed,
155 [TUSB_XFER_ISOCHRONOUS] = NULL // TODO Isochronous
156};
157
158static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed);
159static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr);
160static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd);
161
162//--------------------------------------------------------------------+
163// USBH-HCD API
164//--------------------------------------------------------------------+
165
166// If your system requires separation of virtual and physical memory, implement
167// tusb_app_virt_to_phys and tusb_app_virt_to_phys in your application.
168TU_ATTR_ALWAYS_INLINE static inline void *_phys_addr(void *virtual_address)
169{
170 if (tusb_app_virt_to_phys) return tusb_app_virt_to_phys(virtual_address);
171 return virtual_address;
172}
173
174TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address)
175{
176 if (tusb_app_phys_to_virt) return tusb_app_phys_to_virt(physical_address);
177 return physical_address;
178}
179
180// Initialization according to 5.1.1.4
181bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
182 (void) rhport;
183 (void) rh_init;
184
185 //------------- Data Structure init -------------//
186 tu_memclr(&ohci_data, sizeof(ohci_data_t));
187 for(uint8_t i=0; i<32; i++)
188 { // assign all interrupt pointers to period head ed
189 ohci_data.hcca.interrupt_table[i] = (uint32_t) _phys_addr(&ohci_data.period_head_ed);
190 }
191
192 ohci_data.control[0].ed.skip = 1;
193 ohci_data.bulk_head_ed.skip = 1;
194 ohci_data.period_head_ed.skip = 1;
195
196 //If OHCI hardware is in SMM mode, gain ownership (Ref OHCI spec 5.1.1.3.3)
197 if (OHCI_REG->control_bit.interrupt_routing == 1)
198 {
199 OHCI_REG->command_status_bit.ownership_change_request = 1;
200 while (OHCI_REG->control_bit.interrupt_routing == 1) {}
201 }
202
203 //If OHCI hardware has come from warm-boot, signal resume (Ref OHCI spec 5.1.1.3.4)
204 else if (OHCI_REG->control_bit.hc_functional_state != OHCI_CONTROL_FUNCSTATE_RESET &&
205 OHCI_REG->control_bit.hc_functional_state != OHCI_CONTROL_FUNCSTATE_OPERATIONAL)
206 {
207 //Wait 20 ms. (Ref Usb spec 7.1.7.7)
208 OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_RESUME;
209
210#if CFG_TUSB_OS != OPT_OS_NONE
211 // os_none implement task delay using usb frame counter which is not started yet
212 // therefore cause infinite delay.
213 // TODO find a way to delay in case of os none e.g __nop
214 osal_task_delay(20);
215#endif
216 }
217
218 // reset controller
219 OHCI_REG->command_status_bit.controller_reset = 1;
220 while( OHCI_REG->command_status_bit.controller_reset ) {} // should not take longer than 10 us
221
222 //------------- init ohci registers -------------//
223 OHCI_REG->control_head_ed = (uint32_t) _phys_addr(&ohci_data.control[0].ed);
224 OHCI_REG->bulk_head_ed = (uint32_t) _phys_addr(&ohci_data.bulk_head_ed);
225 OHCI_REG->hcca = (uint32_t) _phys_addr(&ohci_data.hcca);
226
227 OHCI_REG->interrupt_disable = OHCI_REG->interrupt_enable; // disable all interrupts
228 OHCI_REG->interrupt_status = OHCI_REG->interrupt_status; // clear current set bits
232
235
236 OHCI_REG->frame_interval = (OHCI_FMINTERVAL_FSMPS << 16) | OHCI_FMINTERVAL_FI;
237 OHCI_REG->frame_interval ^= (1 << 31); //Must toggle when frame_interval is updated.
238 OHCI_REG->periodic_start = (OHCI_FMINTERVAL_FI * 9) / 10; // Periodic start is 90% of frame interval
239
240 OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
241 OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
242
243#if CFG_TUSB_OS != OPT_OS_NONE
244 // TODO as above delay
245 osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up
246#endif
247
248 return true;
249}
250
251uint32_t hcd_frame_number(uint8_t rhport)
252{
253 (void) rhport;
254 return (ohci_data.frame_number_hi << 16) | OHCI_REG->frame_number;
255}
256
257
258//--------------------------------------------------------------------+
259// PORT API
260//--------------------------------------------------------------------+
261void hcd_port_reset(uint8_t hostid)
262{
263 OHCI_REG->rhport_status[hostid] = RHPORT_PORT_RESET_STATUS_MASK;
264}
265
266void hcd_port_reset_end(uint8_t rhport)
267{
268 (void) rhport;
269}
270
271bool hcd_port_connect_status(uint8_t hostid)
272{
273 return OHCI_REG->rhport_status_bit[hostid].current_connect_status;
274}
275
277{
278 return OHCI_REG->rhport_status_bit[hostid].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
279}
280
281// endpoints are tied to an address, which only reclaim after a long delay when enumerating
282// thus there is no need to make sure ED is not in HC's cahed as it will not for sure
283void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
284{
285 // TODO OHCI
286 (void) rhport;
287
288 // addr0 serves as static head --> only set skip bit
289 if ( dev_addr == 0 )
290 {
291 ohci_data.control[0].ed.skip = 1;
292 }else
293 {
294 // remove control
296
297 // remove bulk
299
300 // remove interrupt
302
303 // TODO remove ISO
304 }
305}
306
307//--------------------------------------------------------------------+
308// Controller API
309//--------------------------------------------------------------------+
310
311//--------------------------------------------------------------------+
312// List Helper
313//--------------------------------------------------------------------+
314static inline tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const * const p_ed)
315{
316 return (p_ed->ep_number == 0 ) ? TUSB_XFER_CONTROL :
317 (p_ed->is_iso ) ? TUSB_XFER_ISOCHRONOUS :
318 (p_ed->is_interrupt_xfer) ? TUSB_XFER_INTERRUPT : TUSB_XFER_BULK;
319}
320
321static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t ep_addr, uint8_t xfer_type, uint8_t interval)
322{
323 (void) interval;
324
325 // address 0 is used as async head, which always on the list --> cannot be cleared
326 if (dev_addr != 0)
327 {
328 tu_memclr(p_ed, sizeof(ohci_ed_t));
329 }
330
331 hcd_devtree_info_t devtree_info;
332 hcd_devtree_get_info(dev_addr, &devtree_info);
333
334 p_ed->dev_addr = dev_addr;
335 p_ed->ep_number = ep_addr & 0x0F;
336 p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT);
337 p_ed->speed = devtree_info.speed;
338 p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
339 p_ed->max_packet_size = ep_size;
340
341 p_ed->used = 1;
342 p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
343}
344
345static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes) {
346 tu_memclr(p_td, sizeof(ohci_gtd_t));
347
348 p_td->used = 1;
350
351 p_td->buffer_rounding = 1; // less than queued length is not a error
352 p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
353 p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
354
355 uint8_t *cbp = (uint8_t *) _phys_addr(data_ptr);
356
357 p_td->current_buffer_pointer = cbp;
358 if ( total_bytes ) {
359 p_td->buffer_end = _phys_addr(data_ptr + total_bytes - 1);
360 } else {
361 p_td->buffer_end = cbp;
362 }
363}
364
365static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
366{
367 if ( tu_edpt_number(ep_addr) == 0 ) return &ohci_data.control[dev_addr].ed;
368
369 ohci_ed_t* ed_pool = ohci_data.ed_pool;
370
371 for(uint32_t i=0; i<ED_MAX; i++)
372 {
373 if ( (ed_pool[i].dev_addr == dev_addr) &&
374 ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) )
375 {
376 return &ed_pool[i];
377 }
378 }
379
380 return NULL;
381}
382
384{
385 ohci_ed_t* ed_pool = ohci_data.ed_pool;
386
387 for(uint8_t i = 0; i < ED_MAX; i++)
388 {
389 if ( !ed_pool[i].used ) return &ed_pool[i];
390 }
391
392 return NULL;
393}
394
395static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed)
396{
397 p_ed->next = p_pre->next;
398 p_pre->next = (uint32_t) _phys_addr(p_ed);
399}
400
401static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
402{
403 ohci_ed_t* p_prev = p_head;
404
405 while( p_prev->next )
406 {
407 ohci_ed_t* ed = (ohci_ed_t*) _virt_addr((void *)p_prev->next);
408
409 if (ed->dev_addr == dev_addr)
410 {
411 // Prevent Host Controller from processing this ED while we remove it
412 ed->skip = 1;
413
414 // unlink ed, will also move up p_prev
415 p_prev->next = ed->next;
416
417 // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED
418 ed->next = (uint32_t) _phys_addr(p_head);
419 ed->used = 0;
420 ed->skip = 0;
421 }else
422 {
423 p_prev = (ohci_ed_t*) _virt_addr((void *)p_prev->next);
424 }
425 }
426}
427
429{
430 for(uint8_t i=0; i < GTD_MAX; i++)
431 {
432 if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
433 }
434
435 return NULL;
436}
437
438static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
439{
440 // tail is always NULL
441 if ( tu_align16(p_ed->td_head.address) == 0 )
442 { // TD queue is empty --> head = TD
443 p_ed->td_head.address |= (uint32_t) _phys_addr(p_gtd);
444 }
445 else
446 { // TODO currently only support queue up to 2 TD each endpoint at a time
447 ((ohci_gtd_t*) tu_align16((uint32_t)_virt_addr((void *)p_ed->td_head.address)))->next = (uint32_t) _phys_addr(p_gtd);
448 }
449}
450
451//--------------------------------------------------------------------+
452// Endpoint API
453//--------------------------------------------------------------------+
454
455bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
456{
457 (void) rhport;
458
459 // TODO iso support
460 TU_ASSERT(ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
461
462 //------------- Prepare Queue Head -------------//
463 ohci_ed_t * p_ed;
464
465 if ( ep_desc->bEndpointAddress == 0 )
466 {
467 p_ed = &ohci_data.control[dev_addr].ed;
468 }else
469 {
470 p_ed = ed_find_free();
471 }
472 TU_ASSERT(p_ed);
473
474 ed_init( p_ed, dev_addr, tu_edpt_packet_size(ep_desc), ep_desc->bEndpointAddress,
475 ep_desc->bmAttributes.xfer, ep_desc->bInterval );
476
477 // control of dev0 is used as static async head
478 if ( dev_addr == 0 )
479 {
480 p_ed->skip = 0; // only need to clear skip bit
481 return true;
482 }
483
484 ed_list_insert( p_ed_head[ep_desc->bmAttributes.xfer], p_ed );
485
486 return true;
487}
488
489bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
490{
491 (void) rhport;
492
493 ohci_ed_t* ed = &ohci_data.control[dev_addr].ed;
494 ohci_gtd_t *qtd = &ohci_data.control[dev_addr].gtd;
495
496 gtd_init(qtd, (uint8_t*)(uintptr_t) setup_packet, 8);
497 qtd->index = dev_addr;
498 qtd->pid = PID_SETUP;
499 qtd->data_toggle = GTD_DT_DATA0;
500 qtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
501
502 //------------- Attach TDs list to Control Endpoint -------------//
503 ed->td_head.address = (uint32_t) _phys_addr(qtd);
504
505 OHCI_REG->command_status_bit.control_list_filled = 1;
506
507 return true;
508}
509
510bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
511{
512 (void) rhport;
513
514 uint8_t const epnum = tu_edpt_number(ep_addr);
515 uint8_t const dir = tu_edpt_dir(ep_addr);
516
517 if ( epnum == 0 )
518 {
519 ohci_ed_t* ed = &ohci_data.control[dev_addr].ed;
520 ohci_gtd_t* gtd = &ohci_data.control[dev_addr].gtd;
521
522 gtd_init(gtd, buffer, buflen);
523
524 gtd->index = dev_addr;
525 gtd->pid = dir ? PID_IN : PID_OUT;
526 gtd->data_toggle = GTD_DT_DATA1; // Both Data and Ack stage start with DATA1
527 gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
528
529 ed->td_head.address = (uint32_t) _phys_addr(gtd);
530
531 OHCI_REG->command_status_bit.control_list_filled = 1;
532 }else
533 {
534 ohci_ed_t * ed = ed_from_addr(dev_addr, ep_addr);
535 ohci_gtd_t* gtd = gtd_find_free();
536
537 TU_ASSERT(gtd);
538
539 gtd_init(gtd, buffer, buflen);
540 gtd->index = ed-ohci_data.ed_pool;
541 gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
542
543 td_insert_to_ed(ed, gtd);
544
546 if (TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1;
547 }
548
549 return true;
550}
551
552bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
553 (void) rhport;
554 (void) dev_addr;
555 (void) ep_addr;
556 // TODO not implemented yet
557 return false;
558}
559
560bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
561 (void) rhport;
562 ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);
563
564 p_ed->is_stalled = 0;
565 p_ed->td_tail &= 0x0Ful; // set tail pointer back to NULL
566
567 p_ed->td_head.toggle = 0; // reset data toggle
568 p_ed->td_head.halted = 0;
569
570 if ( TUSB_XFER_BULK == ed_get_xfer_type(p_ed) ) OHCI_REG->command_status_bit.bulk_list_filled = 1;
571
572 return true;
573}
574
575
576//--------------------------------------------------------------------+
577// OHCI Interrupt Handler
578//--------------------------------------------------------------------+
580{
581 ohci_td_item_t* td_reverse_head = NULL;
582
583 while(td_head != NULL)
584 {
585 td_head = _virt_addr(td_head);
586 uint32_t next = td_head->next;
587
588 // make current's item become reverse's first item
589 td_head->next = (uint32_t) td_reverse_head;
590 td_reverse_head = _phys_addr(td_head);
591
592 td_head = (ohci_td_item_t*) next; // advance to next item
593 }
594
595 return _virt_addr(td_reverse_head);
596}
597
598static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd)
599{
600 return ((uint32_t) p_qtd) < ((uint32_t) ohci_data.gtd_pool); // check ohci_data_t for memory layout
601}
602
603static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd)
604{
605 if ( gtd_is_control(p_qtd) )
606 {
607 return &ohci_data.control[p_qtd->index].ed;
608 }else
609 {
610 return &ohci_data.ed_pool[p_qtd->index];
611 }
612}
613
615 if ( gtd_is_control(gtd) ) {
616 uint8_t idx = ((uintptr_t)gtd - (uintptr_t)&ohci_data.control->gtd) / sizeof(ohci_data.control[0]);
617 return &ohci_data.gtd_extra_control[idx];
618 }else {
619 return &ohci_data.gtd_extra[gtd - ohci_data.gtd_pool];
620 }
621}
622
623static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
624{
625 // 5.2.9 OHCI sample code
626
627 // CBP is 0 mean all data is transferred
628 if (current_buffer == 0) return 0;
629
630 return (tu_align4k(buffer_end ^ current_buffer) ? 0x1000 : 0) +
631 tu_offset4k(buffer_end) - tu_offset4k(current_buffer) + 1;
632}
633
634static void done_queue_isr(uint8_t hostid)
635{
636 (void) hostid;
637
638 // done head is written in reversed order of completion --> need to reverse the done queue first
639 ohci_td_item_t* td_head = list_reverse ( (ohci_td_item_t*) tu_align16(ohci_data.hcca.done_head) );
640 ohci_data.hcca.done_head = 0;
641
642 while( td_head != NULL )
643 {
644 // TODO check if td_head is iso td
645 //------------- Non ISO transfer -------------//
646 ohci_gtd_t * const qtd = (ohci_gtd_t *) td_head;
647 xfer_result_t const event = (qtd->condition_code == OHCI_CCODE_NO_ERROR) ? XFER_RESULT_SUCCESS :
648 (qtd->condition_code == OHCI_CCODE_STALL) ? XFER_RESULT_STALLED : XFER_RESULT_FAILED;
649
650 qtd->used = 0; // free TD
651 if ( (qtd->delay_interrupt == OHCI_INT_ON_COMPLETE_YES) || (event != XFER_RESULT_SUCCESS) )
652 {
653 ohci_ed_t * const ed = gtd_get_ed(qtd);
654 uint32_t const xferred_bytes = gtd_get_extra_data(qtd)->expected_bytes - gtd_xfer_byte_left((uint32_t) qtd->buffer_end, (uint32_t) qtd->current_buffer_pointer);
655
656 // NOTE Assuming the current list is BULK and there is no other EDs in the list has queued TDs.
657 // When there is a error resulting this ED is halted, and this EP still has other queued TD
658 // --> the Bulk list only has this halted EP queueing TDs (remaining)
659 // --> Bulk list will be considered as not empty by HC !!! while there is no attempt transaction on this list
660 // --> HC will not process Control list (due to service ratio when Bulk list not empty)
661 // To walk-around this, the halted ED will have TailP = HeadP (empty list condition), when clearing halt
662 // the TailP must be set back to NULL for processing remaining TDs
663 if (event != XFER_RESULT_SUCCESS)
664 {
665 ed->td_tail &= 0x0Ful;
666 ed->td_tail |= tu_align16(ed->td_head.address); // mark halted EP as empty queue
667 if ( event == XFER_RESULT_STALLED ) ed->is_stalled = 1;
668 }
669
670 uint8_t dir = (ed->ep_number == 0) ? (qtd->pid == PID_IN) : (ed->pid == PID_IN);
671
672 hcd_event_xfer_complete(ed->dev_addr, tu_edpt_addr(ed->ep_number, dir), xferred_bytes, event, true);
673 }
674
675 td_head = (ohci_td_item_t*) _virt_addr((void *)td_head->next);
676 }
677}
678
679void hcd_int_handler(uint8_t hostid, bool in_isr) {
680 (void) in_isr;
681
682 uint32_t const int_en = OHCI_REG->interrupt_enable;
683 uint32_t const int_status = OHCI_REG->interrupt_status & int_en;
684
685 if (int_status == 0) return;
686
687 // Disable MIE as per OHCI spec 5.3
688 OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK;
689
690 // Frame number overflow
691 if ( int_status & OHCI_INT_FRAME_OVERFLOW_MASK )
692 {
693 ohci_data.frame_number_hi++;
694 }
695
696 //------------- RootHub status -------------//
697 if ( int_status & OHCI_INT_RHPORT_STATUS_CHANGE_MASK )
698 {
699 for (int i = 0; i < TUP_OHCI_RHPORTS; i++)
700 {
701 uint32_t const rhport_status = OHCI_REG->rhport_status[i] & RHPORT_ALL_CHANGE_MASK;
702 if ( rhport_status & RHPORT_CONNECT_STATUS_CHANGE_MASK )
703 {
704 // TODO check if remote wake-up
705 if ( OHCI_REG->rhport_status_bit[i].current_connect_status )
706 {
707 // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change)
708 OHCI_REG->rhport_status[i] = RHPORT_PORT_RESET_STATUS_MASK;
710 }else
711 {
713 }
714 }
715
716 if ( rhport_status & RHPORT_PORT_SUSPEND_CHANGE_MASK)
717 {
718
719 }
720
721 OHCI_REG->rhport_status[i] = rhport_status; // acknowledge all interrupt
722 }
723 }
724
725 //------------- Transfer Complete -------------//
726 if (int_status & OHCI_INT_WRITEBACK_DONEHEAD_MASK)
727 {
728 done_queue_isr(hostid);
729 }
730
731 OHCI_REG->interrupt_status = int_status; // Acknowledge handled interrupt
732
733 OHCI_REG->interrupt_enable = OHCI_INT_MASTER_ENABLE_MASK; // Enable MIE
734}
735//--------------------------------------------------------------------+
736// HELPER
737//--------------------------------------------------------------------+
738
739
740#endif
static bool in_isr
uint8_t * data_ptr
Definition: dcd_nuc505.c:111
uint16_t total_bytes
Definition: dcd_nuc505.c:113
uint8_t dev_addr
Definition: dcd_pic32mz.c:81
static TU_ATTR_ALWAYS_INLINE void hcd_event_device_remove(uint8_t rhport, bool in_isr)
Definition: hcd.h:209
static TU_ATTR_ALWAYS_INLINE void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
Definition: hcd.h:221
static TU_ATTR_ALWAYS_INLINE void hcd_event_device_attach(uint8_t rhport, bool in_isr)
Definition: hcd.h:197
void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t *devtree_info)
Definition: usbh.c:949
uint8_t const * buffer
Definition: midi_device.h:100
static TU_ATTR_ALWAYS_INLINE void * _phys_addr(void *virtual_address)
Definition: ohci.c:168
@ PID_FROM_TD
Definition: ohci.c:142
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
Definition: ohci.c:489
static ohci_gtd_t * gtd_find_free(void)
Definition: ohci.c:428
@ PID_IN
Definition: ohci.c:138
@ PID_SETUP
Definition: ohci.c:136
@ PID_OUT
Definition: ohci.c:137
@ GTD_DT_TOGGLE_CARRY
Definition: ohci.c:130
@ GTD_DT_DATA1
Definition: ohci.c:132
@ GTD_DT_DATA0
Definition: ohci.c:131
static gtd_extra_data_t * gtd_get_extra_data(ohci_gtd_t const *const gtd)
Definition: ohci.c:614
static tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const *const p_ed)
Definition: ohci.c:314
void hcd_int_handler(uint8_t hostid, bool in_isr)
Definition: ohci.c:679
static void done_queue_isr(uint8_t hostid)
Definition: ohci.c:634
@ OHCI_PERIODIC_START
Definition: ohci.c:72
@ OHCI_CCODE_DEVICE_NOT_RESPONDING
Definition: ohci.c:114
@ OHCI_CCODE_BIT_STUFFING
Definition: ohci.c:111
@ OHCI_CCODE_NO_ERROR
Definition: ohci.c:109
@ OHCI_CCODE_BUFFER_OVERRUN
Definition: ohci.c:119
@ OHCI_CCODE_PID_CHECK_FAILURE
Definition: ohci.c:115
@ OHCI_CCODE_NOT_ACCESSED
Definition: ohci.c:121
@ OHCI_CCODE_DATA_OVERRUN
Definition: ohci.c:117
@ OHCI_CCODE_CRC
Definition: ohci.c:110
@ OHCI_CCODE_BUFFER_UNDERRUN
Definition: ohci.c:120
@ OHCI_CCODE_STALL
Definition: ohci.c:113
@ OHCI_CCODE_DATA_TOGGLE_MISMATCH
Definition: ohci.c:112
@ OHCI_CCODE_UNEXPECTED_PID
Definition: ohci.c:116
@ OHCI_CCODE_DATA_UNDERRUN
Definition: ohci.c:118
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr)
Definition: ohci.c:560
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
Definition: ohci.c:510
static uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
Definition: ohci.c:623
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
Definition: ohci.c:283
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr)
Definition: ohci.c:552
@ OHCI_FMINTERVAL_FI
Definition: ohci.c:67
@ OHCI_FMINTERVAL_FSMPS
Definition: ohci.c:68
void hcd_port_reset_end(uint8_t rhport)
Definition: ohci.c:266
static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t ep_addr, uint8_t xfer_type, uint8_t interval)
Definition: ohci.c:321
static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
Definition: ohci.c:365
static TU_ATTR_ALWAYS_INLINE void * _virt_addr(void *physical_address)
Definition: ohci.c:174
CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(256)
Definition: ohci.c:148
@ OHCI_CONTROL_FUNCSTATE_RESET
Definition: ohci.c:52
@ OHCI_CONTROL_FUNCSTATE_OPERATIONAL
Definition: ohci.c:54
@ OHCI_CONTROL_FUNCSTATE_SUSPEND
Definition: ohci.c:55
@ OHCI_CONTROL_FUNCSTATE_RESUME
Definition: ohci.c:53
static void td_insert_to_ed(ohci_ed_t *p_ed, ohci_gtd_t *p_gtd)
Definition: ohci.c:438
static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes)
Definition: ohci.c:345
uint32_t hcd_frame_number(uint8_t rhport)
Definition: ohci.c:251
@ OHCI_INT_SCHEDULING_OVERUN_MASK
Definition: ohci.c:76
@ OHCI_INT_OWNERSHIP_CHANGE_MASK
Definition: ohci.c:84
@ OHCI_INT_UNRECOVERABLE_ERROR_MASK
Definition: ohci.c:80
@ OHCI_INT_RHPORT_STATUS_CHANGE_MASK
Definition: ohci.c:82
@ OHCI_INT_SOF_MASK
Definition: ohci.c:78
@ OHCI_INT_MASTER_ENABLE_MASK
Definition: ohci.c:85
@ OHCI_INT_RESUME_DETECTED_MASK
Definition: ohci.c:79
@ OHCI_INT_FRAME_OVERFLOW_MASK
Definition: ohci.c:81
@ OHCI_INT_WRITEBACK_DONEHEAD_MASK
Definition: ohci.c:77
@ RHPORT_CURRENT_CONNECT_STATUS_MASK
Definition: ohci.c:89
@ RHPORT_ALL_CHANGE_MASK
Definition: ohci.c:104
@ RHPORT_LOW_SPEED_DEVICE_ATTACHED_MASK
Definition: ohci.c:96
@ RHPORT_CONNECT_STATUS_CHANGE_MASK
Definition: ohci.c:98
@ RHPORT_PORT_POWER_STATUS_MASK
Definition: ohci.c:95
@ RHPORT_PORT_OVER_CURRENT_INDICATOR_MASK
Definition: ohci.c:92
@ RHPORT_PORT_SUSPEND_STATUS_MASK
Definition: ohci.c:91
@ RHPORT_PORT_SUSPEND_CHANGE_MASK
Definition: ohci.c:100
@ RHPORT_PORT_RESET_CHANGE_MASK
Definition: ohci.c:102
@ RHPORT_PORT_RESET_STATUS_MASK
write '1' to reset port
Definition: ohci.c:93
@ RHPORT_OVER_CURRENT_CHANGE_MASK
Definition: ohci.c:101
@ RHPORT_PORT_ENABLE_CHANGE_MASK
Definition: ohci.c:99
@ RHPORT_PORT_ENABLE_STATUS_MASK
Definition: ohci.c:90
tusb_speed_t hcd_port_speed_get(uint8_t hostid)
Definition: ohci.c:276
static bool gtd_is_control(ohci_gtd_t const *const p_qtd)
Definition: ohci.c:598
bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: ohci.c:181
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc)
Definition: ohci.c:455
static ohci_ed_t * ed_find_free(void)
Definition: ohci.c:383
static ohci_ed_t * gtd_get_ed(ohci_gtd_t const *const p_qtd)
Definition: ohci.c:603
static void ed_list_remove_by_addr(ohci_ed_t *p_head, uint8_t dev_addr)
Definition: ohci.c:401
static ohci_td_item_t * list_reverse(ohci_td_item_t *td_head)
Definition: ohci.c:579
bool hcd_port_connect_status(uint8_t hostid)
Definition: ohci.c:271
void hcd_port_reset(uint8_t hostid)
Definition: ohci.c:261
static void ed_list_insert(ohci_ed_t *p_pre, ohci_ed_t *p_ed)
Definition: ohci.c:395
@ OHCI_CONTROL_CONTROL_BULK_RATIO
This specifies the service ratio between Control and Bulk EDs. 0 = 1:1, 3 = 4:1.
Definition: ohci.c:59
@ OHCI_CONTROL_LIST_ISOCHRONOUS_ENABLE_MASK
Definition: ohci.c:61
@ OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK
Definition: ohci.c:62
@ OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK
Definition: ohci.c:60
@ OHCI_CONTROL_LIST_BULK_ENABLE_MASK
Definition: ohci.c:63
@ OHCI_INT_ON_COMPLETE_NO
Definition: ohci.c:126
@ OHCI_INT_ON_COMPLETE_YES
Definition: ohci.c:125
ohci_gtd_t
Definition: ohci.h:93
ohci_ed_t
Definition: ohci.h:128
ohci_data_t
Definition: ohci.h:183
ohci_td_item_t
Definition: ohci.h:70
TU_ATTR_WEAK void osal_task_delay(uint32_t msec)
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint8_t bInterval
Definition: tusb_types.h:372
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint8_t bEndpointAddress
Definition: video.h:306
uint16_t expected_bytes
Definition: ohci.h:158
uint8_t speed
Definition: hcd.h:97
TU_ATTR_WEAK void * tusb_app_phys_to_virt(void *phys_addr)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align4k(uint32_t value)
Definition: tusb_common.h:172
TU_ATTR_WEAK void * tusb_app_virt_to_phys(void *virt_addr)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align16(uint32_t value)
Definition: tusb_common.h:170
static TU_ATTR_ALWAYS_INLINE uint32_t tu_offset4k(uint32_t value)
Definition: tusb_common.h:173
tusb_speed_t
defined base on EHCI specs value for Endpoint Speed
Definition: tusb_types.h:49
@ TUSB_SPEED_FULL
Definition: tusb_types.h:50
@ TUSB_SPEED_LOW
Definition: tusb_types.h:51
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
Definition: tusb_types.h:507
xfer_result_t
Definition: tusb_types.h:236
@ XFER_RESULT_FAILED
Definition: tusb_types.h:238
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
@ XFER_RESULT_STALLED
Definition: tusb_types.h:239
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
tusb_xfer_type_t
defined base on USB Specs Endpoint's bmAttributes
Definition: tusb_types.h:58
@ TUSB_XFER_CONTROL
Definition: tusb_types.h:59
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
@ TUSB_XFER_INTERRUPT
Definition: tusb_types.h:62
@ TUSB_XFER_BULK
Definition: tusb_types.h:61
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
Definition: tusb_types.h:511