summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/lib/libusb
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/SLOF/lib/libusb
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/SLOF/lib/libusb')
-rw-r--r--qemu/roms/SLOF/lib/libusb/Makefile52
-rw-r--r--qemu/roms/SLOF/lib/libusb/tools.h77
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-core.c590
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-core.h279
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ehci.c609
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ehci.h155
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-hid.c453
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-hub.c183
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-key.c446
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-key.h42
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ohci.c1055
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ohci.h217
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-slof.c61
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-xhci.c1316
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-xhci.h386
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb.code162
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb.h77
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb.in29
18 files changed, 6189 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/lib/libusb/Makefile b/qemu/roms/SLOF/lib/libusb/Makefile
new file mode 100644
index 000000000..0780489ea
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/Makefile
@@ -0,0 +1,52 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+include $(TOPCMNDIR)/make.rules
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR)
+LDFLAGS = -nostdlib
+
+TARGET = ../libusb.a
+
+
+all: $(TARGET)
+
+SRCS = usb-core.c usb-ohci.c usb-ehci.c usb-slof.c usb-key.c usb-hid.c \
+ usb-hub.c usb-xhci.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
diff --git a/qemu/roms/SLOF/lib/libusb/tools.h b/qemu/roms/SLOF/lib/libusb/tools.h
new file mode 100644
index 000000000..f531175c1
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/tools.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __TOOLS_H
+#define __TOOLS_H
+
+#include <stdint.h>
+#include <byteorder.h>
+#include <cache.h>
+
+#define PTR_U32(x) ((uint32_t) (uint64_t) (x))
+
+static inline uint32_t read_reg32(uint32_t *reg)
+{
+ return bswap_32(ci_read_32(reg));
+}
+
+static inline void write_reg32(uint32_t *reg, uint32_t value)
+{
+ mb();
+ ci_write_32(reg, bswap_32(value));
+}
+
+static inline uint8_t read_reg8(uint8_t *reg)
+{
+ return ci_read_8(reg);
+}
+
+static inline void write_reg8(uint8_t *reg, uint8_t value)
+{
+ mb();
+ ci_write_8(reg, value);
+}
+
+static inline uint16_t read_reg16(uint16_t *reg)
+{
+ return bswap_16(ci_read_16(reg));
+}
+
+static inline void write_reg16(uint16_t *reg, uint16_t value)
+{
+ mb();
+ ci_write_16(reg, bswap_16(value));
+}
+
+static inline uint64_t read_reg64(uint64_t *reg)
+{
+ return bswap_64(ci_read_64(reg));
+}
+
+static inline void write_reg64(uint64_t *reg, uint64_t value)
+{
+ mb();
+ ci_write_64(reg, bswap_64(value));
+}
+
+static inline uint32_t ci_read_reg(uint32_t *reg)
+{
+ return bswap_32(ci_read_32(reg));
+}
+
+static inline void ci_write_reg(uint32_t *reg, uint32_t value)
+{
+ mb();
+ ci_write_32(reg, bswap_32(value));
+}
+
+#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.c b/qemu/roms/SLOF/lib/libusb/usb-core.c
new file mode 100644
index 000000000..6719c5726
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-core.c
@@ -0,0 +1,590 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include "usb-core.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#define __unused __attribute__((unused))
+
+struct usb_hcd_ops *head;
+struct usb_dev *devpool;
+#define USB_DEVPOOL_SIZE 4096
+
+static struct usb_dev *usb_alloc_devpool(void)
+{
+ struct usb_dev *head, *curr, *prev;
+ unsigned int dev_count = 0, i;
+
+ head = SLOF_alloc_mem(USB_DEVPOOL_SIZE);
+ if (!head)
+ return NULL;
+
+ dev_count = USB_DEVPOOL_SIZE/sizeof(struct usb_dev);
+ dprintf("%s: %d number of devices\n", __func__, dev_count);
+ /* Although an array, link them*/
+ for (i = 0, curr = head, prev = NULL; i < dev_count; i++, curr++) {
+ if (prev)
+ prev->next = curr;
+ curr->next = NULL;
+ prev = curr;
+ }
+
+#ifdef DEBUG
+ for (i = 0, curr = head; curr; curr = curr->next)
+ printf("%s: %d dev %p\n", __func__, i++, curr);
+#endif
+
+ return head;
+}
+
+struct usb_dev *usb_devpool_get(void)
+{
+ struct usb_dev *new;
+
+ if (!devpool) {
+ devpool = usb_alloc_devpool();
+ if (!devpool)
+ return NULL;
+ }
+
+ new = devpool;
+ devpool = devpool->next;
+ memset(new, 0, sizeof(*new));
+ new->next = NULL;
+ return new;
+}
+
+void usb_devpool_put(struct usb_dev *dev)
+{
+ struct usb_dev *curr;
+ if (!dev && !devpool)
+ return;
+
+ curr = devpool;
+ while (curr->next)
+ curr = curr->next;
+ curr->next = dev;
+ dev->next = NULL;
+}
+
+#ifndef DEBUG
+#define validate_hcd_ops(dev) (dev && dev->hcidev && dev->hcidev->ops)
+#else
+int validate_hcd_ops(struct usb_dev *dev)
+{
+ int ret = true;
+
+ if (!dev) {
+ printf("dev is NULL\n");
+ ret = false;
+ } else if (!dev->hcidev) {
+ printf("hcidev is NULL\n");
+ ret = false;
+ } else if (!dev->hcidev->ops) {
+ printf("ops is NULL\n");
+ ret = false;
+ }
+ return ret;
+}
+#endif
+
+struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len)
+{
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->get_pipe)
+ return dev->hcidev->ops->get_pipe(dev, ep, buf, len);
+ else {
+ printf("%s: Failed\n", __func__);
+ return NULL;
+ }
+}
+
+void usb_put_pipe(struct usb_pipe *pipe)
+{
+ struct usb_dev *dev = NULL;
+ if (pipe && pipe->dev) {
+ dev = pipe->dev;
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->put_pipe)
+ dev->hcidev->ops->put_pipe(pipe);
+ }
+}
+
+int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf)
+{
+ struct usb_dev *dev = NULL;
+ if (pipe && pipe->dev) {
+ dev = pipe->dev;
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->poll_intr)
+ return dev->hcidev->ops->poll_intr(pipe, buf);
+ }
+ return 0;
+}
+
+void usb_hcd_register(struct usb_hcd_ops *ops)
+{
+ struct usb_hcd_ops *list;
+
+ if (!ops)
+ printf("Error");
+ dprintf("Registering %s %d\n", ops->name, ops->usb_type);
+
+ if (head) {
+ list = head;
+ while (list->next)
+ list = list->next;
+ list->next = ops;
+ } else
+ head = ops;
+}
+
+void usb_hcd_init(void *hcidev)
+{
+ struct usb_hcd_dev *dev = hcidev;
+ struct usb_hcd_ops *list = head;
+
+ if (!dev) {
+ printf("Device Error");
+ return;
+ }
+
+ while (list) {
+ if (list->usb_type == dev->type) {
+ dprintf("usb_ops(%p) for the controller found\n", list);
+ dev->ops = list;
+ dev->ops->init(dev);
+ return;
+ }
+ list = list->next;
+ }
+
+ dprintf("usb_ops for the controller not found\n");
+}
+
+void usb_hcd_exit(void *_hcidev)
+{
+ struct usb_hcd_dev *hcidev = _hcidev;
+
+ dprintf("%s: enter \n", __func__);
+ if (!hcidev) {
+ printf("Device Error");
+ return;
+ }
+
+ if (hcidev->ops->exit)
+ hcidev->ops->exit(hcidev);
+}
+
+int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct usb_dev *dev = NULL;
+ if (!pipe)
+ return false;
+ dev = pipe->dev;
+ if (validate_hcd_ops(dev) && dev->hcidev->ops->send_ctrl)
+ return dev->hcidev->ops->send_ctrl(pipe, req, data);
+ else {
+ printf("%s: Failed\n", __func__);
+ return false;
+ }
+}
+
+int usb_transfer_ctrl(void *dev, void *req, void *data)
+{
+ struct usb_pipe *pipe = NULL;
+ struct usb_dev *usbdev;
+
+ if (!dev)
+ return false;
+ usbdev = (struct usb_dev *)dev;
+ pipe = usbdev->control;
+ return usb_send_ctrl(pipe, req, data);
+}
+
+int usb_transfer_bulk(void *dev, int dir, void *td, void *td_phys, void *data, int size)
+{
+ struct usb_pipe *pipe = NULL;
+ struct usb_dev *usbdev;
+
+ if (!dev)
+ return false;
+ usbdev = (struct usb_dev *)dev;
+ pipe = (dir == USB_PIPE_OUT) ? usbdev->bulk_out : usbdev->bulk_in;
+ if (!pipe)
+ return false;
+ if (validate_hcd_ops(usbdev) && usbdev->hcidev->ops->transfer_bulk)
+ return usbdev->hcidev->ops->transfer_bulk(pipe, td, td_phys, data, size);
+ else {
+ printf("%s: Failed\n", __func__);
+ return false;
+ }
+}
+
+/*
+ * USB Specification 1.1
+ * 9.3 USB Device Requests
+ * 9.4 Standard Device Requests
+ */
+static int usb_set_address(struct usb_dev *dev, uint32_t port)
+{
+ struct usb_dev_req req;
+ struct usb_hcd_dev *hcidev;
+
+ if (!dev)
+ return false;
+
+ hcidev = dev->hcidev;
+ req.bmRequestType = 0;
+ req.bRequest = REQ_SET_ADDRESS;
+ req.wIndex = 0;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16((uint16_t)(hcidev->nextaddr));
+ if (usb_send_ctrl(dev->control, &req, NULL)) {
+ dev->addr = hcidev->nextaddr++;
+ return true;
+ } else
+ return false;
+}
+
+static int usb_get_device_descr(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = 0x80;
+ req.bRequest = REQ_GET_DESCRIPTOR;
+ req.wIndex = 0;
+ req.wLength = cpu_to_le16((uint16_t) size);
+ req.wValue = cpu_to_le16(DESCR_TYPE_DEVICE << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+static int usb_get_config_descr(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = 0x80;
+ req.bRequest = REQ_GET_DESCRIPTOR;
+ req.wIndex = 0;
+ req.wLength = cpu_to_le16((uint16_t) size);
+ req.wValue = cpu_to_le16(DESCR_TYPE_CONFIGURATION << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+
+}
+
+static int usb_set_config(struct usb_dev *dev, uint8_t cfg_value)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = 0x00;
+ req.bRequest = REQ_SET_CONFIGURATION;
+ req.wIndex = 0;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16(0x00FF & cfg_value);
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+static int usb_clear_halt(struct usb_pipe *pipe)
+{
+ struct usb_dev_req req;
+ struct usb_dev *dev;
+
+ if (pipe && pipe->dev) {
+ dev = pipe->dev;
+ dprintf("Clearing port %d dir %d type %d\n",
+ pipe->epno, pipe->dir, pipe->type);
+ req.bmRequestType = REQT_DIR_OUT | REQT_REC_EP;
+ req.bRequest = REQ_CLEAR_FEATURE;
+ req.wValue = FEATURE_ENDPOINT_HALT;
+ req.wIndex = cpu_to_le16(pipe->epno | pipe->dir);
+ req.wLength = 0;
+ return usb_send_ctrl(dev->control, &req, NULL);
+ }
+ return false;
+}
+
+int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ void *buf, size_t len)
+{
+ uint8_t dir, type;
+
+ dir = (ep->bEndpointAddress & 0x80) >> 7;
+ type = ep->bmAttributes & USB_EP_TYPE_MASK;
+
+ dprintf("EP: %s: %d size %d type %d\n", dir ? "IN " : "OUT",
+ ep->bEndpointAddress & 0xF, le16_to_cpu(ep->wMaxPacketSize),
+ type);
+ if (type == USB_EP_TYPE_BULK) {
+ if (dir)
+ dev->bulk_in = usb_get_pipe(dev, ep, buf, len);
+ else
+ dev->bulk_out = usb_get_pipe(dev, ep, buf, len);
+ } else if (type == USB_EP_TYPE_INTR)
+ dev->intr = usb_get_pipe(dev, ep, buf, len);
+
+ return true;
+}
+
+static void usb_dev_copy_epdesc(struct usb_dev *dev, struct usb_ep_descr *ep)
+{
+ uint32_t ep_cnt;
+
+ ep_cnt = dev->ep_cnt;
+ if (ep_cnt < USB_DEV_EP_MAX)
+ memcpy((void *)&dev->ep[ep_cnt], ep, sizeof(*ep));
+ else
+ dprintf("usb-core: only %d EPs supported\n", USB_DEV_EP_MAX);
+ dev->ep_cnt++;
+}
+
+int usb_hid_init(void *vdev)
+{
+ struct usb_dev *dev;
+ dev = (struct usb_dev *) vdev;
+ if (!dev)
+ return false;
+ if (dev->class == DEV_HID_KEYB)
+ usb_hid_kbd_init(dev);
+ return true;
+}
+
+int usb_hid_exit(void *vdev)
+{
+ struct usb_dev *dev;
+ dev = (struct usb_dev *) vdev;
+ if (!dev)
+ return false;
+ if (dev->class == DEV_HID_KEYB)
+ usb_hid_kbd_exit(dev);
+ return true;
+}
+
+#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
+
+int usb_msc_init(void *vdev)
+{
+ struct usb_dev *dev;
+ int i;
+
+ dev = (struct usb_dev *) vdev;
+ dprintf("%s: enter %x\n", __func__, dev->class);
+ if (!dev)
+ return false;
+ if (usb_get_intf_class(dev->class) == 8) {
+ for (i = 0; i < dev->ep_cnt; i++) {
+ if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK)
+ == USB_EP_TYPE_BULK)
+ usb_dev_populate_pipe(dev, &dev->ep[i], NULL, 0);
+ }
+ }
+ return true;
+}
+
+int usb_msc_exit(void *vdev)
+{
+ struct usb_dev *dev;
+ dev = (struct usb_dev *) vdev;
+ dprintf("%s: enter %x\n", __func__, dev->class);
+ if (!dev)
+ return false;
+ if (usb_get_intf_class(dev->class) == 8) {
+ if (dev->bulk_in)
+ usb_put_pipe(dev->bulk_in);
+ if (dev->bulk_out)
+ usb_put_pipe(dev->bulk_out);
+ }
+ return true;
+}
+
+static int usb_msc_reset(struct usb_dev *dev)
+{
+ struct usb_dev_req req;
+
+ if (!dev)
+ return false;
+
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+ req.bRequest = 0xFF;
+ req.wLength = 0;
+ req.wValue = 0;
+ req.wIndex = cpu_to_le16(dev->intf_num);
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+void usb_msc_resetrecovery(struct usb_dev *dev)
+{
+ // usb_msc_reset(dev);
+ usb_clear_halt(dev->bulk_in);
+ usb_clear_halt(dev->bulk_out);
+ SLOF_msleep(2);
+}
+
+static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *cfg,
+ uint8_t *ptr, uint16_t len)
+{
+ struct usb_dev_intf_descr *intf = NULL;
+ struct usb_ep_descr *ep = NULL;
+ struct usb_dev_hid_descr *hid __unused = NULL;
+ uint8_t desc_len, desc_type;
+
+ len -= sizeof(struct usb_dev_config_descr);
+ ptr = (uint8_t *)(ptr + sizeof(struct usb_dev_config_descr));
+
+ while (len > 0) {
+ desc_len = *ptr;
+ desc_type = *(ptr + 1);
+ switch (desc_type) {
+ case DESCR_TYPE_INTERFACE:
+ intf = (struct usb_dev_intf_descr *)ptr;
+ dev->class = intf->bInterfaceClass << 16 |
+ intf->bInterfaceSubClass << 8 |
+ intf->bInterfaceProtocol;
+ break;
+ case DESCR_TYPE_ENDPOINT:
+ ep = (struct usb_ep_descr *)ptr;
+ dev->intf_num = intf->bInterfaceNumber;
+ usb_dev_copy_epdesc(dev, ep);
+ break;
+ case DESCR_TYPE_HID:
+ hid = (struct usb_dev_hid_descr *)ptr;
+ dprintf("hid-report %d size %d\n",
+ hid->bReportType, le16_to_cpu(hid->wReportLength));
+ break;
+ case DESCR_TYPE_HUB:
+ break;
+ default:
+ printf("ptr %p desc_type %d\n", ptr, desc_type);
+ }
+ ptr += desc_len;
+ len -= desc_len;
+ }
+ return true;
+}
+
+int setup_new_device(struct usb_dev *dev, unsigned int port)
+{
+ struct usb_dev_descr descr;
+ struct usb_dev_config_descr cfg;
+ struct usb_ep_descr ep;
+ uint16_t len;
+ void *data = NULL;
+
+ dprintf("usb: %s - port %d\n", __func__, port);
+
+ dev->addr = 0;
+ dev->port = port;
+ ep.bEndpointAddress = 0;
+ ep.bmAttributes = USB_EP_TYPE_CONTROL;
+ ep.wMaxPacketSize = cpu_to_le16(8);
+ dev->control = usb_get_pipe(dev, &ep, NULL, 0);
+
+ if (!usb_get_device_descr(dev, &descr, 8))
+ goto fail;
+ dev->control->mps = descr.bMaxPacketSize0;
+
+ /*
+ * For USB3.0 ADDRESS-SLOT command takes care of setting
+ * address, skip this during generic device setup for USB3.0
+ * devices
+ */
+ if (dev->speed != USB_SUPER_SPEED) {
+ /*
+ * Qemu starts the port number from 1 which was
+ * revealed in bootindex and resulted in mismatch for
+ * storage devices names. Adjusting this here for
+ * compatibility.
+ */
+ dev->port = port + 1;
+ if(!usb_set_address(dev, dev->port))
+ goto fail;
+ }
+ mb();
+ SLOF_msleep(100);
+
+ if (!usb_get_device_descr(dev, &descr, sizeof(struct usb_dev_descr)))
+ goto fail;
+
+ if (!usb_get_config_descr(dev, &cfg, sizeof(struct usb_dev_config_descr)))
+ goto fail;
+
+ len = le16_to_cpu(cfg.wTotalLength);
+ /* No device config descriptor present */
+ if (len == sizeof(struct usb_dev_config_descr))
+ goto fail;
+
+ data = SLOF_dma_alloc(len);
+ if (!data) {
+ printf("%s: alloc failed %d\n", __func__, port);
+ goto fail;
+ }
+
+ if (!usb_get_config_descr(dev, data, len))
+ goto fail_mem_free;
+ if (!usb_set_config(dev, cfg.bConfigurationValue))
+ goto fail_mem_free;
+ mb();
+ SLOF_msleep(100);
+
+ if (!usb_handle_device(dev, &cfg, data, len))
+ goto fail_mem_free;
+
+ switch (usb_get_intf_class(dev->class)) {
+ case 3:
+ dprintf("HID found %06X\n", dev->class);
+ slof_usb_handle(dev);
+ break;
+ case 8:
+ dprintf("MASS STORAGE found %d %06X\n", dev->intf_num,
+ dev->class);
+ if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */
+ printf("Device not supported %06X\n", dev->class);
+ goto fail_mem_free;
+ }
+
+ if (!usb_msc_reset(dev)) {
+ printf("%s: bulk reset failed\n", __func__);
+ goto fail_mem_free;
+ }
+ SLOF_msleep(100);
+ slof_usb_handle(dev);
+ break;
+ case 9:
+ dprintf("HUB found\n");
+ slof_usb_handle(dev);
+ break;
+ default:
+ printf("USB Interface class -%x- Not supported\n", dev->class);
+ break;
+ }
+
+ SLOF_dma_free(data, len);
+ return true;
+fail_mem_free:
+ SLOF_dma_free(data, len);
+fail:
+ return false;
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.h b/qemu/roms/SLOF/lib/libusb/usb-core.h
new file mode 100644
index 000000000..7441979e9
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-core.h
@@ -0,0 +1,279 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef __USB_CORE_H
+#define __USB_CORE_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include "helpers.h"
+#include "usb.h"
+#include "tools.h"
+
+enum usb_hcd_type {
+ USB_OHCI = 1,
+ USB_EHCI = 2,
+ USB_XHCI = 3,
+};
+
+struct usb_hcd_dev;
+
+struct usb_hcd_dev {
+ void *base;
+ long type;
+ long num;
+ struct usb_hcd_ops *ops;
+ void *priv; /* hcd owned structure */
+ long nextaddr; /* address for devices */
+};
+
+struct usb_pipe;
+
+/*******************************************/
+/* Standard Endpoint Descriptor */
+/*******************************************/
+/* bmAttributes */
+#define USB_EP_TYPE_MASK 0x03
+#define USB_EP_TYPE_CONTROL 0
+#define USB_EP_TYPE_ISOC 1
+#define USB_EP_TYPE_BULK 2
+#define USB_EP_TYPE_INTR 3
+
+struct usb_ep_descr {
+ uint8_t bLength; /* size of descriptor */
+ uint8_t bDescriptorType; /* Type = 5 */
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+} __attribute__((packed));
+
+#define DEV_HID_KEYB 0x030101 /* class=HIB, protocol=Keyboard */
+#define DEV_HID_MOUSE 0x030102 /* class=HIB, protocol=Mouse */
+#define DEV_HUB 0x090000 /* class=HUB, subclass, protocol */
+#define DEV_MASS_RBC 0x080150 /* MassStorage, RBC, Bulk */
+#define DEV_CDROM_ATAPI 0x080250 /* MassStorage, SFF-8020i , Bulk */
+#define DEV_MASS_FLOPPY 0x080450 /* MassStorage, UFI, Bulk */
+#define DEV_MASS_ATAPI 0x080550 /* MassStorage, SFF-8070i , Bulk */
+#define DEV_MASS_SCSI 0x080650 /* MassStorage, SCSI, Bulk */
+
+enum USB_SPEED_TYPE {
+ USB_LOW_SPEED = 0,
+ USB_FULL_SPEED = 1,
+ USB_HIGH_SPEED = 2,
+ USB_SUPER_SPEED = 3,
+};
+
+/* Max number of endpoints supported in a device */
+#define USB_DEV_EP_MAX 4
+#define USB_TIMEOUT 5000 /* 5 sec usb timeout */
+
+struct usb_dev {
+ struct usb_dev *next;
+ struct usb_hcd_dev *hcidev;
+ struct usb_pipe *intr;
+ struct usb_pipe *control;
+ struct usb_pipe *bulk_in;
+ struct usb_pipe *bulk_out;
+ struct usb_ep_descr ep[USB_DEV_EP_MAX];
+ void *priv;
+ uint32_t ep_cnt;
+ uint32_t class;
+ uint32_t speed;
+ uint32_t addr;
+ uint32_t mps0;
+ uint32_t port;
+ uint16_t intf_num;
+};
+
+#define DEVICE_KEYBOARD 1
+#define DEVICE_MOUSE 2
+#define DEVICE_DISK 3
+#define DEVICE_HUB 4
+
+/* Structure in sync with FORTH code */
+struct slof_usb_dev {
+ void *udev;
+ uint32_t port;
+ uint32_t addr;
+ uint32_t hcitype;
+ uint32_t num;
+ uint32_t devtype;
+} __attribute__((packed));
+
+enum USB_PIPE_DIR {
+ USB_PIPE_OUT = 0,
+ USB_PIPE_IN,
+};
+
+struct usb_pipe {
+ struct usb_dev *dev;
+ struct usb_pipe *next;
+ uint32_t type;
+ uint32_t speed;
+ uint32_t dir;
+ uint16_t epno;
+ uint16_t mps;
+} __attribute__((packed));
+
+#define REQ_GET_STATUS 0 /* see Table 9-4 */
+#define REQ_CLEAR_FEATURE 1
+#define REQ_GET_STATE 2 /* HUB specific */
+#define REQ_SET_FEATURE 3
+#define REQ_SET_ADDRESS 5
+#define REQ_GET_DESCRIPTOR 6
+#define REQ_SET_DESCRIPTOR 7
+#define REQ_GET_CONFIGURATION 8
+#define REQ_SET_CONFIGURATION 9
+#define REQ_GET_INTERFACE 10
+#define REQ_SET_INTERFACE 11
+#define REQ_SYNCH_FRAME 12
+
+#define FEATURE_DEVICE_REMOTE_WAKEUP 1
+#define FEATURE_ENDPOINT_HALT 0
+
+#define REQT_REC_DEVICE 0
+#define REQT_REC_INTERFACE 1
+#define REQT_REC_EP 2
+#define REQT_REC_OTHER 3
+#define REQT_TYPE_STANDARD (0 << 5)
+#define REQT_TYPE_CLASS (1 << 5)
+#define REQT_TYPE_VENDOR (2 << 5)
+#define REQT_TYPE_RSRVD (3 << 5)
+#define REQT_DIR_OUT (0 << 7) /* host -> device */
+#define REQT_DIR_IN (1 << 7) /* device -> host */
+
+#define DESCR_TYPE_DEVICE 1 /* see Table 9-5 */
+#define DESCR_TYPE_CONFIGURATION 2
+#define DESCR_TYPE_STRING 3
+#define DESCR_TYPE_INTERFACE 4
+#define DESCR_TYPE_ENDPOINT 5
+#define DESCR_TYPE_HUB 0x29 /* Class Descriptor HUB */
+#define DESCR_TYPE_HID 0x21 /* Class Descriptor HID */
+#define DESCR_TYPE_REPORT 0x22 /* Class Descriptor HID */
+#define DESCR_TYPE_PHYSICAL 0x23 /* Class Descriptor HID */
+
+struct usb_dev_req {
+ uint8_t bmRequestType; /* direction, recipient */
+ uint8_t bRequest; /* see spec: Table 9-3 */
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength; /* number of bytes to transfer */
+} __attribute__((packed));
+
+/* Standard Device Descriptor (18 Bytes) */
+/*******************************************/
+struct usb_dev_descr {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} __attribute__((packed));
+
+/*******************************************/
+/* Standard Configuration Descriptor */
+/*******************************************/
+struct usb_dev_config_descr {
+ uint8_t bLength; /* size of descriptor */
+ uint8_t bDescriptorType; /* Type = 2 */
+ uint16_t wTotalLength; /* total returned data */
+ uint8_t bNumInterfaces; /* interfaces supported by this config */
+ uint8_t bConfigurationValue; /* Configuration-ID for SetConfiguration */
+ uint8_t iConfiguration; /* index of string descriptor */
+ uint8_t bmAttributes; /* configuration characteristics */
+ uint8_t bMaxPower; /* in 2mA units */
+} __attribute__((packed));
+
+/*******************************************/
+/* Standard Interface Descriptor */
+/*******************************************/
+struct usb_dev_intf_descr {
+ uint8_t bLength; /* size of descriptor */
+ uint8_t bDescriptorType; /* Type = 4 */
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol; /* protocol code */
+ uint8_t iInterface; /* index to string descriptor */
+} __attribute__((packed));
+
+/*******************************************/
+/* HUB-Class Descriptor */
+/*******************************************/
+struct usb_dev_hub_descr {
+ uint8_t bLength; /* size of complete descriptor */
+ uint8_t bDescriptorType; /* type = 0x29 for HUB */
+ uint8_t bNbrPorts; /* number of downstream ports */
+ uint8_t wHubCharacteristics; /* mode bits 7..0 */
+ uint8_t reserved; /* mode bits 15..8 */
+ uint8_t bPwrOn2PwrGood; /* in 2ms units */
+ uint8_t bHubContrCurrent; /* current requirement in mA */
+ uint8_t DeviceTable; /* length depends on number of ports */
+} __attribute__((packed));
+
+/*******************************************/
+/* HID-Class Descriptor */
+/*******************************************/
+struct usb_dev_hid_descr {
+ uint8_t bLength; /* size of this descriptor */
+ uint8_t bDescriptorType; /* type = 0x21 for HID */
+ uint16_t bcdHID; /* Sample: 0x0102 for 2.01 */
+ uint8_t bCountryCode; /* Hardware target country */
+ uint8_t bNumDescriptors; /* Number of HID class descr. */
+ uint8_t bReportType; /* Report Descriptor Type */
+ uint16_t wReportLength; /* Total Length of Report Descr. */
+} __attribute__((packed));
+
+struct usb_hcd_ops {
+ const char *name;
+ void (*init)(struct usb_hcd_dev *);
+ void (*exit)(struct usb_hcd_dev *);
+ void (*detect)(void);
+ void (*disconnect)(void);
+ int (*send_ctrl)(struct usb_pipe *pipe, struct usb_dev_req *req, void *data);
+ struct usb_pipe* (*get_pipe)(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len);
+ int (*transfer_bulk)(struct usb_pipe *pipe, void *td, void *td_phys, void *data, int size);
+ void (*put_pipe)(struct usb_pipe *);
+ int (*poll_intr)(struct usb_pipe *, uint8_t *);
+ struct usb_hcd_ops *next;
+ unsigned int usb_type;
+};
+
+extern void usb_hcd_register(struct usb_hcd_ops *ops);
+extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len);
+extern void usb_put_pipe(struct usb_pipe *pipe);
+extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf);
+extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data);
+extern struct usb_dev *usb_devpool_get(void);
+extern void usb_devpool_put(struct usb_dev *);
+extern int setup_new_device(struct usb_dev *dev, unsigned int port);
+extern int slof_usb_handle(struct usb_dev *dev);
+extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ void *buf, size_t len);
+extern int usb_hid_kbd_init(struct usb_dev *dev);
+extern int usb_hid_kbd_exit(struct usb_dev *dev);
+extern void usb_msc_resetrecovery(struct usb_dev *dev);
+#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.c b/qemu/roms/SLOF/lib/libusb/usb-ehci.c
new file mode 100644
index 000000000..4cca0da15
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.c
@@ -0,0 +1,609 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include "usb.h"
+#include "usb-core.h"
+#include "usb-ehci.h"
+#include "tools.h"
+#include "paflof.h"
+
+#undef EHCI_DEBUG
+//#define EHCI_DEBUG
+#ifdef EHCI_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#ifdef EHCI_DEBUG
+static void dump_ehci_regs(struct ehci_hcd *ehcd)
+{
+ struct ehci_cap_regs *cap_regs;
+ struct ehci_op_regs *op_regs;
+
+ cap_regs = ehcd->cap_regs;
+ op_regs = ehcd->op_regs;
+
+ dprintf("\n - CAPLENGTH %02X", read_reg8(&cap_regs->caplength));
+ dprintf("\n - HCIVERSION %04X", read_reg16(&cap_regs->hciversion));
+ dprintf("\n - HCSPARAMS %08X", read_reg32(&cap_regs->hcsparams));
+ dprintf("\n - HCCPARAMS %08X", read_reg32(&cap_regs->hccparams));
+ dprintf("\n - HCSP_PORTROUTE %016llX", read_reg64(&cap_regs->portroute));
+ dprintf("\n");
+
+ dprintf("\n - USBCMD %08X", read_reg32(&op_regs->usbcmd));
+ dprintf("\n - USBSTS %08X", read_reg32(&op_regs->usbsts));
+ dprintf("\n - USBINTR %08X", read_reg32(&op_regs->usbintr));
+ dprintf("\n - FRINDEX %08X", read_reg32(&op_regs->frindex));
+ dprintf("\n - CTRLDSSEGMENT %08X", read_reg32(&op_regs->ctrldssegment));
+ dprintf("\n - PERIODICLISTBASE %08X", read_reg32(&op_regs->periodiclistbase));
+ dprintf("\n - ASYNCLISTADDR %08X", read_reg32(&op_regs->asynclistaddr));
+ dprintf("\n - CONFIGFLAG %08X", read_reg32(&op_regs->configflag));
+ dprintf("\n - PORTSC %08X", read_reg32(&op_regs->portsc[0]));
+ dprintf("\n");
+}
+#endif
+
+static int ehci_hub_check_ports(struct ehci_hcd *ehcd)
+{
+ uint32_t num_ports, portsc, i;
+ struct usb_dev *dev;
+
+ dprintf("%s: enter\n", __func__);
+ num_ports = read_reg32(&ehcd->cap_regs->hcsparams) & HCS_NPORTS_MASK;
+ for (i = 0; i < num_ports; i++) {
+ dprintf("%s: device %d\n", __func__, i);
+ portsc = read_reg32(&ehcd->op_regs->portsc[i]);
+ if (portsc & PORT_CONNECT) { /* Device present */
+ dprintf("usb-ehci: Device present on port %d\n", i);
+ /* Reset the port */
+ portsc = read_reg32(&ehcd->op_regs->portsc[i]);
+ portsc = (portsc & ~PORT_PE) | PORT_RESET;
+ write_reg32(&ehcd->op_regs->portsc[i], portsc);
+ SLOF_msleep(20);
+ portsc = read_reg32(&ehcd->op_regs->portsc[i]);
+ portsc &= ~PORT_RESET;
+ write_reg32(&ehcd->op_regs->portsc[i], portsc);
+ SLOF_msleep(20);
+ dev = usb_devpool_get();
+ dprintf("usb-ehci: allocated device %p\n", dev);
+ dev->hcidev = ehcd->hcidev;
+ dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */
+ if (!setup_new_device(dev, i))
+ printf("usb-ehci: unable to setup device on port %d\n", i);
+ }
+ }
+ dprintf("%s: exit\n", __func__);
+ return 0;
+}
+
+static int ehci_hcd_init(struct ehci_hcd *ehcd)
+{
+ uint32_t usbcmd;
+ uint32_t time;
+ struct ehci_framelist *fl;
+ struct ehci_qh *qh_intr, *qh_async;
+ int i;
+ long fl_phys = 0, qh_intr_phys = 0, qh_async_phys;
+
+ /* Reset the host controller */
+ time = SLOF_GetTimer() + 250;
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ write_reg32(&ehcd->op_regs->usbcmd, (usbcmd & ~(CMD_PSE | CMD_ASE)) | CMD_HCRESET);
+ while (time > SLOF_GetTimer())
+ cpu_relax();
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ if (usbcmd & CMD_HCRESET) {
+ printf("usb-ehci: reset failed\n");
+ return -1;
+ }
+
+ /* Initialize periodic list */
+ fl = SLOF_dma_alloc(sizeof(*fl));
+ if (!fl) {
+ printf("usb-ehci: Unable to allocate frame list\n");
+ goto fail;
+ }
+ fl_phys = SLOF_dma_map_in(fl, sizeof(*fl), true);
+ dprintf("fl %p, fl_phys %lx\n", fl, fl_phys);
+
+ /* TODO: allocate qh pool */
+ qh_intr = SLOF_dma_alloc(sizeof(*qh_intr));
+ if (!qh_intr) {
+ printf("usb-ehci: Unable to allocate interrupt queue head\n");
+ goto fail_qh_intr;
+ }
+ qh_intr_phys = SLOF_dma_map_in(qh_intr, sizeof(*qh_intr), true);
+ dprintf("qh_intr %p, qh_intr_phys %lx\n", qh_intr, qh_intr_phys);
+
+ memset(qh_intr, 0, sizeof(*qh_intr));
+ qh_intr->qh_ptr = QH_PTR_TERM;
+ qh_intr->ep_cap2 = cpu_to_le32(0x01 << QH_SMASK_SHIFT);
+ qh_intr->next_qtd = qh_intr->alt_next_qtd = QH_PTR_TERM;
+ qh_intr->token = cpu_to_le32(QH_STS_HALTED);
+ for (i = 0; i < FL_SIZE; i++)
+ fl->fl_ptr[i] = cpu_to_le32(qh_intr_phys | EHCI_TYP_QH);
+ write_reg32(&ehcd->op_regs->periodiclistbase, fl_phys);
+
+ /* Initialize async list */
+ qh_async = SLOF_dma_alloc(sizeof(*qh_async));
+ if (!qh_async) {
+ printf("usb-ehci: Unable to allocate async queue head\n");
+ goto fail_qh_async;
+ }
+ qh_async_phys = SLOF_dma_map_in(qh_async, sizeof(*qh_async), true);
+ dprintf("qh_async %p, qh_async_phys %lx\n", qh_async, qh_async_phys);
+
+ memset(qh_async, 0, sizeof(*qh_async));
+ qh_async->qh_ptr = cpu_to_le32(qh_async_phys | EHCI_TYP_QH);
+ qh_async->ep_cap1 = cpu_to_le32(QH_CAP_H);
+ qh_async->next_qtd = qh_async->alt_next_qtd = QH_PTR_TERM;
+ qh_async->token = cpu_to_le32(QH_STS_HALTED);
+ write_reg32(&ehcd->op_regs->asynclistaddr, qh_async_phys);
+ ehcd->qh_async = qh_async;
+ ehcd->qh_async_phys = qh_async_phys;
+ ehcd->qh_intr = qh_intr;
+ ehcd->qh_intr_phys = qh_intr_phys;
+ ehcd->fl = fl;
+ ehcd->fl_phys = fl_phys;
+
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_ASE | CMD_RUN);
+ write_reg32(&ehcd->op_regs->configflag, 1);
+
+ return 0;
+
+fail_qh_async:
+ SLOF_dma_map_out(qh_intr_phys, qh_intr, sizeof(*qh_intr));
+ SLOF_dma_free(qh_intr, sizeof(*qh_intr));
+fail_qh_intr:
+ SLOF_dma_map_out(fl_phys, fl, sizeof(*fl));
+ SLOF_dma_free(fl, sizeof(*fl));
+fail:
+ return -1;
+}
+
+static int ehci_hcd_exit(struct ehci_hcd *ehcd)
+{
+ uint32_t usbcmd;
+
+ if (!ehcd) {
+ dprintf("NULL pointer\n");
+ return false;
+ }
+
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | ~CMD_RUN);
+ write_reg32(&ehcd->op_regs->periodiclistbase, 0);
+
+ if (ehcd->pool) {
+ SLOF_dma_map_out(ehcd->pool_phys, ehcd->pool, EHCI_PIPE_POOL_SIZE);
+ SLOF_dma_free(ehcd->pool, EHCI_PIPE_POOL_SIZE);
+ }
+ if (ehcd->qh_intr) {
+ SLOF_dma_map_out(ehcd->qh_intr_phys, ehcd->qh_intr, sizeof(struct ehci_qh));
+ SLOF_dma_free(ehcd->qh_intr, sizeof(struct ehci_qh));
+ }
+ if (ehcd->qh_async) {
+ SLOF_dma_map_out(ehcd->qh_async_phys, ehcd->qh_async, sizeof(struct ehci_qh));
+ SLOF_dma_free(ehcd->qh_async, sizeof(struct ehci_qh));
+ }
+ if (ehcd->fl) {
+ SLOF_dma_map_out(ehcd->fl_phys, ehcd->fl, sizeof(struct ehci_framelist));
+ SLOF_dma_free(ehcd->fl, sizeof(struct ehci_framelist));
+ }
+ return true;
+}
+
+static int ehci_alloc_pipe_pool(struct ehci_hcd *ehcd)
+{
+ struct ehci_pipe *epipe, *curr, *prev;
+ unsigned int i, count;
+ long epipe_phys = 0;
+
+ count = EHCI_PIPE_POOL_SIZE/sizeof(*epipe);
+ ehcd->pool = epipe = SLOF_dma_alloc(EHCI_PIPE_POOL_SIZE);
+ if (!epipe)
+ return -1;
+ ehcd->pool_phys = epipe_phys = SLOF_dma_map_in(epipe, EHCI_PIPE_POOL_SIZE, true);
+ dprintf("%s: epipe %p, epipe_phys %lx\n", __func__, epipe, epipe_phys);
+
+ /* Although an array, link them */
+ for (i = 0, curr = epipe, prev = NULL; i < count; i++, curr++) {
+ if (prev)
+ prev->pipe.next = &curr->pipe;
+ curr->pipe.next = NULL;
+ prev = curr;
+ curr->qh_phys = epipe_phys + (curr - epipe) * sizeof(*curr) +
+ offset_of(struct ehci_pipe, qh);
+ dprintf("%s - %d: qh %p, qh_phys %lx\n", __func__,
+ i, &curr->qh, curr->qh_phys);
+ }
+
+ if (!ehcd->freelist)
+ ehcd->freelist = &epipe->pipe;
+ else
+ ehcd->end->next = &epipe->pipe;
+ ehcd->end = &prev->pipe;
+
+ return 0;
+}
+
+static void ehci_init(struct usb_hcd_dev *hcidev)
+{
+ struct ehci_hcd *ehcd;
+
+ printf(" EHCI: Initializing\n");
+ dprintf("%s: device base address %p\n", __func__, hcidev->base);
+
+ ehcd = SLOF_alloc_mem(sizeof(*ehcd));
+ if (!ehcd) {
+ printf("usb-ehci: Unable to allocate memory\n");
+ return;
+ }
+ memset(ehcd, 0, sizeof(*ehcd));
+
+ hcidev->nextaddr = 1;
+ hcidev->priv = ehcd;
+ ehcd->hcidev = hcidev;
+ ehcd->cap_regs = (struct ehci_cap_regs *)(hcidev->base);
+ ehcd->op_regs = (struct ehci_op_regs *)(hcidev->base +
+ read_reg8(&ehcd->cap_regs->caplength));
+#ifdef EHCI_DEBUG
+ dump_ehci_regs(ehcd);
+#endif
+ ehci_hcd_init(ehcd);
+ ehci_hub_check_ports(ehcd);
+}
+
+static void ehci_exit(struct usb_hcd_dev *hcidev)
+{
+ struct ehci_hcd *ehcd;
+ static int count = 0;
+
+ dprintf("%s: enter \n", __func__);
+
+ if (!hcidev && !hcidev->priv) {
+ return;
+ }
+ count++;
+ if (count > 1) {
+ printf("%s: already called once \n", __func__);
+ return;
+ }
+ ehcd = hcidev->priv;
+ ehci_hcd_exit(ehcd);
+ SLOF_free_mem(ehcd, sizeof(*ehcd));
+ hcidev->priv = NULL;
+}
+
+static void ehci_detect(void)
+{
+
+}
+
+static void ehci_disconnect(void)
+{
+
+}
+
+static int ehci_handshake(struct ehci_hcd *ehcd, uint32_t timeout)
+{
+ uint32_t usbsts = 0, time;
+ uint32_t usbcmd;
+ mb();
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ /* Ring a doorbell */
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_IAAD);
+ mb();
+ time = SLOF_GetTimer() + timeout;
+ while ((time > SLOF_GetTimer())) {
+ /* Wait for controller to confirm */
+ usbsts = read_reg32(&ehcd->op_regs->usbsts);
+ if (usbsts & STS_IAA) {
+ /* Acknowledge it, for next doorbell to work */
+ write_reg32(&ehcd->op_regs->usbsts, STS_IAA);
+ return true;
+ }
+ cpu_relax();
+ }
+ return false;
+}
+
+static int fill_qtd_buff(struct ehci_qtd *qtd, long data, uint32_t size)
+{
+ long i, rem;
+ long pos = (data + 0x1000) & ~0xfff;
+
+ qtd->buffer[0] = cpu_to_le32(PTR_U32(data));
+ for (i = 1; i < 5; i++) {
+ if ((data + size - 1) >= pos) {
+ //dprintf("data spans page boundary: %d, %p\n", i, pos);
+ qtd->buffer[i] = cpu_to_le32(pos);
+ pos += 0x1000;
+ } else
+ break;
+ }
+ if ((data + size) > pos)
+ rem = data + size - pos;
+ else
+ rem = 0;
+ return rem;
+}
+
+static int ehci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct ehci_hcd *ehcd;
+ struct ehci_qtd *qtd, *qtds, *qtds_phys;
+ struct ehci_pipe *epipe;
+ uint32_t transfer_size = sizeof(*req);
+ uint32_t datalen, pid;
+ uint32_t time;
+ long req_phys = 0, data_phys = 0;
+ int ret = true;
+
+ if (pipe->type != USB_EP_TYPE_CONTROL) {
+ printf("usb-ehci: Not a control pipe.\n");
+ return false;
+ }
+
+ ehcd = pipe->dev->hcidev->priv;
+ qtds = qtd = SLOF_dma_alloc(sizeof(*qtds) * 3);
+ if (!qtds) {
+ printf("Error allocating qTDs.\n");
+ return false;
+ }
+ qtds_phys = (struct ehci_qtd *)SLOF_dma_map_in(qtds, sizeof(*qtds) * 3, true);
+ memset(qtds, 0, sizeof(*qtds) * 3);
+ req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true);
+ qtd->next_qtd = cpu_to_le32(PTR_U32(&qtds_phys[1]));
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ qtd->token = cpu_to_le32((transfer_size << TOKEN_TBTT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (PID_SETUP << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+ fill_qtd_buff(qtd, req_phys, sizeof(*req));
+
+ qtd++;
+ datalen = cpu_to_le16(req->wLength);
+ pid = (req->bmRequestType & REQT_DIR_IN) ? PID_IN : PID_OUT;
+ if (datalen) {
+ data_phys = SLOF_dma_map_in(data, datalen, true);
+ qtd->next_qtd = cpu_to_le32(PTR_U32(&qtds_phys[2]));
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) |
+ (datalen << TOKEN_TBTT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (pid << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+ fill_qtd_buff(qtd, data_phys, datalen);
+ qtd++;
+ }
+
+ if (pid == PID_IN)
+ pid = PID_OUT;
+ else
+ pid = PID_IN;
+ qtd->next_qtd = QH_PTR_TERM;
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (pid << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+
+ /* link qtd to qh and attach to ehcd */
+ mb();
+ epipe = container_of(pipe, struct ehci_pipe, pipe);
+ epipe->qh.next_qtd = cpu_to_le32(PTR_U32(qtds_phys));
+ epipe->qh.qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ epipe->qh.ep_cap1 = cpu_to_le32((pipe->mps << QH_MPS_SHIFT) |
+ (pipe->speed << QH_EPS_SHIFT) |
+ (pipe->epno << QH_EP_SHIFT) |
+ (pipe->dev->addr << QH_DEV_ADDR_SHIFT));
+ mb();
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(epipe->qh_phys | EHCI_TYP_QH);
+
+ /* transfer data */
+ mb();
+ qtd = &qtds[0];
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ do {
+ if (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT))
+ mb();
+ else
+ qtd++;
+
+ if (time < SLOF_GetTimer()) { /* timed out */
+ printf("usb-ehci: control transfer timed out_\n");
+ ret = false;
+ break;
+ }
+ } while (qtd->next_qtd != QH_PTR_TERM);
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ mb();
+ if (!ehci_handshake(ehcd, USB_TIMEOUT)) {
+ printf("%s: handshake failed\n", __func__);
+ ret = false;
+ }
+
+ SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req));
+ SLOF_dma_map_out(data_phys, data, datalen);
+ SLOF_dma_map_out(PTR_U32(qtds_phys), qtds, sizeof(*qtds) * 3);
+ SLOF_dma_free(qtds, sizeof(*qtds) * 3);
+
+ return ret;
+}
+
+static int ehci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
+ void *data_phys, int size)
+{
+ struct ehci_hcd *ehcd;
+ struct ehci_qtd *qtd, *qtd_phys;
+ struct ehci_pipe *epipe;
+ uint32_t pid;
+ int i, rem, ret = true;
+ uint32_t time;
+ long ptr;
+
+ dprintf("usb-ehci: bulk transfer: data %p, size %d, td %p, td_phys %p\n",
+ data_phys, size, td, td_phys);
+
+ if (pipe->type != USB_EP_TYPE_BULK) {
+ printf("usb-ehci: Not a bulk pipe.\n");
+ return false;
+ }
+
+ if (size > QTD_MAX_TRANSFER_LEN) {
+ printf("usb-ehci: bulk transfer size too big\n");
+ return false;
+ }
+
+ ehcd = pipe->dev->hcidev->priv;
+ pid = (pipe->dir == USB_PIPE_OUT) ? PID_OUT : PID_IN;
+ qtd = (struct ehci_qtd *)td;
+ qtd_phys = (struct ehci_qtd *)td_phys;
+ ptr = (long)data_phys;
+ for (i = 0; i < NUM_BULK_QTDS; i++) {
+ memset(qtd, 0, sizeof(*qtd));
+ rem = fill_qtd_buff(qtd, ptr, size);
+ qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) |
+ ((size - rem) << TOKEN_TBTT_SHIFT) |
+ (3 << TOKEN_CERR_SHIFT) |
+ (pid << TOKEN_PID_SHIFT) |
+ (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT));
+ if (rem) {
+ qtd->next_qtd = cpu_to_le32(PTR_U32(&qtd_phys[i+1]));
+ qtd->alt_next_qtd = QH_PTR_TERM;
+ ptr += size - rem;
+ size = rem;
+ qtd++;
+ } else {
+ qtd->next_qtd = qtd->alt_next_qtd = QH_PTR_TERM;
+ break; /* no more data */
+ }
+ }
+
+ /* link qtd to qh and attach to ehcd */
+ mb();
+ epipe = container_of(pipe, struct ehci_pipe, pipe);
+ epipe->qh.next_qtd = cpu_to_le32(PTR_U32(qtd_phys));
+ epipe->qh.qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ epipe->qh.ep_cap1 = cpu_to_le32((pipe->mps << QH_MPS_SHIFT) |
+ (pipe->speed << QH_EPS_SHIFT) |
+ (pipe->epno << QH_EP_SHIFT) |
+ (pipe->dev->addr << QH_DEV_ADDR_SHIFT));
+ mb();
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(epipe->qh_phys | EHCI_TYP_QH);
+
+ /* transfer data */
+ mb();
+ qtd = (struct ehci_qtd *)td;
+ for (i = 0; i < NUM_BULK_QTDS; i++) {
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while ((time > SLOF_GetTimer()) &&
+ (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)))
+ cpu_relax();
+ mb();
+ if (qtd->next_qtd == QH_PTR_TERM)
+ break;
+
+ if (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)) {
+ printf("usb-ehci: bulk transfer timed out_\n");
+ ret = false;
+ break;
+ }
+ qtd++;
+ }
+
+ ehcd->qh_async->qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH);
+ mb();
+ if (!ehci_handshake(ehcd, USB_TIMEOUT)) {
+ printf("%s: handshake failed\n", __func__);
+ ret = false;
+ }
+ return ret;
+}
+
+static struct usb_pipe *ehci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t len)
+{
+ struct ehci_hcd *ehcd;
+ struct usb_pipe *new = NULL;
+
+ if (!dev)
+ return NULL;
+
+ ehcd = (struct ehci_hcd *)dev->hcidev->priv;
+ if (!ehcd->freelist) {
+ dprintf("usb-ehci: %s allocating pool\n", __func__);
+ if (ehci_alloc_pipe_pool(ehcd))
+ return NULL;
+ }
+
+ new = ehcd->freelist;
+ ehcd->freelist = ehcd->freelist->next;
+ if (!ehcd->freelist)
+ ehcd->end = NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->dev = dev;
+ new->next = NULL;
+ new->type = ep->bmAttributes & USB_EP_TYPE_MASK;
+ new->speed = dev->speed;
+ new->mps = ep->wMaxPacketSize;
+ new->dir = (ep->bEndpointAddress & 0x80) >> 7;
+ new->epno = ep->bEndpointAddress & 0x0f;
+
+ return new;
+}
+
+static void ehci_put_pipe(struct usb_pipe *pipe)
+{
+ struct ehci_hcd *ehcd;
+
+ dprintf("usb-ehci: %s enter - %p\n", __func__, pipe);
+ if (!pipe || !pipe->dev)
+ return;
+ ehcd = pipe->dev->hcidev->priv;
+ if (ehcd->end)
+ ehcd->end->next = pipe;
+ else
+ ehcd->freelist = pipe;
+
+ ehcd->end = pipe;
+ pipe->next = NULL;
+ pipe->dev = NULL;
+ memset(pipe, 0, sizeof(*pipe));
+ dprintf("usb-ehci: %s exit\n", __func__);
+}
+
+struct usb_hcd_ops ehci_ops = {
+ .name = "ehci-hcd",
+ .init = ehci_init,
+ .exit = ehci_exit,
+ .detect = ehci_detect,
+ .disconnect = ehci_disconnect,
+ .get_pipe = ehci_get_pipe,
+ .put_pipe = ehci_put_pipe,
+ .send_ctrl = ehci_send_ctrl,
+ .transfer_bulk = ehci_transfer_bulk,
+ .usb_type = USB_EHCI,
+ .next = NULL,
+};
+
+void usb_ehci_register(void)
+{
+ usb_hcd_register(&ehci_ops);
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.h b/qemu/roms/SLOF/lib/libusb/usb-ehci.h
new file mode 100644
index 000000000..2955a9cb8
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.h
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for EHCI Controller
+ *
+ */
+
+#ifndef USB_EHCI_H
+#define USB_EHCI_H
+
+#include <stdint.h>
+#include "usb-core.h"
+
+#define FL_SIZE 1024
+
+struct ehci_cap_regs {
+ uint8_t caplength;
+ uint8_t reserved;
+ uint16_t hciversion;
+ uint32_t hcsparams;
+ uint32_t hccparams;
+ uint64_t portroute;
+} __attribute__ ((packed));
+
+struct ehci_op_regs {
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t usbintr;
+ uint32_t frindex;
+ uint32_t ctrldssegment;
+ uint32_t periodiclistbase;
+ uint32_t asynclistaddr;
+ uint32_t reserved[9];
+ uint32_t configflag;
+ uint32_t portsc[0];
+} __attribute__ ((packed));
+
+struct ehci_framelist {
+ uint32_t fl_ptr[FL_SIZE];
+} __attribute__ ((packed));
+
+struct ehci_hcd {
+ struct ehci_cap_regs *cap_regs;
+ struct ehci_op_regs *op_regs;
+ struct usb_hcd_dev *hcidev;
+ struct ehci_qh *qh_async;
+ struct ehci_qh *qh_intr;
+ struct usb_pipe *freelist;
+ struct usb_pipe *end;
+ struct ehci_framelist *fl;
+ long qh_async_phys;
+ long qh_intr_phys;
+ long fl_phys;
+ void *pool;
+ long pool_phys;
+};
+
+struct ehci_qtd {
+ uint32_t next_qtd;
+ uint32_t alt_next_qtd;
+ uint32_t token;
+ uint32_t buffer[5];
+} __attribute__ ((packed));
+
+struct ehci_qh {
+ uint32_t qh_ptr;
+ uint32_t ep_cap1;
+ uint32_t ep_cap2;
+ uint32_t curr_qtd;
+ uint32_t next_qtd;
+ uint32_t alt_next_qtd;
+ uint32_t token;
+ uint32_t buffer[5];
+} __attribute__ ((packed)) __attribute__((aligned(32)));
+
+struct ehci_pipe {
+ struct ehci_qh qh;
+ struct usb_pipe pipe;
+ long qh_phys;
+};
+
+#define EHCI_PIPE_POOL_SIZE 4096
+
+#define EHCI_TYP_ITD 0x00
+#define EHCI_TYP_QH 0x02
+#define EHCI_TYP_SITD 0x04
+#define EHCI_TYP_FSTN 0x06
+
+#define PID_OUT 0x00
+#define PID_IN 0x01
+#define PID_SETUP 0x02
+
+#define HCS_NPORTS_MASK 0x000f
+
+#define CMD_IAAD (1 << 6)
+#define CMD_ASE (1 << 5)
+#define CMD_PSE (1 << 4)
+#define CMD_FLS_MASK (3 << 2)
+#define CMD_HCRESET (1 << 1)
+#define CMD_RUN (1 << 0)
+
+#define STS_IAA (1 << 5)
+
+#define PORT_RESET (1 << 8)
+#define PORT_PE (1 << 2)
+#define PORT_CSC (1 << 1)
+#define PORT_CONNECT (1 << 0)
+
+#define QH_LOW_SPEED 0
+#define QH_FULL_SPEED 1
+#define QH_HIGH_SPEED 2
+
+#define QH_RL_SHIFT 28
+#define QH_CAP_C (1 << 27)
+#define QH_MPS_SHIFT 16
+#define QH_CAP_H (1 << 15)
+#define QH_CAP_DTC (1 << 14)
+#define QH_EPS_SHIFT 12
+#define QH_EP_SHIFT 8
+#define QH_CAP_I (1 << 7)
+#define QH_DEV_ADDR_SHIFT 0
+
+#define QH_PTR_TERM __builtin_bswap32(1)
+#define QH_SMASK_SHIFT 0
+#define QH_STS_ACTIVE (1 << 7)
+#define QH_STS_HALTED (1 << 6)
+#define QH_STS_DBE (1 << 5)
+#define QH_STS_BABBLE (1 << 4)
+#define QH_STS_XACTERR (1 << 3)
+#define QH_STS_MMF (1 << 2)
+#define QH_STS_SXS (1 << 1)
+#define QH_STS_PING (1 << 0)
+
+#define NUM_BULK_QTDS 4
+#define MAX_XFER_PER_QTD (20 * 1024)
+#define QTD_MAX_TRANSFER_LEN (NUM_BULK_QTDS * MAX_XFER_PER_QTD)
+
+#define TOKEN_DT_SHIFT 31
+#define TOKEN_TBTT_SHIFT 16
+#define TOKEN_IOC_SHIFT 15
+#define TOKEN_CPAGE_SHIFT 12
+#define TOKEN_CERR_SHIFT 10
+#define TOKEN_PID_SHIFT 8
+#define TOKEN_STATUS_SHIFT 0
+
+#endif /* USB_EHCI_H */
diff --git a/qemu/roms/SLOF/lib/libusb/usb-hid.c b/qemu/roms/SLOF/lib/libusb/usb-hid.c
new file mode 100644
index 000000000..f0cab8a69
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-hid.c
@@ -0,0 +1,453 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <termctrl.h>
+
+#include "usb-core.h"
+#include "usb-key.h"
+
+/*
+ * HID Spec Version 1.11
+ */
+
+#define HID_REQ_GET_REPORT 0x01
+#define HID_REQ_GET_IDLE 0x02
+#define HID_REQ_GET_PROTOCOL 0x03
+#define HID_REQ_SET_REPORT 0x09
+#define HID_REQ_SET_IDLE 0x0A
+#define HID_REQ_SET_PROTOCOL 0x0B
+
+//#define KEY_DEBUG
+
+/* HID SPEC - 7.2.6 Set_Protocol Request */
+static int usb_hid_set_protocol(struct usb_dev *dev, uint16_t value)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+ req.bRequest = HID_REQ_SET_PROTOCOL;
+ req.wValue = cpu_to_le16(value);
+ req.wIndex = cpu_to_le16(dev->intf_num);
+ req.wLength = 0;
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+/* HID SPEC - 7.2.4 Set_Idle Request */
+static int usb_hid_set_idle(struct usb_dev *dev, uint16_t ms_delay)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+ req.bRequest = HID_REQ_SET_IDLE;
+ req.wValue = cpu_to_le16((ms_delay/4) << 8);
+ req.wIndex = cpu_to_le16(dev->intf_num);
+ req.wLength = 0;
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+/* HID SPEC - 7.2.1 Get Report Request */
+static int usb_hid_get_report(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_IN;
+ req.bRequest = HID_REQ_GET_REPORT;
+ req.wIndex = cpu_to_le16(dev->intf_num);
+
+ req.wLength = cpu_to_le16((uint16_t)size);
+ req.wValue = cpu_to_le16(1 << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+/* ring buffer with RD/WR indices for key buffering */
+static uint8_t keybuf[256]; /* size fixed to byte range ! */
+uint8_t r_ptr = 0; /* RD-index for Keyboard-Buffer */
+uint8_t w_ptr = 0; /* WR-index for Keyboard-Buffer */
+
+/* variables for LED status */
+uint8_t set_leds;
+const uint8_t *key_std = NULL;
+const uint8_t *key_std_shift = NULL;
+
+/**
+ * read character from Keyboard-Buffer
+ *
+ * @param -
+ * @return > 0 Keycode
+ * = 0 if no key available
+ */
+static int read_key(void)
+{
+ if (r_ptr != w_ptr)
+ return (int)keybuf[r_ptr++];
+ else
+ return false;
+}
+
+/**
+ * Store character into Keyboard-Buffer
+ *
+ * @param Key = detected ASCII-Key (> 0)
+ * @return -
+ */
+static void write_key(uint8_t key)
+{
+ if ((w_ptr + 1) != r_ptr)
+ keybuf[w_ptr++] = key;
+}
+
+/**
+ * Convert keyboard usage-ID to ANSI-Code
+ *
+ * @param Ctrl=Modifier Byte
+ * Key =Usage ID from USB Keyboard
+ * @return -
+ */
+static void get_char(uint8_t ctrl, uint8_t keypos)
+{
+ uint8_t ch;
+
+#ifdef KEY_DEBUG
+ printf("pos %02X\n", keypos);
+#endif
+
+ if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */
+ ctrl |= MODIFIER_SHIFT; /* simulate shift */
+
+ if (ctrl == 0) {
+ ch = key_std[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+
+ if (ctrl & MODIFIER_SHIFT) {
+ ch = key_std_shift[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+
+ if (ctrl & MODIFIER_CTRL) {
+ ch = keycodes_ctrl[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+
+ if (ctrl == MODIFIER_ALT_GR) {
+ ch = keycodes_alt_GR[keypos];
+ if (ch != 0)
+ write_key(ch);
+ return;
+ }
+}
+
+static void check_key_code(uint8_t *buf)
+{
+ static uint8_t key_last[6]; /* list of processed keys */
+ uint8_t i, j, key_pos;
+
+ /* set translation table to defaults */
+ if ((key_std == NULL) || (key_std_shift == NULL)) {
+ key_std = keycodes_std_US;
+ key_std_shift = keycodes_shift_US;
+ }
+
+ if (buf[0] & MODIFIER_SHIFT) /* any shift key pressed ? */
+ set_leds &= ~LED_CAPS_LOCK; /* CAPS-LOCK-LED always off */
+
+ i = 2; /* skip modifier byte and reserved byte */
+ while (i < 8) {
+ key_pos = buf[i];
+ if ((key_pos != 0) && (key_pos <= 100)) { /* support for 101 keys */
+ j = 0;
+ /* search if already processed */
+ while ((j < 6) && (key_pos != key_last[j]))
+ j++;
+
+ if (j >= 6) { /* not found (= not processed) */
+ switch (key_pos) {
+ case 0x39: /* caps-lock key ? */
+ case 0x32: /* caps-lock key ? */
+ set_leds ^= LED_CAPS_LOCK;
+ break;
+
+ case 0x3a: /* F1 */
+ write_key(0x1b);
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x31);
+ write_key(0x7e);
+ break;
+
+ case 0x3b: /* F2 */
+ write_key(0x1b);
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x32);
+ write_key(0x7e);
+ break;
+
+ case 0x3c:
+ write_key(0x1b); /* F3 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x33);
+ write_key(0x7e);
+ break;
+
+ case 0x3d:
+ write_key(0x1b); /* F4 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x34);
+ write_key(0x7e);
+ break;
+
+ case 0x3e:
+ write_key(0x1b); /* F5 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x35);
+ write_key(0x7e);
+ break;
+
+ case 0x3f:
+ write_key(0x1b); /* F6 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x37);
+ write_key(0x7e);
+ break;
+
+ case 0x40:
+ write_key(0x1b); /* F7 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x38);
+ write_key(0x7e);
+ break;
+
+ case 0x41:
+ write_key(0x1b); /* F8 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x39);
+ write_key(0x7e);
+ break;
+
+ case 0x42:
+ write_key(0x1b); /* F9 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x30);
+ write_key(0x7e);
+ break;
+
+ case 0x43:
+ write_key(0x1b); /* F10 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x31);
+ write_key(0x7e);
+ break;
+
+ case 0x44:
+ write_key(0x1b); /* F11 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x33);
+ write_key(0x7e);
+ break;
+
+ case 0x45:
+ write_key(0x1b); /* F12 */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x34);
+ write_key(0x7e);
+ break;
+
+ case 0x47: /* scroll-lock key ? */
+ set_leds ^= LED_SCROLL_LOCK;
+ break;
+
+ case 0x49:
+ write_key(0x1b); /* INS */
+ write_key(0x5b);
+ write_key(0x31);
+ write_key(0x7e);
+ break;
+
+ case 0x4a:
+ write_key(0x1b); /* HOME */
+ write_key(0x5b);
+ write_key(0x32);
+ write_key(0x7e);
+ break;
+
+ case 0x4b:
+ write_key(0x1b); /* PgUp */
+ write_key(0x5b);
+ write_key(0x33);
+ write_key(0x7e);
+ break;
+
+ case 0x4c:
+ write_key(0x1b); /* DEL */
+ write_key(0x5b);
+ write_key(0x34);
+ write_key(0x7e);
+ break;
+
+ case 0x4d:
+ write_key(0x1b); /* END */
+ write_key(0x5b);
+ write_key(0x35);
+ write_key(0x7e);
+ break;
+
+ case 0x4e:
+ write_key(0x1b); /* PgDn */
+ write_key(0x5b);
+ write_key(0x36);
+ write_key(0x7e);
+ break;
+
+ case 0x4f:
+ write_key(0x1b); /* R-Arrow */
+ write_key(0x5b);
+ write_key(0x43);
+ break;
+
+ case 0x50:
+ write_key(0x1b); /* L-Arrow */
+ write_key(0x5b);
+ write_key(0x44);
+ break;
+
+ case 0x51:
+ write_key(0x1b); /* D-Arrow */
+ write_key(0x5b);
+ write_key(0x42);
+ break;
+
+ case 0x52:
+ write_key(0x1b); /* U-Arrow */
+ write_key(0x5b);
+ write_key(0x41);
+ break;
+
+ case 0x53: /* num-lock key ? */
+ set_leds ^= LED_NUM_LOCK;
+ break;
+
+ default:
+ /* convert key position to ASCII code */
+ get_char(buf[0], key_pos);
+ break;
+ }
+ }
+ }
+ i++;
+ }
+ /*****************************************/
+ /* all keys are processed, create a copy */
+ /* to flag them as processed */
+ /*****************************************/
+ for (i = 2, j = 0; j < 6; i++, j++)
+ key_last[j] = buf[i]; /* copy all actual keys to last */
+}
+
+#define USB_HID_SIZE 128
+uint32_t *kbd_buffer;
+
+int usb_hid_kbd_init(struct usb_dev *dev)
+{
+ int i;
+ uint8_t key[8];
+
+ usb_hid_set_protocol(dev, 0);
+ usb_hid_set_idle(dev, 500);
+
+ memset(key, 0, 8);
+ if (usb_hid_get_report(dev, key, 8))
+ check_key_code(key);
+
+ kbd_buffer = SLOF_dma_alloc(USB_HID_SIZE);
+ if (!kbd_buffer) {
+ printf("%s: unable to allocate keyboard buffer\n", __func__);
+ return false;
+ }
+
+#ifdef KEY_DEBUG
+ printf("HID kbd init %d\n", dev->ep_cnt);
+#endif
+ for (i = 0; i < dev->ep_cnt; i++) {
+ if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK)
+ == USB_EP_TYPE_INTR)
+ usb_dev_populate_pipe(dev, &dev->ep[i], kbd_buffer, USB_HID_SIZE);
+ }
+ return true;
+}
+
+int usb_hid_kbd_exit(struct usb_dev *dev)
+{
+ if (dev->intr) {
+ usb_put_pipe(dev->intr);
+ dev->intr = NULL;
+ }
+ SLOF_dma_free(kbd_buffer, USB_HID_SIZE);
+ return true;
+}
+
+static int usb_poll_key(void *vdev)
+{
+ struct usb_dev *dev = vdev;
+ uint8_t key[8];
+ int rc;
+
+ memset(key, 0, 8);
+ rc = usb_poll_intr(dev->intr, key);
+ if (rc)
+ check_key_code(key);
+ return rc;
+}
+
+unsigned char usb_key_available(void *dev)
+{
+ if (!dev)
+ return false;
+
+ usb_poll_key(dev);
+ if (r_ptr != w_ptr)
+ return true;
+ else
+ return false;
+}
+
+unsigned char usb_read_keyb(void *vdev)
+{
+ if (!vdev)
+ return false;
+
+ while (usb_poll_key(vdev)) {
+ /* loop for all pending keys */
+ }
+ return read_key();
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-hub.c b/qemu/roms/SLOF/lib/libusb/usb-hub.c
new file mode 100644
index 000000000..7059cd019
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-hub.c
@@ -0,0 +1,183 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "usb-core.h"
+
+#undef HUB_DEBUG
+//#define HUB_DEBUG
+#ifdef HUB_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+/*
+ * USB Spec 1.1
+ * 11.16.2 Class-specific Requests
+ */
+struct usb_hub_ps {
+ uint16_t wPortStatus;
+ uint16_t wPortChange;
+} __attribute__((packed));
+
+#define HUB_PS_CONNECTION (1 << 0)
+#define HUB_PS_ENABLE (1 << 1)
+#define HUB_PS_SUSPEND (1 << 2)
+#define HUB_PS_OVER_CURRENT (1 << 3)
+#define HUB_PS_RESET (1 << 4)
+#define HUB_PS_POWER (1 << 8)
+#define HUB_PS_LOW_SPEED (1 << 9)
+
+#define HUB_PF_CONNECTION 0
+#define HUB_PF_ENABLE 1
+#define HUB_PF_SUSPEND 2
+#define HUB_PF_OVER_CURRENT 3
+#define HUB_PF_RESET 4
+#define HUB_PF_POWER 8
+#define HUB_PF_LOWSPEED 9
+#define HUB_PF_C_CONNECTION 16
+#define HUB_PF_C_ENABLE 17
+#define HUB_PF_C_SUSPEND 18
+#define HUB_PF_C_OVER_CURRENT 19
+#define HUB_PF_C_RESET 20
+
+static int usb_get_hub_desc(struct usb_dev *dev, void *data, size_t size)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_DEVICE;
+ req.bRequest = REQ_GET_DESCRIPTOR;
+ req.wIndex = 0;
+ req.wLength = cpu_to_le16((uint16_t) size);
+ req.wValue = cpu_to_le16(DESCR_TYPE_HUB << 8);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+static int hub_get_port_status(struct usb_dev *dev, int port, void *data, size_t size)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_OTHER;
+ req.bRequest = REQ_GET_STATUS;
+ req.wValue = 0;
+ req.wIndex = cpu_to_le16((uint16_t)(port + 1));
+ req.wLength = cpu_to_le16((uint16_t)size);
+ return usb_send_ctrl(dev->control, &req, data);
+}
+
+static int hub_set_port_feature(struct usb_dev *dev, int port, int feature)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER;
+ req.bRequest = REQ_SET_FEATURE;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16((uint16_t)feature);
+ req.wIndex = cpu_to_le16((uint16_t)(port + 1));
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+#if 0
+static int hub_clear_port_feature(struct usb_dev *dev, int port, int feature)
+{
+ struct usb_dev_req req;
+ if (!dev)
+ return false;
+ req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER;
+ req.bRequest = REQ_CLEAR_FEATURE;
+ req.wLength = 0;
+ req.wValue = cpu_to_le16((uint16_t)feature);
+ req.wIndex = cpu_to_le16((uint16_t)(port + 1));
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+#endif
+
+static int hub_check_port(struct usb_dev *dev, int port)
+{
+ struct usb_hub_ps ps;
+ uint32_t time;
+
+ if (!hub_get_port_status(dev, port, &ps, sizeof(ps)))
+ return false;
+ dprintf("Port Status %04X Port Change %04X\n",
+ le16_to_cpu(ps.wPortStatus),
+ le16_to_cpu(ps.wPortChange));
+
+ if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_POWER)) {
+ hub_set_port_feature(dev, port, HUB_PF_POWER);
+ SLOF_msleep(100);
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (time > SLOF_GetTimer()) {
+ cpu_relax();
+ hub_get_port_status(dev, port, &ps, sizeof(ps));
+ if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) {
+ dprintf("power on Port Status %04X Port Change %04X\n",
+ le16_to_cpu(ps.wPortStatus),
+ le16_to_cpu(ps.wPortChange));
+ break;
+ }
+ }
+ }
+
+ if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) {
+ hub_set_port_feature(dev, port, HUB_PF_RESET);
+ SLOF_msleep(100);
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (time > SLOF_GetTimer()) {
+ cpu_relax();
+ hub_get_port_status(dev, port, &ps, sizeof(ps));
+ if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_RESET)) {
+ dprintf("reset Port Status %04X Port Change %04X\n",
+ le16_to_cpu(ps.wPortStatus),
+ le16_to_cpu(ps.wPortChange));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+unsigned int usb_hub_init(void *hubdev)
+{
+ struct usb_dev *dev = hubdev;
+ struct usb_dev_hub_descr hub;
+ struct usb_dev *newdev;
+ int i;
+
+ dprintf("%s: enter %p\n", __func__, dev);
+ if (!dev) {
+ printf("usb-hub: NULL\n");
+ return false;
+ }
+ memset(&hub, 0, sizeof(hub));
+ usb_get_hub_desc(dev, &hub, sizeof(hub));
+ dprintf("usb-hub: ports connected %d\n", hub.bNbrPorts);
+ for (i = 0; i < hub.bNbrPorts; i++) {
+ dprintf("usb-hub: ports scanning %d\n", i);
+ if (hub_check_port(dev, i)) {
+ dprintf("***********************************************\n");
+ dprintf("\t\tusb-hub: device found %d\n", i);
+ dprintf("***********************************************\n");
+ newdev = usb_devpool_get();
+ dprintf("usb-hub: allocated device %p\n", newdev);
+ newdev->hcidev = dev->hcidev;
+ if (!setup_new_device(newdev, i))
+ printf("usb-hub: unable to setup device on port %d\n", i);
+ }
+ }
+ return true;
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-key.c b/qemu/roms/SLOF/lib/libusb/usb-key.c
new file mode 100644
index 000000000..7fb45da2c
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-key.c
@@ -0,0 +1,446 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+
+/***********************************/
+/* Keycodes for US Keyboard */
+/* - no control keys pressed - */
+/***********************************/
+const uint8_t keycodes_std_US[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 'a', /* 4 04 Keyboard a and A 31 */
+ 'b', /* 5 05 Keyboard b and B 50 */
+ 'c', /* 6 06 Keyboard c and C 48 */
+ 'd', /* 7 07 Keyboard d and D 33 */
+ 'e', /* 8 08 Keyboard e and E 19 */
+ 'f', /* 9 09 Keyboard f and F 34 */
+ 'g', /* 10 0A Keyboard g and G 35 */
+ 'h', /* 11 0B Keyboard h and H 36 */
+ 'i', /* 12 0C Keyboard i and I 24 */
+ 'j', /* 13 0D Keyboard j and J 37 */
+ 'k', /* 14 0E Keyboard k and K 38 */
+ 'l', /* 15 0F Keyboard l and L 39 */
+ 'm', /* 16 10 Keyboard m and M 52 */
+ 'n', /* 17 11 Keyboard n and N 51 */
+ 'o', /* 18 12 Keyboard o and O 25 */
+ 'p', /* 19 13 Keyboard p and P 26 */
+ 'q', /* 20 14 Keyboard q and Q 17 */
+ 'r', /* 21 15 Keyboard r and R 20 */
+ 's', /* 22 16 Keyboard s and S 32 */
+ 't', /* 23 17 Keyboard t and T 21 */
+ 'u', /* 24 18 Keyboard u and U 23 */
+ 'v', /* 25 19 Keyboard v and V 49 */
+ 'w', /* 26 1A Keyboard w and W 18 */
+ 'x', /* 27 1B Keyboard x and X 47 */
+ 'y', /* 28 1C Keyboard y and Y 22 */
+ 'z', /* 29 1D Keyboard z and Z 46 */
+ '1', /* 30 1E Keyboard 1 and ! 2 */
+ '2', /* 31 1F Keyboard 2 and @ 3 */
+ '3', /* 32 20 Keyboard 3 and # 4 */
+ '4', /* 33 21 Keyboard 4 and $ 5 */
+ '5', /* 34 22 Keyboard 5 and % 6 */
+ '6', /* 35 23 Keyboard 6 and ^ 7 */
+ '7', /* 36 24 Keyboard 7 and & 8 */
+ '8', /* 37 25 Keyboard 8 and * 9 */
+ '9', /* 38 26 Keyboard 9 and ( 10 */
+ '0', /* 39 27 Keyboard 0 and ) 11 */
+ 13, /* 40 28 Keyboard Return (ENTER) 43 */
+ 27, /* 41 29 Keyboard ESCAPE 110 */
+ 8, /* 42 2A Keyboard DELETE (BS) 15 */
+ 9, /* 43 2B Keyboard Tab 16 */
+ ' ', /* 44 2C Keyboard Spacebar 61 */
+ '-', /* 45 2D Keyboard - and (underscore) 12 */
+ '=', /* 46 2E Keyboard = and + 13 */
+ '[', /* 47 2F Keyboard [ and { 27 */
+ ']', /* 48 30 Keyboard ] and } 28 */
+ '\\', /* 49 31 Keyboard \ and | 29 */
+ '\\', /* 50 32 Keyboard \ and | 42 */
+ ';', /* 51 33 Keyboard ; and : 40 */
+ 39, /* 52 34 Keyboard ' and " 41 */
+ 96, /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ ',', /* 54 36 Keyboard , and < 53 */
+ '.', /* 55 37 Keyboard . and > 54 */
+ '/', /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 0, /* 73 49 Keyboard Insert 75 */
+ 0, /* 74 4A Keyboard Home 80 */
+ 0, /* 75 4B Keyboard PageUp 85 */
+ 0, /* 76 4C Keyboard Delete Forward 76 */
+ 0, /* 77 4D Keyboard End 81 */
+ 0, /* 78 4E Keyboard PageDown 86 */
+ 0, /* 79 4F Keyboard RightArrow 89 */
+ 0, /* 80 50 Keyboard LeftArrow 79 */
+ 0, /* 81 51 Keyboard DownArrow 84 */
+ 0, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ '/', /* 84 54 Keypad / 95 */
+ '*', /* 85 55 Keypad * 100 */
+ '-', /* 86 56 Keypad - 105 */
+ '+', /* 87 57 Keypad + 106 */
+ 13, /* 88 58 Keypad ENTER 108 */
+ '1', /* 89 59 Keypad 1 and End 93 */
+ '2', /* 90 5A Keypad 2 and Down Arrow 98 */
+ '3', /* 91 5B Keypad 3 and PageDn 103 */
+ '4', /* 92 5C Keypad 4 and Left Arrow 92 */
+ '5', /* 93 5D Keypad 5 97 */
+ '6', /* 94 5E Keypad 6 and Right Arrow 102 */
+ '7', /* 95 5F Keypad 7 and Home 91 */
+ '8', /* 96 60 Keypad 8 and Up Arrow 96 */
+ '9', /* 97 61 Keypad 9 and PageUp 101 */
+ '0', /* 98 62 Keypad 0 and Insert 99 */
+ '.', /* 99 63 Keypad . and Delete 104 */
+ '\\' /* 100 64 Keyboard Non-US \ and | 45 */
+};
+
+/***********************************/
+/* Keycodes for US Keyboard */
+/* - SHIFT-KEY pressed - */
+/***********************************/
+const uint8_t keycodes_shift_US[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 'A', /* 4 04 Keyboard a and A 31 */
+ 'B', /* 5 05 Keyboard b and B 50 */
+ 'C', /* 6 06 Keyboard c and C 48 */
+ 'D', /* 7 07 Keyboard d and D 33 */
+ 'E', /* 8 08 Keyboard e and E 19 */
+ 'F', /* 9 09 Keyboard f and F 34 */
+ 'G', /* 10 0A Keyboard g and G 35 */
+ 'H', /* 11 0B Keyboard h and H 36 */
+ 'I', /* 12 0C Keyboard i and I 24 */
+ 'J', /* 13 0D Keyboard j and J 37 */
+ 'K', /* 14 0E Keyboard k and K 38 */
+ 'L', /* 15 0F Keyboard l and L 39 */
+ 'M', /* 16 10 Keyboard m and M 52 */
+ 'N', /* 17 11 Keyboard n and N 51 */
+ 'O', /* 18 12 Keyboard o and O 25 */
+ 'P', /* 19 13 Keyboard p and P 26 */
+ 'Q', /* 20 14 Keyboard q and Q 17 */
+ 'R', /* 21 15 Keyboard r and R 20 */
+ 'S', /* 22 16 Keyboard s and S 32 */
+ 'T', /* 23 17 Keyboard t and T 21 */
+ 'U', /* 24 18 Keyboard u and U 23 */
+ 'V', /* 25 19 Keyboard v and V 49 */
+ 'W', /* 26 1A Keyboard w and W 18 */
+ 'X', /* 27 1B Keyboard x and X 47 */
+ 'Y', /* 28 1C Keyboard y and Y 22 */
+ 'Z', /* 29 1D Keyboard z and Z 46 */
+ '!', /* 30 1E Keyboard 1 and ! 2 */
+ '@', /* 31 1F Keyboard 2 and @ 3 */
+ '#', /* 32 20 Keyboard 3 and # 4 */
+ '$', /* 33 21 Keyboard 4 and $ 5 */
+ '%', /* 34 22 Keyboard 5 and % 6 */
+ '^', /* 35 23 Keyboard 6 and ^ 7 */
+ '&', /* 36 24 Keyboard 7 and & 8 */
+ '*', /* 37 25 Keyboard 8 and * 9 */
+ '(', /* 38 26 Keyboard 9 and ( 10 */
+ ')', /* 39 27 Keyboard 0 and ) 11 */
+ 13, /* 40 28 Keyboard Return (ENTER) 43 */
+ 27, /* 41 29 Keyboard ESCAPE 110 */
+ 8, /* 42 2A Keyboard DELETE (BS) 15 */
+ 9, /* 43 2B Keyboard Tab 16 */
+ ' ', /* 44 2C Keyboard Spacebar 61 */
+ '_', /* 45 2D Keyboard - and (underscore) 12 */
+ '+', /* 46 2E Keyboard = and + 13 */
+ '{', /* 47 2F Keyboard [ and { 27 */
+ '}', /* 48 30 Keyboard ] and } 28 */
+ '|', /* 49 31 Keyboard \ and | 29 */
+ '|', /* 50 32 Keyboard \ and | 42 */
+ ':', /* 51 33 Keyboard ; and : 40 */
+ '"', /* 52 34 Keyboard ' and " 41 */
+ '~', /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ '<', /* 54 36 Keyboard , and < 53 */
+ '>', /* 55 37 Keyboard . and > 54 */
+ '?', /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 48, /* 73 49 Keyboard Insert 75 */
+ 55, /* 74 4A Keyboard Home 80 */
+ 57, /* 75 4B Keyboard PageUp 85 */
+ 46, /* 76 4C Keyboard Delete Forward 76 */
+ 49, /* 77 4D Keyboard End 81 */
+ 51, /* 78 4E Keyboard PageDown 86 */
+ 54, /* 79 4F Keyboard RightArrow 89 */
+ 52, /* 80 50 Keyboard LeftArrow 79 */
+ 50, /* 81 51 Keyboard DownArrow 84 */
+ 56, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ '/', /* 84 54 Keypad / 95 */
+ '*', /* 85 55 Keypad * 100 */
+ '-', /* 86 56 Keypad - 105 */
+ '+', /* 87 57 Keypad + 106 */
+ 13, /* 88 58 Keypad ENTER 108 */
+ '1', /* 89 59 Keypad 1 and End 93 */
+ '2', /* 90 5A Keypad 2 and Down Arrow 98 */
+ '3', /* 91 5B Keypad 3 and PageDn 103 */
+ '4', /* 92 5C Keypad 4 and Left Arrow 92 */
+ '5', /* 93 5D Keypad 5 97 */
+ '6', /* 94 5E Keypad 6 and Right Arrow 102 */
+ '7', /* 95 5F Keypad 7 and Home 91 */
+ '8', /* 96 60 Keypad 8 and Up Arrow 96 */
+ '9', /* 97 61 Keypad 9 and PageUp 101 */
+ '0', /* 98 62 Keypad 0 and Insert 99 */
+ '.', /* 99 63 Keypad . and Delete 104 */
+ '|' /* 100 64 Keyboard Non-US \ and | 45 */
+};
+
+/***********************************/
+/* Keycodes for 1 byte translation */
+/* - CONTROL-KEY pressed - */
+/***********************************/
+const uint8_t keycodes_alt_GR[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 0, /* 4 04 Keyboard a and A 31 */
+ 0, /* 5 05 Keyboard b and B 50 */
+ 0, /* 6 06 Keyboard c and C 48 */
+ 0, /* 7 07 Keyboard d and D 33 */
+ 0, /* 8 08 Keyboard e and E 19 */
+ 0, /* 9 09 Keyboard f and F 34 */
+ 0, /* 10 0A Keyboard g and G 35 */
+ 0, /* 11 0B Keyboard h and H 36 */
+ 0, /* 12 0C Keyboard i and I 24 */
+ 0, /* 13 0D Keyboard j and J 37 */
+ 0, /* 14 0E Keyboard k and K 38 */
+ 0, /* 15 0F Keyboard l and L 39 */
+ 0, /* 16 10 Keyboard m and M 52 */
+ 0, /* 17 11 Keyboard n and N 51 */
+ 0, /* 18 12 Keyboard o and O 25 */
+ 0, /* 19 13 Keyboard p and P 26 */
+ '@', /* 20 14 Keyboard q and Q 17 */
+ 0, /* 21 15 Keyboard r and R 20 */
+ 0, /* 22 16 Keyboard s and S 32 */
+ 0, /* 23 17 Keyboard t and T 21 */
+ 0, /* 24 18 Keyboard u and U 23 */
+ 0, /* 25 19 Keyboard v and V 49 */
+ 0, /* 26 1A Keyboard w and W 18 */
+ 0, /* 27 1B Keyboard x and X 47 */
+ 0, /* 28 1C Keyboard y and Y 22 */
+ 0, /* 29 1D Keyboard z and Z 46 */
+ 0, /* 30 1E Keyboard 1 and ! 2 */
+ 0, /* 31 1F Keyboard 2 and @ 3 */
+ 0, /* 32 20 Keyboard 3 and # 4 */
+ 0, /* 33 21 Keyboard 4 and $ 5 */
+ 0, /* 34 22 Keyboard 5 and % 6 */
+ 0, /* 35 23 Keyboard 6 and ^ 7 */
+ '{', /* 36 24 Keyboard 7 and & 8 */
+ '[', /* 37 25 Keyboard 8 and * 9 */
+ ']', /* 38 26 Keyboard 9 and ( 10 */
+ '}', /* 39 27 Keyboard 0 and ) 11 */
+ 0, /* 40 28 Keyboard Return (ENTER) 43 */
+ 0, /* 41 29 Keyboard ESCAPE 110 */
+ 0, /* 42 2A Keyboard DELETE (BS) 15 */
+ 0, /* 43 2B Keyboard Tab 16 */
+ 0, /* 44 2C Keyboard Spacebar 61 */
+ '\\', /* 45 2D Keyboard - and (underscore) 12 */
+ 0, /* 46 2E Keyboard = and + 13 */
+ 0, /* 47 2F Keyboard [ and { 27 */
+ '~', /* 48 30 Keyboard ] and } 28 */
+ 0, /* 49 31 Keyboard \ and | 29 */
+ 0, /* 50 32 Keyboard Non-US # and ~ 42 */
+ 0, /* 51 33 Keyboard ; and : 40 */
+ 0, /* 52 34 Keyboard ' and " 41 */
+ 0, /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ 0, /* 54 36 Keyboard , and < 53 */
+ 0, /* 55 37 Keyboard . and > 54 */
+ 0, /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 0, /* 73 49 Keyboard Insert 75 */
+ 0, /* 74 4A Keyboard Home 80 */
+ 0, /* 75 4B Keyboard PageUp 85 */
+ 0, /* 76 4C Keyboard Delete Forward 76 */
+ 0, /* 77 4D Keyboard End 81 */
+ 0, /* 78 4E Keyboard PageDown 86 */
+ 0, /* 79 4F Keyboard RightArrow 89 */
+ 0, /* 80 50 Keyboard LeftArrow 79 */
+ 0, /* 81 51 Keyboard DownArrow 84 */
+ 0, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ 0, /* 84 54 Keypad / 95 */
+ 0, /* 85 55 Keypad * 100 */
+ 0, /* 86 56 Keypad - 105 */
+ 0, /* 87 57 Keypad + 106 */
+ 0, /* 88 58 Keypad ENTER 108 */
+ 0, /* 89 59 Keypad 1 and End 93 */
+ 0, /* 90 5A Keypad 2 and Down Arrow 98 */
+ 0, /* 91 5B Keypad 3 and PageDn 103 */
+ 0, /* 92 5C Keypad 4 and Left Arrow 92 */
+ 0, /* 93 5D Keypad 5 97 */
+ 0, /* 94 5E Keypad 6 and Right Arrow 102 */
+ 0, /* 95 5F Keypad 7 and Home 91 */
+ 0, /* 96 60 Keypad 8 and Up Arrow 96 */
+ 0, /* 97 61 Keypad 9 and PageUp 101 */
+ 0, /* 98 62 Keypad 0 and Insert 99 */
+ 0, /* 99 63 Keypad . and Delete 104 */
+ '|' /* 100 64 Keyboard Non-US \ and | 45 */
+};
+
+
+/***********************************/
+/* Keycodes for 1 byte translation */
+/* - CONTROL-KEY pressed - */
+/***********************************/
+const uint8_t keycodes_ctrl[] = {
+ 0, /* 0 00 Reserved (no event indicated) */
+ 0, /* 1 01 Keyboard ErrorRollOver */
+ 0, /* 2 02 Keyboard POSTFail */
+ 0, /* 3 03 Keyboard ErrorUndefined */
+ 1, /* 4 04 Keyboard a and A 31 */
+ 2, /* 5 05 Keyboard b and B 50 */
+ 3, /* 6 06 Keyboard c and C 48 */
+ 4, /* 7 07 Keyboard d and D 33 */
+ 5, /* 8 08 Keyboard e and E 19 */
+ 6, /* 9 09 Keyboard f and F 34 */
+ 7, /* 10 0A Keyboard g and G 35 */
+ 8, /* 11 0B Keyboard h and H 36 */
+ 9, /* 12 0C Keyboard i and I 24 */
+ 10, /* 13 0D Keyboard j and J 37 */
+ 11, /* 14 0E Keyboard k and K 38 */
+ 12, /* 15 0F Keyboard l and L 39 */
+ 13, /* 16 10 Keyboard m and M 52 */
+ 14, /* 17 11 Keyboard n and N 51 */
+ 15, /* 18 12 Keyboard o and O 25 */
+ 16, /* 19 13 Keyboard p and P 26 */
+ 17, /* 20 14 Keyboard q and Q 17 */
+ 18, /* 21 15 Keyboard r and R 20 */
+ 19, /* 22 16 Keyboard s and S 32 */
+ 20, /* 23 17 Keyboard t and T 21 */
+ 21, /* 24 18 Keyboard u and U 23 */
+ 22, /* 25 19 Keyboard v and V 49 */
+ 23, /* 26 1A Keyboard w and W 18 */
+ 24, /* 27 1B Keyboard x and X 47 */
+ 25, /* 28 1C Keyboard y and Y 22 */
+ 26, /* 29 1D Keyboard z and Z 46 */
+ 0, /* 30 1E Keyboard 1 and ! 2 */
+ 0, /* 31 1F Keyboard 2 and @ 3 */
+ 0, /* 32 20 Keyboard 3 and # 4 */
+ 0, /* 33 21 Keyboard 4 and $ 5 */
+ 0, /* 34 22 Keyboard 5 and % 6 */
+ 0, /* 35 23 Keyboard 6 and ^ 7 */
+ 0, /* 36 24 Keyboard 7 and & 8 */
+ 0, /* 37 25 Keyboard 8 and * 9 */
+ 0, /* 38 26 Keyboard 9 and ( 10 */
+ 0, /* 39 27 Keyboard 0 and ) 11 */
+ 0, /* 40 28 Keyboard Return (ENTER) 43 */
+ 0, /* 41 29 Keyboard ESCAPE 110 */
+ 0, /* 42 2A Keyboard DELETE (BS) 15 */
+ 0, /* 43 2B Keyboard Tab 16 */
+ 0, /* 44 2C Keyboard Spacebar 61 */
+ 0, /* 45 2D Keyboard - and (underscore) 12 */
+ 0, /* 46 2E Keyboard = and + 13 */
+ 0, /* 47 2F Keyboard [ and { 27 */
+ 0, /* 48 30 Keyboard ] and } 28 */
+ 0, /* 49 31 Keyboard \ and | 29 */
+ 0, /* 50 32 Keyboard Non-US # and ~ 42 */
+ 0, /* 51 33 Keyboard ; and : 40 */
+ 0, /* 52 34 Keyboard ' and " 41 */
+ 0, /* 53 35 Keyboard Grave Accent and Tilde 1 */
+ 0, /* 54 36 Keyboard , and < 53 */
+ 0, /* 55 37 Keyboard . and > 54 */
+ 0, /* 56 38 Keyboard / and ? 55 */
+ 0, /* 57 39 Keyboard Caps Lock 30 */
+ 0, /* 58 3A Keyboard F1 112 */
+ 0, /* 59 3B Keyboard F2 113 */
+ 0, /* 60 3C Keyboard F3 114 */
+ 0, /* 61 3D Keyboard F4 115 */
+ 0, /* 62 3E Keyboard F5 116 */
+ 0, /* 63 3F Keyboard F6 117 */
+ 0, /* 64 40 Keyboard F7 118 */
+ 0, /* 65 41 Keyboard F8 119 */
+ 0, /* 66 42 Keyboard F9 120 */
+ 0, /* 67 43 Keyboard F10 121 */
+ 0, /* 68 44 Keyboard F11 122 */
+ 0, /* 69 45 Keyboard F12 123 */
+ 0, /* 70 46 Keyboard PrintScreen 124 */
+ 0, /* 71 47 Keyboard Scroll Lock 125 */
+ 0, /* 72 48 Keyboard Pause 126 */
+ 0, /* 73 49 Keyboard Insert 75 */
+ 0, /* 74 4A Keyboard Home 80 */
+ 0, /* 75 4B Keyboard PageUp 85 */
+ 0, /* 76 4C Keyboard Delete Forward 76 */
+ 0, /* 77 4D Keyboard End 81 */
+ 0, /* 78 4E Keyboard PageDown 86 */
+ 0, /* 79 4F Keyboard RightArrow 89 */
+ 0, /* 80 50 Keyboard LeftArrow 79 */
+ 0, /* 81 51 Keyboard DownArrow 84 */
+ 0, /* 82 52 Keyboard UpArrow 83 */
+ 0, /* 83 53 Keypad Num Lock and Clear 90 */
+ 0, /* 84 54 Keypad / 95 */
+ 0, /* 85 55 Keypad * 100 */
+ 0, /* 86 56 Keypad - 105 */
+ 0, /* 87 57 Keypad + 106 */
+ 0, /* 88 58 Keypad ENTER 108 */
+ 0, /* 89 59 Keypad 1 and End 93 */
+ 0, /* 90 5A Keypad 2 and Down Arrow 98 */
+ 0, /* 91 5B Keypad 3 and PageDn 103 */
+ 0, /* 92 5C Keypad 4 and Left Arrow 92 */
+ 0, /* 93 5D Keypad 5 97 */
+ 0, /* 94 5E Keypad 6 and Right Arrow 102 */
+ 0, /* 95 5F Keypad 7 and Home 91 */
+ 0, /* 96 60 Keypad 8 and Up Arrow 96 */
+ 0, /* 97 61 Keypad 9 and PageUp 101 */
+ 0, /* 98 62 Keypad 0 and Insert 99 */
+ 0, /* 99 63 Keypad . and Delete 104 */
+ 0 /* 100 64 Keyboard Non-US \ and | 45 */
+};
diff --git a/qemu/roms/SLOF/lib/libusb/usb-key.h b/qemu/roms/SLOF/lib/libusb/usb-key.h
new file mode 100644
index 000000000..1871a9956
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-key.h
@@ -0,0 +1,42 @@
+#ifndef _USB_KEYB_H
+#define _USB_KEYB_H
+
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#define BIT_0 1
+#define BIT_1 (BIT_0 << 1)
+#define BIT_2 (BIT_0 << 2)
+#define BIT_3 (BIT_0 << 3)
+#define BIT_4 (BIT_0 << 4)
+#define BIT_5 (BIT_0 << 5)
+#define BIT_6 (BIT_0 << 6)
+#define BIT_7 (BIT_0 << 7)
+
+/* bits from modifier input */
+#define MODIFIER_CTRL (BIT_0 | BIT_4)
+#define MODIFIER_SHIFT (BIT_1 | BIT_5)
+#define MODIFIER_ALT (BIT_2 | BIT_6)
+#define MODIFIER_GUI (BIT_3 | BIT_7)
+#define MODIFIER_ALT_GR BIT_6
+
+/* bits representing Keyboard-LEDs */
+#define LED_NUM_LOCK BIT_0
+#define LED_CAPS_LOCK BIT_1
+#define LED_SCROLL_LOCK BIT_2
+
+extern const uint8_t keycodes_std_US[];
+extern const uint8_t keycodes_shift_US[];
+extern const uint8_t keycodes_alt_GR[];
+extern const uint8_t keycodes_ctrl[];
+
+#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.c b/qemu/roms/SLOF/lib/libusb/usb-ohci.c
new file mode 100644
index 000000000..0e8400481
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.c
@@ -0,0 +1,1055 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <byteorder.h>
+#include "usb.h"
+#include "usb-core.h"
+#include "usb-ohci.h"
+
+#undef OHCI_DEBUG
+//#define OHCI_DEBUG
+#ifdef OHCI_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+#undef OHCI_DEBUG_PACKET
+//#define OHCI_DEBUG_PACKET
+#ifdef OHCI_DEBUG_PACKET
+#define dpprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dpprintf(_x ...)
+#endif
+
+
+/*
+ * Dump OHCI register
+ *
+ * @param - ohci_hcd
+ * @return -
+ */
+static void ohci_dump_regs(struct ohci_regs *regs)
+{
+ dprintf("\n - HcRevision %08X", read_reg32(&regs->rev));
+ dprintf(" - HcControl %08X", read_reg32(&regs->control));
+ dprintf("\n - HcCommandStatus %08X", read_reg32(&regs->cmd_status));
+ dprintf(" - HcInterruptStatus %08X", read_reg32(&regs->intr_status));
+ dprintf("\n - HcInterruptEnable %08X", read_reg32(&regs->intr_enable));
+ dprintf(" - HcInterruptDisable %08X", read_reg32(&regs->intr_disable));
+ dprintf("\n - HcHCCA %08X", read_reg32(&regs->hcca));
+ dprintf(" - HcPeriodCurrentED %08X", read_reg32(&regs->period_curr_ed));
+ dprintf("\n - HcControlHeadED %08X", read_reg32(&regs->cntl_head_ed));
+ dprintf(" - HcControlCurrentED %08X", read_reg32(&regs->cntl_curr_ed));
+ dprintf("\n - HcBulkHeadED %08X", read_reg32(&regs->bulk_head_ed));
+ dprintf(" - HcBulkCurrentED %08X", read_reg32(&regs->bulk_curr_ed));
+ dprintf("\n - HcDoneHead %08X", read_reg32(&regs->done_head));
+ dprintf(" - HcFmInterval %08X", read_reg32(&regs->fm_interval));
+ dprintf("\n - HcFmRemaining %08X", read_reg32(&regs->fm_remaining));
+ dprintf(" - HcFmNumber %08X", read_reg32(&regs->fm_num));
+ dprintf("\n - HcPeriodicStart %08X", read_reg32(&regs->period_start));
+ dprintf(" - HcLSThreshold %08X", read_reg32(&regs->ls_threshold));
+ dprintf("\n - HcRhDescriptorA %08X", read_reg32(&regs->rh_desc_a));
+ dprintf(" - HcRhDescriptorB %08X", read_reg32(&regs->rh_desc_b));
+ dprintf("\n - HcRhStatus %08X", read_reg32(&regs->rh_status));
+ dprintf("\n");
+}
+
+/*
+ * OHCI Spec 5.1.1
+ * OHCI Spec 7.4 Root Hub Partition
+ */
+static int ohci_hcd_reset(struct ohci_regs *regs)
+{
+ uint32_t time;
+
+ /* USBRESET - 1sec */
+ write_reg32(&regs->control, 0);
+ SLOF_msleep(100);
+
+ write_reg32(&regs->intr_disable, ~0);
+ write_reg32(&regs->cmd_status, OHCI_CMD_STATUS_HCR);
+ mb();
+
+ time = 30; /* wait for not more than 30usec */
+ while ((read_reg32(&regs->cmd_status) & OHCI_CMD_STATUS_HCR) != 0) {
+ time--;
+ if (!time) {
+ printf(" ** HCD Reset failed...");
+ return -1;
+ }
+ SLOF_usleep(1);
+ }
+ return 0;
+}
+
+static int ohci_hcd_init(struct ohci_hcd *ohcd)
+{
+ struct ohci_regs *regs;
+ struct ohci_ed *ed;
+ long ed_phys = 0;
+ unsigned int i;
+ uint32_t oldrwc;
+ struct usb_dev *rhdev = NULL;
+ struct usb_ep_descr ep;
+ uint32_t reg;
+
+ if (!ohcd)
+ return -1;
+
+ regs = ohcd->regs;
+ rhdev = &ohcd->rhdev;
+ dprintf("%s: HCCA memory %p\n", __func__, ohcd->hcca);
+ dprintf("%s: OHCI Regs %p\n", __func__, regs);
+
+ rhdev->hcidev = ohcd->hcidev;
+ ep.bmAttributes = USB_EP_TYPE_INTR;
+ ep.wMaxPacketSize = 8;
+ rhdev->intr = usb_get_pipe(rhdev, &ep, NULL, 0);
+ if (!rhdev->intr) {
+ printf("usb-ohci: oops could not allocate intr_pipe\n");
+ return -1;
+ }
+
+ /*
+ * OHCI Spec 4.4: Host Controller Communications Area
+ */
+ ed = ohci_pipe_get_ed(rhdev->intr);
+ ed_phys = ohci_pipe_get_ed_phys(rhdev->intr);
+ memset(ohcd->hcca, 0, HCCA_SIZE);
+ memset(ed, 0, sizeof(struct ohci_ed));
+ ed->attr = cpu_to_le32(EDA_SKIP);
+ for (i = 0; i < HCCA_INTR_NUM; i++)
+ ohcd->hcca->intr_table[i] = cpu_to_le32(ed_phys);
+
+ write_reg32(&regs->hcca, ohcd->hcca_phys);
+ write_reg32(&regs->cntl_head_ed, 0);
+ write_reg32(&regs->bulk_head_ed, 0);
+
+ /* OHCI Spec 7.1.2 HcControl Register */
+ oldrwc = read_reg32(&regs->control) & OHCI_CTRL_RWC;
+ write_reg32(&regs->control, (OHCI_CTRL_CBSR | OHCI_CTRL_CLE |
+ OHCI_CTRL_BLE | OHCI_CTRL_PLE |
+ OHCI_USB_OPER | oldrwc));
+ SLOF_msleep(100);
+ /*
+ * For JS20/21 need to rewrite it after setting it to
+ * operational state
+ */
+ write_reg32(&regs->fm_interval, FRAME_INTERVAL);
+ write_reg32(&regs->period_start, PERIODIC_START);
+ reg = read_reg32(&regs->rh_desc_a);
+ reg &= ~( RHDA_PSM_INDIVIDUAL | RHDA_OCPM_PERPORT );
+ reg |= RHDA_NPS_ENABLE;
+ write_reg32(&regs->rh_desc_a, reg);
+ write_reg32(&regs->rh_desc_b, 0);
+ mb();
+ SLOF_msleep(100);
+ ohci_dump_regs(regs);
+ return 0;
+}
+
+/*
+ * OHCI Spec 7.4 Root Hub Partition
+ */
+static void ohci_hub_check_ports(struct ohci_hcd *ohcd)
+{
+ struct ohci_regs *regs;
+ struct usb_dev *dev;
+ unsigned int ports, i, port_status, port_clear = 0;
+
+ regs = ohcd->regs;
+ ports = read_reg32(&regs->rh_desc_a) & RHDA_NDP;
+ write_reg32(&regs->rh_status, RH_STATUS_LPSC);
+ SLOF_msleep(100);
+ dprintf("usb-ohci: ports connected %d\n", ports);
+ for (i = 0; i < ports; i++) {
+ dprintf("usb-ohci: ports scanning %d\n", i);
+ port_status = read_reg32(&regs->rh_ps[i]);
+ if (port_status & RH_PS_CSC) {
+ if (port_status & RH_PS_CCS) {
+ write_reg32(&regs->rh_ps[i], RH_PS_PRS);
+ mb();
+ port_clear |= RH_PS_CSC;
+ dprintf("Start enumerating device\n");
+ SLOF_msleep(100);
+ } else
+ printf("Start removing device\n");
+ }
+ port_status = read_reg32(&regs->rh_ps[i]);
+ if (port_status & RH_PS_PRSC) {
+ port_clear |= RH_PS_PRSC;
+ dev = usb_devpool_get();
+ dprintf("usb-ohci: Device reset, setting up %p\n", dev);
+ dev->hcidev = ohcd->hcidev;
+ if (!setup_new_device(dev, i))
+ printf("usb-ohci: unable to setup device on port %d\n", i);
+ }
+ if (port_status & RH_PS_PESC) {
+ port_clear |= RH_PS_PESC;
+ if (port_status & RH_PS_PES)
+ dprintf("enabled\n");
+ else
+ dprintf("disabled\n");
+ }
+ if (port_status & RH_PS_PSSC) {
+ port_clear |= RH_PS_PESC;
+ dprintf("suspended\n");
+ }
+ port_clear &= 0xFFFF0000;
+ if (port_clear)
+ write_reg32(&regs->rh_ps[i], port_clear);
+ }
+}
+
+static inline struct ohci_ed *ohci_pipe_get_ed(struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ opipe = container_of(pipe, struct ohci_pipe, pipe);
+ dpprintf("%s: ed is %p\n", __func__, &opipe->ed);
+ return &opipe->ed;
+}
+
+static inline long ohci_pipe_get_ed_phys(struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ opipe = container_of(pipe, struct ohci_pipe, pipe);
+ dpprintf("%s: ed_phys is %x\n", __func__, opipe->ed_phys);
+ return opipe->ed_phys;
+}
+
+static inline struct ohci_pipe *ohci_pipe_get_opipe(struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ opipe = container_of(pipe, struct ohci_pipe, pipe);
+ dpprintf("%s: opipe is %p\n", __func__, opipe);
+ return opipe;
+}
+
+static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd)
+{
+ struct ohci_pipe *opipe, *curr, *prev;
+ long opipe_phys = 0;
+ unsigned int i, count;
+#ifdef OHCI_DEBUG_PACKET
+ struct usb_pipe *pipe;
+#endif
+
+ dprintf("usb-ohci: %s enter\n", __func__);
+ count = OHCI_PIPE_POOL_SIZE/sizeof(*opipe);
+ ohcd->pool = opipe = SLOF_dma_alloc(OHCI_PIPE_POOL_SIZE);
+ if (!opipe)
+ return false;
+
+ ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true);
+ dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n",
+ __func__, opipe, opipe_phys, sizeof(*opipe), count);
+ /* Although an array, link them*/
+ for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) {
+ if (prev)
+ prev->pipe.next = &curr->pipe;
+ curr->pipe.next = NULL;
+ prev = curr;
+
+ if (((uint64_t)&curr->ed) % 16)
+ printf("usb-ohci: Warning ED not aligned to 16byte boundary");
+ curr->ed_phys = opipe_phys + (curr - opipe) * sizeof(*curr) +
+ offset_of(struct ohci_pipe, ed);
+ }
+
+ if (!ohcd->freelist)
+ ohcd->freelist = &opipe->pipe;
+ else
+ ohcd->end->next = &opipe->pipe;
+ ohcd->end = &prev->pipe;
+
+#ifdef OHCI_DEBUG_PACKET
+ for (i = 0, pipe = ohcd->freelist; pipe; pipe = pipe->next)
+ dprintf("usb-ohci: %d: pipe cur %p ed %p ed_phys %x\n",
+ i++, pipe, ohci_pipe_get_ed(pipe),
+ ohci_pipe_get_ed_phys(pipe));
+#endif
+
+ dprintf("usb-ohci: %s exit\n", __func__);
+ return true;
+}
+
+static void ohci_init(struct usb_hcd_dev *hcidev)
+{
+ struct ohci_hcd *ohcd;
+
+ printf(" OHCI: initializing\n");
+ dprintf("%s: device base address %p\n", __func__, hcidev->base);
+
+ ohcd = SLOF_alloc_mem(sizeof(struct ohci_hcd));
+ if (!ohcd) {
+ printf("usb-ohci: Unable to allocate memory\n");
+ goto out;
+ }
+
+ hcidev->nextaddr = 1;
+ hcidev->priv = ohcd;
+ memset(ohcd, 0, sizeof(*ohcd));
+ ohcd->hcidev = hcidev;
+ ohcd->freelist = NULL;
+ ohcd->end = NULL;
+ ohcd->regs = (struct ohci_regs *)(hcidev->base);
+ ohcd->hcca = SLOF_dma_alloc(sizeof(struct ohci_hcca));
+ if (!ohcd->hcca || PTR_U32(ohcd->hcca) & HCCA_ALIGN) {
+ printf("usb-ohci: Unable to allocate/unaligned HCCA memory %p\n",
+ ohcd->hcca);
+ goto out_free_hcd;
+ }
+ ohcd->hcca_phys = SLOF_dma_map_in(ohcd->hcca,
+ sizeof(struct ohci_hcca), true);
+ dprintf("usb-ohci: HCCA memory %p HCCA-dev memory %08lx\n",
+ ohcd->hcca, ohcd->hcca_phys);
+
+ ohci_hcd_reset(ohcd->regs);
+ ohci_hcd_init(ohcd);
+ ohci_hub_check_ports(ohcd);
+ return;
+
+out_free_hcd:
+ SLOF_dma_free(ohcd->hcca, sizeof(struct ohci_hcca));
+ SLOF_free_mem(ohcd, sizeof(struct ohci_hcd));
+out:
+ return;
+}
+
+static void ohci_exit(struct usb_hcd_dev *hcidev)
+{
+ struct ohci_hcd *ohcd = NULL;
+
+ dprintf("%s: enter \n", __func__);
+ if (!hcidev && !hcidev->priv)
+ return;
+
+ ohcd = hcidev->priv;
+ write_reg32(&ohcd->regs->control, (OHCI_CTRL_CBSR | OHCI_USB_SUSPEND));
+ SLOF_msleep(20);
+ write_reg32(&ohcd->regs->hcca, cpu_to_le32(0));
+
+ if (ohcd->pool) {
+ SLOF_dma_map_out(ohcd->pool_phys, ohcd->pool, OHCI_PIPE_POOL_SIZE);
+ SLOF_dma_free(ohcd->pool, OHCI_PIPE_POOL_SIZE);
+ }
+ if (ohcd->hcca) {
+ SLOF_dma_map_out(ohcd->hcca_phys, ohcd->hcca, sizeof(struct ohci_hcca));
+ SLOF_dma_free(ohcd->hcca, sizeof(struct ohci_hcca));
+ }
+ SLOF_free_mem(ohcd, sizeof(struct ohci_hcd));
+ return;
+}
+
+static void ohci_detect(void)
+{
+
+}
+
+static void ohci_disconnect(void)
+{
+
+}
+
+#define OHCI_CTRL_TDS 3
+
+static void ohci_fill_td(struct ohci_td *td, long next,
+ long req, size_t size, unsigned int attr)
+{
+ if (size && req) {
+ td->cbp = cpu_to_le32(req);
+ td->be = cpu_to_le32(req + size - 1);
+ } else {
+ td->cbp = 0;
+ td->be = 0;
+ }
+ td->attr = cpu_to_le32(attr);
+ td->next_td = cpu_to_le32(next);
+
+ dpprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n", __func__,
+ le32_to_cpu(td->cbp), le32_to_cpu(td->attr),
+ le32_to_cpu(td->next_td), le32_to_cpu(td->be));
+}
+
+static void ohci_fill_ed(struct ohci_ed *ed, long headp, long tailp,
+ unsigned int attr, long next_ed)
+{
+ ed->attr = cpu_to_le32(attr);
+ ed->headp = cpu_to_le32(headp) | (ed->headp & ~EDA_HEADP_MASK_LE);
+ ed->tailp = cpu_to_le32(tailp);
+ ed->next_ed = cpu_to_le32(next_ed);
+ dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+
+}
+
+static long ohci_get_td_phys(struct ohci_td *curr, struct ohci_td *start, long td_phys)
+{
+ dpprintf("position %d\n", curr - start);
+ return td_phys + (curr - start) * sizeof(*start);
+}
+
+static long ohci_get_td_virt(struct ohci_td *curr, struct ohci_td *start, long td_virt, long total_count)
+{
+ dpprintf("position %d\n", curr - start);
+ if ( (curr - start) >= total_count) {
+ /* busted position, should ignore this */
+ return 0;
+ }
+ return td_virt + (curr - start) * sizeof(*start);
+}
+
+/* OHCI Spec: 4.4.2.3 HccaDoneHead*/
+static int ohci_process_done_head(struct ohci_hcd *ohcd,
+ struct ohci_td *td_start,
+ long __td_start_phys, long total_count)
+{
+ struct ohci_hcca *hcca;
+ struct ohci_td *td_phys = NULL, *td_start_phys;
+ struct ohci_td *td, *prev_td = NULL;
+ uint32_t reg = 0, time = 0;
+ int ret = true;
+ long count;
+
+ count = total_count;
+ td_start_phys = (struct ohci_td *) __td_start_phys;
+ hcca = ohcd->hcca;
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ dpprintf("Claiming %ld\n", count);
+
+again:
+ mb();
+ /* Check if there is an interrupt */
+ reg = read_reg32(&ohcd->regs->intr_status);
+ while(!(reg & OHCI_INTR_STATUS_WD))
+ {
+ if (time < SLOF_GetTimer()) {
+ printf("Timed out waiting for interrupt %x\n", reg);
+ return false;
+ }
+ mb();
+ reg = read_reg32(&ohcd->regs->intr_status);
+ }
+
+ /* Interrupt is there, read from done_head pointer */
+ td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head);
+ if (!td_phys) {
+ dprintf("Again td_phys null %ld\n");
+ goto again;
+ }
+ hcca->done_head = 0;
+ mb();
+
+ while (td_phys && (count > 0)) {
+ td = (struct ohci_td *)(uint64_t) ohci_get_td_virt(td_phys,
+ td_start_phys,
+ PTR_U32(td_start),
+ total_count);
+
+ if (!td) {
+ printf("USB: Error TD null %p\n", td_phys);
+ break;
+ }
+ count--;
+ dprintf("Claimed %p(%p) td_start %p count %ld\n",
+ td, td_phys, td_start_phys, count);
+ dpprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n",
+ __func__,
+ le32_to_cpu(td->cbp), le32_to_cpu(td->attr),
+ le32_to_cpu(td->next_td), le32_to_cpu(td->be));
+ mb();
+ reg = (le32_to_cpu(td->attr) & TDA_CC) >> 28;
+ if (reg) {
+ dprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n",
+ __func__,
+ le32_to_cpu(td->cbp), le32_to_cpu(td->attr),
+ le32_to_cpu(td->next_td), le32_to_cpu(td->be));
+ printf("USB: Error %s %p\n", tda_cc_error[reg], td);
+ if (reg > 3) /* Return negative error code */
+ ret = reg * -1;
+ }
+ prev_td = td;
+ td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(td->next_td);
+ prev_td->attr |= cpu_to_le32(TDA_DONE);
+ prev_td->next_td = 0;
+ mb();
+ }
+ /* clear the WD interrupt status */
+ write_reg32(&ohcd->regs->intr_status, OHCI_INTR_STATUS_WD);
+ mb();
+ read_reg32(&ohcd->regs->intr_status);
+
+ if (count > 0) {
+ dpprintf("Pending count %d\n", count);
+ goto again;
+ }
+ dprintf("TD claims done\n");
+ return ret;
+}
+
+/*
+ * OHCI Spec:
+ * 4.2 Endpoint Descriptor
+ * 4.3.1 General Transfer Descriptor
+ * 5.2.8 Transfer Descriptor Queues
+ */
+static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct ohci_ed *ed;
+ struct ohci_td *tds, *td, *td_phys;
+ struct ohci_regs *regs;
+ struct ohci_hcd *ohcd;
+ uint32_t datalen;
+ uint32_t dir, attr = 0;
+ uint32_t time;
+ int ret = true, i;
+ long req_phys = 0, data_phys = 0, td_next = 0, td_count = 0;
+ unsigned char *dbuf;
+
+ datalen = le16_to_cpu(req->wLength);
+ dir = (req->bmRequestType & REQT_DIR_IN) ? 1 : 0;
+
+ dprintf("usb-ohci: %s len %d DIR_IN %d\n", __func__, datalen, dir);
+
+ tds = td = (struct ohci_td *) SLOF_dma_alloc(sizeof(*td) * OHCI_CTRL_TDS);
+ td_phys = (struct ohci_td *) SLOF_dma_map_in(td, sizeof(*td) * OHCI_CTRL_TDS, true);
+ memset(td, 0, sizeof(*td) * OHCI_CTRL_TDS);
+
+ req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true);
+ attr = TDA_DP_SETUP | TDA_CC | TDA_TOGGLE_DATA0;
+ td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys));
+ ohci_fill_td(td, td_next, req_phys, sizeof(*req), attr);
+ td++; td_count++;
+
+ if (datalen) {
+ data_phys = SLOF_dma_map_in(data, datalen, true);
+ attr = 0;
+ attr = (dir ? TDA_DP_IN : TDA_DP_OUT) | TDA_TOGGLE_DATA1 | TDA_CC;
+ td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys));
+ ohci_fill_td(td, td_next, data_phys, datalen, attr);
+ td++; td_count++;
+ }
+
+ attr = 0;
+ attr = (dir ? TDA_DP_OUT : TDA_DP_IN) | TDA_CC | TDA_TOGGLE_DATA1;
+ td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys));
+ ohci_fill_td(td, 0, 0, 0, attr);
+ td_count++;
+
+ ed = ohci_pipe_get_ed(pipe);
+ attr = 0;
+ attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP;
+ ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0);
+ ed->tailp = 0; /* HACK */
+ dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__,
+ td_phys, td_next, req_phys);
+ mb();
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+
+ ohcd = pipe->dev->hcidev->priv;
+ regs = ohcd->regs;
+ write_reg32(&regs->cntl_head_ed, ohci_pipe_get_ed_phys(pipe));
+ mb();
+ write_reg32(&regs->cmd_status, OHCI_CMD_STATUS_CLF);
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while ((time > SLOF_GetTimer()) &&
+ ((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp))
+ cpu_relax();
+
+ if ((ed->headp & EDA_HEADP_MASK_LE) == ed->tailp) {
+ dprintf("%s: packet sent\n", __func__);
+#ifdef OHCI_DEBUG_PACKET
+ dpprintf("Request: ");
+ dbuf = (unsigned char *)req;
+ for(i = 0; i < 8; i++)
+ printf("%02X ", dbuf[i]);
+ dpprintf("\n");
+ if (datalen) {
+ dbuf = (unsigned char *)data;
+ dpprintf("Reply: ");
+ for(i = 0; i < datalen; i++)
+ printf("%02X ", dbuf[i]);
+ dpprintf("\n");
+ }
+#endif
+ }
+ else {
+ printf("%s: timed out - failed\n", __func__);
+ dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n",
+ __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+ printf("Request: ");
+ dbuf = (unsigned char *)req;
+ for(i = 0; i < 8; i++)
+ printf("%02X ", dbuf[i]);
+ printf("\n");
+ }
+ ret = ohci_process_done_head(ohcd, tds, (long)td_phys, td_count);
+ mb();
+ ed->attr |= cpu_to_le32(EDA_SKIP);
+ mb();
+ write_reg32(&regs->cntl_head_ed, 0);
+ write_reg32(&regs->cntl_curr_ed, 0);
+
+ SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req));
+ if (datalen)
+ SLOF_dma_map_out(data_phys, data, datalen);
+ SLOF_dma_map_out(PTR_U32(td_phys), tds, sizeof(*td) * OHCI_CTRL_TDS);
+ SLOF_dma_free(tds, sizeof(*td) * OHCI_CTRL_TDS);
+ return (ret > 0) ? true : false;
+}
+
+static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr,
+ void *td_phys_ptr, void *data_phys, int datalen)
+{
+ struct ohci_ed *ed;
+ struct ohci_td *td, *tds;
+ struct ohci_regs *regs;
+ struct ohci_hcd *ohcd;
+ long td_phys = 0, td_next, ed_phys, ptr, td_count = 0;
+ uint32_t dir, attr = 0, count;
+ size_t len, packet_len;
+ uint32_t time;
+ int ret = true;
+
+ if (pipe->type != USB_EP_TYPE_BULK) {
+ printf("usb-ohci: Not a bulk pipe.\n");
+ ret = false;
+ goto end;
+ }
+
+ dir = (pipe->dir == USB_PIPE_OUT) ? 0 : 1;
+ count = datalen / OHCI_MAX_BULK_SIZE;
+ if (count > OHCI_MAX_TDS) {
+ printf("usb-ohci: buffer size not supported - %d\n", datalen);
+ ret = false;
+ goto end;
+ }
+
+ td = tds = (struct ohci_td *) td_ptr;
+ td_phys = (long)td_phys_ptr;
+ dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n",
+ __func__, pipe, data_phys, datalen, dir, td, td_phys);
+
+ if (!tds) {
+ printf("%s: tds NULL recieved\n", __func__);
+ ret = false;
+ goto end;
+ }
+ memset(td, 0, sizeof(*td) * OHCI_MAX_TDS);
+
+ len = datalen;
+ ptr = (long)data_phys;
+ attr = 0;
+ attr = (dir ? TDA_DP_IN : TDA_DP_OUT) | TDA_CC | TDA_ROUNDING;
+ while (len) {
+ packet_len = (OHCI_MAX_BULK_SIZE < len)? OHCI_MAX_BULK_SIZE : len;
+ td_next = ohci_get_td_phys((td + 1), tds, td_phys);
+ ohci_fill_td(td, td_next, ptr, packet_len, attr);
+ ptr = ptr + packet_len;
+ len = len - packet_len;
+ td++; td_count++;
+ }
+
+ ed = ohci_pipe_get_ed(pipe);
+ attr = 0;
+ dir = pipe->dir ? EDA_DIR_IN : EDA_DIR_OUT;
+ attr = dir | EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps)
+ | EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno);
+ td_next = ohci_get_td_phys(td, tds, td_phys);
+ ohci_fill_ed(ed, td_phys, td_next, attr, 0);
+ dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next);
+ mb();
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+
+ ohcd = pipe->dev->hcidev->priv;
+ regs = ohcd->regs;
+ ed_phys = ohci_pipe_get_ed_phys(pipe);
+ write_reg32(&regs->bulk_head_ed, ed_phys);
+ mb();
+ write_reg32(&regs->cmd_status, 0x4);
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while ((time > SLOF_GetTimer()) &&
+ ((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp))
+ cpu_relax();
+
+ if ((ed->headp & EDA_HEADP_MASK_LE) == ed->tailp)
+ dprintf("%s: packet sent\n", __func__);
+ else {
+ dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+ }
+ mb();
+ ret = ohci_process_done_head(ohcd, tds, td_phys, td_count);
+ mb();
+ ed->attr |= cpu_to_le32(EDA_SKIP);
+ mb();
+ write_reg32(&regs->bulk_head_ed, 0);
+ write_reg32(&regs->bulk_curr_ed, 0);
+
+ if (le32_to_cpu(ed->headp) & EDA_HEADP_HALTED) {
+ printf("ED Halted\n");
+ printf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__,
+ le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp),
+ le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr));
+ ed->headp &= ~cpu_to_le32(EDA_HEADP_HALTED);
+ mb();
+ if (ret == USB_STALL) /* Call reset recovery */
+ usb_msc_resetrecovery(pipe->dev);
+ }
+
+end:
+ return (ret > 0) ? true : false;
+}
+
+/* Populate the hcca intr region with periodic intr */
+static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd,
+ char *buf, size_t buflen)
+{
+ struct ohci_hcca *hcca;
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ struct usb_dev *dev;
+ struct ohci_td *tds, *td;
+ int32_t count = 0, i;
+ uint8_t *ptr;
+ uint16_t mps;
+ long ed_phys, td_phys, td_next, buf_phys;
+
+ if (!pipe || !ohcd)
+ return false;
+
+ hcca = ohcd->hcca;
+ dev = pipe->dev;
+ if (dev->class != DEV_HID_KEYB && dev->class != DEV_HUB)
+ return false;
+
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &(opipe->ed);
+ ed_phys = opipe->ed_phys;
+ mps = pipe->mps;
+ ed->attr = cpu_to_le32(EDA_DIR_IN |
+ EDA_FADDR(dev->addr) |
+ dev->speed |
+ EDA_MPS(pipe->mps) |
+ EDA_SKIP |
+ EDA_EP(pipe->epno));
+ dprintf("%s: pipe %p ed %p dev %p opipe %p\n", __func__,
+ pipe, ed, dev, opipe);
+ count = (buflen/mps) + 1;
+ tds = td = SLOF_dma_alloc(sizeof(*td) * count);
+ if (!tds) {
+ printf("%s: alloc failed\n", __func__);
+ return false;
+ }
+ td_phys = SLOF_dma_map_in(td, sizeof(*td) * count, false);
+
+ memset(tds, 0, sizeof(*tds) * count);
+ memset(buf, 0, buflen);
+ buf_phys = SLOF_dma_map_in(buf, buflen, false);
+ opipe->td = td;
+ opipe->td_phys = td_phys;
+ opipe->count = count;
+ opipe->buf = buf;
+ opipe->buflen = buflen;
+ opipe->buf_phys = buf_phys;
+
+ ptr = (uint8_t *)buf_phys;
+ for (i = 0; i < count - 1; i++, ptr += mps) {
+ td = &tds[i];
+ td_next = ohci_get_td_phys(td + 1, &tds[0], td_phys);
+ td->cbp = cpu_to_le32(PTR_U32(ptr));
+ td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC);
+ td->next_td = cpu_to_le32(td_next);
+ td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1);
+ dprintf("td %x td++ %x ptr %x be %x\n",
+ td, le32_to_cpu(td->next_td),
+ ptr, (PTR_U32(ptr) + mps - 1));
+ }
+ td->next_td = 0;
+ td_next = ohci_get_td_phys(td, &tds[0], td_phys);
+ ed->headp = cpu_to_le32(td_phys);
+ ed->tailp = cpu_to_le32(td_next);
+
+ dprintf("%s: head %08X tail %08X, count %d, mps %d\n", __func__,
+ le32_to_cpu(ed->headp),
+ le32_to_cpu(ed->tailp),
+ count, mps);
+ ed->next_ed = 0;
+
+
+ switch (dev->class) {
+ case DEV_HID_KEYB:
+ dprintf("%s: Keyboard class %d\n", __func__, dev->class);
+ hcca->intr_table[0] = cpu_to_le32(ed_phys);
+ hcca->intr_table[8] = cpu_to_le32(ed_phys);
+ hcca->intr_table[16] = cpu_to_le32(ed_phys);
+ hcca->intr_table[24] = cpu_to_le32(ed_phys);
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+ break;
+
+ case DEV_HUB:
+ dprintf("%s: HUB class %x\n", __func__, dev->class);
+ hcca->intr_table[1] = cpu_to_le32(ed_phys);
+ ed->attr &= cpu_to_le32(~EDA_SKIP);
+ break;
+
+ default:
+ dprintf("%s: unhandled class %d\n", __func__, dev->class);
+ }
+ return true;
+}
+
+static int ohci_put_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd)
+{
+ struct ohci_hcca *hcca;
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ struct usb_dev *dev;
+ struct ohci_td *td;
+ long ed_phys;
+
+ if (!pipe || !ohcd)
+ return false;
+
+ hcca = ohcd->hcca;
+ dev = pipe->dev;
+
+ if (dev->class != DEV_HID_KEYB && dev->class != DEV_HUB)
+ return false;
+
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &(opipe->ed);
+ ed_phys = opipe->ed_phys;
+ dprintf("%s: td %p td_phys %08lx buf %p buf_phys %08lx\n", __func__,
+ opipe->td, opipe->td_phys, opipe->buf, opipe->buf_phys);
+
+ ed->attr |= cpu_to_le32(EDA_SKIP);
+ mb();
+ ed->headp = 0;
+ ed->tailp = 0;
+ ed->next_ed = 0;
+ SLOF_dma_map_out(opipe->buf_phys, opipe->buf, opipe->buflen);
+ SLOF_dma_map_out(opipe->td_phys, opipe->td, sizeof(*td) * opipe->count);
+ SLOF_dma_free(opipe->td, sizeof(*td) * opipe->count);
+
+ switch (dev->class) {
+ case DEV_HID_KEYB:
+ dprintf("%s: Keyboard class %d\n", __func__, dev->class);
+ hcca->intr_table[0] = cpu_to_le32(ed_phys);
+ hcca->intr_table[8] = cpu_to_le32(ed_phys);
+ hcca->intr_table[16] = cpu_to_le32(ed_phys);
+ hcca->intr_table[24] = cpu_to_le32(ed_phys);
+ break;
+
+ case DEV_HUB:
+ dprintf("%s: HUB class %d\n", __func__, dev->class);
+ hcca->intr_table[1] = cpu_to_le32(ed_phys);
+ break;
+
+ default:
+ dprintf("%s: unhandled class %d\n", __func__, dev->class);
+ }
+ return true;
+}
+
+static int ohci_init_bulk_ed(struct usb_dev *dev, struct usb_pipe *pipe)
+{
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ uint32_t dir;
+
+ if (!pipe || !dev)
+ return false;
+
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &(opipe->ed);
+ dir = pipe->dir ? EDA_DIR_IN : EDA_DIR_OUT;
+
+ ed->attr = cpu_to_le32(dir |
+ EDA_FADDR(dev->addr) |
+ dev->speed |
+ EDA_MPS(pipe->mps) |
+ EDA_SKIP |
+ EDA_EP(pipe->epno));
+
+ dprintf("%s: pipe %p attr %x\n", __func__, pipe,
+ le32_to_cpu(ed->attr));
+ return true;
+}
+
+static struct usb_pipe *ohci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
+ char *buf, size_t buflen)
+{
+ struct ohci_hcd *ohcd;
+ struct usb_pipe *new = NULL;
+
+ dprintf("usb-ohci: %s enter %p\n", __func__, dev);
+ if (!dev)
+ return NULL;
+
+ ohcd = (struct ohci_hcd *)dev->hcidev->priv;
+ if (!ohcd->freelist) {
+ dprintf("usb-ohci: %s allocating pool\n", __func__);
+ if (!ohci_alloc_pipe_pool(ohcd))
+ return NULL;
+ }
+
+ new = ohcd->freelist;
+ ohcd->freelist = ohcd->freelist->next;
+ if (!ohcd->freelist)
+ ohcd->end = NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->dev = dev;
+ new->next = NULL;
+ new->type = ep->bmAttributes & USB_EP_TYPE_MASK;
+ new->speed = dev->speed;
+ new->mps = le16_to_cpu(ep->wMaxPacketSize);
+ new->epno = ep->bEndpointAddress & 0xF;
+ new->dir = ep->bEndpointAddress & 0x80;
+ if (new->type == USB_EP_TYPE_INTR)
+ if (!ohci_get_pipe_intr(new, ohcd, buf, buflen))
+ dprintf("usb-ohci: %s alloc_intr failed %p\n",
+ __func__, new);
+ if (new->type == USB_EP_TYPE_BULK)
+ ohci_init_bulk_ed(dev, new);
+
+ dprintf("usb-ohci: %s exit %p\n", __func__, new);
+ return new;
+}
+
+static void ohci_put_pipe(struct usb_pipe *pipe)
+{
+ struct ohci_hcd *ohcd;
+
+ dprintf("usb-ohci: %s enter - %p\n", __func__, pipe);
+ if (!pipe || !pipe->dev)
+ return;
+ ohcd = pipe->dev->hcidev->priv;
+ if (ohcd->end)
+ ohcd->end->next = pipe;
+ else
+ ohcd->freelist = pipe;
+
+ if (pipe->type == USB_EP_TYPE_INTR)
+ if (!ohci_put_pipe_intr(pipe, ohcd))
+ dprintf("usb-ohci: %s alloc_intr failed %p\n",
+ __func__, pipe);
+
+ ohcd->end = pipe;
+ pipe->next = NULL;
+ pipe->dev = NULL;
+ memset(pipe, 0, sizeof(*pipe));
+ dprintf("usb-ohci: %s exit\n", __func__);
+}
+
+static uint16_t ohci_get_last_frame(struct usb_dev *dev)
+{
+ struct ohci_hcd *ohcd;
+ struct ohci_regs *regs;
+
+ ohcd = dev->hcidev->priv;
+ regs = ohcd->regs;
+ return read_reg32(&regs->fm_num);
+}
+
+static int ohci_poll_intr(struct usb_pipe *pipe, uint8_t *data)
+{
+ struct ohci_pipe *opipe;
+ struct ohci_ed *ed;
+ struct ohci_td *head, *tail, *curr, *next;
+ struct ohci_td *head_phys, *tail_phys, *curr_phys;
+ uint8_t *ptr = NULL;
+ unsigned int i, pos;
+ static uint16_t last_frame;
+ long ptr_phys = 0;
+ long td_next;
+
+ if (!pipe || last_frame == ohci_get_last_frame(pipe->dev))
+ return 0;
+
+ dprintf("%s: enter\n", __func__);
+
+ last_frame = ohci_get_last_frame(pipe->dev);
+ opipe = ohci_pipe_get_opipe(pipe);
+ ed = &opipe->ed;
+
+ head_phys = (struct ohci_td *)(long)(le32_to_cpu(ed->headp) & EDA_HEADP_MASK);
+ tail_phys = (struct ohci_td *)(long)le32_to_cpu(ed->tailp);
+ curr_phys = (struct ohci_td *) opipe->td_phys;
+ pos = (tail_phys - curr_phys + 1) % (opipe->count - 1);
+ dprintf("pos %d %ld -- %d\n", pos, (tail_phys - curr_phys + 1),
+ opipe->count);
+ curr = opipe->td + pos;
+ head = opipe->td + (head_phys - (struct ohci_td *) opipe->td_phys);
+ tail = opipe->td + (tail_phys - (struct ohci_td *) opipe->td_phys);
+
+ /* dprintf("%08X %08X %08X %08X\n",
+ opipe->td_phys, head_phys, tail_phys, curr_phys);
+ dprintf("%08X %08X %08X %08X\n", opipe->td, head, tail, curr); */
+
+ if (curr != head) {
+ ptr = (uint8_t *) ((long)opipe->buf + pipe->mps * pos);
+ ptr_phys = opipe->buf_phys + pipe->mps * pos;
+ if (le32_to_cpu(*(uint32_t *)ptr) != 0) {
+ for (i = 0; i < 8; i++)
+ data[i] = *(ptr + i);
+ }
+
+ next = curr + 1;
+ if (next == (opipe->td + opipe->count - 1))
+ next = opipe->td;
+
+ curr->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC);
+ curr->next_td = cpu_to_le32(0);
+ curr->cbp = cpu_to_le32(PTR_U32(ptr_phys));
+ curr->be = cpu_to_le32(PTR_U32(ptr_phys + pipe->mps - 1));
+ td_next = ohci_get_td_phys(curr, opipe->td, opipe->td_phys);
+ dprintf("Connecting %p to %p(phys %08lx) ptr %p, "
+ "ptr_phys %08lx\n", tail, curr, td_next, ptr, ptr_phys);
+ tail->next_td = cpu_to_le32(td_next);
+ mb();
+ ed->tailp = cpu_to_le32(td_next);
+ } else
+ return 0;
+
+ dprintf("%s: exit\n", __func__);
+ return 1;
+}
+
+struct usb_hcd_ops ohci_ops = {
+ .name = "ohci-hcd",
+ .init = ohci_init,
+ .exit = ohci_exit,
+ .detect = ohci_detect,
+ .disconnect = ohci_disconnect,
+ .get_pipe = ohci_get_pipe,
+ .put_pipe = ohci_put_pipe,
+ .send_ctrl = ohci_send_ctrl,
+ .transfer_bulk = ohci_transfer_bulk,
+ .poll_intr = ohci_poll_intr,
+ .usb_type = USB_OHCI,
+ .next = NULL,
+};
+
+void usb_ohci_register(void)
+{
+ usb_hcd_register(&ohci_ops);
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.h b/qemu/roms/SLOF/lib/libusb/usb-ohci.h
new file mode 100644
index 000000000..f4535fddd
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.h
@@ -0,0 +1,217 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for OHCI Controller
+ *
+ * USB on the PowerStation:
+ * ohci0 - port 0 -> not connected
+ * ohci0 - port 1 - 2 -> Internal connector (J60_USBINT)
+ * ohci1 - port 0 -> not connected
+ * ohci1 - port 1 - 2 -> External connector (J10_USBEXT)
+ */
+
+#ifndef USB_OHCI_H
+#define USB_OHCI_H
+
+#include <stdint.h>
+
+struct ohci_regs {
+ uint32_t rev;
+ uint32_t control;
+ uint32_t cmd_status;
+ uint32_t intr_status;
+ uint32_t intr_enable;
+ uint32_t intr_disable;
+ uint32_t hcca;
+ uint32_t period_curr_ed;
+ uint32_t cntl_head_ed;
+ uint32_t cntl_curr_ed;
+ uint32_t bulk_head_ed;
+ uint32_t bulk_curr_ed;
+ uint32_t done_head;
+ uint32_t fm_interval;
+ uint32_t fm_remaining;
+ uint32_t fm_num;
+ uint32_t period_start;
+ uint32_t ls_threshold;
+ uint32_t rh_desc_a;
+ uint32_t rh_desc_b;
+ uint32_t rh_status;
+ uint32_t rh_ps[5];
+} __attribute__((packed));
+
+#define EDA_FADDR(x) ((x & 0x7F))
+#define EDA_EP(x) ((x & 0x0F) << 7)
+#define EDA_DIR_OUT (1 << 11)
+#define EDA_DIR_IN (1 << 12)
+#define EDA_LOW_SPEED (1 << 13)
+#define EDA_SKIP (1 << 14)
+#define EDA_SKIP_LE (0x400000) /* avoiding conversions */
+#define EDA_FORMAT_ISO (1 << 15)
+#define EDA_MPS(x) ((x & 0x7FF) << 16)
+
+#define EDA_HEADP_MASK (0xFFFFFFFC)
+#define EDA_HEADP_MASK_LE (cpu_to_le32(EDA_HEADP_MASK))
+#define EDA_HEADP_HALTED (0x1)
+#define EDA_HEADP_CARRY (0x2)
+
+struct ohci_ed {
+ uint32_t attr;
+ uint32_t tailp;
+ uint32_t headp;
+ uint32_t next_ed;
+} __attribute__((packed));
+
+#define TDA_DONE (1 << 17)
+#define TDA_ROUNDING (1 << 18)
+#define TDA_DP_SETUP (0 << 19)
+#define TDA_DP_OUT (1 << 19)
+#define TDA_DP_IN (1 << 20)
+#define TDA_DI_NO (0x7 << 21)
+#define TDA_TOGGLE_DATA0 (0x02000000)
+#define TDA_TOGGLE_DATA1 (0x03000000)
+#define TDA_CC (0xF << 28)
+
+#define TDA_ERROR(x) ((x) * -1)
+
+/* Table 4-7: Completion Codes */
+const char *tda_cc_error[] = {
+#define USB_NOERROR TDA_ERROR(0)
+ "NOERROR",
+ "CRC",
+ "BITSTUFFING",
+ "DATATOGGLEMISMATCH",
+#define USB_STALL TDA_ERROR(4)
+ "STALL",
+ "DEVICENOTRESPONDING",
+ "PIDCHECKFAILURE",
+ "UNEXPECTEDPID",
+ "DATAOVERRUN",
+ "DATAUNDERRUN",
+ "reserved",
+ "reserved",
+ "BUFFEROVERRUN",
+ "BUFFERUNDERRUN",
+ "NOT ACCESSED",
+ "NOT ACCESSED",
+};
+
+struct ohci_td {
+ uint32_t attr;
+ uint32_t cbp;
+ uint32_t next_td;
+ uint32_t be;
+} __attribute__((packed));
+
+#define HCCA_SIZE 256
+#define HCCA_ALIGN (HCCA_SIZE - 1)
+#define HCCA_INTR_NUM 32
+struct ohci_hcca {
+ uint32_t intr_table[HCCA_INTR_NUM];
+ uint16_t frame_num;
+ uint16_t pad1;
+ uint32_t done_head;
+ uint32_t reserved[120];
+} __attribute__((packed));
+
+struct ohci_pipe {
+ struct ohci_ed ed; /* has to be aligned at 16 byte address*/
+ struct usb_pipe pipe;
+ struct ohci_td *td;
+ void *buf;
+ long ed_phys;
+ long td_phys;
+ long buf_phys;
+ uint32_t buflen;
+ uint32_t count;
+ uint8_t pad[0];
+}__attribute__((packed));
+
+#define OHCI_PIPE_POOL_SIZE 4096
+#define OHCI_MAX_TDS 256 /* supports 16k buffers, i.e. 64 * 256 */
+#define OHCI_MAX_BULK_SIZE 4096
+
+struct ohci_hcd {
+ struct ohci_hcca *hcca;
+ struct ohci_regs *regs;
+ struct usb_hcd_dev *hcidev;
+ struct usb_pipe *freelist;
+ struct usb_pipe *end;
+ struct usb_dev rhdev;
+ long hcca_phys;
+ void *pool;
+ long pool_phys;
+};
+
+#define OHCI_CTRL_CBSR (3 << 0)
+#define OHCI_CTRL_PLE (1 << 2)
+#define OHCI_CTRL_CLE (1 << 4)
+#define OHCI_CTRL_BLE (1 << 5)
+#define OHCI_CTRL_HCFS (3 << 6)
+#define OHCI_USB_RESET (0 << 6)
+#define OHCI_USB_OPER (2 << 6)
+#define OHCI_USB_SUSPEND (3 << 6)
+#define OHCI_CTRL_RWC (1 << 9)
+
+/* OHCI Command Status */
+#define OHCI_CMD_STATUS_HCR (1 << 0)
+#define OHCI_CMD_STATUS_CLF (1 << 1)
+#define OHCI_CMD_STATUS_BLF (1 << 2)
+
+/* OHCI Interrupt status */
+#define OHCI_INTR_STATUS_WD (1 << 1)
+
+/* Root Hub Descriptor A bits */
+#define RHDA_NDP (0xFF)
+#define RHDA_PSM_INDIVIDUAL (1 << 8)
+#define RHDA_NPS_ENABLE (1 << 9)
+#define RHDA_DT (1 << 10)
+#define RHDA_OCPM_PERPORT (1 << 11)
+#define RHDA_NOCP_ENABLE (1 << 12)
+
+/* Root Hub Descriptor B bits */
+#define RHDB_PPCM_PORT_POWER (0xFFFE)
+#define RHDB_PPCM_GLOBAL_POWER (0x0000)
+
+#define RH_STATUS_LPSC (1 << 16)
+#define RH_STATUS_OCIC (1 << 17)
+#define RH_STATUS_CREW (1 << 31)
+
+#define RH_PS_CCS (1 << 0)
+#define RH_PS_PES (1 << 1)
+#define RH_PS_PSS (1 << 2)
+#define RH_PS_POCI (1 << 3)
+#define RH_PS_PRS (1 << 4)
+#define RH_PS_PPS (1 << 8)
+#define RH_PS_LSDA (1 << 9)
+
+#define RH_PS_CSC (1 << 16)
+#define RH_PS_PESC (1 << 17)
+#define RH_PS_PSSC (1 << 18)
+#define RH_PS_OCIC (1 << 19)
+#define RH_PS_PRSC (1 << 20)
+
+/*********************************************************************/
+/* Values for USB Frame Timing */
+/* One USB frame (1ms) consists of 12000 bit-times as clock is 12MHz */
+/* controller can be adjusted for performance optimization */
+/* We use standard values (OHCI spec 6.3.1, 5.1.1.4, 5.4, 7.3.4) */
+/*********************************************************************/
+#define FRAME_INTERVAL (((((11999 - 210) * 6) / 7) << 16) | 11999)
+#define PERIODIC_START ((11999 * 9) / 10)
+
+
+static inline struct ohci_ed *ohci_pipe_get_ed(struct usb_pipe *pipe);
+static inline long ohci_pipe_get_ed_phys(struct usb_pipe *pipe);
+static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd);
+
+#endif /* USB_OHCI_H */
diff --git a/qemu/roms/SLOF/lib/libusb/usb-slof.c b/qemu/roms/SLOF/lib/libusb/usb-slof.c
new file mode 100644
index 000000000..de841f0fb
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-slof.c
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * All functions concerning interface to slof
+ */
+
+#include <string.h>
+#include "helpers.h"
+#include "usb-core.h"
+#include "paflof.h"
+
+#undef SLOF_DEBUG
+//#define SLOF_DEBUG
+#ifdef SLOF_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while(0)
+#else
+#define dprintf(_x ...)
+#endif
+
+int slof_usb_handle(struct usb_dev *dev)
+{
+ struct slof_usb_dev sdev;
+ sdev.port = dev->port;
+ sdev.addr = dev->addr;
+ sdev.hcitype = dev->hcidev->type;
+ sdev.num = dev->hcidev->num;
+ sdev.udev = dev;
+
+ if (dev->class == DEV_HID_KEYB) {
+ dprintf("Keyboard %ld %ld\n", dev->hcidev->type, dev->hcidev->num);
+ sdev.devtype = DEVICE_KEYBOARD;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-keyb.fs\" INCLUDED");
+ } else if (dev->class == DEV_HID_MOUSE) {
+ dprintf("Mouse %ld %ld\n", dev->hcidev->type, dev->hcidev->num);
+ sdev.devtype = DEVICE_MOUSE;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-mouse.fs\" INCLUDED");
+ } else if ((dev->class >> 16 & 0xFF) == 8) {
+ dprintf("MASS Storage device %ld %ld\n", dev->hcidev->type, dev->hcidev->num);
+ sdev.devtype = DEVICE_DISK;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-storage.fs\" INCLUDED");
+ } else if (dev->class == DEV_HUB) {
+ dprintf("Generic hub device %ld %ld\n", dev->hcidev->type,
+ dev->hcidev->num);
+ sdev.devtype = DEVICE_HUB;
+ forth_push((long)&sdev);
+ forth_eval("s\" dev-hub.fs\" INCLUDED");
+ }
+ return true;
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.c b/qemu/roms/SLOF/lib/libusb/usb-xhci.c
new file mode 100644
index 000000000..0c3d6e47f
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.c
@@ -0,0 +1,1316 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include "usb.h"
+#include "usb-core.h"
+#include "usb-xhci.h"
+#include "tools.h"
+#include "paflof.h"
+
+#undef XHCI_DEBUG
+//#define XHCI_DEBUG
+#ifdef XHCI_DEBUG
+#define dprintf(_x ...) do { printf("%s: ", __func__); printf(_x); } while (0)
+#else
+#define dprintf(_x ...)
+#endif
+
+static void dump_xhci_regs(struct xhci_hcd *xhcd)
+{
+#ifdef XHCI_DEBUG
+ struct xhci_cap_regs *cap;
+ struct xhci_op_regs *op;
+ struct xhci_run_regs *run;
+
+ cap = xhcd->cap_regs;
+ op = xhcd->op_regs;
+ run = xhcd->run_regs;
+
+ dprintf("\n");
+ dprintf(" - CAPLENGTH %02X\n", read_reg8 (&cap->caplength));
+ dprintf(" - HCIVERSION %04X\n", read_reg16(&cap->hciversion));
+ dprintf(" - HCSPARAMS1 %08X\n", read_reg32(&cap->hcsparams1));
+ dprintf(" - HCSPARAMS2 %08X\n", read_reg32(&cap->hcsparams2));
+ dprintf(" - HCSPARAMS3 %08X\n", read_reg32(&cap->hcsparams3));
+ dprintf(" - HCCPARAMS %08X\n", read_reg32(&cap->hccparams));
+ dprintf(" - DBOFF %08X\n", read_reg32(&cap->dboff));
+ dprintf(" - RTSOFF %08X\n", read_reg32(&cap->rtsoff));
+ dprintf("\n");
+
+ dprintf(" - USBCMD %08X\n", read_reg32(&op->usbcmd));
+ dprintf(" - USBSTS %08X\n", read_reg32(&op->usbsts));
+ dprintf(" - PAGESIZE %08X\n", read_reg32(&op->pagesize));
+ dprintf(" - DNCTRL %08X\n", read_reg32(&op->dnctrl));
+ dprintf(" - CRCR %016llX\n", read_reg64(&op->crcr));
+ dprintf(" - DCBAAP %016llX\n", read_reg64(&op->dcbaap));
+ dprintf(" - CONFIG %08X\n", read_reg32(&op->config));
+ dprintf("\n");
+
+ dprintf(" - MFINDEX %08X\n", read_reg32(&run->mfindex));
+ dprintf("\n");
+#endif
+}
+
+static void print_port_status(struct xhci_port_regs *prs)
+{
+#ifdef XHCI_DEBUG
+ uint32_t portsc;
+ uint32_t CCS, PED, PP, PLS, i, PR = 0;
+
+ portsc = read_reg32(&prs->portsc);
+ dprintf("portsc %08x portpmsc %08x portli %08x\n",
+ portsc,
+ read_reg32(&prs->portpmsc),
+ read_reg32(&prs->portli));
+
+ if (portsc & PORTSC_CCS) {
+ printf("CCS ");
+ CCS = 1;
+ }
+ if (portsc & PORTSC_PED) {
+ printf("PED ");
+ PED = 1;
+ }
+ if (portsc & PORTSC_OCA)
+ printf("OCA ");
+ if (portsc & PORTSC_PR)
+ printf("OCA ");
+ PLS = (portsc & PORTSC_PLS_MASK) >> 5;
+ printf("PLS:%d ", PLS);
+ if (portsc & PORTSC_PP) {
+ printf("PP ");
+ PP = 1;
+ }
+ printf("PS:%d ", (portsc & PORTSC_PS_MASK) >> 10);
+ printf("PIC:%d ", (portsc & PORTSC_PIC_MASK) >> 14);
+ if (portsc & PORTSC_LWS)
+ printf("LWS ");
+ if (portsc & PORTSC_CSC)
+ printf("CSC ");
+ if (portsc & PORTSC_PEC)
+ printf("PEC ");
+ if (portsc & PORTSC_WRC)
+ printf("WRC ");
+ if (portsc & PORTSC_OCC)
+ printf("OCC ");
+ if (portsc & PORTSC_PRC)
+ printf("PRC ");
+ if (portsc & PORTSC_PLC)
+ printf("PLC ");
+ if (portsc & PORTSC_CEC)
+ printf("CEC ");
+ if (portsc & PORTSC_CAS)
+ printf("CAS ");
+ if (portsc & PORTSC_WCE)
+ printf("WCE ");
+ if (portsc & PORTSC_WDE)
+ printf("WDE ");
+ if (portsc & PORTSC_WOE)
+ printf("WOE ");
+ if (portsc & PORTSC_DR)
+ printf("DR ");
+ if (portsc & PORTSC_WPR)
+ printf("WPR ");
+ printf("\n");
+
+ for (i = 0 ; i < (sizeof(ps_array_usb3)/sizeof(struct port_state)); i++) {
+ if (PP == ps_array_usb3[i].PP) {
+ if (CCS == ps_array_usb3[i].CCS) {
+ if (PED == ps_array_usb3[i].PED) {
+ if (PR == ps_array_usb3[i].PR) {
+ dprintf("%s - PLS %d\n", ps_array_usb3[i].state, PLS);
+ break;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+}
+
+static inline bool xhci_is_hc_ready(uint32_t *usbsts)
+{
+ return !(read_reg32(usbsts) & XHCI_USBSTS_CNR);
+}
+
+static inline bool xhci_wait_for_cnr(uint32_t *usbsts)
+{
+ /* Standard:
+ * Note: The xHC should halt within 16 ms. of software clearing the
+ * R/S bit to ‘0’.
+ * Give some more time... 32ms
+ */
+ int count = 320;
+ dprintf("Waiting for Controller ready ..");
+ while (!xhci_is_hc_ready(usbsts)) {
+ dprintf(".");
+ count--;
+ if (!count) {
+ dprintf(" failed %08X\n", read_reg32(usbsts));
+ return false;
+ }
+ SLOF_usleep(100);
+ }
+ dprintf(" done\n");
+ return true;
+}
+
+static bool xhci_hcd_set_runstop(struct xhci_op_regs *op, bool run_req)
+{
+ uint32_t reg;
+
+ dprintf("Request %s\n", run_req ? "RUN" : "STOP");
+ if (!xhci_is_hc_ready(&op->usbsts)) {
+ dprintf("Controller not ready\n");
+ return false;
+ }
+
+ reg = read_reg32(&op->usbcmd);
+ if (run_req)
+ reg |= run_req;
+ else
+ reg &= (uint32_t)~1;
+ dprintf("writing %08X\n", reg);
+ write_reg32(&op->usbcmd, reg);
+ mb();
+ xhci_wait_for_cnr(&op->usbsts);
+ return true;
+}
+
+static bool xhci_hcd_reset(struct xhci_op_regs *op)
+{
+ uint32_t reg;
+
+ /* Check if the controller is halted, else halt it */
+ if (!(read_reg32(&op->usbsts) & XHCI_USBSTS_HCH)) {
+ dprintf("HCHalted not set\n");
+ if (!xhci_hcd_set_runstop(op, false))
+ return false;
+ }
+
+ if (read_reg32(&op->usbsts) & XHCI_USBSTS_CNR) {
+ dprintf("Controller not ready\n");
+ return false;
+ }
+
+ reg = read_reg32(&op->usbcmd) | XHCI_USBCMD_HCRST;
+ /* Ready to Reset the controller now */
+ write_reg32(&op->usbcmd, reg);
+ xhci_wait_for_cnr(&op->usbsts);
+ return true;
+}
+
+static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd,
+ struct xhci_event_trb *event)
+{
+ uint32_t flags, slot_id, status;
+
+ status = le32_to_cpu(event->status);
+ flags = le32_to_cpu(event->flags);
+ slot_id = TRB_SLOT_ID(flags);
+ if (TRB_STATUS(status) == COMP_SUCCESS)
+ xhcd->slot_id = slot_id;
+ else
+ xhcd->slot_id = 0;
+}
+
+static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
+ uint32_t event_type)
+{
+ struct xhci_event_trb *event;
+ uint64_t val;
+ uint32_t flags, time;
+ int index;
+
+ mb();
+ event = (struct xhci_event_trb *)xhcd->ering.deq;
+ flags = le32_to_cpu(event->flags);
+
+ dprintf("Reading from event ptr %p %08x\n", event, flags);
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+
+ while ((flags & TRB_CYCLE_STATE) != xhcd->ering.cycle_state) {
+ mb();
+ flags = le32_to_cpu(event->flags);
+ if (time < SLOF_GetTimer())
+ return NULL;
+ }
+
+ mb();
+ flags = le32_to_cpu(event->flags);
+ switch(TRB_TYPE(flags))
+ {
+ case TRB_CMD_COMPLETION:
+ dprintf("CMD Completion\n");
+ xhci_handle_cmd_completion(xhcd, event);
+ break;
+ case TRB_PORT_STATUS:
+ dprintf("Port status event\n");
+ break;
+ case TRB_TRANSFER_EVENT:
+ dprintf("XFER event addr %16lx, status %08x, flags %08x\n",
+ le64_to_cpu(event->addr),
+ le32_to_cpu(event->status),
+ le32_to_cpu(event->flags));
+ break;
+ default:
+ printf("TRB_TYPE %d\n", TRB_TYPE(flags));
+ dprintf("Event addr %16lx, status %08x, flags %08x state %d\n",
+ le64_to_cpu(event->addr),
+ le32_to_cpu(event->status),
+ flags, xhcd->ering.cycle_state);
+ break;
+ }
+ xhcd->ering.deq = (uint64_t) (event + 1);
+
+ event->addr = 0;
+ event->status = 0;
+ event->flags = cpu_to_le32(xhcd->ering.cycle_state);
+
+ index = xhcd->ering.deq - (uint64_t)xhcd->ering.trbs;
+ val = xhcd->ering.trbs_dma;
+ val += (index % XHCI_EVENT_TRBS_SIZE);
+ if (!(index % XHCI_EVENT_TRBS_SIZE)) {
+ xhcd->ering.deq = (uint64_t)xhcd->ering.trbs;
+ xhcd->ering.cycle_state = xhcd->ering.cycle_state ? 0 : 1;
+ dprintf("Rounding %d\n", xhcd->ering.cycle_state);
+ }
+ dprintf("Update start %x deq %x index %d\n",
+ xhcd->ering.trbs_dma, val, index/sizeof(*event));
+ write_reg64(&xhcd->run_regs->irs[0].erdp, val);
+ return event;
+}
+
+static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1,
+ uint32_t field2, uint32_t field3, uint32_t field4)
+{
+ struct xhci_db_regs *dbr;
+ struct xhci_command_trb *cmd;
+ uint32_t val, cycle_state;
+
+ dbr = xhcd->db_regs;
+ cmd = (struct xhci_command_trb *)xhcd->crseg.enq;
+
+ cmd->field[0] = cpu_to_le32(field1);
+ cmd->field[1] = cpu_to_le32(field2);
+ cmd->field[2] = cpu_to_le32(field3);
+
+ val = le32_to_cpu(cmd->field[3]);
+ cycle_state = (val & 0x1) ? 0 : 1;
+ val = field4 | cycle_state;
+ cmd->field[3] = cpu_to_le32(val);
+
+ dprintf("CMD %016lx val %08x cycle_state %d field1 %08x, field2 %08x, field3 %08x field4 %08x\n",
+ cmd, val, cycle_state,
+ le32_to_cpu(cmd->field[0]),
+ le32_to_cpu(cmd->field[1]),
+ le32_to_cpu(cmd->field[2]),
+ le32_to_cpu(cmd->field[3])
+ );
+
+ /* Ring the doorbell */
+ write_reg32(&dbr->db[0], 0);
+ xhci_poll_event(xhcd, 0);
+ cmd++;
+ xhcd->crseg.enq = (uint64_t)cmd;
+ return;
+}
+
+static void xhci_send_enable_slot(struct xhci_hcd *xhcd, uint32_t port)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = 0;
+ field2 = 0;
+ field3 = 0;
+ field4 = TRB_CMD_TYPE(TRB_ENABLE_SLOT);
+ xhci_send_cmd(xhcd, field1, field2, field3, field4);
+}
+
+static void xhci_send_addr_device(struct xhci_hcd *xhcd, uint32_t slot_id,
+ uint64_t dma_in_ctx)
+{
+ uint32_t field1, field2, field3, field4;
+
+ dprintf("Address device %lx, low %x, high %x\n", dma_in_ctx,
+ TRB_ADDR_LOW(dma_in_ctx),
+ TRB_ADDR_HIGH(dma_in_ctx));
+ field1 = TRB_ADDR_LOW(dma_in_ctx) & ~0xF;
+ field2 = TRB_ADDR_HIGH(dma_in_ctx);
+ field3 = 0;
+ field4 = TRB_CMD_TYPE(TRB_ADDRESS_DEV) | TRB_CMD_SLOT_ID(slot_id);
+ xhci_send_cmd(xhcd, field1, field2, field3, field4);
+}
+
+static uint32_t xhci_get_epno(struct usb_pipe *pipe)
+{
+ uint32_t x_epno;
+ x_epno = pipe->dir | 2 * pipe->epno;
+ dprintf("EPno %d:%d DIR %d\n", pipe->epno, x_epno, pipe->dir);
+ return x_epno;
+}
+
+static void xhci_configure_ep(struct xhci_hcd *xhcd, uint32_t slot_id,
+ uint64_t dma_in_ctx)
+{
+ uint32_t field1, field2, field3, field4;
+
+ dprintf("Configure EP %lx, low %x, high %x\n", dma_in_ctx,
+ TRB_ADDR_LOW(dma_in_ctx),
+ TRB_ADDR_HIGH(dma_in_ctx));
+ field1 = TRB_ADDR_LOW(dma_in_ctx) & ~0xF;
+ field2 = TRB_ADDR_HIGH(dma_in_ctx);
+ field3 = 0;
+ field4 = TRB_CMD_TYPE(TRB_CONFIG_EP) | TRB_CMD_SLOT_ID(slot_id);
+ xhci_send_cmd(xhcd, field1, field2, field3, field4);
+}
+
+static void xhci_init_seg(struct xhci_seg *seg, uint32_t size, uint32_t type)
+{
+ struct xhci_link_trb *link;
+
+ seg->size = size / XHCI_TRB_SIZE;
+ seg->next = NULL;
+ seg->type = type;
+ seg->cycle_state = 1;
+ seg->enq = (uint64_t)seg->trbs;
+ seg->deq = (uint64_t)seg->trbs;
+ memset((void *)seg->trbs, 0, size);
+
+ link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1);
+ link->addr = cpu_to_le64(seg->trbs_dma);
+ link->field2 = 0;
+ link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ return;
+}
+
+static bool xhci_alloc_seg(struct xhci_seg *seg, uint32_t size, uint32_t type)
+{
+ seg->trbs = (union xhci_trb *)SLOF_dma_alloc(size);
+ if (!seg->trbs) {
+ dprintf("Alloc failed\n");
+ return false;
+ }
+ xhci_init_seg(seg, size, type);
+ seg->trbs_dma = SLOF_dma_map_in((void *)seg->trbs, size, false);
+
+ dprintf(" TRBs %016lX TRBS-DMA %016lX\n", seg->trbs, seg->trbs_dma);
+ return true;
+}
+
+static void xhci_free_seg(struct xhci_seg *seg, uint32_t size)
+{
+ if (seg->trbs) {
+ dprintf(" TRBs %016lX TRBS-DMA %016lX size %x\n", seg->trbs, seg->trbs_dma, size);
+ SLOF_dma_map_out(seg->trbs_dma, (void *)seg->trbs, size);
+ SLOF_dma_free((void *)seg->trbs, size);
+ }
+ memset(seg, 0, sizeof(*seg));
+}
+
+#define CTX_SIZE(x) ( (x) ? 64 : 32 )
+
+static bool xhci_alloc_ctx(struct xhci_ctx *ctx, uint32_t size, uint32_t type)
+{
+ ctx->addr = (uint8_t *)SLOF_dma_alloc(size);
+ if (!ctx->addr) {
+ dprintf("Alloc failed\n");
+ return false;
+ }
+ ctx->size = size;
+ ctx->type = type;
+ memset((void *)ctx->addr, 0, size);
+ ctx->dma_addr = SLOF_dma_map_in((void *)ctx->addr, size, false);
+ dprintf("ctx %llx, ctx_dma %llx\n", ctx->addr, ctx->dma_addr);
+ return true;
+}
+
+static struct xhci_control_ctx *xhci_get_control_ctx(struct xhci_ctx *ctx)
+{
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ return (struct xhci_control_ctx *) ctx->addr;
+ return NULL;
+}
+
+static struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctx *ctx, uint32_t ctx_size)
+{
+ uint32_t offset = 0;
+
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ offset += ctx_size;
+ return (struct xhci_slot_ctx *)(ctx->addr + offset);
+}
+
+static struct xhci_ep_ctx *xhci_get_ep0_ctx(struct xhci_ctx *ctx, uint32_t ctx_size)
+{
+ uint32_t offset = 0;
+
+ offset = ctx_size;
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ offset += ctx_size;
+ return (struct xhci_ep_ctx *)(ctx->addr + offset);
+}
+
+static struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctx *ctx, uint32_t ctx_size,
+ uint32_t epno)
+{
+ uint32_t offset = 0;
+
+ offset = ctx_size * epno;
+ if (ctx->type == XHCI_CTX_TYPE_INPUT)
+ offset += ctx_size;
+ return (struct xhci_ep_ctx *)(ctx->addr + offset);
+}
+
+static void xhci_free_ctx(struct xhci_ctx *ctx, uint32_t size)
+{
+ SLOF_dma_map_out(ctx->dma_addr, (void *)ctx->addr, size);
+ SLOF_dma_free((void *)ctx->addr, size);
+}
+
+static uint32_t usb_control_max_packet(uint32_t speed)
+{
+ uint32_t max_packet = 0;
+
+ switch(speed)
+ {
+ case USB_LOW_SPEED:
+ max_packet = 8;
+ break;
+ case USB_FULL_SPEED:
+ max_packet = 8;
+ break;
+ case USB_HIGH_SPEED:
+ max_packet = 64;
+ break;
+ case USB_SUPER_SPEED:
+ max_packet = 512;
+ break;
+ default:
+ /* should not reach here */
+ dprintf("Unknown speed\n");
+ }
+ return max_packet;
+}
+
+static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t port)
+{
+ struct usb_dev *dev;
+ struct xhci_dev *xdev;
+ struct xhci_slot_ctx *slot;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep0;
+ uint32_t ctx_size, val;
+ uint16_t max_packet;
+ uint32_t newport;
+
+ ctx_size = CTX_SIZE(xhcd->hcc_csz_64);
+ xdev = &xhcd->xdevs[slot_id];
+ xdev->slot_id = slot_id;
+ xdev->ctx_size = ctx_size;
+
+ /* 4.3.3 Device Slot initialization */
+ /* Step 1 */
+ if (!xhci_alloc_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE, XHCI_CTX_TYPE_INPUT)) {
+ dprintf("Failed allocating in_ctx\n");
+ return false;
+ }
+
+ /* Step 2 */
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ ctrl->a_flags = cpu_to_le32(0x3); /* A0, A1 */
+ ctrl->d_flags = 0;
+
+ /* Step 3 */
+ slot = xhci_get_slot_ctx(&xdev->in_ctx, ctx_size);
+ newport = port + 1;
+ val = LAST_CONTEXT(1) | SLOT_SPEED_SS | (newport << 16); /* FIXME speed, read from PS */
+ slot->field1 = cpu_to_le32(val);
+ slot->field2 = cpu_to_le32(ROOT_HUB_PORT(newport)); /* FIXME how to get port no */
+
+ /* Step 4 */
+ if (!xhci_alloc_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE, TYPE_CTRL)) {
+ dprintf("Failed allocating control\n");
+ goto fail_in_ctx;
+ }
+
+ /* Step 5 */
+ ep0 = xhci_get_ep0_ctx(&xdev->in_ctx, ctx_size);
+ val = 0;
+ max_packet = usb_control_max_packet(USB_SUPER_SPEED);
+ max_packet = 64;
+ val = EP_TYPE(EP_CTRL) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(max_packet);
+ ep0->field2 = cpu_to_le32(val);;
+ ep0->deq_addr = cpu_to_le64(xdev->control.trbs_dma | xdev->control.cycle_state);
+ ep0->field4 = cpu_to_le32(8);
+
+ /* Step 6 */
+ if (!xhci_alloc_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE, XHCI_CTX_TYPE_DEVICE)) {
+ dprintf("Failed allocating out_ctx\n");
+ goto fail_control_seg;
+ }
+
+ /* Step 7 */
+ xhcd->dcbaap[slot_id] = cpu_to_le64(xdev->out_ctx.dma_addr);
+
+ /* Step 8 */
+ slot = xhci_get_slot_ctx(&xdev->out_ctx, ctx_size);
+ ep0 = xhci_get_ep0_ctx(&xdev->out_ctx, ctx_size);
+
+ dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4)));
+ xhci_send_addr_device(xhcd, slot_id, xdev->in_ctx.dma_addr);
+ mb();
+ dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4)));
+
+ dprintf("EP0 f0 %08X f1 %08X %016lX %08X\n",
+ le32_to_cpu(ep0->field1),
+ le32_to_cpu(ep0->field2),
+ le64_to_cpu(ep0->deq_addr),
+ le32_to_cpu(ep0->field4));
+
+ /* Step 9 - configure ep */
+ ctrl->a_flags = cpu_to_le32(0x1); /* A0 */
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, slot_id, xdev->in_ctx.dma_addr);
+ mb();
+ dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4)));
+ dprintf("USB Device address %d \n", USB_DEV_ADDRESS(le32_to_cpu(slot->field4)));
+ dprintf("EP0 f0 %08X f1 %08X %016lX %08X\n",
+ le32_to_cpu(ep0->field1),
+ le32_to_cpu(ep0->field2),
+ le64_to_cpu(ep0->deq_addr),
+ le32_to_cpu(ep0->field4));
+
+ dev = usb_devpool_get();
+ dprintf("allocated device %p\n", dev);
+ dev->hcidev = xhcd->hcidev;
+ dev->speed = USB_SUPER_SPEED;
+ dev->addr = USB_DEV_ADDRESS(slot->field4);
+ dev->port = newport;
+ dev->priv = xdev;
+ xdev->dev = dev;
+ if (setup_new_device(dev, newport))
+ return true;
+
+ xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
+fail_control_seg:
+ xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE);
+fail_in_ctx:
+ xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE);
+ return false;
+}
+
+static void xhci_free_dev(struct xhci_dev *xdev)
+{
+ xhci_free_seg(&xdev->bulk_in, XHCI_DATA_TRBS_SIZE);
+ xhci_free_seg(&xdev->bulk_out, XHCI_DATA_TRBS_SIZE);
+ xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE);
+ xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE);
+ xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
+}
+
+static bool usb3_dev_init(struct xhci_hcd *xhcd, uint32_t port)
+{
+ /* Device enable slot */
+ xhci_send_enable_slot(xhcd, port);
+ if (!xhcd->slot_id) {
+ dprintf("Unable to get slot id\n");
+ return false;
+ }
+ dprintf("SLOT ID: %d\n", xhcd->slot_id);
+ if (!xhci_alloc_dev(xhcd, xhcd->slot_id, port)) {
+ dprintf("Unable to allocate device\n");
+ return false;
+ }
+ return true;
+}
+
+static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
+{
+ uint32_t num_ports, portsc, i;
+ struct xhci_op_regs *op;
+ struct xhci_port_regs *prs;
+ struct xhci_cap_regs *cap;
+ uint32_t xecp_off;
+ uint32_t *xecp_addr, *base;
+ uint32_t port_off = 1, port_cnt;
+
+ dprintf("enter\n");
+
+ op = xhcd->op_regs;
+ cap = xhcd->cap_regs;
+ port_cnt = num_ports = read_reg32(&cap->hcsparams1) >> 24;
+
+ /* Read the xHCI extented capability to find usb3 ports and offset*/
+ xecp_off = XHCI_HCCPARAMS_XECP(read_reg32(&cap->hccparams));
+ base = (uint32_t *)cap;
+ while (xecp_off > 0) {
+ xecp_addr = base + xecp_off;
+ dprintf(stderr, "xecp_off %d %p %p \n", xecp_off, base, xecp_addr);
+
+ if (XHCI_XECP_CAP_ID(read_reg32(xecp_addr)) == XHCI_XECP_CAP_SP &&
+ XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == 3 &&
+ XHCI_XECP_CAP_SP_MN(read_reg32(xecp_addr)) == 0) {
+ port_cnt = XHCI_XECP_CAP_SP_PC(read_reg32(xecp_addr + 2));
+ port_off = XHCI_XECP_CAP_SP_PO(read_reg32(xecp_addr + 2));
+ dprintf(stderr, "PortCount %d Portoffset %d\n", port_cnt, port_off);
+ }
+ base = xecp_addr;
+ xecp_off = XHCI_XECP_NEXT_PTR(read_reg32(xecp_addr));
+ }
+ if (port_off == 0) /* port_off should always start from 1 */
+ return false;
+ for (i = (port_off - 1); i < (port_off + port_cnt - 1); i++) {
+ prs = &op->prs[i];
+ portsc = read_reg32(&prs->portsc);
+ if ((portsc & PORTSC_CCS) &&
+ (portsc & PORTSC_PP) &&
+ (portsc & PORTSC_PED)) {
+ /* Device present and enabled */
+ dprintf("Device present on port %d\n", i);
+ /* Reset the port */
+ portsc = read_reg32(&prs->portsc);
+ portsc = portsc | PORTSC_PR;
+ write_reg32(&prs->portsc, portsc);
+ /* FIXME poll for port event */
+ SLOF_msleep(20);
+ xhci_poll_event(xhcd, 0);
+ portsc = read_reg32(&prs->portsc);
+ if (portsc & ~PORTSC_PRC) {
+ dprintf("Port reset complete %d\n", i);
+ }
+ print_port_status(prs);
+ if (!usb3_dev_init(xhcd, (i - (port_off - 1)))) {
+ dprintf("USB device initialization failed\n");
+ }
+ }
+ }
+ dprintf("exit\n");
+ return true;
+}
+
+static bool xhci_hcd_init(struct xhci_hcd *xhcd)
+{
+ struct xhci_op_regs *op;
+ struct xhci_int_regs *irs;
+ uint64_t val;
+ uint32_t reg;
+
+ if (!xhcd) {
+ dprintf("NULL pointer\n");
+ goto fail;
+ }
+
+ op = xhcd->op_regs;
+ irs = &xhcd->run_regs->irs[0];
+ if (!xhci_hcd_reset(op)) {
+ dprintf("Reset failed\n");
+ goto fail;
+ }
+
+ write_reg32(&op->config, XHCI_CONFIG_MAX_SLOT);
+ reg = read_reg32(&xhcd->cap_regs->hccparams);
+ /* 64byte context !! */
+ xhcd->hcc_csz_64 = (reg & XHCI_HCCPARAMS_CSZ) ? 1 : 0;
+
+ if (xhcd->hcc_csz_64) {
+ printf("usb-xhci: 64 Byte context not supported\n");
+ goto fail;
+ }
+ /*
+ * 6.1 Device Context Base Address Array
+ *
+ * Allocate memory and initialize
+ */
+ xhcd->dcbaap = (uint64_t *)SLOF_dma_alloc(XHCI_DCBAAP_MAX_SIZE);
+ if (!xhcd->dcbaap) {
+ dprintf("Alloc failed\n");
+ goto fail;
+ }
+ memset((void *)xhcd->dcbaap, 0, XHCI_DCBAAP_MAX_SIZE);
+ xhcd->dcbaap_dma = SLOF_dma_map_in((void *)xhcd->dcbaap,
+ XHCI_DCBAAP_MAX_SIZE, false);
+ dprintf("dcbaap %llx, dcbaap_phys %llx\n", xhcd->dcbaap, xhcd->dcbaap_dma);
+ write_reg64(&op->dcbaap, xhcd->dcbaap_dma);
+
+ /*
+ * Command Ring Control - TRB
+ * FIXME - better way to allocate it...
+ */
+ if (!xhci_alloc_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE, TYPE_COMMAND))
+ goto fail_dcbaap;
+
+ val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK;
+ val = val | (xhcd->crseg.trbs_dma & XHCI_CRCR_CRP_MASK);
+ write_reg64(&op->crcr, val);
+
+ /*
+ * Event Ring Control - TRB
+ * Allocate event TRBS
+ */
+ if (!xhci_alloc_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE, TYPE_EVENT))
+ goto fail_crseg;
+
+ /*
+ * Populate event ring segment table.
+ * Note: only using one segment.
+ */
+ xhcd->erst.entries = SLOF_dma_alloc(XHCI_EVENT_TRBS_SIZE);
+ if (!xhcd->erst.entries)
+ goto fail_ering;
+ xhcd->erst.dma = SLOF_dma_map_in((void *)xhcd->erst.entries,
+ XHCI_EVENT_TRBS_SIZE, false);
+ xhcd->erst.num_segs = XHCI_ERST_NUM_SEGS;
+
+ /* populate entries[0] */
+ write_reg64(&xhcd->erst.entries->addr, xhcd->ering.trbs_dma);
+ write_reg32(&xhcd->erst.entries->size, xhcd->ering.size);
+ write_reg32(&xhcd->erst.entries->reserved, 0);
+
+ /* populate erdp */
+ val = read_reg64(&irs->erdp) & ~XHCI_ERDP_MASK;
+ val = val | (xhcd->ering.trbs_dma & XHCI_ERDP_MASK);
+ write_reg64(&irs->erdp, val);
+
+ /* populate erstsz */
+ val = read_reg32(&irs->erstsz) & ~XHCI_ERST_SIZE_MASK;
+ val = val | xhcd->erst.num_segs;
+ write_reg32(&irs->erstsz, val);
+
+ /* Now write the erstba */
+ val = read_reg64(&irs->erstba) & ~XHCI_ERST_ADDR_MASK;
+ val = val | (xhcd->erst.dma & XHCI_ERST_ADDR_MASK);
+ write_reg64(&irs->erstba, val);
+
+ dprintf("ERDP %llx TRB-DMA %llx\n", read_reg64(&irs->erdp),
+ xhcd->ering.trbs_dma);
+ dprintf("ERST %llx, ERST DMA %llx, size %d\n",
+ (uint64_t)xhcd->erst.entries, xhcd->erst.dma,
+ xhcd->erst.num_segs);
+
+ mb();
+ if (!xhci_hcd_set_runstop(op, true))
+ goto fail_erst_entries;
+
+ if (!xhci_hub_check_ports(xhcd))
+ goto fail_erst_entries;
+
+ return true;
+fail_erst_entries:
+ write_reg64(&irs->erstba, 0);
+ mb();
+ SLOF_dma_map_out(xhcd->erst.dma, (void *)xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+ SLOF_dma_free((void *)xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+fail_ering:
+ xhci_free_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE);
+fail_crseg:
+ val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK;
+ write_reg64(&op->crcr, val);
+ mb();
+ xhci_free_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE);
+fail_dcbaap:
+ write_reg64(&op->dcbaap, 0);
+ mb();
+ SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+ SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+fail:
+ return false;
+}
+
+static bool xhci_hcd_exit(struct xhci_hcd *xhcd)
+{
+ struct xhci_op_regs *op;
+ struct xhci_int_regs *irs;
+ uint64_t val;
+ int i;
+
+ if (!xhcd) {
+ dprintf("NULL pointer\n");
+ return false;
+ }
+ op = xhcd->op_regs;
+
+ if (!xhci_hcd_set_runstop(op, false)) {
+ dprintf("NULL pointer\n");
+ }
+
+ for (i = 1; i < XHCI_CONFIG_MAX_SLOT; i++) {
+ if (xhcd->xdevs[i].dev)
+ xhci_free_dev(&xhcd->xdevs[i]);
+ }
+
+ irs = &xhcd->run_regs->irs[0];
+ write_reg64(&irs->erstba, 0);
+ mb();
+ if (xhcd->erst.entries) {
+ SLOF_dma_map_out(xhcd->erst.dma, xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+ SLOF_dma_free(xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE);
+ }
+ xhci_free_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE);
+
+ val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK;
+ write_reg64(&op->crcr, val);
+ xhci_free_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE);
+ write_reg64(&op->dcbaap, 0);
+ if (xhcd->dcbaap) {
+ SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+ SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
+ }
+ return true;
+}
+
+static void xhci_init(struct usb_hcd_dev *hcidev)
+{
+ struct xhci_hcd *xhcd;
+
+ printf(" XHCI: Initializing\n");
+ dprintf("device base address %p\n", hcidev->base);
+
+ hcidev->base = (void *)((uint64_t)hcidev->base & ~7);
+ xhcd = SLOF_alloc_mem(sizeof(*xhcd));
+ if (!xhcd) {
+ printf("usb-xhci: Unable to allocate memory\n");
+ return;
+ }
+ memset(xhcd, 0, sizeof(*xhcd));
+
+ hcidev->nextaddr = 1;
+ hcidev->priv = xhcd;
+ xhcd->hcidev = hcidev;
+ xhcd->cap_regs = (struct xhci_cap_regs *)(hcidev->base);
+ xhcd->op_regs = (struct xhci_op_regs *)(hcidev->base +
+ read_reg8(&xhcd->cap_regs->caplength));
+ xhcd->run_regs = (struct xhci_run_regs *)(hcidev->base +
+ read_reg32(&xhcd->cap_regs->rtsoff));
+ xhcd->db_regs = (struct xhci_db_regs *)(hcidev->base +
+ read_reg32(&xhcd->cap_regs->dboff));
+ dump_xhci_regs(xhcd);
+ if (!xhci_hcd_init(xhcd))
+ printf("usb-xhci: failed to initialize XHCI controller.\n");
+ dump_xhci_regs(xhcd);
+}
+
+static void xhci_exit(struct usb_hcd_dev *hcidev)
+{
+ struct xhci_hcd *xhcd;
+
+ dprintf("%s: enter \n", __func__);
+ if (!hcidev && !hcidev->priv) {
+ return;
+ }
+
+ xhcd = hcidev->priv;
+ xhci_hcd_exit(xhcd);
+ SLOF_free_mem(xhcd, sizeof(*xhcd));
+ hcidev->priv = NULL;
+}
+
+static void fill_trb_buff(struct xhci_command_trb *cmd, uint32_t field1,
+ uint32_t field2, uint32_t field3, uint32_t field4)
+{
+ uint32_t val, cycle_state;
+
+ cmd->field[0] = cpu_to_le32(field1);
+ cmd->field[1] = cpu_to_le32(field2);
+ cmd->field[2] = cpu_to_le32(field3);
+
+ val = le32_to_cpu(cmd->field[3]);
+ cycle_state = (val & 0x1) ? 0 : 1;
+ val = cycle_state | (field4 & ~0x1);
+ cmd->field[3] = cpu_to_le32(val);
+
+ dprintf("CMD %016lx val %08x cycle_state %d field1 %08x, field2 %08x, field3 %08x field4 %08x\n",
+ cmd, val, cycle_state,
+ le32_to_cpu(cmd->field[0]),
+ le32_to_cpu(cmd->field[1]),
+ le32_to_cpu(cmd->field[2]),
+ le32_to_cpu(cmd->field[3])
+ );
+
+ return;
+}
+
+static void fill_setup_trb(struct xhci_command_trb *cmd, struct usb_dev_req *req,
+ uint32_t size)
+{
+ uint32_t field1, field2, field3, field4 = 0;
+ uint64_t req_raw;
+ uint32_t datalen = 0, pid = 0;
+
+ req_raw = *((uint64_t *)req);
+ dprintf("%lx %lx \n", *((uint64_t *)req), req_raw);
+ /* req_raw is already in right byte order... */
+ field1 = cpu_to_le32(TRB_ADDR_HIGH(req_raw));
+ field2 = cpu_to_le32(TRB_ADDR_LOW(req_raw));
+ field3 = 8; /* ALWAYS 8 */
+
+ datalen = cpu_to_le16(req->wLength);
+ if (datalen) {
+ pid = (req->bmRequestType & REQT_DIR_IN) ? 3 : 2;
+ field4 = TRB_TRT(pid);
+ }
+ field4 |= TRB_CMD_TYPE(TRB_SETUP_STAGE) | TRB_IDT;
+ fill_trb_buff(cmd, field1, field2, field3, field4);
+}
+
+static void fill_setup_data(struct xhci_command_trb *cmd, void *data,
+ uint32_t size, uint32_t dir)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = TRB_ADDR_LOW(data);
+ field2 = TRB_ADDR_HIGH(data);
+ field3 = size;
+ if (dir)
+ field4 = TRB_DIR_IN;
+ field4 |= TRB_CMD_TYPE(TRB_DATA_STAGE);
+ fill_trb_buff(cmd, field1, field2, field3, field4);
+}
+
+static void fill_status_trb(struct xhci_command_trb *cmd, uint32_t dir)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = 0;
+ field2 = 0;
+ field3 = 0;
+ if (dir)
+ field4 = TRB_DIR_IN;
+
+ field4 |= TRB_CMD_TYPE(TRB_STATUS_STAGE) | TRB_IOC;
+ fill_trb_buff(cmd, field1, field2, field3, field4);
+}
+
+static void fill_normal_trb(struct xhci_transfer_trb *trb, void *data,
+ uint32_t size)
+{
+ uint32_t field1, field2, field3, field4;
+
+ field1 = TRB_ADDR_LOW(data);
+ field2 = TRB_ADDR_HIGH(data);
+ field3 = size;
+ field4 = TRB_CMD_TYPE(TRB_NORMAL) | TRB_IOC;
+ fill_trb_buff((struct xhci_command_trb *)trb, field1, field2, field3, field4);
+}
+
+static int xhci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *ctrl;
+ struct xhci_hcd *xhcd;
+ struct xhci_command_trb *cmd;
+ struct xhci_db_regs *dbr;
+ long req_phys = 0, data_phys = 0;
+ int ret = true;
+ uint32_t slot_id, pid = 0, datalen = 0;
+
+ if (!pipe->dev || !pipe->dev->hcidev) {
+ dprintf(" NULL pointer\n");
+ return false;
+ }
+
+ xdev = pipe->dev->priv;
+ slot_id = xdev->slot_id;
+ ctrl = &xdev->control;
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ dbr = xhcd->db_regs;
+ if (!ctrl || !xdev || !xhcd) {
+ dprintf(" NULL pointer\n");
+ return false;
+ }
+
+ cmd = (struct xhci_command_trb *)ctrl->enq;
+ req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true);
+ fill_setup_trb(cmd, req, sizeof(*req));
+
+ cmd++;
+ datalen = cpu_to_le16(req->wLength);
+ if (datalen)
+ pid = 1;
+ if (datalen) {
+ data_phys = SLOF_dma_map_in(data, datalen, true);
+ fill_setup_data(cmd, (void *) data_phys, datalen, pid);
+ cmd++;
+ }
+
+ fill_status_trb(cmd, pid);
+ cmd++;
+
+ /* Ring the doorbell - ep0 */
+ write_reg32(&dbr->db[slot_id], 1);
+ if (!xhci_poll_event(xhcd, 0)) {
+ dprintf("Command failed\n");
+ ret = false;
+ }
+ ctrl->enq = (uint64_t) cmd;
+ SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req));
+ if (datalen)
+ SLOF_dma_map_out(data_phys, data, datalen);
+ return ret;
+}
+
+static inline struct xhci_pipe *xhci_pipe_get_xpipe(struct usb_pipe *pipe)
+{
+ struct xhci_pipe *xpipe;
+ xpipe = container_of(pipe, struct xhci_pipe, pipe);
+ dprintf("%s: xpipe is %p\n", __func__, xpipe);
+ return xpipe;
+}
+
+static inline struct xhci_seg *xhci_pipe_get_seg(struct usb_pipe *pipe)
+{
+ struct xhci_pipe *xpipe;
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ return xpipe->seg;
+}
+
+static inline void *xhci_get_trb(struct xhci_seg *seg)
+{
+ uint64_t val, enq;
+ uint32_t size;
+ struct xhci_link_trb *link;
+
+ enq = val = seg->enq;
+ val = val + XHCI_TRB_SIZE;
+ size = seg->size * XHCI_TRB_SIZE;
+ /* TRBs being a cyclic buffer, here we cycle back to beginning. */
+ if ((val % size) == 0) {
+ seg->enq = (uint64_t)seg->trbs;
+ enq = seg->enq;
+ seg->enq = seg->enq + XHCI_TRB_SIZE;
+ val = 0;
+ seg->cycle_state ^= seg->cycle_state;
+ link = (struct xhci_link_trb *) (seg->trbs + seg->size - 1);
+ link->addr = cpu_to_le64(seg->trbs_dma);
+ link->field2 = 0;
+ link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ mb();
+ }
+ else {
+ seg->enq = seg->enq + XHCI_TRB_SIZE;
+ }
+
+ return (void *)enq;
+}
+
+static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
+ void *data, int datalen)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_hcd *xhcd;
+ struct xhci_transfer_trb *trb;
+ struct xhci_db_regs *dbr;
+ int ret = true;
+ uint32_t slot_id, epno;
+
+ if (!pipe->dev || !pipe->dev->hcidev) {
+ dprintf(" NULL pointer\n");
+ dprintf(" pipe dev %p hcidev %p\n", pipe->dev, pipe->dev->hcidev);
+ return false;
+ }
+
+ xdev = pipe->dev->priv;
+ slot_id = xdev->slot_id;
+ seg = xhci_pipe_get_seg(pipe);
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ dbr = xhcd->db_regs;
+ if (!seg || !xdev || !xhcd) {
+ dprintf(" NULL pointer\n");
+ dprintf(" seg %p xdev %p xhcd %p\n", seg, xdev, xhcd);
+ return false;
+ }
+
+ if (datalen > XHCI_MAX_BULK_SIZE) {
+ printf("usb-xhci: bulk transfer size too big\n");
+ return false;
+ }
+
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)data, datalen);
+
+ epno = xhci_get_epno(pipe);
+ write_reg32(&dbr->db[slot_id], epno);
+ if (!xhci_poll_event(xhcd, 0)) {
+ dprintf("Bulk failed\n");
+ ret = false;
+ }
+ trb->addr = 0;
+ trb->len = 0;
+ trb->flags = 0;
+ mb();
+
+ return ret;
+}
+
+static int xhci_alloc_pipe_pool(struct xhci_hcd *xhcd)
+{
+ struct xhci_pipe *xpipe, *curr, *prev;
+ unsigned int i, count;
+ long xpipe_phys = 0;
+
+ count = XHCI_PIPE_POOL_SIZE/sizeof(*xpipe);
+ xhcd->pool = xpipe = SLOF_dma_alloc(XHCI_PIPE_POOL_SIZE);
+ if (!xpipe)
+ return -1;
+ xhcd->pool_phys = xpipe_phys = SLOF_dma_map_in(xpipe, XHCI_PIPE_POOL_SIZE, true);
+ dprintf("%s: xpipe %p, xpipe_phys %lx\n", __func__, xpipe, xpipe_phys);
+
+ /* Although an array, link them */
+ for (i = 0, curr = xpipe, prev = NULL; i < count; i++, curr++) {
+ if (prev)
+ prev->pipe.next = &curr->pipe;
+ curr->pipe.next = NULL;
+ prev = curr;
+ }
+
+ if (!xhcd->freelist)
+ xhcd->freelist = &xpipe->pipe;
+ else
+ xhcd->end->next = &xpipe->pipe;
+ xhcd->end = &prev->pipe;
+
+ return 0;
+}
+
+static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe)
+{
+ struct xhci_hcd *xhcd;
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep;
+ uint32_t x_epno, val, type;
+
+ if (!pipe || !dev || !dev->priv)
+ return;
+
+ xdev = dev->priv;
+ xhcd = dev->hcidev->priv;
+ dprintf("dir %d\n", pipe->dir);
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ if (pipe->dir) {
+ type = EP_BULK_IN;
+ seg = &xdev->bulk_in;
+ }
+ else {
+ type = EP_BULK_OUT;
+ seg = &xdev->bulk_out;
+ }
+
+ if (!seg->trbs) {
+ if (!xhci_alloc_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK)) {
+ dprintf("Failed allocating seg\n");
+ }
+ } else {
+ xhci_init_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK);
+ }
+
+ pipe->mps = XHCI_MAX_BULK_SIZE;
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ x_epno = xhci_get_epno(pipe);
+ ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno);
+ val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(pipe->mps);
+ ep->field2 = cpu_to_le32(val);;
+ ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state);
+ ep->field4 = cpu_to_le32(8);
+ ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1);
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr);
+ xpipe->seg = seg;
+}
+
+static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len)
+{
+ struct xhci_hcd *xhcd;
+ struct usb_pipe *new = NULL;
+
+ if (!dev)
+ return NULL;
+
+ xhcd = (struct xhci_hcd *)dev->hcidev->priv;
+ if (!xhcd->freelist) {
+ dprintf("usb-xhci: %s allocating pool\n", __func__);
+ if (xhci_alloc_pipe_pool(xhcd))
+ return NULL;
+ }
+
+ new = xhcd->freelist;
+ xhcd->freelist = xhcd->freelist->next;
+ if (!xhcd->freelist)
+ xhcd->end = NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->dev = dev;
+ new->next = NULL;
+ new->type = ep->bmAttributes & USB_EP_TYPE_MASK;
+ new->speed = dev->speed;
+ new->mps = ep->wMaxPacketSize;
+ new->dir = (ep->bEndpointAddress & 0x80) >> 7;
+ new->epno = ep->bEndpointAddress & 0x0f;
+
+ if (new->type == USB_EP_TYPE_BULK)
+ xhci_init_bulk_ep(dev, new);
+
+ return new;
+}
+
+static void xhci_put_pipe(struct usb_pipe *pipe)
+{
+ struct xhci_hcd *xhcd;
+ struct xhci_pipe *xpipe;
+
+ dprintf("usb-xhci: %s enter - %p\n", __func__, pipe);
+ if (!pipe || !pipe->dev)
+ return;
+ xhcd = pipe->dev->hcidev->priv;
+
+ dprintf("dir %d\n", pipe->dir);
+ if (pipe->type == USB_EP_TYPE_BULK) {
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ xpipe->seg = NULL;
+ }
+ if (xhcd->end)
+ xhcd->end->next = pipe;
+ else
+ xhcd->freelist = pipe;
+
+ xhcd->end = pipe;
+ pipe->next = NULL;
+ pipe->dev = NULL;
+ memset(pipe, 0, sizeof(*pipe));
+
+ dprintf("usb-xhci: %s exit\n", __func__);
+}
+
+struct usb_hcd_ops xhci_ops = {
+ .name = "xhci-hcd",
+ .init = xhci_init,
+ .exit = xhci_exit,
+ .usb_type = USB_XHCI,
+ .get_pipe = xhci_get_pipe,
+ .put_pipe = xhci_put_pipe,
+ .send_ctrl = xhci_send_ctrl,
+ .transfer_bulk = xhci_transfer_bulk,
+ .next = NULL,
+};
+
+void usb_xhci_register(void)
+{
+ usb_hcd_register(&xhci_ops);
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.h b/qemu/roms/SLOF/lib/libusb/usb-xhci.h
new file mode 100644
index 000000000..faeb07ead
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.h
@@ -0,0 +1,386 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * Definitions for XHCI Controller - Revision 1.0 (5/21/10)
+ *
+ */
+
+#ifndef USB_XHCI_H
+#define USB_XHCI_H
+
+#include <stdint.h>
+#include "usb-core.h"
+
+#define BIT(x) (1 << x)
+
+/* 5.3 Host Controller Capability Registers
+ * Table 19
+ */
+struct xhci_cap_regs {
+ uint8_t caplength;
+ uint8_t reserved;
+ uint16_t hciversion;
+ uint32_t hcsparams1;
+ uint32_t hcsparams2;
+ uint32_t hcsparams3;
+ uint32_t hccparams;
+#define XHCI_HCCPARAMS_CSZ BIT(2)
+#define XHCI_HCCPARAMS_XECP(x) ((x & 0xFFFF0000) >> 16)
+ uint32_t dboff;
+ uint32_t rtsoff;
+} __attribute__ ((packed));
+
+/* USB 3.0: Section 7 and 7.2 */
+#define XHCI_XECP_CAP_ID(x) ((x & 0xF))
+#define XHCI_XECP_CAP_SP 2
+#define XHCI_XECP_CAP_SP_MN(x) ((x & 0xFF0000) >> 16)
+#define XHCI_XECP_CAP_SP_MJ(x) ((x & 0xFF000000) >> 24)
+#define XHCI_XECP_CAP_SP_PC(x) ((x & 0xFF00) >> 8)
+#define XHCI_XECP_CAP_SP_PO(x) (x & 0xFF)
+#define XHCI_XECP_NEXT_PTR(x) ((x & 0xFF00) >> 8)
+
+/* Table 27: Host Controller USB Port Register Set */
+struct xhci_port_regs {
+ uint32_t portsc;
+#define PORTSC_CCS BIT(0)
+#define PORTSC_PED BIT(1)
+#define PORTSC_OCA BIT(3)
+#define PORTSC_PR BIT(4)
+#define PORTSC_PLS_MASK (0xF << 5)
+#define PORTSC_PLS_U0 0
+#define PORTSC_PLS_U1 1
+#define PORTSC_PLS_U2 2
+#define PORTSC_PLS_U3 3
+#define PORTSC_PLS_DISABLED 4
+#define PORTSC_PLS_RXDETECT 5
+#define PORTSC_PLS_INACTIVE 6
+#define PORTSC_PLS_POLLING 7
+#define PORTSC_PLS_RECOVERY 8
+#define PORTSC_PLS_HOTRESET 9
+#define PORTSC_PLS_COMP_MODE 10
+#define PORTSC_PLS_TEST_MODE 11
+#define PORTSC_PLS_RESUME 15
+#define PORTSC_PP BIT(9)
+#define PORTSC_PS_MASK (0xF << 10)
+#define PORTSC_PIC_MASK (0x3 << 14)
+#define PORTSC_LWS BIT(16)
+#define PORTSC_CSC BIT(17)
+#define PORTSC_PEC BIT(18)
+#define PORTSC_WRC BIT(19)
+#define PORTSC_OCC BIT(20)
+#define PORTSC_PRC BIT(21)
+#define PORTSC_PLC BIT(22)
+#define PORTSC_CEC BIT(23)
+#define PORTSC_CAS BIT(24)
+#define PORTSC_WCE BIT(25)
+#define PORTSC_WDE BIT(26)
+#define PORTSC_WOE BIT(27)
+#define PORTSC_DR BIT(30)
+#define PORTSC_WPR BIT(31)
+
+ uint32_t portpmsc;
+ uint32_t portli;
+ uint32_t reserved;
+} __attribute__ ((packed));
+
+struct port_state {
+ bool PP;
+ bool CCS;
+ bool PED;
+ bool PR;
+ uint8_t PLS;
+ char *state;
+};
+
+
+struct port_state ps_array_usb2[] = {
+ {1, 0, 0, 0, PORTSC_PLS_U0, "ERROR"}
+};
+
+struct port_state ps_array_usb3[] = {
+ {0, 0, 0, 0, PORTSC_PLS_DISABLED, "Powered-OFF"},
+ {1, 0, 0, 0, PORTSC_PLS_POLLING, "Polling"},
+ {1, 0, 0, 0, PORTSC_PLS_U0, "Polling"},
+ {1, 0, 0, 0, PORTSC_PLS_RXDETECT, "*** Disconnected ***"},
+ {1, 0, 0, 0, PORTSC_PLS_DISABLED, "Disabled"},
+ {1, 0, 0, 0, PORTSC_PLS_INACTIVE, "Error"},
+ {1, 0, 0, 0, PORTSC_PLS_TEST_MODE,"Loopback"},
+ {1, 0, 0, 0, PORTSC_PLS_COMP_MODE,"Compliancek"},
+ {1, 1, 0, 1, PORTSC_PLS_U0, "****** Reset ******"},
+ {1, 1, 1, 0, PORTSC_PLS_U0, "****** Enabled ******"},
+};
+
+/* 5.4 Host Controller Operational Registers
+ * Table 26
+ */
+struct xhci_op_regs {
+ uint32_t usbcmd;
+#define XHCI_USBCMD_RS BIT(0)
+#define XHCI_USBCMD_HCRST BIT(1)
+
+ uint32_t usbsts;
+#define XHCI_USBSTS_HCH BIT(0)
+#define XHCI_USBSTS_CNR BIT(11)
+
+ uint32_t pagesize;
+ uint8_t reserved[8]; /* 0C - 13 */
+ uint32_t dnctrl; /* Device notification control */
+ uint64_t crcr; /* Command ring control */
+#define XHCI_CRCR_CRP_MASK 0xFFFFFFFFFFFFFFC0
+#define XHCI_CRCR_CRR BIT(3)
+#define XHCI_CRCR_CRP_SIZE 4096
+
+ uint8_t reserved1[16]; /* 20 - 2F */
+ uint64_t dcbaap; /* Device Context Base Address Array Pointer */
+#define XHCI_DCBAAP_MAX_SIZE 2048
+
+ uint32_t config; /* Configure */
+#define XHCI_CONFIG_MAX_SLOT 4
+
+ uint8_t reserved2[964]; /* 3C - 3FF */
+ /* USB Port register set */
+#define XHCI_PORT_MAX 256
+ struct xhci_port_regs prs[XHCI_PORT_MAX];
+} __attribute__ ((packed));
+
+/*
+ * 5.5.2 Interrupter Register Set
+ * Table 42: Interrupter Registers
+ */
+struct xhci_int_regs {
+ uint32_t iman;
+ uint32_t imod;
+ uint32_t erstsz;
+#define XHCI_ERST_SIZE_MASK 0xFFFF
+ uint32_t reserved;
+ uint64_t erstba;
+#define XHCI_ERST_ADDR_MASK (~(0x3FUL))
+ uint64_t erdp;
+#define XHCI_ERDP_MASK (~(0xFUL))
+} __attribute__ ((packed));
+
+/* 5.5 Host Controller Runtime Registers */
+struct xhci_run_regs {
+ uint32_t mfindex; /* microframe index */
+ uint8_t reserved[28];
+#define XHCI_IRS_MAX 1024
+ struct xhci_int_regs irs[XHCI_IRS_MAX];
+} __attribute__ ((packed));
+
+/* 5.6 Doorbell Registers*/
+struct xhci_db_regs {
+ uint32_t db[256];
+} __attribute__ ((packed));
+
+#define COMP_SUCCESS 1
+
+#define TRB_SLOT_ID(x) (((x) & (0xFF << 24)) >> 24)
+#define TRB_CMD_SLOT_ID(x) ((x & 0xFF) << 24)
+#define TRB_TYPE(x) (((x) & (0x3F << 10)) >> 10)
+#define TRB_CMD_TYPE(x) ((x & 0x3F) << 10)
+#define TRB_STATUS(x) (((x) & (0xFF << 24)) >> 24)
+#define TRB_ADDR_LOW(x) ((uint32_t)((uint64_t)(x)))
+#define TRB_ADDR_HIGH(x) ((uint32_t)((uint64_t)(x) >> 32))
+#define TRB_TRT(x) (((x) & 0x3) << 16 )
+#define TRB_DIR_IN BIT(16)
+#define TRB_IOC BIT(5)
+#define TRB_IDT BIT(6)
+
+#define TRB_CYCLE_STATE BIT(0)
+
+struct xhci_transfer_trb {
+ uint64_t addr;
+ uint32_t len;
+ uint32_t flags;
+} __attribute__ ((packed));
+
+struct xhci_link_trb {
+ uint64_t addr;
+ uint32_t field2;
+ uint32_t field3;
+} __attribute__ ((packed));
+
+/* Event TRB */
+struct xhci_event_trb {
+ uint64_t addr;
+ uint32_t status;
+ uint32_t flags;
+} __attribute__ ((packed));
+
+#define TRB_NORMAL 1
+#define TRB_SETUP_STAGE 2
+#define TRB_DATA_STAGE 3
+#define TRB_STATUS_STAGE 4
+#define TRB_ISOCH 5
+#define TRB_LINK 6
+#define TRB_EVENT_DATA 7
+#define TRB_NOOP 8
+#define TRB_ENABLE_SLOT 9
+#define TRB_DISABLE_SLOT 10
+#define TRB_ADDRESS_DEV 11
+#define TRB_CONFIG_EP 12
+#define TRB_EVAL_CNTX 13
+#define TRB_TRANSFER_EVENT 32
+#define TRB_CMD_COMPLETION 33
+#define TRB_PORT_STATUS 34
+
+struct xhci_command_trb {
+ uint32_t field[4];
+}__attribute__ ((packed));
+
+union xhci_trb {
+ struct xhci_event_trb event;
+ struct xhci_transfer_trb xfer;
+ struct xhci_command_trb cmd;
+ struct xhci_link_trb link;
+};
+
+enum xhci_seg_type {
+ TYPE_CTRL = 0,
+ TYPE_BULK,
+ TYPE_COMMAND,
+ TYPE_EVENT,
+};
+
+struct xhci_seg {
+ union xhci_trb *trbs;
+ struct xhci_seg *next;
+ uint64_t enq;
+ uint64_t deq;
+ uint64_t trbs_dma;
+ uint32_t size;
+ uint32_t cycle_state;
+ enum xhci_seg_type type;
+};
+
+#define XHCI_TRB_SIZE 16
+#define XHCI_EVENT_TRBS_SIZE 4096
+#define XHCI_CONTROL_TRBS_SIZE 4096
+#define XHCI_DATA_TRBS_SIZE 4096
+#define XHCI_ERST_NUM_SEGS 1
+
+#define XHCI_MAX_BULK_SIZE 0xF000
+
+struct xhci_erst_entry {
+ uint64_t addr;
+ uint32_t size;
+ uint32_t reserved;
+} __attribute__ ((packed));
+
+struct xhci_erst {
+ struct xhci_erst_entry *entries;
+ uint64_t dma;
+ uint32_t num_segs; /* number of segments */
+};
+
+struct xhci_control_ctx {
+ uint32_t d_flags;
+ uint32_t a_flags;
+ uint32_t reserved[6];
+} __attribute__ ((packed));
+
+struct xhci_slot_ctx {
+ uint32_t field1;
+#define SLOT_SPEED_FS BIT(20)
+#define SLOT_SPEED_LS BIT(21)
+#define SLOT_SPEED_HS BIT(22)
+#define SLOT_SPEED_SS BIT(23)
+#define LAST_CONTEXT(x) (x << 27)
+
+ uint32_t field2;
+#define ROOT_HUB_PORT(x) ((x & 0xff) << 16)
+
+ uint32_t field3;
+ uint32_t field4;
+#define USB_DEV_ADDRESS(x) (x & 0xFFU)
+#define SLOT_STATE(x) ((x >> 27) & 0x1FU)
+#define SLOT_STATE_DIS_ENA 0
+#define SLOT_STATE_DEFAULT 1
+#define SLOT_STATE_ADDRESSED 2
+#define SLOT_STATE_CONFIGURED 3
+
+
+ uint32_t reserved[4];
+} __attribute__ ((packed));
+
+struct xhci_ep_ctx {
+ uint32_t field1;
+ uint32_t field2;
+#define MAX_PACKET_SIZE(x) (((x) & 0xFFFF) << 16)
+#define MAX_BURST(x) (((x) & 0xFF) << 8)
+#define EP_TYPE(x) (((x) & 0x07) << 3)
+#define EP_ISOC_OUT 1
+#define EP_BULK_OUT 2
+#define EP_INT_OUT 3
+#define EP_CTRL 4
+#define EP_ISOC_IN 5
+#define EP_BULK_IN 6
+#define EP_INT_IN 7
+
+#define ERROR_COUNT(x) (((x) & 0x03) << 1)
+
+ uint64_t deq_addr;
+ uint32_t field4;
+ uint32_t reserved[3];
+} __attribute__ ((packed));
+
+struct xhci_ctx {
+ uint8_t type;
+#define XHCI_CTX_TYPE_DEVICE 0x1
+#define XHCI_CTX_TYPE_INPUT 0x2
+ uint32_t size;
+ uint8_t *addr;
+#define XHCI_CTX_BUF_SIZE 4096
+ uint64_t dma_addr;
+};
+
+struct xhci_dev {
+ struct usb_dev *dev;
+ uint32_t slot_id;
+ struct xhci_ctx in_ctx;
+ struct xhci_ctx out_ctx;
+ struct xhci_seg control;
+ struct xhci_seg bulk_in;
+ struct xhci_seg bulk_out;
+ uint32_t ctx_size;
+};
+
+struct xhci_hcd {
+ struct xhci_cap_regs *cap_regs;
+ struct xhci_op_regs *op_regs;
+ struct xhci_run_regs *run_regs;
+ struct xhci_db_regs *db_regs;
+ struct usb_hcd_dev *hcidev;
+ struct xhci_dev xdevs[XHCI_CONFIG_MAX_SLOT + 1];
+ struct usb_pipe *freelist;
+ struct usb_pipe *end;
+ uint64_t *dcbaap;
+ uint64_t dcbaap_dma;
+ struct xhci_seg ering;
+ struct xhci_seg crseg;
+ struct xhci_erst erst;
+ uint64_t erds_dma;
+ uint32_t erds_size;
+ uint32_t slot_id;
+ uint32_t hcc_csz_64;
+ void *pool;
+#define XHCI_PIPE_POOL_SIZE 4096
+
+ long pool_phys;
+};
+
+struct xhci_pipe {
+ struct usb_pipe pipe;
+ struct xhci_seg *seg;
+};
+
+#endif /* USB_XHCI_H */
diff --git a/qemu/roms/SLOF/lib/libusb/usb.code b/qemu/roms/SLOF/lib/libusb/usb.code
new file mode 100644
index 000000000..fd92d9e78
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb.code
@@ -0,0 +1,162 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * libusb bindings for SLOF - implementation
+ */
+
+#include <usb.h>
+
+
+/************************************************/
+/* Register with the usb-core */
+/* SLOF: USB-OHCI-REGISTER ( -- ) */
+/* LIBNEWUSB: usb_ohci_register(void) */
+/************************************************/
+PRIM(USB_X2d_OHCI_X2d_REGISTER)
+ usb_ohci_register();
+MIRP
+
+/************************************************/
+/* Register with the usb-core */
+/* SLOF: USB-EHCI-REGISTER ( -- ) */
+/* LIBNEWUSB: usb_ehci_register(void) */
+/************************************************/
+PRIM(USB_X2d_EHCI_X2d_REGISTER)
+ usb_ehci_register();
+MIRP
+
+/************************************************/
+/* Register with the usb-core */
+/* SLOF: USB-XHCI-REGISTER ( -- ) */
+/* LIBNEWUSB: usb_xhci_register(void) */
+/************************************************/
+PRIM(USB_X2d_XHCI_X2d_REGISTER)
+ usb_xhci_register();
+MIRP
+
+/************************************************/
+/* Initialize hcidev with the usb-core */
+/* SLOF: USB-HCD-INIT ( hcidev -- ) */
+/* LIBNEWUSB: usb_hcd_init(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HCD_X2d_INIT)
+ void *hcidev = TOS.a; POP;
+ usb_hcd_init(hcidev);
+MIRP
+
+/************************************************/
+/* Remove hcidev with the usb-core */
+/* SLOF: USB-HCD-EXIT ( hcidev -- ) */
+/* LIBNEWUSB: usb_hcd_exit(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HCD_X2d_EXIT)
+ void *hcidev = TOS.a; POP;
+ usb_hcd_exit(hcidev);
+MIRP
+
+/************************************************/
+/* Initialize hid */
+/* SLOF: USB-HID-INIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_hid_init(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HID_X2d_INIT)
+ void *dev = TOS.a;
+ TOS.n = usb_hid_init(dev);
+MIRP
+
+/************************************************/
+/* Exit hid */
+/* SLOF: USB-HID-EXIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_hid_exit(hcidev) */
+/************************************************/
+PRIM(USB_X2d_HID_X2d_EXIT)
+ void *dev = TOS.a;
+ TOS.n = usb_hid_exit(dev);
+MIRP
+
+/************************************************/
+/* Read usb keyboard for key */
+/* SLOF: USB-READ-KEYB ( dev -- */
+/* ( key | false )) */
+/* LIBNEWUSB: usb_read_keyb */
+/************************************************/
+PRIM(USB_X2d_READ_X2d_KEYB)
+ void *dev = TOS.a;
+ TOS.n = usb_read_keyb(dev);
+MIRP
+
+/************************************************/
+/* Is USB KEY available */
+/* SLOF: USB-KEY-AVAILABLE ( dev -- ( true | */
+/* false ))*/
+/* LIBNEWUSB: usb_key_available */
+/************************************************/
+PRIM(USB_X2d_KEY_X2d_AVAILABLE)
+ void *dev = TOS.a;
+ TOS.n = usb_key_available(dev);
+MIRP
+
+/************************************************/
+/* Initialize and enumerate generic hub */
+/* SLOF: USB-HUB-INIT ( dev -- true | false ) */
+/* LIBNEWUSB: usb_hub_init */
+/************************************************/
+PRIM(USB_X2d_HUB_X2d_INIT)
+ void *dev = TOS.a;
+ TOS.n = usb_hub_init(dev);
+MIRP
+
+/************************************************/
+/* Initialize msc */
+/* SLOF: USB-MSC-INIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_msc_init(hcidev) */
+/************************************************/
+PRIM(USB_X2d_MSC_X2d_INIT)
+ void *dev = TOS.a;
+ TOS.n = usb_msc_init(dev);
+MIRP
+
+/************************************************/
+/* Exit msc */
+/* SLOF: USB-MSC-EXIT ( dev -- true | false )*/
+/* LIBNEWUSB: usb_msc_exit(hcidev) */
+/************************************************/
+PRIM(USB_X2d_MSC_X2d_EXIT)
+ void *dev = TOS.a;
+ TOS.n = usb_msc_exit(dev);
+MIRP
+
+/*****************************************************************************/
+/* Transfer data through control endpoint */
+/* SLOF: USB-TRANSFER_CTRL ( dev req data -- true | false ) */
+/* LIBNEWUSB: int usb_transfer_ctrl(void *dev, void *req, void *data) */
+/*****************************************************************************/
+PRIM(USB_X2d_TRANSFER_X2d_CTRL)
+ void *data = TOS.a; POP;
+ void *req = TOS.a; POP;
+ TOS.n = usb_transfer_ctrl(TOS.a, req, data);
+MIRP
+
+/*****************************************************************************/
+/* Transfer data through bulk endpoint */
+/* SLOF: USB-TRANSFER_BULK ( dev dir td td-phys data size -- true | false ) */
+/* LIBNEWUSB: int usb_transfer_bulk(void *dev, int dir, void *td, */
+/* void *td_phys, void *data, int size) */
+/*****************************************************************************/
+PRIM(USB_X2d_TRANSFER_X2d_BULK)
+ int size = TOS.u; POP;
+ void *data = TOS.a; POP;
+ void *td_phys = TOS.a; POP;
+ void *td = TOS.a; POP;
+ int dir = TOS.u; POP;
+ TOS.n = usb_transfer_bulk(TOS.a, dir, td, td_phys, data, size);
+MIRP
diff --git a/qemu/roms/SLOF/lib/libusb/usb.h b/qemu/roms/SLOF/lib/libusb/usb.h
new file mode 100644
index 000000000..fba19d2a1
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * prototypes for libusb implementation used in libusb.code
+ */
+
+#ifndef __LIBUSB_H
+#define __LIBUSB_H
+
+/*******************************************/
+/* SLOF: USB-OHCI-REGISTER */
+/*******************************************/
+extern void usb_ohci_register(void);
+/*******************************************/
+/* SLOF: USB-EHCI-REGISTER */
+/*******************************************/
+extern void usb_ehci_register(void);
+/*******************************************/
+/* SLOF: USB-XHCI-REGISTER */
+/*******************************************/
+extern void usb_xhci_register(void);
+/*******************************************/
+/* SLOF: USB-HCD-INIT */
+/*******************************************/
+extern void usb_hcd_init(void *hcidev);
+/*******************************************/
+/* SLOF: USB-HCD-EXIT */
+/*******************************************/
+extern void usb_hcd_exit(void *hcidev);
+/*******************************************/
+/* SLOF: USB-HID-INIT */
+/*******************************************/
+extern int usb_hid_init(void *dev);
+/*******************************************/
+/* SLOF: USB-HID-EXIT */
+/*******************************************/
+extern int usb_hid_exit(void *dev);
+/*******************************************/
+/* SLOF: USB-READ-KEYB */
+/*******************************************/
+extern unsigned char usb_read_keyb(void *dev);
+/*******************************************/
+/* SLOF: USB-KEY-AVAILABLE */
+/*******************************************/
+extern unsigned char usb_key_available(void *dev);
+/*******************************************/
+/* SLOF: USB-HUB-INIT */
+/*******************************************/
+extern unsigned int usb_hub_init(void *dev);
+/*******************************************/
+/* SLOF: USB-MSC-INIT */
+/*******************************************/
+extern int usb_msc_init(void *dev);
+/*******************************************/
+/* SLOF: USB-MSC-EXIT */
+/*******************************************/
+extern int usb_msc_exit(void *dev);
+/*******************************************/
+/* SLOF: USB-TRANSFER-CTRL */
+/*******************************************/
+extern int usb_transfer_ctrl(void *dev, void *req, void *data);
+/*******************************************/
+/* SLOF: USB-TRANSFER-BULK */
+/*******************************************/
+extern int usb_transfer_bulk(void *dev, int dir, void *td,
+ void *td_phys, void *data, int size);
+
+#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb.in b/qemu/roms/SLOF/lib/libusb/usb.in
new file mode 100644
index 000000000..7ceba7d2d
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libusb/usb.in
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * Copyright (c) 2007, 2012, 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+/*
+ * libusb bindings for SLOF - definitions
+ */
+
+cod(USB-OHCI-REGISTER)
+cod(USB-EHCI-REGISTER)
+cod(USB-XHCI-REGISTER)
+cod(USB-HCD-INIT)
+cod(USB-HCD-EXIT)
+cod(USB-HID-INIT)
+cod(USB-HID-EXIT)
+cod(USB-READ-KEYB)
+cod(USB-KEY-AVAILABLE)
+cod(USB-HUB-INIT)
+cod(USB-MSC-INIT)
+cod(USB-MSC-EXIT)
+cod(USB-TRANSFER-CTRL)
+cod(USB-TRANSFER-BULK)