diff --git a/Makefile b/Makefile index b678c44..179066e 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,7 @@ CSRCS= \ $(SRCDIR)/MCD_tasks.c \ $(SRCDIR)/MCD_tasksInit.c \ \ + $(SRCDIR)/usb.c \ $(SRCDIR)/ohci-hcd.c \ $(SRCDIR)/ehci-hcd.c \ \ diff --git a/bas.lk.in b/bas.lk.in index 8c03109..7ac7145 100644 --- a/bas.lk.in +++ b/bas.lk.in @@ -34,6 +34,9 @@ SECTIONS OBJDIR/supervisor.o(.text) OBJDIR/mmu.o(.text) OBJDIR/pci.o(.text) + OBJDIR/usb.o(.text) + OBJDIR/ohci-hcd.o(.text) + OBJDIR/ehci-hcd.o(.text) OBJDIR/BaS.o(.text) OBJDIR/wait.o(.text) diff --git a/include/bas_string.h b/include/bas_string.h index 0c9493c..9aa9e38 100644 --- a/include/bas_string.h +++ b/include/bas_string.h @@ -33,6 +33,7 @@ extern char *strcat(char *dst, const char *src); extern char *strncat(char *dst, const char *src, int max); extern int atoi(const char *c); extern void *memcpy(void *dst, const void *src, size_t n); +extern void *memset(void *s, int c, size_t n); extern void bzero(void *s, size_t n); #define isdigit(c) (((c) >= '0') && ((c) <= '9')) diff --git a/include/ehci.h b/include/ehci.h index 4d37076..09f1021 100644 --- a/include/ehci.h +++ b/include/ehci.h @@ -131,16 +131,16 @@ struct usb_linux_config_descriptor { #define ehci_readl(x) (*((volatile u32 *)(x))) #define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b)) #else -#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x)))) -#define ehci_writel(a, b) (*((volatile u32 *)(a)) = cpu_to_le32(((volatile u32)b))) +#define ehci_readl(x) swpl((*((volatile u32 *)(x)))) +#define ehci_writel(a, b) (*((volatile u32 *)(a)) = swpl(((volatile u32)b))) #endif #if defined CONFIG_EHCI_MMIO_BIG_ENDIAN #define hc32_to_cpu(x) be32_to_cpu((x)) #define cpu_to_hc32(x) cpu_to_be32((x)) #else -#define hc32_to_cpu(x) le32_to_cpu((x)) -#define cpu_to_hc32(x) cpu_to_le32((x)) +#define hc32_to_cpu(x) swpl((x)) +#define cpu_to_hc32(x) swpl((x)) #endif #define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */ diff --git a/include/pci.h b/include/pci.h index b2a4434..7ccbc8f 100644 --- a/include/pci.h +++ b/include/pci.h @@ -199,8 +199,18 @@ extern void init_eport(void); extern void init_xlbus_arbiter(void); extern void init_pci(void); +struct resource_descriptor +{ + uint16_t next; + uint16_t flags; + uint32_t start; + uint32_t length; + uint32_t offset; + uint32_t dma_offset; + uint8_t private; +} __attribute__ ((packed)); + extern int pci_find_device(uint16_t device_id, uint16_t vendor_id, int index); -/* FIXME: parameters missing */ extern uint32_t pci_read_config_longword(uint16_t handle, uint16_t offset); extern uint16_t pci_read_config_word(uint16_t handle, uint16_t offset); @@ -210,7 +220,7 @@ extern void pci_write_config_longword(uint16_t handle, uint16_t offset, uint32_t extern void pci_write_config_word(uint16_t handle, uint16_t offset, uint16_t value); extern void pci_write_config_byte(uint16_t handle, uint16_t offset, uint8_t value); -extern void *pci_get_resource(); +extern struct resource_descriptor *pci_get_resource(uint16_t handle); extern void pci_hook_interrupt(); extern void pci_unhook_interrupt(); diff --git a/include/usb.h b/include/usb.h index dbda725..5ea9349 100644 --- a/include/usb.h +++ b/include/usb.h @@ -26,8 +26,8 @@ #ifndef _USB_H_ #define _USB_H_ -#include -#include +//#include +#include #include "pci.h" #include "mod_devicetable.h" #include "pci_ids.h" @@ -44,15 +44,15 @@ extern long *tab_funcs_pci; #define out32r(addr,val) Write_mem_longword(usb_handle,addr,val) -#define __u8 unsigned char -#define __u16 unsigned short -#define __u32 unsigned long -#define u8 unsigned char -#define u16 unsigned short -#define u32 unsigned long -#define uint8_t unsigned char -#define uint32_t unsigned long -#define uint16_t unsigned short +#define __u8 uint8_t +#define __u16 uint16_t +#define __u32 uint32_t +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define uint8_t uint8_t +#define uint32_t uint32_t +#define uint16_t uint16_t extern void kprint(const char *fmt, ...); extern int sprintD(char *s, const char *fmt, ...); @@ -75,71 +75,71 @@ extern int sprintD(char *s, const char *fmt, ...); /* String descriptor */ struct usb_string_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned short wData[1]; + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wData[1]; } __attribute__ ((packed)); /* device request (setup) */ struct devrequest { - unsigned char requesttype; - unsigned char request; - unsigned short value; - unsigned short index; - unsigned short length; + uint8_t requesttype; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; } __attribute__ ((packed)); /* All standard descriptors have these 2 fields in common */ struct usb_descriptor_header { - unsigned char bLength; - unsigned char bDescriptorType; + uint8_t bLength; + uint8_t bDescriptorType; } __attribute__ ((packed)); /* Device descriptor */ struct usb_device_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned short bcdUSB; - unsigned char bDeviceClass; - unsigned char bDeviceSubClass; - unsigned char bDeviceProtocol; - unsigned char bMaxPacketSize0; - unsigned short idVendor; - unsigned short idProduct; - unsigned short bcdDevice; - unsigned char iManufacturer; - unsigned char iProduct; - unsigned char iSerialNumber; - unsigned char bNumConfigurations; + 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)); /* Endpoint descriptor */ struct usb_endpoint_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned char bEndpointAddress; - unsigned char bmAttributes; - unsigned short wMaxPacketSize; - unsigned char bInterval; - unsigned char bRefresh; - unsigned char bSynchAddress; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + uint8_t bRefresh; + uint8_t bSynchAddress; } __attribute__ ((packed)) __attribute__ ((aligned(2))); /* Interface descriptor */ struct usb_interface_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned char bInterfaceNumber; - unsigned char bAlternateSetting; - unsigned char bNumEndpoints; - unsigned char bInterfaceClass; - unsigned char bInterfaceSubClass; - unsigned char bInterfaceProtocol; - unsigned char iInterface; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; - unsigned char no_of_ep; - unsigned char num_altsetting; - unsigned char act_altsetting; + uint8_t no_of_ep; + uint8_t num_altsetting; + uint8_t act_altsetting; struct usb_endpoint_descriptor ep_desc[USB_MAXENDPOINTS]; } __attribute__ ((packed)); @@ -147,16 +147,16 @@ struct usb_interface_descriptor { /* Configuration descriptor information.. */ struct usb_config_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned short wTotalLength; - unsigned char bNumInterfaces; - unsigned char bConfigurationValue; - unsigned char iConfiguration; - unsigned char bmAttributes; - unsigned char MaxPower; + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t MaxPower; - unsigned char no_of_if; /* number of interfaces */ + uint8_t no_of_if; /* number of interfaces */ struct usb_interface_descriptor if_desc[USB_MAXINTERFACES]; } __attribute__ ((packed)); @@ -193,14 +193,14 @@ struct usb_device { int have_langid; /* whether string_langid is valid yet */ int string_langid; /* language ID for strings */ int (*irq_handle)(struct usb_device *dev); - unsigned long irq_status; + uint32_t irq_status; int irq_act_len; /* transfered bytes */ void *privptr; /* * Child devices - if this is a hub device * Each instance needs its own set of data structures. */ - unsigned long status; + uint32_t status; int act_len; /* transfered bytes */ int maxchild; /* Number of ports if hub */ int portnr; @@ -230,16 +230,16 @@ typedef struct int ohci_usb_lowlevel_init(long handle, const struct pci_device_id *ent, void **priv); int ohci_usb_lowlevel_stop(void *priv); -int ohci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len); -int ohci_submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup); -int ohci_submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval); +int ohci_submit_bulk_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len); +int ohci_submit_control_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, struct devrequest *setup); +int ohci_submit_int_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, int interval); void ohci_usb_enable_interrupt(int enable); int ehci_usb_lowlevel_init(long handle, const struct pci_device_id *ent, void **priv); int ehci_usb_lowlevel_stop(void *priv); -int ehci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len); -int ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, struct devrequest *setup); -int ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval); +int ehci_submit_bulk_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len); +int ehci_submit_control_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, struct devrequest *setup); +int ehci_submit_int_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, int interval); void ehci_usb_enable_interrupt(int enable); void usb_enable_interrupt(int enable); @@ -276,16 +276,16 @@ int usb_stop(void); /* stop the USB Controller */ int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol); int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id); struct usb_device *usb_get_dev_index(int index, int bus); -int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned char request, unsigned char requesttype, unsigned short value, - unsigned short index, void *data, unsigned short size, int timeout); +int usb_control_msg(struct usb_device *dev, unsigned int pipe, uint8_t request, uint8_t requesttype, uint16_t value, + uint16_t index, void *data, uint16_t size, int timeout); int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout); -int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval); +int usb_submit_int_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, int interval); void usb_disable_asynch(int disable); -int usb_maxpacket(struct usb_device *dev, unsigned long pipe); -void wait_ms(unsigned long ms); -int usb_get_configuration_no(struct usb_device *dev, unsigned char *buffer, int cfgno); -int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size); -int usb_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size); +int usb_maxpacket(struct usb_device *dev, uint32_t pipe); +void wait_ms(uint32_t ms); +int usb_get_configuration_no(struct usb_device *dev, uint8_t *buffer, int cfgno); +int usb_get_report(struct usb_device *dev, int ifnum, uint8_t type, uint8_t id, void *buf, int size); +int usb_get_class_descriptor(struct usb_device *dev, int ifnum, uint8_t type, uint8_t id, void *buf, int size); int usb_clear_halt(struct usb_device *dev, int pipe); int usb_string(struct usb_device *dev, int index, char *buf, size_t size); int usb_set_interface(struct usb_device *dev, int interface, int alternate); @@ -391,26 +391,26 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); * Hub Stuff */ struct usb_port_status { - unsigned short wPortStatus; - unsigned short wPortChange; + uint16_t wPortStatus; + uint16_t wPortChange; } __attribute__ ((packed)); struct usb_hub_status { - unsigned short wHubStatus; - unsigned short wHubChange; + uint16_t wHubStatus; + uint16_t wHubChange; } __attribute__ ((packed)); /* Hub descriptor */ struct usb_hub_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned char bNbrPorts; - unsigned short wHubCharacteristics; - unsigned char bPwrOn2PwrGood; - unsigned char bHubContrCurrent; - unsigned char DeviceRemovable[(USB_MAXCHILDREN+1+7)/8]; - unsigned char PortPowerCtrlMask[(USB_MAXCHILDREN+1+7)/8]; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable[(USB_MAXCHILDREN+1+7)/8]; + uint8_t PortPowerCtrlMask[(USB_MAXCHILDREN+1+7)/8]; /* DeviceRemovable and PortPwrCtrlMask want to be variable-length bitmaps that hold max 255 entries. (bit0 is ignored) */ } __attribute__ ((packed)); diff --git a/include/util.h b/include/util.h index e04526a..3adf4fa 100644 --- a/include/util.h +++ b/include/util.h @@ -31,7 +31,7 @@ * uint16_t swpw(uint16_t val); * swap endianess of val, 16 bits only. */ -inline uint16_t swpw(uint16_t w) +static inline uint16_t swpw(uint16_t w) { register uint32_t result asm("d0"); __asm__ __volatile__ @@ -52,7 +52,7 @@ inline uint16_t swpw(uint16_t w) * swap endianess of val, 32 bits only. * e.g. ABCD => DCBA */ -inline uint32_t swpl(uint32_t l) +static inline uint32_t swpl(uint32_t l) { register uint32_t result asm("d0"); diff --git a/include/wait.h b/include/wait.h index 33e8424..0f7d9c6 100644 --- a/include/wait.h +++ b/include/wait.h @@ -36,6 +36,8 @@ //#error unknown machine #endif /* MACHINE_FIREBEE */ +#include "MCF5475.h" + typedef bool (*checker_func)(void); extern __inline__ void wait(uint32_t) __attribute__((always_inline)); diff --git a/sources/bas_string.c b/sources/bas_string.c index 0172048..a466bc5 100644 --- a/sources/bas_string.c +++ b/sources/bas_string.c @@ -42,6 +42,18 @@ void bzero(void *s, size_t n) ((unsigned char *) s)[i] = '\0'; } +void *memset(void *s, int c, size_t n) +{ + uint8_t *dst = s; + + do + { + *dst++ = c; + } while ((dst - (uint8_t *) s) < n); + + return s; +} + int strncmp(const char *s1, const char *s2, int max) { diff --git a/sources/ehci-hcd.c b/sources/ehci-hcd.c index f3cab0a..4609f2d 100644 --- a/sources/ehci-hcd.c +++ b/sources/ehci-hcd.c @@ -23,6 +23,7 @@ #include "util.h" /* for endian conversions */ +#include "wait.h" #include "usb.h" #include "ehci.h" @@ -204,13 +205,13 @@ static void cache_qh(struct QH *qh, int flush) if((uint32_t)qh & QH_LINK_TYPE_QH) break; qh = qh_addr(qh); - qh = (struct QH *)(hc32_to_cpu(qh->qh_link) + gehci.dma_offset); + qh = (struct QH *)(swpl(qh->qh_link) + gehci.dma_offset); } qh = qh_addr(qh); /* Save first qTD pointer, needed for invalidating pass on this QH */ if(flush) { - qtd = (struct qTD *)(hc32_to_cpu(*(uint32_t *)&qh->qh_overlay) & 0xffffffe0); + qtd = (struct qTD *)(swpl(*(uint32_t *)&qh->qh_overlay) & 0xffffffe0); if(qtd != NULL) qtd = (struct qTD *)(gehci.dma_offset + (uint32_t)qtd); first_qtd = qtd; @@ -223,7 +224,7 @@ static void cache_qh(struct QH *qh, int flush) if(qtd == NULL) break; cache_qtd(qtd, flush); - next = (struct qTD *)((uint32_t)hc32_to_cpu(qtd->qt_next) & 0xffffffe0); + next = (struct qTD *)((uint32_t)swpl(qtd->qt_next) & 0xffffffe0); if(next != NULL) next = (struct qTD *)(gehci.dma_offset + (uint32_t)next); if(next == qtd) @@ -396,7 +397,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) idx = 0; while(idx < 5) { - td->qt_buffer[idx] = cpu_to_hc32(addr - gehci.dma_offset); + td->qt_buffer[idx] = swpl(addr - gehci.dma_offset); next = (addr + 4096) & ~4095; delta = next - addr; if(delta >= sz) @@ -427,21 +428,21 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\r\n", dev, pipe, buffer, length, req); if(req != NULL) debug("ehci_submit_async req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\r\n", - req->request, req->request, req->requesttype, req->requesttype, le16_to_cpu(req->value), le16_to_cpu(req->value), le16_to_cpu(req->index)); + req->request, req->request, req->requesttype, req->requesttype, swpw(req->value), swpw(req->value), swpw(req->index)); qh = ehci_alloc(sizeof(struct QH), 32); if(qh == NULL) { debug("unable to allocate QH\r\n"); return -1; } - qh->qh_link = cpu_to_hc32(((uint32_t)gehci.qh_list - gehci.dma_offset) | QH_LINK_TYPE_QH); + qh->qh_link = swpl(((uint32_t)gehci.qh_list - gehci.dma_offset) | QH_LINK_TYPE_QH); c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && usb_pipeendpoint(pipe) == 0) ? 1 : 0; endpt = (8 << 28) | (c << 27) | (usb_maxpacket(dev, pipe) << 16) | (0 << 15) | (1 << 14) | (usb_pipespeed(pipe) << 12) | (usb_pipeendpoint(pipe) << 8) | (0 << 7) | (usb_pipedevice(pipe) << 0); - qh->qh_endpt1 = cpu_to_hc32(endpt); + qh->qh_endpt1 = swpl(endpt); endpt = (1 << 30) | (dev->portnr << 23) | (dev->parent->devnum << 16) | (0 << 8) | (0 << 0); - qh->qh_endpt2 = cpu_to_hc32(endpt); - qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + qh->qh_endpt2 = swpl(endpt); + qh->qh_overlay.qt_next = swpl(QT_NEXT_TERMINATE); + qh->qh_overlay.qt_altnext = swpl(QT_NEXT_TERMINATE); td = NULL; tdp = &qh->qh_overlay.qt_next; toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); @@ -453,17 +454,17 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b debug("unable to allocate SETUP td\r\n"); goto fail; } - td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + td->qt_next = swpl(QT_NEXT_TERMINATE); + td->qt_altnext = swpl(QT_NEXT_TERMINATE); token = (0 << 31) | (sizeof(*req) << 16) | (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0); - td->qt_token = cpu_to_hc32(token); + td->qt_token = swpl(token); if(ehci_td_buffer(td, req, sizeof(*req)) != 0) { debug("unable construct SETUP td\r\n"); ehci_free(td, sizeof(*td)); goto fail; } - *tdp = cpu_to_hc32((uint32_t)td - gehci.dma_offset); + *tdp = swpl((uint32_t)td - gehci.dma_offset); tdp = &td->qt_next; toggle = 1; } @@ -475,17 +476,17 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b debug("unable to allocate DATA td\r\n"); goto fail; } - td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + td->qt_next = swpl(QT_NEXT_TERMINATE); + td->qt_altnext = swpl(QT_NEXT_TERMINATE); token = (toggle << 31) | (length << 16) | ((req == NULL ? 1 : 0) << 15) | (0 << 12) | (3 << 10) | ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0); - td->qt_token = cpu_to_hc32(token); + td->qt_token = swpl(token); if(ehci_td_buffer(td, buffer, length) != 0) { debug("unable construct DATA td\r\n"); ehci_free(td, sizeof(*td)); goto fail; } - *tdp = cpu_to_hc32((uint32_t)td - gehci.dma_offset); + *tdp = swpl((uint32_t)td - gehci.dma_offset); tdp = &td->qt_next; } if(req != NULL) @@ -496,14 +497,14 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b debug("unable to allocate ACK td\r\n"); goto fail; } - td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + td->qt_next = swpl(QT_NEXT_TERMINATE); + td->qt_altnext = swpl(QT_NEXT_TERMINATE); token = (toggle << 31) | (0 << 16) | (1 << 15) | (0 << 12) | (3 << 10) | ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0); - td->qt_token = cpu_to_hc32(token); - *tdp = cpu_to_hc32((uint32_t)td - gehci.dma_offset); + td->qt_token = swpl(token); + *tdp = swpl((uint32_t)td - gehci.dma_offset); tdp = &td->qt_next; } - gehci.qh_list->qh_link = cpu_to_hc32(((uint32_t)qh - gehci.dma_offset) | QH_LINK_TYPE_QH); + gehci.qh_list->qh_link = swpl(((uint32_t)qh - gehci.dma_offset) | QH_LINK_TYPE_QH); /* Flush dcache */ ehci_flush_dcache(gehci.qh_list); usbsts = ehci_readl(&gehci.hcor->or_usbsts); @@ -525,10 +526,10 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b { /* Invalidate dcache */ ehci_invalidate_dcache(gehci.qh_list); - token = hc32_to_cpu(vtd->qt_token); + token = swpl(vtd->qt_token); if(!(token & 0x80)) break; - wait_ms(1); + wait(1 * 1000); ts++; } while(ts < 1000); @@ -542,8 +543,8 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b err("EHCI fail timeout STD_ASS reset (usbsts=%#x)", ehci_readl(&gehci.hcor->or_usbsts)); goto fail; } - gehci.qh_list->qh_link = cpu_to_hc32(((uint32_t)gehci.qh_list - gehci.dma_offset) | QH_LINK_TYPE_QH); - token = hc32_to_cpu(qh->qh_overlay.qt_token); + gehci.qh_list->qh_link = swpl(((uint32_t)gehci.qh_list - gehci.dma_offset) | QH_LINK_TYPE_QH); + token = swpl(qh->qh_overlay.qt_token); if(!(token & 0x80)) { debug("TOKEN=%#x\r\n", token); @@ -579,14 +580,14 @@ static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *b } return (dev->status != USB_ST_NOT_PROC) ? 0 : -1; fail: - td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); + td = (void *)swpl(qh->qh_overlay.qt_next); if(td != (void *)QT_NEXT_TERMINATE) td = (struct qTD *)(gehci.dma_offset + (uint32_t)td); while(td != (void *)QT_NEXT_TERMINATE) { qh->qh_overlay.qt_next = td->qt_next; ehci_free(td, sizeof(*td)); - td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); + td = (void *)swpl(qh->qh_overlay.qt_next); if(td != (void *)QT_NEXT_TERMINATE) td = (struct qTD *)(gehci.dma_offset + (uint32_t)td); } @@ -622,20 +623,20 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu int len, srclen; uint32_t reg; uint32_t *status_reg; - if(le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) + if(swpw(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { - err("The request port(%d) is not configured", le16_to_cpu(req->index) - 1); + err("The request port(%d) is not configured", swpw(req->index) - 1); return -1; } - status_reg = (uint32_t *)&gehci.hcor->or_portsc[le16_to_cpu(req->index) - 1]; + status_reg = (uint32_t *)&gehci.hcor->or_portsc[swpw(req->index) - 1]; srclen = 0; debug("ehci_submit_root req=%u (%#x), type=%u (%#x), value=%u, index=%u\r\n", - req->request, req->request, req->requesttype, req->requesttype, le16_to_cpu(req->value), le16_to_cpu(req->index)); + req->request, req->request, req->requesttype, req->requesttype, swpw(req->value), swpw(req->index)); typeReq = req->request | req->requesttype << 8; switch(typeReq) { case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(le16_to_cpu(req->value) >> 8) + switch(swpw(req->value) >> 8) { case USB_DT_DEVICE: debug("USB_DT_DEVICE request\r\n"); @@ -649,7 +650,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu break; case USB_DT_STRING: debug("USB_DT_STRING config\r\n"); - switch(le16_to_cpu(req->value) & 0xff) + switch(swpw(req->value) & 0xff) { case 0: /* Language */ srcptr = "\4\3\1\0"; @@ -665,17 +666,17 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu break; default: debug("unknown value DT_STRING %x\r\n", - le16_to_cpu(req->value)); + swpw(req->value)); goto unknown; } break; default: - debug("unknown value %x\r\n", le16_to_cpu(req->value)); + debug("unknown value %x\r\n", swpw(req->value)); goto unknown; } break; case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8): - switch(le16_to_cpu(req->value) >> 8) + switch(swpw(req->value) >> 8) { case USB_DT_HUB: debug("USB_DT_HUB config\r\n"); @@ -683,13 +684,13 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu srclen = 0x8; break; default: - debug("unknown value %x\r\n", le16_to_cpu(req->value)); + debug("unknown value %x\r\n", swpw(req->value)); goto unknown; } break; case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8): debug("USB_REQ_SET_ADDRESS\r\n"); - rootdev = le16_to_cpu(req->value); + rootdev = swpw(req->value); break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: debug("USB_REQ_SET_CONFIGURATION\r\n"); @@ -704,7 +705,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): memset(tmpbuf, 0, 4); reg = ehci_readl(status_reg); - if((reg & EHCI_PS_PR) && (portreset & (1 << le16_to_cpu(req->index)))) + if((reg & EHCI_PS_PR) && (portreset & (1 << swpw(req->index)))) { int ret; /* force reset to complete */ @@ -717,7 +718,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu reg = ehci_readl(status_reg); } else - err("port(%d) reset error", le16_to_cpu(req->index) - 1); + err("port(%d) reset error", swpw(req->index) - 1); } if(reg & EHCI_PS_CS) tmpbuf[0] |= USB_PORT_STAT_CONNECTION; @@ -747,7 +748,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; if(reg & EHCI_PS_OCC) tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; - if(portreset & (1 << le16_to_cpu(req->index))) + if(portreset & (1 << swpw(req->index))) tmpbuf[2] |= USB_PORT_STAT_C_RESET; srcptr = tmpbuf; srclen = 4; @@ -755,7 +756,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): reg = ehci_readl(status_reg); reg &= ~EHCI_PS_CLEAR; - switch(le16_to_cpu(req->value)) + switch(swpw(req->value)) { case USB_PORT_FEAT_ENABLE: reg |= EHCI_PS_PE; @@ -772,10 +773,10 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu if((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS && !ehci_is_TDI() && EHCI_PS_IS_LOWSPEED(reg)) { /* Low speed device, give up ownership. */ - debug("port %d low speed --> companion\r\n", le16_to_cpu(req->index)); + debug("port %d low speed --> companion\r\n", swpw(req->index)); reg |= EHCI_PS_PO; ehci_writel(status_reg, reg); - companion |= (1 << le16_to_cpu(req->index)); + companion |= (1 << swpw(req->index)); break; } else @@ -787,12 +788,12 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu * caller must wait, then call GetPortStatus * usb 2.0 specification say 50 ms resets on root */ - wait_ms(50); - portreset |= (1 << le16_to_cpu(req->index)); + wait(50 * 1000); + portreset |= (1 << swpw(req->index)); } break; default: - debug("unknown feature %x\r\n", le16_to_cpu(req->value)); + debug("unknown feature %x\r\n", swpw(req->value)); goto unknown; } /* unblock posted writes */ @@ -800,7 +801,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu break; case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): reg = ehci_readl(status_reg); - switch(le16_to_cpu(req->value)) + switch(swpw(req->value)) { case USB_PORT_FEAT_ENABLE: reg &= ~EHCI_PS_PE; @@ -818,10 +819,10 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; break; case USB_PORT_FEAT_C_RESET: - portreset &= ~(1 << le16_to_cpu(req->index)); + portreset &= ~(1 << swpw(req->index)); break; default: - debug("unknown feature %x\r\n", le16_to_cpu(req->value)); + debug("unknown feature %x\r\n", swpw(req->value)); goto unknown; } ehci_writel(status_reg, reg); @@ -832,8 +833,8 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu debug("Unknown request\r\n"); goto unknown; } - wait_ms(1); - len = min3(srclen, le16_to_cpu(req->length), length); + wait(1 * 1000); + len = min3(srclen, swpw(req->length), length); if(srcptr != NULL && len > 0) memcpy(buffer, srcptr, len); else @@ -843,7 +844,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *bu return 0; unknown: debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\r\n", - req->requesttype, req->request, le16_to_cpu(req->value), le16_to_cpu(req->index), le16_to_cpu(req->length)); + req->requesttype, req->request, swpw(req->value), swpw(req->index), swpw(req->length)); dev->act_len = 0; dev->status = USB_ST_STALLED; return -1; @@ -1056,12 +1057,12 @@ int ehci_usb_lowlevel_init(long handle, const struct pci_device_id *ent, void ** return(-1); } /* Set head of reclaim list */ - gehci.qh_list->qh_link = cpu_to_hc32(((uint32_t)gehci.qh_list - gehci.dma_offset) | QH_LINK_TYPE_QH); - gehci.qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12)); - gehci.qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE); - gehci.qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - gehci.qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - gehci.qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40); + gehci.qh_list->qh_link = swpl(((uint32_t)gehci.qh_list - gehci.dma_offset) | QH_LINK_TYPE_QH); + gehci.qh_list->qh_endpt1 = swpl((1 << 15) | (USB_SPEED_HIGH << 12)); + gehci.qh_list->qh_curtd = swpl(QT_NEXT_TERMINATE); + gehci.qh_list->qh_overlay.qt_next = swpl(QT_NEXT_TERMINATE); + gehci.qh_list->qh_overlay.qt_altnext = swpl(QT_NEXT_TERMINATE); + gehci.qh_list->qh_overlay.qt_token = swpl(0x40); /* Set async. queue head pointer. */ ehci_writel(&gehci.hcor->or_asynclistaddr, (uint32_t)gehci.qh_list - gehci.dma_offset); reg = ehci_readl(&gehci.hccr->cr_hcsparams); @@ -1086,7 +1087,7 @@ int ehci_usb_lowlevel_init(long handle, const struct pci_device_id *ent, void ** ehci_writel(&gehci.hcor->or_configflag, FLAG_CF); /* unblock posted write */ cmd = ehci_readl(&gehci.hcor->or_usbcmd); - wait_ms(5); + wait(5 * 1000); reg = HC_VERSION(ehci_readl(&gehci.hccr->cr_capbase)); info("USB EHCI %x.%02x", reg >> 8, reg & 0xff); #ifndef CONFIG_USB_INTERRUPT_POLLING diff --git a/sources/ohci-hcd.c b/sources/ohci-hcd.c index 94149de..44d452c 100644 --- a/sources/ohci-hcd.c +++ b/sources/ohci-hcd.c @@ -45,7 +45,10 @@ #include "usb.h" #include "ohci.h" -#include "util.h" /* for endian conversions */ +#include "util.h" /* for endian conversions */ +#include "wait.h" /* for wait routines */ +#include "bas_printf.h" +#include "bas_string.h" /* for memset() */ //extern xQueueHandle queue_poll_hub; @@ -88,16 +91,13 @@ struct pci_device_id ohci_usb_pci_table[] = { #else #define dbg(format, arg...) do {} while (0) #endif /* DEBUG */ -#define err usb_error_msg +#define err xprintf #ifdef SHOW_INFO #define info(format, arg...) do board_printf("INFO: " format "\r\n", ## arg) #else #define info(format, arg...) do {} while (0) #endif -#define m16_swap(x) cpu_to_le16(x) -#define m32_swap(x) cpu_to_le32(x) - extern void udelay(long usec); /* global ohci_t */ @@ -138,7 +138,7 @@ static void urb_free_priv(urb_priv_t *urb) } } } - usb_free(urb); + /* FIXME: usb_free(urb); */ } /*-------------------------------------------------------------------------*/ @@ -202,7 +202,7 @@ static void ep_print_int_eds(ohci_t *ohci, char *str) board_printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i); while(*ed_p != 0 && j--) { - ed_t *ed = (ed_t *)m32_swap((unsigned long)ed_p); + ed_t *ed = (ed_t *)swpl((unsigned long)ed_p); board_printf(" ed: %4x;", ed->hwINFO); ed_p = &ed->hwNextED; } @@ -484,7 +484,7 @@ static inline int sohci_return_job(ohci_t *ohci, urb_priv_t *urb) static int sohci_get_current_frame_number(ohci_t *ohci, struct usb_device *usb_dev) { - return m16_swap(ohci->hcca->frame_no); + return swpw(ohci->hcca->frame_no); } #endif @@ -648,14 +648,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) ohci->hc_control &= ~OHCI_CTRL_CLE; writel(ohci->hc_control, &ohci->regs->control); } - writel(m32_swap(*((uint32_t *)&ed->hwNextED)), &ohci->regs->ed_controlhead); + writel(swpl(*((uint32_t *)&ed->hwNextED)), &ohci->regs->ed_controlhead); } else ed->ed_prev->hwNextED = ed->hwNextED; if(ohci->ed_controltail == ed) ohci->ed_controltail = ed->ed_prev; else - ((ed_t *)(m32_swap(*((uint32_t *)&ed->hwNextED)) + ohci->dma_offset))->ed_prev = ed->ed_prev; + ((ed_t *)(swpl(*((uint32_t *)&ed->hwNextED)) + ohci->dma_offset))->ed_prev = ed->ed_prev; break; case PIPE_BULK: if(ed->ed_prev == NULL) @@ -665,14 +665,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi) ohci->hc_control &= ~OHCI_CTRL_BLE; writel(ohci->hc_control, &ohci->regs->control); } - writel(m32_swap(*((uint32_t *)&ed->hwNextED)), &ohci->regs->ed_bulkhead); + writel(swpl(*((uint32_t *)&ed->hwNextED)), &ohci->regs->ed_bulkhead); } else ed->ed_prev->hwNextED = ed->hwNextED; if(ohci->ed_bulktail == ed) ohci->ed_bulktail = ed->ed_prev; else - ((ed_t *)(m32_swap(*((uint32_t *)&ed->hwNextED)) + ohci->dma_offset))->ed_prev = ed->ed_prev; + ((ed_t *)(swpl(*((uint32_t *)&ed->hwNextED)) + ohci->dma_offset))->ed_prev = ed->ed_prev; break; case PIPE_INTERRUPT: periodic_unlink(ohci, ed, 0, 1); @@ -711,13 +711,13 @@ static ed_t *ep_add_ed(ohci_t *ohci, struct usb_device *usb_dev, unsigned long p { /* dummy td; end of td list for ed */ td = td_alloc(usb_dev); - ed->hwTailP = m32_swap((unsigned long)td - ohci->dma_offset); + ed->hwTailP = swpl((unsigned long)td - ohci->dma_offset); ed->hwHeadP = ed->hwTailP; ed->state = ED_UNLINK; ed->type = usb_pipetype(pipe); ohci_dev->ed_cnt++; } - ed->hwINFO = m32_swap(usb_pipedevice(pipe) + ed->hwINFO = swpl(usb_pipedevice(pipe) | usb_pipeendpoint(pipe) << 7 | (usb_pipeisoc(pipe)? 0x8000: 0) | (usb_pipecontrol(pipe)? 0: (usb_pipeout(pipe)? 0x800: 0x1000)) @@ -753,7 +753,7 @@ static void td_fill(ohci_t *ohci, unsigned int info, void *data, int len, td_pt = urb_priv->td[index]; td_pt->hwNextTD = 0; /* fill the old dummy TD */ - td = urb_priv->td[index] = (td_t *)((m32_swap(urb_priv->ed->hwTailP) & ~0xf) + ohci->dma_offset); + td = urb_priv->td[index] = (td_t *)((swpl(urb_priv->ed->hwTailP) & ~0xf) + ohci->dma_offset); td->ed = urb_priv->ed; td->next_dl_td = NULL; td->index = index; @@ -768,18 +768,18 @@ static void td_fill(ohci_t *ohci, unsigned int info, void *data, int len, #endif if(!len) data = NULL; - td->hwINFO = m32_swap(info); + td->hwINFO = swpl(info); if(data != NULL) { - td->hwCBP = m32_swap((unsigned long)data - ohci->dma_offset); - td->hwBE = m32_swap((unsigned long)(data + len - 1 - ohci->dma_offset)); + td->hwCBP = swpl((unsigned long)data - ohci->dma_offset); + td->hwBE = swpl((unsigned long)(data + len - 1 - ohci->dma_offset)); } else { td->hwCBP = 0; td->hwBE = 0; } - td->hwNextTD = m32_swap((unsigned long)td_pt - ohci->dma_offset); + td->hwNextTD = swpl((unsigned long)td_pt - ohci->dma_offset); /* append to queue */ td->ed->hwTailP = td->hwNextTD; #if 0 @@ -787,14 +787,14 @@ static void td_fill(ohci_t *ohci, unsigned int info, void *data, int len, { int i; board_printf("td_fill: %08x %08x %08X %08X at 0x%08X\r\n", - m32_swap(td->hwINFO), m32_swap(td->hwCBP), m32_swap(td->hwNextTD), m32_swap(td->hwBE), td); + swpl(td->hwINFO), swpl(td->hwCBP), swpl(td->hwNextTD), swpl(td->hwBE), td); for(i = 0; i < len; i++) board_printf("%02X ", *(unsigned char *)(data + i) & 0xff); board_printf("\r\n"); } else board_printf("td_fill: %08x %08x %08X %08X at 0x%08X\r\n", - m32_swap(td->hwINFO), m32_swap(td->hwCBP), m32_swap(td->hwNextTD), m32_swap(td->hwBE), td); + swpl(td->hwINFO), swpl(td->hwCBP), swpl(td->hwNextTD), swpl(td->hwBE), td); #endif } @@ -875,9 +875,9 @@ static void dl_transfer_length(ohci_t *ohci, td_t *td) { uint32_t tdINFO, tdBE, tdCBP; urb_priv_t *lurb_priv = td->ed->purb; - tdINFO = m32_swap(td->hwINFO); - tdBE = m32_swap(td->hwBE); - tdCBP = m32_swap(td->hwCBP); + tdINFO = swpl(td->hwINFO); + tdBE = swpl(td->hwBE); + tdCBP = swpl(td->hwCBP); if(tdBE) tdBE += ohci->dma_offset; if(tdCBP) @@ -900,19 +900,19 @@ static void check_status(ohci_t *ohci, td_t *td_list) urb_priv_t *lurb_priv = td_list->ed->purb; int urb_len = lurb_priv->length; uint32_t *phwHeadP = &td_list->ed->hwHeadP; - int cc = TD_CC_GET(m32_swap(td_list->hwINFO)); + int cc = TD_CC_GET(swpl(td_list->hwINFO)); if(cc) { err("OHCI usb-%s-%c error: %s (%x)", ohci->slot_name, (char)ohci->controller + '0', cc_to_string[cc], cc); - if(*phwHeadP & m32_swap(0x1)) + if(*phwHeadP & swpl(0x1)) { if(lurb_priv && ((td_list->index + 1) < urb_len)) { - *phwHeadP = (lurb_priv->td[urb_len - 1]->hwNextTD & m32_swap(0xfffffff0)) | (*phwHeadP & m32_swap(0x2)); + *phwHeadP = (lurb_priv->td[urb_len - 1]->hwNextTD & swpl(0xfffffff0)) | (*phwHeadP & swpl(0x2)); lurb_priv->td_cnt += urb_len - td_list->index - 1; } else - *phwHeadP &= m32_swap(0xfffffff2); + *phwHeadP &= swpl(0xfffffff2); } #ifdef CONFIG_MPC5200 td_list->hwNextTD = 0; @@ -927,7 +927,7 @@ static td_t *dl_reverse_done_list(ohci_t *ohci) uint32_t td_list_hc; td_t *td_rev = NULL; td_t *td_list = NULL; - td_list_hc = m32_swap(ohci->hcca->done_head) & ~0xf; + td_list_hc = swpl(ohci->hcca->done_head) & ~0xf; if(td_list_hc) td_list_hc += ohci->dma_offset; ohci->hcca->done_head = 0; @@ -937,7 +937,7 @@ static td_t *dl_reverse_done_list(ohci_t *ohci) check_status(ohci, td_list); td_list->next_dl_td = td_rev; td_rev = td_list; - td_list_hc = m32_swap(td_list->hwNextTD) & ~0xf; + td_list_hc = swpl(td_list->hwNextTD) & ~0xf; if(td_list_hc) td_list_hc += ohci->dma_offset; } @@ -969,7 +969,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) /* urb_t *urb; */ urb_priv_t *lurb_priv; uint32_t tdINFO, edHeadP, edTailP; - tdINFO = m32_swap(td_list->hwINFO); + tdINFO = swpl(td_list->hwINFO); ed = td_list->ed; if(ed == NULL) { @@ -994,8 +994,8 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) dbg("dl_done_list: processing TD %x, len %x", lurb_priv->td_cnt, lurb_priv->length); if(ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) { - edHeadP = m32_swap(ed->hwHeadP) & ~0xf; - edTailP = m32_swap(ed->hwTailP); + edHeadP = swpl(ed->hwHeadP) & ~0xf; + edTailP = swpl(ed->hwTailP); /* unlink eds if they are not busy */ if((edHeadP == edTailP) && (ed->state == ED_OPER)) ep_unlink(ohci, ed); @@ -1180,7 +1180,7 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, unsigned lon pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif if(usb_pipeint(pipe)) { @@ -1254,7 +1254,7 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, unsigned lon OK(0); case (RH_PORT_POWER): WR_RH_PORTSTAT(RH_PS_PPS); - wait_ms(100); + wait(100 * 1000); OK(0); case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/ if(RD_RH_PORTSTAT & RH_PS_CCS) @@ -1333,7 +1333,7 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, unsigned lon ohci_dump_roothub(ohci, 1); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif len = min_t(int, len, leni); if(data != data_buf) @@ -1344,7 +1344,7 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, unsigned lon pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif return stat; } @@ -1382,7 +1382,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, unsigned long pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif if(!maxsize) { @@ -1395,7 +1395,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, unsigned long return -1; } #if 0 - wait_ms(10); + wait(10 * 1000); /* ohci_dump_status(ohci); */ #endif /* allow more time for a BULK device to react - some are slow */ @@ -1436,7 +1436,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, unsigned long } if(--timeout) { - wait_ms(1); + wait(1 * 1000); // if(!urb->finished) // dbg("*"); } @@ -1455,7 +1455,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, unsigned long pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif /* free TDs in urb_priv */ if(!usb_pipeint(pipe)) @@ -1479,7 +1479,7 @@ int ohci_submit_control_msg(struct usb_device *dev, unsigned long pipe, void *bu pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif if(!maxsize) { @@ -1553,7 +1553,7 @@ static int hc_reset(ohci_t *ohci) err("USB RootHub reset timed out!\r\n"); break; } - udelay(1); + wait(1 * 1000); } } } @@ -1574,12 +1574,12 @@ static int hc_reset(ohci_t *ohci) { dbg("USB OHCI set 48MHz clock\r\n"); pci_write_config_longword(ohci->handle, 0xE4, 0x21); // oscillator & disable ehci - wait_ms(10); + wait(10 * 1000); } else { pci_write_config_longword(ohci->handle, 0xE4, pci_read_config_longword(ohci->handle, 0xE4) | 0x01); // disable ehci - wait_ms(10); + wait(10 * 1000); } } @@ -1590,7 +1590,7 @@ static int hc_reset(ohci_t *ohci) info("USB HC TakeOver from SMM"); while(readl(&ohci->regs->control) & OHCI_CTRL_IR) { - wait_ms(10); + wait(10 * 1000); if(--smm_timeout == 0) { err("USB HC TakeOver failed!"); @@ -1604,7 +1604,7 @@ static int hc_reset(ohci_t *ohci) /* Reset USB (needed by some controllers) */ ohci->hc_control = 0; writel(ohci->hc_control, &ohci->regs->control); - wait_ms(50); + wait(50 * 1000); /* HC Reset requires max 10 us delay */ writel(OHCI_HCR, &ohci->regs->cmdstatus); while((readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) @@ -1614,7 +1614,7 @@ static int hc_reset(ohci_t *ohci) err("USB HC reset timed out!"); return -1; } - udelay(1); + wait(1 * 1000); } return 0; } @@ -1661,7 +1661,7 @@ static int hc_start(ohci_t *ohci) writel(RH_HS_LPSC, &ohci->regs->roothub.status); #endif /* OHCI_USE_NPS */ /* POTPGT delay is bits 24-31, in 2 ms units. */ - wait_ms((ohci->ndp >> 23) & 0x1fe); + wait((ohci->ndp >> 23) & 0x1fe * 1000); ohci->ndp &= RH_A_NDP; /* connect the virtual root hub */ ohci->rh.devnum = 0; @@ -1708,7 +1708,7 @@ static int hc_interrupt(ohci_t *ohci) { struct ohci_regs *regs = ohci->regs; int ints, stat = -1; - if((ohci->hcca->done_head != 0) && !(m32_swap(ohci->hcca->done_head) & 0x01)) + if((ohci->hcca->done_head != 0) && !(swpl(ohci->hcca->done_head) & 0x01)) ints = OHCI_INTR_WDH; else { @@ -1759,7 +1759,7 @@ static int hc_interrupt(ohci_t *ohci) ohci_dump(ohci, 1); #else if(ohci->irq) - wait_ms(1); + wait(1 * 1000); #endif /* HC Reset */ ohci->hc_control = 0; @@ -1769,7 +1769,7 @@ static int hc_interrupt(ohci_t *ohci) if(ints & OHCI_INTR_WDH) { if(ohci->irq) - wait_ms(1); + wait(1 * 1000); writel(OHCI_INTR_WDH, ®s->intrdisable); (void)readl(®s->intrdisable); /* flush */ stat = dl_done_list(ohci); @@ -1785,9 +1785,9 @@ static int hc_interrupt(ohci_t *ohci) /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */ if(ints & OHCI_INTR_SF) { - unsigned int frame = m16_swap(ohci->hcca->frame_no) & 1; + unsigned int frame = swpw(ohci->hcca->frame_no) & 1; if(ohci->irq) - wait_ms(1); + wait(1 * 1000); writel(OHCI_INTR_SF, ®s->intrdisable); if(ohci->ed_rm_list[frame] != NULL) writel(OHCI_INTR_SF, ®s->intrenable); @@ -1846,17 +1846,17 @@ static void hc_free_buffers(ohci_t *ohci) { if(ohci->td_unaligned != NULL) { - usb_free(ohci->td_unaligned); + /* FIXME: usb_free(ohci->td_unaligned); */ ohci->td_unaligned = NULL; } if(ohci->ohci_dev_unaligned != NULL) { - usb_free(ohci->ohci_dev_unaligned); + /* FIXME: usb_free(ohci->ohci_dev_unaligned); */ ohci->ohci_dev_unaligned = NULL; } if(ohci->hcca_unaligned != NULL) { - usb_free(ohci->hcca_unaligned); + /* FIXME: usb_free(ohci->hcca_unaligned); */ ohci->hcca_unaligned = NULL; } } @@ -1963,7 +1963,7 @@ int ohci_usb_lowlevel_init(long handle, const struct pci_device_id *ent, void ** default: ohci->slot_name = "generic"; break; } } - kprint("OHCI usb-%s-%c, regs address 0x%08X, PCI handle 0x%X\r\n", ohci->slot_name, (char)ohci->controller + '0', ohci->regs, handle); + xprintf("OHCI usb-%s-%c, regs address 0x%08X, PCI handle 0x%X\r\n", ohci->slot_name, (char)ohci->controller + '0', ohci->regs, handle); if(hc_reset(ohci) < 0) { err("Can't reset OHCI usb-%s-%c", ohci->slot_name, (char)ohci->controller + '0'); diff --git a/sources/pci.c b/sources/pci.c index 3b6b578..e7a2d2f 100644 --- a/sources/pci.c +++ b/sources/pci.c @@ -59,6 +59,8 @@ static struct pci_class }; static int num_classes = sizeof(pci_classes) / sizeof(struct pci_class); +static struct resource_descriptor resource_descriptors[16]; + static char *device_class(int classcode) { int i; @@ -155,6 +157,13 @@ void pci_write_config_longword(uint16_t handle, uint16_t offset, uint32_t value) * (volatile uint32_t *) PCI_IO_OFFSET = swpl(value); /* access device */ } +struct resource_descriptor *pci_get_resource(uint16_t handle) +{ + /* TODO: implement */ + + return (struct resource_descriptor *) 0L; +} + int pci_find_device(uint16_t device_id, uint16_t vendor_id, int index) { uint16_t bus; diff --git a/sources/usb.c b/sources/usb.c new file mode 100644 index 0000000..aefdd37 --- /dev/null +++ b/sources/usb.c @@ -0,0 +1,1570 @@ +/* + * + * Most of this source has been derived from the Linux USB + * project: + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 (new USB architecture) + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) + * (C) Copyright Yggdrasil Computing, Inc. 2000 + * (usb_device_id matching changes by Adam J. Richter) + * + * Adapted for U-Boot: + * (C) Copyright 2001 Denis Peter, MPL AG Switzerland + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * How it works: + * + * Since this is a bootloader, the devices will not be automatic + * (re)configured on hotplug, but after a restart of the USB the + * device should work. + * + * For each transfer (except "Interrupt") we wait for completion. + */ + +#include +#include "bas_string.h" +#include "bas_printf.h" +#include "util.h" /* for byte swap funcs */ +#include "wait.h" +#include +#include "usb.h" + +extern int usb_stor_curr_dev; +extern unsigned long usb_1st_disk_drive; + +#undef USB_DEBUG + +#ifdef USB_DEBUG +#define USB_PRINTF(fmt, args...) xprintf(fmt , ##args) +#else +#define USB_PRINTF(fmt, args...) +#endif + +#define USB_BUFSIZ 512 + +struct hci { + /* ------- common part -------- */ + long handle; /* PCI BIOS */ + const struct pci_device_id *ent; + int usbnum; + /* ---- end of common part ---- */ +}; + +extern void udelay(long usec); + +static struct usb_device *usb_dev; +static int bus_index; +static int dev_index[USB_MAX_BUS]; +static struct hci *controller_priv[USB_MAX_BUS]; +static int asynch_allowed; +static struct devrequest *setup_packet; + +char usb_started; /* flag for the started/stopped USB status */ + +char usb_error_str[256]; + +typedef struct +{ + int dest; + void (*func)(char); + char *loc; +} PRINTK_INFO; + +#define DEST_CONSOLE (1) +#define DEST_STRING (2) + +/********************************************************************** + * some forward declerations... + */ +void usb_scan_devices(void *priv); + +int usb_hub_probe(struct usb_device *dev, int ifnum); +void usb_hub_reset(int index_bus); +static int hub_port_reset(struct usb_device *dev, int port, unsigned short *portstat); + +extern int printk(PRINTK_INFO *info, const char *fmt, va_list ap); + +/*************************************************************************** + * Init USB Device + */ +int usb_init(long handle, const struct pci_device_id *ent) +{ + void *priv; + int res = 0; + if(bus_index >= USB_MAX_BUS) + return(-1); + dev_index[bus_index] = 0; + asynch_allowed = 1; + if(handle && (ent != NULL)) + { + if(usb_mem_init()) + { + usb_started = 0; + return -1; /* out of memoy */ + } + if(usb_dev == NULL) + usb_dev = (struct usb_device *)usb_malloc(sizeof(struct usb_device) * USB_MAX_BUS * USB_MAX_DEVICE); + if(usb_dev == NULL) + { + usb_started = 0; + return -1; /* out of memoy */ + } + } + else /* restart */ + { + int i; + res = 0; + for(i = 0; i < USB_MAX_BUS; i++) + { + if(controller_priv[i] != NULL) + { + long handle = controller_priv[i]->handle; + if(handle) + res |= usb_init(handle, NULL); + } + } + return res; + } + usb_hub_reset(bus_index); + /* init low_level USB */ + xprintf("USB: "); + switch(ent->class) + { +#ifdef CONFIG_USB_UHCI + case PCI_CLASS_SERIAL_USB_UHCI: + res = uhci_usb_lowlevel_init(handle, ent, &priv); + break; +#endif +#ifdef CONFIG_USB_OHCI + case PCI_CLASS_SERIAL_USB_OHCI: + res = ohci_usb_lowlevel_init(handle, ent, &priv); + break; +#endif +#ifdef CONFIG_USB_EHCI + case PCI_CLASS_SERIAL_USB_EHCI: + res = ehci_usb_lowlevel_init(handle, ent, &priv); + break; +#endif + default: res = -1; break; + } + if(!res) + { + /* if lowlevel init is OK, scan the bus for devices + * i.e. search HUBs and configure them */ + if(setup_packet == NULL) + setup_packet = (void *)usb_malloc(sizeof(struct devrequest)); + if(setup_packet == NULL) + { + usb_started = 0; + return -1; /* out of memoy */ + } + xprintf("Scanning bus for devices... "); + controller_priv[bus_index] = (struct hci *)priv; + controller_priv[bus_index]->usbnum = bus_index; + usb_scan_devices(priv); + bus_index++; + usb_started = 1; + return 0; + } + else + { + xprintf("Error, couldn't init Lowlevel part\r\n"); + usb_started = 0; + return -1; + } +} + +/****************************************************************************** + * Stop USB this stops the LowLevel Part and deregisters USB devices. + */ +int usb_stop(void) +{ + int i, res = 0; + if(usb_started) + { + asynch_allowed = 1; + usb_started = 0; + usb_hub_reset(bus_index); + usb_free(setup_packet); + for(i = 0; i < USB_MAX_BUS; i++) + { + struct hci *priv = controller_priv[i]; + if(priv != NULL) + { + switch(priv->ent->class) + { +#ifdef CONFIG_USB_UHCI + case PCI_CLASS_SERIAL_USB_UHCI: + res |= uhci_usb_lowlevel_stop(priv); + break; +#endif +#ifdef CONFIG_USB_OHCI + case PCI_CLASS_SERIAL_USB_OHCI: + res |= ohci_usb_lowlevel_stop(priv); + break; +#endif +#ifdef CONFIG_USB_EHCI + case PCI_CLASS_SERIAL_USB_EHCI: + res |= ehci_usb_lowlevel_stop(priv); + break; +#endif + } + } + } + bus_index = 0; + usb_mem_stop(); + } + return res; +} + + +void usb_enable_interrupt(int enable) +{ + ohci_usb_enable_interrupt(enable); + ehci_usb_enable_interrupt(enable); +} + + +/* + * disables the asynch behaviour of the control message. This is used for data + * transfers that uses the exclusiv access to the control and bulk messages. + */ +void usb_disable_asynch(int disable) +{ + asynch_allowed = !disable; +} + +/*------------------------------------------------------------------- + * Message wrappers. + * + */ + +/* + * submits an Interrupt Message + */ +int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval) +{ + struct hci *priv = (struct hci *)dev->priv_hcd; + switch(priv->ent->class) + { + case PCI_CLASS_SERIAL_USB_OHCI: + return ohci_submit_int_msg(dev, pipe, buffer, transfer_len, interval); + case PCI_CLASS_SERIAL_USB_EHCI: + return ehci_submit_int_msg(dev, pipe, buffer, transfer_len, interval); + default: + return -1; + } +} + +/* + * submits a control message and waits for comletion (at least timeout * 1ms) + * If timeout is 0, we don't wait for completion (used as example to set and + * clear keyboards LEDs). For data transfers, (storage transfers) we don't + * allow control messages with 0 timeout, by previousely resetting the flag + * asynch_allowed (usb_disable_asynch(1)). + * returns the transfered length if OK or -1 if error. The transfered length + * and the current status are stored in the dev->act_len and dev->status. + */ +int usb_control_msg(struct usb_device *dev, unsigned int pipe, + unsigned char request, unsigned char requesttype, + unsigned short value, unsigned short index, + void *data, unsigned short size, int timeout) +{ + struct hci *priv = (struct hci *)dev->priv_hcd; + if((timeout == 0) && (!asynch_allowed)) + { + /* request for a asynch control pipe is not allowed */ + return -1; + } + /* set setup command */ + setup_packet->requesttype = requesttype; + setup_packet->request = request; + setup_packet->value = swpw(value); + setup_packet->index = swpw(index); + setup_packet->length = swpw(size); + USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, value 0x%X index 0x%X length 0x%X\r\n", request, requesttype, value, index, size); + switch(priv->ent->class) + { + case PCI_CLASS_SERIAL_USB_OHCI: + dev->status = USB_ST_NOT_PROC; /* not yet processed */ + ohci_submit_control_msg(dev, pipe, data, size, setup_packet); + break; + case PCI_CLASS_SERIAL_USB_EHCI: + dev->status = USB_ST_NOT_PROC; /* not yet processed */ + ehci_submit_control_msg(dev, pipe, data, size, setup_packet); + break; + default: + return -1; + } + if(timeout == 0) + return (int)size; + if(dev->status != 0) + { + /* + * Let's wait a while for the timeout to elapse. + * It has no real use, but it keeps the interface happy. + */ + wait(timeout * 1000); + return -1; + } + return dev->act_len; +} + +/*------------------------------------------------------------------- + * submits bulk message, and waits for completion. returns 0 if Ok or + * -1 if Error. + * synchronous behavior + */ +int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) +{ + struct hci *priv = (struct hci *)dev->priv_hcd; + if(len < 0) + return -1; + switch(priv->ent->class) + { + case PCI_CLASS_SERIAL_USB_OHCI: + dev->status = USB_ST_NOT_PROC; /* not yet processed */ + ohci_submit_bulk_msg(dev, pipe, data, len); + break; + case PCI_CLASS_SERIAL_USB_EHCI: + dev->status = USB_ST_NOT_PROC; /* not yet processed */ + ehci_submit_bulk_msg(dev, pipe, data, len); + break; + default: + return -1; + } + while(timeout--) + { + if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC)) + break; + wait(1 * 1000); + } + *actual_length = dev->act_len; + if(dev->status == 0) + return 0; + else + return -1; +} + + +/*------------------------------------------------------------------- + * Max Packet stuff + */ + +/* + * returns the max packet size, depending on the pipe direction and + * the configurations values + */ +int usb_maxpacket(struct usb_device *dev, unsigned long pipe) +{ + /* direction is out -> use emaxpacket out */ + if((pipe & USB_DIR_IN) == 0) + return dev->epmaxpacketout[((pipe>>15) & 0xf)]; + else + return dev->epmaxpacketin[((pipe>>15) & 0xf)]; +} + +/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine + * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine + * when it is inlined in 1 single routine. What happens is that the register r3 + * is used as loop-count 'i', but gets overwritten later on. + * This is clearly a compiler bug, but it is easier to workaround it here than + * to update the compiler (Occurs with at least several GCC 4.{1,2},x + * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM) + */ +static void __attribute__((noinline))usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep) +{ + int b; + b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) + { + /* Control => bidirectional */ + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + dev->epmaxpacketin[b] = ep->wMaxPacketSize; + USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\r\n", b, dev->epmaxpacketin[b]); + } + else + { + if((ep->bEndpointAddress & 0x80) == 0) + { + /* OUT Endpoint */ + if(ep->wMaxPacketSize > dev->epmaxpacketout[b]) + { + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketout[%d] = %d\r\n", b, dev->epmaxpacketout[b]); + } + } + else + { + /* IN Endpoint */ + if(ep->wMaxPacketSize > dev->epmaxpacketin[b]) + { + dev->epmaxpacketin[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketin[%d] = %d\r\n", b, dev->epmaxpacketin[b]); + } + } /* if out */ + } /* if control */ +} + +/* + * set the max packed value of all endpoints in the given configuration + */ +int usb_set_maxpacket(struct usb_device *dev) +{ + int i, ii; + for(i = 0; i < dev->config.bNumInterfaces; i++) + for(ii = 0; ii < dev->config.if_desc[i].bNumEndpoints; ii++) + usb_set_maxpacket_ep(dev,&dev->config.if_desc[i].ep_desc[ii]); + return 0; +} + +/******************************************************************************* + * Parse the config, located in buffer, and fills the dev->config structure. + * Note that all little/big endian swapping are done automatically. + */ +int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) +{ + struct usb_descriptor_header *head; + int index, ifno, epno, curr_if_num; + int i; + unsigned char *ch; + ifno = -1; + epno = -1; + curr_if_num = -1; + dev->configno = cfgno; + head = (struct usb_descriptor_header *)&buffer[0]; + if(head->bDescriptorType != USB_DT_CONFIG) + { + xprintf(" ERROR: NOT USB_CONFIG_DESC %x\r\n", head->bDescriptorType); + return -1; + } + memcpy(&dev->config, buffer, buffer[0]); + swpw(&(dev->config.wTotalLength)); + dev->config.no_of_if = 0; + index = dev->config.bLength; + /* Ok the first entry must be a configuration entry, + * now process the others */ + head = (struct usb_descriptor_header *) &buffer[index]; + while(index + 1 < dev->config.wTotalLength) + { + switch (head->bDescriptorType) + { + case USB_DT_INTERFACE: + if(((struct usb_interface_descriptor *)&buffer[index])->bInterfaceNumber != curr_if_num) + { + /* this is a new interface, copy new desc */ + ifno = dev->config.no_of_if; + dev->config.no_of_if++; + memcpy(&dev->config.if_desc[ifno], &buffer[index], buffer[index]); + dev->config.if_desc[ifno].no_of_ep = 0; + dev->config.if_desc[ifno].num_altsetting = 1; + curr_if_num = dev->config.if_desc[ifno].bInterfaceNumber; + } + else + { + /* found alternate setting for the interface */ + dev->config.if_desc[ifno].num_altsetting++; + } + break; + case USB_DT_ENDPOINT: + epno = dev->config.if_desc[ifno].no_of_ep; + /* found an endpoint */ + dev->config.if_desc[ifno].no_of_ep++; + memcpy(&dev->config.if_desc[ifno].ep_desc[epno], &buffer[index], buffer[index]); + swpw(&(dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize)); + USB_PRINTF("if %d, ep %d\r\n", ifno, epno); + break; + default: + if(head->bLength == 0) + return 1; + USB_PRINTF("unknown Description Type : %x\r\n", head->bDescriptorType); + { + ch = (unsigned char *)head; + for (i = 0; i < head->bLength; i++) + USB_PRINTF(" %02X", *ch++); + USB_PRINTF("\r\n"); + } + break; + } + index += head->bLength; + head = (struct usb_descriptor_header *)&buffer[index]; + } + return 1; +} + +/*********************************************************************** + * Clears an endpoint + * endp: endpoint number in bits 0-3; + * direction flag in bit 7 (1 = IN, 0 = OUT) + */ +int usb_clear_halt(struct usb_device *dev, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3); + /* don't clear if failed */ + if(result < 0) + return result; + /* + * NOTE: we do not get status and verify reset was successful + * as some devices are reported to lock up upon this check.. + */ + usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + /* toggle is reset on clear */ + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + return 0; +} + +/********************************************************************** + * get_descriptor type + */ +int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) +{ + int res; + res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, USB_CNTL_TIMEOUT); + return res; +} + +/********************************************************************** + * gets configuration cfgno and store it in the buffer + */ +int usb_get_configuration_no(struct usb_device *dev, unsigned char *buffer, int cfgno) +{ + int result; + unsigned int tmp; + struct usb_config_descriptor *config; + config = (struct usb_config_descriptor *)&buffer[0]; + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9); + if(result < 9) + { + if(result < 0) + xprintf("unable to get descriptor, error %lX\r\n", dev->status); + else + xprintf("config descriptor too short (expected %i, got %i)\n", 9, result); + return -1; + } + tmp = swpw(config->wTotalLength); + if(tmp > USB_BUFSIZ) + { + USB_PRINTF("usb_get_configuration_no: failed to get descriptor - too long: %d\r\n", tmp); + return -1; + } + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp); + USB_PRINTF("get_conf_no %d Result %d, wLength %d\r\n", cfgno, result, tmp); + return result; +} + +/******************************************************************** + * set address of a device to the value in dev->devnum. + * This can only be done by addressing the device via the default address (0) + */ +int usb_set_address(struct usb_device *dev) +{ + int res; + USB_PRINTF("set address %d\r\n", dev->devnum); + res = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, 0, (dev->devnum), 0, NULL, 0, USB_CNTL_TIMEOUT); + return res; +} + +/******************************************************************** + * set interface number to interface + */ +int usb_set_interface(struct usb_device *dev, int interface, int alternate) +{ + struct usb_interface_descriptor *if_face = NULL; + int ret, i; + for(i = 0; i < dev->config.bNumInterfaces; i++) + { + if(dev->config.if_desc[i].bInterfaceNumber == interface) + { + if_face = &dev->config.if_desc[i]; + break; + } + } + if(!if_face) + { + xprintf("selecting invalid interface %d", interface); + return -1; + } + /* + * We should return now for devices with only one alternate setting. + * According to 9.4.10 of the Universal Serial Bus Specification + * Revision 2.0 such devices can return with a STALL. This results in + * some USB sticks timeouting during initialization and then being + * unusable in U-Boot. + */ + if(if_face->num_altsetting == 1) + return 0; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate, interface, NULL, 0, USB_CNTL_TIMEOUT * 5); + if(ret < 0) + return ret; + return 0; +} + +/******************************************************************** + * set configuration number to configuration + */ +int usb_set_configuration(struct usb_device *dev, int configuration) +{ + int res; + USB_PRINTF("set configuration %d\r\n", configuration); + /* set setup command */ + res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, USB_CNTL_TIMEOUT); + if(res == 0) + { + dev->toggle[0] = 0; + dev->toggle[1] = 0; + return 0; + } + else + return -1; +} + +/******************************************************************** + * set protocol to protocol + */ +int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * set idle + */ +int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * get report + */ +int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * get class descriptor + */ +int usb_get_class_descriptor(struct usb_device *dev, int ifnum, + unsigned char type, unsigned char id, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, + (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * get string index in buffer + */ +int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) +{ + int i; + int result; + for(i = 0; i < 3; ++i) + { + /* some devices are flaky */ + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_STRING << 8) + index, langid, buf, size, USB_CNTL_TIMEOUT); + if(result > 0) + break; + } + return result; +} + +static void usb_try_string_workarounds(unsigned char *buf, int *length) +{ + int newlength, oldlength = *length; + for(newlength = 2; newlength + 1 < oldlength; newlength += 2) + { + char c = buf[newlength]; + if((c < ' ') || (c >= 127) || buf[newlength + 1]) + break; + } + if(newlength > 2) + { + buf[0] = newlength; + *length = newlength; + } +} + +static int usb_string_sub(struct usb_device *dev, unsigned int langid, unsigned int index, unsigned char *buf) +{ + int rc; + /* Try to read the string descriptor by asking for the maximum + * possible number of bytes */ + rc = usb_get_string(dev, langid, index, buf, 255); + /* If that failed try to read the descriptor length, then + * ask for just that many bytes */ + if(rc < 2) + { + rc = usb_get_string(dev, langid, index, buf, 2); + if(rc == 2) + rc = usb_get_string(dev, langid, index, buf, buf[0]); + } + if(rc >= 2) + { + if (!buf[0] && !buf[1]) + usb_try_string_workarounds(buf, &rc); + /* There might be extra junk at the end of the descriptor */ + if (buf[0] < rc) + rc = buf[0]; + rc = rc - (rc & 1); /* force a multiple of two */ + } + if(rc < 2) + rc = -1; + return rc; +} + +/******************************************************************** + * usb_string: + * Get string index and translate it to ascii. + * returns string length (> 0) or error (< 0) + */ +int usb_string(struct usb_device *dev, int index, char *buf, size_t size) +{ + unsigned char *tbuf; + int err; + unsigned int u, idx; + if(size <= 0 || !buf || !index) + return -1; + buf[0] = 0; + tbuf = (unsigned char *)usb_malloc(USB_BUFSIZ); + if(tbuf == NULL) + { + USB_PRINTF("usb_string: malloc failure\r\n"); + return -1; + } + /* get langid for strings if it's not yet known */ + if(!dev->have_langid) + { + err = usb_string_sub(dev, 0, 0, tbuf); + if(err < 0) + { + USB_PRINTF("error getting string descriptor 0 (error=%lx)\r\n", dev->status); + usb_free(tbuf); + return -1; + } + else if(tbuf[0] < 4) + { + USB_PRINTF("string descriptor 0 too short\r\n"); + usb_free(tbuf); + return -1; + } + else + { + dev->have_langid = -1; + dev->string_langid = tbuf[2] | (tbuf[3] << 8); + /* always use the first langid listed */ + USB_PRINTF("USB device number %d default language ID 0x%x\r\n", dev->devnum, dev->string_langid); + } + } + err = usb_string_sub(dev, dev->string_langid, index, tbuf); + if(err < 0) + { + usb_free(tbuf); + return err; + } + size--; /* leave room for trailing NULL char in output buffer */ + for(idx = 0, u = 2; u < err; u += 2) + { + if(idx >= size) + break; + if(tbuf[u+1]) /* high byte */ + buf[idx++] = '?'; /* non-ASCII character */ + else + buf[idx++] = tbuf[u]; + } + buf[idx] = 0; + err = idx; + usb_free(tbuf); + return err; +} + +/******************************************************************** + * USB device handling: + * the USB device are static allocated [USB_MAX_DEVICE]. + */ + +/* + * Something got disconnected. Get rid of it, and all of its children. + */ +void usb_disconnect(struct usb_device **pdev) +{ + struct usb_device *dev = *pdev; + if(dev != NULL) + { + int i; + USB_PRINTF("USB %d disconnect on device %d\r\n", dev->parent->usbnum, dev->parent->devnum); + USB_PRINTF("USB %d disconnected, device number %d\r\n", dev->usbnum, dev->devnum); + if(dev->deregister != NULL) + dev->deregister(dev); + /* Free up all the children.. */ + for(i = 0; i < USB_MAXCHILDREN; i++) + { + if(dev->children[i] != NULL) + { + USB_PRINTF("USB %d, disconnect children %d\r\n", dev->usbnum, dev->children[i]->devnum); + usb_disconnect(&dev->children[i]); + dev->children[i] = NULL; + } + } + /* Free up the device itself, including its device number */ + if(dev->devnum > 0) + { + dev_index[dev->usbnum]--; + memset(dev, 0, sizeof(struct usb_device)); + dev->devnum = -1; + } + *pdev = NULL; + } +} + +/* returns a pointer to the device with the index [index]. + * if the device is not assigned (dev->devnum==-1) returns NULL + */ +struct usb_device *usb_get_dev_index(int index, int index_bus) +{ + struct usb_device *dev; + if((index_bus >= USB_MAX_BUS) || (index_bus < 0) + || (index >= USB_MAX_DEVICE) || (index < 0)) + return NULL; + dev = &usb_dev[(index_bus * USB_MAX_DEVICE) + index]; + if((controller_priv[index_bus] == NULL) || (dev->devnum == -1)) + return NULL; + return dev; +} + +/* returns a pointer of a new device structure or NULL, if + * no device struct is available + */ +struct usb_device *usb_alloc_new_device(int bus_index, void *priv) +{ + int i, index = dev_index[bus_index]; + struct usb_device *dev; + USB_PRINTF("USB %d new device %d\r\n", bus_index, index); + if(index >= USB_MAX_DEVICE) + { + xprintf("ERROR, too many USB Devices, max=%d\r\n", USB_MAX_DEVICE); + return NULL; + } + /* default Address is 0, real addresses start with 1 */ + dev = &usb_dev[(bus_index * USB_MAX_DEVICE) + index]; + dev->devnum = index + 1; + dev->maxchild = 0; + for(i = 0; i < USB_MAXCHILDREN; dev->children[i++] = NULL); + dev->parent = NULL; + dev->priv_hcd = priv; + dev->usbnum = bus_index; + dev_index[bus_index]++; + return dev; +} + +/* + * By the time we get here, the device has gotten a new device ID + * and is in the default state. We need to identify the thing and + * get the ball rolling.. + * + * Returns 0 for success, != 0 for error. + */ +int usb_new_device(struct usb_device *dev) +{ + int addr, err, tmp; + unsigned char *tmpbuf; +#ifndef CONFIG_LEGACY_USB_INIT_SEQ + struct usb_device_descriptor *desc; + int port = -1; + struct usb_device *parent = dev->parent; + unsigned short portstatus; +#endif + if(dev == NULL) + return 1; + /* We still haven't set the Address yet */ + addr = dev->devnum; + dev->devnum = 0; + tmpbuf = (unsigned char *)usb_malloc(USB_BUFSIZ); + if(tmpbuf == NULL) + { + USB_PRINTF("usb_new_device: malloc failure\r\n"); + return 1; + } +#ifdef CONFIG_LEGACY_USB_INIT_SEQ + /* this is the old and known way of initializing devices, it is + * different than what Windows and Linux are doing. Windows and Linux + * both retrieve 64 bytes while reading the device descriptor + * Several USB stick devices report ERR: CTL_TIMEOUT, caused by an + * invalid header while reading 8 bytes as device descriptor. */ + dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ + dev->maxpacketsize = PACKET_SIZE_8; + dev->epmaxpacketin[0] = 8; + dev->epmaxpacketout[0] = 8; + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); + if(err < 8) + { + xprintf("\r\nUSB device not responding, giving up (status=%lX)\r\n", dev->status); + usb_free(tmpbuf); + return 1; + } +#else + /* This is a Windows scheme of initialization sequence, with double + * reset of the device (Linux uses the same sequence) + * Some equipment is said to work only with such init sequence; this + * patch is based on the work by Alan Stern: + * http://sourceforge.net/mailarchive/forum.php? + * thread_id=5729457&forum_id=5398 + */ + /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is + * only 18 bytes long, this will terminate with a short packet. But if + * the maxpacket size is 8 or 16 the device may be waiting to transmit + * some more, or keeps on retransmitting the 8 byte header. */ + desc = (struct usb_device_descriptor *)tmpbuf; + dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */ + /* Default to 64 byte max packet size */ + dev->maxpacketsize = PACKET_SIZE_64; + dev->epmaxpacketin[0] = 64; + dev->epmaxpacketout[0] = 64; + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); + if(err < 0) + { + USB_PRINTF("usb_new_device: usb_get_descriptor() failed\r\n"); + usb_free(tmpbuf); + return 1; + } + dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0; + /* find the port number we're at */ + if(parent) + { + int j; + for(j = 0; j < parent->maxchild; j++) + { + if(parent->children[j] == dev) + { + port = j; + break; + } + } + if(port < 0) + { + xprintf("usb_new_device: cannot locate device's port.\r\n"); + usb_free(tmpbuf); + return 1; + } + /* reset the port for the second time */ + err = hub_port_reset(dev->parent, port, &portstatus); + if(err < 0) + { + xprintf("\r\nCouldn't reset port %i\r\n", port); + usb_free(tmpbuf); + return 1; + } + } +#endif + dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; + switch (dev->descriptor.bMaxPacketSize0) + { + case 8: dev->maxpacketsize = PACKET_SIZE_8; break; + case 16: dev->maxpacketsize = PACKET_SIZE_16; break; + case 32: dev->maxpacketsize = PACKET_SIZE_32; break; + case 64: dev->maxpacketsize = PACKET_SIZE_64; break; + } + dev->devnum = addr; + err = usb_set_address(dev); /* set address */ + if(err < 0) + { + xprintf("\r\nUSB device not accepting new address (error=%lX)\r\n", dev->status); + usb_free(tmpbuf); + return 1; + } + wait(10 * 1000); /* Let the SET_ADDRESS settle */ + tmp = sizeof(dev->descriptor); + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); + if(err < tmp) + { + if(err < 0) + xprintf("unable to get device descriptor (error=%d)\r\n", err); + else + xprintf("USB device descriptor short read (expected %i, got %i)\r\n", tmp, err); + usb_free(tmpbuf); + return 1; + } + /* correct le values */ + swpw(&dev->descriptor.bcdUSB); + swpw(&dev->descriptor.idVendor); + swpw(&dev->descriptor.idProduct); + swpw(&dev->descriptor.bcdDevice); + /* only support for one config for now */ + usb_get_configuration_no(dev, &tmpbuf[0], 0); + usb_parse_config(dev, &tmpbuf[0], 0); + usb_set_maxpacket(dev); + /* we set the default configuration here */ + if(usb_set_configuration(dev, dev->config.bConfigurationValue)) + { + xprintf("failed to set default configuration len %d, status %lX\r\n", dev->act_len, dev->status); + usb_free(tmpbuf); + return -1; + } + USB_PRINTF("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\r\n", + dev->descriptor.iManufacturer, dev->descriptor.iProduct, + dev->descriptor.iSerialNumber); + memset(dev->mf, 0, sizeof(dev->mf)); + memset(dev->prod, 0, sizeof(dev->prod)); + memset(dev->serial, 0, sizeof(dev->serial)); + if(dev->descriptor.iManufacturer) + usb_string(dev, dev->descriptor.iManufacturer, dev->mf, sizeof(dev->mf)); + if(dev->descriptor.iProduct) + usb_string(dev, dev->descriptor.iProduct, dev->prod, sizeof(dev->prod)); + if(dev->descriptor.iSerialNumber) + usb_string(dev, dev->descriptor.iSerialNumber, dev->serial, sizeof(dev->serial)); + USB_PRINTF("Manufacturer %s\r\n", dev->mf); + USB_PRINTF("Product %s\r\n", dev->prod); + USB_PRINTF("SerialNumber %s\r\n", dev->serial); + /* now prode if the device is a hub */ + usb_hub_probe(dev, 0); + usb_free(tmpbuf); + return 0; +} + +/* build device Tree */ +void usb_scan_devices(void *priv) +{ + int i; + struct usb_device *dev; + /* first make all devices unknown */ + for(i = 0; i < USB_MAX_DEVICE; i++) + { + memset(&usb_dev[(bus_index * USB_MAX_DEVICE) + i], 0, sizeof(struct usb_device)); + usb_dev[(bus_index * USB_MAX_DEVICE) + i].devnum = -1; + } + dev_index[bus_index] = 0; + /* device 0 is always present (root hub, so let it analyze) */ + dev = usb_alloc_new_device(bus_index, priv); + if(usb_new_device(dev)) + { + xprintf("No USB Device found\r\n"); + if(dev != NULL) + dev_index[bus_index]--; + } + else + { + xprintf("%d USB Device(s) found\r\n", dev_index[bus_index]); + } + { + /* insert "driver" if possible */ + if (drv_usb_kbd_init() < 0) + xprintf("No USB keyboard found\r\n"); + else + xprintf("USB HID keyboard driver installed\r\n"); + if(drv_usb_mouse_init() < 0) + xprintf("No USB mouse found\r\n"); + else + xprintf("USB HID mouse driver installed\r\n"); + } + xprintf("Scan end\r\n"); +} + +/**************************************************************************** + * HUB "Driver" + * Probes device for being a hub and configurate it + */ + +#undef USB_HUB_DEBUG + +#ifdef USB_HUB_DEBUG +#define USB_HUB_PRINTF(fmt, args...) xprintf(fmt , ##args) +#else +#define USB_HUB_PRINTF(fmt, args...) +#endif + +static struct usb_hub_device hub_dev[USB_MAX_BUS][USB_MAX_HUB]; +static int usb_hub_index[USB_MAX_BUS]; + +int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT); +} + +int usb_clear_hub_feature(struct usb_device *dev, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, USB_CNTL_TIMEOUT); +} + +int usb_clear_port_feature(struct usb_device *dev, int port, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, USB_CNTL_TIMEOUT); +} + +int usb_set_port_feature(struct usb_device *dev, int port, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, USB_CNTL_TIMEOUT); +} + +int usb_get_hub_status(struct usb_device *dev, void *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); +} + +int usb_get_port_status(struct usb_device *dev, int port, void *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); +} + +static void usb_hub_power_on(struct usb_hub_device *hub) +{ + int i; + struct usb_device *dev; + dev = hub->pusb_dev; + /* Enable power to the ports */ + USB_HUB_PRINTF("enabling power on all ports\r\n"); + for (i = 0; i < dev->maxchild; i++) + { + usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + USB_HUB_PRINTF("port %d returns %lX\r\n", i + 1, dev->status); + wait(hub->desc.bPwrOn2PwrGood * 2 * 1000); + } +} + +void usb_hub_reset(int bus_index) +{ + usb_hub_index[bus_index] = 0; +} + +struct usb_hub_device *usb_hub_allocate(void) +{ + if(usb_hub_index[bus_index] < USB_MAX_HUB) + return &hub_dev[bus_index][usb_hub_index[bus_index]++]; + xprintf("ERROR: USB_MAX_HUB (%d) reached\r\n", USB_MAX_HUB); + return NULL; +} + +#define MAX_TRIES 5 + +static inline char *portspeed(int portstatus) +{ + if(portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) + return "480 Mb/s"; + else if(portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) + return "1.5 Mb/s"; + else + return "12 Mb/s"; +} + +static int hub_port_reset(struct usb_device *dev, int port, unsigned short *portstat) +{ + int tries; + struct usb_port_status portsts; + unsigned short portstatus, portchange; + USB_HUB_PRINTF("hub_port_reset: resetting port %d...\r\n", port + 1); + for(tries = 0; tries < MAX_TRIES; tries++) + { + usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET); +#ifdef USB_POLL_HUB + if(pxCurrentTCB != NULL) + vTaskDelay((200*configTICK_RATE_HZ)/1000); + else +#endif + wait(200 * 1000); + if(usb_get_port_status(dev, port + 1, &portsts) < 0) + { + USB_HUB_PRINTF("get_port_status failed status %lX\r\n", dev->status); + return -1; + } + portstatus = swpw(portsts.wPortStatus); + portchange = swpw(portsts.wPortChange); + USB_HUB_PRINTF("USB %d portstatus %x, change %x, %s\r\n", dev->usbnum, portstatus, portchange, portspeed(portstatus)); + USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d USB_PORT_STAT_ENABLE = %d\r\n", + (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0, (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); + if((portchange & USB_PORT_STAT_C_CONNECTION) || !(portstatus & USB_PORT_STAT_CONNECTION)) + return -1; + if(portstatus & USB_PORT_STAT_ENABLE) + break; +#ifdef USB_POLL_HUB + if(pxCurrentTCB != NULL) + vTaskDelay((200*configTICK_RATE_HZ)/1000); + else +#endif + wait(200 * 1000); + } + if(tries == MAX_TRIES) + { + USB_HUB_PRINTF("USB %d, cannot enable port %i after %i retries, disabling port.\r\n", dev->usbnum, port + 1, MAX_TRIES); + USB_HUB_PRINTF("Maybe the USB cable is bad?\r\n"); + return -1; + } + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET); + *portstat = portstatus; + return 0; +} + +void usb_hub_port_connect_change(struct usb_device *dev, int port) +{ + struct usb_device *usb; + struct usb_port_status portsts; + unsigned short portstatus, portchange; + /* Check status */ + if(usb_get_port_status(dev, port + 1, &portsts) < 0) + { + USB_HUB_PRINTF("USB %d get_port_status failed\r\n", dev->usbnum); + return; + } + portstatus = swpw(portsts.wPortStatus); + portchange = swpw(portsts.wPortChange); + USB_HUB_PRINTF("USB %d, portstatus %x, change %x, %s\r\n", dev->usbnum, portstatus, portchange, portspeed(portstatus)); + /* Clear the connection change status */ + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION); + /* Disconnect any existing devices under this port */ + if(((!(portstatus & USB_PORT_STAT_CONNECTION)) + && (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) + { + USB_HUB_PRINTF("USB %d port %i disconnected\r\n", dev->usbnum, port + 1); + usb_disconnect(&dev->children[port]); + /* Return now if nothing is connected */ + if(!(portstatus & USB_PORT_STAT_CONNECTION)) + return; + } +#ifdef USB_POLL_HUB + if(pxCurrentTCB != NULL) + vTaskDelay((200*configTICK_RATE_HZ)/1000); + else +#endif + wait(200 * 1000); + /* Reset the port */ + if(hub_port_reset(dev, port, &portstatus) < 0) + { + USB_HUB_PRINTF("USB %d cannot reset port %i!?\r\n", dev->usbnum, port + 1); + return; + } +#ifdef USB_POLL_HUB + if(pxCurrentTCB != NULL) + vTaskDelay((200*configTICK_RATE_HZ)/1000); + else +#endif + wait(200 * 1000); + /* Allocate a new device struct for it */ + usb = usb_alloc_new_device(dev->usbnum, dev->priv_hcd); + if(portstatus & USB_PORT_STAT_HIGH_SPEED) + usb->speed = USB_SPEED_HIGH; + else if(portstatus & USB_PORT_STAT_LOW_SPEED) + usb->speed = USB_SPEED_LOW; + else + usb->speed = USB_SPEED_FULL; + dev->children[port] = usb; + usb->parent = dev; + /* Run it through the hoops (find a driver, etc) */ + if(usb_new_device(usb)) + { + /* Woops, disable the port */ + USB_HUB_PRINTF("USB %d hub: disabling port %d\r\n", dev->usbnum, port + 1); + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); + } +#ifdef USB_POLL_HUB + else if(pxCurrentTCB != NULL) + { +#ifdef CONFIG_USB_KEYBOARD + usb_kbd_register(usb); +#endif /* CONFIG_USB_KEYBOARD */ +#ifdef CONFIG_USB_MOUSE + usb_mouse_register(usb); +#endif /* CONFIG_USB_MOUSE */ +#ifdef CONFIG_USB_STORAGE + usb_stor_register(usb); +#endif /* CONFIG_USB_STORAGE */ + } +#endif +} + +static void usb_hub_events(struct usb_device *dev) +{ + int i; + struct usb_hub_device *hub = dev->hub; + if(hub == NULL) + return; + for(i = 0; i < dev->maxchild; i++) + { + struct usb_port_status portsts; + unsigned short portstatus, portchange; + if(usb_get_port_status(dev, i + 1, &portsts) < 0) + { + USB_HUB_PRINTF("get_port_status failed\r\n"); + continue; + } + portstatus = swpw(portsts.wPortStatus); + portchange = swpw(portsts.wPortChange); +// USB_HUB_PRINTF("USB %d Port %d Status %X Change %X\r\n", dev->usbnum, i + 1, portstatus, portchange); + if(portchange & USB_PORT_STAT_C_CONNECTION) + { + USB_HUB_PRINTF("USB %d port %d connection change\r\n", dev->usbnum, i + 1); + usb_hub_port_connect_change(dev, i); + } + if(portchange & USB_PORT_STAT_C_ENABLE) + { + USB_HUB_PRINTF("USB %d port %d enable change, status %x\r\n", dev->usbnum, i + 1, portstatus); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); + /* EM interference sometimes causes bad shielded USB + * devices to be shutdown by the hub, this hack enables + * them again. Works at least with mouse driver */ + if(!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && ((dev->children[i]))) + { + USB_HUB_PRINTF("USB %d already running port %i disabled by hub (EMI?), re-enabling...\r\n", dev->usbnum, i + 1); + usb_hub_port_connect_change(dev, i); + } + } + if(portstatus & USB_PORT_STAT_SUSPEND) + { + USB_HUB_PRINTF("USB %d port %d suspend change\r\n", dev->usbnum, i + 1); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); + } + if(portchange & USB_PORT_STAT_C_OVERCURRENT) + { + USB_HUB_PRINTF("USB %d port %d over-current change\r\n", dev->usbnum, i + 1); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); + usb_hub_power_on(hub); + } + if(portchange & USB_PORT_STAT_C_RESET) + { + USB_HUB_PRINTF("USB %d port %d reset change\r\n", dev->usbnum, i + 1); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); + } + } /* end for i all ports */ +} + +#ifdef USB_POLL_HUB +void usb_poll_hub_task(void *pvParameters) +{ + int index_bus = 0; + portTickType timeout = configTICK_RATE_HZ/10; + if(pvParameters); + while(1) + { + if(xQueueAltReceive(queue_poll_hub, &index_bus, timeout) == pdPASS) + { + if((index_bus >= 0) && (index_bus < USB_MAX_BUS) && (controller_priv[index_bus] != NULL)) + { + USB_HUB_PRINTF("USB %d event change\r\n", index_bus); +#ifdef CONFIG_USB_INTERRUPT_POLLING + *vblsem = 0; +#endif + usb_hub_events(&usb_dev[index_bus * USB_MAX_DEVICE]); +#ifdef CONFIG_USB_INTERRUPT_POLLING + *vblsem = 1; +#endif + } + } + else /* timeout */ + { + int i; +#ifdef CONFIG_USB_INTERRUPT_POLLING + *vblsem = 0; +#endif + for(i = 0; i < USB_MAX_BUS ; i++) + { + if(controller_priv[i] != NULL) + usb_hub_events(&usb_dev[i * USB_MAX_DEVICE]); + } +#ifdef CONFIG_USB_INTERRUPT_POLLING + *vblsem = 1; +#endif + } + timeout = portMAX_DELAY; + } +} +#endif /* USB_POLL_HUB */ + +int usb_hub_configure(struct usb_device *dev) +{ + unsigned char *buffer, *bitmap; + struct usb_hub_descriptor *descriptor; + struct usb_hub_status *hubsts; + int i; + struct usb_hub_device *hub; + /* "allocate" Hub device */ + hub = usb_hub_allocate(); + dev->hub = hub; + if(hub == NULL) + return -1; + hub->pusb_dev = dev; + buffer = (unsigned char *)usb_malloc(USB_BUFSIZ); + if(buffer == NULL) + { + USB_HUB_PRINTF("usb_hub_configure: malloc failure\r\n"); + return -1; + } + /* Get the the hub descriptor */ + if(usb_get_hub_descriptor(dev, buffer, 4) < 0) + { + USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor, giving up %lX\r\n", dev->status); + usb_free(buffer); + return -1; + } + USB_HUB_PRINTF("bLength:%02X bDescriptorType:%02X bNbrPorts:%02X\r\n", buffer[0], buffer[1], buffer[2]); + descriptor = (struct usb_hub_descriptor *)buffer; + /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ + i = descriptor->bLength; + if(i > USB_BUFSIZ) + { + USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor - too long: %d\r\n", descriptor->bLength); + usb_free(buffer); + return -1; + } + if(usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) + { + USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor 2nd giving up %lX\r\n", dev->status); + usb_free(buffer); + return -1; + } + memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); + /* adjust 16bit values */ + hub->desc.wHubCharacteristics = swpw(descriptor->wHubCharacteristics); + /* set the bitmap */ + bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; + /* devices not removable by default */ + memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); + bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; + memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ + for(i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) + hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; + for(i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) + hub->desc.DeviceRemovable[i] = descriptor->PortPowerCtrlMask[i]; + dev->maxchild = descriptor->bNbrPorts; + USB_HUB_PRINTF("USB %d, %d ports detected\r\n", dev->usbnum, dev->maxchild); + if(dev->maxchild >= 10) + dev->maxchild = 10; + switch(hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) + { + case 0x00: USB_HUB_PRINTF("ganged power switching\r\n"); break; + case 0x01: USB_HUB_PRINTF("individual port power switching\r\n"); break; + case 0x02: + case 0x03: USB_HUB_PRINTF("unknown reserved power switching mode\r\n"); break; + } + if(hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) + { + USB_HUB_PRINTF("part of a compound device\r\n"); + } + else + { + USB_HUB_PRINTF("standalone hub\r\n"); + } + switch(hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) + { + case 0x00: USB_HUB_PRINTF("global over-current protection\r\n"); break; + case 0x08: USB_HUB_PRINTF("individual port over-current protection\r\n"); break; + case 0x10: + case 0x18: USB_HUB_PRINTF("no over-current protection\r\n"); break; + } + USB_HUB_PRINTF("power on to power good time: %dms\r\n", descriptor->bPwrOn2PwrGood * 2); + USB_HUB_PRINTF("hub controller current requirement: %dmA\r\n", descriptor->bHubContrCurrent); + for(i = 0; i < dev->maxchild; i++) + { + USB_HUB_PRINTF("USB %d port %d is%s removable\r\n", dev->usbnum, i + 1, hub->desc.DeviceRemovable[(i + 1) / 8] & (1 << ((i + 1) % 8)) ? " not" : ""); + } + if(sizeof(struct usb_hub_status) > USB_BUFSIZ) + { + USB_HUB_PRINTF("usb_hub_configure: failed to get Status - too long: %d\r\n", descriptor->bLength); + usb_free(buffer); + return -1; + } + if(usb_get_hub_status(dev, buffer) < 0) + { + USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\r\n", dev->status); + usb_free(buffer); + return -1; + } + hubsts = (struct usb_hub_status *)buffer; + USB_HUB_PRINTF("get_hub_status returned status %X, change %X\r\n", swpw(hubsts->wHubStatus), swpw(hubsts->wHubChange)); + USB_HUB_PRINTF("local power source is %s\r\n", (swpw(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); + USB_HUB_PRINTF("%sover-current condition exists\r\n", (swpw(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no "); + usb_hub_power_on(hub); +#ifdef USB_POLL_HUB + if((queue_poll_hub == NULL) && (pxCurrentTCB != NULL)) + { + queue_poll_hub = xQueueCreate(64, sizeof(int)); + if(queue_poll_hub != NULL) + { + /* Create poll/event task */ + if(xTaskCreate(usb_poll_hub_task, (void *)"USBHub", configMINIMAL_STACK_SIZE, NULL, 16, NULL) != pdPASS) + { + vQueueDelete(queue_poll_hub); + queue_poll_hub = NULL; + } + } + vTaskDelay(configTICK_RATE_HZ); + } + if(queue_poll_hub == NULL) +#endif + usb_hub_events(dev); + usb_free(buffer); + return 0; +} + +int usb_hub_probe(struct usb_device *dev, int ifnum) +{ + struct usb_interface_descriptor *iface; + struct usb_endpoint_descriptor *ep; + int ret; + iface = &dev->config.if_desc[ifnum]; + /* Is it a hub? */ + if(iface->bInterfaceClass != USB_CLASS_HUB) + return 0; + /* Some hubs have a subclass of 1, which AFAICT according to the */ + /* specs is not defined, but it works */ + if((iface->bInterfaceSubClass != 0) && (iface->bInterfaceSubClass != 1)) + return 0; + /* Multiple endpoints? What kind of mutant ninja-hub is this? */ + if(iface->bNumEndpoints != 1) + return 0; + ep = &iface->ep_desc[0]; + /* Output endpoint? Curiousier and curiousier.. */ + if(!(ep->bEndpointAddress & USB_DIR_IN)) + return 0; + /* If it's not an interrupt endpoint, we'd better punt! */ + if((ep->bmAttributes & 3) != 3) + return 0; + /* We found a hub */ + USB_HUB_PRINTF("USB %d hub found\r\n", dev->usbnum); + ret = usb_hub_configure(dev); + return ret; +} + +