aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2013-07-24 14:27:09 +0530
committerNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2013-07-24 14:46:23 +0530
commit2deb222c4c9eac625526f9d2f45df8666753c09a (patch)
tree420d9d8057a07715e735b54352f9d7e59a0be96d /lib
parent912a746dc1530179560a87f65121feb1920b583f (diff)
downloadSLOF-2deb222c4c9eac625526f9d2f45df8666753c09a.zip
SLOF-2deb222c4c9eac625526f9d2f45df8666753c09a.tar.gz
SLOF-2deb222c4c9eac625526f9d2f45df8666753c09a.tar.bz2
usb-core: setup new device
* Configures the newly found usb devices. Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Fixes-by: Avik Sil <aviksil@linux.vnet.ibm.com> Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Acked-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/libusb/Makefile4
-rw-r--r--lib/libusb/usb-core.c216
-rw-r--r--lib/libusb/usb-core.h119
-rw-r--r--lib/libusb/usb-ohci.c13
-rw-r--r--lib/libusb/usb-slof.c55
5 files changed, 399 insertions, 8 deletions
diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile
index 3153e6b..ca3a8fa 100644
--- a/lib/libusb/Makefile
+++ b/lib/libusb/Makefile
@@ -14,7 +14,7 @@ TOPCMNDIR ?= ../..
ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
- -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR)
LDFLAGS = -nostdlib
TARGET = ../libusb.a
@@ -22,7 +22,7 @@ TARGET = ../libusb.a
all: $(TARGET)
-SRCS = usb-core.c usb-ohci.c usb-ehci.c
+SRCS = usb-core.c usb-ohci.c usb-ehci.c usb-slof.c
OBJS = $(SRCS:%.c=%.o)
diff --git a/lib/libusb/usb-core.c b/lib/libusb/usb-core.c
index b1e3449..3a96795 100644
--- a/lib/libusb/usb-core.c
+++ b/lib/libusb/usb-core.c
@@ -108,8 +108,10 @@ struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
{
if (validate_hcd_ops(dev) && dev->hcidev->ops->get_pipe)
return dev->hcidev->ops->get_pipe(dev, ep, buf, len);
- else
+ else {
+ printf("%s: Failed\n", __func__);
return NULL;
+ }
}
void usb_put_pipe(struct usb_pipe *pipe)
@@ -175,3 +177,215 @@ int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data)
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;
+ write_reg16(&req.wValue, (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;
+ write_reg16(&req.wLength, (uint16_t)size);
+ write_reg16(&req.wValue, 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;
+ write_reg16(&req.wLength, (uint16_t)size);
+ write_reg16(&req.wValue, 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;
+ write_reg16(&req.wValue, 0x00FF & cfg_value);
+ return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+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, read_reg16(&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 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 = 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_populate_pipe(dev, ep, NULL, 0); */
+ break;
+ case DESCR_TYPE_HID:
+ hid = (struct usb_dev_hid_descr *)ptr;
+ dprintf("hid-report %d size %d\n",
+ hid->bReportType, read_reg16(&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;
+}
+
+#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
+
+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;
+ write_reg16(&ep.wMaxPacketSize, 8);
+ dev->control = usb_get_pipe(dev, &ep, NULL, 0);
+
+ if (!usb_get_device_descr(dev, &descr, sizeof(struct usb_dev_descr)))
+ goto fail;
+ dev->control->mps = descr.bMaxPacketSize0;
+
+ if (!usb_set_address(dev, port))
+ goto fail;
+
+ 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 = read_reg16(&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;
+ 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\n", dev->intf_num);
+ 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/lib/libusb/usb-core.h b/lib/libusb/usb-core.h
index cc9dbe9..ca3b627 100644
--- a/lib/libusb/usb-core.h
+++ b/lib/libusb/usb-core.h
@@ -57,8 +57,18 @@ struct usb_ep_descr {
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 */
+
/* 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;
@@ -69,11 +79,29 @@ struct usb_dev {
struct usb_pipe *bulk_out;
struct usb_ep_descr ep[USB_DEV_EP_MAX];
uint32_t ep_cnt;
- uint32_t type;
+ uint32_t class;
uint32_t speed;
uint32_t addr;
+ uint32_t mps;
+ 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));
+
struct usb_pipe {
struct usb_dev *dev;
struct usb_pipe *next;
@@ -108,6 +136,16 @@ struct usb_pipe {
#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 */
@@ -116,6 +154,81 @@ struct usb_dev_req {
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 MaxPower; /* 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 *);
@@ -136,5 +249,9 @@ extern void usb_put_pipe(struct usb_pipe *pipe);
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);
#endif
diff --git a/lib/libusb/usb-ohci.c b/lib/libusb/usb-ohci.c
index 6fe0181..22f23e0 100644
--- a/lib/libusb/usb-ohci.c
+++ b/lib/libusb/usb-ohci.c
@@ -62,7 +62,7 @@ static void ohci_dump_regs(struct ohci_regs *regs)
static int ohci_hcd_reset(struct ohci_regs *regs)
{
uint32_t time;
- time = SLOF_GetTimer() + 20;
+ time = SLOF_GetTimer() + USB_TIMEOUT;
write_reg(&regs->cmd_status, OHCI_CMD_STATUS_HCR);
while ((time > SLOF_GetTimer()) &&
(read_reg(&regs->cmd_status) & OHCI_CMD_STATUS_HCR))
@@ -135,6 +135,7 @@ static int ohci_hcd_init(struct ohci_hcd *ohcd)
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;
@@ -152,12 +153,16 @@ static void ohci_hub_check_ports(struct ohci_hcd *ohcd)
dprintf("Start enumerating device\n");
SLOF_msleep(10);
} else
- dprintf("Start removing device\n");
+ printf("Start removing device\n");
}
port_status = read_reg(&regs->rh_ps[i]);
if (port_status & RH_PS_PRSC) {
port_clear |= RH_PS_PRSC;
- dprintf("Device reset\n");
+ 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;
@@ -393,7 +398,7 @@ static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *
write_reg(&regs->cntl_head_ed, ohci_pipe_get_ed_phys(pipe));
write_reg(&regs->cmd_status, OHCI_CMD_STATUS_CLF);
- time = SLOF_GetTimer() + 20;
+ time = SLOF_GetTimer() + USB_TIMEOUT;
while ((time > SLOF_GetTimer()) &&
((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp))
cpu_relax();
diff --git a/lib/libusb/usb-slof.c b/lib/libusb/usb-slof.c
new file mode 100644
index 0000000..6f2c852
--- /dev/null
+++ b/lib/libusb/usb-slof.c
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * 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 ...) printf(_x)
+#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");
+ }
+ return true;
+}