Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision 049eb877f0d0f895e826c16311bcf58d26511f0a)
+++ uspace/drv/ohci/hc.c	(revision 87906500fff813e7fa98e3c24caafe7911fef646)
@@ -47,4 +47,6 @@
 static void hc_gain_control(hc_t *instance);
 static void hc_init_hw(hc_t *instance);
+static int hc_init_transfer_lists(hc_t *instance);
+static int hc_init_memory(hc_t *instance);
 /*----------------------------------------------------------------------------*/
 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
@@ -59,9 +61,18 @@
 	    &instance->manager, hub_address, hub_fun->handle);
 
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	assert(ep);
+	int ret = endpoint_init(ep, hub_address, 0, USB_DIRECTION_BOTH,
+	    USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64);
+	assert(ret == EOK);
+	ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, 0);
+	assert(ret == EOK);
+
 	char *match_str = NULL;
-	int ret = asprintf(&match_str, "usb&class=hub");
-	ret = (match_str == NULL) ? ret : EOK;
+	ret = asprintf(&match_str, "usb&class=hub");
+//	ret = (match_str == NULL) ? ret : EOK;
 	if (ret < 0) {
-		usb_log_error("Failed to create root hub match-id string.\n");
+		usb_log_error(
+		    "Failed(%d) to create root hub match-id string.\n", ret);
 		return ret;
 	}
@@ -97,4 +108,12 @@
 	    ret, str_error(ret));
 
+	hc_gain_control(instance);
+	ret = hc_init_memory(instance);
+	CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures:%s.\n",
+	    ret, str_error(ret));
+	hc_init_hw(instance);
+
+	rh_init(&instance->rh, dev, instance->registers);
+
 	if (!interrupts) {
 		instance->interrupt_emulator =
@@ -103,11 +122,4 @@
 	}
 
-	hc_gain_control(instance);
-
-	rh_init(&instance->rh, dev, instance->registers);
-
-	hc_init_hw(instance);
-
-	/* TODO: implement */
 	return EOK;
 }
@@ -117,9 +129,30 @@
 	assert(instance);
 	assert(batch);
+
+	/* check for root hub communication */
 	if (batch->target.address == instance->rh.address) {
 		return rh_request(&instance->rh, batch);
 	}
-	/* TODO: implement */
-	return ENOTSUP;
+
+	transfer_list_add_batch(
+	    instance->transfers[batch->transfer_type], batch);
+
+	switch (batch->transfer_type) {
+	case USB_TRANSFER_CONTROL:
+		instance->registers->control &= ~C_CLE;
+		instance->registers->command_status |= CS_CLF;
+		usb_log_debug2("Set control transfer filled: %x.\n",
+			instance->registers->command_status);
+		instance->registers->control |= C_CLE;
+		break;
+	case USB_TRANSFER_BULK:
+		instance->registers->command_status |= CS_BLF;
+		usb_log_debug2("Set bulk transfer filled: %x.\n",
+			instance->registers->command_status);
+		break;
+	default:
+		break;
+	}
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -127,5 +160,5 @@
 {
 	assert(instance);
-	if (status == 0)
+	if ((status & ~IS_SF) == 0) /* ignore sof status */
 		return;
 	if (status & IS_RHSC)
@@ -134,6 +167,18 @@
 	usb_log_info("OHCI interrupt: %x.\n", status);
 
-	/* TODO: Check for further interrupt causes */
-	/* TODO: implement */
+
+	LIST_INITIALIZE(done);
+	transfer_list_remove_finished(&instance->transfers_interrupt, &done);
+	transfer_list_remove_finished(&instance->transfers_isochronous, &done);
+	transfer_list_remove_finished(&instance->transfers_control, &done);
+	transfer_list_remove_finished(&instance->transfers_bulk, &done);
+
+	while (!list_empty(&done)) {
+		link_t *item = done.next;
+		list_remove(item);
+		usb_transfer_batch_t *batch =
+		    list_get_instance(item, usb_transfer_batch_t, link);
+		usb_transfer_batch_finish(batch);
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -154,12 +199,19 @@
 {
 	assert(instance);
+	/* Turn off legacy emulation */
+	volatile uint32_t *ohci_emulation_reg =
+	    (uint32_t*)((char*)instance->registers + 0x100);
+	usb_log_debug("OHCI legacy register %p: %x.\n",
+		ohci_emulation_reg, *ohci_emulation_reg);
+	*ohci_emulation_reg = 0;
+
 	/* Interrupt routing enabled => smm driver is active */
 	if (instance->registers->control & C_IR) {
-		usb_log_info("Found SMM driver requesting ownership change.\n");
+		usb_log_debug("SMM driver: request ownership change.\n");
 		instance->registers->command_status |= CS_OCR;
 		while (instance->registers->control & C_IR) {
 			async_usleep(1000);
 		}
-		usb_log_info("Ownership taken from SMM driver.\n");
+		usb_log_info("SMM driver: Ownership taken.\n");
 		return;
 	}
@@ -169,7 +221,7 @@
 	/* Interrupt routing disabled && status != USB_RESET => BIOS active */
 	if (hc_status != C_HCFS_RESET) {
-		usb_log_info("Found BIOS driver.\n");
+		usb_log_debug("BIOS driver found.\n");
 		if (hc_status == C_HCFS_OPERATIONAL) {
-			usb_log_info("HC operational(BIOS).\n");
+			usb_log_info("BIOS driver: HC operational.\n");
 			return;
 		}
@@ -177,4 +229,5 @@
 		instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
 		async_usleep(20000);
+		usb_log_info("BIOS driver: HC resumed.\n");
 		return;
 	}
@@ -182,32 +235,137 @@
 	/* HC is in reset (hw startup) => no other driver
 	 * maintain reset for at least the time specified in USB spec (50 ms)*/
+	usb_log_info("HC found in reset.\n");
 	async_usleep(50000);
-
-	/* turn off legacy emulation */
-	volatile uint32_t *ohci_emulation_reg =
-	    (uint32_t*)((char*)instance->registers + 0x100);
-	usb_log_info("OHCI legacy register status %p: %x.\n",
-		ohci_emulation_reg, *ohci_emulation_reg);
-	*ohci_emulation_reg = 0;
-
 }
 /*----------------------------------------------------------------------------*/
 void hc_init_hw(hc_t *instance)
 {
-	assert(instance);
+	/* OHCI guide page 42 */
+	assert(instance);
+	usb_log_debug2("Started hc initialization routine.\n");
+
+	/* Save contents of fm_interval register */
 	const uint32_t fm_interval = instance->registers->fm_interval;
+	usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
+
+	/* Reset hc */
+	usb_log_debug2("HC reset.\n");
+	size_t time = 0;
 	instance->registers->command_status = CS_HCR;
-	async_usleep(10);
+	while (instance->registers->command_status & CS_HCR) {
+		async_usleep(10);
+		time += 10;
+	}
+	usb_log_debug2("HC reset complete in %zu us.\n", time);
+
+	/* Restore fm_interval */
 	instance->registers->fm_interval = fm_interval;
 	assert((instance->registers->command_status & CS_HCR) == 0);
+
 	/* hc is now in suspend state */
-	/* TODO: init HCCA block */
-	/* TODO: init queues */
-	/* TODO: enable queues */
-	/* TODO: enable interrupts */
-	/* TODO: set periodic start to 90% */
+	usb_log_debug2("HC should be in suspend state(%x).\n",
+	    instance->registers->control);
+
+	/* Enable queues */
+	instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
+	usb_log_debug2("All queues enabled(%x).\n",
+	    instance->registers->control);
+
+	/* Disable interrupts */
+	instance->registers->interrupt_disable = I_SF | I_OC;
+	usb_log_debug2("Disabling interrupts: %x.\n",
+	    instance->registers->interrupt_disable);
+	instance->registers->interrupt_disable = I_MI;
+	usb_log_debug2("Enabled interrupts: %x.\n",
+	    instance->registers->interrupt_enable);
+
+	/* Set periodic start to 90% */
+	uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
+	instance->registers->periodic_start = (frame_length / 10) * 9;
+	usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
+	    instance->registers->periodic_start,
+	    instance->registers->periodic_start, frame_length);
 
 	instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
-	usb_log_info("OHCI HC up and running.\n");
+	usb_log_info("OHCI HC up and running(%x).\n",
+	    instance->registers->control);
+}
+/*----------------------------------------------------------------------------*/
+int hc_init_transfer_lists(hc_t *instance)
+{
+	assert(instance);
+
+#define SETUP_TRANSFER_LIST(type, name) \
+do { \
+	int ret = transfer_list_init(&instance->type, name); \
+	if (ret != EOK) { \
+		usb_log_error("Failed(%d) to setup %s transfer list.\n", \
+		    ret, name); \
+		transfer_list_fini(&instance->transfers_isochronous); \
+		transfer_list_fini(&instance->transfers_interrupt); \
+		transfer_list_fini(&instance->transfers_control); \
+		transfer_list_fini(&instance->transfers_bulk); \
+	} \
+} while (0)
+
+	SETUP_TRANSFER_LIST(transfers_isochronous, "ISOCHRONOUS");
+	SETUP_TRANSFER_LIST(transfers_interrupt, "INTERRUPT");
+	SETUP_TRANSFER_LIST(transfers_control, "CONTROL");
+	SETUP_TRANSFER_LIST(transfers_bulk, "BULK");
+
+	transfer_list_set_next(&instance->transfers_interrupt,
+	    &instance->transfers_isochronous);
+
+	/* Assign pointers to be used during scheduling */
+	instance->transfers[USB_TRANSFER_INTERRUPT] =
+	  &instance->transfers_interrupt;
+	instance->transfers[USB_TRANSFER_ISOCHRONOUS] =
+	  &instance->transfers_interrupt;
+	instance->transfers[USB_TRANSFER_CONTROL] =
+	  &instance->transfers_control;
+	instance->transfers[USB_TRANSFER_BULK] =
+	  &instance->transfers_bulk;
+
+	return EOK;
+#undef CHECK_RET_CLEAR_RETURN
+}
+/*----------------------------------------------------------------------------*/
+int hc_init_memory(hc_t *instance)
+{
+	assert(instance);
+	/* Init queues */
+	hc_init_transfer_lists(instance);
+
+	/*Init HCCA */
+	instance->hcca = malloc32(sizeof(hcca_t));
+	if (instance->hcca == NULL)
+		return ENOMEM;
+	bzero(instance->hcca, sizeof(hcca_t));
+	instance->registers->hcca = addr_to_phys(instance->hcca);
+	usb_log_debug2("OHCI HCCA initialized at %p(%p).\n",
+	    instance->hcca, instance->registers->hcca);
+
+	/* Use queues */
+	instance->registers->bulk_head = instance->transfers_bulk.list_head_pa;
+	usb_log_debug2("Bulk HEAD set to: %p(%p).\n",
+	    instance->transfers_bulk.list_head,
+	    instance->transfers_bulk.list_head_pa);
+
+	instance->registers->control_head =
+	    instance->transfers_control.list_head_pa;
+	usb_log_debug2("Control HEAD set to: %p(%p).\n",
+	    instance->transfers_control.list_head,
+	    instance->transfers_control.list_head_pa);
+
+	unsigned i = 0;
+	for (; i < 32; ++i) {
+		instance->hcca->int_ep[i] =
+		    instance->transfers_interrupt.list_head_pa;
+	}
+	usb_log_debug2("Interrupt HEADs set to: %p(%p).\n",
+	    instance->transfers_interrupt.list_head,
+	    instance->transfers_interrupt.list_head_pa);
+
+	return EOK;
 }
 /**
