Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 1f6eb7d6b2a2f1768e69c5c79ecfd1d85a8ac555)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision 78ab6d44673765571d9cc1cecc8d2943a82e2a45)
@@ -147,7 +147,6 @@
 
 	fibril_mutex_initialize(&instance->guard);
+
 	hc_gain_control(instance);
-
-	rh_init(&instance->rh, instance->registers);
 
 	if (!interrupts) {
@@ -157,7 +156,12 @@
 	}
 
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
+	rh_init(&instance->rh, instance->registers);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Get number of commands used in IRQ code.
+ * @return Number of commands.
+ */
 size_t hc_irq_cmd_count(void)
 {
@@ -165,4 +169,12 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Generate IRQ code commands.
+ * @param[out] cmds Place to store the commands.
+ * @param[in] cmd_size Size of the place (bytes).
+ * @param[in] regs Physical address of device's registers.
+ * @param[in] reg_size Size of the register area (bytes).
+ *
+ * @return Error code.
+ */
 int hc_get_irq_commands(
     irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
@@ -172,6 +184,6 @@
 		return EOVERFLOW;
 
-	/* Create register mapping to use in IRQ handler
-	 * this mapping should be present in kernel only.
+	/* Create register mapping to use in IRQ handler.
+	 * This mapping should be present in kernel only.
 	 * Remove it from here when kernel knows how to create mappings
 	 * and accepts physical addresses in IRQ code.
@@ -181,5 +193,7 @@
 
 	/* Some bogus access to force create mapping. DO NOT remove,
-	 * unless whole virtual addresses in irq is replaced */
+	 * unless whole virtual addresses in irq is replaced
+	 * NOTE: Compiler won't remove this as ohci_regs_t members
+	 * are declared volatile. */
 	registers->revision;
 
@@ -195,5 +209,5 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Create and register endpoint structures
+/** Create and register endpoint structures.
  *
  * @param[in] instance OHCI driver structure.
@@ -444,4 +458,7 @@
 /** Turn off any (BIOS)driver that might be in control of the device.
  *
+ * This function implements routines described in chapter 5.1.1.3 of the OHCI
+ * specification (page 40, pdf page 54).
+ *
  * @param[in] instance OHCI hc driver structure.
  */
@@ -449,14 +466,22 @@
 {
 	assert(instance);
+
 	usb_log_debug("Requesting OHCI control.\n");
-	/* 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);
-	/* Do not change A20 state */
-	*ohci_emulation_reg &= 0x100;
-	usb_log_debug("OHCI legacy register %p: %x.\n",
-	    ohci_emulation_reg, *ohci_emulation_reg);
+	if (instance->registers->revision & R_LEGACY_FLAG) {
+		/* Turn off legacy emulation, it should be enough to zero
+		 * the lowest bit, but it caused problems. Thus clear all
+		 * except GateA20 (causes restart on some hw).
+		 * See page 145 of the specs for details.
+		 */
+		volatile uint32_t *ohci_emulation_reg =
+		(uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
+		usb_log_debug("OHCI legacy register %p: %x.\n",
+		    ohci_emulation_reg, *ohci_emulation_reg);
+		/* Zero everything but A20State */
+		*ohci_emulation_reg &= 0x100;
+		usb_log_debug(
+		    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
+		    ohci_emulation_reg, *ohci_emulation_reg);
+	}
 
 	/* Interrupt routing enabled => smm driver is active */
@@ -464,15 +489,15 @@
 		usb_log_debug("SMM driver: request ownership change.\n");
 		instance->registers->command_status |= CS_OCR;
+		/* Hope that SMM actually knows its stuff or we can hang here */
 		while (instance->registers->control & C_IR) {
 			async_usleep(1000);
 		}
 		usb_log_info("SMM driver: Ownership taken.\n");
-		instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
+		C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
 		async_usleep(50000);
 		return;
 	}
 
-	const unsigned hc_status =
-	    (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
+	const unsigned hc_status = C_HCFS_GET(instance->registers->control);
 	/* Interrupt routing disabled && status != USB_RESET => BIOS active */
 	if (hc_status != C_HCFS_RESET) {
@@ -482,6 +507,6 @@
 			return;
 		}
-		/* HC is suspended assert resume for 20ms */
-		instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
+		/* HC is suspended assert resume for 20ms, */
+		C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
 		async_usleep(20000);
 		usb_log_info("BIOS driver: HC resumed.\n");
@@ -561,5 +586,5 @@
 	    instance->registers->periodic_start, frame_length);
 
-	instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
+	C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
 	usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
 	    instance->registers->control);
Index: uspace/drv/bus/usb/ohci/ohci_regs.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_regs.h	(revision 1f6eb7d6b2a2f1768e69c5c79ecfd1d85a8ac555)
+++ uspace/drv/bus/usb/ohci/ohci_regs.h	(revision 78ab6d44673765571d9cc1cecc8d2943a82e2a45)
@@ -36,7 +36,13 @@
 #include <stdint.h>
 
+#define LEGACY_REGS_OFFSET 0x100
+
 /** OHCI memory mapped registers structure */
 typedef struct ohci_regs {
 	const volatile uint32_t revision;
+#define R_REVISION_MASK (0x3f)
+#define R_REVISION_SHIFT (0)
+#define R_LEGACY_FLAG   (0x80)
+
 	volatile uint32_t control;
 #define C_CSBR_MASK (0x3) /* Control-bulk service ratio */
@@ -58,4 +64,13 @@
 #define C_HCFS_SUSPEND     (0x3)
 #define C_HCFS_SHIFT       (6)
+
+#define C_HCFS_GET(reg) \
+	((reg >> C_HCFS_SHIFT) & C_HCFS_MASK)
+#define C_HCFS_SET(reg, hcfs_state) \
+do { \
+	reg = (reg & ~(C_HCFS_MASK << C_HCFS_SHIFT)) \
+	    | ((hcfs_state & C_HCFS_MASK) << C_HCFS_SHIFT); \
+} while (0)
+
 
 #define C_IR  (1 << 8)   /* Interrupt routing, make sure it's 0 */
