diff options
author | Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> | 2013-07-24 14:27:09 +0530 |
---|---|---|
committer | Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> | 2013-07-24 14:46:23 +0530 |
commit | 2deb222c4c9eac625526f9d2f45df8666753c09a (patch) | |
tree | 420d9d8057a07715e735b54352f9d7e59a0be96d /lib | |
parent | 912a746dc1530179560a87f65121feb1920b583f (diff) | |
download | SLOF-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/Makefile | 4 | ||||
-rw-r--r-- | lib/libusb/usb-core.c | 216 | ||||
-rw-r--r-- | lib/libusb/usb-core.h | 119 | ||||
-rw-r--r-- | lib/libusb/usb-ohci.c | 13 | ||||
-rw-r--r-- | lib/libusb/usb-slof.c | 55 |
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(®s->cmd_status, OHCI_CMD_STATUS_HCR); while ((time > SLOF_GetTimer()) && (read_reg(®s->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(®s->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(®s->cntl_head_ed, ohci_pipe_get_ed_phys(pipe)); write_reg(®s->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; +} |