* SUCH DAMAGE.
*/
-#define USB_DEBUG
+//#define USB_DEBUG
#include <arch/virtual.h>
#include <usb/usb.h>
hci_t *controller = new_controller ();
if (!controller)
- usb_fatal("Could not create USB controller instance.\n");
+ fatal("Could not create USB controller instance.\n");
controller->instance = malloc (sizeof (ohci_t));
if(!controller->instance)
- usb_fatal("Not enough memory creating USB controller instance.\n");
+ fatal("Not enough memory creating USB controller instance.\n");
controller->start = ohci_start;
controller->stop = ohci_stop;
OHCI_INST (controller)->opreg->HcHCCA = virt_to_phys(OHCI_INST (controller)->hcca);
OHCI_INST (controller)->opreg->HcControl &= ~IsochronousEnable; // unused by this driver
- OHCI_INST (controller)->opreg->HcControl |= BulkListEnable; // always enabled. OHCI still sleeps on BulkListFilled
- OHCI_INST (controller)->opreg->HcControl |= ControlListEnable; // dito
- OHCI_INST (controller)->opreg->HcControl |= PeriodicListEnable; // FIXME: setup interrupt data structures and enable all the time
// disable everything, contrary to what OHCI spec says in 5.1.1.4, as we don't need IRQs
OHCI_INST (controller)->opreg->HcInterruptEnable = 1<<31;
OHCI_INST (controller)->opreg->HcInterruptDisable = ~(1<<31);
#ifdef USB_DEBUG
static const char *spaces=" ";
const char *spc=spaces+(10-level);
-#endif
- debug("%std at %x (%s), condition code: %s\n", spc, cur, direction[cur->direction], completion_codes[cur->condition_code & 0xf]);
+ debug("%std at %x (%s), condition code: %s\n", spc, cur, direction[(cur->config & TD_DIRECTION_MASK) >> TD_DIRECTION_SHIFT],
+ completion_codes[(cur->config & TD_CC_MASK) >> TD_CC_SHIFT]);
debug("%s toggle: %x\n", spc, cur->toggle);
+#endif
}
static int
/* wait for results */
while (((head->head_pointer & ~3) != head->tail_pointer) &&
!(head->head_pointer & 1) &&
- ((((td_t*)phys_to_virt(head->head_pointer & ~3))->condition_code & 0xf)>=0xe)) {
+ ((((td_t*)phys_to_virt(head->head_pointer & ~3))->config & TD_CC_MASK) >= TD_CC_NOACCESS)) {
debug("intst: %x; ctrl: %x; cmdst: %x; head: %x -> %x, tail: %x, condition: %x\n",
OHCI_INST(dev->controller)->opreg->HcInterruptStatus,
OHCI_INST(dev->controller)->opreg->HcControl,
head->head_pointer,
((td_t*)phys_to_virt(head->head_pointer & ~3))->next_td,
head->tail_pointer,
- ((td_t*)phys_to_virt(head->head_pointer & ~3))->condition_code);
+ (((td_t*)phys_to_virt(head->head_pointer & ~3))->config & TD_CC_MASK) >> TD_CC_SHIFT);
mdelay(1);
}
+ mdelay(5);
if (OHCI_INST(dev->controller)->opreg->HcInterruptStatus & WritebackDoneHead) {
debug("done queue:\n");
debug("%x, %x\n", OHCI_INST(dev->controller)->hcca->HccaDoneHead, phys_to_virt(OHCI_INST(dev->controller)->hcca->HccaDoneHead));
}
td_t *done_queue = NULL;
td_t *done_head = (td_t*)phys_to_virt(OHCI_INST(dev->controller)->hcca->HccaDoneHead);
- OHCI_INST(dev->controller)->opreg->HcInterruptStatus = WritebackDoneHead;
while (1) {
td_t *oldnext = (td_t*)phys_to_virt(done_head->next_td);
if (oldnext == done_queue) break; /* last element refers to second to last, ie. endless loop */
for (cur = done_queue; cur != 0; cur = (td_t*)cur->next_td) {
dump_td(cur, 1);
}
+ OHCI_INST(dev->controller)->opreg->HcInterruptStatus &= ~WritebackDoneHead;
}
if (head->head_pointer & 1) {
}
tds[td_count + 3].next_td = 0;
- tds[0].direction = OHCI_SETUP;
- tds[0].toggle_from_td = 1;
- tds[0].toggle = 0;
- tds[0].error_count = 0;
- tds[0].delay_interrupt = 7;
- tds[0].condition_code = 0xf;
+ tds[0].config = TD_DIRECTION_SETUP |
+ TD_DELAY_INTERRUPT_NODELAY |
+ TD_TOGGLE_FROM_TD |
+ TD_TOGGLE_DATA0 |
+ TD_CC_NOACCESS;
tds[0].current_buffer_pointer = virt_to_phys(devreq);
tds[0].buffer_end = virt_to_phys(devreq + drlen - 1);
while (pages > 0) {
cur++;
- cur->direction = (dir==IN)?OHCI_IN:OHCI_OUT;
- cur->toggle_from_td = 0;
- cur->toggle = 1;
- cur->error_count = 0;
- cur->delay_interrupt = 7;
- cur->condition_code = 0xf;
+ cur->config = (dir==IN)?TD_DIRECTION_IN:TD_DIRECTION_OUT |
+ TD_DELAY_INTERRUPT_NODELAY |
+ TD_TOGGLE_FROM_ED |
+ TD_CC_NOACCESS;
cur->current_buffer_pointer = virt_to_phys(data);
pages--;
int consumed = (4096 - ((unsigned long)data % 4096));
}
cur++;
- cur->direction = (dir==IN)?OHCI_OUT:OHCI_IN;
- cur->toggle_from_td = 1;
- cur->toggle = 1;
- cur->error_count = 0;
- cur->delay_interrupt = 7;
- cur->condition_code = 0xf;
+ cur->config = (dir==IN)?TD_DIRECTION_OUT:TD_DIRECTION_IN |
+ TD_DELAY_INTERRUPT_NODELAY |
+ TD_TOGGLE_FROM_TD |
+ TD_TOGGLE_DATA1 |
+ TD_CC_NOACCESS;
cur->current_buffer_pointer = 0;
cur->buffer_end = 0;
/* Data structures */
ed_t *head = memalign(sizeof(ed_t), sizeof(ed_t));
memset((void*)head, 0, sizeof(*head));
- head->function_address = dev->address;
- head->endpoint_number = 0;
- head->direction = OHCI_FROM_TD;
- head->lowspeed = dev->speed;
- head->format = 0;
- head->maximum_packet_size = dev->endpoints[0].maxpacketsize;
+ head->config = (dev->address << ED_FUNC_SHIFT) |
+ (0 << ED_EP_SHIFT) |
+ (OHCI_FROM_TD << ED_DIR_SHIFT) |
+ (dev->speed?ED_LOWSPEED:0) |
+ (dev->endpoints[0].maxpacketsize << ED_MPS_SHIFT);
head->tail_pointer = virt_to_phys(cur);
head->head_pointer = virt_to_phys(tds);
- head->halted = 0;
- head->toggle = 0;
- debug("doing control transfer with %x. first_td at %x\n", head->function_address, virt_to_phys(tds));
+ debug("doing control transfer with %x. first_td at %x\n", head->config & ED_FUNC_MASK, virt_to_phys(tds));
/* activate schedule */
OHCI_INST(dev->controller)->opreg->HcControlHeadED = virt_to_phys(head);
+ OHCI_INST(dev->controller)->opreg->HcControl |= ControlListEnable;
OHCI_INST(dev->controller)->opreg->HcCommandStatus = ControlListFilled;
int failure = wait_for_ed(dev, head);
+ OHCI_INST(dev->controller)->opreg->HcControl &= ~ControlListEnable;
/* free memory */
free((void*)tds);
}
for (cur = tds; cur->next_td != 0; cur++) {
- cur->toggle_from_td = 0;
- cur->error_count = 0;
- cur->delay_interrupt = 7;
- cur->condition_code = 0xf;
- cur->direction = (ep->direction==IN)?OHCI_IN:OHCI_OUT;
+ cur->config = (ep->direction==IN)?TD_DIRECTION_IN:TD_DIRECTION_OUT |
+ TD_DELAY_INTERRUPT_NODELAY |
+ TD_TOGGLE_FROM_ED |
+ TD_CC_NOACCESS;
+ cur->current_buffer_pointer = virt_to_phys(data);
pages--;
if (dalen == 0) {
/* magic TD for empty packet transfer */
/* Data structures */
ed_t *head = memalign(sizeof(ed_t), sizeof(ed_t));
memset((void*)head, 0, sizeof(*head));
- head->function_address = ep->dev->address;
- head->endpoint_number = ep->endpoint & 0xf;
- head->direction = (ep->direction==IN)?OHCI_IN:OHCI_OUT;
- head->lowspeed = ep->dev->speed;
- head->format = 0;
- head->maximum_packet_size = ep->maxpacketsize;
+ head->config = (ep->dev->address << ED_FUNC_SHIFT) |
+ ((ep->endpoint & 0xf) << ED_EP_SHIFT) |
+ (((ep->direction==IN)?OHCI_IN:OHCI_OUT) << ED_DIR_SHIFT) |
+ (ep->dev->speed?ED_LOWSPEED:0) |
+ (ep->maxpacketsize << ED_MPS_SHIFT);
head->tail_pointer = virt_to_phys(cur);
- head->head_pointer = virt_to_phys(tds);
- head->halted = 0;
- head->toggle = ep->toggle;
+ head->head_pointer = virt_to_phys(tds) | (ep->toggle?ED_TOGGLE:0);
- debug("doing bulk transfer with %x(%x). first_td at %x, last %x\n", head->function_address, head->endpoint_number, virt_to_phys(tds), virt_to_phys(cur));
+ debug("doing bulk transfer with %x(%x). first_td at %x, last %x\n", head->config & ED_FUNC_MASK,
+ (head->config & ED_EP_MASK) >> ED_EP_SHIFT, virt_to_phys(tds), virt_to_phys(cur));
/* activate schedule */
OHCI_INST(ep->dev->controller)->opreg->HcBulkHeadED = virt_to_phys(head);
+ OHCI_INST(ep->dev->controller)->opreg->HcControl |= BulkListEnable;
OHCI_INST(ep->dev->controller)->opreg->HcCommandStatus = BulkListFilled;
int failure = wait_for_ed(ep->dev, head);
+ OHCI_INST(ep->dev->controller)->opreg->HcControl &= ~BulkListEnable;
- ep->toggle = head->toggle;
+ ep->toggle = head->head_pointer & ED_TOGGLE;
/* free memory */
free((void*)tds);