SVN maintenance:
authorHervé Poussineau <hpoussin@reactos.org>
Fri, 20 May 2005 21:53:08 +0000 (21:53 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Fri, 20 May 2005 21:53:08 +0000 (21:53 +0000)
Set svn:eol-style and svn:keywords for files
Set svn:ignore for directories

svn path=/trunk/; revision=15440

59 files changed:
reactos/drivers/usb/cromwell/Makefile
reactos/drivers/usb/cromwell/core/buffer_simple.c
reactos/drivers/usb/cromwell/core/config.c
reactos/drivers/usb/cromwell/core/hcd-pci.c
reactos/drivers/usb/cromwell/core/hcd.c
reactos/drivers/usb/cromwell/core/hcd.h
reactos/drivers/usb/cromwell/core/hub.c
reactos/drivers/usb/cromwell/core/hub.h
reactos/drivers/usb/cromwell/core/makefile
reactos/drivers/usb/cromwell/core/makefile.crom
reactos/drivers/usb/cromwell/core/message.c
reactos/drivers/usb/cromwell/core/urb.c
reactos/drivers/usb/cromwell/core/usb-debug.c
reactos/drivers/usb/cromwell/core/usb.c
reactos/drivers/usb/cromwell/core/usb.h
reactos/drivers/usb/cromwell/core/usbcore.c
reactos/drivers/usb/cromwell/core/usbcore.def
reactos/drivers/usb/cromwell/core/usbcore.rc
reactos/drivers/usb/cromwell/host/makefile
reactos/drivers/usb/cromwell/host/makefile.crom
reactos/drivers/usb/cromwell/host/ohci-dbg.c
reactos/drivers/usb/cromwell/host/ohci-hcd.c
reactos/drivers/usb/cromwell/host/ohci-hub.c
reactos/drivers/usb/cromwell/host/ohci-mem.c
reactos/drivers/usb/cromwell/host/ohci-pci.c
reactos/drivers/usb/cromwell/host/ohci-q.c
reactos/drivers/usb/cromwell/host/ohci.def
reactos/drivers/usb/cromwell/host/ohci.h
reactos/drivers/usb/cromwell/host/ohci.rc
reactos/drivers/usb/cromwell/host/ohci_config.h
reactos/drivers/usb/cromwell/host/ohci_main.c
reactos/drivers/usb/cromwell/host/ohci_main.h
reactos/drivers/usb/cromwell/linux/asm/bitops.h
reactos/drivers/usb/cromwell/linux/bitops.h
reactos/drivers/usb/cromwell/linux/boot.h
reactos/drivers/usb/cromwell/linux/consts.h
reactos/drivers/usb/cromwell/linux/cromwell_types.h
reactos/drivers/usb/cromwell/linux/errno.h
reactos/drivers/usb/cromwell/linux/linux_wrapper.h
reactos/drivers/usb/cromwell/linux/list.h
reactos/drivers/usb/cromwell/linux/pci_hal.c
reactos/drivers/usb/cromwell/linux/pci_ids.h
reactos/drivers/usb/cromwell/linux/usb.h
reactos/drivers/usb/cromwell/linux/usb_ch9.h
reactos/drivers/usb/cromwell/sys/BootUSB.c
reactos/drivers/usb/cromwell/sys/Makefile
reactos/drivers/usb/cromwell/sys/linuxwrapper.c
reactos/drivers/usb/cromwell/sys/risefall.c
reactos/drivers/usb/cromwell/sys/ros_wrapper.c
reactos/drivers/usb/cromwell/sys/usbkey.c
reactos/drivers/usb/cromwell/sys/usbwrapper.c
reactos/drivers/usb/cromwell/sys/xpad.c
reactos/drivers/usb/cromwell/sys/xremote.c
reactos/drivers/usb/cromwell/uhci/makefile
reactos/drivers/usb/cromwell/uhci/uhci.def
reactos/drivers/usb/cromwell/uhci/uhci.rc
reactos/drivers/usb/cromwell/uhci/uhci_config.h
reactos/drivers/usb/cromwell/uhci/uhci_main.c
reactos/drivers/usb/cromwell/usb_wrapper.h

index 1f12473..f2d4bf0 100644 (file)
@@ -1,50 +1,50 @@
-#\r
-# ReactOS USB-Cromwell Drivers\r
-#\r
-\r
-PATH_TO_TOP = ../../..\r
-\r
-include $(PATH_TO_TOP)/rules.mak\r
-\r
-DRIVERS = core host uhci\r
-\r
-all: $(DRIVERS)\r
-\r
-depends: \r
-\r
-implib: $(DRIVERS:%=%_implib)\r
-\r
-clean:         $(DRIVERS:%=%_clean)\r
-\r
-install: $(DRIVERS:%=%_install)\r
-\r
-bootcd: $(DRIVERS:%=%_bootcd)\r
-\r
-.PHONY: all depends implib clean install bootcd\r
-\r
-\r
-#\r
-# USB DRIVERS\r
-#\r
-$(DRIVERS): %:\r
-       $(MAKE) -C $*\r
-\r
-$(DRIVERS:%=%_implib): %_implib:\r
-       $(MAKE) -C $* implib\r
-\r
-$(DRIVERS:%=%_clean): %_clean:\r
-       $(MAKE) -C $* clean\r
-\r
-$(DRIVERS:%=%_install): %_install:\r
-       $(MAKE) -C $* install\r
-\r
-$(DRIVERS:%=%_bootcd): %_bootcd:\r
-       $(MAKE) -C $* bootcd\r
-\r
-.PHONY: $(DRIVERS) $(DRIVERS:%=%_implib) $(DRIVERS:%=%_clean) $(DRIVERS:%=%_install) $(DRIVERS:%=%_bootcd)\r
-\r
-\r
-etags:\r
-       find . -name "*.[ch]" -print | etags --language=c -\r
-\r
-# EOF\r
+#
+# ReactOS USB-Cromwell Drivers
+#
+
+PATH_TO_TOP = ../../..
+
+include $(PATH_TO_TOP)/rules.mak
+
+DRIVERS = core host uhci
+
+all: $(DRIVERS)
+
+depends: 
+
+implib: $(DRIVERS:%=%_implib)
+
+clean:         $(DRIVERS:%=%_clean)
+
+install: $(DRIVERS:%=%_install)
+
+bootcd: $(DRIVERS:%=%_bootcd)
+
+.PHONY: all depends implib clean install bootcd
+
+
+#
+# USB DRIVERS
+#
+$(DRIVERS): %:
+       $(MAKE) -C $*
+
+$(DRIVERS:%=%_implib): %_implib:
+       $(MAKE) -C $* implib
+
+$(DRIVERS:%=%_clean): %_clean:
+       $(MAKE) -C $* clean
+
+$(DRIVERS:%=%_install): %_install:
+       $(MAKE) -C $* install
+
+$(DRIVERS:%=%_bootcd): %_bootcd:
+       $(MAKE) -C $* bootcd
+
+.PHONY: $(DRIVERS) $(DRIVERS:%=%_implib) $(DRIVERS:%=%_clean) $(DRIVERS:%=%_install) $(DRIVERS:%=%_bootcd)
+
+
+etags:
+       find . -name "*.[ch]" -print | etags --language=c -
+
+# EOF
index 7ac70ce..b0c0470 100644 (file)
@@ -1,42 +1,42 @@
-/* \r
- * buffer_simple.c -- replacement for usb/core/buffer.c\r
- *\r
- * (c) Georg Acher, georg@acher.org\r
- *\r
- */\r
-\r
-#include "../usb_wrapper.h"\r
-#define __KERNEL__\r
-#define CONFIG_PCI\r
-#include "hcd.h"\r
-\r
-/*------------------------------------------------------------------------*/ \r
-int hcd_buffer_create (struct usb_hcd *hcd)\r
-{\r
-       return 0;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void hcd_buffer_destroy (struct usb_hcd *hcd)\r
-{\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void *hcd_buffer_alloc (\r
-        struct usb_bus          *bus,\r
-        size_t                  size,\r
-        int                     mem_flags,\r
-        dma_addr_t              *dma\r
-)\r
-{\r
-       return kmalloc(size,0);\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void hcd_buffer_free (\r
-        struct usb_bus          *bus,\r
-        size_t                  size,\r
-        void                    *addr,\r
-        dma_addr_t              dma\r
-)\r
-{\r
-       kfree(addr);\r
-}\r
-\r
+/* 
+ * buffer_simple.c -- replacement for usb/core/buffer.c
+ *
+ * (c) Georg Acher, georg@acher.org
+ *
+ */
+
+#include "../usb_wrapper.h"
+#define __KERNEL__
+#define CONFIG_PCI
+#include "hcd.h"
+
+/*------------------------------------------------------------------------*/ 
+int hcd_buffer_create (struct usb_hcd *hcd)
+{
+       return 0;
+}
+/*------------------------------------------------------------------------*/ 
+void hcd_buffer_destroy (struct usb_hcd *hcd)
+{
+}
+/*------------------------------------------------------------------------*/ 
+void *hcd_buffer_alloc (
+        struct usb_bus          *bus,
+        size_t                  size,
+        int                     mem_flags,
+        dma_addr_t              *dma
+)
+{
+       return kmalloc(size,0);
+}
+/*------------------------------------------------------------------------*/ 
+void hcd_buffer_free (
+        struct usb_bus          *bus,
+        size_t                  size,
+        void                    *addr,
+        dma_addr_t              dma
+)
+{
+       kfree(addr);
+}
+
index 7d400e9..1c40bbd 100644 (file)
-#if 0\r
-#include <linux/usb.h>\r
-#include <linux/module.h>\r
-#include <linux/init.h>\r
-#include <linux/slab.h>\r
-#include <asm/byteorder.h>\r
-#else\r
-#include "../usb_wrapper.h"\r
-#endif\r
-\r
-#define USB_MAXALTSETTING              128     /* Hard limit */\r
-#define USB_MAXENDPOINTS               30      /* Hard limit */\r
-\r
-/* these maximums are arbitrary */\r
-#define USB_MAXCONFIG                  8\r
-#define USB_ALTSETTINGALLOC            4\r
-#define USB_MAXINTERFACES              32\r
-\r
-static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size)\r
-{\r
-       struct usb_descriptor_header *header;\r
-       unsigned char *begin;\r
-       int parsed = 0, len, numskipped;\r
-\r
-       header = (struct usb_descriptor_header *)buffer;\r
-\r
-       /* Everything should be fine being passed into here, but we sanity */\r
-       /*  check JIC */\r
-       if (header->bLength > size) {\r
-               err("ran out of descriptors parsing");\r
-               return -1;\r
-       }\r
-               \r
-       if (header->bDescriptorType != USB_DT_ENDPOINT) {\r
-               warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X",\r
-                       header->bDescriptorType, USB_DT_ENDPOINT);\r
-               return parsed;\r
-       }\r
-\r
-       if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)\r
-               memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);\r
-       else\r
-               memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);\r
-       \r
-       le16_to_cpus(&endpoint->desc.wMaxPacketSize);\r
-\r
-       buffer += header->bLength;\r
-       size -= header->bLength;\r
-       parsed += header->bLength;\r
-\r
-       /* Skip over the rest of the Class Specific or Vendor Specific */\r
-       /*  descriptors */\r
-       begin = buffer;\r
-       numskipped = 0;\r
-       while (size >= sizeof(struct usb_descriptor_header)) {\r
-               header = (struct usb_descriptor_header *)buffer;\r
-\r
-               if (header->bLength < 2) {\r
-                       err("invalid descriptor length of %d", header->bLength);\r
-                       return -1;\r
-               }\r
-\r
-               /* If we find another "proper" descriptor then we're done  */\r
-               if ((header->bDescriptorType == USB_DT_ENDPOINT) ||\r
-                   (header->bDescriptorType == USB_DT_INTERFACE) ||\r
-                   (header->bDescriptorType == USB_DT_CONFIG) ||\r
-                   (header->bDescriptorType == USB_DT_DEVICE))\r
-                       break;\r
-\r
-               dbg("skipping descriptor 0x%X",\r
-                       header->bDescriptorType);\r
-               numskipped++;\r
-\r
-               buffer += header->bLength;\r
-               size -= header->bLength;\r
-               parsed += header->bLength;\r
-       }\r
-       if (numskipped)\r
-               dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);\r
-\r
-       /* Copy any unknown descriptors into a storage area for drivers */\r
-       /*  to later parse */\r
-       len = (int)(buffer - begin);\r
-       if (!len) {\r
-               endpoint->extra = NULL;\r
-               endpoint->extralen = 0;\r
-               return parsed;\r
-       }\r
-\r
-       endpoint->extra = kmalloc(len, GFP_KERNEL);\r
-\r
-       if (!endpoint->extra) {\r
-               err("couldn't allocate memory for endpoint extra descriptors");\r
-               endpoint->extralen = 0;\r
-               return parsed;\r
-       }\r
-\r
-       memcpy(endpoint->extra, begin, len);\r
-       endpoint->extralen = len;\r
-\r
-       return parsed;\r
-}\r
-\r
-static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)\r
-{\r
-       int i, len, numskipped, retval, parsed = 0;\r
-       struct usb_descriptor_header *header;\r
-       struct usb_host_interface *ifp;\r
-       unsigned char *begin;\r
-\r
-       interface->act_altsetting = 0;\r
-       interface->num_altsetting = 0;\r
-       interface->max_altsetting = USB_ALTSETTINGALLOC;\r
-       device_initialize(&interface->dev);\r
-\r
-       interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,\r
-                                       GFP_KERNEL);\r
-       \r
-       if (!interface->altsetting) {\r
-               err("couldn't kmalloc interface->altsetting");\r
-               return -1;\r
-       }\r
-\r
-       while (size > 0) {\r
-               struct usb_interface_descriptor *d;\r
-       \r
-               if (interface->num_altsetting >= interface->max_altsetting) {\r
-                       struct usb_host_interface *ptr;\r
-                       int oldmas;\r
-\r
-                       oldmas = interface->max_altsetting;\r
-                       interface->max_altsetting += USB_ALTSETTINGALLOC;\r
-                       if (interface->max_altsetting > USB_MAXALTSETTING) {\r
-                               warn("too many alternate settings (incr %d max %d)\n",\r
-                                       USB_ALTSETTINGALLOC, USB_MAXALTSETTING);\r
-                               return -1;\r
-                       }\r
-\r
-                       ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL);\r
-                       if (ptr == NULL) {\r
-                               err("couldn't kmalloc interface->altsetting");\r
-                               return -1;\r
-                       }\r
-                       memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas);\r
-                       kfree(interface->altsetting);\r
-                       interface->altsetting = ptr;\r
-               }\r
-\r
-               ifp = interface->altsetting + interface->num_altsetting;\r
-               ifp->endpoint = NULL;\r
-               ifp->extra = NULL;\r
-               ifp->extralen = 0;\r
-               interface->num_altsetting++;\r
-\r
-               memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);\r
-\r
-               /* Skip over the interface */\r
-               buffer += ifp->desc.bLength;\r
-               parsed += ifp->desc.bLength;\r
-               size -= ifp->desc.bLength;\r
-\r
-               begin = buffer;\r
-               numskipped = 0;\r
-\r
-               /* Skip over any interface, class or vendor descriptors */\r
-               while (size >= sizeof(struct usb_descriptor_header)) {\r
-                       header = (struct usb_descriptor_header *)buffer;\r
-\r
-                       if (header->bLength < 2) {\r
-                               err("invalid descriptor length of %d", header->bLength);\r
-                               return -1;\r
-                       }\r
-\r
-                       /* If we find another "proper" descriptor then we're done  */\r
-                       if ((header->bDescriptorType == USB_DT_INTERFACE) ||\r
-                           (header->bDescriptorType == USB_DT_ENDPOINT) ||\r
-                           (header->bDescriptorType == USB_DT_CONFIG) ||\r
-                           (header->bDescriptorType == USB_DT_DEVICE))\r
-                               break;\r
-\r
-                       numskipped++;\r
-\r
-                       buffer += header->bLength;\r
-                       parsed += header->bLength;\r
-                       size -= header->bLength;\r
-               }\r
-\r
-               if (numskipped)\r
-                       dbg("skipped %d class/vendor specific interface descriptors", numskipped);\r
-\r
-               /* Copy any unknown descriptors into a storage area for */\r
-               /*  drivers to later parse */\r
-               len = (int)(buffer - begin);\r
-               if (len) {\r
-                       ifp->extra = kmalloc(len, GFP_KERNEL);\r
-\r
-                       if (!ifp->extra) {\r
-                               err("couldn't allocate memory for interface extra descriptors");\r
-                               ifp->extralen = 0;\r
-                               return -1;\r
-                       }\r
-                       memcpy(ifp->extra, begin, len);\r
-                       ifp->extralen = len;\r
-               }\r
-\r
-               /* Did we hit an unexpected descriptor? */\r
-               header = (struct usb_descriptor_header *)buffer;\r
-               if ((size >= sizeof(struct usb_descriptor_header)) &&\r
-                   ((header->bDescriptorType == USB_DT_CONFIG) ||\r
-                    (header->bDescriptorType == USB_DT_DEVICE)))\r
-                       return parsed;\r
-\r
-               if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {\r
-                       warn("too many endpoints");\r
-                       return -1;\r
-               }\r
-\r
-               ifp->endpoint = (struct usb_host_endpoint *)\r
-                       kmalloc(ifp->desc.bNumEndpoints *\r
-                       sizeof(struct usb_host_endpoint), GFP_KERNEL);\r
-               if (!ifp->endpoint) {\r
-                       err("out of memory");\r
-                       return -1;      \r
-               }\r
-\r
-               memset(ifp->endpoint, 0, ifp->desc.bNumEndpoints *\r
-                       sizeof(struct usb_host_endpoint));\r
-       \r
-               for (i = 0; i < ifp->desc.bNumEndpoints; i++) {\r
-                       header = (struct usb_descriptor_header *)buffer;\r
-\r
-                       if (header->bLength > size) {\r
-                               err("ran out of descriptors parsing");\r
-                               return -1;\r
-                       }\r
-               \r
-                       retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);\r
-                       if (retval < 0)\r
-                               return retval;\r
-\r
-                       buffer += retval;\r
-                       parsed += retval;\r
-                       size -= retval;\r
-               }\r
-\r
-               /* We check to see if it's an alternate to this one */\r
-               d = (struct usb_interface_descriptor *)buffer;\r
-               if (size < USB_DT_INTERFACE_SIZE\r
-                               || d->bDescriptorType != USB_DT_INTERFACE\r
-                               || !d->bAlternateSetting)\r
-                       return parsed;\r
-       }\r
-\r
-       return parsed;\r
-}\r
-\r
-int usb_parse_configuration(struct usb_host_config *config, char *buffer)\r
-{\r
-       int i, retval, size;\r
-       struct usb_descriptor_header *header;\r
-\r
-       memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);\r
-       le16_to_cpus(&config->desc.wTotalLength);\r
-       size = config->desc.wTotalLength;\r
-\r
-       if (config->desc.bNumInterfaces > USB_MAXINTERFACES) {\r
-               warn("too many interfaces");\r
-               return -1;\r
-       }\r
-\r
-       config->interface = (struct usb_interface *)\r
-               kmalloc(config->desc.bNumInterfaces *\r
-               sizeof(struct usb_interface), GFP_KERNEL);\r
-       dbg("kmalloc IF %p, numif %i", config->interface, config->desc.bNumInterfaces);\r
-       if (!config->interface) {\r
-               err("out of memory");\r
-               return -1;      \r
-       }\r
-\r
-       memset(config->interface, 0,\r
-              config->desc.bNumInterfaces * sizeof(struct usb_interface));\r
-\r
-       buffer += config->desc.bLength;\r
-       size -= config->desc.bLength;\r
-       \r
-       config->extra = NULL;\r
-       config->extralen = 0;\r
-\r
-       for (i = 0; i < config->desc.bNumInterfaces; i++) {\r
-               int numskipped, len;\r
-               char *begin;\r
-\r
-               /* Skip over the rest of the Class Specific or Vendor */\r
-               /*  Specific descriptors */\r
-               begin = buffer;\r
-               numskipped = 0;\r
-               while (size >= sizeof(struct usb_descriptor_header)) {\r
-                       header = (struct usb_descriptor_header *)buffer;\r
-\r
-                       if ((header->bLength > size) || (header->bLength < 2)) {\r
-                               err("invalid descriptor length of %d", header->bLength);\r
-                               return -1;\r
-                       }\r
-\r
-                       /* If we find another "proper" descriptor then we're done  */\r
-                       if ((header->bDescriptorType == USB_DT_ENDPOINT) ||\r
-                           (header->bDescriptorType == USB_DT_INTERFACE) ||\r
-                           (header->bDescriptorType == USB_DT_CONFIG) ||\r
-                           (header->bDescriptorType == USB_DT_DEVICE))\r
-                               break;\r
-\r
-                       dbg("skipping descriptor 0x%X", header->bDescriptorType);\r
-                       numskipped++;\r
-\r
-                       buffer += header->bLength;\r
-                       size -= header->bLength;\r
-               }\r
-               if (numskipped)\r
-                       dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);\r
-\r
-               /* Copy any unknown descriptors into a storage area for */\r
-               /*  drivers to later parse */\r
-               len = (int)(buffer - begin);\r
-               if (len) {\r
-                       if (config->extralen) {\r
-                               warn("extra config descriptor");\r
-                       } else {\r
-                               config->extra = kmalloc(len, GFP_KERNEL);\r
-                               if (!config->extra) {\r
-                                       err("couldn't allocate memory for config extra descriptors");\r
-                                       config->extralen = 0;\r
-                                       return -1;\r
-                               }\r
-\r
-                               memcpy(config->extra, begin, len);\r
-                               config->extralen = len;\r
-                       }\r
-               }\r
-\r
-               retval = usb_parse_interface(config->interface + i, buffer, size);\r
-               if (retval < 0)\r
-                       return retval;\r
-\r
-               buffer += retval;\r
-               size -= retval;\r
-       }\r
-\r
-       return size;\r
-}\r
-\r
-// hub-only!! ... and only exported for reset/reinit path.\r
-// otherwise used internally on disconnect/destroy path\r
-void usb_destroy_configuration(struct usb_device *dev)\r
-{\r
-       int c, i, j, k;\r
-       \r
-       if (!dev->config)\r
-               return;\r
-\r
-       if (dev->rawdescriptors) {\r
-               for (i = 0; i < dev->descriptor.bNumConfigurations; i++)\r
-                       kfree(dev->rawdescriptors[i]);\r
-\r
-               kfree(dev->rawdescriptors);\r
-       }\r
-\r
-       for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {\r
-               struct usb_host_config *cf = &dev->config[c];\r
-\r
-               if (!cf->interface)\r
-                       break;\r
-\r
-               for (i = 0; i < cf->desc.bNumInterfaces; i++) {\r
-                       struct usb_interface *ifp =\r
-                               &cf->interface[i];\r
-                               \r
-                       if (!ifp->altsetting)\r
-                               break;\r
-\r
-                       for (j = 0; j < ifp->num_altsetting; j++) {\r
-                               struct usb_host_interface *as =\r
-                                       &ifp->altsetting[j];\r
-                                       \r
-                               if(as->extra) {\r
-                                       kfree(as->extra);\r
-                               }\r
-\r
-                               if (!as->endpoint)\r
-                                       break;\r
-                                       \r
-                               for(k = 0; k < as->desc.bNumEndpoints; k++) {\r
-                                       if(as->endpoint[k].extra) {\r
-                                               kfree(as->endpoint[k].extra);\r
-                                       }\r
-                               }       \r
-                               kfree(as->endpoint);\r
-                       }\r
-\r
-                       kfree(ifp->altsetting);\r
-               }\r
-               kfree(cf->interface);\r
-       }\r
-       kfree(dev->config);\r
-}\r
-\r
-\r
-// hub-only!! ... and only in reset path, or usb_new_device()\r
-// (used by real hubs and virtual root hubs)\r
-int usb_get_configuration(struct usb_device *dev)\r
-{\r
-       int result;\r
-       unsigned int cfgno, length;\r
-       unsigned char *buffer;\r
-       unsigned char *bigbuffer;\r
-       struct usb_config_descriptor *desc;\r
-\r
-       if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {\r
-               warn("too many configurations");\r
-               return -EINVAL;\r
-       }\r
-\r
-       if (dev->descriptor.bNumConfigurations < 1) {\r
-               warn("not enough configurations");\r
-               return -EINVAL;\r
-       }\r
-\r
-       dev->config = (struct usb_host_config *)\r
-               kmalloc(dev->descriptor.bNumConfigurations *\r
-               sizeof(struct usb_host_config), GFP_KERNEL);\r
-       if (!dev->config) {\r
-               err("out of memory");\r
-               return -ENOMEM; \r
-       }\r
-       memset(dev->config, 0, dev->descriptor.bNumConfigurations *\r
-               sizeof(struct usb_host_config));\r
-\r
-       dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *\r
-               dev->descriptor.bNumConfigurations, GFP_KERNEL);\r
-       if (!dev->rawdescriptors) {\r
-               err("out of memory");\r
-               return -ENOMEM;\r
-       }\r
-\r
-       buffer = kmalloc(8, GFP_KERNEL);\r
-       if (!buffer) {\r
-               err("unable to allocate memory for configuration descriptors");\r
-               return -ENOMEM;\r
-       }\r
-       desc = (struct usb_config_descriptor *)buffer;\r
-\r
-       for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {\r
-               /* We grab the first 8 bytes so we know how long the whole */\r
-               /*  configuration is */\r
-               result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);\r
-               if (result < 8) {\r
-                       if (result < 0)\r
-                               err("unable to get descriptor");\r
-                       else {\r
-                               err("config descriptor too short (expected %i, got %i)", 8, result);\r
-                               result = -EINVAL;\r
-                       }\r
-                       goto err;\r
-               }\r
-\r
-               /* Get the full buffer */\r
-               length = le16_to_cpu(desc->wTotalLength);\r
-\r
-               bigbuffer = kmalloc(length, GFP_KERNEL);\r
-               if (!bigbuffer) {\r
-                       err("unable to allocate memory for configuration descriptors");\r
-                       result = -ENOMEM;\r
-                       goto err;\r
-               }\r
-\r
-               /* Now that we know the length, get the whole thing */\r
-               result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);\r
-               if (result < 0) {\r
-                       err("couldn't get all of config descriptors");\r
-                       kfree(bigbuffer);\r
-                       goto err;\r
-               }       \r
-       \r
-               if (result < length) {\r
-                       err("config descriptor too short (expected %i, got %i)", length, result);\r
-                       result = -EINVAL;\r
-                       kfree(bigbuffer);\r
-                       goto err;\r
-               }\r
-\r
-               dev->rawdescriptors[cfgno] = bigbuffer;\r
-\r
-               result = usb_parse_configuration(&dev->config[cfgno], bigbuffer);\r
-               if (result > 0)\r
-                       dbg("descriptor data left");\r
-               else if (result < 0) {\r
-                       result = -EINVAL;\r
-                       goto err;\r
-               }\r
-       }\r
-\r
-       kfree(buffer);\r
-       return 0;\r
-err:\r
-       kfree(buffer);\r
-       dev->descriptor.bNumConfigurations = cfgno;\r
-       return result;\r
-}\r
-\r
+#if 0
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+#else
+#include "../usb_wrapper.h"
+#endif
+
+#define USB_MAXALTSETTING              128     /* Hard limit */
+#define USB_MAXENDPOINTS               30      /* Hard limit */
+
+/* these maximums are arbitrary */
+#define USB_MAXCONFIG                  8
+#define USB_ALTSETTINGALLOC            4
+#define USB_MAXINTERFACES              32
+
+static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size)
+{
+       struct usb_descriptor_header *header;
+       unsigned char *begin;
+       int parsed = 0, len, numskipped;
+
+       header = (struct usb_descriptor_header *)buffer;
+
+       /* Everything should be fine being passed into here, but we sanity */
+       /*  check JIC */
+       if (header->bLength > size) {
+               err("ran out of descriptors parsing");
+               return -1;
+       }
+               
+       if (header->bDescriptorType != USB_DT_ENDPOINT) {
+               warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X",
+                       header->bDescriptorType, USB_DT_ENDPOINT);
+               return parsed;
+       }
+
+       if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
+               memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
+       else
+               memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);
+       
+       le16_to_cpus(&endpoint->desc.wMaxPacketSize);
+
+       buffer += header->bLength;
+       size -= header->bLength;
+       parsed += header->bLength;
+
+       /* Skip over the rest of the Class Specific or Vendor Specific */
+       /*  descriptors */
+       begin = buffer;
+       numskipped = 0;
+       while (size >= sizeof(struct usb_descriptor_header)) {
+               header = (struct usb_descriptor_header *)buffer;
+
+               if (header->bLength < 2) {
+                       err("invalid descriptor length of %d", header->bLength);
+                       return -1;
+               }
+
+               /* If we find another "proper" descriptor then we're done  */
+               if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
+                   (header->bDescriptorType == USB_DT_INTERFACE) ||
+                   (header->bDescriptorType == USB_DT_CONFIG) ||
+                   (header->bDescriptorType == USB_DT_DEVICE))
+                       break;
+
+               dbg("skipping descriptor 0x%X",
+                       header->bDescriptorType);
+               numskipped++;
+
+               buffer += header->bLength;
+               size -= header->bLength;
+               parsed += header->bLength;
+       }
+       if (numskipped)
+               dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
+
+       /* Copy any unknown descriptors into a storage area for drivers */
+       /*  to later parse */
+       len = (int)(buffer - begin);
+       if (!len) {
+               endpoint->extra = NULL;
+               endpoint->extralen = 0;
+               return parsed;
+       }
+
+       endpoint->extra = kmalloc(len, GFP_KERNEL);
+
+       if (!endpoint->extra) {
+               err("couldn't allocate memory for endpoint extra descriptors");
+               endpoint->extralen = 0;
+               return parsed;
+       }
+
+       memcpy(endpoint->extra, begin, len);
+       endpoint->extralen = len;
+
+       return parsed;
+}
+
+static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)
+{
+       int i, len, numskipped, retval, parsed = 0;
+       struct usb_descriptor_header *header;
+       struct usb_host_interface *ifp;
+       unsigned char *begin;
+
+       interface->act_altsetting = 0;
+       interface->num_altsetting = 0;
+       interface->max_altsetting = USB_ALTSETTINGALLOC;
+       device_initialize(&interface->dev);
+
+       interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,
+                                       GFP_KERNEL);
+       
+       if (!interface->altsetting) {
+               err("couldn't kmalloc interface->altsetting");
+               return -1;
+       }
+
+       while (size > 0) {
+               struct usb_interface_descriptor *d;
+       
+               if (interface->num_altsetting >= interface->max_altsetting) {
+                       struct usb_host_interface *ptr;
+                       int oldmas;
+
+                       oldmas = interface->max_altsetting;
+                       interface->max_altsetting += USB_ALTSETTINGALLOC;
+                       if (interface->max_altsetting > USB_MAXALTSETTING) {
+                               warn("too many alternate settings (incr %d max %d)\n",
+                                       USB_ALTSETTINGALLOC, USB_MAXALTSETTING);
+                               return -1;
+                       }
+
+                       ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL);
+                       if (ptr == NULL) {
+                               err("couldn't kmalloc interface->altsetting");
+                               return -1;
+                       }
+                       memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas);
+                       kfree(interface->altsetting);
+                       interface->altsetting = ptr;
+               }
+
+               ifp = interface->altsetting + interface->num_altsetting;
+               ifp->endpoint = NULL;
+               ifp->extra = NULL;
+               ifp->extralen = 0;
+               interface->num_altsetting++;
+
+               memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
+
+               /* Skip over the interface */
+               buffer += ifp->desc.bLength;
+               parsed += ifp->desc.bLength;
+               size -= ifp->desc.bLength;
+
+               begin = buffer;
+               numskipped = 0;
+
+               /* Skip over any interface, class or vendor descriptors */
+               while (size >= sizeof(struct usb_descriptor_header)) {
+                       header = (struct usb_descriptor_header *)buffer;
+
+                       if (header->bLength < 2) {
+                               err("invalid descriptor length of %d", header->bLength);
+                               return -1;
+                       }
+
+                       /* If we find another "proper" descriptor then we're done  */
+                       if ((header->bDescriptorType == USB_DT_INTERFACE) ||
+                           (header->bDescriptorType == USB_DT_ENDPOINT) ||
+                           (header->bDescriptorType == USB_DT_CONFIG) ||
+                           (header->bDescriptorType == USB_DT_DEVICE))
+                               break;
+
+                       numskipped++;
+
+                       buffer += header->bLength;
+                       parsed += header->bLength;
+                       size -= header->bLength;
+               }
+
+               if (numskipped)
+                       dbg("skipped %d class/vendor specific interface descriptors", numskipped);
+
+               /* Copy any unknown descriptors into a storage area for */
+               /*  drivers to later parse */
+               len = (int)(buffer - begin);
+               if (len) {
+                       ifp->extra = kmalloc(len, GFP_KERNEL);
+
+                       if (!ifp->extra) {
+                               err("couldn't allocate memory for interface extra descriptors");
+                               ifp->extralen = 0;
+                               return -1;
+                       }
+                       memcpy(ifp->extra, begin, len);
+                       ifp->extralen = len;
+               }
+
+               /* Did we hit an unexpected descriptor? */
+               header = (struct usb_descriptor_header *)buffer;
+               if ((size >= sizeof(struct usb_descriptor_header)) &&
+                   ((header->bDescriptorType == USB_DT_CONFIG) ||
+                    (header->bDescriptorType == USB_DT_DEVICE)))
+                       return parsed;
+
+               if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
+                       warn("too many endpoints");
+                       return -1;
+               }
+
+               ifp->endpoint = (struct usb_host_endpoint *)
+                       kmalloc(ifp->desc.bNumEndpoints *
+                       sizeof(struct usb_host_endpoint), GFP_KERNEL);
+               if (!ifp->endpoint) {
+                       err("out of memory");
+                       return -1;      
+               }
+
+               memset(ifp->endpoint, 0, ifp->desc.bNumEndpoints *
+                       sizeof(struct usb_host_endpoint));
+       
+               for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
+                       header = (struct usb_descriptor_header *)buffer;
+
+                       if (header->bLength > size) {
+                               err("ran out of descriptors parsing");
+                               return -1;
+                       }
+               
+                       retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
+                       if (retval < 0)
+                               return retval;
+
+                       buffer += retval;
+                       parsed += retval;
+                       size -= retval;
+               }
+
+               /* We check to see if it's an alternate to this one */
+               d = (struct usb_interface_descriptor *)buffer;
+               if (size < USB_DT_INTERFACE_SIZE
+                               || d->bDescriptorType != USB_DT_INTERFACE
+                               || !d->bAlternateSetting)
+                       return parsed;
+       }
+
+       return parsed;
+}
+
+int usb_parse_configuration(struct usb_host_config *config, char *buffer)
+{
+       int i, retval, size;
+       struct usb_descriptor_header *header;
+
+       memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
+       le16_to_cpus(&config->desc.wTotalLength);
+       size = config->desc.wTotalLength;
+
+       if (config->desc.bNumInterfaces > USB_MAXINTERFACES) {
+               warn("too many interfaces");
+               return -1;
+       }
+
+       config->interface = (struct usb_interface *)
+               kmalloc(config->desc.bNumInterfaces *
+               sizeof(struct usb_interface), GFP_KERNEL);
+       dbg("kmalloc IF %p, numif %i", config->interface, config->desc.bNumInterfaces);
+       if (!config->interface) {
+               err("out of memory");
+               return -1;      
+       }
+
+       memset(config->interface, 0,
+              config->desc.bNumInterfaces * sizeof(struct usb_interface));
+
+       buffer += config->desc.bLength;
+       size -= config->desc.bLength;
+       
+       config->extra = NULL;
+       config->extralen = 0;
+
+       for (i = 0; i < config->desc.bNumInterfaces; i++) {
+               int numskipped, len;
+               char *begin;
+
+               /* Skip over the rest of the Class Specific or Vendor */
+               /*  Specific descriptors */
+               begin = buffer;
+               numskipped = 0;
+               while (size >= sizeof(struct usb_descriptor_header)) {
+                       header = (struct usb_descriptor_header *)buffer;
+
+                       if ((header->bLength > size) || (header->bLength < 2)) {
+                               err("invalid descriptor length of %d", header->bLength);
+                               return -1;
+                       }
+
+                       /* If we find another "proper" descriptor then we're done  */
+                       if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
+                           (header->bDescriptorType == USB_DT_INTERFACE) ||
+                           (header->bDescriptorType == USB_DT_CONFIG) ||
+                           (header->bDescriptorType == USB_DT_DEVICE))
+                               break;
+
+                       dbg("skipping descriptor 0x%X", header->bDescriptorType);
+                       numskipped++;
+
+                       buffer += header->bLength;
+                       size -= header->bLength;
+               }
+               if (numskipped)
+                       dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
+
+               /* Copy any unknown descriptors into a storage area for */
+               /*  drivers to later parse */
+               len = (int)(buffer - begin);
+               if (len) {
+                       if (config->extralen) {
+                               warn("extra config descriptor");
+                       } else {
+                               config->extra = kmalloc(len, GFP_KERNEL);
+                               if (!config->extra) {
+                                       err("couldn't allocate memory for config extra descriptors");
+                                       config->extralen = 0;
+                                       return -1;
+                               }
+
+                               memcpy(config->extra, begin, len);
+                               config->extralen = len;
+                       }
+               }
+
+               retval = usb_parse_interface(config->interface + i, buffer, size);
+               if (retval < 0)
+                       return retval;
+
+               buffer += retval;
+               size -= retval;
+       }
+
+       return size;
+}
+
+// hub-only!! ... and only exported for reset/reinit path.
+// otherwise used internally on disconnect/destroy path
+void usb_destroy_configuration(struct usb_device *dev)
+{
+       int c, i, j, k;
+       
+       if (!dev->config)
+               return;
+
+       if (dev->rawdescriptors) {
+               for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+                       kfree(dev->rawdescriptors[i]);
+
+               kfree(dev->rawdescriptors);
+       }
+
+       for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+               struct usb_host_config *cf = &dev->config[c];
+
+               if (!cf->interface)
+                       break;
+
+               for (i = 0; i < cf->desc.bNumInterfaces; i++) {
+                       struct usb_interface *ifp =
+                               &cf->interface[i];
+                               
+                       if (!ifp->altsetting)
+                               break;
+
+                       for (j = 0; j < ifp->num_altsetting; j++) {
+                               struct usb_host_interface *as =
+                                       &ifp->altsetting[j];
+                                       
+                               if(as->extra) {
+                                       kfree(as->extra);
+                               }
+
+                               if (!as->endpoint)
+                                       break;
+                                       
+                               for(k = 0; k < as->desc.bNumEndpoints; k++) {
+                                       if(as->endpoint[k].extra) {
+                                               kfree(as->endpoint[k].extra);
+                                       }
+                               }       
+                               kfree(as->endpoint);
+                       }
+
+                       kfree(ifp->altsetting);
+               }
+               kfree(cf->interface);
+       }
+       kfree(dev->config);
+}
+
+
+// hub-only!! ... and only in reset path, or usb_new_device()
+// (used by real hubs and virtual root hubs)
+int usb_get_configuration(struct usb_device *dev)
+{
+       int result;
+       unsigned int cfgno, length;
+       unsigned char *buffer;
+       unsigned char *bigbuffer;
+       struct usb_config_descriptor *desc;
+
+       if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+               warn("too many configurations");
+               return -EINVAL;
+       }
+
+       if (dev->descriptor.bNumConfigurations < 1) {
+               warn("not enough configurations");
+               return -EINVAL;
+       }
+
+       dev->config = (struct usb_host_config *)
+               kmalloc(dev->descriptor.bNumConfigurations *
+               sizeof(struct usb_host_config), GFP_KERNEL);
+       if (!dev->config) {
+               err("out of memory");
+               return -ENOMEM; 
+       }
+       memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+               sizeof(struct usb_host_config));
+
+       dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
+               dev->descriptor.bNumConfigurations, GFP_KERNEL);
+       if (!dev->rawdescriptors) {
+               err("out of memory");
+               return -ENOMEM;
+       }
+
+       buffer = kmalloc(8, GFP_KERNEL);
+       if (!buffer) {
+               err("unable to allocate memory for configuration descriptors");
+               return -ENOMEM;
+       }
+       desc = (struct usb_config_descriptor *)buffer;
+
+       for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
+               /* We grab the first 8 bytes so we know how long the whole */
+               /*  configuration is */
+               result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
+               if (result < 8) {
+                       if (result < 0)
+                               err("unable to get descriptor");
+                       else {
+                               err("config descriptor too short (expected %i, got %i)", 8, result);
+                               result = -EINVAL;
+                       }
+                       goto err;
+               }
+
+               /* Get the full buffer */
+               length = le16_to_cpu(desc->wTotalLength);
+
+               bigbuffer = kmalloc(length, GFP_KERNEL);
+               if (!bigbuffer) {
+                       err("unable to allocate memory for configuration descriptors");
+                       result = -ENOMEM;
+                       goto err;
+               }
+
+               /* Now that we know the length, get the whole thing */
+               result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
+               if (result < 0) {
+                       err("couldn't get all of config descriptors");
+                       kfree(bigbuffer);
+                       goto err;
+               }       
+       
+               if (result < length) {
+                       err("config descriptor too short (expected %i, got %i)", length, result);
+                       result = -EINVAL;
+                       kfree(bigbuffer);
+                       goto err;
+               }
+
+               dev->rawdescriptors[cfgno] = bigbuffer;
+
+               result = usb_parse_configuration(&dev->config[cfgno], bigbuffer);
+               if (result > 0)
+                       dbg("descriptor data left");
+               else if (result < 0) {
+                       result = -EINVAL;
+                       goto err;
+               }
+       }
+
+       kfree(buffer);
+       return 0;
+err:
+       kfree(buffer);
+       dev->descriptor.bNumConfigurations = cfgno;
+       return result;
+}
+
index 148cf85..42afc27 100644 (file)
-/*\r
- * (C) Copyright David Brownell 2000-2002\r
- * \r
- * This program is free software; you can redistribute it and/or modify it\r
- * under the terms of the GNU General Public License as published by the\r
- * Free Software Foundation; either version 2 of the License, or (at your\r
- * option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
- * for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software Foundation,\r
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- */\r
-\r
-#if 0\r
-#include <linux/config.h>\r
-\r
-#ifdef CONFIG_USB_DEBUG\r
-       #define DEBUG\r
-#else\r
-       #undef DEBUG\r
-#endif\r
-\r
-#include <linux/kernel.h>\r
-#include <linux/module.h>\r
-#include <linux/pci.h>\r
-#include <asm/io.h>\r
-#include <asm/irq.h>\r
-#include <linux/usb.h>\r
-#include "hcd.h"\r
-#else\r
-#define DEBUG\r
-#include "../usb_wrapper.h"\r
-#include "hcd.h"\r
-#endif\r
-\r
-\r
-/* PCI-based HCs are normal, but custom bus glue should be ok */\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* configure so an HC device and id are always provided */\r
-/* always called with process context; sleeping is OK */\r
-\r
-/**\r
- * usb_hcd_pci_probe - initialize PCI-based HCDs\r
- * @dev: USB Host Controller being probed\r
- * @id: pci hotplug id connecting controller to HCD framework\r
- * Context: !in_interrupt()\r
- *\r
- * Allocates basic PCI resources for this USB host controller, and\r
- * then invokes the start() method for the HCD associated with it\r
- * through the hotplug entry's driver_data.\r
- *\r
- * Store this function in the HCD's struct pci_driver as probe().\r
- */\r
-int STDCALL usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)\r
-{\r
-       struct hc_driver        *driver;\r
-       PHYSICAL_ADDRESS        resource;\r
-       unsigned long           len;\r
-       void                    *base;\r
-       struct usb_hcd          *hcd;\r
-       int                     retval, region;\r
-       char                    buf [8];\r
-       //char                  *bufp = buf;\r
-\r
-       printk("usbcore: usb_hcd_pci_probe() called\n");\r
-\r
-       if (usb_disabled())\r
-               return -ENODEV;\r
-\r
-       if (!id || !(driver = (struct hc_driver *) id->driver_data))\r
-               return -EINVAL;\r
-\r
-       if (pci_enable_device (dev) < 0)\r
-               return -ENODEV;\r
-\r
-        if (!dev->irq) {\r
-               err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",\r
-                       dev->slot_name);\r
-               return -ENODEV;\r
-        }\r
-\r
-       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI\r
-               region = 0;\r
-               resource = pci_resource_start (dev, 0);\r
-               len = pci_resource_len (dev, 0);\r
-               if (!request_mem_region (resource, len, driver->description)) {\r
-                       dbg ("controller already in use");\r
-                       return -EBUSY;\r
-               }\r
-               base = ioremap_nocache (resource, len);\r
-               if (base == NULL) {\r
-                       dbg ("error mapping memory");\r
-                       retval = -EFAULT;\r
-clean_1:\r
-                       release_mem_region (resource, len);\r
-                       err ("init %s fail, %d", dev->slot_name, retval);\r
-                       return retval;\r
-               }\r
-\r
-       } else {                                // UHCI\r
-               //resource = 0;\r
-               len = 0;\r
-               for (region = 0; region < PCI_ROM_RESOURCE; region++) {\r
-                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))\r
-                               continue;\r
-\r
-                       resource = pci_resource_start (dev, region);\r
-                       len = pci_resource_len (dev, region);\r
-                       if (request_region (resource, len,\r
-                                       driver->description))\r
-                               break;\r
-               }\r
-               if (region == PCI_ROM_RESOURCE) {\r
-                       dbg ("no i/o regions available");\r
-                       return -EBUSY;\r
-               }\r
-               base = (void *) (ULONG_PTR)resource.u.LowPart;\r
-       }\r
-\r
-       // driver->start(), later on, will transfer device from\r
-       // control by SMM/BIOS to control by Linux (if needed)\r
-\r
-       pci_set_master (dev);\r
-\r
-       hcd = driver->hcd_alloc ();\r
-       if (hcd == NULL){\r
-               dbg ("hcd alloc fail");\r
-               retval = -ENOMEM;\r
-clean_2:\r
-               if (driver->flags & HCD_MEMORY) {\r
-                       iounmap (base);\r
-                       goto clean_1;\r
-               } else {\r
-                       release_region (resource, len);\r
-                       err ("init %s fail, %d", dev->slot_name, retval);\r
-                       return retval;\r
-               }\r
-       }\r
-       pci_set_drvdata (dev, hcd);\r
-       hcd->driver = driver;\r
-       hcd->description = driver->description;\r
-       hcd->pdev = dev;\r
-       hcd->self.bus_name = dev->slot_name;\r
-       hcd->product_desc = dev->dev.name;\r
-       hcd->self.controller = &dev->dev;\r
-       hcd->controller = hcd->self.controller;\r
-\r
-       if ((retval = hcd_buffer_create (hcd)) != 0) {\r
-clean_3:\r
-               driver->hcd_free (hcd);\r
-               goto clean_2;\r
-       }\r
-\r
-       dev_info (hcd->controller, "%s\n", hcd->product_desc);\r
-\r
-#ifndef __sparc__\r
-       sprintf (buf, "%d", dev->irq);\r
-#else\r
-       bufp = __irq_itoa(dev->irq);\r
-#endif\r
-       if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)\r
-                       != 0) {\r
-               dev_err (hcd->controller,\r
-                               "request interrupt %s failed\n", buf);\r
-               retval = -EBUSY;\r
-               goto clean_3;\r
-       }\r
-       hcd->irq = dev->irq;\r
-\r
-       hcd->regs = base;\r
-       hcd->region = region;\r
-       dev_info (hcd->controller, "irq %s, %s %p\n", buf,\r
-               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",\r
-               base);\r
-\r
-       usb_bus_init (&hcd->self);\r
-       hcd->self.op = &usb_hcd_operations;\r
-       hcd->self.hcpriv = (void *) hcd;\r
-\r
-       INIT_LIST_HEAD (&hcd->dev_list);\r
-\r
-       usb_register_bus (&hcd->self);\r
-\r
-       if ((retval = driver->start (hcd)) < 0)\r
-               usb_hcd_pci_remove (dev);\r
-\r
-       return retval;\r
-} \r
-EXPORT_SYMBOL (usb_hcd_pci_probe);\r
-\r
-\r
-/* may be called without controller electrically present */\r
-/* may be called with controller, bus, and devices active */\r
-\r
-/**\r
- * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs\r
- * @dev: USB Host Controller being removed\r
- * Context: !in_interrupt()\r
- *\r
- * Reverses the effect of usb_hcd_pci_probe(), first invoking\r
- * the HCD's stop() method.  It is always called from a thread\r
- * context, normally "rmmod", "apmd", or something similar.\r
- *\r
- * Store this function in the HCD's struct pci_driver as remove().\r
- */\r
-void STDCALL usb_hcd_pci_remove (struct pci_dev *dev)\r
-{\r
-       struct usb_hcd          *hcd;\r
-       struct usb_device       *hub;\r
-\r
-       hcd = pci_get_drvdata(dev);\r
-       if (!hcd)\r
-               return;\r
-       dev_info (hcd->controller, "remove, state %x\n", hcd->state);\r
-\r
-       if (in_interrupt ())\r
-               BUG ();\r
-\r
-       hub = hcd->self.root_hub;\r
-       hcd->state = USB_STATE_QUIESCING;\r
-\r
-       dev_dbg (hcd->controller, "roothub graceful disconnect\n");\r
-       usb_disconnect (&hub);\r
-\r
-       hcd->driver->stop (hcd);\r
-       hcd_buffer_destroy (hcd);\r
-       hcd->state = USB_STATE_HALT;\r
-       pci_set_drvdata (dev, 0);\r
-\r
-       free_irq (hcd->irq, hcd);\r
-       if (hcd->driver->flags & HCD_MEMORY) {\r
-               iounmap (hcd->regs);\r
-               release_mem_region (pci_resource_start (dev, 0),\r
-                       pci_resource_len (dev, 0));\r
-       } else {\r
-               release_region (pci_resource_start (dev, hcd->region),\r
-                       pci_resource_len (dev, hcd->region));\r
-       }\r
-\r
-       usb_deregister_bus (&hcd->self);\r
-       if (atomic_read (&hcd->self.refcnt) != 1) {\r
-               dev_warn (hcd->controller,\r
-                       "dangling refs (%d) to bus %d!\n",\r
-                       atomic_read (&hcd->self.refcnt) - 1,\r
-                       hcd->self.busnum);\r
-       }\r
-       hcd->driver->hcd_free (hcd);\r
-}\r
-EXPORT_SYMBOL (usb_hcd_pci_remove);\r
-\r
-\r
-#ifdef CONFIG_PM\r
-\r
-/*\r
- * Some "sleep" power levels imply updating struct usb_driver\r
- * to include a callback asking hcds to do their bit by checking\r
- * if all the drivers can suspend.  Gets involved with remote wakeup.\r
- *\r
- * If there are pending urbs, then HCs will need to access memory,\r
- * causing extra power drain.  New sleep()/wakeup() PM calls might\r
- * be needed, beyond PCI suspend()/resume().  The root hub timer\r
- * still be accessing memory though ...\r
- *\r
- * FIXME:  USB should have some power budgeting support working with\r
- * all kinds of hubs.\r
- *\r
- * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.\r
- * D1 and D2 states should do something, yes?\r
- *\r
- * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()\r
- * for all supported states, so that USB remote wakeup can work for any\r
- * devices that support it (and are connected via powered hubs).\r
- *\r
- * FIXME:  resume doesn't seem to work right any more...\r
- */\r
-\r
-\r
-// 2.4 kernels have issued concurrent resumes (w/APM)\r
-// we defend against that error; PCI doesn't yet.\r
-\r
-/**\r
- * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD\r
- * @dev: USB Host Controller being suspended\r
- *\r
- * Store this function in the HCD's struct pci_driver as suspend().\r
- */\r
-int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)\r
-{\r
-       struct usb_hcd          *hcd;\r
-       int                     retval;\r
-\r
-       hcd = pci_get_drvdata(dev);\r
-       dev_info (hcd->controller, "suspend to state %d\n", state);\r
-\r
-       pci_save_state (dev, hcd->pci_state);\r
-\r
-       // FIXME for all connected devices, leaf-to-root:\r
-       // driver->suspend()\r
-       // proposed "new 2.5 driver model" will automate that\r
-\r
-       /* driver may want to disable DMA etc */\r
-       retval = hcd->driver->suspend (hcd, state);\r
-       hcd->state = USB_STATE_SUSPENDED;\r
-\r
-       pci_set_power_state (dev, state);\r
-       return retval;\r
-}\r
-EXPORT_SYMBOL (usb_hcd_pci_suspend);\r
-\r
-/**\r
- * usb_hcd_pci_resume - power management resume of a PCI-based HCD\r
- * @dev: USB Host Controller being resumed\r
- *\r
- * Store this function in the HCD's struct pci_driver as resume().\r
- */\r
-int usb_hcd_pci_resume (struct pci_dev *dev)\r
-{\r
-       struct usb_hcd          *hcd;\r
-       int                     retval;\r
-\r
-       hcd = pci_get_drvdata(dev);\r
-       dev_info (hcd->controller, "resume\n");\r
-\r
-       /* guard against multiple resumes (APM bug?) */\r
-       atomic_inc (&hcd->resume_count);\r
-       if (atomic_read (&hcd->resume_count) != 1) {\r
-               dev_err (hcd->controller, "concurrent PCI resumes\n");\r
-               retval = 0;\r
-               goto done;\r
-       }\r
-\r
-       retval = -EBUSY;\r
-       if (hcd->state != USB_STATE_SUSPENDED) {\r
-               dev_dbg (hcd->controller, "can't resume, not suspended!\n");\r
-               goto done;\r
-       }\r
-       hcd->state = USB_STATE_RESUMING;\r
-\r
-       pci_set_power_state (dev, 0);\r
-       pci_restore_state (dev, hcd->pci_state);\r
-\r
-       retval = hcd->driver->resume (hcd);\r
-       if (!HCD_IS_RUNNING (hcd->state)) {\r
-               dev_dbg (hcd->controller, "resume fail, retval %d\n", retval);\r
-               usb_hc_died (hcd);\r
-// FIXME:  recover, reset etc.\r
-       } else {\r
-               // FIXME for all connected devices, root-to-leaf:\r
-               // driver->resume ();\r
-               // proposed "new 2.5 driver model" will automate that\r
-       }\r
-\r
-done:\r
-       atomic_dec (&hcd->resume_count);\r
-       return retval;\r
-}\r
-EXPORT_SYMBOL (usb_hcd_pci_resume);\r
-\r
-#endif /* CONFIG_PM */\r
-\r
-\r
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if 0
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/usb.h>
+#include "hcd.h"
+#else
+#define DEBUG
+#include "../usb_wrapper.h"
+#include "hcd.h"
+#endif
+
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int STDCALL usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct hc_driver        *driver;
+       PHYSICAL_ADDRESS        resource;
+       unsigned long           len;
+       void                    *base;
+       struct usb_hcd          *hcd;
+       int                     retval, region;
+       char                    buf [8];
+       //char                  *bufp = buf;
+
+       printk("usbcore: usb_hcd_pci_probe() called\n");
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       if (!id || !(driver = (struct hc_driver *) id->driver_data))
+               return -EINVAL;
+
+       if (pci_enable_device (dev) < 0)
+               return -ENODEV;
+
+        if (!dev->irq) {
+               err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+                       dev->slot_name);
+               return -ENODEV;
+        }
+
+       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
+               region = 0;
+               resource = pci_resource_start (dev, 0);
+               len = pci_resource_len (dev, 0);
+               if (!request_mem_region (resource, len, driver->description)) {
+                       dbg ("controller already in use");
+                       return -EBUSY;
+               }
+               base = ioremap_nocache (resource, len);
+               if (base == NULL) {
+                       dbg ("error mapping memory");
+                       retval = -EFAULT;
+clean_1:
+                       release_mem_region (resource, len);
+                       err ("init %s fail, %d", dev->slot_name, retval);
+                       return retval;
+               }
+
+       } else {                                // UHCI
+               //resource = 0;
+               len = 0;
+               for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+                               continue;
+
+                       resource = pci_resource_start (dev, region);
+                       len = pci_resource_len (dev, region);
+                       if (request_region (resource, len,
+                                       driver->description))
+                               break;
+               }
+               if (region == PCI_ROM_RESOURCE) {
+                       dbg ("no i/o regions available");
+                       return -EBUSY;
+               }
+               base = (void *) (ULONG_PTR)resource.u.LowPart;
+       }
+
+       // driver->start(), later on, will transfer device from
+       // control by SMM/BIOS to control by Linux (if needed)
+
+       pci_set_master (dev);
+
+       hcd = driver->hcd_alloc ();
+       if (hcd == NULL){
+               dbg ("hcd alloc fail");
+               retval = -ENOMEM;
+clean_2:
+               if (driver->flags & HCD_MEMORY) {
+                       iounmap (base);
+                       goto clean_1;
+               } else {
+                       release_region (resource, len);
+                       err ("init %s fail, %d", dev->slot_name, retval);
+                       return retval;
+               }
+       }
+       pci_set_drvdata (dev, hcd);
+       hcd->driver = driver;
+       hcd->description = driver->description;
+       hcd->pdev = dev;
+       hcd->self.bus_name = dev->slot_name;
+       hcd->product_desc = dev->dev.name;
+       hcd->self.controller = &dev->dev;
+       hcd->controller = hcd->self.controller;
+
+       if ((retval = hcd_buffer_create (hcd)) != 0) {
+clean_3:
+               driver->hcd_free (hcd);
+               goto clean_2;
+       }
+
+       dev_info (hcd->controller, "%s\n", hcd->product_desc);
+
+#ifndef __sparc__
+       sprintf (buf, "%d", dev->irq);
+#else
+       bufp = __irq_itoa(dev->irq);
+#endif
+       if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
+                       != 0) {
+               dev_err (hcd->controller,
+                               "request interrupt %s failed\n", buf);
+               retval = -EBUSY;
+               goto clean_3;
+       }
+       hcd->irq = dev->irq;
+
+       hcd->regs = base;
+       hcd->region = region;
+       dev_info (hcd->controller, "irq %s, %s %p\n", buf,
+               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+               base);
+
+       usb_bus_init (&hcd->self);
+       hcd->self.op = &usb_hcd_operations;
+       hcd->self.hcpriv = (void *) hcd;
+
+       INIT_LIST_HEAD (&hcd->dev_list);
+
+       usb_register_bus (&hcd->self);
+
+       if ((retval = driver->start (hcd)) < 0)
+               usb_hcd_pci_remove (dev);
+
+       return retval;
+} 
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void STDCALL usb_hcd_pci_remove (struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+       struct usb_device       *hub;
+
+       hcd = pci_get_drvdata(dev);
+       if (!hcd)
+               return;
+       dev_info (hcd->controller, "remove, state %x\n", hcd->state);
+
+       if (in_interrupt ())
+               BUG ();
+
+       hub = hcd->self.root_hub;
+       hcd->state = USB_STATE_QUIESCING;
+
+       dev_dbg (hcd->controller, "roothub graceful disconnect\n");
+       usb_disconnect (&hub);
+
+       hcd->driver->stop (hcd);
+       hcd_buffer_destroy (hcd);
+       hcd->state = USB_STATE_HALT;
+       pci_set_drvdata (dev, 0);
+
+       free_irq (hcd->irq, hcd);
+       if (hcd->driver->flags & HCD_MEMORY) {
+               iounmap (hcd->regs);
+               release_mem_region (pci_resource_start (dev, 0),
+                       pci_resource_len (dev, 0));
+       } else {
+               release_region (pci_resource_start (dev, hcd->region),
+                       pci_resource_len (dev, hcd->region));
+       }
+
+       usb_deregister_bus (&hcd->self);
+       if (atomic_read (&hcd->self.refcnt) != 1) {
+               dev_warn (hcd->controller,
+                       "dangling refs (%d) to bus %d!\n",
+                       atomic_read (&hcd->self.refcnt) - 1,
+                       hcd->self.busnum);
+       }
+       hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend.  Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain.  New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume().  The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME:  USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME:  resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+       struct usb_hcd          *hcd;
+       int                     retval;
+
+       hcd = pci_get_drvdata(dev);
+       dev_info (hcd->controller, "suspend to state %d\n", state);
+
+       pci_save_state (dev, hcd->pci_state);
+
+       // FIXME for all connected devices, leaf-to-root:
+       // driver->suspend()
+       // proposed "new 2.5 driver model" will automate that
+
+       /* driver may want to disable DMA etc */
+       retval = hcd->driver->suspend (hcd, state);
+       hcd->state = USB_STATE_SUSPENDED;
+
+       pci_set_power_state (dev, state);
+       return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+       int                     retval;
+
+       hcd = pci_get_drvdata(dev);
+       dev_info (hcd->controller, "resume\n");
+
+       /* guard against multiple resumes (APM bug?) */
+       atomic_inc (&hcd->resume_count);
+       if (atomic_read (&hcd->resume_count) != 1) {
+               dev_err (hcd->controller, "concurrent PCI resumes\n");
+               retval = 0;
+               goto done;
+       }
+
+       retval = -EBUSY;
+       if (hcd->state != USB_STATE_SUSPENDED) {
+               dev_dbg (hcd->controller, "can't resume, not suspended!\n");
+               goto done;
+       }
+       hcd->state = USB_STATE_RESUMING;
+
+       pci_set_power_state (dev, 0);
+       pci_restore_state (dev, hcd->pci_state);
+
+       retval = hcd->driver->resume (hcd);
+       if (!HCD_IS_RUNNING (hcd->state)) {
+               dev_dbg (hcd->controller, "resume fail, retval %d\n", retval);
+               usb_hc_died (hcd);
+// FIXME:  recover, reset etc.
+       } else {
+               // FIXME for all connected devices, root-to-leaf:
+               // driver->resume ();
+               // proposed "new 2.5 driver model" will automate that
+       }
+
+done:
+       atomic_dec (&hcd->resume_count);
+       return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif /* CONFIG_PM */
+
+
index a9efdf7..e594362 100644 (file)
-/*\r
- * (C) Copyright Linus Torvalds 1999\r
- * (C) Copyright Johannes Erdfelt 1999-2001\r
- * (C) Copyright Andreas Gal 1999\r
- * (C) Copyright Gregory P. Smith 1999\r
- * (C) Copyright Deti Fliegl 1999\r
- * (C) Copyright Randy Dunlap 2000\r
- * (C) Copyright David Brownell 2000-2002\r
- * \r
- * This program is free software; you can redistribute it and/or modify it\r
- * under the terms of the GNU General Public License as published by the\r
- * Free Software Foundation; either version 2 of the License, or (at your\r
- * option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
- * for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software Foundation,\r
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- */\r
-\r
-#if 0\r
-#include <linux/config.h>\r
-\r
-#ifdef CONFIG_USB_DEBUG\r
-#define DEBUG\r
-#endif\r
-\r
-#include <linux/module.h>\r
-#include <linux/version.h>\r
-#include <linux/kernel.h>\r
-#include <linux/slab.h>\r
-#include <linux/completion.h>\r
-#include <linux/uts.h>                 /* for UTS_SYSNAME */\r
-#include <linux/pci.h>                 /* for hcd->pdev and dma addressing */\r
-#include <linux/dma-mapping.h>\r
-#include <asm/byteorder.h>\r
-\r
-#include <linux/usb.h>\r
-#else\r
-#include "../usb_wrapper.h"\r
-//#define DEBUG\r
-#endif\r
-\r
-#include "hcd.h"\r
-\r
-// #define USB_BANDWIDTH_MESSAGES\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * USB Host Controller Driver framework\r
- *\r
- * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing\r
- * HCD-specific behaviors/bugs.\r
- *\r
- * This does error checks, tracks devices and urbs, and delegates to a\r
- * "hc_driver" only for code (and data) that really needs to know about\r
- * hardware differences.  That includes root hub registers, i/o queues,\r
- * and so on ... but as little else as possible.\r
- *\r
- * Shared code includes most of the "root hub" code (these are emulated,\r
- * though each HC's hardware works differently) and PCI glue, plus request\r
- * tracking overhead.  The HCD code should only block on spinlocks or on\r
- * hardware handshaking; blocking on software events (such as other kernel\r
- * threads releasing resources, or completing actions) is all generic.\r
- *\r
- * Happens the USB 2.0 spec says this would be invisible inside the "USBD",\r
- * and includes mostly a "HCDI" (HCD Interface) along with some APIs used\r
- * only by the hub driver ... and that neither should be seen or used by\r
- * usb client device drivers.\r
- *\r
- * Contributors of ideas or unattributed patches include: David Brownell,\r
- * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ...\r
- *\r
- * HISTORY:\r
- * 2002-02-21  Pull in most of the usb_bus support from usb.c; some\r
- *             associated cleanup.  "usb_hcd" still != "usb_bus".\r
- * 2001-12-12  Initial patch version for Linux 2.5.1 kernel.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* host controllers we manage */\r
-LIST_HEAD (usb_bus_list);\r
-EXPORT_SYMBOL_GPL (usb_bus_list);\r
-\r
-/* used when allocating bus numbers */\r
-#define USB_MAXBUS             64\r
-struct usb_busmap {\r
-       unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];\r
-};\r
-static struct usb_busmap busmap;\r
-\r
-/* used when updating list of hcds */\r
-DECLARE_MUTEX (usb_bus_list_lock);     /* exported only for usbfs */\r
-EXPORT_SYMBOL_GPL (usb_bus_list_lock);\r
-\r
-/* used when updating hcd data */\r
-static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * Sharable chunks of root hub code.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#define KERNEL_REL     ((LINUX_VERSION_CODE >> 16) & 0x0ff)\r
-#define KERNEL_VER     ((LINUX_VERSION_CODE >> 8) & 0x0ff)\r
-\r
-/* usb 2.0 root hub device descriptor */\r
-static const u8 usb2_rh_dev_descriptor [18] = {\r
-       0x12,       /*  __u8  bLength; */\r
-       0x01,       /*  __u8  bDescriptorType; Device */\r
-       0x00, 0x02, /*  __u16 bcdUSB; v2.0 */\r
-\r
-       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */\r
-       0x00,       /*  __u8  bDeviceSubClass; */\r
-       0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/\r
-       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */\r
-\r
-       0x00, 0x00, /*  __u16 idVendor; */\r
-       0x00, 0x00, /*  __u16 idProduct; */\r
-       KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */\r
-\r
-       0x03,       /*  __u8  iManufacturer; */\r
-       0x02,       /*  __u8  iProduct; */\r
-       0x01,       /*  __u8  iSerialNumber; */\r
-       0x01        /*  __u8  bNumConfigurations; */\r
-};\r
-\r
-/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */\r
-\r
-/* usb 1.1 root hub device descriptor */\r
-static const u8 usb11_rh_dev_descriptor [18] = {\r
-       0x12,       /*  __u8  bLength; */\r
-       0x01,       /*  __u8  bDescriptorType; Device */\r
-       0x10, 0x01, /*  __u16 bcdUSB; v1.1 */\r
-\r
-       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */\r
-       0x00,       /*  __u8  bDeviceSubClass; */\r
-       0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */\r
-       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */\r
-\r
-       0x00, 0x00, /*  __u16 idVendor; */\r
-       0x00, 0x00, /*  __u16 idProduct; */\r
-       KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */\r
-\r
-       0x03,       /*  __u8  iManufacturer; */\r
-       0x02,       /*  __u8  iProduct; */\r
-       0x01,       /*  __u8  iSerialNumber; */\r
-       0x01        /*  __u8  bNumConfigurations; */\r
-};\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* Configuration descriptors for our root hubs */\r
-\r
-static const u8 fs_rh_config_descriptor [] = {\r
-\r
-       /* one configuration */\r
-       0x09,       /*  __u8  bLength; */\r
-       0x02,       /*  __u8  bDescriptorType; Configuration */\r
-       0x19, 0x00, /*  __u16 wTotalLength; */\r
-       0x01,       /*  __u8  bNumInterfaces; (1) */\r
-       0x01,       /*  __u8  bConfigurationValue; */\r
-       0x00,       /*  __u8  iConfiguration; */\r
-       0x40,       /*  __u8  bmAttributes; \r
-                                Bit 7: Bus-powered,\r
-                                    6: Self-powered,\r
-                                    5 Remote-wakwup,\r
-                                    4..0: resvd */\r
-       0x00,       /*  __u8  MaxPower; */\r
-      \r
-       /* USB 1.1:\r
-        * USB 2.0, single TT organization (mandatory):\r
-        *      one interface, protocol 0\r
-        *\r
-        * USB 2.0, multiple TT organization (optional):\r
-        *      two interfaces, protocols 1 (like single TT)\r
-        *      and 2 (multiple TT mode) ... config is\r
-        *      sometimes settable\r
-        *      NOT IMPLEMENTED\r
-        */\r
-\r
-       /* one interface */\r
-       0x09,       /*  __u8  if_bLength; */\r
-       0x04,       /*  __u8  if_bDescriptorType; Interface */\r
-       0x00,       /*  __u8  if_bInterfaceNumber; */\r
-       0x00,       /*  __u8  if_bAlternateSetting; */\r
-       0x01,       /*  __u8  if_bNumEndpoints; */\r
-       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */\r
-       0x00,       /*  __u8  if_bInterfaceSubClass; */\r
-       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */\r
-       0x00,       /*  __u8  if_iInterface; */\r
-     \r
-       /* one endpoint (status change endpoint) */\r
-       0x07,       /*  __u8  ep_bLength; */\r
-       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */\r
-       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */\r
-       0x03,       /*  __u8  ep_bmAttributes; Interrupt */\r
-       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */\r
-       0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */\r
-};\r
-\r
-static const u8 hs_rh_config_descriptor [] = {\r
-\r
-       /* one configuration */\r
-       0x09,       /*  __u8  bLength; */\r
-       0x02,       /*  __u8  bDescriptorType; Configuration */\r
-       0x19, 0x00, /*  __u16 wTotalLength; */\r
-       0x01,       /*  __u8  bNumInterfaces; (1) */\r
-       0x01,       /*  __u8  bConfigurationValue; */\r
-       0x00,       /*  __u8  iConfiguration; */\r
-       0x40,       /*  __u8  bmAttributes; \r
-                                Bit 7: Bus-powered,\r
-                                    6: Self-powered,\r
-                                    5 Remote-wakwup,\r
-                                    4..0: resvd */\r
-       0x00,       /*  __u8  MaxPower; */\r
-      \r
-       /* USB 1.1:\r
-        * USB 2.0, single TT organization (mandatory):\r
-        *      one interface, protocol 0\r
-        *\r
-        * USB 2.0, multiple TT organization (optional):\r
-        *      two interfaces, protocols 1 (like single TT)\r
-        *      and 2 (multiple TT mode) ... config is\r
-        *      sometimes settable\r
-        *      NOT IMPLEMENTED\r
-        */\r
-\r
-       /* one interface */\r
-       0x09,       /*  __u8  if_bLength; */\r
-       0x04,       /*  __u8  if_bDescriptorType; Interface */\r
-       0x00,       /*  __u8  if_bInterfaceNumber; */\r
-       0x00,       /*  __u8  if_bAlternateSetting; */\r
-       0x01,       /*  __u8  if_bNumEndpoints; */\r
-       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */\r
-       0x00,       /*  __u8  if_bInterfaceSubClass; */\r
-       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */\r
-       0x00,       /*  __u8  if_iInterface; */\r
-     \r
-       /* one endpoint (status change endpoint) */\r
-       0x07,       /*  __u8  ep_bLength; */\r
-       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */\r
-       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */\r
-       0x03,       /*  __u8  ep_bmAttributes; Interrupt */\r
-       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */\r
-       0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */\r
-};\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * helper routine for returning string descriptors in UTF-16LE\r
- * input can actually be ISO-8859-1; ASCII is its 7-bit subset\r
- */\r
-static int ascii2utf (char *s, u8 *utf, int utfmax)\r
-{\r
-       int retval;\r
-\r
-       for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {\r
-               *utf++ = *s++;\r
-               *utf++ = 0;\r
-       }\r
-       return retval;\r
-}\r
-\r
-/*\r
- * rh_string - provides manufacturer, product and serial strings for root hub\r
- * @id: the string ID number (1: serial number, 2: product, 3: vendor)\r
- * @hcd: the host controller for this root hub\r
- * @type: string describing our driver \r
- * @data: return packet in UTF-16 LE\r
- * @len: length of the return packet\r
- *\r
- * Produces either a manufacturer, product or serial number string for the\r
- * virtual root hub device.\r
- */\r
-static int rh_string (\r
-       int             id,\r
-       struct usb_hcd  *hcd,\r
-       u8              *data,\r
-       int             len\r
-) {\r
-       char buf [100];\r
-\r
-       // language ids\r
-       if (id == 0) {\r
-               *data++ = 4; *data++ = 3;       /* 4 bytes string data */\r
-               *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */\r
-               return 4;\r
-\r
-       // serial number\r
-       } else if (id == 1) {\r
-               strcpy (buf, hcd->self.bus_name);\r
-\r
-       // product description\r
-       } else if (id == 2) {\r
-                strcpy (buf, hcd->product_desc);\r
-\r
-       // id 3 == vendor description\r
-       } else if (id == 3) {\r
-                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,\r
-                       hcd->description);\r
-\r
-       // unsupported IDs --> "protocol stall"\r
-       } else\r
-           return 0;\r
-\r
-       data [0] = 2 * (strlen (buf) + 1);\r
-       data [1] = 3;   /* type == string */\r
-       return 2 + ascii2utf (buf, data + 2, len - 2);\r
-}\r
-\r
-\r
-/* Root hub control transfers execute synchronously */\r
-static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)\r
-{\r
-       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;\r
-       u16             typeReq, wValue, wIndex, wLength;\r
-       const u8        *bufp = 0;\r
-       u8              *ubuf = urb->transfer_buffer;\r
-       int             len = 0;\r
-       //unsigned long flags;\r
-\r
-       typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;\r
-       wValue   = le16_to_cpu (cmd->wValue);\r
-       wIndex   = le16_to_cpu (cmd->wIndex);\r
-       wLength  = le16_to_cpu (cmd->wLength);\r
-\r
-       if (wLength > urb->transfer_buffer_length)\r
-               goto error;\r
-\r
-       /* set up for success */\r
-       urb->status = 0;\r
-       urb->actual_length = wLength;\r
-       switch (typeReq) {\r
-\r
-       /* DEVICE REQUESTS */\r
-\r
-       case DeviceRequest | USB_REQ_GET_STATUS:\r
-               // DEVICE_REMOTE_WAKEUP\r
-               ubuf [0] = 1; // selfpowered\r
-               ubuf [1] = 0;\r
-                       /* FALLTHROUGH */\r
-       case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:\r
-       case DeviceOutRequest | USB_REQ_SET_FEATURE:\r
-               dev_dbg (hcd->controller, "no device features yet yet\n");\r
-               break;\r
-       case DeviceRequest | USB_REQ_GET_CONFIGURATION:\r
-               ubuf [0] = 1;\r
-                       /* FALLTHROUGH */\r
-       case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:\r
-               break;\r
-       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:\r
-               switch (wValue & 0xff00) {\r
-               case USB_DT_DEVICE << 8:\r
-                       if (hcd->driver->flags & HCD_USB2)\r
-                               bufp = usb2_rh_dev_descriptor;\r
-                       else if (hcd->driver->flags & HCD_USB11)\r
-                               bufp = usb11_rh_dev_descriptor;\r
-                       else\r
-                               goto error;\r
-                       len = 18;\r
-                       break;\r
-               case USB_DT_CONFIG << 8:\r
-                       if (hcd->driver->flags & HCD_USB2) {\r
-                               bufp = hs_rh_config_descriptor;\r
-                               len = sizeof hs_rh_config_descriptor;\r
-                       } else {\r
-                               bufp = fs_rh_config_descriptor;\r
-                               len = sizeof fs_rh_config_descriptor;\r
-                       }\r
-                       break;\r
-               case USB_DT_STRING << 8:\r
-                       urb->actual_length = rh_string (\r
-                               wValue & 0xff, hcd,\r
-                               ubuf, wLength);\r
-                       break;\r
-               default:\r
-                       goto error;\r
-               }\r
-               break;\r
-       case DeviceRequest | USB_REQ_GET_INTERFACE:\r
-               ubuf [0] = 0;\r
-                       /* FALLTHROUGH */\r
-       case DeviceOutRequest | USB_REQ_SET_INTERFACE:\r
-               break;\r
-       case DeviceOutRequest | USB_REQ_SET_ADDRESS:\r
-               // wValue == urb->dev->devaddr\r
-               dev_dbg (hcd->controller, "root hub device address %d\n",\r
-                       wValue);\r
-               break;\r
-\r
-       /* INTERFACE REQUESTS (no defined feature/status flags) */\r
-\r
-       /* ENDPOINT REQUESTS */\r
-\r
-       case EndpointRequest | USB_REQ_GET_STATUS:\r
-               // ENDPOINT_HALT flag\r
-               ubuf [0] = 0;\r
-               ubuf [1] = 0;\r
-                       /* FALLTHROUGH */\r
-       case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:\r
-       case EndpointOutRequest | USB_REQ_SET_FEATURE:\r
-               dev_dbg (hcd->controller, "no endpoint features yet\n");\r
-               break;\r
-\r
-       /* CLASS REQUESTS (and errors) */\r
-\r
-       default:\r
-               /* non-generic request */\r
-               urb->status = hcd->driver->hub_control (hcd,\r
-                       typeReq, wValue, wIndex,\r
-                       ubuf, wLength);\r
-               break;\r
-error:\r
-               /* "protocol stall" on error */\r
-               urb->status = -EPIPE;\r
-               dev_dbg (hcd->controller, "unsupported hub control message (maxchild %d)\n",\r
-                               urb->dev->maxchild);\r
-       }\r
-       if (urb->status) {\r
-               urb->actual_length = 0;\r
-               dev_dbg (hcd->controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",\r
-                       typeReq, wValue, wIndex, wLength, urb->status);\r
-       }\r
-       if (bufp) {\r
-               if (urb->transfer_buffer_length < len)\r
-                       len = urb->transfer_buffer_length;\r
-               urb->actual_length = len;\r
-               // always USB_DIR_IN, toward host\r
-               memcpy (ubuf, bufp, len);\r
-       }\r
-\r
-       /* any errors get returned through the urb completion */\r
-       local_irq_save (flags);\r
-       usb_hcd_giveback_urb (hcd, urb, NULL);\r
-       local_irq_restore (flags);\r
-       return 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * Root Hub interrupt transfers are synthesized with a timer.\r
- * Completions are called in_interrupt() but not in_irq().\r
- */\r
-\r
-static void rh_report_status (unsigned long ptr);\r
-\r
-static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) \r
-{\r
-       int     len = 1 + (urb->dev->maxchild / 8);\r
-\r
-       /* rh_timer protected by hcd_data_lock */\r
-       if (hcd->rh_timer.data\r
-                       || urb->status != -EINPROGRESS\r
-                       || urb->transfer_buffer_length < len) {\r
-               dev_dbg (hcd->controller,\r
-                               "not queuing rh status urb, stat %d\n",\r
-                               urb->status);\r
-               return -EINVAL;\r
-       }\r
-\r
-       init_timer (&hcd->rh_timer);\r
-\r
-       hcd->rh_timer.function = rh_report_status;\r
-       hcd->rh_timer.data = (unsigned long) urb;\r
-       /* USB 2.0 spec says 256msec; this is close enough */\r
-       hcd->rh_timer.expires = jiffies + HZ/4;\r
-       add_timer (&hcd->rh_timer);\r
-       urb->hcpriv = hcd;      /* nonzero to indicate it's queued */\r
-       return 0;\r
-}\r
-\r
-/* timer callback */\r
-\r
-static void rh_report_status (unsigned long ptr)\r
-{\r
-       struct urb      *urb;\r
-       struct usb_hcd  *hcd;\r
-       int             length;\r
-       //unsigned long flags;\r
-\r
-       urb = (struct urb *) ptr;\r
-       local_irq_save (flags);\r
-       spin_lock (&urb->lock);\r
-\r
-       /* do nothing if the hc is gone or the urb's been unlinked */\r
-       if (!urb->dev\r
-                       || urb->status != -EINPROGRESS\r
-                       || (hcd = urb->dev->bus->hcpriv) == 0\r
-                       || !HCD_IS_RUNNING (hcd->state)) {\r
-               spin_unlock (&urb->lock);\r
-               local_irq_restore (flags);\r
-               return;\r
-       }\r
-\r
-       length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer);\r
-\r
-       /* complete the status urb, or retrigger the timer */\r
-       spin_lock (&hcd_data_lock);\r
-       if (length > 0) {\r
-               hcd->rh_timer.data = 0;\r
-               urb->actual_length = length;\r
-               urb->status = 0;\r
-               urb->hcpriv = 0;\r
-       } else\r
-               mod_timer (&hcd->rh_timer, jiffies + HZ/4);\r
-       spin_unlock (&hcd_data_lock);\r
-       spin_unlock (&urb->lock);\r
-\r
-       /* local irqs are always blocked in completions */\r
-       if (length > 0)\r
-               usb_hcd_giveback_urb (hcd, urb, NULL);\r
-       local_irq_restore (flags);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)\r
-{\r
-       if (usb_pipeint (urb->pipe)) {\r
-               int             retval;\r
-               unsigned long   flags;\r
-\r
-               spin_lock_irqsave (&hcd_data_lock, flags);\r
-               retval = rh_status_urb (hcd, urb);\r
-               spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-               return retval;\r
-       }\r
-       if (usb_pipecontrol (urb->pipe))\r
-               return rh_call_control (hcd, urb);\r
-       else\r
-               return -EINVAL;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)\r
-{\r
-       //unsigned long flags;\r
-\r
-       /* note:  always a synchronous unlink */\r
-       del_timer_sync (&hcd->rh_timer);\r
-       hcd->rh_timer.data = 0;\r
-\r
-       local_irq_save (flags);\r
-       urb->hcpriv = 0;\r
-       usb_hcd_giveback_urb (hcd, urb, NULL);\r
-       local_irq_restore (flags);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* exported only within usbcore */\r
-void usb_bus_get (struct usb_bus *bus)\r
-{\r
-       atomic_inc (&bus->refcnt);\r
-}\r
-\r
-/* exported only within usbcore */\r
-void usb_bus_put (struct usb_bus *bus)\r
-{\r
-       if (atomic_dec_and_test (&bus->refcnt))\r
-               kfree (bus);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_bus_init - shared initialization code\r
- * @bus: the bus structure being initialized\r
- *\r
- * This code is used to initialize a usb_bus structure, memory for which is\r
- * separately managed.\r
- */\r
-void STDCALL usb_bus_init (struct usb_bus *bus)\r
-{\r
-       memset (&bus->devmap, 0, sizeof(struct usb_devmap));\r
-\r
-       bus->devnum_next = 1;\r
-\r
-       bus->root_hub = NULL;\r
-       bus->hcpriv = NULL;\r
-       bus->busnum = -1;\r
-       bus->bandwidth_allocated = 0;\r
-       bus->bandwidth_int_reqs  = 0;\r
-       bus->bandwidth_isoc_reqs = 0;\r
-\r
-       INIT_LIST_HEAD (&bus->bus_list);\r
-\r
-       atomic_set (&bus->refcnt, 1);\r
-}\r
-\r
-/**\r
- * usb_alloc_bus - creates a new USB host controller structure\r
- * @op: pointer to a struct usb_operations that this bus structure should use\r
- * Context: !in_interrupt()\r
- *\r
- * Creates a USB host controller bus structure with the specified \r
- * usb_operations and initializes all the necessary internal objects.\r
- *\r
- * If no memory is available, NULL is returned.\r
- *\r
- * The caller should call usb_free_bus() when it is finished with the structure.\r
- */\r
-struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *op)\r
-{\r
-       struct usb_bus *bus;\r
-\r
-       bus = kmalloc (sizeof *bus, GFP_KERNEL);\r
-       if (!bus)\r
-               return NULL;\r
-       usb_bus_init (bus);\r
-       bus->op = op;\r
-       return bus;\r
-}\r
-\r
-/**\r
- * usb_free_bus - frees the memory used by a bus structure\r
- * @bus: pointer to the bus to free\r
- *\r
- * To be invoked by a HCD, only as the last step of decoupling from\r
- * hardware.  It is an error to call this if the reference count is\r
- * anything but one.  That would indicate that some system component\r
- * did not correctly shut down, and thought the hardware was still\r
- * accessible.\r
- */\r
-void STDCALL usb_free_bus (struct usb_bus *bus)\r
-{\r
-       if (!bus)\r
-               return;\r
-       if (atomic_read (&bus->refcnt) != 1)\r
-               err ("usb_free_bus #%d, count != 1", bus->busnum);\r
-       usb_bus_put (bus);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_register_bus - registers the USB host controller with the usb core\r
- * @bus: pointer to the bus to register\r
- * Context: !in_interrupt()\r
- *\r
- * Assigns a bus number, and links the controller into usbcore data\r
- * structures so that it can be seen by scanning the bus list.\r
- */\r
-void STDCALL usb_register_bus(struct usb_bus *bus)\r
-{\r
-       int busnum;\r
-\r
-       down (&usb_bus_list_lock);\r
-       busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);\r
-       if (busnum < USB_MAXBUS) {\r
-               set_bit (busnum, busmap.busmap);\r
-               bus->busnum = busnum;\r
-       } else\r
-               warn ("too many buses");\r
-\r
-       usb_bus_get (bus);\r
-\r
-       /* Add it to the list of buses */\r
-       list_add (&bus->bus_list, &usb_bus_list);\r
-       up (&usb_bus_list_lock);\r
-\r
-       usbfs_add_bus (bus);\r
-\r
-       dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);\r
-}\r
-\r
-/**\r
- * usb_deregister_bus - deregisters the USB host controller\r
- * @bus: pointer to the bus to deregister\r
- * Context: !in_interrupt()\r
- *\r
- * Recycles the bus number, and unlinks the controller from usbcore data\r
- * structures so that it won't be seen by scanning the bus list.\r
- */\r
-void STDCALL usb_deregister_bus (struct usb_bus *bus)\r
-{\r
-       dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum);\r
-\r
-       /*\r
-        * NOTE: make sure that all the devices are removed by the\r
-        * controller code, as well as having it call this when cleaning\r
-        * itself up\r
-        */\r
-       down (&usb_bus_list_lock);\r
-       list_del (&bus->bus_list);\r
-       up (&usb_bus_list_lock);\r
-\r
-       usbfs_remove_bus (bus);\r
-\r
-       clear_bit (bus->busnum, busmap.busmap);\r
-\r
-       usb_bus_put (bus);\r
-}\r
-\r
-/**\r
- * usb_register_root_hub - called by HCD to register its root hub \r
- * @usb_dev: the usb root hub device to be registered.\r
- * @parent_dev: the parent device of this root hub.\r
- *\r
- * The USB host controller calls this function to register the root hub\r
- * properly with the USB subsystem.  It sets up the device properly in\r
- * the driverfs tree, and then calls usb_new_device() to register the\r
- * usb device.\r
- */\r
-int STDCALL usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)\r
-{\r
-       int retval;\r
-\r
-       sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum);\r
-       usb_dev->state = USB_STATE_DEFAULT;\r
-       retval = usb_new_device (usb_dev, parent_dev);\r
-       if (retval)\r
-               dev_err (parent_dev, "can't register root hub for %s, %d\n",\r
-                               usb_dev->dev.bus_id, retval);\r
-       return retval;\r
-}\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_calc_bus_time - approximate periodic transaction time in nanoseconds\r
- * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}\r
- * @is_input: true iff the transaction sends data to the host\r
- * @isoc: true for isochronous transactions, false for interrupt ones\r
- * @bytecount: how many bytes in the transaction.\r
- *\r
- * Returns approximate bus time in nanoseconds for a periodic transaction.\r
- * See USB 2.0 spec section 5.11.3; only periodic transfers need to be\r
- * scheduled in software, this function is only used for such scheduling.\r
- */\r
-long STDCALL usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)\r
-{\r
-       unsigned long   tmp;\r
-\r
-       switch (speed) {\r
-       case USB_SPEED_LOW:     /* INTR only */\r
-               if (is_input) {\r
-                       tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;\r
-                       return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);\r
-               } else {\r
-                       tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;\r
-                       return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);\r
-               }\r
-       case USB_SPEED_FULL:    /* ISOC or INTR */\r
-               if (isoc) {\r
-                       tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;\r
-                       return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);\r
-               } else {\r
-                       tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;\r
-                       return (9107L + BW_HOST_DELAY + tmp);\r
-               }\r
-       case USB_SPEED_HIGH:    /* ISOC or INTR */\r
-               // FIXME adjust for input vs output\r
-               if (isoc)\r
-                       tmp = HS_USECS (bytecount);\r
-               else\r
-                       tmp = HS_USECS_ISO (bytecount);\r
-               return tmp;\r
-       default:\r
-               dbg ("bogus device speed!");\r
-               return -1;\r
-       }\r
-}\r
-\r
-/*\r
- * usb_check_bandwidth():\r
- *\r
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;\r
- * bustime is from calc_bus_time(), but converted to microseconds.\r
- *\r
- * returns <bustime in us> if successful,\r
- * or -ENOSPC if bandwidth request fails.\r
- *\r
- * FIXME:\r
- * This initial implementation does not use Endpoint.bInterval\r
- * in managing bandwidth allocation.\r
- * It probably needs to be expanded to use Endpoint.bInterval.\r
- * This can be done as a later enhancement (correction).\r
- *\r
- * This will also probably require some kind of\r
- * frame allocation tracking...meaning, for example,\r
- * that if multiple drivers request interrupts every 10 USB frames,\r
- * they don't all have to be allocated at\r
- * frame numbers N, N+10, N+20, etc.  Some of them could be at\r
- * N+11, N+21, N+31, etc., and others at\r
- * N+12, N+22, N+32, etc.\r
- *\r
- * Similarly for isochronous transfers...\r
- *\r
- * Individual HCDs can schedule more directly ... this logic\r
- * is not correct for high speed transfers.\r
- */\r
-int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb)\r
-{\r
-       unsigned int    pipe = urb->pipe;\r
-       long            bustime;\r
-       int             is_in = usb_pipein (pipe);\r
-       int             is_iso = usb_pipeisoc (pipe);\r
-       int             old_alloc = dev->bus->bandwidth_allocated;\r
-       int             new_alloc;\r
-\r
-\r
-       bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,\r
-                       usb_maxpacket (dev, pipe, !is_in)));\r
-       if (is_iso)\r
-               bustime /= urb->number_of_packets;\r
-\r
-       new_alloc = old_alloc + (int) bustime;\r
-       if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {\r
-#ifdef DEBUG\r
-               char    *mode = \r
-#ifdef CONFIG_USB_BANDWIDTH\r
-                       "";\r
-#else\r
-                       "would have ";\r
-#endif\r
-               dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",\r
-                       mode, old_alloc, bustime, new_alloc);\r
-#endif\r
-#ifdef CONFIG_USB_BANDWIDTH\r
-               bustime = -ENOSPC;      /* report error */\r
-#endif\r
-       }\r
-\r
-       return bustime;\r
-}\r
-\r
-\r
-/**\r
- * usb_claim_bandwidth - records bandwidth for a periodic transfer\r
- * @dev: source/target of request\r
- * @urb: request (urb->dev == dev)\r
- * @bustime: bandwidth consumed, in (average) microseconds per frame\r
- * @isoc: true iff the request is isochronous\r
- *\r
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.\r
- * HCDs are expected not to overcommit periodic bandwidth, and to record such\r
- * reservations whenever endpoints are added to the periodic schedule.\r
- *\r
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's\r
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable\r
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how\r
- * large its periodic schedule is.\r
- */\r
-void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)\r
-{\r
-       dev->bus->bandwidth_allocated += bustime;\r
-       if (isoc)\r
-               dev->bus->bandwidth_isoc_reqs++;\r
-       else\r
-               dev->bus->bandwidth_int_reqs++;\r
-       urb->bandwidth = bustime;\r
-\r
-#ifdef USB_BANDWIDTH_MESSAGES\r
-       dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",\r
-               bustime,\r
-               isoc ? "ISOC" : "INTR",\r
-               dev->bus->bandwidth_allocated,\r
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);\r
-#endif\r
-}\r
-\r
-\r
-/**\r
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()\r
- * @dev: source/target of request\r
- * @urb: request (urb->dev == dev)\r
- * @isoc: true iff the request is isochronous\r
- *\r
- * This records that previously allocated bandwidth has been released.\r
- * Bandwidth is released when endpoints are removed from the host controller's\r
- * periodic schedule.\r
- */\r
-void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)\r
-{\r
-       dev->bus->bandwidth_allocated -= urb->bandwidth;\r
-       if (isoc)\r
-               dev->bus->bandwidth_isoc_reqs--;\r
-       else\r
-               dev->bus->bandwidth_int_reqs--;\r
-\r
-#ifdef USB_BANDWIDTH_MESSAGES\r
-       dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",\r
-               urb->bandwidth,\r
-               isoc ? "ISOC" : "INTR",\r
-               dev->bus->bandwidth_allocated,\r
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);\r
-#endif\r
-       urb->bandwidth = 0;\r
-}\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * Generic HC operations.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* called from khubd, or root hub init threads for hcd-private init */\r
-static int hcd_alloc_dev (struct usb_device *udev)\r
-{\r
-       struct hcd_dev          *dev;\r
-       struct usb_hcd          *hcd;\r
-       unsigned long           flags;\r
-\r
-       if (!udev || udev->hcpriv)\r
-               return -EINVAL;\r
-       if (!udev->bus || !udev->bus->hcpriv)\r
-               return -ENODEV;\r
-       hcd = udev->bus->hcpriv;\r
-       if (hcd->state == USB_STATE_QUIESCING)\r
-               return -ENOLINK;\r
-\r
-       dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);\r
-       if (dev == NULL)\r
-               return -ENOMEM;\r
-       memset (dev, 0, sizeof *dev);\r
-\r
-       INIT_LIST_HEAD (&dev->dev_list);\r
-       INIT_LIST_HEAD (&dev->urb_list);\r
-\r
-       spin_lock_irqsave (&hcd_data_lock, flags);\r
-       list_add (&dev->dev_list, &hcd->dev_list);\r
-       // refcount is implicit\r
-       udev->hcpriv = dev;\r
-       spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-\r
-       return 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static void urb_unlink (struct urb *urb)\r
-{\r
-       unsigned long           flags;\r
-       struct usb_device       *dev;\r
-\r
-       /* Release any periodic transfer bandwidth */\r
-       if (urb->bandwidth)\r
-               usb_release_bandwidth (urb->dev, urb,\r
-                       usb_pipeisoc (urb->pipe));\r
-\r
-       /* clear all state linking urb to this dev (and hcd) */\r
-\r
-       spin_lock_irqsave (&hcd_data_lock, flags);\r
-       list_del_init (&urb->urb_list);\r
-       dev = urb->dev;\r
-       spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-       usb_put_dev (dev);\r
-}\r
-\r
-\r
-/* may be called in any context with a valid urb->dev usecount\r
- * caller surrenders "ownership" of urb\r
- * expects usb_submit_urb() to have sanity checked and conditioned all\r
- * inputs in the urb\r
- */\r
-static int hcd_submit_urb (struct urb *urb, int mem_flags)\r
-{\r
-       int                     status;\r
-       struct usb_hcd          *hcd = urb->dev->bus->hcpriv;\r
-       struct hcd_dev          *dev = urb->dev->hcpriv;\r
-       unsigned long           flags;\r
-       \r
-\r
-       if (!hcd || !dev)\r
-               return -ENODEV;\r
-//     printk("submit_urb %p, # %i, t %i\n",urb,urb->dev->devnum,usb_pipetype(urb->pipe));\r
-       /*\r
-        * FIXME:  make urb timeouts be generic, keeping the HCD cores\r
-        * as simple as possible.\r
-        */\r
-\r
-       // NOTE:  a generic device/urb monitoring hook would go here.\r
-       // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)\r
-       // It would catch submission paths for all urbs.\r
-\r
-       /*\r
-        * Atomically queue the urb,  first to our records, then to the HCD.\r
-        * Access to urb->status is controlled by urb->lock ... changes on\r
-        * i/o completion (normal or fault) or unlinking.\r
-        */\r
-\r
-       // FIXME:  verify that quiescing hc works right (RH cleans up)\r
-\r
-       spin_lock_irqsave (&hcd_data_lock, flags);\r
-       if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {\r
-               usb_get_dev (urb->dev);\r
-               list_add_tail (&urb->urb_list, &dev->urb_list);\r
-               status = 0;\r
-       } else {\r
-               INIT_LIST_HEAD (&urb->urb_list);\r
-               status = -ESHUTDOWN;\r
-       }\r
-       spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-       if (status)\r
-               return status;\r
-\r
-       /* increment urb's reference count as part of giving it to the HCD\r
-        * (which now controls it).  HCD guarantees that it either returns\r
-        * an error or calls giveback(), but not both.\r
-        */\r
-\r
-       urb = usb_get_urb (urb);\r
-       if (urb->dev == hcd->self.root_hub) {\r
-               /* NOTE:  requirement on hub callers (usbfs and the hub\r
-                * driver, for now) that URBs' urb->transfer_buffer be\r
-                * valid and usb_buffer_{sync,unmap}() not be needed, since\r
-                * they could clobber root hub response data.\r
-                */\r
-               urb->transfer_flags |= URB_NO_DMA_MAP;\r
-               status = rh_urb_enqueue (hcd, urb);\r
-               goto done;\r
-       }\r
-\r
-       /* lower level hcd code should use *_dma exclusively,\r
-        * unless it uses pio or talks to another transport.\r
-        */\r
-       if (!(urb->transfer_flags & URB_NO_DMA_MAP)\r
-                       && hcd->controller->dma_mask) {\r
-               if (usb_pipecontrol (urb->pipe))\r
-                       urb->setup_dma = dma_map_single (\r
-                                       hcd->controller,\r
-                                       urb->setup_packet,\r
-                                       sizeof (struct usb_ctrlrequest),\r
-                                       DMA_TO_DEVICE);\r
-               if (urb->transfer_buffer_length != 0)\r
-                       urb->transfer_dma = dma_map_single (\r
-                                       hcd->controller,\r
-                                       urb->transfer_buffer,\r
-                                       urb->transfer_buffer_length,\r
-                                       usb_pipein (urb->pipe)\r
-                                           ? DMA_FROM_DEVICE\r
-                                           : DMA_TO_DEVICE);\r
-       }\r
-\r
-       status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);\r
-done:\r
-       if (status) {\r
-               usb_put_urb (urb);\r
-               urb_unlink (urb);\r
-       }\r
-       return status;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* called in any context */\r
-static int hcd_get_frame_number (struct usb_device *udev)\r
-{\r
-       struct usb_hcd  *hcd = (struct usb_hcd *)udev->bus->hcpriv;\r
-       return hcd->driver->get_frame_number (hcd);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* this makes the hcd giveback() the urb more quickly, by kicking it\r
- * off hardware queues (which may take a while) and returning it as\r
- * soon as practical.  we've already set up the urb's return status,\r
- * but we can't know if the callback completed already.\r
- */\r
-static void\r
-unlink1 (struct usb_hcd *hcd, struct urb *urb)\r
-{\r
-       if (urb == (struct urb *) hcd->rh_timer.data)\r
-               usb_rh_status_dequeue (hcd, urb);\r
-       else {\r
-               int             value;\r
-\r
-               /* failures "should" be harmless */\r
-               value = hcd->driver->urb_dequeue (hcd, urb);\r
-               if (value != 0)\r
-                       dev_dbg (hcd->controller,\r
-                               "dequeue %p --> %d\n",\r
-                               urb, value);\r
-       }\r
-}\r
-\r
-struct completion_splice {             // modified urb context:\r
-       /* did we complete? */\r
-       struct completion       done;\r
-\r
-       /* original urb data */\r
-       usb_complete_t          complete;\r
-       void                    *context;\r
-};\r
-\r
-static void unlink_complete (struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct completion_splice        *splice;\r
-\r
-       splice = (struct completion_splice *) urb->context;\r
-\r
-       /* issue original completion call */\r
-       urb->complete = splice->complete;\r
-       urb->context = splice->context;\r
-       urb->complete (urb, regs);\r
-\r
-       /* then let the synchronous unlink call complete */\r
-       complete (&splice->done);\r
-}\r
-\r
-/*\r
- * called in any context; note ASYNC_UNLINK restrictions\r
- *\r
- * caller guarantees urb won't be recycled till both unlink()\r
- * and the urb's completion function return\r
- */\r
-static int hcd_unlink_urb (struct urb *urb)\r
-{\r
-       struct hcd_dev                  *dev;\r
-       struct usb_hcd                  *hcd = 0;\r
-       struct device                   *sys = 0;\r
-       unsigned long                   flags;\r
-       struct completion_splice        splice;\r
-       int                             retval;\r
-\r
-       if (!urb)\r
-               return -EINVAL;\r
-\r
-       /*\r
-        * we contend for urb->status with the hcd core,\r
-        * which changes it while returning the urb.\r
-        *\r
-        * Caller guaranteed that the urb pointer hasn't been freed, and\r
-        * that it was submitted.  But as a rule it can't know whether or\r
-        * not it's already been unlinked ... so we respect the reversed\r
-        * lock sequence needed for the usb_hcd_giveback_urb() code paths\r
-        * (urb lock, then hcd_data_lock) in case some other CPU is now\r
-        * unlinking it.\r
-        */\r
-       spin_lock_irqsave (&urb->lock, flags);\r
-       spin_lock (&hcd_data_lock);\r
-\r
-       if (!urb->dev || !urb->dev->bus) {\r
-               retval = -ENODEV;\r
-               goto done;\r
-       }\r
-\r
-       dev = urb->dev->hcpriv;\r
-       sys = &urb->dev->dev;\r
-       hcd = urb->dev->bus->hcpriv;\r
-       if (!dev || !hcd) {\r
-               retval = -ENODEV;\r
-               goto done;\r
-       }\r
-\r
-       if (!urb->hcpriv) {\r
-               retval = -EINVAL;\r
-               goto done;\r
-       }\r
-\r
-       /* Any status except -EINPROGRESS means something already started to\r
-        * unlink this URB from the hardware.  So there's no more work to do.\r
-        *\r
-        * FIXME use better explicit urb state\r
-        */\r
-       if (urb->status != -EINPROGRESS) {\r
-               retval = -EBUSY;\r
-               goto done;\r
-       }\r
-\r
-       /* maybe set up to block until the urb's completion fires.  the\r
-        * lower level hcd code is always async, locking on urb->status\r
-        * updates; an intercepted completion unblocks us.\r
-        */\r
-       if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {\r
-               if (in_interrupt ()) {\r
-                       dev_dbg (hcd->controller, "non-async unlink in_interrupt");\r
-                       retval = -EWOULDBLOCK;\r
-                       goto done;\r
-               }\r
-               /* synchronous unlink: block till we see the completion */\r
-               init_completion (&splice.done);\r
-               splice.complete = urb->complete;\r
-               splice.context = urb->context;\r
-               urb->complete = unlink_complete;\r
-               urb->context = &splice;\r
-               urb->status = -ENOENT;\r
-       } else {\r
-               /* asynchronous unlink */\r
-               urb->status = -ECONNRESET;\r
-       }\r
-       spin_unlock (&hcd_data_lock);\r
-       spin_unlock_irqrestore (&urb->lock, flags);\r
-\r
-       // FIXME remove splicing, so this becomes unlink1 (hcd, urb);\r
-       if (urb == (struct urb *) hcd->rh_timer.data) {\r
-               usb_rh_status_dequeue (hcd, urb);\r
-               retval = 0;\r
-       } else {\r
-               retval = hcd->driver->urb_dequeue (hcd, urb);\r
-\r
-               /* hcds shouldn't really fail these calls, but... */\r
-               if (retval) {\r
-                       dev_dbg (sys, "dequeue %p --> %d\n", urb, retval);\r
-                       if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {\r
-                               spin_lock_irqsave (&urb->lock, flags);\r
-                               urb->complete = splice.complete;\r
-                               urb->context = splice.context;\r
-                               spin_unlock_irqrestore (&urb->lock, flags);\r
-                       }\r
-                       goto bye;\r
-               }\r
-       }\r
-\r
-       /* block till giveback, if needed */\r
-       if (urb->transfer_flags & URB_ASYNC_UNLINK)\r
-               return -EINPROGRESS;\r
-\r
-       wait_for_completion (&splice.done);\r
-       return 0;\r
-\r
-done:\r
-       spin_unlock (&hcd_data_lock);\r
-       spin_unlock_irqrestore (&urb->lock, flags);\r
-bye:\r
-       if (retval && sys && sys->driver)\r
-               dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);\r
-       return retval;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* disables the endpoint: cancels any pending urbs, then synchronizes with\r
- * the hcd to make sure all endpoint state is gone from hardware. use for\r
- * set_configuration, set_interface, driver removal, physical disconnect.\r
- *\r
- * example:  a qh stored in hcd_dev.ep[], holding state related to endpoint\r
- * type, maxpacket size, toggle, halt status, and scheduling.\r
- */\r
-static void hcd_endpoint_disable (struct usb_device *udev, int endpoint)\r
-{\r
-       unsigned long   flags;\r
-       struct hcd_dev  *dev;\r
-       struct usb_hcd  *hcd;\r
-       struct urb      *urb;\r
-       unsigned        epnum = endpoint & USB_ENDPOINT_NUMBER_MASK;\r
-\r
-       dev = udev->hcpriv;\r
-       hcd = udev->bus->hcpriv;\r
-\r
-rescan:\r
-       /* (re)block new requests, as best we can */\r
-       if (endpoint & USB_DIR_IN) {\r
-               usb_endpoint_halt (udev, epnum, 0);\r
-               udev->epmaxpacketin [epnum] = 0;\r
-       } else {\r
-               usb_endpoint_halt (udev, epnum, 1);\r
-               udev->epmaxpacketout [epnum] = 0;\r
-       }\r
-\r
-       /* then kill any current requests */\r
-       spin_lock_irqsave (&hcd_data_lock, flags);\r
-       list_for_each_entry (urb, &dev->urb_list, urb_list) {\r
-               int     tmp = urb->pipe;\r
-\r
-               /* ignore urbs for other endpoints */\r
-               if (usb_pipeendpoint (tmp) != epnum)\r
-                       continue;\r
-               if ((tmp ^ endpoint) & USB_DIR_IN)\r
-                       continue;\r
-\r
-               /* another cpu may be in hcd, spinning on hcd_data_lock\r
-                * to giveback() this urb.  the races here should be\r
-                * small, but a full fix needs a new "can't submit"\r
-                * urb state.\r
-                */\r
-               if (urb->status != -EINPROGRESS)\r
-                       continue;\r
-               usb_get_urb (urb);\r
-               spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-\r
-               spin_lock_irqsave (&urb->lock, flags);\r
-               tmp = urb->status;\r
-               if (tmp == -EINPROGRESS)\r
-                       urb->status = -ESHUTDOWN;\r
-               spin_unlock_irqrestore (&urb->lock, flags);\r
-\r
-               /* kick hcd unless it's already returning this */\r
-               if (tmp == -EINPROGRESS) {\r
-                       tmp = urb->pipe;\r
-                       unlink1 (hcd, urb);\r
-                       dev_dbg (hcd->controller,\r
-                               "shutdown urb %p pipe %08x ep%d%s%s\n",\r
-                               urb, tmp, usb_pipeendpoint (tmp),\r
-                               (tmp & USB_DIR_IN) ? "in" : "out",\r
-                               ({ char *s; \\r
-                                switch (usb_pipetype (tmp)) { \\r
-                                case PIPE_CONTROL:     s = ""; break; \\r
-                                case PIPE_BULK:        s = "-bulk"; break; \\r
-                                case PIPE_INTERRUPT:   s = "-intr"; break; \\r
-                                default:               s = "-iso"; break; \\r
-                               }; s;}));\r
-               }\r
-               usb_put_urb (urb);\r
-\r
-               /* list contents may have changed */\r
-               goto rescan;\r
-       }\r
-       spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-\r
-       /* synchronize with the hardware, so old configuration state\r
-        * clears out immediately (and will be freed).\r
-        */\r
-       might_sleep ();\r
-       if (hcd->driver->endpoint_disable)\r
-               hcd->driver->endpoint_disable (hcd, dev, endpoint);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup.\r
- * we're guaranteed that the device is fully quiesced.  also, that each\r
- * endpoint has been hcd_endpoint_disabled.\r
- */\r
-\r
-static int hcd_free_dev (struct usb_device *udev)\r
-{\r
-       struct hcd_dev          *dev;\r
-       struct usb_hcd          *hcd;\r
-       unsigned long           flags;\r
-\r
-       if (!udev || !udev->hcpriv)\r
-               return -EINVAL;\r
-\r
-       if (!udev->bus || !udev->bus->hcpriv)\r
-               return -ENODEV;\r
-\r
-       // should udev->devnum == -1 ??\r
-\r
-       dev = udev->hcpriv;\r
-       hcd = udev->bus->hcpriv;\r
-\r
-       /* device driver problem with refcounts? */\r
-       if (!list_empty (&dev->urb_list)) {\r
-               dev_dbg (hcd->controller, "free busy dev, %s devnum %d (bug!)\n",\r
-                       hcd->self.bus_name, udev->devnum);\r
-               return -EINVAL;\r
-       }\r
-\r
-       spin_lock_irqsave (&hcd_data_lock, flags);\r
-       list_del (&dev->dev_list);\r
-       udev->hcpriv = NULL;\r
-       spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-\r
-       kfree (dev);\r
-       return 0;\r
-}\r
-\r
-/*\r
- * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)\r
- *\r
- * When registering a USB bus through the HCD framework code, use this\r
- * usb_operations vector.  The PCI glue layer does so automatically; only\r
- * bus glue for non-PCI system busses will need to use this.\r
- */\r
-struct usb_operations usb_hcd_operations = {\r
-       .allocate =             hcd_alloc_dev,\r
-       .get_frame_number =     hcd_get_frame_number,\r
-       .submit_urb =           hcd_submit_urb,\r
-       .unlink_urb =           hcd_unlink_urb,\r
-       .deallocate =           hcd_free_dev,\r
-       .buffer_alloc =         hcd_buffer_alloc,\r
-       .buffer_free =          hcd_buffer_free,\r
-       .disable =              hcd_endpoint_disable,\r
-};\r
-EXPORT_SYMBOL (usb_hcd_operations);\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_hcd_giveback_urb - return URB from HCD to device driver\r
- * @hcd: host controller returning the URB\r
- * @urb: urb being returned to the USB device driver.\r
- * @regs: pt_regs, passed down to the URB completion handler\r
- * Context: in_interrupt()\r
- *\r
- * This hands the URB from HCD to its USB device driver, using its\r
- * completion function.  The HCD has freed all per-urb resources\r
- * (and is done using urb->hcpriv).  It also released all HCD locks;\r
- * the device driver won't cause problems if it frees, modifies,\r
- * or resubmits this URB.\r
- */\r
-void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)\r
-{\r
-       urb_unlink (urb);\r
-\r
-       // NOTE:  a generic device/urb monitoring hook would go here.\r
-       // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)\r
-       // It would catch exit/unlink paths for all urbs.\r
-\r
-       /* lower level hcd code should use *_dma exclusively */\r
-       if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {\r
-               if (usb_pipecontrol (urb->pipe))\r
-                       pci_unmap_single (hcd->pdev, urb->setup_dma,\r
-                                       sizeof (struct usb_ctrlrequest),\r
-                                       PCI_DMA_TODEVICE);\r
-               if (urb->transfer_buffer_length != 0)\r
-                       pci_unmap_single (hcd->pdev, urb->transfer_dma,\r
-                                       urb->transfer_buffer_length,\r
-                                       usb_pipein (urb->pipe)\r
-                                           ? PCI_DMA_FROMDEVICE\r
-                                           : PCI_DMA_TODEVICE);\r
-       }\r
-\r
-       /* pass ownership to the completion handler */\r
-       urb->complete (urb, regs);\r
-       usb_put_urb (urb);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_hcd_irq - hook IRQs to HCD framework (bus glue)\r
- * @irq: the IRQ being raised\r
- * @__hcd: pointer to the HCD whose IRQ is beinng signaled\r
- * @r: saved hardware registers\r
- *\r
- * When registering a USB bus through the HCD framework code, use this\r
- * to handle interrupts.  The PCI glue layer does so automatically; only\r
- * bus glue for non-PCI system busses will need to use this.\r
- */\r
-irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)\r
-{\r
-       struct usb_hcd          *hcd = __hcd;\r
-       int                     start = hcd->state;\r
-\r
-       if (unlikely (hcd->state == USB_STATE_HALT))    /* irq sharing? */\r
-               return IRQ_NONE;\r
-\r
-       hcd->driver->irq (hcd, r);\r
-       if (hcd->state != start && hcd->state == USB_STATE_HALT)\r
-               usb_hc_died (hcd);\r
-       return IRQ_HANDLED;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static void hcd_panic (void *_hcd)\r
-{\r
-       struct usb_hcd *hcd = _hcd;\r
-       hcd->driver->stop (hcd);\r
-}\r
-\r
-/**\r
- * usb_hc_died - report abnormal shutdown of a host controller (bus glue)\r
- * @hcd: pointer to the HCD representing the controller\r
- *\r
- * This is called by bus glue to report a USB host controller that died\r
- * while operations may still have been pending.  It's called automatically\r
- * by the PCI glue, so only glue for non-PCI busses should need to call it. \r
- */\r
-void STDCALL usb_hc_died (struct usb_hcd *hcd)\r
-{\r
-       struct list_head        *devlist, *urblist;\r
-       struct hcd_dev          *dev;\r
-       struct urb              *urb;\r
-       unsigned long           flags;\r
-       \r
-       /* flag every pending urb as done */\r
-       spin_lock_irqsave (&hcd_data_lock, flags);\r
-       list_for_each (devlist, &hcd->dev_list) {\r
-               dev = list_entry (devlist, struct hcd_dev, dev_list);\r
-               list_for_each (urblist, &dev->urb_list) {\r
-                       urb = list_entry (urblist, struct urb, urb_list);\r
-                       dev_dbg (hcd->controller, "shutdown %s urb %p pipe %x, current status %d\n",\r
-                               hcd->self.bus_name, urb, urb->pipe, urb->status);\r
-                       if (urb->status == -EINPROGRESS)\r
-                               urb->status = -ESHUTDOWN;\r
-               }\r
-       }\r
-       urb = (struct urb *) hcd->rh_timer.data;\r
-       if (urb)\r
-               urb->status = -ESHUTDOWN;\r
-       spin_unlock_irqrestore (&hcd_data_lock, flags);\r
-\r
-       /* hcd->stop() needs a task context */\r
-       INIT_WORK (&hcd->work, hcd_panic, hcd);\r
-       (void) schedule_work (&hcd->work);\r
-}\r
-\r
+/*
+ * (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
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2002
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if 0
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/uts.h>                 /* for UTS_SYSNAME */
+#include <linux/pci.h>                 /* for hcd->pdev and dma addressing */
+#include <linux/dma-mapping.h>
+#include <asm/byteorder.h>
+
+#include <linux/usb.h>
+#else
+#include "../usb_wrapper.h"
+//#define DEBUG
+#endif
+
+#include "hcd.h"
+
+// #define USB_BANDWIDTH_MESSAGES
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver framework
+ *
+ * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
+ * HCD-specific behaviors/bugs.
+ *
+ * This does error checks, tracks devices and urbs, and delegates to a
+ * "hc_driver" only for code (and data) that really needs to know about
+ * hardware differences.  That includes root hub registers, i/o queues,
+ * and so on ... but as little else as possible.
+ *
+ * Shared code includes most of the "root hub" code (these are emulated,
+ * though each HC's hardware works differently) and PCI glue, plus request
+ * tracking overhead.  The HCD code should only block on spinlocks or on
+ * hardware handshaking; blocking on software events (such as other kernel
+ * threads releasing resources, or completing actions) is all generic.
+ *
+ * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
+ * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
+ * only by the hub driver ... and that neither should be seen or used by
+ * usb client device drivers.
+ *
+ * Contributors of ideas or unattributed patches include: David Brownell,
+ * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ...
+ *
+ * HISTORY:
+ * 2002-02-21  Pull in most of the usb_bus support from usb.c; some
+ *             associated cleanup.  "usb_hcd" still != "usb_bus".
+ * 2001-12-12  Initial patch version for Linux 2.5.1 kernel.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* host controllers we manage */
+LIST_HEAD (usb_bus_list);
+EXPORT_SYMBOL_GPL (usb_bus_list);
+
+/* used when allocating bus numbers */
+#define USB_MAXBUS             64
+struct usb_busmap {
+       unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];
+};
+static struct usb_busmap busmap;
+
+/* used when updating list of hcds */
+DECLARE_MUTEX (usb_bus_list_lock);     /* exported only for usbfs */
+EXPORT_SYMBOL_GPL (usb_bus_list_lock);
+
+/* used when updating hcd data */
+static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sharable chunks of root hub code.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#define KERNEL_REL     ((LINUX_VERSION_CODE >> 16) & 0x0ff)
+#define KERNEL_VER     ((LINUX_VERSION_CODE >> 8) & 0x0ff)
+
+/* usb 2.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor [18] = {
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x00, 0x02, /*  __u16 bcdUSB; v2.0 */
+
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
+       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+       0x00, 0x00, /*  __u16 idVendor; */
+       0x00, 0x00, /*  __u16 idProduct; */
+       KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */
+
+       0x03,       /*  __u8  iManufacturer; */
+       0x02,       /*  __u8  iProduct; */
+       0x01,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
+/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
+
+/* usb 1.1 root hub device descriptor */
+static const u8 usb11_rh_dev_descriptor [18] = {
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x10, 0x01, /*  __u16 bcdUSB; v1.1 */
+
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
+       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+       0x00, 0x00, /*  __u16 idVendor; */
+       0x00, 0x00, /*  __u16 idProduct; */
+       KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */
+
+       0x03,       /*  __u8  iManufacturer; */
+       0x02,       /*  __u8  iProduct; */
+       0x01,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Configuration descriptors for our root hubs */
+
+static const u8 fs_rh_config_descriptor [] = {
+
+       /* one configuration */
+       0x09,       /*  __u8  bLength; */
+       0x02,       /*  __u8  bDescriptorType; Configuration */
+       0x19, 0x00, /*  __u16 wTotalLength; */
+       0x01,       /*  __u8  bNumInterfaces; (1) */
+       0x01,       /*  __u8  bConfigurationValue; */
+       0x00,       /*  __u8  iConfiguration; */
+       0x40,       /*  __u8  bmAttributes; 
+                                Bit 7: Bus-powered,
+                                    6: Self-powered,
+                                    5 Remote-wakwup,
+                                    4..0: resvd */
+       0x00,       /*  __u8  MaxPower; */
+      
+       /* USB 1.1:
+        * USB 2.0, single TT organization (mandatory):
+        *      one interface, protocol 0
+        *
+        * USB 2.0, multiple TT organization (optional):
+        *      two interfaces, protocols 1 (like single TT)
+        *      and 2 (multiple TT mode) ... config is
+        *      sometimes settable
+        *      NOT IMPLEMENTED
+        */
+
+       /* one interface */
+       0x09,       /*  __u8  if_bLength; */
+       0x04,       /*  __u8  if_bDescriptorType; Interface */
+       0x00,       /*  __u8  if_bInterfaceNumber; */
+       0x00,       /*  __u8  if_bAlternateSetting; */
+       0x01,       /*  __u8  if_bNumEndpoints; */
+       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  if_bInterfaceSubClass; */
+       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+       0x00,       /*  __u8  if_iInterface; */
+     
+       /* one endpoint (status change endpoint) */
+       0x07,       /*  __u8  ep_bLength; */
+       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+       0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const u8 hs_rh_config_descriptor [] = {
+
+       /* one configuration */
+       0x09,       /*  __u8  bLength; */
+       0x02,       /*  __u8  bDescriptorType; Configuration */
+       0x19, 0x00, /*  __u16 wTotalLength; */
+       0x01,       /*  __u8  bNumInterfaces; (1) */
+       0x01,       /*  __u8  bConfigurationValue; */
+       0x00,       /*  __u8  iConfiguration; */
+       0x40,       /*  __u8  bmAttributes; 
+                                Bit 7: Bus-powered,
+                                    6: Self-powered,
+                                    5 Remote-wakwup,
+                                    4..0: resvd */
+       0x00,       /*  __u8  MaxPower; */
+      
+       /* USB 1.1:
+        * USB 2.0, single TT organization (mandatory):
+        *      one interface, protocol 0
+        *
+        * USB 2.0, multiple TT organization (optional):
+        *      two interfaces, protocols 1 (like single TT)
+        *      and 2 (multiple TT mode) ... config is
+        *      sometimes settable
+        *      NOT IMPLEMENTED
+        */
+
+       /* one interface */
+       0x09,       /*  __u8  if_bLength; */
+       0x04,       /*  __u8  if_bDescriptorType; Interface */
+       0x00,       /*  __u8  if_bInterfaceNumber; */
+       0x00,       /*  __u8  if_bAlternateSetting; */
+       0x01,       /*  __u8  if_bNumEndpoints; */
+       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  if_bInterfaceSubClass; */
+       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+       0x00,       /*  __u8  if_iInterface; */
+     
+       /* one endpoint (status change endpoint) */
+       0x07,       /*  __u8  ep_bLength; */
+       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+       0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *s, u8 *utf, int utfmax)
+{
+       int retval;
+
+       for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+               *utf++ = *s++;
+               *utf++ = 0;
+       }
+       return retval;
+}
+
+/*
+ * rh_string - provides manufacturer, product and serial strings for root hub
+ * @id: the string ID number (1: serial number, 2: product, 3: vendor)
+ * @hcd: the host controller for this root hub
+ * @type: string describing our driver 
+ * @data: return packet in UTF-16 LE
+ * @len: length of the return packet
+ *
+ * Produces either a manufacturer, product or serial number string for the
+ * virtual root hub device.
+ */
+static int rh_string (
+       int             id,
+       struct usb_hcd  *hcd,
+       u8              *data,
+       int             len
+) {
+       char buf [100];
+
+       // language ids
+       if (id == 0) {
+               *data++ = 4; *data++ = 3;       /* 4 bytes string data */
+               *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */
+               return 4;
+
+       // serial number
+       } else if (id == 1) {
+               strcpy (buf, hcd->self.bus_name);
+
+       // product description
+       } else if (id == 2) {
+                strcpy (buf, hcd->product_desc);
+
+       // id 3 == vendor description
+       } else if (id == 3) {
+                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
+                       hcd->description);
+
+       // unsupported IDs --> "protocol stall"
+       } else
+           return 0;
+
+       data [0] = 2 * (strlen (buf) + 1);
+       data [1] = 3;   /* type == string */
+       return 2 + ascii2utf (buf, data + 2, len - 2);
+}
+
+
+/* Root hub control transfers execute synchronously */
+static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
+{
+       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+       u16             typeReq, wValue, wIndex, wLength;
+       const u8        *bufp = 0;
+       u8              *ubuf = urb->transfer_buffer;
+       int             len = 0;
+       //unsigned long flags;
+
+       typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
+       wValue   = le16_to_cpu (cmd->wValue);
+       wIndex   = le16_to_cpu (cmd->wIndex);
+       wLength  = le16_to_cpu (cmd->wLength);
+
+       if (wLength > urb->transfer_buffer_length)
+               goto error;
+
+       /* set up for success */
+       urb->status = 0;
+       urb->actual_length = wLength;
+       switch (typeReq) {
+
+       /* DEVICE REQUESTS */
+
+       case DeviceRequest | USB_REQ_GET_STATUS:
+               // DEVICE_REMOTE_WAKEUP
+               ubuf [0] = 1; // selfpowered
+               ubuf [1] = 0;
+                       /* FALLTHROUGH */
+       case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+       case DeviceOutRequest | USB_REQ_SET_FEATURE:
+               dev_dbg (hcd->controller, "no device features yet yet\n");
+               break;
+       case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+               ubuf [0] = 1;
+                       /* FALLTHROUGH */
+       case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+               break;
+       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+               switch (wValue & 0xff00) {
+               case USB_DT_DEVICE << 8:
+                       if (hcd->driver->flags & HCD_USB2)
+                               bufp = usb2_rh_dev_descriptor;
+                       else if (hcd->driver->flags & HCD_USB11)
+                               bufp = usb11_rh_dev_descriptor;
+                       else
+                               goto error;
+                       len = 18;
+                       break;
+               case USB_DT_CONFIG << 8:
+                       if (hcd->driver->flags & HCD_USB2) {
+                               bufp = hs_rh_config_descriptor;
+                               len = sizeof hs_rh_config_descriptor;
+                       } else {
+                               bufp = fs_rh_config_descriptor;
+                               len = sizeof fs_rh_config_descriptor;
+                       }
+                       break;
+               case USB_DT_STRING << 8:
+                       urb->actual_length = rh_string (
+                               wValue & 0xff, hcd,
+                               ubuf, wLength);
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case DeviceRequest | USB_REQ_GET_INTERFACE:
+               ubuf [0] = 0;
+                       /* FALLTHROUGH */
+       case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+               break;
+       case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+               // wValue == urb->dev->devaddr
+               dev_dbg (hcd->controller, "root hub device address %d\n",
+                       wValue);
+               break;
+
+       /* INTERFACE REQUESTS (no defined feature/status flags) */
+
+       /* ENDPOINT REQUESTS */
+
+       case EndpointRequest | USB_REQ_GET_STATUS:
+               // ENDPOINT_HALT flag
+               ubuf [0] = 0;
+               ubuf [1] = 0;
+                       /* FALLTHROUGH */
+       case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+       case EndpointOutRequest | USB_REQ_SET_FEATURE:
+               dev_dbg (hcd->controller, "no endpoint features yet\n");
+               break;
+
+       /* CLASS REQUESTS (and errors) */
+
+       default:
+               /* non-generic request */
+               urb->status = hcd->driver->hub_control (hcd,
+                       typeReq, wValue, wIndex,
+                       ubuf, wLength);
+               break;
+error:
+               /* "protocol stall" on error */
+               urb->status = -EPIPE;
+               dev_dbg (hcd->controller, "unsupported hub control message (maxchild %d)\n",
+                               urb->dev->maxchild);
+       }
+       if (urb->status) {
+               urb->actual_length = 0;
+               dev_dbg (hcd->controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",
+                       typeReq, wValue, wIndex, wLength, urb->status);
+       }
+       if (bufp) {
+               if (urb->transfer_buffer_length < len)
+                       len = urb->transfer_buffer_length;
+               urb->actual_length = len;
+               // always USB_DIR_IN, toward host
+               memcpy (ubuf, bufp, len);
+       }
+
+       /* any errors get returned through the urb completion */
+       local_irq_save (flags);
+       usb_hcd_giveback_urb (hcd, urb, NULL);
+       local_irq_restore (flags);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Root Hub interrupt transfers are synthesized with a timer.
+ * Completions are called in_interrupt() but not in_irq().
+ */
+
+static void rh_report_status (unsigned long ptr);
+
+static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
+{
+       int     len = 1 + (urb->dev->maxchild / 8);
+
+       /* rh_timer protected by hcd_data_lock */
+       if (hcd->rh_timer.data
+                       || urb->status != -EINPROGRESS
+                       || urb->transfer_buffer_length < len) {
+               dev_dbg (hcd->controller,
+                               "not queuing rh status urb, stat %d\n",
+                               urb->status);
+               return -EINVAL;
+       }
+
+       init_timer (&hcd->rh_timer);
+
+       hcd->rh_timer.function = rh_report_status;
+       hcd->rh_timer.data = (unsigned long) urb;
+       /* USB 2.0 spec says 256msec; this is close enough */
+       hcd->rh_timer.expires = jiffies + HZ/4;
+       add_timer (&hcd->rh_timer);
+       urb->hcpriv = hcd;      /* nonzero to indicate it's queued */
+       return 0;
+}
+
+/* timer callback */
+
+static void rh_report_status (unsigned long ptr)
+{
+       struct urb      *urb;
+       struct usb_hcd  *hcd;
+       int             length;
+       //unsigned long flags;
+
+       urb = (struct urb *) ptr;
+       local_irq_save (flags);
+       spin_lock (&urb->lock);
+
+       /* do nothing if the hc is gone or the urb's been unlinked */
+       if (!urb->dev
+                       || urb->status != -EINPROGRESS
+                       || (hcd = urb->dev->bus->hcpriv) == 0
+                       || !HCD_IS_RUNNING (hcd->state)) {
+               spin_unlock (&urb->lock);
+               local_irq_restore (flags);
+               return;
+       }
+
+       length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer);
+
+       /* complete the status urb, or retrigger the timer */
+       spin_lock (&hcd_data_lock);
+       if (length > 0) {
+               hcd->rh_timer.data = 0;
+               urb->actual_length = length;
+               urb->status = 0;
+               urb->hcpriv = 0;
+       } else
+               mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+       spin_unlock (&hcd_data_lock);
+       spin_unlock (&urb->lock);
+
+       /* local irqs are always blocked in completions */
+       if (length > 0)
+               usb_hcd_giveback_urb (hcd, urb, NULL);
+       local_irq_restore (flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
+{
+       if (usb_pipeint (urb->pipe)) {
+               int             retval;
+               unsigned long   flags;
+
+               spin_lock_irqsave (&hcd_data_lock, flags);
+               retval = rh_status_urb (hcd, urb);
+               spin_unlock_irqrestore (&hcd_data_lock, flags);
+               return retval;
+       }
+       if (usb_pipecontrol (urb->pipe))
+               return rh_call_control (hcd, urb);
+       else
+               return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+       //unsigned long flags;
+
+       /* note:  always a synchronous unlink */
+       del_timer_sync (&hcd->rh_timer);
+       hcd->rh_timer.data = 0;
+
+       local_irq_save (flags);
+       urb->hcpriv = 0;
+       usb_hcd_giveback_urb (hcd, urb, NULL);
+       local_irq_restore (flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* exported only within usbcore */
+void usb_bus_get (struct usb_bus *bus)
+{
+       atomic_inc (&bus->refcnt);
+}
+
+/* exported only within usbcore */
+void usb_bus_put (struct usb_bus *bus)
+{
+       if (atomic_dec_and_test (&bus->refcnt))
+               kfree (bus);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_bus_init - shared initialization code
+ * @bus: the bus structure being initialized
+ *
+ * This code is used to initialize a usb_bus structure, memory for which is
+ * separately managed.
+ */
+void STDCALL usb_bus_init (struct usb_bus *bus)
+{
+       memset (&bus->devmap, 0, sizeof(struct usb_devmap));
+
+       bus->devnum_next = 1;
+
+       bus->root_hub = NULL;
+       bus->hcpriv = NULL;
+       bus->busnum = -1;
+       bus->bandwidth_allocated = 0;
+       bus->bandwidth_int_reqs  = 0;
+       bus->bandwidth_isoc_reqs = 0;
+
+       INIT_LIST_HEAD (&bus->bus_list);
+
+       atomic_set (&bus->refcnt, 1);
+}
+
+/**
+ * usb_alloc_bus - creates a new USB host controller structure
+ * @op: pointer to a struct usb_operations that this bus structure should use
+ * Context: !in_interrupt()
+ *
+ * Creates a USB host controller bus structure with the specified 
+ * usb_operations and initializes all the necessary internal objects.
+ *
+ * If no memory is available, NULL is returned.
+ *
+ * The caller should call usb_free_bus() when it is finished with the structure.
+ */
+struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *op)
+{
+       struct usb_bus *bus;
+
+       bus = kmalloc (sizeof *bus, GFP_KERNEL);
+       if (!bus)
+               return NULL;
+       usb_bus_init (bus);
+       bus->op = op;
+       return bus;
+}
+
+/**
+ * usb_free_bus - frees the memory used by a bus structure
+ * @bus: pointer to the bus to free
+ *
+ * To be invoked by a HCD, only as the last step of decoupling from
+ * hardware.  It is an error to call this if the reference count is
+ * anything but one.  That would indicate that some system component
+ * did not correctly shut down, and thought the hardware was still
+ * accessible.
+ */
+void STDCALL usb_free_bus (struct usb_bus *bus)
+{
+       if (!bus)
+               return;
+       if (atomic_read (&bus->refcnt) != 1)
+               err ("usb_free_bus #%d, count != 1", bus->busnum);
+       usb_bus_put (bus);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_register_bus - registers the USB host controller with the usb core
+ * @bus: pointer to the bus to register
+ * Context: !in_interrupt()
+ *
+ * Assigns a bus number, and links the controller into usbcore data
+ * structures so that it can be seen by scanning the bus list.
+ */
+void STDCALL usb_register_bus(struct usb_bus *bus)
+{
+       int busnum;
+
+       down (&usb_bus_list_lock);
+       busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
+       if (busnum < USB_MAXBUS) {
+               set_bit (busnum, busmap.busmap);
+               bus->busnum = busnum;
+       } else
+               warn ("too many buses");
+
+       usb_bus_get (bus);
+
+       /* Add it to the list of buses */
+       list_add (&bus->bus_list, &usb_bus_list);
+       up (&usb_bus_list_lock);
+
+       usbfs_add_bus (bus);
+
+       dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+}
+
+/**
+ * usb_deregister_bus - deregisters the USB host controller
+ * @bus: pointer to the bus to deregister
+ * Context: !in_interrupt()
+ *
+ * Recycles the bus number, and unlinks the controller from usbcore data
+ * structures so that it won't be seen by scanning the bus list.
+ */
+void STDCALL usb_deregister_bus (struct usb_bus *bus)
+{
+       dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum);
+
+       /*
+        * NOTE: make sure that all the devices are removed by the
+        * controller code, as well as having it call this when cleaning
+        * itself up
+        */
+       down (&usb_bus_list_lock);
+       list_del (&bus->bus_list);
+       up (&usb_bus_list_lock);
+
+       usbfs_remove_bus (bus);
+
+       clear_bit (bus->busnum, busmap.busmap);
+
+       usb_bus_put (bus);
+}
+
+/**
+ * usb_register_root_hub - called by HCD to register its root hub 
+ * @usb_dev: the usb root hub device to be registered.
+ * @parent_dev: the parent device of this root hub.
+ *
+ * The USB host controller calls this function to register the root hub
+ * properly with the USB subsystem.  It sets up the device properly in
+ * the driverfs tree, and then calls usb_new_device() to register the
+ * usb device.
+ */
+int STDCALL usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
+{
+       int retval;
+
+       sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum);
+       usb_dev->state = USB_STATE_DEFAULT;
+       retval = usb_new_device (usb_dev, parent_dev);
+       if (retval)
+               dev_err (parent_dev, "can't register root hub for %s, %d\n",
+                               usb_dev->dev.bus_id, retval);
+       return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_calc_bus_time - approximate periodic transaction time in nanoseconds
+ * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
+ * @is_input: true iff the transaction sends data to the host
+ * @isoc: true for isochronous transactions, false for interrupt ones
+ * @bytecount: how many bytes in the transaction.
+ *
+ * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
+ * scheduled in software, this function is only used for such scheduling.
+ */
+long STDCALL usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
+{
+       unsigned long   tmp;
+
+       switch (speed) {
+       case USB_SPEED_LOW:     /* INTR only */
+               if (is_input) {
+                       tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
+                       return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
+               } else {
+                       tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
+                       return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
+               }
+       case USB_SPEED_FULL:    /* ISOC or INTR */
+               if (isoc) {
+                       tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+                       return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
+               } else {
+                       tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+                       return (9107L + BW_HOST_DELAY + tmp);
+               }
+       case USB_SPEED_HIGH:    /* ISOC or INTR */
+               // FIXME adjust for input vs output
+               if (isoc)
+                       tmp = HS_USECS (bytecount);
+               else
+                       tmp = HS_USECS_ISO (bytecount);
+               return tmp;
+       default:
+               dbg ("bogus device speed!");
+               return -1;
+       }
+}
+
+/*
+ * usb_check_bandwidth():
+ *
+ * old_alloc is from host_controller->bandwidth_allocated in microseconds;
+ * bustime is from calc_bus_time(), but converted to microseconds.
+ *
+ * returns <bustime in us> if successful,
+ * or -ENOSPC if bandwidth request fails.
+ *
+ * FIXME:
+ * This initial implementation does not use Endpoint.bInterval
+ * in managing bandwidth allocation.
+ * It probably needs to be expanded to use Endpoint.bInterval.
+ * This can be done as a later enhancement (correction).
+ *
+ * This will also probably require some kind of
+ * frame allocation tracking...meaning, for example,
+ * that if multiple drivers request interrupts every 10 USB frames,
+ * they don't all have to be allocated at
+ * frame numbers N, N+10, N+20, etc.  Some of them could be at
+ * N+11, N+21, N+31, etc., and others at
+ * N+12, N+22, N+32, etc.
+ *
+ * Similarly for isochronous transfers...
+ *
+ * Individual HCDs can schedule more directly ... this logic
+ * is not correct for high speed transfers.
+ */
+int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
+{
+       unsigned int    pipe = urb->pipe;
+       long            bustime;
+       int             is_in = usb_pipein (pipe);
+       int             is_iso = usb_pipeisoc (pipe);
+       int             old_alloc = dev->bus->bandwidth_allocated;
+       int             new_alloc;
+
+
+       bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
+                       usb_maxpacket (dev, pipe, !is_in)));
+       if (is_iso)
+               bustime /= urb->number_of_packets;
+
+       new_alloc = old_alloc + (int) bustime;
+       if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
+#ifdef DEBUG
+               char    *mode = 
+#ifdef CONFIG_USB_BANDWIDTH
+                       "";
+#else
+                       "would have ";
+#endif
+               dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
+                       mode, old_alloc, bustime, new_alloc);
+#endif
+#ifdef CONFIG_USB_BANDWIDTH
+               bustime = -ENOSPC;      /* report error */
+#endif
+       }
+
+       return bustime;
+}
+
+
+/**
+ * usb_claim_bandwidth - records bandwidth for a periodic transfer
+ * @dev: source/target of request
+ * @urb: request (urb->dev == dev)
+ * @bustime: bandwidth consumed, in (average) microseconds per frame
+ * @isoc: true iff the request is isochronous
+ *
+ * Bus bandwidth reservations are recorded purely for diagnostic purposes.
+ * HCDs are expected not to overcommit periodic bandwidth, and to record such
+ * reservations whenever endpoints are added to the periodic schedule.
+ *
+ * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
+ * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
+ * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
+ * large its periodic schedule is.
+ */
+void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
+{
+       dev->bus->bandwidth_allocated += bustime;
+       if (isoc)
+               dev->bus->bandwidth_isoc_reqs++;
+       else
+               dev->bus->bandwidth_int_reqs++;
+       urb->bandwidth = bustime;
+
+#ifdef USB_BANDWIDTH_MESSAGES
+       dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
+               bustime,
+               isoc ? "ISOC" : "INTR",
+               dev->bus->bandwidth_allocated,
+               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
+}
+
+
+/**
+ * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
+ * @dev: source/target of request
+ * @urb: request (urb->dev == dev)
+ * @isoc: true iff the request is isochronous
+ *
+ * This records that previously allocated bandwidth has been released.
+ * Bandwidth is released when endpoints are removed from the host controller's
+ * periodic schedule.
+ */
+void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
+{
+       dev->bus->bandwidth_allocated -= urb->bandwidth;
+       if (isoc)
+               dev->bus->bandwidth_isoc_reqs--;
+       else
+               dev->bus->bandwidth_int_reqs--;
+
+#ifdef USB_BANDWIDTH_MESSAGES
+       dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
+               urb->bandwidth,
+               isoc ? "ISOC" : "INTR",
+               dev->bus->bandwidth_allocated,
+               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
+       urb->bandwidth = 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic HC operations.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* called from khubd, or root hub init threads for hcd-private init */
+static int hcd_alloc_dev (struct usb_device *udev)
+{
+       struct hcd_dev          *dev;
+       struct usb_hcd          *hcd;
+       unsigned long           flags;
+
+       if (!udev || udev->hcpriv)
+               return -EINVAL;
+       if (!udev->bus || !udev->bus->hcpriv)
+               return -ENODEV;
+       hcd = udev->bus->hcpriv;
+       if (hcd->state == USB_STATE_QUIESCING)
+               return -ENOLINK;
+
+       dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);
+       if (dev == NULL)
+               return -ENOMEM;
+       memset (dev, 0, sizeof *dev);
+
+       INIT_LIST_HEAD (&dev->dev_list);
+       INIT_LIST_HEAD (&dev->urb_list);
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_add (&dev->dev_list, &hcd->dev_list);
+       // refcount is implicit
+       udev->hcpriv = dev;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void urb_unlink (struct urb *urb)
+{
+       unsigned long           flags;
+       struct usb_device       *dev;
+
+       /* Release any periodic transfer bandwidth */
+       if (urb->bandwidth)
+               usb_release_bandwidth (urb->dev, urb,
+                       usb_pipeisoc (urb->pipe));
+
+       /* clear all state linking urb to this dev (and hcd) */
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_del_init (&urb->urb_list);
+       dev = urb->dev;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+       usb_put_dev (dev);
+}
+
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+static int hcd_submit_urb (struct urb *urb, int mem_flags)
+{
+       int                     status;
+       struct usb_hcd          *hcd = urb->dev->bus->hcpriv;
+       struct hcd_dev          *dev = urb->dev->hcpriv;
+       unsigned long           flags;
+       
+
+       if (!hcd || !dev)
+               return -ENODEV;
+//     printk("submit_urb %p, # %i, t %i\n",urb,urb->dev->devnum,usb_pipetype(urb->pipe));
+       /*
+        * FIXME:  make urb timeouts be generic, keeping the HCD cores
+        * as simple as possible.
+        */
+
+       // NOTE:  a generic device/urb monitoring hook would go here.
+       // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
+       // It would catch submission paths for all urbs.
+
+       /*
+        * Atomically queue the urb,  first to our records, then to the HCD.
+        * Access to urb->status is controlled by urb->lock ... changes on
+        * i/o completion (normal or fault) or unlinking.
+        */
+
+       // FIXME:  verify that quiescing hc works right (RH cleans up)
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
+               usb_get_dev (urb->dev);
+               list_add_tail (&urb->urb_list, &dev->urb_list);
+               status = 0;
+       } else {
+               INIT_LIST_HEAD (&urb->urb_list);
+               status = -ESHUTDOWN;
+       }
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+       if (status)
+               return status;
+
+       /* increment urb's reference count as part of giving it to the HCD
+        * (which now controls it).  HCD guarantees that it either returns
+        * an error or calls giveback(), but not both.
+        */
+
+       urb = usb_get_urb (urb);
+       if (urb->dev == hcd->self.root_hub) {
+               /* NOTE:  requirement on hub callers (usbfs and the hub
+                * driver, for now) that URBs' urb->transfer_buffer be
+                * valid and usb_buffer_{sync,unmap}() not be needed, since
+                * they could clobber root hub response data.
+                */
+               urb->transfer_flags |= URB_NO_DMA_MAP;
+               status = rh_urb_enqueue (hcd, urb);
+               goto done;
+       }
+
+       /* lower level hcd code should use *_dma exclusively,
+        * unless it uses pio or talks to another transport.
+        */
+       if (!(urb->transfer_flags & URB_NO_DMA_MAP)
+                       && hcd->controller->dma_mask) {
+               if (usb_pipecontrol (urb->pipe))
+                       urb->setup_dma = dma_map_single (
+                                       hcd->controller,
+                                       urb->setup_packet,
+                                       sizeof (struct usb_ctrlrequest),
+                                       DMA_TO_DEVICE);
+               if (urb->transfer_buffer_length != 0)
+                       urb->transfer_dma = dma_map_single (
+                                       hcd->controller,
+                                       urb->transfer_buffer,
+                                       urb->transfer_buffer_length,
+                                       usb_pipein (urb->pipe)
+                                           ? DMA_FROM_DEVICE
+                                           : DMA_TO_DEVICE);
+       }
+
+       status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+done:
+       if (status) {
+               usb_put_urb (urb);
+               urb_unlink (urb);
+       }
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+static int hcd_get_frame_number (struct usb_device *udev)
+{
+       struct usb_hcd  *hcd = (struct usb_hcd *)udev->bus->hcpriv;
+       return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* this makes the hcd giveback() the urb more quickly, by kicking it
+ * off hardware queues (which may take a while) and returning it as
+ * soon as practical.  we've already set up the urb's return status,
+ * but we can't know if the callback completed already.
+ */
+static void
+unlink1 (struct usb_hcd *hcd, struct urb *urb)
+{
+       if (urb == (struct urb *) hcd->rh_timer.data)
+               usb_rh_status_dequeue (hcd, urb);
+       else {
+               int             value;
+
+               /* failures "should" be harmless */
+               value = hcd->driver->urb_dequeue (hcd, urb);
+               if (value != 0)
+                       dev_dbg (hcd->controller,
+                               "dequeue %p --> %d\n",
+                               urb, value);
+       }
+}
+
+struct completion_splice {             // modified urb context:
+       /* did we complete? */
+       struct completion       done;
+
+       /* original urb data */
+       usb_complete_t          complete;
+       void                    *context;
+};
+
+static void unlink_complete (struct urb *urb, struct pt_regs *regs)
+{
+       struct completion_splice        *splice;
+
+       splice = (struct completion_splice *) urb->context;
+
+       /* issue original completion call */
+       urb->complete = splice->complete;
+       urb->context = splice->context;
+       urb->complete (urb, regs);
+
+       /* then let the synchronous unlink call complete */
+       complete (&splice->done);
+}
+
+/*
+ * called in any context; note ASYNC_UNLINK restrictions
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+static int hcd_unlink_urb (struct urb *urb)
+{
+       struct hcd_dev                  *dev;
+       struct usb_hcd                  *hcd = 0;
+       struct device                   *sys = 0;
+       unsigned long                   flags;
+       struct completion_splice        splice;
+       int                             retval;
+
+       if (!urb)
+               return -EINVAL;
+
+       /*
+        * we contend for urb->status with the hcd core,
+        * which changes it while returning the urb.
+        *
+        * Caller guaranteed that the urb pointer hasn't been freed, and
+        * that it was submitted.  But as a rule it can't know whether or
+        * not it's already been unlinked ... so we respect the reversed
+        * lock sequence needed for the usb_hcd_giveback_urb() code paths
+        * (urb lock, then hcd_data_lock) in case some other CPU is now
+        * unlinking it.
+        */
+       spin_lock_irqsave (&urb->lock, flags);
+       spin_lock (&hcd_data_lock);
+
+       if (!urb->dev || !urb->dev->bus) {
+               retval = -ENODEV;
+               goto done;
+       }
+
+       dev = urb->dev->hcpriv;
+       sys = &urb->dev->dev;
+       hcd = urb->dev->bus->hcpriv;
+       if (!dev || !hcd) {
+               retval = -ENODEV;
+               goto done;
+       }
+
+       if (!urb->hcpriv) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       /* Any status except -EINPROGRESS means something already started to
+        * unlink this URB from the hardware.  So there's no more work to do.
+        *
+        * FIXME use better explicit urb state
+        */
+       if (urb->status != -EINPROGRESS) {
+               retval = -EBUSY;
+               goto done;
+       }
+
+       /* maybe set up to block until the urb's completion fires.  the
+        * lower level hcd code is always async, locking on urb->status
+        * updates; an intercepted completion unblocks us.
+        */
+       if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
+               if (in_interrupt ()) {
+                       dev_dbg (hcd->controller, "non-async unlink in_interrupt");
+                       retval = -EWOULDBLOCK;
+                       goto done;
+               }
+               /* synchronous unlink: block till we see the completion */
+               init_completion (&splice.done);
+               splice.complete = urb->complete;
+               splice.context = urb->context;
+               urb->complete = unlink_complete;
+               urb->context = &splice;
+               urb->status = -ENOENT;
+       } else {
+               /* asynchronous unlink */
+               urb->status = -ECONNRESET;
+       }
+       spin_unlock (&hcd_data_lock);
+       spin_unlock_irqrestore (&urb->lock, flags);
+
+       // FIXME remove splicing, so this becomes unlink1 (hcd, urb);
+       if (urb == (struct urb *) hcd->rh_timer.data) {
+               usb_rh_status_dequeue (hcd, urb);
+               retval = 0;
+       } else {
+               retval = hcd->driver->urb_dequeue (hcd, urb);
+
+               /* hcds shouldn't really fail these calls, but... */
+               if (retval) {
+                       dev_dbg (sys, "dequeue %p --> %d\n", urb, retval);
+                       if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
+                               spin_lock_irqsave (&urb->lock, flags);
+                               urb->complete = splice.complete;
+                               urb->context = splice.context;
+                               spin_unlock_irqrestore (&urb->lock, flags);
+                       }
+                       goto bye;
+               }
+       }
+
+       /* block till giveback, if needed */
+       if (urb->transfer_flags & URB_ASYNC_UNLINK)
+               return -EINPROGRESS;
+
+       wait_for_completion (&splice.done);
+       return 0;
+
+done:
+       spin_unlock (&hcd_data_lock);
+       spin_unlock_irqrestore (&urb->lock, flags);
+bye:
+       if (retval && sys && sys->driver)
+               dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* disables the endpoint: cancels any pending urbs, then synchronizes with
+ * the hcd to make sure all endpoint state is gone from hardware. use for
+ * set_configuration, set_interface, driver removal, physical disconnect.
+ *
+ * example:  a qh stored in hcd_dev.ep[], holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+static void hcd_endpoint_disable (struct usb_device *udev, int endpoint)
+{
+       unsigned long   flags;
+       struct hcd_dev  *dev;
+       struct usb_hcd  *hcd;
+       struct urb      *urb;
+       unsigned        epnum = endpoint & USB_ENDPOINT_NUMBER_MASK;
+
+       dev = udev->hcpriv;
+       hcd = udev->bus->hcpriv;
+
+rescan:
+       /* (re)block new requests, as best we can */
+       if (endpoint & USB_DIR_IN) {
+               usb_endpoint_halt (udev, epnum, 0);
+               udev->epmaxpacketin [epnum] = 0;
+       } else {
+               usb_endpoint_halt (udev, epnum, 1);
+               udev->epmaxpacketout [epnum] = 0;
+       }
+
+       /* then kill any current requests */
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_for_each_entry (urb, &dev->urb_list, urb_list) {
+               int     tmp = urb->pipe;
+
+               /* ignore urbs for other endpoints */
+               if (usb_pipeendpoint (tmp) != epnum)
+                       continue;
+               if ((tmp ^ endpoint) & USB_DIR_IN)
+                       continue;
+
+               /* another cpu may be in hcd, spinning on hcd_data_lock
+                * to giveback() this urb.  the races here should be
+                * small, but a full fix needs a new "can't submit"
+                * urb state.
+                */
+               if (urb->status != -EINPROGRESS)
+                       continue;
+               usb_get_urb (urb);
+               spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+               spin_lock_irqsave (&urb->lock, flags);
+               tmp = urb->status;
+               if (tmp == -EINPROGRESS)
+                       urb->status = -ESHUTDOWN;
+               spin_unlock_irqrestore (&urb->lock, flags);
+
+               /* kick hcd unless it's already returning this */
+               if (tmp == -EINPROGRESS) {
+                       tmp = urb->pipe;
+                       unlink1 (hcd, urb);
+                       dev_dbg (hcd->controller,
+                               "shutdown urb %p pipe %08x ep%d%s%s\n",
+                               urb, tmp, usb_pipeendpoint (tmp),
+                               (tmp & USB_DIR_IN) ? "in" : "out",
+                               ({ char *s; \
+                                switch (usb_pipetype (tmp)) { \
+                                case PIPE_CONTROL:     s = ""; break; \
+                                case PIPE_BULK:        s = "-bulk"; break; \
+                                case PIPE_INTERRUPT:   s = "-intr"; break; \
+                                default:               s = "-iso"; break; \
+                               }; s;}));
+               }
+               usb_put_urb (urb);
+
+               /* list contents may have changed */
+               goto rescan;
+       }
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       /* synchronize with the hardware, so old configuration state
+        * clears out immediately (and will be freed).
+        */
+       might_sleep ();
+       if (hcd->driver->endpoint_disable)
+               hcd->driver->endpoint_disable (hcd, dev, endpoint);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup.
+ * we're guaranteed that the device is fully quiesced.  also, that each
+ * endpoint has been hcd_endpoint_disabled.
+ */
+
+static int hcd_free_dev (struct usb_device *udev)
+{
+       struct hcd_dev          *dev;
+       struct usb_hcd          *hcd;
+       unsigned long           flags;
+
+       if (!udev || !udev->hcpriv)
+               return -EINVAL;
+
+       if (!udev->bus || !udev->bus->hcpriv)
+               return -ENODEV;
+
+       // should udev->devnum == -1 ??
+
+       dev = udev->hcpriv;
+       hcd = udev->bus->hcpriv;
+
+       /* device driver problem with refcounts? */
+       if (!list_empty (&dev->urb_list)) {
+               dev_dbg (hcd->controller, "free busy dev, %s devnum %d (bug!)\n",
+                       hcd->self.bus_name, udev->devnum);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_del (&dev->dev_list);
+       udev->hcpriv = NULL;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       kfree (dev);
+       return 0;
+}
+
+/*
+ * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
+ *
+ * When registering a USB bus through the HCD framework code, use this
+ * usb_operations vector.  The PCI glue layer does so automatically; only
+ * bus glue for non-PCI system busses will need to use this.
+ */
+struct usb_operations usb_hcd_operations = {
+       .allocate =             hcd_alloc_dev,
+       .get_frame_number =     hcd_get_frame_number,
+       .submit_urb =           hcd_submit_urb,
+       .unlink_urb =           hcd_unlink_urb,
+       .deallocate =           hcd_free_dev,
+       .buffer_alloc =         hcd_buffer_alloc,
+       .buffer_free =          hcd_buffer_free,
+       .disable =              hcd_endpoint_disable,
+};
+EXPORT_SYMBOL (usb_hcd_operations);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * @regs: pt_regs, passed down to the URB completion handler
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+{
+       urb_unlink (urb);
+
+       // NOTE:  a generic device/urb monitoring hook would go here.
+       // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
+       // It would catch exit/unlink paths for all urbs.
+
+       /* lower level hcd code should use *_dma exclusively */
+       if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
+               if (usb_pipecontrol (urb->pipe))
+                       pci_unmap_single (hcd->pdev, urb->setup_dma,
+                                       sizeof (struct usb_ctrlrequest),
+                                       PCI_DMA_TODEVICE);
+               if (urb->transfer_buffer_length != 0)
+                       pci_unmap_single (hcd->pdev, urb->transfer_dma,
+                                       urb->transfer_buffer_length,
+                                       usb_pipein (urb->pipe)
+                                           ? PCI_DMA_FROMDEVICE
+                                           : PCI_DMA_TODEVICE);
+       }
+
+       /* pass ownership to the completion handler */
+       urb->complete (urb, regs);
+       usb_put_urb (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
+ * @irq: the IRQ being raised
+ * @__hcd: pointer to the HCD whose IRQ is beinng signaled
+ * @r: saved hardware registers
+ *
+ * When registering a USB bus through the HCD framework code, use this
+ * to handle interrupts.  The PCI glue layer does so automatically; only
+ * bus glue for non-PCI system busses will need to use this.
+ */
+irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+       struct usb_hcd          *hcd = __hcd;
+       int                     start = hcd->state;
+
+       if (unlikely (hcd->state == USB_STATE_HALT))    /* irq sharing? */
+               return IRQ_NONE;
+
+       hcd->driver->irq (hcd, r);
+       if (hcd->state != start && hcd->state == USB_STATE_HALT)
+               usb_hc_died (hcd);
+       return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_panic (void *_hcd)
+{
+       struct usb_hcd *hcd = _hcd;
+       hcd->driver->stop (hcd);
+}
+
+/**
+ * usb_hc_died - report abnormal shutdown of a host controller (bus glue)
+ * @hcd: pointer to the HCD representing the controller
+ *
+ * This is called by bus glue to report a USB host controller that died
+ * while operations may still have been pending.  It's called automatically
+ * by the PCI glue, so only glue for non-PCI busses should need to call it. 
+ */
+void STDCALL usb_hc_died (struct usb_hcd *hcd)
+{
+       struct list_head        *devlist, *urblist;
+       struct hcd_dev          *dev;
+       struct urb              *urb;
+       unsigned long           flags;
+       
+       /* flag every pending urb as done */
+       spin_lock_irqsave (&hcd_data_lock, flags);
+       list_for_each (devlist, &hcd->dev_list) {
+               dev = list_entry (devlist, struct hcd_dev, dev_list);
+               list_for_each (urblist, &dev->urb_list) {
+                       urb = list_entry (urblist, struct urb, urb_list);
+                       dev_dbg (hcd->controller, "shutdown %s urb %p pipe %x, current status %d\n",
+                               hcd->self.bus_name, urb, urb->pipe, urb->status);
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = -ESHUTDOWN;
+               }
+       }
+       urb = (struct urb *) hcd->rh_timer.data;
+       if (urb)
+               urb->status = -ESHUTDOWN;
+       spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+       /* hcd->stop() needs a task context */
+       INIT_WORK (&hcd->work, hcd_panic, hcd);
+       (void) schedule_work (&hcd->work);
+}
+
index 266324d..a5b3859 100644 (file)
-/*\r
- * Copyright (c) 2001-2002 by David Brownell\r
- *\r
- * This program is free software; you can redistribute it and/or modify it\r
- * under the terms of the GNU General Public License as published by the\r
- * Free Software Foundation; either version 2 of the License, or (at your\r
- * option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
- * for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software Foundation,\r
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- */\r
-\r
-\r
-#ifdef __KERNEL__\r
-\r
-/* This file contains declarations of usbcore internals that are mostly\r
- * used or exposed by Host Controller Drivers.\r
- */\r
-\r
-/*\r
- * USB Packet IDs (PIDs)\r
- */\r
-#define USB_PID_UNDEF_0                        0xf0\r
-#define USB_PID_OUT                    0xe1\r
-#define USB_PID_ACK                    0xd2\r
-#define USB_PID_DATA0                  0xc3\r
-#define USB_PID_PING                   0xb4    /* USB 2.0 */\r
-#define USB_PID_SOF                    0xa5\r
-#define USB_PID_NYET                   0x96    /* USB 2.0 */\r
-#define USB_PID_DATA2                  0x87    /* USB 2.0 */\r
-#define USB_PID_SPLIT                  0x78    /* USB 2.0 */\r
-#define USB_PID_IN                     0x69\r
-#define USB_PID_NAK                    0x5a\r
-#define USB_PID_DATA1                  0x4b\r
-#define USB_PID_PREAMBLE               0x3c    /* Token mode */\r
-#define USB_PID_ERR                    0x3c    /* USB 2.0: handshake mode */\r
-#define USB_PID_SETUP                  0x2d\r
-#define USB_PID_STALL                  0x1e\r
-#define USB_PID_MDATA                  0x0f    /* USB 2.0 */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * USB Host Controller Driver (usb_hcd) framework\r
- *\r
- * Since "struct usb_bus" is so thin, you can't share much code in it.\r
- * This framework is a layer over that, and should be more sharable.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-struct usb_hcd {       /* usb_bus.hcpriv points to this */\r
-\r
-       /*\r
-        * housekeeping\r
-        */\r
-       struct usb_bus          self;           /* hcd is-a bus */\r
-\r
-       const char              *product_desc;  /* product/vendor string */\r
-       const char              *description;   /* "ehci-hcd" etc */\r
-\r
-       struct timer_list       rh_timer;       /* drives root hub */\r
-       struct list_head        dev_list;       /* devices on this bus */\r
-       struct work_struct      work;\r
-\r
-       /*\r
-        * hardware info/state\r
-        */\r
-       struct hc_driver        *driver;        /* hw-specific hooks */\r
-       int                     irq;            /* irq allocated */\r
-       void                    *regs;          /* device memory/io */\r
-       struct device           *controller;    /* handle to hardware */\r
-\r
-       /* a few non-PCI controllers exist, mostly for OHCI */\r
-       struct pci_dev          *pdev;          /* pci is typical */\r
-#ifdef CONFIG_PCI\r
-       int                     region;         /* pci region for regs */\r
-       u32                     pci_state [16]; /* for PM state save */\r
-       atomic_t                resume_count;   /* multiple resumes issue */\r
-#endif\r
-\r
-#define HCD_BUFFER_POOLS       4\r
-       struct pci_pool         *pool [HCD_BUFFER_POOLS];\r
-\r
-       int                     state;\r
-#      define  __ACTIVE                0x01\r
-#      define  __SLEEPY                0x02\r
-#      define  __SUSPEND               0x04\r
-#      define  __TRANSIENT             0x80\r
-\r
-#      define  USB_STATE_HALT          0\r
-#      define  USB_STATE_RUNNING       (__ACTIVE)\r
-#      define  USB_STATE_READY         (__ACTIVE|__SLEEPY)\r
-#      define  USB_STATE_QUIESCING     (__SUSPEND|__TRANSIENT|__ACTIVE)\r
-#      define  USB_STATE_RESUMING      (__SUSPEND|__TRANSIENT)\r
-#      define  USB_STATE_SUSPENDED     (__SUSPEND)\r
-\r
-#define        HCD_IS_RUNNING(state) ((state) & __ACTIVE)\r
-#define        HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)\r
-\r
-       /* more shared queuing code would be good; it should support\r
-        * smarter scheduling, handle transaction translators, etc;\r
-        * input size of periodic table to an interrupt scheduler. \r
-        * (ohci 32, uhci 1024, ehci 256/512/1024).\r
-        */\r
-};\r
-\r
-/* 2.4 does this a bit differently ... */\r
-static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)\r
-{\r
-       return &hcd->self;\r
-}\r
-\r
-\r
-struct hcd_dev {       /* usb_device.hcpriv points to this */\r
-       struct list_head        dev_list;       /* on this hcd */\r
-       struct list_head        urb_list;       /* pending on this dev */\r
-\r
-       /* per-configuration HC/HCD state, such as QH or ED */\r
-       void                    *ep[32];\r
-};\r
-\r
-// urb.hcpriv is really hardware-specific\r
-\r
-struct hcd_timeout {   /* timeouts we allocate */\r
-       struct list_head        timeout_list;\r
-       struct timer_list       timer;\r
-};\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * FIXME usb_operations should vanish or become hc_driver,\r
- * when usb_bus and usb_hcd become the same thing.\r
- */\r
-\r
-struct usb_operations {\r
-       int (*allocate)(struct usb_device *);\r
-       int (*deallocate)(struct usb_device *);\r
-       int (*get_frame_number) (struct usb_device *usb_dev);\r
-       int (*submit_urb) (struct urb *urb, int mem_flags);\r
-       int (*unlink_urb) (struct urb *urb);\r
-\r
-       /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */\r
-       void *(*buffer_alloc)(struct usb_bus *bus, size_t size,\r
-                       int mem_flags,\r
-                       dma_addr_t *dma);\r
-       void (*buffer_free)(struct usb_bus *bus, size_t size,\r
-                       void *addr, dma_addr_t dma);\r
-\r
-       void (*disable)(struct usb_device *udev, int bEndpointAddress);\r
-};\r
-\r
-/* each driver provides one of these, and hardware init support */\r
-\r
-struct pt_regs;\r
-\r
-// new struct from 2.6\r
-struct hc_driver {\r
-       const char      *description;   /* "ehci-hcd" etc */\r
-\r
-       /* irq handler */\r
-       irqreturn_t     (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);\r
-\r
-       int     flags;\r
-#define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */\r
-#define        HCD_USB11       0x0010          /* USB 1.1 */\r
-#define        HCD_USB2        0x0020          /* USB 2.0 */\r
-\r
-       /* called to init HCD and root hub */\r
-       int     (*reset) (struct usb_hcd *hcd);\r
-       int     (*start) (struct usb_hcd *hcd);\r
-\r
-       /* called after all devices were suspended */\r
-       int     (*suspend) (struct usb_hcd *hcd, u32 state);\r
-\r
-       /* called before any devices get resumed */\r
-       int     (*resume) (struct usb_hcd *hcd);\r
-\r
-       /* cleanly make HCD stop writing memory and doing I/O */\r
-       void    (*stop) (struct usb_hcd *hcd);\r
-\r
-       /* return current frame number */\r
-       int     (*get_frame_number) (struct usb_hcd *hcd);\r
-\r
-       /* memory lifecycle */\r
-       struct usb_hcd  *(*hcd_alloc) (void);\r
-       void            (*hcd_free) (struct usb_hcd *hcd);\r
-\r
-       /* manage i/o requests, device state */\r
-       int     (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,\r
-                                       int mem_flags);\r
-       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);\r
-\r
-       /* hw synch, freeing endpoint resources that urb_dequeue can't */\r
-       void    (*endpoint_disable)(struct usb_hcd *hcd,\r
-                       struct hcd_dev *dev, int bEndpointAddress);\r
-\r
-       /* root hub support */\r
-       int             (*hub_status_data) (struct usb_hcd *hcd, char *buf);\r
-       int             (*hub_control) (struct usb_hcd *hcd,\r
-                               u16 typeReq, u16 wValue, u16 wIndex,\r
-                               char *buf, u16 wLength);\r
-};\r
-\r
-// old version, "just in case"\r
-#if 0\r
-struct hc_driver {\r
-       const char      *description;   /* "ehci-hcd" etc */\r
-\r
-       /* irq handler */\r
-       void    (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);\r
-\r
-       int     flags;\r
-#define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */\r
-#define        HCD_USB11       0x0010          /* USB 1.1 */\r
-#define        HCD_USB2        0x0020          /* USB 2.0 */\r
-\r
-       /* called to init HCD and root hub */\r
-       int     (*start) (struct usb_hcd *hcd);\r
-\r
-       /* called after all devices were suspended */\r
-       int     (*suspend) (struct usb_hcd *hcd, u32 state);\r
-\r
-       /* called before any devices get resumed */\r
-       int     (*resume) (struct usb_hcd *hcd);\r
-\r
-       /* cleanly make HCD stop writing memory and doing I/O */\r
-       void    (*stop) (struct usb_hcd *hcd);\r
-\r
-       /* return current frame number */\r
-       int     (*get_frame_number) (struct usb_hcd *hcd);\r
-\r
-       /* memory lifecycle */\r
-       struct usb_hcd  *(*hcd_alloc) (void);\r
-       void            (*hcd_free) (struct usb_hcd *hcd);\r
-\r
-       /* manage i/o requests, device state */\r
-       int     (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,\r
-                                       int mem_flags);\r
-       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);\r
-\r
-       /* hw synch, freeing endpoint resources that urb_dequeue can't */\r
-       void    (*endpoint_disable)(struct usb_hcd *hcd,\r
-                       struct hcd_dev *dev, int bEndpointAddress);\r
-\r
-       /* root hub support */\r
-       int             (*hub_status_data) (struct usb_hcd *hcd, char *buf);\r
-       int             (*hub_control) (struct usb_hcd *hcd,\r
-                               u16 typeReq, u16 wValue, u16 wIndex,\r
-                               char *buf, u16 wLength);\r
-};\r
-#endif\r
-\r
-extern void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);\r
-extern void STDCALL usb_bus_init (struct usb_bus *bus);\r
-extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);\r
-\r
-#ifdef CONFIG_PCI\r
-struct pci_dev;\r
-struct pci_device_id;\r
-extern int STDCALL usb_hcd_pci_probe (struct pci_dev *dev,\r
-                               const struct pci_device_id *id);\r
-extern void STDCALL usb_hcd_pci_remove (struct pci_dev *dev);\r
-\r
-#ifdef CONFIG_PM\r
-// FIXME:  see Documentation/power/pci.txt (2.4.6 and later?)\r
-// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);\r
-extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);\r
-extern int usb_hcd_pci_resume (struct pci_dev *dev);\r
-// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);\r
-#endif /* CONFIG_PM */\r
-\r
-#endif /* CONFIG_PCI */\r
-\r
-/* pci-ish (pdev null is ok) buffer alloc/mapping support */\r
-int hcd_buffer_create (struct usb_hcd *hcd);\r
-void hcd_buffer_destroy (struct usb_hcd *hcd);\r
-\r
-void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,\r
-       int mem_flags, dma_addr_t *dma);\r
-void hcd_buffer_free (struct usb_bus *bus, size_t size,\r
-       void *addr, dma_addr_t dma);\r
-\r
-/* generic bus glue, needed for host controllers that don't use PCI */\r
-extern struct usb_operations usb_hcd_operations;\r
-extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);\r
-extern void STDCALL usb_hc_died (struct usb_hcd *hcd);\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/* Enumeration is only for the hub driver, or HCD virtual root hubs */\r
-extern int usb_new_device(struct usb_device *dev, struct device *parent);\r
-extern void STDCALL usb_connect(struct usb_device *dev);\r
-extern void usb_disconnect(struct usb_device **);\r
-\r
-/* exported to hub driver ONLY to support usb_reset_device () */\r
-extern int usb_get_configuration(struct usb_device *dev);\r
-extern void usb_set_maxpacket(struct usb_device *dev);\r
-extern void usb_destroy_configuration(struct usb_device *dev);\r
-extern int usb_set_address(struct usb_device *dev);\r
-\r
-/* use these only before the device's address has been set */\r
-#define usb_snddefctrl(dev)            ((PIPE_CONTROL << 30))\r
-#define usb_rcvdefctrl(dev)            ((PIPE_CONTROL << 30) | USB_DIR_IN)\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * HCD Root Hub support\r
- */\r
-\r
-#include "hub.h"\r
-\r
-/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */\r
-#define DeviceRequest \\r
-       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)\r
-#define DeviceOutRequest \\r
-       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)\r
-\r
-#define InterfaceRequest \\r
-       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)\r
-\r
-#define EndpointRequest \\r
-       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)\r
-#define EndpointOutRequest \\r
-       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)\r
-\r
-/* table 9.6 standard features */\r
-#define DEVICE_REMOTE_WAKEUP   1\r
-#define ENDPOINT_HALT          0\r
-\r
-/* class requests from the USB 2.0 hub spec, table 11-15 */\r
-/* GetBusState and SetHubDescriptor are optional, omitted */\r
-#define ClearHubFeature                (0x2000 | USB_REQ_CLEAR_FEATURE)\r
-#define ClearPortFeature       (0x2300 | USB_REQ_CLEAR_FEATURE)\r
-#define GetHubDescriptor       (0xa000 | USB_REQ_GET_DESCRIPTOR)\r
-#define GetHubStatus           (0xa000 | USB_REQ_GET_STATUS)\r
-#define GetPortStatus          (0xa300 | USB_REQ_GET_STATUS)\r
-#define SetHubFeature          (0x2000 | USB_REQ_SET_FEATURE)\r
-#define SetPortFeature         (0x2300 | USB_REQ_SET_FEATURE)\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * Generic bandwidth allocation constants/support\r
- */\r
-#define FRAME_TIME_USECS       1000L\r
-#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */\r
-               /* Trying not to use worst-case bit-stuffing\r
-                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */\r
-               /* bytecount = data payload byte count */\r
-\r
-#define NS_TO_US(ns)   ((ns + 500L) / 1000L)\r
-                       /* convert & round nanoseconds to microseconds */\r
-\r
-extern void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,\r
-               int bustime, int isoc);\r
-extern void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb,\r
-               int isoc);\r
-\r
-/*\r
- * Full/low speed bandwidth allocation constants/support.\r
- */\r
-#define BW_HOST_DELAY  1000L           /* nanoseconds */\r
-#define BW_HUB_LS_SETUP        333L            /* nanoseconds */\r
-                        /* 4 full-speed bit times (est.) */\r
-\r
-#define FRAME_TIME_BITS         12000L         /* frame = 1 millisecond */\r
-#define FRAME_TIME_MAX_BITS_ALLOC      (90L * FRAME_TIME_BITS / 100L)\r
-#define FRAME_TIME_MAX_USECS_ALLOC     (90L * FRAME_TIME_USECS / 100L)\r
-\r
-extern int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb);\r
-\r
-/*\r
- * Ceiling microseconds (typical) for that many bytes at high speed\r
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed\r
- * to preallocate bandwidth)\r
- */\r
-#define USB2_HOST_DELAY        5       /* nsec, guess */\r
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \\r
-       + ((2083UL * (3167 + BitTime (bytes)))/1000) \\r
-       + USB2_HOST_DELAY)\r
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \\r
-       + ((2083UL * (3167 + BitTime (bytes)))/1000) \\r
-       + USB2_HOST_DELAY)\r
-\r
-extern long STDCALL usb_calc_bus_time (int speed, int is_input,\r
-                       int isoc, int bytecount);\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-extern struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *);\r
-extern void STDCALL usb_free_bus (struct usb_bus *);\r
-\r
-extern void STDCALL usb_register_bus (struct usb_bus *);\r
-extern void STDCALL usb_deregister_bus (struct usb_bus *);\r
-\r
-extern int STDCALL usb_register_root_hub (struct usb_device *usb_dev,\r
-               struct device *parent_dev);\r
-\r
-/* for portability to 2.4, hcds should call this */\r
-static inline int hcd_register_root (struct usb_hcd *hcd)\r
-{\r
-       return usb_register_root_hub (\r
-               hcd_to_bus (hcd)->root_hub, hcd->controller);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* exported only within usbcore */\r
-\r
-extern struct list_head usb_bus_list;\r
-extern struct semaphore usb_bus_list_lock;\r
-\r
-extern void usb_bus_get (struct usb_bus *bus);\r
-extern void usb_bus_put (struct usb_bus *bus);\r
-\r
-extern int usb_find_interface_driver (struct usb_device *dev,\r
-       struct usb_interface *interface);\r
-\r
-#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))\r
-\r
-#define usb_endpoint_out(ep_dir)       (!((ep_dir) & USB_DIR_IN))\r
-\r
-/*\r
- * USB device fs stuff\r
- */\r
-\r
-#ifdef CONFIG_USB_DEVICEFS\r
-\r
-/*\r
- * these are expected to be called from the USB core/hub thread\r
- * with the kernel lock held\r
- */\r
-extern void usbfs_add_bus(struct usb_bus *bus);\r
-extern void usbfs_remove_bus(struct usb_bus *bus);\r
-extern void usbfs_add_device(struct usb_device *dev);\r
-extern void usbfs_remove_device(struct usb_device *dev);\r
-extern void usbfs_update_special (void);\r
-\r
-extern int usbfs_init(void);\r
-extern void usbfs_cleanup(void);\r
-\r
-#else /* CONFIG_USB_DEVICEFS */\r
-\r
-static inline void usbfs_add_bus(struct usb_bus *bus) {}\r
-static inline void usbfs_remove_bus(struct usb_bus *bus) {}\r
-static inline void usbfs_add_device(struct usb_device *dev) {}\r
-static inline void usbfs_remove_device(struct usb_device *dev) {}\r
-static inline void usbfs_update_special (void) {}\r
-\r
-static inline int usbfs_init(void) { return 0; }\r
-static inline void usbfs_cleanup(void) { }\r
-\r
-#endif /* CONFIG_USB_DEVICEFS */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */\r
-// bleech -- resurfaced in 2.4.11 or 2.4.12\r
-#define bitmap         DeviceRemovable\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* random stuff */\r
-\r
-#define        RUN_CONTEXT (in_irq () ? "in_irq" \\r
-               : (in_interrupt () ? "in_interrupt" : "can sleep"))\r
-\r
-\r
-#endif /* __KERNEL__ */\r
-\r
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifdef __KERNEL__
+
+/* This file contains declarations of usbcore internals that are mostly
+ * used or exposed by Host Controller Drivers.
+ */
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_UNDEF_0                        0xf0
+#define USB_PID_OUT                    0xe1
+#define USB_PID_ACK                    0xd2
+#define USB_PID_DATA0                  0xc3
+#define USB_PID_PING                   0xb4    /* USB 2.0 */
+#define USB_PID_SOF                    0xa5
+#define USB_PID_NYET                   0x96    /* USB 2.0 */
+#define USB_PID_DATA2                  0x87    /* USB 2.0 */
+#define USB_PID_SPLIT                  0x78    /* USB 2.0 */
+#define USB_PID_IN                     0x69
+#define USB_PID_NAK                    0x5a
+#define USB_PID_DATA1                  0x4b
+#define USB_PID_PREAMBLE               0x3c    /* Token mode */
+#define USB_PID_ERR                    0x3c    /* USB 2.0: handshake mode */
+#define USB_PID_SETUP                  0x2d
+#define USB_PID_STALL                  0x1e
+#define USB_PID_MDATA                  0x0f    /* USB 2.0 */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver (usb_hcd) framework
+ *
+ * Since "struct usb_bus" is so thin, you can't share much code in it.
+ * This framework is a layer over that, and should be more sharable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_hcd {       /* usb_bus.hcpriv points to this */
+
+       /*
+        * housekeeping
+        */
+       struct usb_bus          self;           /* hcd is-a bus */
+
+       const char              *product_desc;  /* product/vendor string */
+       const char              *description;   /* "ehci-hcd" etc */
+
+       struct timer_list       rh_timer;       /* drives root hub */
+       struct list_head        dev_list;       /* devices on this bus */
+       struct work_struct      work;
+
+       /*
+        * hardware info/state
+        */
+       struct hc_driver        *driver;        /* hw-specific hooks */
+       int                     irq;            /* irq allocated */
+       void                    *regs;          /* device memory/io */
+       struct device           *controller;    /* handle to hardware */
+
+       /* a few non-PCI controllers exist, mostly for OHCI */
+       struct pci_dev          *pdev;          /* pci is typical */
+#ifdef CONFIG_PCI
+       int                     region;         /* pci region for regs */
+       u32                     pci_state [16]; /* for PM state save */
+       atomic_t                resume_count;   /* multiple resumes issue */
+#endif
+
+#define HCD_BUFFER_POOLS       4
+       struct pci_pool         *pool [HCD_BUFFER_POOLS];
+
+       int                     state;
+#      define  __ACTIVE                0x01
+#      define  __SLEEPY                0x02
+#      define  __SUSPEND               0x04
+#      define  __TRANSIENT             0x80
+
+#      define  USB_STATE_HALT          0
+#      define  USB_STATE_RUNNING       (__ACTIVE)
+#      define  USB_STATE_READY         (__ACTIVE|__SLEEPY)
+#      define  USB_STATE_QUIESCING     (__SUSPEND|__TRANSIENT|__ACTIVE)
+#      define  USB_STATE_RESUMING      (__SUSPEND|__TRANSIENT)
+#      define  USB_STATE_SUSPENDED     (__SUSPEND)
+
+#define        HCD_IS_RUNNING(state) ((state) & __ACTIVE)
+#define        HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
+
+       /* more shared queuing code would be good; it should support
+        * smarter scheduling, handle transaction translators, etc;
+        * input size of periodic table to an interrupt scheduler. 
+        * (ohci 32, uhci 1024, ehci 256/512/1024).
+        */
+};
+
+/* 2.4 does this a bit differently ... */
+static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+{
+       return &hcd->self;
+}
+
+
+struct hcd_dev {       /* usb_device.hcpriv points to this */
+       struct list_head        dev_list;       /* on this hcd */
+       struct list_head        urb_list;       /* pending on this dev */
+
+       /* per-configuration HC/HCD state, such as QH or ED */
+       void                    *ep[32];
+};
+
+// urb.hcpriv is really hardware-specific
+
+struct hcd_timeout {   /* timeouts we allocate */
+       struct list_head        timeout_list;
+       struct timer_list       timer;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * FIXME usb_operations should vanish or become hc_driver,
+ * when usb_bus and usb_hcd become the same thing.
+ */
+
+struct usb_operations {
+       int (*allocate)(struct usb_device *);
+       int (*deallocate)(struct usb_device *);
+       int (*get_frame_number) (struct usb_device *usb_dev);
+       int (*submit_urb) (struct urb *urb, int mem_flags);
+       int (*unlink_urb) (struct urb *urb);
+
+       /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
+       void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
+                       int mem_flags,
+                       dma_addr_t *dma);
+       void (*buffer_free)(struct usb_bus *bus, size_t size,
+                       void *addr, dma_addr_t dma);
+
+       void (*disable)(struct usb_device *udev, int bEndpointAddress);
+};
+
+/* each driver provides one of these, and hardware init support */
+
+struct pt_regs;
+
+// new struct from 2.6
+struct hc_driver {
+       const char      *description;   /* "ehci-hcd" etc */
+
+       /* irq handler */
+       irqreturn_t     (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);
+
+       int     flags;
+#define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */
+#define        HCD_USB11       0x0010          /* USB 1.1 */
+#define        HCD_USB2        0x0020          /* USB 2.0 */
+
+       /* called to init HCD and root hub */
+       int     (*reset) (struct usb_hcd *hcd);
+       int     (*start) (struct usb_hcd *hcd);
+
+       /* called after all devices were suspended */
+       int     (*suspend) (struct usb_hcd *hcd, u32 state);
+
+       /* called before any devices get resumed */
+       int     (*resume) (struct usb_hcd *hcd);
+
+       /* cleanly make HCD stop writing memory and doing I/O */
+       void    (*stop) (struct usb_hcd *hcd);
+
+       /* return current frame number */
+       int     (*get_frame_number) (struct usb_hcd *hcd);
+
+       /* memory lifecycle */
+       struct usb_hcd  *(*hcd_alloc) (void);
+       void            (*hcd_free) (struct usb_hcd *hcd);
+
+       /* manage i/o requests, device state */
+       int     (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,
+                                       int mem_flags);
+       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+
+       /* hw synch, freeing endpoint resources that urb_dequeue can't */
+       void    (*endpoint_disable)(struct usb_hcd *hcd,
+                       struct hcd_dev *dev, int bEndpointAddress);
+
+       /* root hub support */
+       int             (*hub_status_data) (struct usb_hcd *hcd, char *buf);
+       int             (*hub_control) (struct usb_hcd *hcd,
+                               u16 typeReq, u16 wValue, u16 wIndex,
+                               char *buf, u16 wLength);
+};
+
+// old version, "just in case"
+#if 0
+struct hc_driver {
+       const char      *description;   /* "ehci-hcd" etc */
+
+       /* irq handler */
+       void    (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);
+
+       int     flags;
+#define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */
+#define        HCD_USB11       0x0010          /* USB 1.1 */
+#define        HCD_USB2        0x0020          /* USB 2.0 */
+
+       /* called to init HCD and root hub */
+       int     (*start) (struct usb_hcd *hcd);
+
+       /* called after all devices were suspended */
+       int     (*suspend) (struct usb_hcd *hcd, u32 state);
+
+       /* called before any devices get resumed */
+       int     (*resume) (struct usb_hcd *hcd);
+
+       /* cleanly make HCD stop writing memory and doing I/O */
+       void    (*stop) (struct usb_hcd *hcd);
+
+       /* return current frame number */
+       int     (*get_frame_number) (struct usb_hcd *hcd);
+
+       /* memory lifecycle */
+       struct usb_hcd  *(*hcd_alloc) (void);
+       void            (*hcd_free) (struct usb_hcd *hcd);
+
+       /* manage i/o requests, device state */
+       int     (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,
+                                       int mem_flags);
+       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+
+       /* hw synch, freeing endpoint resources that urb_dequeue can't */
+       void    (*endpoint_disable)(struct usb_hcd *hcd,
+                       struct hcd_dev *dev, int bEndpointAddress);
+
+       /* root hub support */
+       int             (*hub_status_data) (struct usb_hcd *hcd, char *buf);
+       int             (*hub_control) (struct usb_hcd *hcd,
+                               u16 typeReq, u16 wValue, u16 wIndex,
+                               char *buf, u16 wLength);
+};
+#endif
+
+extern void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
+extern void STDCALL usb_bus_init (struct usb_bus *bus);
+extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
+
+#ifdef CONFIG_PCI
+struct pci_dev;
+struct pci_device_id;
+extern int STDCALL usb_hcd_pci_probe (struct pci_dev *dev,
+                               const struct pci_device_id *id);
+extern void STDCALL usb_hcd_pci_remove (struct pci_dev *dev);
+
+#ifdef CONFIG_PM
+// FIXME:  see Documentation/power/pci.txt (2.4.6 and later?)
+// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_resume (struct pci_dev *dev);
+// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);
+#endif /* CONFIG_PM */
+
+#endif /* CONFIG_PCI */
+
+/* pci-ish (pdev null is ok) buffer alloc/mapping support */
+int hcd_buffer_create (struct usb_hcd *hcd);
+void hcd_buffer_destroy (struct usb_hcd *hcd);
+
+void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,
+       int mem_flags, dma_addr_t *dma);
+void hcd_buffer_free (struct usb_bus *bus, size_t size,
+       void *addr, dma_addr_t dma);
+
+/* generic bus glue, needed for host controllers that don't use PCI */
+extern struct usb_operations usb_hcd_operations;
+extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+extern void STDCALL usb_hc_died (struct usb_hcd *hcd);
+
+/* -------------------------------------------------------------------------- */
+
+/* Enumeration is only for the hub driver, or HCD virtual root hubs */
+extern int usb_new_device(struct usb_device *dev, struct device *parent);
+extern void STDCALL usb_connect(struct usb_device *dev);
+extern void usb_disconnect(struct usb_device **);
+
+/* exported to hub driver ONLY to support usb_reset_device () */
+extern int usb_get_configuration(struct usb_device *dev);
+extern void usb_set_maxpacket(struct usb_device *dev);
+extern void usb_destroy_configuration(struct usb_device *dev);
+extern int usb_set_address(struct usb_device *dev);
+
+/* use these only before the device's address has been set */
+#define usb_snddefctrl(dev)            ((PIPE_CONTROL << 30))
+#define usb_rcvdefctrl(dev)            ((PIPE_CONTROL << 30) | USB_DIR_IN)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * HCD Root Hub support
+ */
+
+#include "hub.h"
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest \
+       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+
+#define InterfaceRequest \
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+#define EndpointRequest \
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointOutRequest \
+       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+/* table 9.6 standard features */
+#define DEVICE_REMOTE_WAKEUP   1
+#define ENDPOINT_HALT          0
+
+/* class requests from the USB 2.0 hub spec, table 11-15 */
+/* GetBusState and SetHubDescriptor are optional, omitted */
+#define ClearHubFeature                (0x2000 | USB_REQ_CLEAR_FEATURE)
+#define ClearPortFeature       (0x2300 | USB_REQ_CLEAR_FEATURE)
+#define GetHubDescriptor       (0xa000 | USB_REQ_GET_DESCRIPTOR)
+#define GetHubStatus           (0xa000 | USB_REQ_GET_STATUS)
+#define GetPortStatus          (0xa300 | USB_REQ_GET_STATUS)
+#define SetHubFeature          (0x2000 | USB_REQ_SET_FEATURE)
+#define SetPortFeature         (0x2300 | USB_REQ_SET_FEATURE)
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic bandwidth allocation constants/support
+ */
+#define FRAME_TIME_USECS       1000L
+#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
+               /* Trying not to use worst-case bit-stuffing
+                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+               /* bytecount = data payload byte count */
+
+#define NS_TO_US(ns)   ((ns + 500L) / 1000L)
+                       /* convert & round nanoseconds to microseconds */
+
+extern void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
+               int bustime, int isoc);
+extern void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
+               int isoc);
+
+/*
+ * Full/low speed bandwidth allocation constants/support.
+ */
+#define BW_HOST_DELAY  1000L           /* nanoseconds */
+#define BW_HUB_LS_SETUP        333L            /* nanoseconds */
+                        /* 4 full-speed bit times (est.) */
+
+#define FRAME_TIME_BITS         12000L         /* frame = 1 millisecond */
+#define FRAME_TIME_MAX_BITS_ALLOC      (90L * FRAME_TIME_BITS / 100L)
+#define FRAME_TIME_MAX_USECS_ALLOC     (90L * FRAME_TIME_USECS / 100L)
+
+extern int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define USB2_HOST_DELAY        5       /* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+       + ((2083UL * (3167 + BitTime (bytes)))/1000) \
+       + USB2_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+       + ((2083UL * (3167 + BitTime (bytes)))/1000) \
+       + USB2_HOST_DELAY)
+
+extern long STDCALL usb_calc_bus_time (int speed, int is_input,
+                       int isoc, int bytecount);
+
+/*-------------------------------------------------------------------------*/
+
+extern struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *);
+extern void STDCALL usb_free_bus (struct usb_bus *);
+
+extern void STDCALL usb_register_bus (struct usb_bus *);
+extern void STDCALL usb_deregister_bus (struct usb_bus *);
+
+extern int STDCALL usb_register_root_hub (struct usb_device *usb_dev,
+               struct device *parent_dev);
+
+/* for portability to 2.4, hcds should call this */
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+       return usb_register_root_hub (
+               hcd_to_bus (hcd)->root_hub, hcd->controller);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* exported only within usbcore */
+
+extern struct list_head usb_bus_list;
+extern struct semaphore usb_bus_list_lock;
+
+extern void usb_bus_get (struct usb_bus *bus);
+extern void usb_bus_put (struct usb_bus *bus);
+
+extern int usb_find_interface_driver (struct usb_device *dev,
+       struct usb_interface *interface);
+
+#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
+
+#define usb_endpoint_out(ep_dir)       (!((ep_dir) & USB_DIR_IN))
+
+/*
+ * USB device fs stuff
+ */
+
+#ifdef CONFIG_USB_DEVICEFS
+
+/*
+ * these are expected to be called from the USB core/hub thread
+ * with the kernel lock held
+ */
+extern void usbfs_add_bus(struct usb_bus *bus);
+extern void usbfs_remove_bus(struct usb_bus *bus);
+extern void usbfs_add_device(struct usb_device *dev);
+extern void usbfs_remove_device(struct usb_device *dev);
+extern void usbfs_update_special (void);
+
+extern int usbfs_init(void);
+extern void usbfs_cleanup(void);
+
+#else /* CONFIG_USB_DEVICEFS */
+
+static inline void usbfs_add_bus(struct usb_bus *bus) {}
+static inline void usbfs_remove_bus(struct usb_bus *bus) {}
+static inline void usbfs_add_device(struct usb_device *dev) {}
+static inline void usbfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_update_special (void) {}
+
+static inline int usbfs_init(void) { return 0; }
+static inline void usbfs_cleanup(void) { }
+
+#endif /* CONFIG_USB_DEVICEFS */
+
+/*-------------------------------------------------------------------------*/
+
+/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
+// bleech -- resurfaced in 2.4.11 or 2.4.12
+#define bitmap         DeviceRemovable
+
+
+/*-------------------------------------------------------------------------*/
+
+/* random stuff */
+
+#define        RUN_CONTEXT (in_irq () ? "in_irq" \
+               : (in_interrupt () ? "in_interrupt" : "can sleep"))
+
+
+#endif /* __KERNEL__ */
+
index 1b7e820..8efb82d 100644 (file)
-/*\r
- * USB hub driver.\r
- *\r
- * (C) Copyright 1999 Linus Torvalds\r
- * (C) Copyright 1999 Johannes Erdfelt\r
- * (C) Copyright 1999 Gregory P. Smith\r
- * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)\r
- *\r
- */\r
-#define DEBUG\r
-#if 0\r
-#include <linux/config.h>\r
-#include <linux/kernel.h>\r
-#include <linux/errno.h>\r
-#include <linux/module.h>\r
-#include <linux/completion.h>\r
-#include <linux/sched.h>\r
-#include <linux/list.h>\r
-#include <linux/slab.h>\r
-#include <linux/smp_lock.h>\r
-#include <linux/ioctl.h>\r
-#ifdef CONFIG_USB_DEBUG\r
-       #define DEBUG\r
-#else\r
-       #undef DEBUG\r
-#endif\r
-#include <linux/usb.h>\r
-#include <linux/usbdevice_fs.h>\r
-#include <linux/suspend.h>\r
-\r
-#include <asm/semaphore.h>\r
-#include <asm/uaccess.h>\r
-#include <asm/byteorder.h>\r
-\r
-#include "hcd.h"\r
-#include "hub.h"\r
-#else\r
-#include "../usb_wrapper.h"\r
-#include "hcd.h"\r
-#include "hub.h"\r
-#define DEBUG\r
-#endif\r
-\r
-/* Wakes up khubd */\r
-static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;\r
-static DECLARE_MUTEX(usb_address0_sem);\r
-\r
-static LIST_HEAD(hub_event_list);      /* List of hubs needing servicing */\r
-static LIST_HEAD(hub_list);            /* List of all hubs (for cleanup) */\r
-\r
-static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);\r
-static pid_t khubd_pid = 0;                    /* PID of khubd */\r
-static DECLARE_COMPLETION(khubd_exited);\r
-\r
-#ifdef DEBUG\r
-static inline char *portspeed (int portstatus)\r
-{\r
-       if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))\r
-               return "480 Mb/s";\r
-       else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))\r
-               return "1.5 Mb/s";\r
-       else\r
-               return "12 Mb/s";\r
-}\r
-#endif\r
-\r
-/* for dev_info, dev_dbg, etc */\r
-static inline struct device *hubdev (struct usb_device *dev)\r
-{\r
-       return &dev->actconfig->interface [0].dev;\r
-}\r
-\r
-/* USB 2.0 spec Section 11.24.4.5 */\r
-static int get_hub_descriptor(struct usb_device *dev, void *data, int size)\r
-{\r
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),\r
-               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,\r
-               USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT);\r
-}\r
-\r
-/*\r
- * USB 2.0 spec Section 11.24.2.1\r
- */\r
-static int clear_hub_feature(struct usb_device *dev, int feature)\r
-{\r
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),\r
-               USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);\r
-}\r
-\r
-/*\r
- * USB 2.0 spec Section 11.24.2.2\r
- * BUG: doesn't handle port indicator selector in high byte of wIndex\r
- */\r
-static int clear_port_feature(struct usb_device *dev, int port, int feature)\r
-{\r
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),\r
-               USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);\r
-}\r
-\r
-/*\r
- * USB 2.0 spec Section 11.24.2.13\r
- * BUG: doesn't handle port indicator selector in high byte of wIndex\r
- */\r
-static int set_port_feature(struct usb_device *dev, int port, int feature)\r
-{\r
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),\r
-               USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);\r
-}\r
-\r
-/*\r
- * USB 2.0 spec Section 11.24.2.6\r
- */\r
-static int get_hub_status(struct usb_device *dev,\r
-               struct usb_hub_status *data)\r
-{\r
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),\r
-               USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,\r
-               data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);\r
-}\r
-\r
-/*\r
- * USB 2.0 spec Section 11.24.2.7\r
- */\r
-static int get_port_status(struct usb_device *dev, int port,\r
-               struct usb_port_status *data)\r
-{\r
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),\r
-               USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,\r
-               data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);\r
-}\r
-\r
-/* completion function, fires on port status changes and various faults */\r
-static void hub_irq(struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct usb_hub *hub = (struct usb_hub *)urb->context;\r
-       unsigned long flags;\r
-       int status;\r
-\r
-       switch (urb->status) {\r
-       case -ENOENT:           /* synchronous unlink */\r
-       case -ECONNRESET:       /* async unlink */\r
-       case -ESHUTDOWN:        /* hardware going away */\r
-               return;\r
-\r
-       default:                /* presumably an error */\r
-               /* Cause a hub reset after 10 consecutive errors */\r
-               dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status);\r
-               if ((++hub->nerrors < 10) || hub->error)\r
-                       goto resubmit;\r
-               hub->error = urb->status;\r
-               /* FALL THROUGH */\r
-       \r
-       /* let khubd handle things */\r
-       case 0:                 /* we got data:  port status changed */\r
-               break;\r
-       }\r
-\r
-       hub->nerrors = 0;\r
-\r
-       /* Something happened, let khubd figure it out */\r
-       spin_lock_irqsave(&hub_event_lock, flags);\r
-       if (list_empty(&hub->event_list)) {\r
-               list_add(&hub->event_list, &hub_event_list);\r
-               wake_up(&khubd_wait);\r
-       }\r
-       spin_unlock_irqrestore(&hub_event_lock, flags);\r
-\r
-resubmit:\r
-       if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0\r
-                       /* ENODEV means we raced disconnect() */\r
-                       && status != -ENODEV)\r
-               dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);\r
-}\r
-\r
-/* USB 2.0 spec Section 11.24.2.3 */\r
-static inline int\r
-hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt)\r
-{\r
-       return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0),\r
-               HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER,\r
-               devinfo, tt, 0, 0, HZ);\r
-}\r
-\r
-/*\r
- * enumeration blocks khubd for a long time. we use keventd instead, since\r
- * long blocking there is the exception, not the rule.  accordingly, HCDs\r
- * talking to TTs must queue control transfers (not just bulk and iso), so\r
- * both can talk to the same hub concurrently.\r
- */\r
-static void hub_tt_kevent (void *arg)\r
-{\r
-       struct usb_hub          *hub = arg;\r
-       unsigned long           flags;\r
-\r
-       spin_lock_irqsave (&hub->tt.lock, flags);\r
-       while (!list_empty (&hub->tt.clear_list)) {\r
-               struct list_head        *temp;\r
-               struct usb_tt_clear     *clear;\r
-               struct usb_device       *dev;\r
-               int                     status;\r
-\r
-               temp = hub->tt.clear_list.next;\r
-               clear = list_entry (temp, struct usb_tt_clear, clear_list);\r
-               list_del (&clear->clear_list);\r
-\r
-               /* drop lock so HCD can concurrently report other TT errors */\r
-               spin_unlock_irqrestore (&hub->tt.lock, flags);\r
-               dev = interface_to_usbdev (hub->intf);\r
-               status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt);\r
-               spin_lock_irqsave (&hub->tt.lock, flags);\r
-\r
-               if (status)\r
-                       err ("usb-%s-%s clear tt %d (%04x) error %d",\r
-                               dev->bus->bus_name, dev->devpath,\r
-                               clear->tt, clear->devinfo, status);\r
-               kfree (clear);\r
-       }\r
-       spin_unlock_irqrestore (&hub->tt.lock, flags);\r
-}\r
-\r
-/**\r
- * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub\r
- * @dev: the device whose split transaction failed\r
- * @pipe: identifies the endpoint of the failed transaction\r
- *\r
- * High speed HCDs use this to tell the hub driver that some split control or\r
- * bulk transaction failed in a way that requires clearing internal state of\r
- * a transaction translator.  This is normally detected (and reported) from\r
- * interrupt context.\r
- *\r
- * It may not be possible for that hub to handle additional full (or low)\r
- * speed transactions until that state is fully cleared out.\r
- */\r
-void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)\r
-{\r
-       struct usb_tt           *tt = dev->tt;\r
-       unsigned long           flags;\r
-       struct usb_tt_clear     *clear;\r
-\r
-       /* we've got to cope with an arbitrary number of pending TT clears,\r
-        * since each TT has "at least two" buffers that can need it (and\r
-        * there can be many TTs per hub).  even if they're uncommon.\r
-        */\r
-       if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {\r
-               err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s",\r
-                       dev->bus->bus_name, tt->hub->devpath);\r
-               /* FIXME recover somehow ... RESET_TT? */\r
-               return;\r
-       }\r
-\r
-       /* info that CLEAR_TT_BUFFER needs */\r
-       clear->tt = tt->multi ? dev->ttport : 1;\r
-       clear->devinfo = usb_pipeendpoint (pipe);\r
-       clear->devinfo |= dev->devnum << 4;\r
-       clear->devinfo |= usb_pipecontrol (pipe)\r
-                       ? (USB_ENDPOINT_XFER_CONTROL << 11)\r
-                       : (USB_ENDPOINT_XFER_BULK << 11);\r
-       if (usb_pipein (pipe))\r
-               clear->devinfo |= 1 << 15;\r
-       \r
-       /* tell keventd to clear state for this TT */\r
-       spin_lock_irqsave (&tt->lock, flags);\r
-       list_add_tail (&clear->clear_list, &tt->clear_list);\r
-       schedule_work (&tt->kevent);\r
-       spin_unlock_irqrestore (&tt->lock, flags);\r
-}\r
-\r
-static void hub_power_on(struct usb_hub *hub)\r
-{\r
-       struct usb_device *dev;\r
-       int i;\r
-\r
-       /* Enable power to the ports */\r
-       dev_dbg(hubdev(interface_to_usbdev(hub->intf)),\r
-               "enabling power on all ports\n");\r
-       dev = interface_to_usbdev(hub->intf);\r
-\r
-       for (i = 0; i < hub->descriptor->bNbrPorts; i++)\r
-               set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);\r
-\r
-       /* Wait for power to be enabled */\r
-       wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);\r
-}\r
-\r
-static int hub_hub_status(struct usb_hub *hub,\r
-               u16 *status, u16 *change)\r
-{\r
-       struct usb_device *dev = interface_to_usbdev (hub->intf);\r
-       int ret;\r
-\r
-       ret = get_hub_status(dev, &hub->status->hub);\r
-       if (ret < 0)\r
-               dev_err (hubdev (dev),\r
-                       "%s failed (err = %d)\n", __FUNCTION__, ret);\r
-       else {\r
-               *status = le16_to_cpu(hub->status->hub.wHubStatus);\r
-               *change = le16_to_cpu(hub->status->hub.wHubChange); \r
-               ret = 0;\r
-       }\r
-       return ret;\r
-}\r
-\r
-static int hub_configure(struct usb_hub *hub,\r
-       struct usb_endpoint_descriptor *endpoint)\r
-{\r
-       struct usb_device *dev = interface_to_usbdev (hub->intf);\r
-       struct device *hub_dev;\r
-       u16 hubstatus, hubchange;\r
-       unsigned int pipe;\r
-       int maxp, ret;\r
-       char *message;\r
-\r
-       hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL,\r
-                       &hub->buffer_dma);\r
-       if (!hub->buffer) {\r
-               message = "can't allocate hub irq buffer";\r
-               ret = -ENOMEM;\r
-               goto fail;\r
-       }\r
-\r
-       hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);\r
-       if (!hub->status) {\r
-               message = "can't kmalloc hub status buffer";\r
-               ret = -ENOMEM;\r
-               goto fail;\r
-       }\r
-\r
-       hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);\r
-       if (!hub->descriptor) {\r
-               message = "can't kmalloc hub descriptor";\r
-               ret = -ENOMEM;\r
-               goto fail;\r
-       }\r
-\r
-       /* Request the entire hub descriptor.\r
-        * hub->descriptor can handle USB_MAXCHILDREN ports,\r
-        * but the hub can/will return fewer bytes here.\r
-        */\r
-       ret = get_hub_descriptor(dev, hub->descriptor,\r
-                       sizeof(*hub->descriptor));\r
-       if (ret < 0) {\r
-               message = "can't read hub descriptor";\r
-               goto fail;\r
-       } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {\r
-               message = "hub has too many ports!";\r
-               ret = -ENODEV;\r
-               goto fail;\r
-       }\r
-\r
-       hub_dev = hubdev(dev);\r
-       dev->maxchild = hub->descriptor->bNbrPorts;\r
-       dev_info (hub_dev, "%d port%s detected\n", dev->maxchild,\r
-               (dev->maxchild == 1) ? "" : "s");\r
-\r
-       le16_to_cpus(&hub->descriptor->wHubCharacteristics);\r
-\r
-       if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) {\r
-               int     i;\r
-               char    portstr [USB_MAXCHILDREN + 1];\r
-\r
-               for (i = 0; i < dev->maxchild; i++)\r
-                       portstr[i] = hub->descriptor->DeviceRemovable\r
-                                   [((i + 1) / 8)] & (1 << ((i + 1) % 8))\r
-                               ? 'F' : 'R';\r
-               portstr[dev->maxchild] = 0;\r
-               dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);\r
-       } else\r
-               dev_dbg(hub_dev, "standalone hub\n");\r
-\r
-       switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {\r
-               case 0x00:\r
-                       dev_dbg(hub_dev, "ganged power switching\n");\r
-                       break;\r
-               case 0x01:\r
-                       dev_dbg(hub_dev, "individual port power switching\n");\r
-                       break;\r
-               case 0x02:\r
-               case 0x03:\r
-                       dev_dbg(hub_dev, "unknown reserved power switching mode\n");\r
-                       break;\r
-       }\r
-\r
-       switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {\r
-               case 0x00:\r
-                       dev_dbg(hub_dev, "global over-current protection\n");\r
-                       break;\r
-               case 0x08:\r
-                       dev_dbg(hub_dev, "individual port over-current protection\n");\r
-                       break;\r
-               case 0x10:\r
-               case 0x18:\r
-                       dev_dbg(hub_dev, "no over-current protection\n");\r
-                        break;\r
-       }\r
-\r
-       spin_lock_init (&hub->tt.lock);\r
-       INIT_LIST_HEAD (&hub->tt.clear_list);\r
-       INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub);\r
-       switch (dev->descriptor.bDeviceProtocol) {\r
-               case 0:\r
-                       break;\r
-               case 1:\r
-                       dev_dbg(hub_dev, "Single TT\n");\r
-                       hub->tt.hub = dev;\r
-                       break;\r
-               case 2:\r
-                       dev_dbg(hub_dev, "TT per port\n");\r
-                       hub->tt.hub = dev;\r
-                       hub->tt.multi = 1;\r
-                       break;\r
-               default:\r
-                       dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",\r
-                               dev->descriptor.bDeviceProtocol);\r
-                       break;\r
-       }\r
-\r
-       switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {\r
-               case 0x00:\r
-                       if (dev->descriptor.bDeviceProtocol != 0)\r
-                               dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n");\r
-                       break;\r
-               case 0x20:\r
-                       dev_dbg(hub_dev, "TT requires at most 16 FS bit times\n");\r
-                       break;\r
-               case 0x40:\r
-                       dev_dbg(hub_dev, "TT requires at most 24 FS bit times\n");\r
-                       break;\r
-               case 0x60:\r
-                       dev_dbg(hub_dev, "TT requires at most 32 FS bit times\n");\r
-                       break;\r
-       }\r
-\r
-       dev_dbg(hub_dev, "Port indicators are %s supported\n", \r
-           (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND)\r
-               ? "" : "not");\r
-\r
-       dev_dbg(hub_dev, "power on to power good time: %dms\n",\r
-               hub->descriptor->bPwrOn2PwrGood * 2);\r
-       dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",\r
-               hub->descriptor->bHubContrCurrent);\r
-\r
-       ret = hub_hub_status(hub, &hubstatus, &hubchange);\r
-       if (ret < 0) {\r
-               message = "can't get hub status";\r
-               goto fail;\r
-       }\r
-\r
-       dev_dbg(hub_dev, "local power source is %s\n",\r
-               (hubstatus & HUB_STATUS_LOCAL_POWER)\r
-               ? "lost (inactive)" : "good");\r
-\r
-       dev_dbg(hub_dev, "%sover-current condition exists\n",\r
-               (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");\r
-\r
-       /* Start the interrupt endpoint */\r
-       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);\r
-       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));\r
-\r
-       if (maxp > sizeof(*hub->buffer))\r
-               maxp = sizeof(*hub->buffer);\r
-\r
-       hub->urb = usb_alloc_urb(0, GFP_KERNEL);\r
-       if (!hub->urb) {\r
-               message = "couldn't allocate interrupt urb";\r
-               ret = -ENOMEM;\r
-               goto fail;\r
-       }\r
-\r
-       usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,\r
-               hub, endpoint->bInterval);\r
-       hub->urb->transfer_dma = hub->buffer_dma;\r
-       hub->urb->transfer_flags |= URB_NO_DMA_MAP;\r
-       ret = usb_submit_urb(hub->urb, GFP_KERNEL);\r
-       if (ret) {\r
-               message = "couldn't submit status urb";\r
-               goto fail;\r
-       }\r
-\r
-       /* Wake up khubd */\r
-       wake_up(&khubd_wait);\r
-\r
-       hub_power_on(hub);\r
-\r
-       return 0;\r
-\r
-fail:\r
-       dev_err (&hub->intf->dev, "config failed, %s (err %d)\n",\r
-                       message, ret);\r
-       /* hub_disconnect() frees urb and descriptor */\r
-       return ret;\r
-}\r
-\r
-static void hub_disconnect(struct usb_interface *intf)\r
-{\r
-       struct usb_hub *hub = usb_get_intfdata (intf);\r
-       unsigned long flags;\r
-\r
-       if (!hub)\r
-               return;\r
-\r
-       usb_set_intfdata (intf, NULL);\r
-       spin_lock_irqsave(&hub_event_lock, flags);\r
-\r
-       /* Delete it and then reset it */\r
-       list_del(&hub->event_list);\r
-       INIT_LIST_HEAD(&hub->event_list);\r
-       list_del(&hub->hub_list);\r
-       INIT_LIST_HEAD(&hub->hub_list);\r
-\r
-       spin_unlock_irqrestore(&hub_event_lock, flags);\r
-\r
-       down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */\r
-       up(&hub->khubd_sem);\r
-\r
-       /* assuming we used keventd, it must quiesce too */\r
-       if (hub->tt.hub)\r
-               flush_scheduled_work ();\r
-\r
-       if (hub->urb) {\r
-               usb_unlink_urb(hub->urb);\r
-               usb_free_urb(hub->urb);\r
-               hub->urb = NULL;\r
-       }\r
-\r
-       if (hub->descriptor) {\r
-               kfree(hub->descriptor);\r
-               hub->descriptor = NULL;\r
-       }\r
-\r
-       if (hub->status) {\r
-               kfree(hub->status);\r
-               hub->status = NULL;\r
-       }\r
-\r
-       if (hub->buffer) {\r
-               usb_buffer_free(interface_to_usbdev(intf),\r
-                               sizeof(*hub->buffer), hub->buffer,\r
-                               hub->buffer_dma);\r
-               hub->buffer = NULL;\r
-       }\r
-\r
-       /* Free the memory */\r
-       kfree(hub);\r
-}\r
-\r
-static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)\r
-{\r
-       struct usb_host_interface *desc;\r
-       struct usb_endpoint_descriptor *endpoint;\r
-       struct usb_device *dev;\r
-       struct usb_hub *hub;\r
-       unsigned long flags;\r
-\r
-       desc = intf->altsetting + intf->act_altsetting;\r
-       dev = interface_to_usbdev(intf);\r
-\r
-       /* Some hubs have a subclass of 1, which AFAICT according to the */\r
-       /*  specs is not defined, but it works */\r
-       if ((desc->desc.bInterfaceSubClass != 0) &&\r
-           (desc->desc.bInterfaceSubClass != 1)) {\r
-descriptor_error:\r
-               dev_err (&intf->dev, "bad descriptor, ignoring hub\n");\r
-               return -EIO;\r
-       }\r
-\r
-       /* Multiple endpoints? What kind of mutant ninja-hub is this? */\r
-       if (desc->desc.bNumEndpoints != 1) {\r
-               goto descriptor_error;\r
-       }\r
-\r
-       endpoint = &desc->endpoint[0].desc;\r
-\r
-       /* Output endpoint? Curiouser and curiouser.. */\r
-       if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {\r
-               goto descriptor_error;\r
-       }\r
-\r
-       /* If it's not an interrupt endpoint, we'd better punt! */\r
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)\r
-                       != USB_ENDPOINT_XFER_INT) {\r
-               goto descriptor_error;\r
-               return -EIO;\r
-       }\r
-\r
-       /* We found a hub */\r
-       dev_info (hubdev (dev), "USB hub found\n");\r
-\r
-       hub = kmalloc(sizeof(*hub), GFP_KERNEL);\r
-       if (!hub) {\r
-               err("couldn't kmalloc hub struct");\r
-               return -ENOMEM;\r
-       }\r
-\r
-       memset(hub, 0, sizeof(*hub));\r
-\r
-       INIT_LIST_HEAD(&hub->event_list);\r
-       hub->intf = intf;\r
-       init_MUTEX(&hub->khubd_sem);\r
-\r
-       /* Record the new hub's existence */\r
-       spin_lock_irqsave(&hub_event_lock, flags);\r
-       INIT_LIST_HEAD(&hub->hub_list);\r
-       list_add(&hub->hub_list, &hub_list);\r
-       spin_unlock_irqrestore(&hub_event_lock, flags);\r
-\r
-       usb_set_intfdata (intf, hub);\r
-\r
-       if (hub_configure(hub, endpoint) >= 0) {\r
-               strcpy (intf->dev.name, "Hub");\r
-               return 0;\r
-       }\r
-\r
-       hub_disconnect (intf);\r
-       return -ENODEV;\r
-}\r
-\r
-static int\r
-hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)\r
-{\r
-       struct usb_device *hub = interface_to_usbdev (intf);\r
-\r
-       /* assert ifno == 0 (part of hub spec) */\r
-       switch (code) {\r
-       case USBDEVFS_HUB_PORTINFO: {\r
-               struct usbdevfs_hub_portinfo *info = user_data;\r
-               unsigned long flags;\r
-               int i;\r
-\r
-               spin_lock_irqsave(&hub_event_lock, flags);\r
-               if (hub->devnum <= 0)\r
-                       info->nports = 0;\r
-               else {\r
-                       info->nports = hub->maxchild;\r
-                       for (i = 0; i < info->nports; i++) {\r
-                               if (hub->children[i] == NULL)\r
-                                       info->port[i] = 0;\r
-                               else\r
-                                       info->port[i] =\r
-                                               hub->children[i]->devnum;\r
-                       }\r
-               }\r
-               spin_unlock_irqrestore(&hub_event_lock, flags);\r
-\r
-               return info->nports + 1;\r
-               }\r
-\r
-       default:\r
-               return -ENOSYS;\r
-       }\r
-}\r
-\r
-static int hub_reset(struct usb_hub *hub)\r
-{\r
-       struct usb_device *dev = interface_to_usbdev(hub->intf);\r
-       int i;\r
-\r
-       /* Disconnect any attached devices */\r
-       for (i = 0; i < hub->descriptor->bNbrPorts; i++) {\r
-               if (dev->children[i])\r
-                       usb_disconnect(&dev->children[i]);\r
-       }\r
-\r
-       /* Attempt to reset the hub */\r
-       if (hub->urb)\r
-               usb_unlink_urb(hub->urb);\r
-       else\r
-               return -1;\r
-\r
-       if (usb_reset_device(dev))\r
-               return -1;\r
-\r
-       hub->urb->dev = dev;                                                    \r
-       if (usb_submit_urb(hub->urb, GFP_KERNEL))\r
-               return -1;\r
-\r
-       hub_power_on(hub);\r
-\r
-       return 0;\r
-}\r
-\r
-static void hub_start_disconnect(struct usb_device *dev)\r
-{\r
-       struct usb_device *parent = dev->parent;\r
-       int i;\r
-\r
-       /* Find the device pointer to disconnect */\r
-       if (parent) {\r
-               for (i = 0; i < parent->maxchild; i++) {\r
-                       if (parent->children[i] == dev) {\r
-                               usb_disconnect(&parent->children[i]);\r
-                               return;\r
-                       }\r
-               }\r
-       }\r
-\r
-       err("cannot disconnect hub %s", dev->devpath);\r
-}\r
-\r
-static int hub_port_status(struct usb_device *dev, int port,\r
-                              u16 *status, u16 *change)\r
-{\r
-       struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);\r
-       int ret;\r
-\r
-       ret = get_port_status(dev, port + 1, &hub->status->port);\r
-       if (ret < 0)\r
-               dev_err (hubdev (dev),\r
-                       "%s failed (err = %d)\n", __FUNCTION__, ret);\r
-       else {\r
-               *status = le16_to_cpu(hub->status->port.wPortStatus);\r
-               *change = le16_to_cpu(hub->status->port.wPortChange); \r
-               ret = 0;\r
-       }\r
-       return ret;\r
-}\r
-\r
-#define HUB_RESET_TRIES                5\r
-#define HUB_PROBE_TRIES                2\r
-#define HUB_SHORT_RESET_TIME   10\r
-#define HUB_LONG_RESET_TIME    200\r
-#define HUB_RESET_TIMEOUT      500\r
-\r
-/* return: -1 on error, 0 on success, 1 on disconnect.  */\r
-static int hub_port_wait_reset(struct usb_device *hub, int port,\r
-                               struct usb_device *dev, unsigned int delay)\r
-{\r
-       int delay_time, ret;\r
-       u16 portstatus;\r
-       u16 portchange;\r
-\r
-       for (delay_time = 0;\r
-                       delay_time < HUB_RESET_TIMEOUT;\r
-                       delay_time += delay) {\r
-               /* wait to give the device a chance to reset */\r
-               wait_ms(delay);\r
-\r
-               /* read and decode port status */\r
-               ret = hub_port_status(hub, port, &portstatus, &portchange);\r
-               if (ret < 0) {\r
-                       return -1;\r
-               }\r
-\r
-               /* Device went away? */\r
-               if (!(portstatus & USB_PORT_STAT_CONNECTION))\r
-                       return 1;\r
-\r
-               /* bomb out completely if something weird happened */\r
-               if ((portchange & USB_PORT_STAT_C_CONNECTION))\r
-                       return -1;\r
-\r
-               /* if we`ve finished resetting, then break out of the loop */\r
-               if (!(portstatus & USB_PORT_STAT_RESET) &&\r
-                   (portstatus & USB_PORT_STAT_ENABLE)) {\r
-                       if (portstatus & USB_PORT_STAT_HIGH_SPEED)\r
-                               dev->speed = USB_SPEED_HIGH;\r
-                       else if (portstatus & USB_PORT_STAT_LOW_SPEED)\r
-                               dev->speed = USB_SPEED_LOW;\r
-                       else\r
-                               dev->speed = USB_SPEED_FULL;\r
-                       return 0;\r
-               }\r
-\r
-               /* switch to the long delay after two short delay failures */\r
-               if (delay_time >= 2 * HUB_SHORT_RESET_TIME)\r
-                       delay = HUB_LONG_RESET_TIME;\r
-\r
-               dev_dbg (hubdev (hub),\r
-                       "port %d not reset yet, waiting %dms\n",\r
-                       port + 1, delay);\r
-       }\r
-\r
-       return -1;\r
-}\r
-\r
-/* return: -1 on error, 0 on success, 1 on disconnect.  */\r
-static int hub_port_reset(struct usb_device *hub, int port,\r
-                               struct usb_device *dev, unsigned int delay)\r
-{\r
-       int i, status;\r
-\r
-       /* Reset the port */\r
-       for (i = 0; i < HUB_RESET_TRIES; i++) {\r
-               set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);\r
-\r
-               /* return on disconnect or reset */\r
-               status = hub_port_wait_reset(hub, port, dev, delay);\r
-               if (status != -1) {\r
-                       clear_port_feature(hub,\r
-                               port + 1, USB_PORT_FEAT_C_RESET);\r
-                       dev->state = status\r
-                                       ? USB_STATE_NOTATTACHED\r
-                                       : USB_STATE_DEFAULT;\r
-                       return status;\r
-               }\r
-\r
-               dev_dbg (hubdev (hub),\r
-                       "port %d not enabled, trying reset again...\n",\r
-                       port + 1);\r
-               delay = HUB_LONG_RESET_TIME;\r
-       }\r
-\r
-       dev_err (hubdev (hub),\r
-               "Cannot enable port %i.  Maybe the USB cable is bad?\n",\r
-               port + 1);\r
-\r
-       return -1;\r
-}\r
-\r
-int hub_port_disable(struct usb_device *hub, int port)\r
-{\r
-       int ret;\r
-\r
-       ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);\r
-       if (ret)\r
-               dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",\r
-                       port + 1, ret);\r
-\r
-       return ret;\r
-}\r
-\r
-/* USB 2.0 spec, 7.1.7.3 / fig 7-29:\r
- *\r
- * Between connect detection and reset signaling there must be a delay\r
- * of 100ms at least for debounce and power-settling. The corresponding\r
- * timer shall restart whenever the downstream port detects a disconnect.\r
- * \r
- * Apparently there are some bluetooth and irda-dongles and a number\r
- * of low-speed devices which require longer delays of about 200-400ms.\r
- * Not covered by the spec - but easy to deal with.\r
- *\r
- * This implementation uses 400ms minimum debounce timeout and checks\r
- * every 25ms for transient disconnects to restart the delay.\r
- */\r
-\r
-#define HUB_DEBOUNCE_TIMEOUT   400\r
-#define HUB_DEBOUNCE_STEP       25\r
-#define HUB_DEBOUNCE_STABLE      4\r
-\r
-/* return: -1 on error, 0 on success, 1 on disconnect.  */\r
-static int hub_port_debounce(struct usb_device *hub, int port)\r
-{\r
-       int ret;\r
-       int delay_time, stable_count;\r
-       u16 portchange, portstatus;\r
-       unsigned connection;\r
-\r
-       connection = 0;\r
-       stable_count = 0;\r
-       for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {\r
-               wait_ms(HUB_DEBOUNCE_STEP);\r
-\r
-               ret = hub_port_status(hub, port, &portstatus, &portchange);\r
-               if (ret < 0)\r
-                       return -1;\r
-\r
-               if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) {\r
-                       if (connection) {\r
-                               if (++stable_count == HUB_DEBOUNCE_STABLE)\r
-                                       break;\r
-                       }\r
-               } else {\r
-                       stable_count = 0;\r
-               }\r
-               connection = portstatus & USB_PORT_STAT_CONNECTION;\r
-\r
-               if ((portchange & USB_PORT_STAT_C_CONNECTION)) {\r
-                       clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);\r
-               }\r
-       }\r
-\r
-       /* XXX Replace this with dbg() when 2.6 is about to ship. */\r
-       dev_dbg (hubdev (hub),\r
-               "debounce: port %d: delay %dms stable %d status 0x%x\n",\r
-               port + 1, delay_time, stable_count, portstatus);\r
-\r
-       return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;\r
-}\r
-\r
-static void hub_port_connect_change(struct usb_hub *hubstate, int port,\r
-                                       u16 portstatus, u16 portchange)\r
-{\r
-       struct usb_device *hub = interface_to_usbdev(hubstate->intf);\r
-       struct usb_device *dev;\r
-       unsigned int delay = HUB_SHORT_RESET_TIME;\r
-       int i;\r
-\r
-       dev_dbg (&hubstate->intf->dev,\r
-               "port %d, status %x, change %x, %s\n",\r
-               port + 1, portstatus, portchange, portspeed (portstatus));\r
-\r
-       /* Clear the connection change status */\r
-       clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);\r
-\r
-       /* Disconnect any existing devices under this port */\r
-       if (hub->children[port])\r
-               usb_disconnect(&hub->children[port]);\r
-\r
-       /* Return now if nothing is connected */\r
-       if (!(portstatus & USB_PORT_STAT_CONNECTION)) {\r
-               if (portstatus & USB_PORT_STAT_ENABLE)\r
-                       hub_port_disable(hub, port);\r
-\r
-               return;\r
-       }\r
-\r
-       if (hub_port_debounce(hub, port)) {\r
-               dev_err (&hubstate->intf->dev,\r
-                       "connect-debounce failed, port %d disabled\n",\r
-                       port+1);\r
-               hub_port_disable(hub, port);\r
-               return;\r
-       }\r
-\r
-       /* Some low speed devices have problems with the quick delay, so */\r
-       /*  be a bit pessimistic with those devices. RHbug #23670 */\r
-       if (portstatus & USB_PORT_STAT_LOW_SPEED)\r
-               delay = HUB_LONG_RESET_TIME;\r
-\r
-       down(&usb_address0_sem);\r
-\r
-       for (i = 0; i < HUB_PROBE_TRIES; i++) {\r
-               struct usb_device *pdev;\r
-               int     len;\r
-\r
-               /* Allocate a new device struct */\r
-               dev = usb_alloc_dev(hub, hub->bus);\r
-               if (!dev) {\r
-                       dev_err (&hubstate->intf->dev,\r
-                               "couldn't allocate usb_device\n");\r
-                       break;\r
-               }\r
-\r
-               hub->children[port] = dev;\r
-               dev->state = USB_STATE_POWERED;\r
-\r
-               /* Reset the device, and detect its speed */\r
-               if (hub_port_reset(hub, port, dev, delay)) {\r
-                       usb_put_dev(dev);\r
-                       break;\r
-               }\r
-\r
-               /* Find a new address for it */\r
-               usb_connect(dev);\r
-\r
-               /* Set up TT records, if needed  */\r
-               if (hub->tt) {\r
-                       dev->tt = hub->tt;\r
-                       dev->ttport = hub->ttport;\r
-               } else if (dev->speed != USB_SPEED_HIGH\r
-                               && hub->speed == USB_SPEED_HIGH) {\r
-                       dev->tt = &hubstate->tt;\r
-                       dev->ttport = port + 1;\r
-               }\r
-\r
-               /* Save readable and stable topology id, distinguishing\r
-                * devices by location for diagnostics, tools, etc.  The\r
-                * string is a path along hub ports, from the root.  Each\r
-                * device's id will be stable until USB is re-cabled, and\r
-                * hubs are often labeled with these port numbers.\r
-                *\r
-                * Initial size: ".NN" times five hubs + NUL = 16 bytes max\r
-                * (quite rare, since most hubs have 4-6 ports).\r
-                */\r
-               pdev = dev->parent;\r
-               if (pdev->devpath [0] != '0')   /* parent not root? */\r
-                       len = snprintf (dev->devpath, sizeof dev->devpath,\r
-                               "%s.%d", pdev->devpath, port + 1);\r
-               /* root == "0", root port 2 == "2", port 3 that hub "2.3" */\r
-               else\r
-                       len = snprintf (dev->devpath, sizeof dev->devpath,\r
-                               "%d", port + 1);\r
-               if (len == sizeof dev->devpath)\r
-                       dev_err (&hubstate->intf->dev,\r
-                               "devpath size! usb/%03d/%03d path %s\n",\r
-                               dev->bus->busnum, dev->devnum, dev->devpath);\r
-               dev_info (&hubstate->intf->dev,\r
-                       "new USB device on port %d, assigned address %d\n",\r
-                       port + 1, dev->devnum);\r
-\r
-               /* put the device in the global device tree. the hub port\r
-                * is the "bus_id"; hubs show in hierarchy like bridges\r
-                */\r
-               dev->dev.parent = dev->parent->dev.parent->parent;\r
-\r
-               /* Run it through the hoops (find a driver, etc) */\r
-               if (!usb_new_device(dev, &hub->dev))\r
-                       goto done;\r
-\r
-               /* Free the configuration if there was an error */\r
-               usb_put_dev(dev);\r
-\r
-               /* Switch to a long reset time */\r
-               delay = HUB_LONG_RESET_TIME;\r
-       }\r
-\r
-       hub->children[port] = NULL;\r
-       hub_port_disable(hub, port);\r
-done:\r
-       up(&usb_address0_sem);\r
-}\r
-\r
-static void hub_events(void)\r
-{\r
-       unsigned long flags;\r
-       struct list_head *tmp;\r
-       struct usb_device *dev;\r
-       struct usb_hub *hub;\r
-       u16 hubstatus;\r
-       u16 hubchange;\r
-       u16 portstatus;\r
-       u16 portchange;\r
-       int i, ret;\r
-       int m=0;\r
-       /*\r
-        *  We restart the list every time to avoid a deadlock with\r
-        * deleting hubs downstream from this one. This should be\r
-        * safe since we delete the hub from the event list.\r
-        * Not the most efficient, but avoids deadlocks.\r
-        */\r
-\r
-       while (m<5) {\r
-               m++;\r
-               spin_lock_irqsave(&hub_event_lock, flags);\r
-\r
-               if (list_empty(&hub_event_list))\r
-                       break;\r
-\r
-               /* Grab the next entry from the beginning of the list */\r
-               tmp = hub_event_list.next;\r
-\r
-               hub = list_entry(tmp, struct usb_hub, event_list);\r
-               dev = interface_to_usbdev(hub->intf);\r
-\r
-               list_del_init(tmp);\r
-\r
-               if (unlikely(down_trylock(&hub->khubd_sem)))\r
-                       BUG();  /* never blocks, we were on list */\r
-\r
-               spin_unlock_irqrestore(&hub_event_lock, flags);\r
-\r
-               if (hub->error) {\r
-                       dev_dbg (&hub->intf->dev, "resetting for error %d\n",\r
-                               hub->error);\r
-\r
-                       if (hub_reset(hub)) {\r
-                               dev_dbg (&hub->intf->dev,\r
-                                       "can't reset; disconnecting\n");\r
-                               up(&hub->khubd_sem);\r
-                               hub_start_disconnect(dev);\r
-                               continue;\r
-                       }\r
-\r
-                       hub->nerrors = 0;\r
-                       hub->error = 0;\r
-               }\r
-\r
-               for (i = 0; i < hub->descriptor->bNbrPorts; i++) {\r
-                       ret = hub_port_status(dev, i, &portstatus, &portchange);\r
-                       if (ret < 0) {\r
-                               continue;\r
-                       }\r
-\r
-                       if (portchange & USB_PORT_STAT_C_CONNECTION) {\r
-                               hub_port_connect_change(hub, i, portstatus, portchange);\r
-                       } else if (portchange & USB_PORT_STAT_C_ENABLE) {\r
-                               dev_dbg (hubdev (dev),\r
-                                       "port %d enable change, status %x\n",\r
-                                       i + 1, portstatus);\r
-                               clear_port_feature(dev,\r
-                                       i + 1, USB_PORT_FEAT_C_ENABLE);\r
-\r
-                               /*\r
-                                * EM interference sometimes causes badly\r
-                                * shielded USB devices to be shutdown by\r
-                                * the hub, this hack enables them again.\r
-                                * Works at least with mouse driver. \r
-                                */\r
-                               if (!(portstatus & USB_PORT_STAT_ENABLE)\r
-                                   && (portstatus & USB_PORT_STAT_CONNECTION)\r
-                                   && (dev->children[i])) {\r
-                                       dev_err (&hub->intf->dev,\r
-                                           "port %i "\r
-                                           "disabled by hub (EMI?), "\r
-                                           "re-enabling...",\r
-                                               i + 1);\r
-                                       hub_port_connect_change(hub,\r
-                                               i, portstatus, portchange);\r
-                               }\r
-                       }\r
-\r
-                       if (portchange & USB_PORT_STAT_C_SUSPEND) {\r
-                               dev_dbg (&hub->intf->dev,\r
-                                       "suspend change on port %d\n",\r
-                                       i + 1);\r
-                               clear_port_feature(dev,\r
-                                       i + 1,  USB_PORT_FEAT_C_SUSPEND);\r
-                       }\r
-                       \r
-                       if (portchange & USB_PORT_STAT_C_OVERCURRENT) {\r
-                               dev_err (&hub->intf->dev,\r
-                                       "over-current change on port %d\n",\r
-                                       i + 1);\r
-                               clear_port_feature(dev,\r
-                                       i + 1, USB_PORT_FEAT_C_OVER_CURRENT);\r
-                               hub_power_on(hub);\r
-                       }\r
-\r
-                       if (portchange & USB_PORT_STAT_C_RESET) {\r
-                               dev_dbg (&hub->intf->dev,\r
-                                       "reset change on port %d\n",\r
-                                       i + 1);\r
-                               clear_port_feature(dev,\r
-                                       i + 1, USB_PORT_FEAT_C_RESET);\r
-                       }\r
-               } /* end for i */\r
-\r
-               /* deal with hub status changes */\r
-               if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)\r
-                       dev_err (&hub->intf->dev, "get_hub_status failed\n");\r
-               else {\r
-                       if (hubchange & HUB_CHANGE_LOCAL_POWER) {\r
-                               dev_dbg (&hub->intf->dev, "power change\n");\r
-                               clear_hub_feature(dev, C_HUB_LOCAL_POWER);\r
-                       }\r
-                       if (hubchange & HUB_CHANGE_OVERCURRENT) {\r
-                               dev_dbg (&hub->intf->dev, "overcurrent change\n");\r
-                               wait_ms(500);   /* Cool down */\r
-                               clear_hub_feature(dev, C_HUB_OVER_CURRENT);\r
-                               hub_power_on(hub);\r
-                       }\r
-               }\r
-               up(&hub->khubd_sem);\r
-        } /* end while (1) */\r
-\r
-       spin_unlock_irqrestore(&hub_event_lock, flags);\r
-}\r
-\r
-static int hub_thread(void *__hub)\r
-{\r
-       /*\r
-        * This thread doesn't need any user-level access,\r
-        * so get rid of all our resources\r
-        */\r
-\r
-       daemonize("khubd");\r
-       allow_signal(SIGKILL);\r
-       /* Send me a signal to get me die (for debugging) */\r
-       do {\r
-               \r
-               hub_events();\r
-\r
-               //FIXME: Correct this\r
-               //wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); // interruptable_sleep_on analog - below\r
-               while (!list_empty(&hub_event_list)) {\r
-                       interruptible_sleep_on(&khubd_wait);\r
-               }\r
-\r
-               if (current->flags & PF_FREEZE)\r
-                       refrigerator(PF_IOTHREAD);\r
-\r
-       } while (!signal_pending(current));\r
-\r
-//     dbg("hub_thread exiting");\r
-       complete_and_exit(&khubd_exited, 0);\r
-}\r
-\r
-static struct usb_device_id hub_id_table [] = {\r
-    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,\r
-      .bDeviceClass = USB_CLASS_HUB},\r
-    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,\r
-      .bInterfaceClass = USB_CLASS_HUB},\r
-    { }                                                /* Terminating entry */\r
-};\r
-\r
-MODULE_DEVICE_TABLE (usb, hub_id_table);\r
-\r
-static struct usb_driver hub_driver = {\r
-       .owner =        THIS_MODULE,\r
-       .name =         "hub",\r
-       .probe =        hub_probe,\r
-       .disconnect =   hub_disconnect,\r
-       .ioctl =        hub_ioctl,\r
-       .id_table =     hub_id_table,\r
-};\r
-\r
-/*\r
- * This should be a separate module.\r
- */\r
-int usb_hub_init(void)\r
-{\r
-       pid_t pid;\r
-\r
-       // ReactOS-specific\r
-       // Create Event object, initialize other sync events\r
-       KeInitializeEvent(&khubd_wait, NotificationEvent, TRUE); // signalled state\r
-\r
-       if (usb_register(&hub_driver) < 0) {\r
-               err("Unable to register USB hub driver");\r
-               return -1;\r
-       }\r
-\r
-       pid = kernel_thread(hub_thread, NULL,\r
-               CLONE_FS | CLONE_FILES | CLONE_SIGHAND);\r
-       if (pid >= 0) {\r
-               khubd_pid = pid;\r
-               return 0;\r
-       }\r
-\r
-       /* Fall through if kernel_thread failed */\r
-       usb_deregister(&hub_driver);\r
-       err("failed to start hub_thread");\r
-\r
-       return -1;\r
-}\r
-\r
-void usb_hub_cleanup(void)\r
-{\r
-       int ret;\r
-\r
-       /* Kill the thread */\r
-       ret = kill_proc(khubd_pid, SIGKILL, 1);\r
-\r
-       wait_for_completion(&khubd_exited);\r
-\r
-       /*\r
-        * Hub resources are freed for us by usb_deregister. It calls\r
-        * usb_driver_purge on every device which in turn calls that\r
-        * devices disconnect function if it is using this driver.\r
-        * The hub_disconnect function takes care of releasing the\r
-        * individual hub resources. -greg\r
-        */\r
-       usb_deregister(&hub_driver);\r
-} /* usb_hub_cleanup() */\r
-\r
-/*\r
- * WARNING - If a driver calls usb_reset_device, you should simulate a\r
- * disconnect() and probe() for other interfaces you doesn't claim. This\r
- * is left up to the driver writer right now. This insures other drivers\r
- * have a chance to re-setup their interface.\r
- *\r
- * Take a look at proc_resetdevice in devio.c for some sample code to\r
- * do this.\r
- * Use this only from within your probe function, otherwise use\r
- * usb_reset_device() below, which ensure proper locking\r
- */\r
-int usb_physical_reset_device(struct usb_device *dev)\r
-{\r
-       struct usb_device *parent = dev->parent;\r
-       struct usb_device_descriptor *descriptor;\r
-       int i, ret, port = -1;\r
-\r
-       if (!parent) {\r
-               err("attempting to reset root hub!");\r
-               return -EINVAL;\r
-       }\r
-\r
-       for (i = 0; i < parent->maxchild; i++)\r
-               if (parent->children[i] == dev) {\r
-                       port = i;\r
-                       break;\r
-               }\r
-\r
-       if (port < 0)\r
-               return -ENOENT;\r
-\r
-       descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);\r
-       if (!descriptor) {\r
-               return -ENOMEM;\r
-       }\r
-\r
-       down(&usb_address0_sem);\r
-\r
-       /* Send a reset to the device */\r
-       if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {\r
-               hub_port_disable(parent, port);\r
-               up(&usb_address0_sem);\r
-               kfree(descriptor);\r
-               return(-ENODEV);\r
-       }\r
-\r
-       /* Reprogram the Address */\r
-       ret = usb_set_address(dev);\r
-       if (ret < 0) {\r
-               err("USB device not accepting new address (error=%d)", ret);\r
-               hub_port_disable(parent, port);\r
-               up(&usb_address0_sem);\r
-               kfree(descriptor);\r
-               return ret;\r
-       }\r
-\r
-       /* Let the SET_ADDRESS settle */\r
-       wait_ms(10);\r
-\r
-       up(&usb_address0_sem);\r
-\r
-       /*\r
-        * Now we fetch the configuration descriptors for the device and\r
-        * see if anything has changed. If it has, we dump the current\r
-        * parsed descriptors and reparse from scratch. Then we leave\r
-        * the device alone for the caller to finish setting up.\r
-        *\r
-        * If nothing changed, we reprogram the configuration and then\r
-        * the alternate settings.\r
-        */\r
-\r
-       ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,\r
-                       sizeof(*descriptor));\r
-       if (ret < 0) {\r
-               kfree(descriptor);\r
-               return ret;\r
-       }\r
-\r
-       le16_to_cpus(&descriptor->bcdUSB);\r
-       le16_to_cpus(&descriptor->idVendor);\r
-       le16_to_cpus(&descriptor->idProduct);\r
-       le16_to_cpus(&descriptor->bcdDevice);\r
-\r
-       if (RtlCompareMemory(&dev->descriptor, descriptor, sizeof(*descriptor))) {\r
-               kfree(descriptor);\r
-               usb_destroy_configuration(dev);\r
-\r
-               ret = usb_get_device_descriptor(dev);\r
-               if (ret < sizeof(dev->descriptor)) {\r
-                       if (ret < 0)\r
-                               err("unable to get device %s descriptor "\r
-                                       "(error=%d)", dev->devpath, ret);\r
-                       else\r
-                               err("USB device %s descriptor short read "\r
-                                       "(expected %Zi, got %i)",\r
-                                       dev->devpath,\r
-                                       sizeof(dev->descriptor), ret);\r
-\r
-                       clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-                       dev->devnum = -1;\r
-                       return -EIO;\r
-               }\r
-\r
-               ret = usb_get_configuration(dev);\r
-               if (ret < 0) {\r
-                       err("unable to get configuration (error=%d)", ret);\r
-                       usb_destroy_configuration(dev);\r
-                       clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-                       dev->devnum = -1;\r
-                       return 1;\r
-               }\r
-\r
-               dev->actconfig = dev->config;\r
-               usb_set_maxpacket(dev);\r
-\r
-               return 1;\r
-       }\r
-\r
-       kfree(descriptor);\r
-\r
-       ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue);\r
-       if (ret < 0) {\r
-               err("failed to set dev %s active configuration (error=%d)",\r
-                       dev->devpath, ret);\r
-               return ret;\r
-       }\r
-\r
-       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {\r
-               struct usb_interface *intf = &dev->actconfig->interface[i];\r
-               struct usb_interface_descriptor *as;\r
-\r
-               as = &intf->altsetting[intf->act_altsetting].desc;\r
-               ret = usb_set_interface(dev, as->bInterfaceNumber,\r
-                       as->bAlternateSetting);\r
-               if (ret < 0) {\r
-                       err("failed to set active alternate setting "\r
-                               "for dev %s interface %d (error=%d)",\r
-                               dev->devpath, i, ret);\r
-                       return ret;\r
-               }\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-int usb_reset_device(struct usb_device *udev)\r
-{\r
-       //struct device *gdev = &udev->dev;\r
-       int r;\r
-       \r
-       down_read(&gdev->bus->subsys.rwsem);\r
-       r = usb_physical_reset_device(udev);\r
-       up_read(&gdev->bus->subsys.rwsem);\r
-\r
-       return r;\r
-}\r
-\r
-\r
+/*
+ * USB hub driver.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Gregory P. Smith
+ * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)
+ *
+ */
+#define DEBUG
+#if 0
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/suspend.h>
+
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "hcd.h"
+#include "hub.h"
+#else
+#include "../usb_wrapper.h"
+#include "hcd.h"
+#include "hub.h"
+#define DEBUG
+#endif
+
+/* Wakes up khubd */
+static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(usb_address0_sem);
+
+static LIST_HEAD(hub_event_list);      /* List of hubs needing servicing */
+static LIST_HEAD(hub_list);            /* List of all hubs (for cleanup) */
+
+static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+static pid_t khubd_pid = 0;                    /* PID of khubd */
+static DECLARE_COMPLETION(khubd_exited);
+
+#ifdef DEBUG
+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";
+}
+#endif
+
+/* for dev_info, dev_dbg, etc */
+static inline struct device *hubdev (struct usb_device *dev)
+{
+       return &dev->actconfig->interface [0].dev;
+}
+
+/* USB 2.0 spec Section 11.24.4.5 */
+static int 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, HZ * USB_CTRL_GET_TIMEOUT);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.1
+ */
+static int 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, HZ);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.2
+ * BUG: doesn't handle port indicator selector in high byte of wIndex
+ */
+static int 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, HZ);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.13
+ * BUG: doesn't handle port indicator selector in high byte of wIndex
+ */
+static int 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, HZ);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.6
+ */
+static int get_hub_status(struct usb_device *dev,
+               struct usb_hub_status *data)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+               data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
+}
+
+/*
+ * USB 2.0 spec Section 11.24.2.7
+ */
+static int get_port_status(struct usb_device *dev, int port,
+               struct usb_port_status *data)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+               data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
+}
+
+/* completion function, fires on port status changes and various faults */
+static void hub_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_hub *hub = (struct usb_hub *)urb->context;
+       unsigned long flags;
+       int status;
+
+       switch (urb->status) {
+       case -ENOENT:           /* synchronous unlink */
+       case -ECONNRESET:       /* async unlink */
+       case -ESHUTDOWN:        /* hardware going away */
+               return;
+
+       default:                /* presumably an error */
+               /* Cause a hub reset after 10 consecutive errors */
+               dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status);
+               if ((++hub->nerrors < 10) || hub->error)
+                       goto resubmit;
+               hub->error = urb->status;
+               /* FALL THROUGH */
+       
+       /* let khubd handle things */
+       case 0:                 /* we got data:  port status changed */
+               break;
+       }
+
+       hub->nerrors = 0;
+
+       /* Something happened, let khubd figure it out */
+       spin_lock_irqsave(&hub_event_lock, flags);
+       if (list_empty(&hub->event_list)) {
+               list_add(&hub->event_list, &hub_event_list);
+               wake_up(&khubd_wait);
+       }
+       spin_unlock_irqrestore(&hub_event_lock, flags);
+
+resubmit:
+       if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
+                       /* ENODEV means we raced disconnect() */
+                       && status != -ENODEV)
+               dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);
+}
+
+/* USB 2.0 spec Section 11.24.2.3 */
+static inline int
+hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt)
+{
+       return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0),
+               HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER,
+               devinfo, tt, 0, 0, HZ);
+}
+
+/*
+ * enumeration blocks khubd for a long time. we use keventd instead, since
+ * long blocking there is the exception, not the rule.  accordingly, HCDs
+ * talking to TTs must queue control transfers (not just bulk and iso), so
+ * both can talk to the same hub concurrently.
+ */
+static void hub_tt_kevent (void *arg)
+{
+       struct usb_hub          *hub = arg;
+       unsigned long           flags;
+
+       spin_lock_irqsave (&hub->tt.lock, flags);
+       while (!list_empty (&hub->tt.clear_list)) {
+               struct list_head        *temp;
+               struct usb_tt_clear     *clear;
+               struct usb_device       *dev;
+               int                     status;
+
+               temp = hub->tt.clear_list.next;
+               clear = list_entry (temp, struct usb_tt_clear, clear_list);
+               list_del (&clear->clear_list);
+
+               /* drop lock so HCD can concurrently report other TT errors */
+               spin_unlock_irqrestore (&hub->tt.lock, flags);
+               dev = interface_to_usbdev (hub->intf);
+               status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt);
+               spin_lock_irqsave (&hub->tt.lock, flags);
+
+               if (status)
+                       err ("usb-%s-%s clear tt %d (%04x) error %d",
+                               dev->bus->bus_name, dev->devpath,
+                               clear->tt, clear->devinfo, status);
+               kfree (clear);
+       }
+       spin_unlock_irqrestore (&hub->tt.lock, flags);
+}
+
+/**
+ * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
+ * @dev: the device whose split transaction failed
+ * @pipe: identifies the endpoint of the failed transaction
+ *
+ * High speed HCDs use this to tell the hub driver that some split control or
+ * bulk transaction failed in a way that requires clearing internal state of
+ * a transaction translator.  This is normally detected (and reported) from
+ * interrupt context.
+ *
+ * It may not be possible for that hub to handle additional full (or low)
+ * speed transactions until that state is fully cleared out.
+ */
+void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
+{
+       struct usb_tt           *tt = dev->tt;
+       unsigned long           flags;
+       struct usb_tt_clear     *clear;
+
+       /* we've got to cope with an arbitrary number of pending TT clears,
+        * since each TT has "at least two" buffers that can need it (and
+        * there can be many TTs per hub).  even if they're uncommon.
+        */
+       if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) {
+               err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s",
+                       dev->bus->bus_name, tt->hub->devpath);
+               /* FIXME recover somehow ... RESET_TT? */
+               return;
+       }
+
+       /* info that CLEAR_TT_BUFFER needs */
+       clear->tt = tt->multi ? dev->ttport : 1;
+       clear->devinfo = usb_pipeendpoint (pipe);
+       clear->devinfo |= dev->devnum << 4;
+       clear->devinfo |= usb_pipecontrol (pipe)
+                       ? (USB_ENDPOINT_XFER_CONTROL << 11)
+                       : (USB_ENDPOINT_XFER_BULK << 11);
+       if (usb_pipein (pipe))
+               clear->devinfo |= 1 << 15;
+       
+       /* tell keventd to clear state for this TT */
+       spin_lock_irqsave (&tt->lock, flags);
+       list_add_tail (&clear->clear_list, &tt->clear_list);
+       schedule_work (&tt->kevent);
+       spin_unlock_irqrestore (&tt->lock, flags);
+}
+
+static void hub_power_on(struct usb_hub *hub)
+{
+       struct usb_device *dev;
+       int i;
+
+       /* Enable power to the ports */
+       dev_dbg(hubdev(interface_to_usbdev(hub->intf)),
+               "enabling power on all ports\n");
+       dev = interface_to_usbdev(hub->intf);
+
+       for (i = 0; i < hub->descriptor->bNbrPorts; i++)
+               set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+
+       /* Wait for power to be enabled */
+       wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
+}
+
+static int hub_hub_status(struct usb_hub *hub,
+               u16 *status, u16 *change)
+{
+       struct usb_device *dev = interface_to_usbdev (hub->intf);
+       int ret;
+
+       ret = get_hub_status(dev, &hub->status->hub);
+       if (ret < 0)
+               dev_err (hubdev (dev),
+                       "%s failed (err = %d)\n", __FUNCTION__, ret);
+       else {
+               *status = le16_to_cpu(hub->status->hub.wHubStatus);
+               *change = le16_to_cpu(hub->status->hub.wHubChange); 
+               ret = 0;
+       }
+       return ret;
+}
+
+static int hub_configure(struct usb_hub *hub,
+       struct usb_endpoint_descriptor *endpoint)
+{
+       struct usb_device *dev = interface_to_usbdev (hub->intf);
+       struct device *hub_dev;
+       u16 hubstatus, hubchange;
+       unsigned int pipe;
+       int maxp, ret;
+       char *message;
+
+       hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL,
+                       &hub->buffer_dma);
+       if (!hub->buffer) {
+               message = "can't allocate hub irq buffer";
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
+       if (!hub->status) {
+               message = "can't kmalloc hub status buffer";
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
+       if (!hub->descriptor) {
+               message = "can't kmalloc hub descriptor";
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       /* Request the entire hub descriptor.
+        * hub->descriptor can handle USB_MAXCHILDREN ports,
+        * but the hub can/will return fewer bytes here.
+        */
+       ret = get_hub_descriptor(dev, hub->descriptor,
+                       sizeof(*hub->descriptor));
+       if (ret < 0) {
+               message = "can't read hub descriptor";
+               goto fail;
+       } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+               message = "hub has too many ports!";
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       hub_dev = hubdev(dev);
+       dev->maxchild = hub->descriptor->bNbrPorts;
+       dev_info (hub_dev, "%d port%s detected\n", dev->maxchild,
+               (dev->maxchild == 1) ? "" : "s");
+
+       le16_to_cpus(&hub->descriptor->wHubCharacteristics);
+
+       if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) {
+               int     i;
+               char    portstr [USB_MAXCHILDREN + 1];
+
+               for (i = 0; i < dev->maxchild; i++)
+                       portstr[i] = hub->descriptor->DeviceRemovable
+                                   [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+                               ? 'F' : 'R';
+               portstr[dev->maxchild] = 0;
+               dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
+       } else
+               dev_dbg(hub_dev, "standalone hub\n");
+
+       switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
+               case 0x00:
+                       dev_dbg(hub_dev, "ganged power switching\n");
+                       break;
+               case 0x01:
+                       dev_dbg(hub_dev, "individual port power switching\n");
+                       break;
+               case 0x02:
+               case 0x03:
+                       dev_dbg(hub_dev, "unknown reserved power switching mode\n");
+                       break;
+       }
+
+       switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {
+               case 0x00:
+                       dev_dbg(hub_dev, "global over-current protection\n");
+                       break;
+               case 0x08:
+                       dev_dbg(hub_dev, "individual port over-current protection\n");
+                       break;
+               case 0x10:
+               case 0x18:
+                       dev_dbg(hub_dev, "no over-current protection\n");
+                        break;
+       }
+
+       spin_lock_init (&hub->tt.lock);
+       INIT_LIST_HEAD (&hub->tt.clear_list);
+       INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub);
+       switch (dev->descriptor.bDeviceProtocol) {
+               case 0:
+                       break;
+               case 1:
+                       dev_dbg(hub_dev, "Single TT\n");
+                       hub->tt.hub = dev;
+                       break;
+               case 2:
+                       dev_dbg(hub_dev, "TT per port\n");
+                       hub->tt.hub = dev;
+                       hub->tt.multi = 1;
+                       break;
+               default:
+                       dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
+                               dev->descriptor.bDeviceProtocol);
+                       break;
+       }
+
+       switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
+               case 0x00:
+                       if (dev->descriptor.bDeviceProtocol != 0)
+                               dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n");
+                       break;
+               case 0x20:
+                       dev_dbg(hub_dev, "TT requires at most 16 FS bit times\n");
+                       break;
+               case 0x40:
+                       dev_dbg(hub_dev, "TT requires at most 24 FS bit times\n");
+                       break;
+               case 0x60:
+                       dev_dbg(hub_dev, "TT requires at most 32 FS bit times\n");
+                       break;
+       }
+
+       dev_dbg(hub_dev, "Port indicators are %s supported\n", 
+           (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND)
+               ? "" : "not");
+
+       dev_dbg(hub_dev, "power on to power good time: %dms\n",
+               hub->descriptor->bPwrOn2PwrGood * 2);
+       dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
+               hub->descriptor->bHubContrCurrent);
+
+       ret = hub_hub_status(hub, &hubstatus, &hubchange);
+       if (ret < 0) {
+               message = "can't get hub status";
+               goto fail;
+       }
+
+       dev_dbg(hub_dev, "local power source is %s\n",
+               (hubstatus & HUB_STATUS_LOCAL_POWER)
+               ? "lost (inactive)" : "good");
+
+       dev_dbg(hub_dev, "%sover-current condition exists\n",
+               (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+
+       /* Start the interrupt endpoint */
+       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       if (maxp > sizeof(*hub->buffer))
+               maxp = sizeof(*hub->buffer);
+
+       hub->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!hub->urb) {
+               message = "couldn't allocate interrupt urb";
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,
+               hub, endpoint->bInterval);
+       hub->urb->transfer_dma = hub->buffer_dma;
+       hub->urb->transfer_flags |= URB_NO_DMA_MAP;
+       ret = usb_submit_urb(hub->urb, GFP_KERNEL);
+       if (ret) {
+               message = "couldn't submit status urb";
+               goto fail;
+       }
+
+       /* Wake up khubd */
+       wake_up(&khubd_wait);
+
+       hub_power_on(hub);
+
+       return 0;
+
+fail:
+       dev_err (&hub->intf->dev, "config failed, %s (err %d)\n",
+                       message, ret);
+       /* hub_disconnect() frees urb and descriptor */
+       return ret;
+}
+
+static void hub_disconnect(struct usb_interface *intf)
+{
+       struct usb_hub *hub = usb_get_intfdata (intf);
+       unsigned long flags;
+
+       if (!hub)
+               return;
+
+       usb_set_intfdata (intf, NULL);
+       spin_lock_irqsave(&hub_event_lock, flags);
+
+       /* Delete it and then reset it */
+       list_del(&hub->event_list);
+       INIT_LIST_HEAD(&hub->event_list);
+       list_del(&hub->hub_list);
+       INIT_LIST_HEAD(&hub->hub_list);
+
+       spin_unlock_irqrestore(&hub_event_lock, flags);
+
+       down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
+       up(&hub->khubd_sem);
+
+       /* assuming we used keventd, it must quiesce too */
+       if (hub->tt.hub)
+               flush_scheduled_work ();
+
+       if (hub->urb) {
+               usb_unlink_urb(hub->urb);
+               usb_free_urb(hub->urb);
+               hub->urb = NULL;
+       }
+
+       if (hub->descriptor) {
+               kfree(hub->descriptor);
+               hub->descriptor = NULL;
+       }
+
+       if (hub->status) {
+               kfree(hub->status);
+               hub->status = NULL;
+       }
+
+       if (hub->buffer) {
+               usb_buffer_free(interface_to_usbdev(intf),
+                               sizeof(*hub->buffer), hub->buffer,
+                               hub->buffer_dma);
+               hub->buffer = NULL;
+       }
+
+       /* Free the memory */
+       kfree(hub);
+}
+
+static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_host_interface *desc;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_device *dev;
+       struct usb_hub *hub;
+       unsigned long flags;
+
+       desc = intf->altsetting + intf->act_altsetting;
+       dev = interface_to_usbdev(intf);
+
+       /* Some hubs have a subclass of 1, which AFAICT according to the */
+       /*  specs is not defined, but it works */
+       if ((desc->desc.bInterfaceSubClass != 0) &&
+           (desc->desc.bInterfaceSubClass != 1)) {
+descriptor_error:
+               dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
+               return -EIO;
+       }
+
+       /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+       if (desc->desc.bNumEndpoints != 1) {
+               goto descriptor_error;
+       }
+
+       endpoint = &desc->endpoint[0].desc;
+
+       /* Output endpoint? Curiouser and curiouser.. */
+       if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
+               goto descriptor_error;
+       }
+
+       /* If it's not an interrupt endpoint, we'd better punt! */
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                       != USB_ENDPOINT_XFER_INT) {
+               goto descriptor_error;
+               return -EIO;
+       }
+
+       /* We found a hub */
+       dev_info (hubdev (dev), "USB hub found\n");
+
+       hub = kmalloc(sizeof(*hub), GFP_KERNEL);
+       if (!hub) {
+               err("couldn't kmalloc hub struct");
+               return -ENOMEM;
+       }
+
+       memset(hub, 0, sizeof(*hub));
+
+       INIT_LIST_HEAD(&hub->event_list);
+       hub->intf = intf;
+       init_MUTEX(&hub->khubd_sem);
+
+       /* Record the new hub's existence */
+       spin_lock_irqsave(&hub_event_lock, flags);
+       INIT_LIST_HEAD(&hub->hub_list);
+       list_add(&hub->hub_list, &hub_list);
+       spin_unlock_irqrestore(&hub_event_lock, flags);
+
+       usb_set_intfdata (intf, hub);
+
+       if (hub_configure(hub, endpoint) >= 0) {
+               strcpy (intf->dev.name, "Hub");
+               return 0;
+       }
+
+       hub_disconnect (intf);
+       return -ENODEV;
+}
+
+static int
+hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
+{
+       struct usb_device *hub = interface_to_usbdev (intf);
+
+       /* assert ifno == 0 (part of hub spec) */
+       switch (code) {
+       case USBDEVFS_HUB_PORTINFO: {
+               struct usbdevfs_hub_portinfo *info = user_data;
+               unsigned long flags;
+               int i;
+
+               spin_lock_irqsave(&hub_event_lock, flags);
+               if (hub->devnum <= 0)
+                       info->nports = 0;
+               else {
+                       info->nports = hub->maxchild;
+                       for (i = 0; i < info->nports; i++) {
+                               if (hub->children[i] == NULL)
+                                       info->port[i] = 0;
+                               else
+                                       info->port[i] =
+                                               hub->children[i]->devnum;
+                       }
+               }
+               spin_unlock_irqrestore(&hub_event_lock, flags);
+
+               return info->nports + 1;
+               }
+
+       default:
+               return -ENOSYS;
+       }
+}
+
+static int hub_reset(struct usb_hub *hub)
+{
+       struct usb_device *dev = interface_to_usbdev(hub->intf);
+       int i;
+
+       /* Disconnect any attached devices */
+       for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
+               if (dev->children[i])
+                       usb_disconnect(&dev->children[i]);
+       }
+
+       /* Attempt to reset the hub */
+       if (hub->urb)
+               usb_unlink_urb(hub->urb);
+       else
+               return -1;
+
+       if (usb_reset_device(dev))
+               return -1;
+
+       hub->urb->dev = dev;                                                    
+       if (usb_submit_urb(hub->urb, GFP_KERNEL))
+               return -1;
+
+       hub_power_on(hub);
+
+       return 0;
+}
+
+static void hub_start_disconnect(struct usb_device *dev)
+{
+       struct usb_device *parent = dev->parent;
+       int i;
+
+       /* Find the device pointer to disconnect */
+       if (parent) {
+               for (i = 0; i < parent->maxchild; i++) {
+                       if (parent->children[i] == dev) {
+                               usb_disconnect(&parent->children[i]);
+                               return;
+                       }
+               }
+       }
+
+       err("cannot disconnect hub %s", dev->devpath);
+}
+
+static int hub_port_status(struct usb_device *dev, int port,
+                              u16 *status, u16 *change)
+{
+       struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);
+       int ret;
+
+       ret = get_port_status(dev, port + 1, &hub->status->port);
+       if (ret < 0)
+               dev_err (hubdev (dev),
+                       "%s failed (err = %d)\n", __FUNCTION__, ret);
+       else {
+               *status = le16_to_cpu(hub->status->port.wPortStatus);
+               *change = le16_to_cpu(hub->status->port.wPortChange); 
+               ret = 0;
+       }
+       return ret;
+}
+
+#define HUB_RESET_TRIES                5
+#define HUB_PROBE_TRIES                2
+#define HUB_SHORT_RESET_TIME   10
+#define HUB_LONG_RESET_TIME    200
+#define HUB_RESET_TIMEOUT      500
+
+/* return: -1 on error, 0 on success, 1 on disconnect.  */
+static int hub_port_wait_reset(struct usb_device *hub, int port,
+                               struct usb_device *dev, unsigned int delay)
+{
+       int delay_time, ret;
+       u16 portstatus;
+       u16 portchange;
+
+       for (delay_time = 0;
+                       delay_time < HUB_RESET_TIMEOUT;
+                       delay_time += delay) {
+               /* wait to give the device a chance to reset */
+               wait_ms(delay);
+
+               /* read and decode port status */
+               ret = hub_port_status(hub, port, &portstatus, &portchange);
+               if (ret < 0) {
+                       return -1;
+               }
+
+               /* Device went away? */
+               if (!(portstatus & USB_PORT_STAT_CONNECTION))
+                       return 1;
+
+               /* bomb out completely if something weird happened */
+               if ((portchange & USB_PORT_STAT_C_CONNECTION))
+                       return -1;
+
+               /* if we`ve finished resetting, then break out of the loop */
+               if (!(portstatus & USB_PORT_STAT_RESET) &&
+                   (portstatus & USB_PORT_STAT_ENABLE)) {
+                       if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+                               dev->speed = USB_SPEED_HIGH;
+                       else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+                               dev->speed = USB_SPEED_LOW;
+                       else
+                               dev->speed = USB_SPEED_FULL;
+                       return 0;
+               }
+
+               /* switch to the long delay after two short delay failures */
+               if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
+                       delay = HUB_LONG_RESET_TIME;
+
+               dev_dbg (hubdev (hub),
+                       "port %d not reset yet, waiting %dms\n",
+                       port + 1, delay);
+       }
+
+       return -1;
+}
+
+/* return: -1 on error, 0 on success, 1 on disconnect.  */
+static int hub_port_reset(struct usb_device *hub, int port,
+                               struct usb_device *dev, unsigned int delay)
+{
+       int i, status;
+
+       /* Reset the port */
+       for (i = 0; i < HUB_RESET_TRIES; i++) {
+               set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+
+               /* return on disconnect or reset */
+               status = hub_port_wait_reset(hub, port, dev, delay);
+               if (status != -1) {
+                       clear_port_feature(hub,
+                               port + 1, USB_PORT_FEAT_C_RESET);
+                       dev->state = status
+                                       ? USB_STATE_NOTATTACHED
+                                       : USB_STATE_DEFAULT;
+                       return status;
+               }
+
+               dev_dbg (hubdev (hub),
+                       "port %d not enabled, trying reset again...\n",
+                       port + 1);
+               delay = HUB_LONG_RESET_TIME;
+       }
+
+       dev_err (hubdev (hub),
+               "Cannot enable port %i.  Maybe the USB cable is bad?\n",
+               port + 1);
+
+       return -1;
+}
+
+int hub_port_disable(struct usb_device *hub, int port)
+{
+       int ret;
+
+       ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
+       if (ret)
+               dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
+                       port + 1, ret);
+
+       return ret;
+}
+
+/* USB 2.0 spec, 7.1.7.3 / fig 7-29:
+ *
+ * Between connect detection and reset signaling there must be a delay
+ * of 100ms at least for debounce and power-settling. The corresponding
+ * timer shall restart whenever the downstream port detects a disconnect.
+ * 
+ * Apparently there are some bluetooth and irda-dongles and a number
+ * of low-speed devices which require longer delays of about 200-400ms.
+ * Not covered by the spec - but easy to deal with.
+ *
+ * This implementation uses 400ms minimum debounce timeout and checks
+ * every 25ms for transient disconnects to restart the delay.
+ */
+
+#define HUB_DEBOUNCE_TIMEOUT   400
+#define HUB_DEBOUNCE_STEP       25
+#define HUB_DEBOUNCE_STABLE      4
+
+/* return: -1 on error, 0 on success, 1 on disconnect.  */
+static int hub_port_debounce(struct usb_device *hub, int port)
+{
+       int ret;
+       int delay_time, stable_count;
+       u16 portchange, portstatus;
+       unsigned connection;
+
+       connection = 0;
+       stable_count = 0;
+       for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
+               wait_ms(HUB_DEBOUNCE_STEP);
+
+               ret = hub_port_status(hub, port, &portstatus, &portchange);
+               if (ret < 0)
+                       return -1;
+
+               if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) {
+                       if (connection) {
+                               if (++stable_count == HUB_DEBOUNCE_STABLE)
+                                       break;
+                       }
+               } else {
+                       stable_count = 0;
+               }
+               connection = portstatus & USB_PORT_STAT_CONNECTION;
+
+               if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
+                       clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
+               }
+       }
+
+       /* XXX Replace this with dbg() when 2.6 is about to ship. */
+       dev_dbg (hubdev (hub),
+               "debounce: port %d: delay %dms stable %d status 0x%x\n",
+               port + 1, delay_time, stable_count, portstatus);
+
+       return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
+}
+
+static void hub_port_connect_change(struct usb_hub *hubstate, int port,
+                                       u16 portstatus, u16 portchange)
+{
+       struct usb_device *hub = interface_to_usbdev(hubstate->intf);
+       struct usb_device *dev;
+       unsigned int delay = HUB_SHORT_RESET_TIME;
+       int i;
+
+       dev_dbg (&hubstate->intf->dev,
+               "port %d, status %x, change %x, %s\n",
+               port + 1, portstatus, portchange, portspeed (portstatus));
+
+       /* Clear the connection change status */
+       clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+       /* Disconnect any existing devices under this port */
+       if (hub->children[port])
+               usb_disconnect(&hub->children[port]);
+
+       /* Return now if nothing is connected */
+       if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
+               if (portstatus & USB_PORT_STAT_ENABLE)
+                       hub_port_disable(hub, port);
+
+               return;
+       }
+
+       if (hub_port_debounce(hub, port)) {
+               dev_err (&hubstate->intf->dev,
+                       "connect-debounce failed, port %d disabled\n",
+                       port+1);
+               hub_port_disable(hub, port);
+               return;
+       }
+
+       /* Some low speed devices have problems with the quick delay, so */
+       /*  be a bit pessimistic with those devices. RHbug #23670 */
+       if (portstatus & USB_PORT_STAT_LOW_SPEED)
+               delay = HUB_LONG_RESET_TIME;
+
+       down(&usb_address0_sem);
+
+       for (i = 0; i < HUB_PROBE_TRIES; i++) {
+               struct usb_device *pdev;
+               int     len;
+
+               /* Allocate a new device struct */
+               dev = usb_alloc_dev(hub, hub->bus);
+               if (!dev) {
+                       dev_err (&hubstate->intf->dev,
+                               "couldn't allocate usb_device\n");
+                       break;
+               }
+
+               hub->children[port] = dev;
+               dev->state = USB_STATE_POWERED;
+
+               /* Reset the device, and detect its speed */
+               if (hub_port_reset(hub, port, dev, delay)) {
+                       usb_put_dev(dev);
+                       break;
+               }
+
+               /* Find a new address for it */
+               usb_connect(dev);
+
+               /* Set up TT records, if needed  */
+               if (hub->tt) {
+                       dev->tt = hub->tt;
+                       dev->ttport = hub->ttport;
+               } else if (dev->speed != USB_SPEED_HIGH
+                               && hub->speed == USB_SPEED_HIGH) {
+                       dev->tt = &hubstate->tt;
+                       dev->ttport = port + 1;
+               }
+
+               /* Save readable and stable topology id, distinguishing
+                * devices by location for diagnostics, tools, etc.  The
+                * string is a path along hub ports, from the root.  Each
+                * device's id will be stable until USB is re-cabled, and
+                * hubs are often labeled with these port numbers.
+                *
+                * Initial size: ".NN" times five hubs + NUL = 16 bytes max
+                * (quite rare, since most hubs have 4-6 ports).
+                */
+               pdev = dev->parent;
+               if (pdev->devpath [0] != '0')   /* parent not root? */
+                       len = snprintf (dev->devpath, sizeof dev->devpath,
+                               "%s.%d", pdev->devpath, port + 1);
+               /* root == "0", root port 2 == "2", port 3 that hub "2.3" */
+               else
+                       len = snprintf (dev->devpath, sizeof dev->devpath,
+                               "%d", port + 1);
+               if (len == sizeof dev->devpath)
+                       dev_err (&hubstate->intf->dev,
+                               "devpath size! usb/%03d/%03d path %s\n",
+                               dev->bus->busnum, dev->devnum, dev->devpath);
+               dev_info (&hubstate->intf->dev,
+                       "new USB device on port %d, assigned address %d\n",
+                       port + 1, dev->devnum);
+
+               /* put the device in the global device tree. the hub port
+                * is the "bus_id"; hubs show in hierarchy like bridges
+                */
+               dev->dev.parent = dev->parent->dev.parent->parent;
+
+               /* Run it through the hoops (find a driver, etc) */
+               if (!usb_new_device(dev, &hub->dev))
+                       goto done;
+
+               /* Free the configuration if there was an error */
+               usb_put_dev(dev);
+
+               /* Switch to a long reset time */
+               delay = HUB_LONG_RESET_TIME;
+       }
+
+       hub->children[port] = NULL;
+       hub_port_disable(hub, port);
+done:
+       up(&usb_address0_sem);
+}
+
+static void hub_events(void)
+{
+       unsigned long flags;
+       struct list_head *tmp;
+       struct usb_device *dev;
+       struct usb_hub *hub;
+       u16 hubstatus;
+       u16 hubchange;
+       u16 portstatus;
+       u16 portchange;
+       int i, ret;
+       int m=0;
+       /*
+        *  We restart the list every time to avoid a deadlock with
+        * deleting hubs downstream from this one. This should be
+        * safe since we delete the hub from the event list.
+        * Not the most efficient, but avoids deadlocks.
+        */
+
+       while (m<5) {
+               m++;
+               spin_lock_irqsave(&hub_event_lock, flags);
+
+               if (list_empty(&hub_event_list))
+                       break;
+
+               /* Grab the next entry from the beginning of the list */
+               tmp = hub_event_list.next;
+
+               hub = list_entry(tmp, struct usb_hub, event_list);
+               dev = interface_to_usbdev(hub->intf);
+
+               list_del_init(tmp);
+
+               if (unlikely(down_trylock(&hub->khubd_sem)))
+                       BUG();  /* never blocks, we were on list */
+
+               spin_unlock_irqrestore(&hub_event_lock, flags);
+
+               if (hub->error) {
+                       dev_dbg (&hub->intf->dev, "resetting for error %d\n",
+                               hub->error);
+
+                       if (hub_reset(hub)) {
+                               dev_dbg (&hub->intf->dev,
+                                       "can't reset; disconnecting\n");
+                               up(&hub->khubd_sem);
+                               hub_start_disconnect(dev);
+                               continue;
+                       }
+
+                       hub->nerrors = 0;
+                       hub->error = 0;
+               }
+
+               for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
+                       ret = hub_port_status(dev, i, &portstatus, &portchange);
+                       if (ret < 0) {
+                               continue;
+                       }
+
+                       if (portchange & USB_PORT_STAT_C_CONNECTION) {
+                               hub_port_connect_change(hub, i, portstatus, portchange);
+                       } else if (portchange & USB_PORT_STAT_C_ENABLE) {
+                               dev_dbg (hubdev (dev),
+                                       "port %d enable change, status %x\n",
+                                       i + 1, portstatus);
+                               clear_port_feature(dev,
+                                       i + 1, USB_PORT_FEAT_C_ENABLE);
+
+                               /*
+                                * EM interference sometimes causes badly
+                                * 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])) {
+                                       dev_err (&hub->intf->dev,
+                                           "port %i "
+                                           "disabled by hub (EMI?), "
+                                           "re-enabling...",
+                                               i + 1);
+                                       hub_port_connect_change(hub,
+                                               i, portstatus, portchange);
+                               }
+                       }
+
+                       if (portchange & USB_PORT_STAT_C_SUSPEND) {
+                               dev_dbg (&hub->intf->dev,
+                                       "suspend change on port %d\n",
+                                       i + 1);
+                               clear_port_feature(dev,
+                                       i + 1,  USB_PORT_FEAT_C_SUSPEND);
+                       }
+                       
+                       if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+                               dev_err (&hub->intf->dev,
+                                       "over-current change on port %d\n",
+                                       i + 1);
+                               clear_port_feature(dev,
+                                       i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+                               hub_power_on(hub);
+                       }
+
+                       if (portchange & USB_PORT_STAT_C_RESET) {
+                               dev_dbg (&hub->intf->dev,
+                                       "reset change on port %d\n",
+                                       i + 1);
+                               clear_port_feature(dev,
+                                       i + 1, USB_PORT_FEAT_C_RESET);
+                       }
+               } /* end for i */
+
+               /* deal with hub status changes */
+               if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
+                       dev_err (&hub->intf->dev, "get_hub_status failed\n");
+               else {
+                       if (hubchange & HUB_CHANGE_LOCAL_POWER) {
+                               dev_dbg (&hub->intf->dev, "power change\n");
+                               clear_hub_feature(dev, C_HUB_LOCAL_POWER);
+                       }
+                       if (hubchange & HUB_CHANGE_OVERCURRENT) {
+                               dev_dbg (&hub->intf->dev, "overcurrent change\n");
+                               wait_ms(500);   /* Cool down */
+                               clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+                               hub_power_on(hub);
+                       }
+               }
+               up(&hub->khubd_sem);
+        } /* end while (1) */
+
+       spin_unlock_irqrestore(&hub_event_lock, flags);
+}
+
+static int hub_thread(void *__hub)
+{
+       /*
+        * This thread doesn't need any user-level access,
+        * so get rid of all our resources
+        */
+
+       daemonize("khubd");
+       allow_signal(SIGKILL);
+       /* Send me a signal to get me die (for debugging) */
+       do {
+               
+               hub_events();
+
+               //FIXME: Correct this
+               //wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); // interruptable_sleep_on analog - below
+               while (!list_empty(&hub_event_list)) {
+                       interruptible_sleep_on(&khubd_wait);
+               }
+
+               if (current->flags & PF_FREEZE)
+                       refrigerator(PF_IOTHREAD);
+
+       } while (!signal_pending(current));
+
+//     dbg("hub_thread exiting");
+       complete_and_exit(&khubd_exited, 0);
+}
+
+static struct usb_device_id hub_id_table [] = {
+    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
+      .bDeviceClass = USB_CLASS_HUB},
+    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+      .bInterfaceClass = USB_CLASS_HUB},
+    { }                                                /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hub_id_table);
+
+static struct usb_driver hub_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "hub",
+       .probe =        hub_probe,
+       .disconnect =   hub_disconnect,
+       .ioctl =        hub_ioctl,
+       .id_table =     hub_id_table,
+};
+
+/*
+ * This should be a separate module.
+ */
+int usb_hub_init(void)
+{
+       pid_t pid;
+
+       // ReactOS-specific
+       // Create Event object, initialize other sync events
+       KeInitializeEvent(&khubd_wait, NotificationEvent, TRUE); // signalled state
+
+       if (usb_register(&hub_driver) < 0) {
+               err("Unable to register USB hub driver");
+               return -1;
+       }
+
+       pid = kernel_thread(hub_thread, NULL,
+               CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+       if (pid >= 0) {
+               khubd_pid = pid;
+               return 0;
+       }
+
+       /* Fall through if kernel_thread failed */
+       usb_deregister(&hub_driver);
+       err("failed to start hub_thread");
+
+       return -1;
+}
+
+void usb_hub_cleanup(void)
+{
+       int ret;
+
+       /* Kill the thread */
+       ret = kill_proc(khubd_pid, SIGKILL, 1);
+
+       wait_for_completion(&khubd_exited);
+
+       /*
+        * Hub resources are freed for us by usb_deregister. It calls
+        * usb_driver_purge on every device which in turn calls that
+        * devices disconnect function if it is using this driver.
+        * The hub_disconnect function takes care of releasing the
+        * individual hub resources. -greg
+        */
+       usb_deregister(&hub_driver);
+} /* usb_hub_cleanup() */
+
+/*
+ * WARNING - If a driver calls usb_reset_device, you should simulate a
+ * disconnect() and probe() for other interfaces you doesn't claim. This
+ * is left up to the driver writer right now. This insures other drivers
+ * have a chance to re-setup their interface.
+ *
+ * Take a look at proc_resetdevice in devio.c for some sample code to
+ * do this.
+ * Use this only from within your probe function, otherwise use
+ * usb_reset_device() below, which ensure proper locking
+ */
+int usb_physical_reset_device(struct usb_device *dev)
+{
+       struct usb_device *parent = dev->parent;
+       struct usb_device_descriptor *descriptor;
+       int i, ret, port = -1;
+
+       if (!parent) {
+               err("attempting to reset root hub!");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < parent->maxchild; i++)
+               if (parent->children[i] == dev) {
+                       port = i;
+                       break;
+               }
+
+       if (port < 0)
+               return -ENOENT;
+
+       descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
+       if (!descriptor) {
+               return -ENOMEM;
+       }
+
+       down(&usb_address0_sem);
+
+       /* Send a reset to the device */
+       if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {
+               hub_port_disable(parent, port);
+               up(&usb_address0_sem);
+               kfree(descriptor);
+               return(-ENODEV);
+       }
+
+       /* Reprogram the Address */
+       ret = usb_set_address(dev);
+       if (ret < 0) {
+               err("USB device not accepting new address (error=%d)", ret);
+               hub_port_disable(parent, port);
+               up(&usb_address0_sem);
+               kfree(descriptor);
+               return ret;
+       }
+
+       /* Let the SET_ADDRESS settle */
+       wait_ms(10);
+
+       up(&usb_address0_sem);
+
+       /*
+        * Now we fetch the configuration descriptors for the device and
+        * see if anything has changed. If it has, we dump the current
+        * parsed descriptors and reparse from scratch. Then we leave
+        * the device alone for the caller to finish setting up.
+        *
+        * If nothing changed, we reprogram the configuration and then
+        * the alternate settings.
+        */
+
+       ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
+                       sizeof(*descriptor));
+       if (ret < 0) {
+               kfree(descriptor);
+               return ret;
+       }
+
+       le16_to_cpus(&descriptor->bcdUSB);
+       le16_to_cpus(&descriptor->idVendor);
+       le16_to_cpus(&descriptor->idProduct);
+       le16_to_cpus(&descriptor->bcdDevice);
+
+       if (RtlCompareMemory(&dev->descriptor, descriptor, sizeof(*descriptor))) {
+               kfree(descriptor);
+               usb_destroy_configuration(dev);
+
+               ret = usb_get_device_descriptor(dev);
+               if (ret < sizeof(dev->descriptor)) {
+                       if (ret < 0)
+                               err("unable to get device %s descriptor "
+                                       "(error=%d)", dev->devpath, ret);
+                       else
+                               err("USB device %s descriptor short read "
+                                       "(expected %Zi, got %i)",
+                                       dev->devpath,
+                                       sizeof(dev->descriptor), ret);
+
+                       clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+                       dev->devnum = -1;
+                       return -EIO;
+               }
+
+               ret = usb_get_configuration(dev);
+               if (ret < 0) {
+                       err("unable to get configuration (error=%d)", ret);
+                       usb_destroy_configuration(dev);
+                       clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+                       dev->devnum = -1;
+                       return 1;
+               }
+
+               dev->actconfig = dev->config;
+               usb_set_maxpacket(dev);
+
+               return 1;
+       }
+
+       kfree(descriptor);
+
+       ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue);
+       if (ret < 0) {
+               err("failed to set dev %s active configuration (error=%d)",
+                       dev->devpath, ret);
+               return ret;
+       }
+
+       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+               struct usb_interface *intf = &dev->actconfig->interface[i];
+               struct usb_interface_descriptor *as;
+
+               as = &intf->altsetting[intf->act_altsetting].desc;
+               ret = usb_set_interface(dev, as->bInterfaceNumber,
+                       as->bAlternateSetting);
+               if (ret < 0) {
+                       err("failed to set active alternate setting "
+                               "for dev %s interface %d (error=%d)",
+                               dev->devpath, i, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+int usb_reset_device(struct usb_device *udev)
+{
+       //struct device *gdev = &udev->dev;
+       int r;
+       
+       down_read(&gdev->bus->subsys.rwsem);
+       r = usb_physical_reset_device(udev);
+       up_read(&gdev->bus->subsys.rwsem);
+
+       return r;
+}
+
+
index f51a999..1e25078 100644 (file)
-#ifndef __LINUX_HUB_H\r
-#define __LINUX_HUB_H\r
-\r
-/*\r
- * Hub protocol and driver data structures.\r
- *\r
- * Some of these are known to the "virtual root hub" code\r
- * in host controller drivers.\r
- */\r
-#if 0\r
-#include <linux/list.h>\r
-#include <linux/workqueue.h>\r
-#include <linux/compiler.h>    /* likely()/unlikely() */\r
-#endif \r
-/*\r
- * Hub request types\r
- */\r
-\r
-#define USB_RT_HUB     (USB_TYPE_CLASS | USB_RECIP_DEVICE)\r
-#define USB_RT_PORT    (USB_TYPE_CLASS | USB_RECIP_OTHER)\r
-\r
-/*\r
- * Hub class requests\r
- * See USB 2.0 spec Table 11-16\r
- */\r
-#define HUB_CLEAR_TT_BUFFER    8\r
-#define HUB_RESET_TT           9\r
-#define HUB_GET_TT_STATE       10\r
-#define HUB_STOP_TT            11\r
-\r
-/*\r
- * Hub Class feature numbers\r
- * See USB 2.0 spec Table 11-17\r
- */\r
-#define C_HUB_LOCAL_POWER      0\r
-#define C_HUB_OVER_CURRENT     1\r
-\r
-/*\r
- * Port feature numbers\r
- * See USB 2.0 spec Table 11-17\r
- */\r
-#define USB_PORT_FEAT_CONNECTION       0\r
-#define USB_PORT_FEAT_ENABLE           1\r
-#define USB_PORT_FEAT_SUSPEND          2\r
-#define USB_PORT_FEAT_OVER_CURRENT     3\r
-#define USB_PORT_FEAT_RESET            4\r
-#define USB_PORT_FEAT_POWER            8\r
-#define USB_PORT_FEAT_LOWSPEED         9\r
-#define USB_PORT_FEAT_HIGHSPEED                10\r
-#define USB_PORT_FEAT_C_CONNECTION     16\r
-#define USB_PORT_FEAT_C_ENABLE         17\r
-#define USB_PORT_FEAT_C_SUSPEND                18\r
-#define USB_PORT_FEAT_C_OVER_CURRENT   19\r
-#define USB_PORT_FEAT_C_RESET          20\r
-#define USB_PORT_FEAT_TEST              21\r
-#define USB_PORT_FEAT_INDICATOR         22\r
-\r
-/* \r
- * Hub Status and Hub Change results\r
- * See USB 2.0 spec Table 11-19 and Table 11-20\r
- */\r
-struct usb_port_status {\r
-       __u16 wPortStatus;\r
-       __u16 wPortChange;      \r
-} __attribute__ ((packed));\r
-\r
-/* \r
- * wPortStatus bit field\r
- * See USB 2.0 spec Table 11-21\r
- */\r
-#define USB_PORT_STAT_CONNECTION       0x0001\r
-#define USB_PORT_STAT_ENABLE           0x0002\r
-#define USB_PORT_STAT_SUSPEND          0x0004\r
-#define USB_PORT_STAT_OVERCURRENT      0x0008\r
-#define USB_PORT_STAT_RESET            0x0010\r
-/* bits 5 to 7 are reserved */\r
-#define USB_PORT_STAT_POWER            0x0100\r
-#define USB_PORT_STAT_LOW_SPEED                0x0200\r
-#define USB_PORT_STAT_HIGH_SPEED        0x0400\r
-#define USB_PORT_STAT_TEST              0x0800\r
-#define USB_PORT_STAT_INDICATOR         0x1000\r
-/* bits 13 to 15 are reserved */\r
-\r
-/* \r
- * wPortChange bit field\r
- * See USB 2.0 spec Table 11-22\r
- * Bits 0 to 4 shown, bits 5 to 15 are reserved\r
- */\r
-#define USB_PORT_STAT_C_CONNECTION     0x0001\r
-#define USB_PORT_STAT_C_ENABLE         0x0002\r
-#define USB_PORT_STAT_C_SUSPEND                0x0004\r
-#define USB_PORT_STAT_C_OVERCURRENT    0x0008\r
-#define USB_PORT_STAT_C_RESET          0x0010\r
-\r
-/*\r
- * wHubCharacteristics (masks) \r
- * See USB 2.0 spec Table 11-13, offset 3\r
- */\r
-#define HUB_CHAR_LPSM          0x0003 /* D1 .. D0 */\r
-#define HUB_CHAR_COMPOUND      0x0004 /* D2       */\r
-#define HUB_CHAR_OCPM          0x0018 /* D4 .. D3 */\r
-#define HUB_CHAR_TTTT           0x0060 /* D6 .. D5 */\r
-#define HUB_CHAR_PORTIND        0x0080 /* D7       */\r
-\r
-struct usb_hub_status {\r
-       __u16 wHubStatus;\r
-       __u16 wHubChange;\r
-} __attribute__ ((packed));\r
-\r
-/*\r
- * Hub Status & Hub Change bit masks\r
- * See USB 2.0 spec Table 11-19 and Table 11-20\r
- * Bits 0 and 1 for wHubStatus and wHubChange\r
- * Bits 2 to 15 are reserved for both\r
- */\r
-#define HUB_STATUS_LOCAL_POWER 0x0001\r
-#define HUB_STATUS_OVERCURRENT 0x0002\r
-#define HUB_CHANGE_LOCAL_POWER 0x0001\r
-#define HUB_CHANGE_OVERCURRENT 0x0002\r
-\r
-\r
-/* \r
- * Hub descriptor \r
- * See USB 2.0 spec Table 11-13\r
- */\r
-\r
-#define USB_DT_HUB                     (USB_TYPE_CLASS | 0x09)\r
-#define USB_DT_HUB_NONVAR_SIZE         7\r
-\r
-struct usb_hub_descriptor {\r
-       __u8  bDescLength;\r
-       __u8  bDescriptorType;\r
-       __u8  bNbrPorts;\r
-       __u16 wHubCharacteristics;\r
-       __u8  bPwrOn2PwrGood;\r
-       __u8  bHubContrCurrent;\r
-               /* add 1 bit for hub status change; round to bytes */\r
-       __u8  DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];\r
-       __u8  PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];\r
-} __attribute__ ((packed));\r
-\r
-struct usb_device;\r
-\r
-/*\r
- * As of USB 2.0, full/low speed devices are segregated into trees.\r
- * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).\r
- * The other type grows from high speed hubs when they connect to\r
- * full/low speed devices using "Transaction Translators" (TTs).\r
- *\r
- * TTs should only be known to the hub driver, and high speed bus\r
- * drivers (only EHCI for now).  They affect periodic scheduling and\r
- * sometimes control/bulk error recovery.\r
- */\r
-struct usb_tt {\r
-       struct usb_device       *hub;   /* upstream highspeed hub */\r
-       int                     multi;  /* true means one TT per port */\r
-\r
-       /* for control/bulk error recovery (CLEAR_TT_BUFFER) */\r
-       spinlock_t              lock;\r
-       struct list_head        clear_list;     /* of usb_tt_clear */\r
-       struct work_struct                      kevent;\r
-};\r
-\r
-struct usb_tt_clear {\r
-       struct list_head        clear_list;\r
-       unsigned                tt;\r
-       u16                     devinfo;\r
-};\r
-\r
-extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);\r
-\r
-struct usb_hub {\r
-       struct usb_interface    *intf;          /* the "real" device */\r
-       struct urb              *urb;           /* for interrupt polling pipe */\r
-\r
-       /* buffer for urb ... 1 bit each for hub and children, rounded up */\r
-       char                    (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];\r
-       dma_addr_t              buffer_dma;     /* DMA address for buffer */\r
-       union {\r
-               struct usb_hub_status   hub;\r
-               struct usb_port_status  port;\r
-       }                       *status;        /* buffer for status reports */\r
-\r
-       int                     error;          /* last reported error */\r
-       int                     nerrors;        /* track consecutive errors */\r
-\r
-       struct list_head        hub_list;       /* all hubs */\r
-       struct list_head        event_list;     /* hubs w/data or errs ready */\r
-\r
-       struct usb_hub_descriptor *descriptor;  /* class descriptor */\r
-       struct semaphore        khubd_sem;\r
-       struct usb_tt           tt;             /* Transaction Translator */\r
-};\r
-\r
-#endif /* __LINUX_HUB_H */\r
+#ifndef __LINUX_HUB_H
+#define __LINUX_HUB_H
+
+/*
+ * Hub protocol and driver data structures.
+ *
+ * Some of these are known to the "virtual root hub" code
+ * in host controller drivers.
+ */
+#if 0
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/compiler.h>    /* likely()/unlikely() */
+#endif 
+/*
+ * Hub request types
+ */
+
+#define USB_RT_HUB     (USB_TYPE_CLASS | USB_RECIP_DEVICE)
+#define USB_RT_PORT    (USB_TYPE_CLASS | USB_RECIP_OTHER)
+
+/*
+ * Hub class requests
+ * See USB 2.0 spec Table 11-16
+ */
+#define HUB_CLEAR_TT_BUFFER    8
+#define HUB_RESET_TT           9
+#define HUB_GET_TT_STATE       10
+#define HUB_STOP_TT            11
+
+/*
+ * Hub Class feature numbers
+ * See USB 2.0 spec Table 11-17
+ */
+#define C_HUB_LOCAL_POWER      0
+#define C_HUB_OVER_CURRENT     1
+
+/*
+ * Port feature numbers
+ * See USB 2.0 spec Table 11-17
+ */
+#define USB_PORT_FEAT_CONNECTION       0
+#define USB_PORT_FEAT_ENABLE           1
+#define USB_PORT_FEAT_SUSPEND          2
+#define USB_PORT_FEAT_OVER_CURRENT     3
+#define USB_PORT_FEAT_RESET            4
+#define USB_PORT_FEAT_POWER            8
+#define USB_PORT_FEAT_LOWSPEED         9
+#define USB_PORT_FEAT_HIGHSPEED                10
+#define USB_PORT_FEAT_C_CONNECTION     16
+#define USB_PORT_FEAT_C_ENABLE         17
+#define USB_PORT_FEAT_C_SUSPEND                18
+#define USB_PORT_FEAT_C_OVER_CURRENT   19
+#define USB_PORT_FEAT_C_RESET          20
+#define USB_PORT_FEAT_TEST              21
+#define USB_PORT_FEAT_INDICATOR         22
+
+/* 
+ * Hub Status and Hub Change results
+ * See USB 2.0 spec Table 11-19 and Table 11-20
+ */
+struct usb_port_status {
+       __u16 wPortStatus;
+       __u16 wPortChange;      
+} __attribute__ ((packed));
+
+/* 
+ * wPortStatus bit field
+ * See USB 2.0 spec Table 11-21
+ */
+#define USB_PORT_STAT_CONNECTION       0x0001
+#define USB_PORT_STAT_ENABLE           0x0002
+#define USB_PORT_STAT_SUSPEND          0x0004
+#define USB_PORT_STAT_OVERCURRENT      0x0008
+#define USB_PORT_STAT_RESET            0x0010
+/* bits 5 to 7 are reserved */
+#define USB_PORT_STAT_POWER            0x0100
+#define USB_PORT_STAT_LOW_SPEED                0x0200
+#define USB_PORT_STAT_HIGH_SPEED        0x0400
+#define USB_PORT_STAT_TEST              0x0800
+#define USB_PORT_STAT_INDICATOR         0x1000
+/* bits 13 to 15 are reserved */
+
+/* 
+ * wPortChange bit field
+ * See USB 2.0 spec Table 11-22
+ * Bits 0 to 4 shown, bits 5 to 15 are reserved
+ */
+#define USB_PORT_STAT_C_CONNECTION     0x0001
+#define USB_PORT_STAT_C_ENABLE         0x0002
+#define USB_PORT_STAT_C_SUSPEND                0x0004
+#define USB_PORT_STAT_C_OVERCURRENT    0x0008
+#define USB_PORT_STAT_C_RESET          0x0010
+
+/*
+ * wHubCharacteristics (masks) 
+ * See USB 2.0 spec Table 11-13, offset 3
+ */
+#define HUB_CHAR_LPSM          0x0003 /* D1 .. D0 */
+#define HUB_CHAR_COMPOUND      0x0004 /* D2       */
+#define HUB_CHAR_OCPM          0x0018 /* D4 .. D3 */
+#define HUB_CHAR_TTTT           0x0060 /* D6 .. D5 */
+#define HUB_CHAR_PORTIND        0x0080 /* D7       */
+
+struct usb_hub_status {
+       __u16 wHubStatus;
+       __u16 wHubChange;
+} __attribute__ ((packed));
+
+/*
+ * Hub Status & Hub Change bit masks
+ * See USB 2.0 spec Table 11-19 and Table 11-20
+ * Bits 0 and 1 for wHubStatus and wHubChange
+ * Bits 2 to 15 are reserved for both
+ */
+#define HUB_STATUS_LOCAL_POWER 0x0001
+#define HUB_STATUS_OVERCURRENT 0x0002
+#define HUB_CHANGE_LOCAL_POWER 0x0001
+#define HUB_CHANGE_OVERCURRENT 0x0002
+
+
+/* 
+ * Hub descriptor 
+ * See USB 2.0 spec Table 11-13
+ */
+
+#define USB_DT_HUB                     (USB_TYPE_CLASS | 0x09)
+#define USB_DT_HUB_NONVAR_SIZE         7
+
+struct usb_hub_descriptor {
+       __u8  bDescLength;
+       __u8  bDescriptorType;
+       __u8  bNbrPorts;
+       __u16 wHubCharacteristics;
+       __u8  bPwrOn2PwrGood;
+       __u8  bHubContrCurrent;
+               /* add 1 bit for hub status change; round to bytes */
+       __u8  DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
+       __u8  PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
+} __attribute__ ((packed));
+
+struct usb_device;
+
+/*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ *
+ * TTs should only be known to the hub driver, and high speed bus
+ * drivers (only EHCI for now).  They affect periodic scheduling and
+ * sometimes control/bulk error recovery.
+ */
+struct usb_tt {
+       struct usb_device       *hub;   /* upstream highspeed hub */
+       int                     multi;  /* true means one TT per port */
+
+       /* for control/bulk error recovery (CLEAR_TT_BUFFER) */
+       spinlock_t              lock;
+       struct list_head        clear_list;     /* of usb_tt_clear */
+       struct work_struct                      kevent;
+};
+
+struct usb_tt_clear {
+       struct list_head        clear_list;
+       unsigned                tt;
+       u16                     devinfo;
+};
+
+extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
+
+struct usb_hub {
+       struct usb_interface    *intf;          /* the "real" device */
+       struct urb              *urb;           /* for interrupt polling pipe */
+
+       /* buffer for urb ... 1 bit each for hub and children, rounded up */
+       char                    (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
+       dma_addr_t              buffer_dma;     /* DMA address for buffer */
+       union {
+               struct usb_hub_status   hub;
+               struct usb_port_status  port;
+       }                       *status;        /* buffer for status reports */
+
+       int                     error;          /* last reported error */
+       int                     nerrors;        /* track consecutive errors */
+
+       struct list_head        hub_list;       /* all hubs */
+       struct list_head        event_list;     /* hubs w/data or errs ready */
+
+       struct usb_hub_descriptor *descriptor;  /* class descriptor */
+       struct semaphore        khubd_sem;
+       struct usb_tt           tt;             /* Transaction Translator */
+};
+
+#endif /* __LINUX_HUB_H */
index 5301aa3..10ffd28 100644 (file)
@@ -1,22 +1,22 @@
-PATH_TO_TOP = ../../../..\r
-\r
-TARGET_TYPE = export_driver\r
-\r
-TARGET_NAME = usbcore\r
-\r
-TARGET_DDKLIBS = ntoskrnl.a\r
-\r
-TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE\r
-\r
-TARGET_OBJECTS = \\r
-  message.o hcd.o hcd-pci.o hub.o usb.o config.o urb.o \\r
-  buffer_simple.o usb-debug.o ../sys/ros_wrapper.o \\r
-  ../sys/linuxwrapper.o usbcore.o\r
-\r
-include $(PATH_TO_TOP)/rules.mak\r
-\r
-include $(TOOLS_PATH)/helper.mk\r
-\r
-# Automatic dependency tracking\r
-DEP_OBJECTS := $(TARGET_OBJECTS)\r
-include $(PATH_TO_TOP)/tools/depend.mk\r
+PATH_TO_TOP = ../../../..
+
+TARGET_TYPE = export_driver
+
+TARGET_NAME = usbcore
+
+TARGET_DDKLIBS = ntoskrnl.a
+
+TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE
+
+TARGET_OBJECTS = \
+  message.o hcd.o hcd-pci.o hub.o usb.o config.o urb.o \
+  buffer_simple.o usb-debug.o ../sys/ros_wrapper.o \
+  ../sys/linuxwrapper.o usbcore.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
+
+# Automatic dependency tracking
+DEP_OBJECTS := $(TARGET_OBJECTS)
+include $(PATH_TO_TOP)/tools/depend.mk
index 489af58..dd6262c 100644 (file)
@@ -1,6 +1,6 @@
-\r
-O_TARGET :=  message.o hcd.o  hcd-pci.o hub.o usb.o config.o urb.o buffer_simple.o urb.o usb-debug.o\r
-\r
-#O_TARGET :=  urb.o\r
-\r
-include $(TOPDIR)/Rules.make\r
+
+O_TARGET :=  message.o hcd.o  hcd-pci.o hub.o usb.o config.o urb.o buffer_simple.o urb.o usb-debug.o
+
+#O_TARGET :=  urb.o
+
+include $(TOPDIR)/Rules.make
index 749c76b..3885771 100644 (file)
-/*\r
- * message.c - synchronous message handling\r
- */\r
-#if 0\r
-#include <linux/pci.h> /* for scatterlist macros */\r
-#include <linux/usb.h>\r
-#include <linux/module.h>\r
-#include <linux/slab.h>\r
-#include <linux/init.h>\r
-#include <linux/mm.h>\r
-#include <asm/byteorder.h>\r
-#else\r
-#include "../usb_wrapper.h"\r
-#endif\r
-\r
-#include "hcd.h"       /* for usbcore internals */\r
-\r
-// ReactOS specific: No WAITQUEUEs here\r
-#define wake_up(a) do {} while(0)\r
-\r
-struct usb_api_data {\r
-       wait_queue_head_t wqh;\r
-       int done;\r
-};\r
-\r
-static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct usb_api_data *awd = (struct usb_api_data *)urb->context;\r
-\r
-       awd->done = 1;\r
-       wmb();\r
-       wake_up(&awd->wqh);\r
-}\r
-\r
-// Starts urb and waits for completion or timeout\r
-static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)\r
-{ \r
-       //DECLARE_WAITQUEUE(wait, current); // Fireball, 24Jan05 - silent gcc complaining about unused wait variable\r
-       struct usb_api_data awd;\r
-       int status;\r
-\r
-       init_waitqueue_head(&awd.wqh);  \r
-       awd.done = 0;\r
-\r
-       set_current_state(TASK_UNINTERRUPTIBLE);\r
-       add_wait_queue(&awd.wqh, &wait);\r
-\r
-       urb->context = &awd;\r
-       status = usb_submit_urb(urb, GFP_ATOMIC);\r
-       if (status) {\r
-               // something went wrong\r
-               usb_free_urb(urb);\r
-               set_current_state(TASK_RUNNING);\r
-               remove_wait_queue(&awd.wqh, &wait);\r
-               return status;\r
-       }\r
-       \r
-       while (timeout && !awd.done)\r
-       {               \r
-               timeout = schedule_timeout(timeout);\r
-               set_current_state(TASK_UNINTERRUPTIBLE);\r
-               rmb();\r
-       }\r
-\r
-       set_current_state(TASK_RUNNING);\r
-       remove_wait_queue(&awd.wqh, &wait);\r
-\r
-       if (!timeout && !awd.done) {\r
-               if (urb->status != -EINPROGRESS) {      /* No callback?!! */\r
-                       printk(KERN_ERR "usb: raced timeout, "\r
-                           "pipe 0x%x status %d time left %d\n",\r
-                           urb->pipe, urb->status, timeout);\r
-                       status = urb->status;\r
-               } else {\r
-                       warn("usb_control/bulk_msg: timeout");\r
-                       usb_unlink_urb(urb);  // remove urb safely\r
-                       status = -ETIMEDOUT;\r
-               }\r
-       } else\r
-               status = urb->status;\r
-\r
-       if (actual_length)\r
-               *actual_length = urb->actual_length;\r
-\r
-       usb_free_urb(urb);\r
-       return status;\r
-}\r
-\r
-/*-------------------------------------------------------------------*/\r
-// returns status (negative) or length (positive)\r
-int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, \r
-                           struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)\r
-{\r
-       struct urb *urb;\r
-       int retv;\r
-       int length;\r
-\r
-       urb = usb_alloc_urb(0, GFP_NOIO);\r
-       if (!urb)\r
-               return -ENOMEM;\r
-  \r
-       usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,\r
-                  usb_api_blocking_completion, 0);\r
-\r
-       retv = usb_start_wait_urb(urb, timeout, &length);\r
-\r
-       if (retv < 0)\r
-               return retv;\r
-       else\r
-               return length;\r
-}\r
-\r
-/**\r
- *     usb_control_msg - Builds a control urb, sends it off and waits for completion\r
- *     @dev: pointer to the usb device to send the message to\r
- *     @pipe: endpoint "pipe" to send the message to\r
- *     @request: USB message request value\r
- *     @requesttype: USB message request type value\r
- *     @value: USB message value\r
- *     @index: USB message index value\r
- *     @data: pointer to the data to send\r
- *     @size: length in bytes of the data to send\r
- *     @timeout: time in jiffies to wait for the message to complete before\r
- *             timing out (if 0 the wait is forever)\r
- *     Context: !in_interrupt ()\r
- *\r
- *     This function sends a simple control message to a specified endpoint\r
- *     and waits for the message to complete, or timeout.\r
- *     \r
- *     If successful, it returns the number of bytes transferred, otherwise a negative error number.\r
- *\r
- *     Don't use this function from within an interrupt context, like a\r
- *     bottom half handler.  If you need an asynchronous message, or need to send\r
- *     a message from within interrupt context, use usb_submit_urb()\r
- *      If a thread in your driver uses this call, make sure your disconnect()\r
- *      method can wait for it to complete.  Since you don't have a handle on\r
- *      the URB used, you can't cancel the request.\r
- */\r
-int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,\r
-                        __u16 value, __u16 index, void *data, __u16 size, int timeout)\r
-{\r
-       struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);\r
-       int ret;\r
-       \r
-       if (!dr)\r
-               return -ENOMEM;\r
-\r
-       dr->bRequestType= requesttype;\r
-       dr->bRequest = request;\r
-       dr->wValue = cpu_to_le16p(&value);\r
-       dr->wIndex = cpu_to_le16p(&index);\r
-       dr->wLength = cpu_to_le16p(&size);\r
-\r
-       //dbg("usb_control_msg");       \r
-\r
-       ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);\r
-\r
-       kfree(dr);\r
-\r
-       return ret;\r
-}\r
-\r
-\r
-/**\r
- *     usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion\r
- *     @usb_dev: pointer to the usb device to send the message to\r
- *     @pipe: endpoint "pipe" to send the message to\r
- *     @data: pointer to the data to send\r
- *     @len: length in bytes of the data to send\r
- *     @actual_length: pointer to a location to put the actual length transferred in bytes\r
- *     @timeout: time in jiffies to wait for the message to complete before\r
- *             timing out (if 0 the wait is forever)\r
- *     Context: !in_interrupt ()\r
- *\r
- *     This function sends a simple bulk message to a specified endpoint\r
- *     and waits for the message to complete, or timeout.\r
- *     \r
- *     If successful, it returns 0, otherwise a negative error number.\r
- *     The number of actual bytes transferred will be stored in the \r
- *     actual_length paramater.\r
- *\r
- *     Don't use this function from within an interrupt context, like a\r
- *     bottom half handler.  If you need an asynchronous message, or need to\r
- *     send a message from within interrupt context, use usb_submit_urb()\r
- *      If a thread in your driver uses this call, make sure your disconnect()\r
- *      method can wait for it to complete.  Since you don't have a handle on\r
- *      the URB used, you can't cancel the request.\r
- */\r
-int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, \r
-                       void *data, int len, int *actual_length, int timeout)\r
-{\r
-       struct urb *urb;\r
-\r
-       if (len < 0)\r
-               return -EINVAL;\r
-\r
-       urb=usb_alloc_urb(0, GFP_KERNEL);\r
-       if (!urb)\r
-               return -ENOMEM;\r
-\r
-       usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,\r
-                   usb_api_blocking_completion, 0);\r
-\r
-       return usb_start_wait_urb(urb,timeout,actual_length);\r
-}\r
-\r
-/*-------------------------------------------------------------------*/\r
-//#warning "Scatter-gather stuff disabled"\r
-#if 0\r
-static void sg_clean (struct usb_sg_request *io)\r
-{\r
-       if (io->urbs) {\r
-               while (io->entries--)\r
-                       usb_free_urb (io->urbs [io->entries]);\r
-               kfree (io->urbs);\r
-               io->urbs = 0;\r
-       }\r
-       if (io->dev->dev.dma_mask != 0)\r
-               usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);\r
-       io->dev = 0;\r
-}\r
-\r
-static void sg_complete (struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct usb_sg_request   *io = (struct usb_sg_request *) urb->context;\r
-       unsigned long           flags;\r
-\r
-       spin_lock_irqsave (&io->lock, flags);\r
-\r
-       /* In 2.5 we require hcds' endpoint queues not to progress after fault\r
-        * reports, until the completion callback (this!) returns.  That lets\r
-        * device driver code (like this routine) unlink queued urbs first,\r
-        * if it needs to, since the HC won't work on them at all.  So it's\r
-        * not possible for page N+1 to overwrite page N, and so on.\r
-        *\r
-        * That's only for "hard" faults; "soft" faults (unlinks) sometimes\r
-        * complete before the HCD can get requests away from hardware,\r
-        * though never during cleanup after a hard fault.\r
-        */\r
-       if (io->status\r
-                       && (io->status != -ECONNRESET\r
-                               || urb->status != -ECONNRESET)\r
-                       && urb->actual_length) {\r
-               dev_err (io->dev->bus->controller,\r
-                       "dev %s ep%d%s scatterlist error %d/%d\n",\r
-                       io->dev->devpath,\r
-                       usb_pipeendpoint (urb->pipe),\r
-                       usb_pipein (urb->pipe) ? "in" : "out",\r
-                       urb->status, io->status);\r
-               // BUG ();\r
-       }\r
-\r
-       if (urb->status && urb->status != -ECONNRESET) {\r
-               int             i, found, status;\r
-\r
-               io->status = urb->status;\r
-\r
-               /* the previous urbs, and this one, completed already.\r
-                * unlink the later ones so they won't rx/tx bad data,\r
-                *\r
-                * FIXME don't bother unlinking urbs that haven't yet been\r
-                * submitted; those non-error cases shouldn't be syslogged\r
-                */\r
-               for (i = 0, found = 0; i < io->entries; i++) {\r
-                       if (found) {\r
-                               status = usb_unlink_urb (io->urbs [i]);\r
-                               if (status && status != -EINPROGRESS)\r
-                                       err ("sg_complete, unlink --> %d",\r
-                                                       status);\r
-                       } else if (urb == io->urbs [i])\r
-                               found = 1;\r
-               }\r
-       }\r
-\r
-       /* on the last completion, signal usb_sg_wait() */\r
-       io->bytes += urb->actual_length;\r
-       io->count--;\r
-       if (!io->count)\r
-               complete (&io->complete);\r
-\r
-       spin_unlock_irqrestore (&io->lock, flags);\r
-}\r
-\r
-\r
-/**\r
- * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request\r
- * @io: request block being initialized.  until usb_sg_wait() returns,\r
- *     treat this as a pointer to an opaque block of memory,\r
- * @dev: the usb device that will send or receive the data\r
- * @pipe: endpoint "pipe" used to transfer the data\r
- * @period: polling rate for interrupt endpoints, in frames or\r
- *     (for high speed endpoints) microframes; ignored for bulk\r
- * @sg: scatterlist entries\r
- * @nents: how many entries in the scatterlist\r
- * @length: how many bytes to send from the scatterlist, or zero to\r
- *     send every byte identified in the list.\r
- * @mem_flags: SLAB_* flags affecting memory allocations in this call\r
- *\r
- * Returns zero for success, else a negative errno value.  This initializes a\r
- * scatter/gather request, allocating resources such as I/O mappings and urb\r
- * memory (except maybe memory used by USB controller drivers).\r
- *\r
- * The request must be issued using usb_sg_wait(), which waits for the I/O to\r
- * complete (or to be canceled) and then cleans up all resources allocated by\r
- * usb_sg_init().\r
- *\r
- * The request may be canceled with usb_sg_cancel(), either before or after\r
- * usb_sg_wait() is called.\r
- */\r
-int usb_sg_init (\r
-       struct usb_sg_request   *io,\r
-       struct usb_device       *dev,\r
-       unsigned                pipe, \r
-       unsigned                period,\r
-       struct scatterlist      *sg,\r
-       int                     nents,\r
-       size_t                  length,\r
-       int                     mem_flags\r
-)\r
-{\r
-       int                     i;\r
-       int                     urb_flags;\r
-       int                     dma;\r
-\r
-       if (!io || !dev || !sg\r
-                       || usb_pipecontrol (pipe)\r
-                       || usb_pipeisoc (pipe)\r
-                       || nents <= 0)\r
-               return -EINVAL;\r
-\r
-       spin_lock_init (&io->lock);\r
-       io->dev = dev;\r
-       io->pipe = pipe;\r
-       io->sg = sg;\r
-       io->nents = nents;\r
-\r
-       /* not all host controllers use DMA (like the mainstream pci ones);\r
-        * they can use PIO (sl811) or be software over another transport.\r
-        */\r
-       dma = (dev->dev.dma_mask != 0);\r
-       if (dma)\r
-               io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);\r
-       else\r
-               io->entries = nents;\r
-\r
-       /* initialize all the urbs we'll use */\r
-       if (io->entries <= 0)\r
-               return io->entries;\r
-\r
-       io->count = 0;\r
-       io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);\r
-       if (!io->urbs)\r
-               goto nomem;\r
-\r
-       urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT;\r
-       if (usb_pipein (pipe))\r
-               urb_flags |= URB_SHORT_NOT_OK;\r
-\r
-       for (i = 0; i < io->entries; i++, io->count = i) {\r
-               unsigned                len;\r
-\r
-               io->urbs [i] = usb_alloc_urb (0, mem_flags);\r
-               if (!io->urbs [i]) {\r
-                       io->entries = i;\r
-                       goto nomem;\r
-               }\r
-\r
-               io->urbs [i]->dev = dev;\r
-               io->urbs [i]->pipe = pipe;\r
-               io->urbs [i]->interval = period;\r
-               io->urbs [i]->transfer_flags = urb_flags;\r
-\r
-               io->urbs [i]->complete = sg_complete;\r
-               io->urbs [i]->context = io;\r
-               io->urbs [i]->status = -EINPROGRESS;\r
-               io->urbs [i]->actual_length = 0;\r
-\r
-               if (dma) {\r
-                       /* hc may use _only_ transfer_dma */\r
-                       io->urbs [i]->transfer_dma = sg_dma_address (sg + i);\r
-                       len = sg_dma_len (sg + i);\r
-               } else {\r
-                       /* hc may use _only_ transfer_buffer */\r
-                       io->urbs [i]->transfer_buffer =\r
-                               page_address (sg [i].page) + sg [i].offset;\r
-                       len = sg [i].length;\r
-               }\r
-\r
-               if (length) {\r
-                       len = min_t (unsigned, len, length);\r
-                       length -= len;\r
-                       if (length == 0)\r
-                               io->entries = i + 1;\r
-               }\r
-               io->urbs [i]->transfer_buffer_length = len;\r
-       }\r
-       io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;\r
-\r
-       /* transaction state */\r
-       io->status = 0;\r
-       io->bytes = 0;\r
-       init_completion (&io->complete);\r
-       return 0;\r
-\r
-nomem:\r
-       sg_clean (io);\r
-       return -ENOMEM;\r
-}\r
-\r
-\r
-/**\r
- * usb_sg_wait - synchronously execute scatter/gather request\r
- * @io: request block handle, as initialized with usb_sg_init().\r
- *     some fields become accessible when this call returns.\r
- * Context: !in_interrupt ()\r
- *\r
- * This function blocks until the specified I/O operation completes.  It\r
- * leverages the grouping of the related I/O requests to get good transfer\r
- * rates, by queueing the requests.  At higher speeds, such queuing can\r
- * significantly improve USB throughput.\r
- *\r
- * There are three kinds of completion for this function.\r
- * (1) success, where io->status is zero.  The number of io->bytes\r
- *     transferred is as requested.\r
- * (2) error, where io->status is a negative errno value.  The number\r
- *     of io->bytes transferred before the error is usually less\r
- *     than requested, and can be nonzero.\r
- * (3) cancelation, a type of error with status -ECONNRESET that\r
- *     is initiated by usb_sg_cancel().\r
- *\r
- * When this function returns, all memory allocated through usb_sg_init() or\r
- * this call will have been freed.  The request block parameter may still be\r
- * passed to usb_sg_cancel(), or it may be freed.  It could also be\r
- * reinitialized and then reused.\r
- *\r
- * Data Transfer Rates:\r
- *\r
- * Bulk transfers are valid for full or high speed endpoints.\r
- * The best full speed data rate is 19 packets of 64 bytes each\r
- * per frame, or 1216 bytes per millisecond.\r
- * The best high speed data rate is 13 packets of 512 bytes each\r
- * per microframe, or 52 KBytes per millisecond.\r
- *\r
- * The reason to use interrupt transfers through this API would most likely\r
- * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond\r
- * could be transferred.  That capability is less useful for low or full\r
- * speed interrupt endpoints, which allow at most one packet per millisecond,\r
- * of at most 8 or 64 bytes (respectively).\r
- */\r
-void usb_sg_wait (struct usb_sg_request *io)\r
-{\r
-       int             i;\r
-       unsigned long   flags;\r
-\r
-       /* queue the urbs.  */\r
-       spin_lock_irqsave (&io->lock, flags);\r
-       for (i = 0; i < io->entries && !io->status; i++) {\r
-               int     retval;\r
-\r
-               retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC);\r
-\r
-               /* after we submit, let completions or cancelations fire;\r
-                * we handshake using io->status.\r
-                */\r
-               spin_unlock_irqrestore (&io->lock, flags);\r
-               switch (retval) {\r
-                       /* maybe we retrying will recover */\r
-               case -ENXIO:    // hc didn't queue this one\r
-               case -EAGAIN:\r
-               case -ENOMEM:\r
-                       retval = 0;\r
-                       i--;\r
-                       // FIXME:  should it usb_sg_cancel() on INTERRUPT?\r
-                       yield ();\r
-                       break;\r
-\r
-                       /* no error? continue immediately.\r
-                        *\r
-                        * NOTE: to work better with UHCI (4K I/O buffer may\r
-                        * need 3K of TDs) it may be good to limit how many\r
-                        * URBs are queued at once; N milliseconds?\r
-                        */\r
-               case 0:\r
-                       cpu_relax ();\r
-                       break;\r
-\r
-                       /* fail any uncompleted urbs */\r
-               default:\r
-                       io->urbs [i]->status = retval;\r
-                       dbg ("usb_sg_msg, submit --> %d", retval);\r
-                       usb_sg_cancel (io);\r
-               }\r
-               spin_lock_irqsave (&io->lock, flags);\r
-               if (retval && io->status == -ECONNRESET)\r
-                       io->status = retval;\r
-       }\r
-       spin_unlock_irqrestore (&io->lock, flags);\r
-\r
-       /* OK, yes, this could be packaged as non-blocking.\r
-        * So could the submit loop above ... but it's easier to\r
-        * solve neither problem than to solve both!\r
-        */\r
-       wait_for_completion (&io->complete);\r
-\r
-       sg_clean (io);\r
-}\r
-\r
-/**\r
- * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()\r
- * @io: request block, initialized with usb_sg_init()\r
- *\r
- * This stops a request after it has been started by usb_sg_wait().\r
- * It can also prevents one initialized by usb_sg_init() from starting,\r
- * so that call just frees resources allocated to the request.\r
- */\r
-void usb_sg_cancel (struct usb_sg_request *io)\r
-{\r
-       unsigned long   flags;\r
-\r
-       spin_lock_irqsave (&io->lock, flags);\r
-\r
-       /* shut everything down, if it didn't already */\r
-       if (!io->status) {\r
-               int     i;\r
-\r
-               io->status = -ECONNRESET;\r
-               for (i = 0; i < io->entries; i++) {\r
-                       int     retval;\r
-\r
-                       if (!io->urbs [i]->dev)\r
-                               continue;\r
-                       retval = usb_unlink_urb (io->urbs [i]);\r
-                       if (retval && retval != -EINPROGRESS)\r
-                               warn ("usb_sg_cancel, unlink --> %d", retval);\r
-                       // FIXME don't warn on "not yet submitted" error\r
-               }\r
-       }\r
-       spin_unlock_irqrestore (&io->lock, flags);\r
-}\r
-#endif\r
-/*-------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_get_descriptor - issues a generic GET_DESCRIPTOR request\r
- * @dev: the device whose descriptor is being retrieved\r
- * @type: the descriptor type (USB_DT_*)\r
- * @index: the number of the descriptor\r
- * @buf: where to put the descriptor\r
- * @size: how big is "buf"?\r
- * Context: !in_interrupt ()\r
- *\r
- * Gets a USB descriptor.  Convenience functions exist to simplify\r
- * getting some types of descriptors.  Use\r
- * usb_get_device_descriptor() for USB_DT_DEVICE,\r
- * and usb_get_string() or usb_string() for USB_DT_STRING.\r
- * Configuration descriptors (USB_DT_CONFIG) are part of the device\r
- * structure, at least for the current configuration.\r
- * In addition to a number of USB-standard descriptors, some\r
- * devices also use class-specific or vendor-specific descriptors.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns the number of bytes received on success, or else the status code\r
- * returned by the underlying usb_control_msg() call.\r
- */\r
-int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)\r
-{\r
-       int i = 5;\r
-       int result;\r
-       \r
-       memset(buf,0,size);     // Make sure we parse really received data\r
-\r
-       while (i--) {\r
-               /* retries if the returned length was 0; flakey device */\r
-               if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),\r
-                                   USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,\r
-                                   (type << 8) + index, 0, buf, size,\r
-                                   HZ * USB_CTRL_GET_TIMEOUT)) > 0\r
-                               || result == -EPIPE)\r
-                       break;\r
-       }\r
-       return result;\r
-}\r
-\r
-/**\r
- * usb_get_string - gets a string descriptor\r
- * @dev: the device whose string descriptor is being retrieved\r
- * @langid: code for language chosen (from string descriptor zero)\r
- * @index: the number of the descriptor\r
- * @buf: where to put the string\r
- * @size: how big is "buf"?\r
- * Context: !in_interrupt ()\r
- *\r
- * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,\r
- * in little-endian byte order).\r
- * The usb_string() function will often be a convenient way to turn\r
- * these strings into kernel-printable form.\r
- *\r
- * Strings may be referenced in device, configuration, interface, or other\r
- * descriptors, and could also be used in vendor-specific ways.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns the number of bytes received on success, or else the status code\r
- * returned by the underlying usb_control_msg() call.\r
- */\r
-int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)\r
-{\r
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),\r
-               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,\r
-               (USB_DT_STRING << 8) + index, langid, buf, size,\r
-               HZ * USB_CTRL_GET_TIMEOUT);\r
-}\r
-\r
-/**\r
- * usb_get_device_descriptor - (re)reads the device descriptor\r
- * @dev: the device whose device descriptor is being updated\r
- * Context: !in_interrupt ()\r
- *\r
- * Updates the copy of the device descriptor stored in the device structure,\r
- * which dedicates space for this purpose.  Note that several fields are\r
- * converted to the host CPU's byte order:  the USB version (bcdUSB), and\r
- * vendors product and version fields (idVendor, idProduct, and bcdDevice).\r
- * That lets device drivers compare against non-byteswapped constants.\r
- *\r
- * There's normally no need to use this call, although some devices\r
- * will change their descriptors after events like updating firmware.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns the number of bytes received on success, or else the status code\r
- * returned by the underlying usb_control_msg() call.\r
- */\r
-int usb_get_device_descriptor(struct usb_device *dev)\r
-{\r
-       int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,\r
-                                    sizeof(dev->descriptor));\r
-       if (ret >= 0) {\r
-               le16_to_cpus(&dev->descriptor.bcdUSB);\r
-               le16_to_cpus(&dev->descriptor.idVendor);\r
-               le16_to_cpus(&dev->descriptor.idProduct);\r
-               le16_to_cpus(&dev->descriptor.bcdDevice);\r
-       }\r
-       return ret;\r
-}\r
-\r
-/**\r
- * usb_get_status - issues a GET_STATUS call\r
- * @dev: the device whose status is being checked\r
- * @type: USB_RECIP_*; for device, interface, or endpoint\r
- * @target: zero (for device), else interface or endpoint number\r
- * @data: pointer to two bytes of bitmap data\r
- * Context: !in_interrupt ()\r
- *\r
- * Returns device, interface, or endpoint status.  Normally only of\r
- * interest to see if the device is self powered, or has enabled the\r
- * remote wakeup facility; or whether a bulk or interrupt endpoint\r
- * is halted ("stalled").\r
- *\r
- * Bits in these status bitmaps are set using the SET_FEATURE request,\r
- * and cleared using the CLEAR_FEATURE request.  The usb_clear_halt()\r
- * function should be used to clear halt ("stall") status.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns the number of bytes received on success, or else the status code\r
- * returned by the underlying usb_control_msg() call.\r
- */\r
-int usb_get_status(struct usb_device *dev, int type, int target, void *data)\r
-{\r
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),\r
-               USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2,\r
-               HZ * USB_CTRL_GET_TIMEOUT);\r
-}\r
-\r
-\r
-// hub-only!! ... and only exported for reset/reinit path.\r
-// otherwise used internally, when setting up a config\r
-void usb_set_maxpacket(struct usb_device *dev)\r
-{\r
-       int i, b;\r
-\r
-       /* NOTE:  affects all endpoints _except_ ep0 */\r
-       for (i=0; i<dev->actconfig->desc.bNumInterfaces; i++) {\r
-               struct usb_interface *ifp = dev->actconfig->interface + i;\r
-               struct usb_host_interface *as = ifp->altsetting + ifp->act_altsetting;\r
-               struct usb_host_endpoint *ep = as->endpoint;\r
-               int e;\r
-\r
-               for (e=0; e<as->desc.bNumEndpoints; e++) {\r
-                       struct usb_endpoint_descriptor  *d;\r
-                       d = &ep [e].desc;\r
-                       b = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;\r
-                       if ((d->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==\r
-                               USB_ENDPOINT_XFER_CONTROL) {    /* Control => bidirectional */\r
-                               dev->epmaxpacketout[b] = d->wMaxPacketSize;\r
-                               dev->epmaxpacketin [b] = d->wMaxPacketSize;\r
-                               }\r
-                       else if (usb_endpoint_out(d->bEndpointAddress)) {\r
-                               if (d->wMaxPacketSize > dev->epmaxpacketout[b])\r
-                                       dev->epmaxpacketout[b] = d->wMaxPacketSize;\r
-                       }\r
-                       else {\r
-                               if (d->wMaxPacketSize > dev->epmaxpacketin [b])\r
-                                       dev->epmaxpacketin [b] = d->wMaxPacketSize;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-/**\r
- * usb_clear_halt - tells device to clear endpoint halt/stall condition\r
- * @dev: device whose endpoint is halted\r
- * @pipe: endpoint "pipe" being cleared\r
- * Context: !in_interrupt ()\r
- *\r
- * This is used to clear halt conditions for bulk and interrupt endpoints,\r
- * as reported by URB completion status.  Endpoints that are halted are\r
- * sometimes referred to as being "stalled".  Such endpoints are unable\r
- * to transmit or receive data until the halt status is cleared.  Any URBs\r
- * queued for such an endpoint should normally be unlinked by the driver\r
- * before clearing the halt condition, as described in sections 5.7.5\r
- * and 5.8.5 of the USB 2.0 spec.\r
- *\r
- * Note that control and isochronous endpoints don't halt, although control\r
- * endpoints report "protocol stall" (for unsupported requests) using the\r
- * same status code used to report a true stall.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns zero on success, or else the status code returned by the\r
- * underlying usb_control_msg() call.\r
- */\r
-int usb_clear_halt(struct usb_device *dev, int pipe)\r
-{\r
-       int result;\r
-       int endp = usb_pipeendpoint(pipe);\r
-       \r
-       if (usb_pipein (pipe))\r
-               endp |= USB_DIR_IN;\r
-\r
-       /* we don't care if it wasn't halted first. in fact some devices\r
-        * (like some ibmcam model 1 units) seem to expect hosts to make\r
-        * this request for iso endpoints, which can't halt!\r
-        */\r
-       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),\r
-               USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0,\r
-               HZ * USB_CTRL_SET_TIMEOUT);\r
-\r
-       /* don't un-halt or force to DATA0 except on success */\r
-       if (result < 0)\r
-               return result;\r
-\r
-       /* NOTE:  seems like Microsoft and Apple don't bother verifying\r
-        * the clear "took", so some devices could lock up if you check...\r
-        * such as the Hagiwara FlashGate DUAL.  So we won't bother.\r
-        *\r
-        * NOTE:  make sure the logic here doesn't diverge much from\r
-        * the copy in usb-storage, for as long as we need two copies.\r
-        */\r
-\r
-       /* toggle was reset by the clear, then ep was reactivated */\r
-       usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);\r
-       usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * usb_set_interface - Makes a particular alternate setting be current\r
- * @dev: the device whose interface is being updated\r
- * @interface: the interface being updated\r
- * @alternate: the setting being chosen.\r
- * Context: !in_interrupt ()\r
- *\r
- * This is used to enable data transfers on interfaces that may not\r
- * be enabled by default.  Not all devices support such configurability.\r
- * Only the driver bound to an interface may change its setting.\r
- *\r
- * Within any given configuration, each interface may have several\r
- * alternative settings.  These are often used to control levels of\r
- * bandwidth consumption.  For example, the default setting for a high\r
- * speed interrupt endpoint may not send more than 64 bytes per microframe,\r
- * while interrupt transfers of up to 3KBytes per microframe are legal.\r
- * Also, isochronous endpoints may never be part of an\r
- * interface's default setting.  To access such bandwidth, alternate\r
- * interface settings must be made current.\r
- *\r
- * Note that in the Linux USB subsystem, bandwidth associated with\r
- * an endpoint in a given alternate setting is not reserved until an URB\r
- * is submitted that needs that bandwidth.  Some other operating systems\r
- * allocate bandwidth early, when a configuration is chosen.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- * Also, drivers must not change altsettings while urbs are scheduled for\r
- * endpoints in that interface; all such urbs must first be completed\r
- * (perhaps forced by unlinking).\r
- *\r
- * Returns zero on success, or else the status code returned by the\r
- * underlying usb_control_msg() call.\r
- */\r
-int usb_set_interface(struct usb_device *dev, int interface, int alternate)\r
-{\r
-       struct usb_interface *iface;\r
-       struct usb_host_interface *iface_as;\r
-       int i, ret;\r
-       void (*disable)(struct usb_device *, int) = dev->bus->op->disable;\r
-\r
-       iface = usb_ifnum_to_if(dev, interface);\r
-       if (!iface) {\r
-               warn("selecting invalid interface %d", interface);\r
-               return -EINVAL;\r
-       }\r
-\r
-       /* 9.4.10 says devices don't need this, if the interface\r
-          only has one alternate setting */\r
-       if (iface->num_altsetting == 1) {\r
-               dbg("ignoring set_interface for dev %d, iface %d, alt %d",\r
-                       dev->devnum, interface, alternate);\r
-               return 0;\r
-       }\r
-\r
-       if (alternate < 0 || alternate >= iface->num_altsetting)\r
-               return -EINVAL;\r
-\r
-       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),\r
-                                  USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,\r
-                                  iface->altsetting[alternate]\r
-                                       .desc.bAlternateSetting,\r
-                                  interface, NULL, 0, HZ * 5)) < 0)\r
-               return ret;\r
-\r
-       /* FIXME drivers shouldn't need to replicate/bugfix the logic here\r
-        * when they implement async or easily-killable versions of this or\r
-        * other "should-be-internal" functions (like clear_halt).\r
-        * should hcd+usbcore postprocess control requests?\r
-        */\r
-\r
-       /* prevent submissions using previous endpoint settings */\r
-       iface_as = iface->altsetting + iface->act_altsetting;\r
-       for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {\r
-               u8      ep = iface_as->endpoint [i].desc.bEndpointAddress;\r
-               int     out = !(ep & USB_DIR_IN);\r
-\r
-               /* clear out hcd state, then usbcore state */\r
-               if (disable)\r
-                       disable (dev, ep);\r
-               ep &= USB_ENDPOINT_NUMBER_MASK;\r
-               (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0;\r
-       }\r
-       iface->act_altsetting = alternate;\r
-\r
-       /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as\r
-        *\r
-        * Note:\r
-        * Despite EP0 is always present in all interfaces/AS, the list of\r
-        * endpoints from the descriptor does not contain EP0. Due to its\r
-        * omnipresence one might expect EP0 being considered "affected" by\r
-        * any SetInterface request and hence assume toggles need to be reset.\r
-        * However, EP0 toggles are re-synced for every individual transfer\r
-        * during the SETUP stage - hence EP0 toggles are "don't care" here.\r
-        * (Likewise, EP0 never "halts" on well designed devices.)\r
-        */\r
-\r
-       iface_as = &iface->altsetting[alternate];\r
-       for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {\r
-               u8      ep = iface_as->endpoint[i].desc.bEndpointAddress;\r
-               int     out = !(ep & USB_DIR_IN);\r
-\r
-               ep &= USB_ENDPOINT_NUMBER_MASK;\r
-               usb_settoggle (dev, ep, out, 0);\r
-               (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep]\r
-                       = iface_as->endpoint [i].desc.wMaxPacketSize;\r
-               usb_endpoint_running (dev, ep, out);\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * usb_set_configuration - Makes a particular device setting be current\r
- * @dev: the device whose configuration is being updated\r
- * @configuration: the configuration being chosen.\r
- * Context: !in_interrupt ()\r
- *\r
- * This is used to enable non-default device modes.  Not all devices\r
- * support this kind of configurability.  By default, configuration\r
- * zero is selected after enumeration; many devices only have a single\r
- * configuration.\r
- *\r
- * USB devices may support one or more configurations, which affect\r
- * power consumption and the functionality available.  For example,\r
- * the default configuration is limited to using 100mA of bus power,\r
- * so that when certain device functionality requires more power,\r
- * and the device is bus powered, that functionality will be in some\r
- * non-default device configuration.  Other device modes may also be\r
- * reflected as configuration options, such as whether two ISDN\r
- * channels are presented as independent 64Kb/s interfaces or as one\r
- * bonded 128Kb/s interface.\r
- *\r
- * Note that USB has an additional level of device configurability,\r
- * associated with interfaces.  That configurability is accessed using\r
- * usb_set_interface().\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns zero on success, or else the status code returned by the\r
- * underlying usb_control_msg() call.\r
- */\r
-int usb_set_configuration(struct usb_device *dev, int configuration)\r
-{\r
-       int i, ret;\r
-       struct usb_host_config *cp = NULL;\r
-       void (*disable)(struct usb_device *, int) = dev->bus->op->disable;\r
-       \r
-       for (i=0; i<dev->descriptor.bNumConfigurations; i++) {\r
-               if (dev->config[i].desc.bConfigurationValue == configuration) {\r
-                       cp = &dev->config[i];\r
-                       break;\r
-               }\r
-       }\r
-       if ((!cp && configuration != 0) || (cp && configuration == 0)) {\r
-               warn("selecting invalid configuration %d", configuration);\r
-               return -EINVAL;\r
-       }\r
-\r
-       /* if it's already configured, clear out old state first. */\r
-       if (dev->state != USB_STATE_ADDRESS && disable) {\r
-               for (i = 1 /* skip ep0 */; i < 15; i++) {\r
-                       disable (dev, i);\r
-                       disable (dev, USB_DIR_IN | i);\r
-               }\r
-       }\r
-       dev->toggle[0] = dev->toggle[1] = 0;\r
-       dev->halted[0] = dev->halted[1] = 0;\r
-       dev->state = USB_STATE_ADDRESS;\r
-\r
-       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),\r
-                       USB_REQ_SET_CONFIGURATION, 0, configuration, 0,\r
-                       NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)\r
-               return ret;\r
-       if (configuration)\r
-               dev->state = USB_STATE_CONFIGURED;\r
-       dev->actconfig = cp;\r
-\r
-       /* reset more hc/hcd endpoint state */\r
-       usb_set_maxpacket(dev);\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-/**\r
- * usb_string - returns ISO 8859-1 version of a string descriptor\r
- * @dev: the device whose string descriptor is being retrieved\r
- * @index: the number of the descriptor\r
- * @buf: where to put the string\r
- * @size: how big is "buf"?\r
- * Context: !in_interrupt ()\r
- * \r
- * This converts the UTF-16LE encoded strings returned by devices, from\r
- * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones\r
- * that are more usable in most kernel contexts.  Note that all characters\r
- * in the chosen descriptor that can't be encoded using ISO-8859-1\r
- * are converted to the question mark ("?") character, and this function\r
- * chooses strings in the first language supported by the device.\r
- *\r
- * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit\r
- * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,\r
- * and is appropriate for use many uses of English and several other\r
- * Western European languages.  (But it doesn't include the "Euro" symbol.)\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Returns length of the string (>= 0) or usb_control_msg status (< 0).\r
- */\r
-int usb_string(struct usb_device *dev, int index, char *buf, size_t size)\r
-{\r
-       unsigned char *tbuf;\r
-       int err, len;\r
-       unsigned int u, idx;\r
-\r
-       if (size <= 0 || !buf || !index)\r
-               return -EINVAL;\r
-       buf[0] = 0;\r
-       tbuf = kmalloc(256, GFP_KERNEL);\r
-       if (!tbuf)\r
-               return -ENOMEM;\r
-\r
-       /* get langid for strings if it's not yet known */\r
-       if (!dev->have_langid) {\r
-               err = usb_get_string(dev, 0, 0, tbuf, 4);\r
-               if (err < 0) {\r
-                       err("error getting string descriptor 0 (error=%d)", err);\r
-                       goto errout;\r
-               } else if (tbuf[0] < 4) {\r
-                       err("string descriptor 0 too short");\r
-                       err = -EINVAL;\r
-                       goto errout;\r
-               } else {\r
-                       dev->have_langid = -1;\r
-                       dev->string_langid = tbuf[2] | (tbuf[3]<< 8);\r
-                               /* always use the first langid listed */\r
-                       dbg("USB device number %d default language ID 0x%x",\r
-                               dev->devnum, dev->string_langid);\r
-               }\r
-       }\r
-\r
-       /*\r
-        * ask for the length of the string \r
-        */\r
-\r
-       err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);\r
-       if(err<2)\r
-               goto errout;\r
-       len=tbuf[0];    \r
-       \r
-       err = usb_get_string(dev, dev->string_langid, index, tbuf, len);\r
-       if (err < 0)\r
-               goto errout;\r
-\r
-       size--;         /* leave room for trailing NULL char in output buffer */\r
-       for (idx = 0, u = 2; u < err; u += 2) {\r
-               if (idx >= size)\r
-                       break;\r
-               if (tbuf[u+1])                  /* high byte */\r
-                       buf[idx++] = '?';  /* non ISO-8859-1 character */\r
-               else\r
-                       buf[idx++] = tbuf[u];\r
-       }\r
-       buf[idx] = 0;\r
-       err = idx;\r
-\r
- errout:\r
-       kfree(tbuf);\r
-       return err;\r
-}\r
-\r
-// synchronous request completion model\r
-EXPORT_SYMBOL(usb_control_msg);\r
-EXPORT_SYMBOL(usb_bulk_msg);\r
-\r
-EXPORT_SYMBOL(usb_sg_init);\r
-EXPORT_SYMBOL(usb_sg_cancel);\r
-EXPORT_SYMBOL(usb_sg_wait);\r
-\r
-// synchronous control message convenience routines\r
-EXPORT_SYMBOL(usb_get_descriptor);\r
-EXPORT_SYMBOL(usb_get_device_descriptor);\r
-EXPORT_SYMBOL(usb_get_status);\r
-EXPORT_SYMBOL(usb_get_string);\r
-EXPORT_SYMBOL(usb_string);\r
-EXPORT_SYMBOL(usb_clear_halt);\r
-EXPORT_SYMBOL(usb_set_configuration);\r
-EXPORT_SYMBOL(usb_set_interface);\r
-\r
+/*
+ * message.c - synchronous message handling
+ */
+#if 0
+#include <linux/pci.h> /* for scatterlist macros */
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/byteorder.h>
+#else
+#include "../usb_wrapper.h"
+#endif
+
+#include "hcd.h"       /* for usbcore internals */
+
+// ReactOS specific: No WAITQUEUEs here
+#define wake_up(a) do {} while(0)
+
+struct usb_api_data {
+       wait_queue_head_t wqh;
+       int done;
+};
+
+static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_api_data *awd = (struct usb_api_data *)urb->context;
+
+       awd->done = 1;
+       wmb();
+       wake_up(&awd->wqh);
+}
+
+// Starts urb and waits for completion or timeout
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
+{ 
+       //DECLARE_WAITQUEUE(wait, current); // Fireball, 24Jan05 - silent gcc complaining about unused wait variable
+       struct usb_api_data awd;
+       int status;
+
+       init_waitqueue_head(&awd.wqh);  
+       awd.done = 0;
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(&awd.wqh, &wait);
+
+       urb->context = &awd;
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status) {
+               // something went wrong
+               usb_free_urb(urb);
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&awd.wqh, &wait);
+               return status;
+       }
+       
+       while (timeout && !awd.done)
+       {               
+               timeout = schedule_timeout(timeout);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               rmb();
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&awd.wqh, &wait);
+
+       if (!timeout && !awd.done) {
+               if (urb->status != -EINPROGRESS) {      /* No callback?!! */
+                       printk(KERN_ERR "usb: raced timeout, "
+                           "pipe 0x%x status %d time left %d\n",
+                           urb->pipe, urb->status, timeout);
+                       status = urb->status;
+               } else {
+                       warn("usb_control/bulk_msg: timeout");
+                       usb_unlink_urb(urb);  // remove urb safely
+                       status = -ETIMEDOUT;
+               }
+       } else
+               status = urb->status;
+
+       if (actual_length)
+               *actual_length = urb->actual_length;
+
+       usb_free_urb(urb);
+       return status;
+}
+
+/*-------------------------------------------------------------------*/
+// returns status (negative) or length (positive)
+int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
+                           struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
+{
+       struct urb *urb;
+       int retv;
+       int length;
+
+       urb = usb_alloc_urb(0, GFP_NOIO);
+       if (!urb)
+               return -ENOMEM;
+  
+       usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
+                  usb_api_blocking_completion, 0);
+
+       retv = usb_start_wait_urb(urb, timeout, &length);
+
+       if (retv < 0)
+               return retv;
+       else
+               return length;
+}
+
+/**
+ *     usb_control_msg - Builds a control urb, sends it off and waits for completion
+ *     @dev: pointer to the usb device to send the message to
+ *     @pipe: endpoint "pipe" to send the message to
+ *     @request: USB message request value
+ *     @requesttype: USB message request type value
+ *     @value: USB message value
+ *     @index: USB message index value
+ *     @data: pointer to the data to send
+ *     @size: length in bytes of the data to send
+ *     @timeout: time in jiffies to wait for the message to complete before
+ *             timing out (if 0 the wait is forever)
+ *     Context: !in_interrupt ()
+ *
+ *     This function sends a simple control message to a specified endpoint
+ *     and waits for the message to complete, or timeout.
+ *     
+ *     If successful, it returns the number of bytes transferred, otherwise a negative error number.
+ *
+ *     Don't use this function from within an interrupt context, like a
+ *     bottom half handler.  If you need an asynchronous message, or need to send
+ *     a message from within interrupt context, use usb_submit_urb()
+ *      If a thread in your driver uses this call, make sure your disconnect()
+ *      method can wait for it to complete.  Since you don't have a handle on
+ *      the URB used, you can't cancel the request.
+ */
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
+                        __u16 value, __u16 index, void *data, __u16 size, int timeout)
+{
+       struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+       int ret;
+       
+       if (!dr)
+               return -ENOMEM;
+
+       dr->bRequestType= requesttype;
+       dr->bRequest = request;
+       dr->wValue = cpu_to_le16p(&value);
+       dr->wIndex = cpu_to_le16p(&index);
+       dr->wLength = cpu_to_le16p(&size);
+
+       //dbg("usb_control_msg");       
+
+       ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+
+       kfree(dr);
+
+       return ret;
+}
+
+
+/**
+ *     usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
+ *     @usb_dev: pointer to the usb device to send the message to
+ *     @pipe: endpoint "pipe" to send the message to
+ *     @data: pointer to the data to send
+ *     @len: length in bytes of the data to send
+ *     @actual_length: pointer to a location to put the actual length transferred in bytes
+ *     @timeout: time in jiffies to wait for the message to complete before
+ *             timing out (if 0 the wait is forever)
+ *     Context: !in_interrupt ()
+ *
+ *     This function sends a simple bulk message to a specified endpoint
+ *     and waits for the message to complete, or timeout.
+ *     
+ *     If successful, it returns 0, otherwise a negative error number.
+ *     The number of actual bytes transferred will be stored in the 
+ *     actual_length paramater.
+ *
+ *     Don't use this function from within an interrupt context, like a
+ *     bottom half handler.  If you need an asynchronous message, or need to
+ *     send a message from within interrupt context, use usb_submit_urb()
+ *      If a thread in your driver uses this call, make sure your disconnect()
+ *      method can wait for it to complete.  Since you don't have a handle on
+ *      the URB used, you can't cancel the request.
+ */
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
+                       void *data, int len, int *actual_length, int timeout)
+{
+       struct urb *urb;
+
+       if (len < 0)
+               return -EINVAL;
+
+       urb=usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return -ENOMEM;
+
+       usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
+                   usb_api_blocking_completion, 0);
+
+       return usb_start_wait_urb(urb,timeout,actual_length);
+}
+
+/*-------------------------------------------------------------------*/
+//#warning "Scatter-gather stuff disabled"
+#if 0
+static void sg_clean (struct usb_sg_request *io)
+{
+       if (io->urbs) {
+               while (io->entries--)
+                       usb_free_urb (io->urbs [io->entries]);
+               kfree (io->urbs);
+               io->urbs = 0;
+       }
+       if (io->dev->dev.dma_mask != 0)
+               usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+       io->dev = 0;
+}
+
+static void sg_complete (struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_sg_request   *io = (struct usb_sg_request *) urb->context;
+       unsigned long           flags;
+
+       spin_lock_irqsave (&io->lock, flags);
+
+       /* In 2.5 we require hcds' endpoint queues not to progress after fault
+        * reports, until the completion callback (this!) returns.  That lets
+        * device driver code (like this routine) unlink queued urbs first,
+        * if it needs to, since the HC won't work on them at all.  So it's
+        * not possible for page N+1 to overwrite page N, and so on.
+        *
+        * That's only for "hard" faults; "soft" faults (unlinks) sometimes
+        * complete before the HCD can get requests away from hardware,
+        * though never during cleanup after a hard fault.
+        */
+       if (io->status
+                       && (io->status != -ECONNRESET
+                               || urb->status != -ECONNRESET)
+                       && urb->actual_length) {
+               dev_err (io->dev->bus->controller,
+                       "dev %s ep%d%s scatterlist error %d/%d\n",
+                       io->dev->devpath,
+                       usb_pipeendpoint (urb->pipe),
+                       usb_pipein (urb->pipe) ? "in" : "out",
+                       urb->status, io->status);
+               // BUG ();
+       }
+
+       if (urb->status && urb->status != -ECONNRESET) {
+               int             i, found, status;
+
+               io->status = urb->status;
+
+               /* the previous urbs, and this one, completed already.
+                * unlink the later ones so they won't rx/tx bad data,
+                *
+                * FIXME don't bother unlinking urbs that haven't yet been
+                * submitted; those non-error cases shouldn't be syslogged
+                */
+               for (i = 0, found = 0; i < io->entries; i++) {
+                       if (found) {
+                               status = usb_unlink_urb (io->urbs [i]);
+                               if (status && status != -EINPROGRESS)
+                                       err ("sg_complete, unlink --> %d",
+                                                       status);
+                       } else if (urb == io->urbs [i])
+                               found = 1;
+               }
+       }
+
+       /* on the last completion, signal usb_sg_wait() */
+       io->bytes += urb->actual_length;
+       io->count--;
+       if (!io->count)
+               complete (&io->complete);
+
+       spin_unlock_irqrestore (&io->lock, flags);
+}
+
+
+/**
+ * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request
+ * @io: request block being initialized.  until usb_sg_wait() returns,
+ *     treat this as a pointer to an opaque block of memory,
+ * @dev: the usb device that will send or receive the data
+ * @pipe: endpoint "pipe" used to transfer the data
+ * @period: polling rate for interrupt endpoints, in frames or
+ *     (for high speed endpoints) microframes; ignored for bulk
+ * @sg: scatterlist entries
+ * @nents: how many entries in the scatterlist
+ * @length: how many bytes to send from the scatterlist, or zero to
+ *     send every byte identified in the list.
+ * @mem_flags: SLAB_* flags affecting memory allocations in this call
+ *
+ * Returns zero for success, else a negative errno value.  This initializes a
+ * scatter/gather request, allocating resources such as I/O mappings and urb
+ * memory (except maybe memory used by USB controller drivers).
+ *
+ * The request must be issued using usb_sg_wait(), which waits for the I/O to
+ * complete (or to be canceled) and then cleans up all resources allocated by
+ * usb_sg_init().
+ *
+ * The request may be canceled with usb_sg_cancel(), either before or after
+ * usb_sg_wait() is called.
+ */
+int usb_sg_init (
+       struct usb_sg_request   *io,
+       struct usb_device       *dev,
+       unsigned                pipe, 
+       unsigned                period,
+       struct scatterlist      *sg,
+       int                     nents,
+       size_t                  length,
+       int                     mem_flags
+)
+{
+       int                     i;
+       int                     urb_flags;
+       int                     dma;
+
+       if (!io || !dev || !sg
+                       || usb_pipecontrol (pipe)
+                       || usb_pipeisoc (pipe)
+                       || nents <= 0)
+               return -EINVAL;
+
+       spin_lock_init (&io->lock);
+       io->dev = dev;
+       io->pipe = pipe;
+       io->sg = sg;
+       io->nents = nents;
+
+       /* not all host controllers use DMA (like the mainstream pci ones);
+        * they can use PIO (sl811) or be software over another transport.
+        */
+       dma = (dev->dev.dma_mask != 0);
+       if (dma)
+               io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+       else
+               io->entries = nents;
+
+       /* initialize all the urbs we'll use */
+       if (io->entries <= 0)
+               return io->entries;
+
+       io->count = 0;
+       io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
+       if (!io->urbs)
+               goto nomem;
+
+       urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT;
+       if (usb_pipein (pipe))
+               urb_flags |= URB_SHORT_NOT_OK;
+
+       for (i = 0; i < io->entries; i++, io->count = i) {
+               unsigned                len;
+
+               io->urbs [i] = usb_alloc_urb (0, mem_flags);
+               if (!io->urbs [i]) {
+                       io->entries = i;
+                       goto nomem;
+               }
+
+               io->urbs [i]->dev = dev;
+               io->urbs [i]->pipe = pipe;
+               io->urbs [i]->interval = period;
+               io->urbs [i]->transfer_flags = urb_flags;
+
+               io->urbs [i]->complete = sg_complete;
+               io->urbs [i]->context = io;
+               io->urbs [i]->status = -EINPROGRESS;
+               io->urbs [i]->actual_length = 0;
+
+               if (dma) {
+                       /* hc may use _only_ transfer_dma */
+                       io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
+                       len = sg_dma_len (sg + i);
+               } else {
+                       /* hc may use _only_ transfer_buffer */
+                       io->urbs [i]->transfer_buffer =
+                               page_address (sg [i].page) + sg [i].offset;
+                       len = sg [i].length;
+               }
+
+               if (length) {
+                       len = min_t (unsigned, len, length);
+                       length -= len;
+                       if (length == 0)
+                               io->entries = i + 1;
+               }
+               io->urbs [i]->transfer_buffer_length = len;
+       }
+       io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
+
+       /* transaction state */
+       io->status = 0;
+       io->bytes = 0;
+       init_completion (&io->complete);
+       return 0;
+
+nomem:
+       sg_clean (io);
+       return -ENOMEM;
+}
+
+
+/**
+ * usb_sg_wait - synchronously execute scatter/gather request
+ * @io: request block handle, as initialized with usb_sg_init().
+ *     some fields become accessible when this call returns.
+ * Context: !in_interrupt ()
+ *
+ * This function blocks until the specified I/O operation completes.  It
+ * leverages the grouping of the related I/O requests to get good transfer
+ * rates, by queueing the requests.  At higher speeds, such queuing can
+ * significantly improve USB throughput.
+ *
+ * There are three kinds of completion for this function.
+ * (1) success, where io->status is zero.  The number of io->bytes
+ *     transferred is as requested.
+ * (2) error, where io->status is a negative errno value.  The number
+ *     of io->bytes transferred before the error is usually less
+ *     than requested, and can be nonzero.
+ * (3) cancelation, a type of error with status -ECONNRESET that
+ *     is initiated by usb_sg_cancel().
+ *
+ * When this function returns, all memory allocated through usb_sg_init() or
+ * this call will have been freed.  The request block parameter may still be
+ * passed to usb_sg_cancel(), or it may be freed.  It could also be
+ * reinitialized and then reused.
+ *
+ * Data Transfer Rates:
+ *
+ * Bulk transfers are valid for full or high speed endpoints.
+ * The best full speed data rate is 19 packets of 64 bytes each
+ * per frame, or 1216 bytes per millisecond.
+ * The best high speed data rate is 13 packets of 512 bytes each
+ * per microframe, or 52 KBytes per millisecond.
+ *
+ * The reason to use interrupt transfers through this API would most likely
+ * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond
+ * could be transferred.  That capability is less useful for low or full
+ * speed interrupt endpoints, which allow at most one packet per millisecond,
+ * of at most 8 or 64 bytes (respectively).
+ */
+void usb_sg_wait (struct usb_sg_request *io)
+{
+       int             i;
+       unsigned long   flags;
+
+       /* queue the urbs.  */
+       spin_lock_irqsave (&io->lock, flags);
+       for (i = 0; i < io->entries && !io->status; i++) {
+               int     retval;
+
+               retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC);
+
+               /* after we submit, let completions or cancelations fire;
+                * we handshake using io->status.
+                */
+               spin_unlock_irqrestore (&io->lock, flags);
+               switch (retval) {
+                       /* maybe we retrying will recover */
+               case -ENXIO:    // hc didn't queue this one
+               case -EAGAIN:
+               case -ENOMEM:
+                       retval = 0;
+                       i--;
+                       // FIXME:  should it usb_sg_cancel() on INTERRUPT?
+                       yield ();
+                       break;
+
+                       /* no error? continue immediately.
+                        *
+                        * NOTE: to work better with UHCI (4K I/O buffer may
+                        * need 3K of TDs) it may be good to limit how many
+                        * URBs are queued at once; N milliseconds?
+                        */
+               case 0:
+                       cpu_relax ();
+                       break;
+
+                       /* fail any uncompleted urbs */
+               default:
+                       io->urbs [i]->status = retval;
+                       dbg ("usb_sg_msg, submit --> %d", retval);
+                       usb_sg_cancel (io);
+               }
+               spin_lock_irqsave (&io->lock, flags);
+               if (retval && io->status == -ECONNRESET)
+                       io->status = retval;
+       }
+       spin_unlock_irqrestore (&io->lock, flags);
+
+       /* OK, yes, this could be packaged as non-blocking.
+        * So could the submit loop above ... but it's easier to
+        * solve neither problem than to solve both!
+        */
+       wait_for_completion (&io->complete);
+
+       sg_clean (io);
+}
+
+/**
+ * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
+ * @io: request block, initialized with usb_sg_init()
+ *
+ * This stops a request after it has been started by usb_sg_wait().
+ * It can also prevents one initialized by usb_sg_init() from starting,
+ * so that call just frees resources allocated to the request.
+ */
+void usb_sg_cancel (struct usb_sg_request *io)
+{
+       unsigned long   flags;
+
+       spin_lock_irqsave (&io->lock, flags);
+
+       /* shut everything down, if it didn't already */
+       if (!io->status) {
+               int     i;
+
+               io->status = -ECONNRESET;
+               for (i = 0; i < io->entries; i++) {
+                       int     retval;
+
+                       if (!io->urbs [i]->dev)
+                               continue;
+                       retval = usb_unlink_urb (io->urbs [i]);
+                       if (retval && retval != -EINPROGRESS)
+                               warn ("usb_sg_cancel, unlink --> %d", retval);
+                       // FIXME don't warn on "not yet submitted" error
+               }
+       }
+       spin_unlock_irqrestore (&io->lock, flags);
+}
+#endif
+/*-------------------------------------------------------------------*/
+
+/**
+ * usb_get_descriptor - issues a generic GET_DESCRIPTOR request
+ * @dev: the device whose descriptor is being retrieved
+ * @type: the descriptor type (USB_DT_*)
+ * @index: the number of the descriptor
+ * @buf: where to put the descriptor
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ *
+ * Gets a USB descriptor.  Convenience functions exist to simplify
+ * getting some types of descriptors.  Use
+ * usb_get_device_descriptor() for USB_DT_DEVICE,
+ * and usb_get_string() or usb_string() for USB_DT_STRING.
+ * Configuration descriptors (USB_DT_CONFIG) are part of the device
+ * structure, at least for the current configuration.
+ * In addition to a number of USB-standard descriptors, some
+ * devices also use class-specific or vendor-specific descriptors.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+{
+       int i = 5;
+       int result;
+       
+       memset(buf,0,size);     // Make sure we parse really received data
+
+       while (i--) {
+               /* retries if the returned length was 0; flakey device */
+               if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                   USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+                                   (type << 8) + index, 0, buf, size,
+                                   HZ * USB_CTRL_GET_TIMEOUT)) > 0
+                               || result == -EPIPE)
+                       break;
+       }
+       return result;
+}
+
+/**
+ * usb_get_string - gets a string descriptor
+ * @dev: the device whose string descriptor is being retrieved
+ * @langid: code for language chosen (from string descriptor zero)
+ * @index: the number of the descriptor
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ *
+ * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
+ * in little-endian byte order).
+ * The usb_string() function will often be a convenient way to turn
+ * these strings into kernel-printable form.
+ *
+ * Strings may be referenced in device, configuration, interface, or other
+ * descriptors, and could also be used in vendor-specific ways.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+               (USB_DT_STRING << 8) + index, langid, buf, size,
+               HZ * USB_CTRL_GET_TIMEOUT);
+}
+
+/**
+ * usb_get_device_descriptor - (re)reads the device descriptor
+ * @dev: the device whose device descriptor is being updated
+ * Context: !in_interrupt ()
+ *
+ * Updates the copy of the device descriptor stored in the device structure,
+ * which dedicates space for this purpose.  Note that several fields are
+ * converted to the host CPU's byte order:  the USB version (bcdUSB), and
+ * vendors product and version fields (idVendor, idProduct, and bcdDevice).
+ * That lets device drivers compare against non-byteswapped constants.
+ *
+ * There's normally no need to use this call, although some devices
+ * will change their descriptors after events like updating firmware.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_device_descriptor(struct usb_device *dev)
+{
+       int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
+                                    sizeof(dev->descriptor));
+       if (ret >= 0) {
+               le16_to_cpus(&dev->descriptor.bcdUSB);
+               le16_to_cpus(&dev->descriptor.idVendor);
+               le16_to_cpus(&dev->descriptor.idProduct);
+               le16_to_cpus(&dev->descriptor.bcdDevice);
+       }
+       return ret;
+}
+
+/**
+ * usb_get_status - issues a GET_STATUS call
+ * @dev: the device whose status is being checked
+ * @type: USB_RECIP_*; for device, interface, or endpoint
+ * @target: zero (for device), else interface or endpoint number
+ * @data: pointer to two bytes of bitmap data
+ * Context: !in_interrupt ()
+ *
+ * Returns device, interface, or endpoint status.  Normally only of
+ * interest to see if the device is self powered, or has enabled the
+ * remote wakeup facility; or whether a bulk or interrupt endpoint
+ * is halted ("stalled").
+ *
+ * Bits in these status bitmaps are set using the SET_FEATURE request,
+ * and cleared using the CLEAR_FEATURE request.  The usb_clear_halt()
+ * function should be used to clear halt ("stall") status.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns the number of bytes received on success, or else the status code
+ * returned by the underlying usb_control_msg() call.
+ */
+int usb_get_status(struct usb_device *dev, int type, int target, void *data)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2,
+               HZ * USB_CTRL_GET_TIMEOUT);
+}
+
+
+// hub-only!! ... and only exported for reset/reinit path.
+// otherwise used internally, when setting up a config
+void usb_set_maxpacket(struct usb_device *dev)
+{
+       int i, b;
+
+       /* NOTE:  affects all endpoints _except_ ep0 */
+       for (i=0; i<dev->actconfig->desc.bNumInterfaces; i++) {
+               struct usb_interface *ifp = dev->actconfig->interface + i;
+               struct usb_host_interface *as = ifp->altsetting + ifp->act_altsetting;
+               struct usb_host_endpoint *ep = as->endpoint;
+               int e;
+
+               for (e=0; e<as->desc.bNumEndpoints; e++) {
+                       struct usb_endpoint_descriptor  *d;
+                       d = &ep [e].desc;
+                       b = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+                       if ((d->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                               USB_ENDPOINT_XFER_CONTROL) {    /* Control => bidirectional */
+                               dev->epmaxpacketout[b] = d->wMaxPacketSize;
+                               dev->epmaxpacketin [b] = d->wMaxPacketSize;
+                               }
+                       else if (usb_endpoint_out(d->bEndpointAddress)) {
+                               if (d->wMaxPacketSize > dev->epmaxpacketout[b])
+                                       dev->epmaxpacketout[b] = d->wMaxPacketSize;
+                       }
+                       else {
+                               if (d->wMaxPacketSize > dev->epmaxpacketin [b])
+                                       dev->epmaxpacketin [b] = d->wMaxPacketSize;
+                       }
+               }
+       }
+}
+
+/**
+ * usb_clear_halt - tells device to clear endpoint halt/stall condition
+ * @dev: device whose endpoint is halted
+ * @pipe: endpoint "pipe" being cleared
+ * Context: !in_interrupt ()
+ *
+ * This is used to clear halt conditions for bulk and interrupt endpoints,
+ * as reported by URB completion status.  Endpoints that are halted are
+ * sometimes referred to as being "stalled".  Such endpoints are unable
+ * to transmit or receive data until the halt status is cleared.  Any URBs
+ * queued for such an endpoint should normally be unlinked by the driver
+ * before clearing the halt condition, as described in sections 5.7.5
+ * and 5.8.5 of the USB 2.0 spec.
+ *
+ * Note that control and isochronous endpoints don't halt, although control
+ * endpoints report "protocol stall" (for unsupported requests) using the
+ * same status code used to report a true stall.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns zero on success, or else the status code returned by the
+ * underlying usb_control_msg() call.
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
+{
+       int result;
+       int endp = usb_pipeendpoint(pipe);
+       
+       if (usb_pipein (pipe))
+               endp |= USB_DIR_IN;
+
+       /* we don't care if it wasn't halted first. in fact some devices
+        * (like some ibmcam model 1 units) seem to expect hosts to make
+        * this request for iso endpoints, which can't halt!
+        */
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0,
+               HZ * USB_CTRL_SET_TIMEOUT);
+
+       /* don't un-halt or force to DATA0 except on success */
+       if (result < 0)
+               return result;
+
+       /* NOTE:  seems like Microsoft and Apple don't bother verifying
+        * the clear "took", so some devices could lock up if you check...
+        * such as the Hagiwara FlashGate DUAL.  So we won't bother.
+        *
+        * NOTE:  make sure the logic here doesn't diverge much from
+        * the copy in usb-storage, for as long as we need two copies.
+        */
+
+       /* toggle was reset by the clear, then ep was reactivated */
+       usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+       usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+       return 0;
+}
+
+/**
+ * usb_set_interface - Makes a particular alternate setting be current
+ * @dev: the device whose interface is being updated
+ * @interface: the interface being updated
+ * @alternate: the setting being chosen.
+ * Context: !in_interrupt ()
+ *
+ * This is used to enable data transfers on interfaces that may not
+ * be enabled by default.  Not all devices support such configurability.
+ * Only the driver bound to an interface may change its setting.
+ *
+ * Within any given configuration, each interface may have several
+ * alternative settings.  These are often used to control levels of
+ * bandwidth consumption.  For example, the default setting for a high
+ * speed interrupt endpoint may not send more than 64 bytes per microframe,
+ * while interrupt transfers of up to 3KBytes per microframe are legal.
+ * Also, isochronous endpoints may never be part of an
+ * interface's default setting.  To access such bandwidth, alternate
+ * interface settings must be made current.
+ *
+ * Note that in the Linux USB subsystem, bandwidth associated with
+ * an endpoint in a given alternate setting is not reserved until an URB
+ * is submitted that needs that bandwidth.  Some other operating systems
+ * allocate bandwidth early, when a configuration is chosen.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ * Also, drivers must not change altsettings while urbs are scheduled for
+ * endpoints in that interface; all such urbs must first be completed
+ * (perhaps forced by unlinking).
+ *
+ * Returns zero on success, or else the status code returned by the
+ * underlying usb_control_msg() call.
+ */
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+       struct usb_interface *iface;
+       struct usb_host_interface *iface_as;
+       int i, ret;
+       void (*disable)(struct usb_device *, int) = dev->bus->op->disable;
+
+       iface = usb_ifnum_to_if(dev, interface);
+       if (!iface) {
+               warn("selecting invalid interface %d", interface);
+               return -EINVAL;
+       }
+
+       /* 9.4.10 says devices don't need this, if the interface
+          only has one alternate setting */
+       if (iface->num_altsetting == 1) {
+               dbg("ignoring set_interface for dev %d, iface %d, alt %d",
+                       dev->devnum, interface, alternate);
+               return 0;
+       }
+
+       if (alternate < 0 || alternate >= iface->num_altsetting)
+               return -EINVAL;
+
+       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                  USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
+                                  iface->altsetting[alternate]
+                                       .desc.bAlternateSetting,
+                                  interface, NULL, 0, HZ * 5)) < 0)
+               return ret;
+
+       /* FIXME drivers shouldn't need to replicate/bugfix the logic here
+        * when they implement async or easily-killable versions of this or
+        * other "should-be-internal" functions (like clear_halt).
+        * should hcd+usbcore postprocess control requests?
+        */
+
+       /* prevent submissions using previous endpoint settings */
+       iface_as = iface->altsetting + iface->act_altsetting;
+       for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {
+               u8      ep = iface_as->endpoint [i].desc.bEndpointAddress;
+               int     out = !(ep & USB_DIR_IN);
+
+               /* clear out hcd state, then usbcore state */
+               if (disable)
+                       disable (dev, ep);
+               ep &= USB_ENDPOINT_NUMBER_MASK;
+               (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0;
+       }
+       iface->act_altsetting = alternate;
+
+       /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as
+        *
+        * Note:
+        * Despite EP0 is always present in all interfaces/AS, the list of
+        * endpoints from the descriptor does not contain EP0. Due to its
+        * omnipresence one might expect EP0 being considered "affected" by
+        * any SetInterface request and hence assume toggles need to be reset.
+        * However, EP0 toggles are re-synced for every individual transfer
+        * during the SETUP stage - hence EP0 toggles are "don't care" here.
+        * (Likewise, EP0 never "halts" on well designed devices.)
+        */
+
+       iface_as = &iface->altsetting[alternate];
+       for (i = 0; i < iface_as->desc.bNumEndpoints; i++) {
+               u8      ep = iface_as->endpoint[i].desc.bEndpointAddress;
+               int     out = !(ep & USB_DIR_IN);
+
+               ep &= USB_ENDPOINT_NUMBER_MASK;
+               usb_settoggle (dev, ep, out, 0);
+               (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep]
+                       = iface_as->endpoint [i].desc.wMaxPacketSize;
+               usb_endpoint_running (dev, ep, out);
+       }
+
+       return 0;
+}
+
+/**
+ * usb_set_configuration - Makes a particular device setting be current
+ * @dev: the device whose configuration is being updated
+ * @configuration: the configuration being chosen.
+ * Context: !in_interrupt ()
+ *
+ * This is used to enable non-default device modes.  Not all devices
+ * support this kind of configurability.  By default, configuration
+ * zero is selected after enumeration; many devices only have a single
+ * configuration.
+ *
+ * USB devices may support one or more configurations, which affect
+ * power consumption and the functionality available.  For example,
+ * the default configuration is limited to using 100mA of bus power,
+ * so that when certain device functionality requires more power,
+ * and the device is bus powered, that functionality will be in some
+ * non-default device configuration.  Other device modes may also be
+ * reflected as configuration options, such as whether two ISDN
+ * channels are presented as independent 64Kb/s interfaces or as one
+ * bonded 128Kb/s interface.
+ *
+ * Note that USB has an additional level of device configurability,
+ * associated with interfaces.  That configurability is accessed using
+ * usb_set_interface().
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns zero on success, or else the status code returned by the
+ * underlying usb_control_msg() call.
+ */
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+       int i, ret;
+       struct usb_host_config *cp = NULL;
+       void (*disable)(struct usb_device *, int) = dev->bus->op->disable;
+       
+       for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+               if (dev->config[i].desc.bConfigurationValue == configuration) {
+                       cp = &dev->config[i];
+                       break;
+               }
+       }
+       if ((!cp && configuration != 0) || (cp && configuration == 0)) {
+               warn("selecting invalid configuration %d", configuration);
+               return -EINVAL;
+       }
+
+       /* if it's already configured, clear out old state first. */
+       if (dev->state != USB_STATE_ADDRESS && disable) {
+               for (i = 1 /* skip ep0 */; i < 15; i++) {
+                       disable (dev, i);
+                       disable (dev, USB_DIR_IN | i);
+               }
+       }
+       dev->toggle[0] = dev->toggle[1] = 0;
+       dev->halted[0] = dev->halted[1] = 0;
+       dev->state = USB_STATE_ADDRESS;
+
+       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+                       NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
+               return ret;
+       if (configuration)
+               dev->state = USB_STATE_CONFIGURED;
+       dev->actconfig = cp;
+
+       /* reset more hc/hcd endpoint state */
+       usb_set_maxpacket(dev);
+
+       return 0;
+}
+
+
+/**
+ * usb_string - returns ISO 8859-1 version of a string descriptor
+ * @dev: the device whose string descriptor is being retrieved
+ * @index: the number of the descriptor
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ * 
+ * This converts the UTF-16LE encoded strings returned by devices, from
+ * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
+ * that are more usable in most kernel contexts.  Note that all characters
+ * in the chosen descriptor that can't be encoded using ISO-8859-1
+ * are converted to the question mark ("?") character, and this function
+ * chooses strings in the first language supported by the device.
+ *
+ * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
+ * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
+ * and is appropriate for use many uses of English and several other
+ * Western European languages.  (But it doesn't include the "Euro" symbol.)
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns length of the string (>= 0) or usb_control_msg status (< 0).
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+       unsigned char *tbuf;
+       int err, len;
+       unsigned int u, idx;
+
+       if (size <= 0 || !buf || !index)
+               return -EINVAL;
+       buf[0] = 0;
+       tbuf = kmalloc(256, GFP_KERNEL);
+       if (!tbuf)
+               return -ENOMEM;
+
+       /* get langid for strings if it's not yet known */
+       if (!dev->have_langid) {
+               err = usb_get_string(dev, 0, 0, tbuf, 4);
+               if (err < 0) {
+                       err("error getting string descriptor 0 (error=%d)", err);
+                       goto errout;
+               } else if (tbuf[0] < 4) {
+                       err("string descriptor 0 too short");
+                       err = -EINVAL;
+                       goto errout;
+               } else {
+                       dev->have_langid = -1;
+                       dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+                               /* always use the first langid listed */
+                       dbg("USB device number %d default language ID 0x%x",
+                               dev->devnum, dev->string_langid);
+               }
+       }
+
+       /*
+        * ask for the length of the string 
+        */
+
+       err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);
+       if(err<2)
+               goto errout;
+       len=tbuf[0];    
+       
+       err = usb_get_string(dev, dev->string_langid, index, tbuf, len);
+       if (err < 0)
+               goto errout;
+
+       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 ISO-8859-1 character */
+               else
+                       buf[idx++] = tbuf[u];
+       }
+       buf[idx] = 0;
+       err = idx;
+
+ errout:
+       kfree(tbuf);
+       return err;
+}
+
+// synchronous request completion model
+EXPORT_SYMBOL(usb_control_msg);
+EXPORT_SYMBOL(usb_bulk_msg);
+
+EXPORT_SYMBOL(usb_sg_init);
+EXPORT_SYMBOL(usb_sg_cancel);
+EXPORT_SYMBOL(usb_sg_wait);
+
+// synchronous control message convenience routines
+EXPORT_SYMBOL(usb_get_descriptor);
+EXPORT_SYMBOL(usb_get_device_descriptor);
+EXPORT_SYMBOL(usb_get_status);
+EXPORT_SYMBOL(usb_get_string);
+EXPORT_SYMBOL(usb_string);
+EXPORT_SYMBOL(usb_clear_halt);
+EXPORT_SYMBOL(usb_set_configuration);
+EXPORT_SYMBOL(usb_set_interface);
+
index 08b691f..4ba8cb4 100644 (file)
-#include "../usb_wrapper.h"\r
-#include "hcd.h"\r
-\r
-/**\r
- * usb_init_urb - initializes a urb so that it can be used by a USB driver\r
- * @urb: pointer to the urb to initialize\r
- *\r
- * Initializes a urb so that the USB subsystem can use it properly.\r
- *\r
- * If a urb is created with a call to usb_alloc_urb() it is not\r
- * necessary to call this function.  Only use this if you allocate the\r
- * space for a struct urb on your own.  If you call this function, be\r
- * careful when freeing the memory for your urb that it is no longer in\r
- * use by the USB core.\r
- *\r
- * Only use this function if you _really_ understand what you are doing.\r
- */\r
-void STDCALL usb_init_urb(struct urb *urb)\r
-{\r
-       if (urb) {\r
-               memset(urb, 0, sizeof(*urb));\r
-               urb->count = (atomic_t)ATOMIC_INIT(1);\r
-               spin_lock_init(&urb->lock);\r
-       }\r
-}\r
-\r
-/**\r
- * usb_alloc_urb - creates a new urb for a USB driver to use\r
- * @iso_packets: number of iso packets for this urb\r
- * @mem_flags: the type of memory to allocate, see kmalloc() for a list of\r
- *     valid options for this.\r
- *\r
- * Creates an urb for the USB driver to use, initializes a few internal\r
- * structures, incrementes the usage counter, and returns a pointer to it.\r
- *\r
- * If no memory is available, NULL is returned.\r
- *\r
- * If the driver want to use this urb for interrupt, control, or bulk\r
- * endpoints, pass '0' as the number of iso packets.\r
- *\r
- * The driver must call usb_free_urb() when it is finished with the urb.\r
- */\r
-struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags)\r
-{\r
-       struct urb *urb;\r
-\r
-       urb = (struct urb *)kmalloc(sizeof(struct urb) + \r
-               iso_packets * sizeof(struct usb_iso_packet_descriptor),\r
-               mem_flags);\r
-       if (!urb) {\r
-               err("alloc_urb: kmalloc failed");\r
-               return NULL;\r
-       }\r
-       usb_init_urb(urb);\r
-       return urb;\r
-}\r
-\r
-/**\r
- * usb_free_urb - frees the memory used by a urb when all users of it are finished\r
- * @urb: pointer to the urb to free\r
- *\r
- * Must be called when a user of a urb is finished with it.  When the last user\r
- * of the urb calls this function, the memory of the urb is freed.\r
- *\r
- * Note: The transfer buffer associated with the urb is not freed, that must be\r
- * done elsewhere.\r
- */\r
-void STDCALL usb_free_urb(struct urb *urb)\r
-{\r
-       if (urb)\r
-               if (atomic_dec_and_test(&urb->count))\r
-               {\r
-                       kfree(urb);\r
-               }\r
-}\r
-\r
-/**\r
- * usb_get_urb - increments the reference count of the urb\r
- * @urb: pointer to the urb to modify\r
- *\r
- * This must be  called whenever a urb is transferred from a device driver to a\r
- * host controller driver.  This allows proper reference counting to happen\r
- * for urbs.\r
- *\r
- * A pointer to the urb with the incremented reference counter is returned.\r
- */\r
-struct urb STDCALL * usb_get_urb(struct urb *urb)\r
-{\r
-       if (urb) {\r
-               atomic_inc(&urb->count);\r
-               return urb;\r
-       } else\r
-               return NULL;\r
-}\r
-               \r
-\r
-/*-------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_submit_urb - issue an asynchronous transfer request for an endpoint\r
- * @urb: pointer to the urb describing the request\r
- * @mem_flags: the type of memory to allocate, see kmalloc() for a list\r
- *     of valid options for this.\r
- *\r
- * This submits a transfer request, and transfers control of the URB\r
- * describing that request to the USB subsystem.  Request completion will\r
- * be indicated later, asynchronously, by calling the completion handler.\r
- * The three types of completion are success, error, and unlink\r
- * (also called "request cancellation").\r
- * URBs may be submitted in interrupt context.\r
- *\r
- * The caller must have correctly initialized the URB before submitting\r
- * it.  Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are\r
- * available to ensure that most fields are correctly initialized, for\r
- * the particular kind of transfer, although they will not initialize\r
- * any transfer flags.\r
- *\r
- * Successful submissions return 0; otherwise this routine returns a\r
- * negative error number.  If the submission is successful, the complete()\r
- * callback from the urb will be called exactly once, when the USB core and\r
- * host controller driver are finished with the urb.  When the completion\r
- * function is called, control of the URB is returned to the device\r
- * driver which issued the request.  The completion handler may then\r
- * immediately free or reuse that URB.\r
- *\r
- * For control endpoints, the synchronous usb_control_msg() call is\r
- * often used (in non-interrupt context) instead of this call.\r
- * That is often used through convenience wrappers, for the requests\r
- * that are standardized in the USB 2.0 specification.  For bulk\r
- * endpoints, a synchronous usb_bulk_msg() call is available.\r
- *\r
- * Request Queuing:\r
- *\r
- * URBs may be submitted to endpoints before previous ones complete, to\r
- * minimize the impact of interrupt latencies and system overhead on data\r
- * throughput.  This is required for continuous isochronous data streams,\r
- * and may also be required for some kinds of interrupt transfers. Such\r
- * queueing also maximizes bandwidth utilization by letting USB controllers\r
- * start work on later requests before driver software has finished the\r
- * completion processing for earlier requests.\r
- *\r
- * Bulk and Isochronous URBs may always be queued.  At this writing, all\r
- * mainstream host controller drivers support queueing for control and\r
- * interrupt transfer requests.\r
- *\r
- * Reserved Bandwidth Transfers:\r
- *\r
- * Periodic transfers (interrupt or isochronous) are performed repeatedly,\r
- * using the interval specified in the urb.  Submitting the first urb to\r
- * the endpoint reserves the bandwidth necessary to make those transfers.\r
- * If the USB subsystem can't allocate sufficient bandwidth to perform\r
- * the periodic request, submitting such a periodic request should fail.\r
- *\r
- * Device drivers must explicitly request that repetition, by ensuring that\r
- * some URB is always on the endpoint's queue (except possibly for short\r
- * periods during completion callacks).  When there is no longer an urb\r
- * queued, the endpoint's bandwidth reservation is canceled.  This means\r
- * drivers can use their completion handlers to ensure they keep bandwidth\r
- * they need, by reinitializing and resubmitting the just-completed urb\r
- * until the driver longer needs that periodic bandwidth.\r
- *\r
- * Memory Flags:\r
- *\r
- * The general rules for how to decide which mem_flags to use\r
- * are the same as for kmalloc.  There are four\r
- * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and\r
- * GFP_ATOMIC.\r
- *\r
- * GFP_NOFS is not ever used, as it has not been implemented yet.\r
- *\r
- * GFP_ATOMIC is used when\r
- *   (a) you are inside a completion handler, an interrupt, bottom half,\r
- *       tasklet or timer, or\r
- *   (b) you are holding a spinlock or rwlock (does not apply to\r
- *       semaphores), or\r
- *   (c) current->state != TASK_RUNNING, this is the case only after\r
- *       you've changed it.\r
- * \r
- * GFP_NOIO is used in the block io path and error handling of storage\r
- * devices.\r
- *\r
- * All other situations use GFP_KERNEL.\r
- *\r
- * Some more specific rules for mem_flags can be inferred, such as\r
- *  (1) start_xmit, timeout, and receive methods of network drivers must\r
- *      use GFP_ATOMIC (they are called with a spinlock held);\r
- *  (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also\r
- *      called with a spinlock held);\r
- *  (3) If you use a kernel thread with a network driver you must use\r
- *      GFP_NOIO, unless (b) or (c) apply;\r
- *  (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)\r
- *      apply or your are in a storage driver's block io path;\r
- *  (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and\r
- *  (6) changing firmware on a running storage or net device uses\r
- *      GFP_NOIO, unless b) or c) apply\r
- *\r
- */\r
-int STDCALL usb_submit_urb(struct urb *urb, int mem_flags)\r
-{\r
-       int                     pipe, temp, max;\r
-       struct usb_device       *dev;\r
-       struct usb_operations   *op;\r
-       int                     is_out;\r
-//     printk("sub dev %p bus %p num %i op %p sub %p\n",\r
-//            urb->dev, urb->dev->bus,urb->dev->devnum,urb->dev->bus->op, urb->dev->bus->op->submit_urb);\r
-       if (!urb || urb->hcpriv || !urb->complete)\r
-               return -EINVAL;\r
-       if (!(dev = urb->dev) ||\r
-           (dev->state < USB_STATE_DEFAULT) ||\r
-           (!dev->bus) || (dev->devnum <= 0))\r
-               return -ENODEV;\r
-       if (!(op = dev->bus->op) || !op->submit_urb)\r
-               return -ENODEV;\r
-\r
-       urb->status = -EINPROGRESS;\r
-       urb->actual_length = 0;\r
-       urb->bandwidth = 0;\r
-\r
-       /* Lots of sanity checks, so HCDs can rely on clean data\r
-        * and don't need to duplicate tests\r
-        */\r
-       pipe = urb->pipe;\r
-       temp = usb_pipetype (pipe);\r
-       is_out = usb_pipeout (pipe);\r
-\r
-       if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)\r
-               return -ENODEV;\r
-\r
-       /* (actually HCDs may need to duplicate this, endpoint might yet\r
-        * stall due to queued bulk/intr transactions that complete after\r
-        * we check)\r
-        */\r
-       if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out))\r
-               return -EPIPE;\r
-\r
-       /* FIXME there should be a sharable lock protecting us against\r
-        * config/altsetting changes and disconnects, kicking in here.\r
-        * (here == before maxpacket, and eventually endpoint type,\r
-        * checks get made.)\r
-        */\r
-\r
-       max = usb_maxpacket (dev, pipe, is_out);\r
-       if (max <= 0) {\r
-               dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)",\r
-                       __FUNCTION__,\r
-                       usb_pipeendpoint (pipe), is_out ? "OUT" : "IN",\r
-                       dev->bus->bus_name, dev->devpath,\r
-                       max);\r
-               return -EMSGSIZE;\r
-       }\r
-\r
-       /* periodic transfers limit size per frame/uframe,\r
-        * but drivers only control those sizes for ISO.\r
-        * while we're checking, initialize return status.\r
-        */\r
-       if (temp == PIPE_ISOCHRONOUS) {\r
-               int     n, len;\r
-\r
-               /* "high bandwidth" mode, 1-3 packets/uframe? */\r
-               if (dev->speed == USB_SPEED_HIGH) {\r
-                       int     mult = 1 + ((max >> 11) & 0x03);\r
-                       max &= 0x03ff;\r
-                       max *= mult;\r
-               }\r
-\r
-               if (urb->number_of_packets <= 0)                    \r
-                       return -EINVAL;\r
-               for (n = 0; n < urb->number_of_packets; n++) {\r
-                       len = urb->iso_frame_desc [n].length;\r
-                       if (len < 0 || len > max) \r
-                               return -EMSGSIZE;\r
-                       urb->iso_frame_desc [n].status = -EXDEV;\r
-                       urb->iso_frame_desc [n].actual_length = 0;\r
-               }\r
-       }\r
-\r
-       /* the I/O buffer must be mapped/unmapped, except when length=0 */\r
-       if (urb->transfer_buffer_length < 0)\r
-               return -EMSGSIZE;\r
-\r
-#ifdef DEBUG\r
-       /* stuff that drivers shouldn't do, but which shouldn't\r
-        * cause problems in HCDs if they get it wrong.\r
-        */\r
-       {\r
-       unsigned int    orig_flags = urb->transfer_flags;\r
-       unsigned int    allowed;\r
-\r
-       /* enforce simple/standard policy */\r
-       allowed = URB_ASYNC_UNLINK;     // affects later unlinks\r
-       allowed |= URB_NO_DMA_MAP;\r
-       allowed |= URB_NO_INTERRUPT;\r
-       switch (temp) {\r
-       case PIPE_BULK:\r
-               if (is_out)\r
-                       allowed |= URB_ZERO_PACKET;\r
-               /* FALLTHROUGH */\r
-       case PIPE_CONTROL:\r
-               allowed |= URB_NO_FSBR; /* only affects UHCI */\r
-               /* FALLTHROUGH */\r
-       default:                        /* all non-iso endpoints */\r
-               if (!is_out)\r
-                       allowed |= URB_SHORT_NOT_OK;\r
-               break;\r
-       case PIPE_ISOCHRONOUS:\r
-               allowed |= URB_ISO_ASAP;\r
-               break;\r
-       }\r
-       urb->transfer_flags &= allowed;\r
-\r
-       /* fail if submitter gave bogus flags */\r
-       if (urb->transfer_flags != orig_flags) {\r
-               err ("BOGUS urb flags, %x --> %x",\r
-                       orig_flags, urb->transfer_flags);\r
-               return -EINVAL;\r
-       }\r
-       }\r
-#endif\r
-       /*\r
-        * Force periodic transfer intervals to be legal values that are\r
-        * a power of two (so HCDs don't need to).\r
-        *\r
-        * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC\r
-        * supports different values... this uses EHCI/UHCI defaults (and\r
-        * EHCI can use smaller non-default values).\r
-        */\r
-       switch (temp) {\r
-       case PIPE_ISOCHRONOUS:\r
-       case PIPE_INTERRUPT:\r
-               /* too small? */\r
-               if (urb->interval <= 0)\r
-                       return -EINVAL;\r
-               /* too big? */\r
-               switch (dev->speed) {\r
-               case USB_SPEED_HIGH:    /* units are microframes */\r
-                       // NOTE usb handles 2^15\r
-                       if (urb->interval > (1024 * 8))\r
-                               urb->interval = 1024 * 8;\r
-                       temp = 1024 * 8;\r
-                       break;\r
-               case USB_SPEED_FULL:    /* units are frames/msec */\r
-               case USB_SPEED_LOW:\r
-                       if (temp == PIPE_INTERRUPT) {\r
-                               if (urb->interval > 255)\r
-                                       return -EINVAL;\r
-                               // NOTE ohci only handles up to 32\r
-                               temp = 128;\r
-                       } else {\r
-                               if (urb->interval > 1024)\r
-                                       urb->interval = 1024;\r
-                               // NOTE usb and ohci handle up to 2^15\r
-                               temp = 1024;\r
-                       }\r
-                       break;\r
-               default:\r
-                       return -EINVAL;\r
-               }\r
-               /* power of two? */\r
-               while (temp > urb->interval)\r
-                       temp >>= 1;\r
-               urb->interval = temp;\r
-       }\r
-\r
-       return op->submit_urb (urb, mem_flags);\r
-}\r
-\r
-/*-------------------------------------------------------------------*/\r
-\r
-/**\r
- * usb_unlink_urb - abort/cancel a transfer request for an endpoint\r
- * @urb: pointer to urb describing a previously submitted request\r
- *\r
- * This routine cancels an in-progress request.  The requests's\r
- * completion handler will be called with a status code indicating\r
- * that the request has been canceled, and that control of the URB\r
- * has been returned to that device driver.\r
- *\r
- * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this\r
- * request is synchronous.  Success is indicated by returning zero,\r
- * at which time the urb will have been unlinked,\r
- * and the completion function will see status -ENOENT.  Failure is\r
- * indicated by any other return value.  This mode may not be used\r
- * when unlinking an urb from an interrupt context, such as a bottom\r
- * half or a completion handler,\r
- *\r
- * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this\r
- * request is asynchronous.  Success is indicated by returning -EINPROGRESS,\r
- * at which time the urb will normally not have been unlinked,\r
- * and the completion function will see status -ECONNRESET.  Failure is\r
- * indicated by any other return value.\r
- */\r
-int STDCALL usb_unlink_urb(struct urb *urb)\r
-{\r
-       if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)\r
-               return urb->dev->bus->op->unlink_urb(urb);\r
-       else\r
-               return -ENODEV;\r
-}\r
+#include "../usb_wrapper.h"
+#include "hcd.h"
+
+/**
+ * usb_init_urb - initializes a urb so that it can be used by a USB driver
+ * @urb: pointer to the urb to initialize
+ *
+ * Initializes a urb so that the USB subsystem can use it properly.
+ *
+ * If a urb is created with a call to usb_alloc_urb() it is not
+ * necessary to call this function.  Only use this if you allocate the
+ * space for a struct urb on your own.  If you call this function, be
+ * careful when freeing the memory for your urb that it is no longer in
+ * use by the USB core.
+ *
+ * Only use this function if you _really_ understand what you are doing.
+ */
+void STDCALL usb_init_urb(struct urb *urb)
+{
+       if (urb) {
+               memset(urb, 0, sizeof(*urb));
+               urb->count = (atomic_t)ATOMIC_INIT(1);
+               spin_lock_init(&urb->lock);
+       }
+}
+
+/**
+ * usb_alloc_urb - creates a new urb for a USB driver to use
+ * @iso_packets: number of iso packets for this urb
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list of
+ *     valid options for this.
+ *
+ * Creates an urb for the USB driver to use, initializes a few internal
+ * structures, incrementes the usage counter, and returns a pointer to it.
+ *
+ * If no memory is available, NULL is returned.
+ *
+ * If the driver want to use this urb for interrupt, control, or bulk
+ * endpoints, pass '0' as the number of iso packets.
+ *
+ * The driver must call usb_free_urb() when it is finished with the urb.
+ */
+struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags)
+{
+       struct urb *urb;
+
+       urb = (struct urb *)kmalloc(sizeof(struct urb) + 
+               iso_packets * sizeof(struct usb_iso_packet_descriptor),
+               mem_flags);
+       if (!urb) {
+               err("alloc_urb: kmalloc failed");
+               return NULL;
+       }
+       usb_init_urb(urb);
+       return urb;
+}
+
+/**
+ * usb_free_urb - frees the memory used by a urb when all users of it are finished
+ * @urb: pointer to the urb to free
+ *
+ * Must be called when a user of a urb is finished with it.  When the last user
+ * of the urb calls this function, the memory of the urb is freed.
+ *
+ * Note: The transfer buffer associated with the urb is not freed, that must be
+ * done elsewhere.
+ */
+void STDCALL usb_free_urb(struct urb *urb)
+{
+       if (urb)
+               if (atomic_dec_and_test(&urb->count))
+               {
+                       kfree(urb);
+               }
+}
+
+/**
+ * usb_get_urb - increments the reference count of the urb
+ * @urb: pointer to the urb to modify
+ *
+ * This must be  called whenever a urb is transferred from a device driver to a
+ * host controller driver.  This allows proper reference counting to happen
+ * for urbs.
+ *
+ * A pointer to the urb with the incremented reference counter is returned.
+ */
+struct urb STDCALL * usb_get_urb(struct urb *urb)
+{
+       if (urb) {
+               atomic_inc(&urb->count);
+               return urb;
+       } else
+               return NULL;
+}
+               
+
+/*-------------------------------------------------------------------*/
+
+/**
+ * usb_submit_urb - issue an asynchronous transfer request for an endpoint
+ * @urb: pointer to the urb describing the request
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list
+ *     of valid options for this.
+ *
+ * This submits a transfer request, and transfers control of the URB
+ * describing that request to the USB subsystem.  Request completion will
+ * be indicated later, asynchronously, by calling the completion handler.
+ * The three types of completion are success, error, and unlink
+ * (also called "request cancellation").
+ * URBs may be submitted in interrupt context.
+ *
+ * The caller must have correctly initialized the URB before submitting
+ * it.  Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
+ * available to ensure that most fields are correctly initialized, for
+ * the particular kind of transfer, although they will not initialize
+ * any transfer flags.
+ *
+ * Successful submissions return 0; otherwise this routine returns a
+ * negative error number.  If the submission is successful, the complete()
+ * callback from the urb will be called exactly once, when the USB core and
+ * host controller driver are finished with the urb.  When the completion
+ * function is called, control of the URB is returned to the device
+ * driver which issued the request.  The completion handler may then
+ * immediately free or reuse that URB.
+ *
+ * For control endpoints, the synchronous usb_control_msg() call is
+ * often used (in non-interrupt context) instead of this call.
+ * That is often used through convenience wrappers, for the requests
+ * that are standardized in the USB 2.0 specification.  For bulk
+ * endpoints, a synchronous usb_bulk_msg() call is available.
+ *
+ * Request Queuing:
+ *
+ * URBs may be submitted to endpoints before previous ones complete, to
+ * minimize the impact of interrupt latencies and system overhead on data
+ * throughput.  This is required for continuous isochronous data streams,
+ * and may also be required for some kinds of interrupt transfers. Such
+ * queueing also maximizes bandwidth utilization by letting USB controllers
+ * start work on later requests before driver software has finished the
+ * completion processing for earlier requests.
+ *
+ * Bulk and Isochronous URBs may always be queued.  At this writing, all
+ * mainstream host controller drivers support queueing for control and
+ * interrupt transfer requests.
+ *
+ * Reserved Bandwidth Transfers:
+ *
+ * Periodic transfers (interrupt or isochronous) are performed repeatedly,
+ * using the interval specified in the urb.  Submitting the first urb to
+ * the endpoint reserves the bandwidth necessary to make those transfers.
+ * If the USB subsystem can't allocate sufficient bandwidth to perform
+ * the periodic request, submitting such a periodic request should fail.
+ *
+ * Device drivers must explicitly request that repetition, by ensuring that
+ * some URB is always on the endpoint's queue (except possibly for short
+ * periods during completion callacks).  When there is no longer an urb
+ * queued, the endpoint's bandwidth reservation is canceled.  This means
+ * drivers can use their completion handlers to ensure they keep bandwidth
+ * they need, by reinitializing and resubmitting the just-completed urb
+ * until the driver longer needs that periodic bandwidth.
+ *
+ * Memory Flags:
+ *
+ * The general rules for how to decide which mem_flags to use
+ * are the same as for kmalloc.  There are four
+ * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
+ * GFP_ATOMIC.
+ *
+ * GFP_NOFS is not ever used, as it has not been implemented yet.
+ *
+ * GFP_ATOMIC is used when
+ *   (a) you are inside a completion handler, an interrupt, bottom half,
+ *       tasklet or timer, or
+ *   (b) you are holding a spinlock or rwlock (does not apply to
+ *       semaphores), or
+ *   (c) current->state != TASK_RUNNING, this is the case only after
+ *       you've changed it.
+ * 
+ * GFP_NOIO is used in the block io path and error handling of storage
+ * devices.
+ *
+ * All other situations use GFP_KERNEL.
+ *
+ * Some more specific rules for mem_flags can be inferred, such as
+ *  (1) start_xmit, timeout, and receive methods of network drivers must
+ *      use GFP_ATOMIC (they are called with a spinlock held);
+ *  (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
+ *      called with a spinlock held);
+ *  (3) If you use a kernel thread with a network driver you must use
+ *      GFP_NOIO, unless (b) or (c) apply;
+ *  (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
+ *      apply or your are in a storage driver's block io path;
+ *  (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
+ *  (6) changing firmware on a running storage or net device uses
+ *      GFP_NOIO, unless b) or c) apply
+ *
+ */
+int STDCALL usb_submit_urb(struct urb *urb, int mem_flags)
+{
+       int                     pipe, temp, max;
+       struct usb_device       *dev;
+       struct usb_operations   *op;
+       int                     is_out;
+//     printk("sub dev %p bus %p num %i op %p sub %p\n",
+//            urb->dev, urb->dev->bus,urb->dev->devnum,urb->dev->bus->op, urb->dev->bus->op->submit_urb);
+       if (!urb || urb->hcpriv || !urb->complete)
+               return -EINVAL;
+       if (!(dev = urb->dev) ||
+           (dev->state < USB_STATE_DEFAULT) ||
+           (!dev->bus) || (dev->devnum <= 0))
+               return -ENODEV;
+       if (!(op = dev->bus->op) || !op->submit_urb)
+               return -ENODEV;
+
+       urb->status = -EINPROGRESS;
+       urb->actual_length = 0;
+       urb->bandwidth = 0;
+
+       /* Lots of sanity checks, so HCDs can rely on clean data
+        * and don't need to duplicate tests
+        */
+       pipe = urb->pipe;
+       temp = usb_pipetype (pipe);
+       is_out = usb_pipeout (pipe);
+
+       if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+               return -ENODEV;
+
+       /* (actually HCDs may need to duplicate this, endpoint might yet
+        * stall due to queued bulk/intr transactions that complete after
+        * we check)
+        */
+       if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out))
+               return -EPIPE;
+
+       /* FIXME there should be a sharable lock protecting us against
+        * config/altsetting changes and disconnects, kicking in here.
+        * (here == before maxpacket, and eventually endpoint type,
+        * checks get made.)
+        */
+
+       max = usb_maxpacket (dev, pipe, is_out);
+       if (max <= 0) {
+               dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)",
+                       __FUNCTION__,
+                       usb_pipeendpoint (pipe), is_out ? "OUT" : "IN",
+                       dev->bus->bus_name, dev->devpath,
+                       max);
+               return -EMSGSIZE;
+       }
+
+       /* periodic transfers limit size per frame/uframe,
+        * but drivers only control those sizes for ISO.
+        * while we're checking, initialize return status.
+        */
+       if (temp == PIPE_ISOCHRONOUS) {
+               int     n, len;
+
+               /* "high bandwidth" mode, 1-3 packets/uframe? */
+               if (dev->speed == USB_SPEED_HIGH) {
+                       int     mult = 1 + ((max >> 11) & 0x03);
+                       max &= 0x03ff;
+                       max *= mult;
+               }
+
+               if (urb->number_of_packets <= 0)                    
+                       return -EINVAL;
+               for (n = 0; n < urb->number_of_packets; n++) {
+                       len = urb->iso_frame_desc [n].length;
+                       if (len < 0 || len > max) 
+                               return -EMSGSIZE;
+                       urb->iso_frame_desc [n].status = -EXDEV;
+                       urb->iso_frame_desc [n].actual_length = 0;
+               }
+       }
+
+       /* the I/O buffer must be mapped/unmapped, except when length=0 */
+       if (urb->transfer_buffer_length < 0)
+               return -EMSGSIZE;
+
+#ifdef DEBUG
+       /* stuff that drivers shouldn't do, but which shouldn't
+        * cause problems in HCDs if they get it wrong.
+        */
+       {
+       unsigned int    orig_flags = urb->transfer_flags;
+       unsigned int    allowed;
+
+       /* enforce simple/standard policy */
+       allowed = URB_ASYNC_UNLINK;     // affects later unlinks
+       allowed |= URB_NO_DMA_MAP;
+       allowed |= URB_NO_INTERRUPT;
+       switch (temp) {
+       case PIPE_BULK:
+               if (is_out)
+                       allowed |= URB_ZERO_PACKET;
+               /* FALLTHROUGH */
+       case PIPE_CONTROL:
+               allowed |= URB_NO_FSBR; /* only affects UHCI */
+               /* FALLTHROUGH */
+       default:                        /* all non-iso endpoints */
+               if (!is_out)
+                       allowed |= URB_SHORT_NOT_OK;
+               break;
+       case PIPE_ISOCHRONOUS:
+               allowed |= URB_ISO_ASAP;
+               break;
+       }
+       urb->transfer_flags &= allowed;
+
+       /* fail if submitter gave bogus flags */
+       if (urb->transfer_flags != orig_flags) {
+               err ("BOGUS urb flags, %x --> %x",
+                       orig_flags, urb->transfer_flags);
+               return -EINVAL;
+       }
+       }
+#endif
+       /*
+        * Force periodic transfer intervals to be legal values that are
+        * a power of two (so HCDs don't need to).
+        *
+        * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC
+        * supports different values... this uses EHCI/UHCI defaults (and
+        * EHCI can use smaller non-default values).
+        */
+       switch (temp) {
+       case PIPE_ISOCHRONOUS:
+       case PIPE_INTERRUPT:
+               /* too small? */
+               if (urb->interval <= 0)
+                       return -EINVAL;
+               /* too big? */
+               switch (dev->speed) {
+               case USB_SPEED_HIGH:    /* units are microframes */
+                       // NOTE usb handles 2^15
+                       if (urb->interval > (1024 * 8))
+                               urb->interval = 1024 * 8;
+                       temp = 1024 * 8;
+                       break;
+               case USB_SPEED_FULL:    /* units are frames/msec */
+               case USB_SPEED_LOW:
+                       if (temp == PIPE_INTERRUPT) {
+                               if (urb->interval > 255)
+                                       return -EINVAL;
+                               // NOTE ohci only handles up to 32
+                               temp = 128;
+                       } else {
+                               if (urb->interval > 1024)
+                                       urb->interval = 1024;
+                               // NOTE usb and ohci handle up to 2^15
+                               temp = 1024;
+                       }
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               /* power of two? */
+               while (temp > urb->interval)
+                       temp >>= 1;
+               urb->interval = temp;
+       }
+
+       return op->submit_urb (urb, mem_flags);
+}
+
+/*-------------------------------------------------------------------*/
+
+/**
+ * usb_unlink_urb - abort/cancel a transfer request for an endpoint
+ * @urb: pointer to urb describing a previously submitted request
+ *
+ * This routine cancels an in-progress request.  The requests's
+ * completion handler will be called with a status code indicating
+ * that the request has been canceled, and that control of the URB
+ * has been returned to that device driver.
+ *
+ * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this
+ * request is synchronous.  Success is indicated by returning zero,
+ * at which time the urb will have been unlinked,
+ * and the completion function will see status -ENOENT.  Failure is
+ * indicated by any other return value.  This mode may not be used
+ * when unlinking an urb from an interrupt context, such as a bottom
+ * half or a completion handler,
+ *
+ * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
+ * request is asynchronous.  Success is indicated by returning -EINPROGRESS,
+ * at which time the urb will normally not have been unlinked,
+ * and the completion function will see status -ECONNRESET.  Failure is
+ * indicated by any other return value.
+ */
+int STDCALL usb_unlink_urb(struct urb *urb)
+{
+       if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
+               return urb->dev->bus->op->unlink_urb(urb);
+       else
+               return -ENODEV;
+}
index a2a3404..a6a6160 100644 (file)
-/*\r
- * debug.c - USB debug helper routines.\r
- *\r
- * I just want these out of the way where they aren't in your\r
- * face, but so that you can still use them..\r
- */\r
-#define CONFIG_USB_DEBUG\r
-#if 0\r
-#include <linux/config.h>\r
-#include <linux/kernel.h>\r
-#include <linux/mm.h>\r
-#include <linux/slab.h>\r
-#ifdef CONFIG_USB_DEBUG\r
-       #define DEBUG\r
-#else\r
-       #undef DEBUG\r
-#endif\r
-#include <linux/usb.h>\r
-#else\r
-#include "../usb_wrapper.h"\r
-#endif\r
-\r
-static void usb_show_endpoint(struct usb_host_endpoint *endpoint)\r
-{\r
-       usb_show_endpoint_descriptor(&endpoint->desc);\r
-}\r
-\r
-static void usb_show_interface(struct usb_host_interface *altsetting)\r
-{\r
-       int i;\r
-\r
-       usb_show_interface_descriptor(&altsetting->desc);\r
-\r
-       for (i = 0; i < altsetting->desc.bNumEndpoints; i++)\r
-               usb_show_endpoint(altsetting->endpoint + i);\r
-}\r
-\r
-static void usb_show_config(struct usb_host_config *config)\r
-{\r
-       int i, j;\r
-       struct usb_interface *ifp;\r
-\r
-       usb_show_config_descriptor(&config->desc);\r
-       for (i = 0; i < config->desc.bNumInterfaces; i++) {\r
-               ifp = config->interface + i;\r
-\r
-               if (!ifp)\r
-                       break;\r
-\r
-               printk("\n  Interface: %d\n", i);\r
-               for (j = 0; j < ifp->num_altsetting; j++)\r
-                       usb_show_interface(ifp->altsetting + j);\r
-       }\r
-}\r
-\r
-void usb_show_device(struct usb_device *dev)\r
-{\r
-       int i;\r
-\r
-       usb_show_device_descriptor(&dev->descriptor);\r
-       for (i = 0; i < dev->descriptor.bNumConfigurations; i++)\r
-               usb_show_config(dev->config + i);\r
-}\r
-\r
-/*\r
- * Parse and show the different USB descriptors.\r
- */\r
-void usb_show_device_descriptor(struct usb_device_descriptor *desc)\r
-{\r
-       if (!desc)\r
-       {\r
-               printk("Invalid USB device descriptor (NULL POINTER)\n");\r
-               return;\r
-       }\r
-       printk("  Length              = %2d%s\n", desc->bLength,\r
-               desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)");\r
-       printk("  DescriptorType      = %02x\n", desc->bDescriptorType);\r
-\r
-       printk("  USB version         = %x.%02x\n",\r
-               desc->bcdUSB >> 8, desc->bcdUSB & 0xff);\r
-       printk("  Vendor:Product      = %04x:%04x\n",\r
-               desc->idVendor, desc->idProduct);\r
-       printk("  MaxPacketSize0      = %d\n", desc->bMaxPacketSize0);\r
-       printk("  NumConfigurations   = %d\n", desc->bNumConfigurations);\r
-       printk("  Device version      = %x.%02x\n",\r
-               desc->bcdDevice >> 8, desc->bcdDevice & 0xff);\r
-\r
-       printk("  Device Class:SubClass:Protocol = %02x:%02x:%02x\n",\r
-               desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol);\r
-       switch (desc->bDeviceClass) {\r
-       case 0:\r
-               printk("    Per-interface classes\n");\r
-               break;\r
-       case USB_CLASS_AUDIO:\r
-               printk("    Audio device class\n");\r
-               break;\r
-       case USB_CLASS_COMM:\r
-               printk("    Communications class\n");\r
-               break;\r
-       case USB_CLASS_HID:\r
-               printk("    Human Interface Devices class\n");\r
-               break;\r
-       case USB_CLASS_PRINTER:\r
-               printk("    Printer device class\n");\r
-               break;\r
-       case USB_CLASS_MASS_STORAGE:\r
-               printk("    Mass Storage device class\n");\r
-               break;\r
-       case USB_CLASS_HUB:\r
-               printk("    Hub device class\n");\r
-               break;\r
-       case USB_CLASS_VENDOR_SPEC:\r
-               printk("    Vendor class\n");\r
-               break;\r
-       default:\r
-               printk("    Unknown class\n");\r
-       }\r
-}\r
-\r
-void usb_show_config_descriptor(struct usb_config_descriptor *desc)\r
-{\r
-       printk("Configuration:\n");\r
-       printk("  bLength             = %4d%s\n", desc->bLength,\r
-               desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)");\r
-       printk("  bDescriptorType     =   %02x\n", desc->bDescriptorType);\r
-       printk("  wTotalLength        = %04x\n", desc->wTotalLength);\r
-       printk("  bNumInterfaces      =   %02x\n", desc->bNumInterfaces);\r
-       printk("  bConfigurationValue =   %02x\n", desc->bConfigurationValue);\r
-       printk("  iConfiguration      =   %02x\n", desc->iConfiguration);\r
-       printk("  bmAttributes        =   %02x\n", desc->bmAttributes);\r
-       printk("  bMaxPower            = %4dmA\n", desc->bMaxPower * 2);\r
-}\r
-\r
-void usb_show_interface_descriptor(struct usb_interface_descriptor *desc)\r
-{\r
-       printk("  Alternate Setting: %2d\n", desc->bAlternateSetting);\r
-       printk("    bLength             = %4d%s\n", desc->bLength,\r
-               desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)");\r
-       printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);\r
-       printk("    bInterfaceNumber    =   %02x\n", desc->bInterfaceNumber);\r
-       printk("    bAlternateSetting   =   %02x\n", desc->bAlternateSetting);\r
-       printk("    bNumEndpoints       =   %02x\n", desc->bNumEndpoints);\r
-       printk("    bInterface Class:SubClass:Protocol =   %02x:%02x:%02x\n",\r
-               desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol);\r
-       printk("    iInterface          =   %02x\n", desc->iInterface);\r
-}\r
-\r
-void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)\r
-{\r
-       char *LengthCommentString = (desc->bLength ==\r
-               USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength ==\r
-               USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)";\r
-       char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };\r
-\r
-       printk("    Endpoint:\n");\r
-       printk("      bLength             = %4d%s\n",\r
-               desc->bLength, LengthCommentString);\r
-       printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);\r
-       printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,\r
-               (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==\r
-                       USB_ENDPOINT_XFER_CONTROL ? "i/o" :\r
-               (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? "in" : "out");\r
-       printk("      bmAttributes        =   %02x (%s)\n", desc->bmAttributes,\r
-               EndpointType[USB_ENDPOINT_XFERTYPE_MASK & desc->bmAttributes]);\r
-       printk("      wMaxPacketSize      = %04x\n", desc->wMaxPacketSize);\r
-       printk("      bInterval           =   %02x\n", desc->bInterval);\r
-\r
-       /* Audio extensions to the endpoint descriptor */\r
-       if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) {\r
-               printk("      bRefresh            =   %02x\n", desc->bRefresh);\r
-               printk("      bSynchAddress       =   %02x\n", desc->bSynchAddress);\r
-       }\r
-}\r
-\r
-void usb_show_string(struct usb_device *dev, char *id, int index)\r
-{\r
-       char *buf;\r
-\r
-       if (!index)\r
-               return;\r
-       if (!(buf = kmalloc(256, GFP_KERNEL)))\r
-               return;\r
-       if (usb_string(dev, index, buf, 256) > 0)\r
-               dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);\r
-       kfree(buf);\r
-}\r
-\r
-void usb_dump_urb (struct urb *urb)\r
-{\r
-       printk ("urb                   :%p\n", urb);\r
-       printk ("dev                   :%p\n", urb->dev);\r
-       printk ("pipe                  :%08X\n", urb->pipe);\r
-       printk ("status                :%d\n", urb->status);\r
-       printk ("transfer_flags        :%08X\n", urb->transfer_flags);\r
-       printk ("transfer_buffer       :%p\n", urb->transfer_buffer);\r
-       printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);\r
-       printk ("actual_length         :%d\n", urb->actual_length);\r
-       printk ("setup_packet          :%p\n", urb->setup_packet);\r
-       printk ("start_frame           :%d\n", urb->start_frame);\r
-       printk ("number_of_packets     :%d\n", urb->number_of_packets);\r
-       printk ("interval              :%d\n", urb->interval);\r
-       printk ("error_count           :%d\n", urb->error_count);\r
-       printk ("context               :%p\n", urb->context);\r
-       printk ("complete              :%p\n", urb->complete);\r
-}\r
-\r
+/*
+ * debug.c - USB debug helper routines.
+ *
+ * I just want these out of the way where they aren't in your
+ * face, but so that you can still use them..
+ */
+#define CONFIG_USB_DEBUG
+#if 0
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+#include <linux/usb.h>
+#else
+#include "../usb_wrapper.h"
+#endif
+
+static void usb_show_endpoint(struct usb_host_endpoint *endpoint)
+{
+       usb_show_endpoint_descriptor(&endpoint->desc);
+}
+
+static void usb_show_interface(struct usb_host_interface *altsetting)
+{
+       int i;
+
+       usb_show_interface_descriptor(&altsetting->desc);
+
+       for (i = 0; i < altsetting->desc.bNumEndpoints; i++)
+               usb_show_endpoint(altsetting->endpoint + i);
+}
+
+static void usb_show_config(struct usb_host_config *config)
+{
+       int i, j;
+       struct usb_interface *ifp;
+
+       usb_show_config_descriptor(&config->desc);
+       for (i = 0; i < config->desc.bNumInterfaces; i++) {
+               ifp = config->interface + i;
+
+               if (!ifp)
+                       break;
+
+               printk("\n  Interface: %d\n", i);
+               for (j = 0; j < ifp->num_altsetting; j++)
+                       usb_show_interface(ifp->altsetting + j);
+       }
+}
+
+void usb_show_device(struct usb_device *dev)
+{
+       int i;
+
+       usb_show_device_descriptor(&dev->descriptor);
+       for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+               usb_show_config(dev->config + i);
+}
+
+/*
+ * Parse and show the different USB descriptors.
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *desc)
+{
+       if (!desc)
+       {
+               printk("Invalid USB device descriptor (NULL POINTER)\n");
+               return;
+       }
+       printk("  Length              = %2d%s\n", desc->bLength,
+               desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)");
+       printk("  DescriptorType      = %02x\n", desc->bDescriptorType);
+
+       printk("  USB version         = %x.%02x\n",
+               desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
+       printk("  Vendor:Product      = %04x:%04x\n",
+               desc->idVendor, desc->idProduct);
+       printk("  MaxPacketSize0      = %d\n", desc->bMaxPacketSize0);
+       printk("  NumConfigurations   = %d\n", desc->bNumConfigurations);
+       printk("  Device version      = %x.%02x\n",
+               desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
+
+       printk("  Device Class:SubClass:Protocol = %02x:%02x:%02x\n",
+               desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol);
+       switch (desc->bDeviceClass) {
+       case 0:
+               printk("    Per-interface classes\n");
+               break;
+       case USB_CLASS_AUDIO:
+               printk("    Audio device class\n");
+               break;
+       case USB_CLASS_COMM:
+               printk("    Communications class\n");
+               break;
+       case USB_CLASS_HID:
+               printk("    Human Interface Devices class\n");
+               break;
+       case USB_CLASS_PRINTER:
+               printk("    Printer device class\n");
+               break;
+       case USB_CLASS_MASS_STORAGE:
+               printk("    Mass Storage device class\n");
+               break;
+       case USB_CLASS_HUB:
+               printk("    Hub device class\n");
+               break;
+       case USB_CLASS_VENDOR_SPEC:
+               printk("    Vendor class\n");
+               break;
+       default:
+               printk("    Unknown class\n");
+       }
+}
+
+void usb_show_config_descriptor(struct usb_config_descriptor *desc)
+{
+       printk("Configuration:\n");
+       printk("  bLength             = %4d%s\n", desc->bLength,
+               desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)");
+       printk("  bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("  wTotalLength        = %04x\n", desc->wTotalLength);
+       printk("  bNumInterfaces      =   %02x\n", desc->bNumInterfaces);
+       printk("  bConfigurationValue =   %02x\n", desc->bConfigurationValue);
+       printk("  iConfiguration      =   %02x\n", desc->iConfiguration);
+       printk("  bmAttributes        =   %02x\n", desc->bmAttributes);
+       printk("  bMaxPower            = %4dmA\n", desc->bMaxPower * 2);
+}
+
+void usb_show_interface_descriptor(struct usb_interface_descriptor *desc)
+{
+       printk("  Alternate Setting: %2d\n", desc->bAlternateSetting);
+       printk("    bLength             = %4d%s\n", desc->bLength,
+               desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)");
+       printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("    bInterfaceNumber    =   %02x\n", desc->bInterfaceNumber);
+       printk("    bAlternateSetting   =   %02x\n", desc->bAlternateSetting);
+       printk("    bNumEndpoints       =   %02x\n", desc->bNumEndpoints);
+       printk("    bInterface Class:SubClass:Protocol =   %02x:%02x:%02x\n",
+               desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol);
+       printk("    iInterface          =   %02x\n", desc->iInterface);
+}
+
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)
+{
+       char *LengthCommentString = (desc->bLength ==
+               USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength ==
+               USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)";
+       char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
+
+       printk("    Endpoint:\n");
+       printk("      bLength             = %4d%s\n",
+               desc->bLength, LengthCommentString);
+       printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,
+               (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                       USB_ENDPOINT_XFER_CONTROL ? "i/o" :
+               (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? "in" : "out");
+       printk("      bmAttributes        =   %02x (%s)\n", desc->bmAttributes,
+               EndpointType[USB_ENDPOINT_XFERTYPE_MASK & desc->bmAttributes]);
+       printk("      wMaxPacketSize      = %04x\n", desc->wMaxPacketSize);
+       printk("      bInterval           =   %02x\n", desc->bInterval);
+
+       /* Audio extensions to the endpoint descriptor */
+       if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) {
+               printk("      bRefresh            =   %02x\n", desc->bRefresh);
+               printk("      bSynchAddress       =   %02x\n", desc->bSynchAddress);
+       }
+}
+
+void usb_show_string(struct usb_device *dev, char *id, int index)
+{
+       char *buf;
+
+       if (!index)
+               return;
+       if (!(buf = kmalloc(256, GFP_KERNEL)))
+               return;
+       if (usb_string(dev, index, buf, 256) > 0)
+               dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
+       kfree(buf);
+}
+
+void usb_dump_urb (struct urb *urb)
+{
+       printk ("urb                   :%p\n", urb);
+       printk ("dev                   :%p\n", urb->dev);
+       printk ("pipe                  :%08X\n", urb->pipe);
+       printk ("status                :%d\n", urb->status);
+       printk ("transfer_flags        :%08X\n", urb->transfer_flags);
+       printk ("transfer_buffer       :%p\n", urb->transfer_buffer);
+       printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+       printk ("actual_length         :%d\n", urb->actual_length);
+       printk ("setup_packet          :%p\n", urb->setup_packet);
+       printk ("start_frame           :%d\n", urb->start_frame);
+       printk ("number_of_packets     :%d\n", urb->number_of_packets);
+       printk ("interval              :%d\n", urb->interval);
+       printk ("error_count           :%d\n", urb->error_count);
+       printk ("context               :%p\n", urb->context);
+       printk ("complete              :%p\n", urb->complete);
+}
+
index a772617..c4a2060 100644 (file)
-/*\r
- * drivers/usb/usb.c\r
- *\r
- * (C) Copyright Linus Torvalds 1999\r
- * (C) Copyright Johannes Erdfelt 1999-2001\r
- * (C) Copyright Andreas Gal 1999\r
- * (C) Copyright Gregory P. Smith 1999\r
- * (C) Copyright Deti Fliegl 1999 (new USB architecture)\r
- * (C) Copyright Randy Dunlap 2000\r
- * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,\r
-       more docs, etc)\r
- * (C) Copyright Yggdrasil Computing, Inc. 2000\r
- *     (usb_device_id matching changes by Adam J. Richter)\r
- * (C) Copyright Greg Kroah-Hartman 2002-2003\r
- *\r
- * NOTE! This is not actually a driver at all, rather this is\r
- * just a collection of helper routines that implement the\r
- * generic USB things that the real drivers can use..\r
- *\r
- * Think of this as a "USB library" rather than anything else.\r
- * It should be considered a slave, with no callbacks. Callbacks\r
- * are evil.\r
- */\r
-\r
-#if 0\r
-#include <linux/config.h>\r
-\r
-#ifdef CONFIG_USB_DEBUG\r
-       #define DEBUG\r
-#else\r
-       #undef DEBUG\r
-#endif\r
-\r
-#include <linux/module.h>\r
-#include <linux/string.h>\r
-#include <linux/bitops.h>\r
-#include <linux/slab.h>\r
-#include <linux/interrupt.h>  /* for in_interrupt() */\r
-#include <linux/kmod.h>\r
-#include <linux/init.h>\r
-#include <linux/spinlock.h>\r
-#include <linux/errno.h>\r
-#include <linux/smp_lock.h>\r
-#include <linux/usb.h>\r
-\r
-#include <asm/io.h>\r
-#include <asm/scatterlist.h>\r
-#include <linux/mm.h>\r
-#include <linux/dma-mapping.h>\r
-#include "hcd.h"\r
-#include "usb.h"\r
-#else\r
-#include "../usb_wrapper.h"\r
-#include "hcd.h"\r
-#endif\r
-\r
-\r
-extern int  usb_hub_init(void);\r
-extern void usb_hub_cleanup(void);\r
-extern int usb_major_init(void);\r
-extern void usb_major_cleanup(void);\r
-\r
-\r
-int nousb;             /* Disable USB when built into kernel image */\r
-                       /* Not honored on modular build */\r
-\r
-\r
-static int generic_probe (struct device *dev)\r
-{\r
-       return 0;\r
-}\r
-static int generic_remove (struct device *dev)\r
-{\r
-       return 0;\r
-}\r
-\r
-static struct device_driver usb_generic_driver = {\r
-       .name = "usb",\r
-       .bus = &usb_bus_type,\r
-       .probe = generic_probe,\r
-       .remove = generic_remove,\r
-};\r
-\r
-static int usb_generic_driver_data;\r
-\r
-/* needs to be called with BKL held */\r
-int usb_device_probe(struct device *dev)\r
-{\r
-       struct usb_interface * intf = to_usb_interface(dev);\r
-       struct usb_driver * driver = to_usb_driver(dev->driver);\r
-       const struct usb_device_id *id;\r
-       int error = -ENODEV;\r
-\r
-       dev_dbg(dev, "%s\n", __FUNCTION__);\r
-\r
-       if (!driver->probe)\r
-               return error;\r
-\r
-       id = usb_match_id (intf, driver->id_table);\r
-       if (id) {\r
-               dev_dbg (dev, "%s - got id\n", __FUNCTION__);\r
-               down (&driver->serialize);\r
-               error = driver->probe (intf, id);\r
-               up (&driver->serialize);\r
-       }\r
-       if (!error)\r
-               intf->driver = driver;\r
-\r
-       return error;\r
-}\r
-\r
-int usb_device_remove(struct device *dev)\r
-{\r
-       struct usb_interface *intf;\r
-       struct usb_driver *driver;\r
-\r
-       intf = list_entry(dev,struct usb_interface,dev);\r
-       driver = to_usb_driver(dev->driver);\r
-\r
-       down(&driver->serialize);\r
-\r
-       if (intf->driver && intf->driver->disconnect)\r
-               intf->driver->disconnect(intf);\r
-\r
-       /* if driver->disconnect didn't release the interface */\r
-       if (intf->driver)\r
-               usb_driver_release_interface(driver, intf);\r
-\r
-       up(&driver->serialize);\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * usb_register - register a USB driver\r
- * @new_driver: USB operations for the driver\r
- *\r
- * Registers a USB driver with the USB core.  The list of unattached\r
- * interfaces will be rescanned whenever a new driver is added, allowing\r
- * the new driver to attach to any recognized devices.\r
- * Returns a negative error code on failure and 0 on success.\r
- * \r
- * NOTE: if you want your driver to use the USB major number, you must call\r
- * usb_register_dev() to enable that functionality.  This function no longer\r
- * takes care of that.\r
- */\r
-int usb_register(struct usb_driver *new_driver)\r
-{\r
-       int retval = 0;\r
-\r
-       if (nousb)\r
-               return -ENODEV;\r
-\r
-       new_driver->driver.name = (char *)new_driver->name;\r
-       new_driver->driver.bus = &usb_bus_type;\r
-       new_driver->driver.probe = usb_device_probe;\r
-       new_driver->driver.remove = usb_device_remove;\r
-\r
-       init_MUTEX(&new_driver->serialize);\r
-\r
-       retval = driver_register(&new_driver->driver);\r
-\r
-       if (!retval) {\r
-               info("registered new driver %s", new_driver->name);\r
-               usbfs_update_special();\r
-       } else {\r
-               err("problem %d when registering driver %s",\r
-                       retval, new_driver->name);\r
-       }\r
-\r
-       return retval;\r
-}\r
-\r
-/**\r
- * usb_deregister - unregister a USB driver\r
- * @driver: USB operations of the driver to unregister\r
- * Context: !in_interrupt (), must be called with BKL held\r
- *\r
- * Unlinks the specified driver from the internal USB driver list.\r
- * \r
- * NOTE: If you called usb_register_dev(), you still need to call\r
- * usb_deregister_dev() to clean up your driver's allocated minor numbers,\r
- * this * call will no longer do it for you.\r
- */\r
-void usb_deregister(struct usb_driver *driver)\r
-{\r
-       info("deregistering driver %s", driver->name);\r
-\r
-       driver_unregister (&driver->driver);\r
-\r
-       usbfs_update_special();\r
-}\r
-\r
-/**\r
- * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)\r
- * @dev: the device whose current configuration is considered\r
- * @ifnum: the desired interface\r
- *\r
- * This walks the device descriptor for the currently active configuration\r
- * and returns a pointer to the interface with that particular interface\r
- * number, or null.\r
- *\r
- * Note that configuration descriptors are not required to assign interface\r
- * numbers sequentially, so that it would be incorrect to assume that\r
- * the first interface in that descriptor corresponds to interface zero.\r
- * This routine helps device drivers avoid such mistakes.\r
- * However, you should make sure that you do the right thing with any\r
- * alternate settings available for this interfaces.\r
- */\r
-struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)\r
-{\r
-       int i;\r
-\r
-       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)\r
-               if (dev->actconfig->interface[i].altsetting[0]\r
-                               .desc.bInterfaceNumber == ifnum)\r
-                       return &dev->actconfig->interface[i];\r
-\r
-       return NULL;\r
-}\r
-\r
-/**\r
- * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number\r
- * @dev: the device whose current configuration is considered\r
- * @epnum: the desired endpoint\r
- *\r
- * This walks the device descriptor for the currently active configuration,\r
- * and returns a pointer to the endpoint with that particular endpoint\r
- * number, or null.\r
- *\r
- * Note that interface descriptors are not required to assign endpont\r
- * numbers sequentially, so that it would be incorrect to assume that\r
- * the first endpoint in that descriptor corresponds to interface zero.\r
- * This routine helps device drivers avoid such mistakes.\r
- */\r
-struct usb_endpoint_descriptor *\r
-usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)\r
-{\r
-       int i, j, k;\r
-\r
-       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)\r
-               for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)\r
-                       for (k = 0; k < dev->actconfig->interface[i]\r
-                               .altsetting[j].desc.bNumEndpoints; k++)\r
-                               if (epnum == dev->actconfig->interface[i]\r
-                                               .altsetting[j].endpoint[k]\r
-                                               .desc.bEndpointAddress)\r
-                                       return &dev->actconfig->interface[i]\r
-                                               .altsetting[j].endpoint[k]\r
-                                               .desc;\r
-\r
-       return NULL;\r
-}\r
-\r
-/**\r
- * usb_driver_claim_interface - bind a driver to an interface\r
- * @driver: the driver to be bound\r
- * @iface: the interface to which it will be bound\r
- * @priv: driver data associated with that interface\r
- *\r
- * This is used by usb device drivers that need to claim more than one\r
- * interface on a device when probing (audio and acm are current examples).\r
- * No device driver should directly modify internal usb_interface or\r
- * usb_device structure members.\r
- *\r
- * Few drivers should need to use this routine, since the most natural\r
- * way to bind to an interface is to return the private data from\r
- * the driver's probe() method.  Any driver that does use this must\r
- * first be sure that no other driver has claimed the interface, by\r
- * checking with usb_interface_claimed().\r
- */\r
-void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)\r
-{\r
-       if (!iface || !driver)\r
-               return;\r
-\r
-       // FIXME change API to report an error in this case\r
-       if (iface->driver)\r
-           err ("%s driver booted %s off interface %p",\r
-               driver->name, iface->driver->name, iface);\r
-       else\r
-           dbg("%s driver claimed interface %p", driver->name, iface);\r
-\r
-       iface->driver = driver;\r
-       usb_set_intfdata(iface, priv);\r
-}\r
-\r
-/**\r
- * usb_interface_claimed - returns true iff an interface is claimed\r
- * @iface: the interface being checked\r
- *\r
- * This should be used by drivers to check other interfaces to see if\r
- * they are available or not.  If another driver has claimed the interface,\r
- * they may not claim it.  Otherwise it's OK to claim it using\r
- * usb_driver_claim_interface().\r
- *\r
- * Returns true (nonzero) iff the interface is claimed, else false (zero).\r
- */\r
-int usb_interface_claimed(struct usb_interface *iface)\r
-{\r
-       if (!iface)\r
-               return 0;\r
-\r
-       return (iface->driver != NULL);\r
-} /* usb_interface_claimed() */\r
-\r
-/**\r
- * usb_driver_release_interface - unbind a driver from an interface\r
- * @driver: the driver to be unbound\r
- * @iface: the interface from which it will be unbound\r
- * \r
- * This should be used by drivers to release their claimed interfaces.\r
- * It is normally called in their disconnect() methods, and only for\r
- * drivers that bound to more than one interface in their probe().\r
- *\r
- * When the USB subsystem disconnect()s a driver from some interface,\r
- * it automatically invokes this method for that interface.  That\r
- * means that even drivers that used usb_driver_claim_interface()\r
- * usually won't need to call this.\r
- */\r
-void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)\r
-{\r
-       /* this should never happen, don't release something that's not ours */\r
-       if (!iface || iface->driver != driver)\r
-               return;\r
-\r
-       iface->driver = NULL;\r
-       usb_set_intfdata(iface, NULL);\r
-}\r
-\r
-/**\r
- * usb_match_id - find first usb_device_id matching device or interface\r
- * @interface: the interface of interest\r
- * @id: array of usb_device_id structures, terminated by zero entry\r
- *\r
- * usb_match_id searches an array of usb_device_id's and returns\r
- * the first one matching the device or interface, or null.\r
- * This is used when binding (or rebinding) a driver to an interface.\r
- * Most USB device drivers will use this indirectly, through the usb core,\r
- * but some layered driver frameworks use it directly.\r
- * These device tables are exported with MODULE_DEVICE_TABLE, through\r
- * modutils and "modules.usbmap", to support the driver loading\r
- * functionality of USB hotplugging.\r
- *\r
- * What Matches:\r
- *\r
- * The "match_flags" element in a usb_device_id controls which\r
- * members are used.  If the corresponding bit is set, the\r
- * value in the device_id must match its corresponding member\r
- * in the device or interface descriptor, or else the device_id\r
- * does not match.\r
- *\r
- * "driver_info" is normally used only by device drivers,\r
- * but you can create a wildcard "matches anything" usb_device_id\r
- * as a driver's "modules.usbmap" entry if you provide an id with\r
- * only a nonzero "driver_info" field.  If you do this, the USB device\r
- * driver's probe() routine should use additional intelligence to\r
- * decide whether to bind to the specified interface.\r
- * \r
- * What Makes Good usb_device_id Tables:\r
- *\r
- * The match algorithm is very simple, so that intelligence in\r
- * driver selection must come from smart driver id records.\r
- * Unless you have good reasons to use another selection policy,\r
- * provide match elements only in related groups, and order match\r
- * specifiers from specific to general.  Use the macros provided\r
- * for that purpose if you can.\r
- *\r
- * The most specific match specifiers use device descriptor\r
- * data.  These are commonly used with product-specific matches;\r
- * the USB_DEVICE macro lets you provide vendor and product IDs,\r
- * and you can also match against ranges of product revisions.\r
- * These are widely used for devices with application or vendor\r
- * specific bDeviceClass values.\r
- *\r
- * Matches based on device class/subclass/protocol specifications\r
- * are slightly more general; use the USB_DEVICE_INFO macro, or\r
- * its siblings.  These are used with single-function devices\r
- * where bDeviceClass doesn't specify that each interface has\r
- * its own class. \r
- *\r
- * Matches based on interface class/subclass/protocol are the\r
- * most general; they let drivers bind to any interface on a\r
- * multiple-function device.  Use the USB_INTERFACE_INFO\r
- * macro, or its siblings, to match class-per-interface style \r
- * devices (as recorded in bDeviceClass).\r
- *  \r
- * Within those groups, remember that not all combinations are\r
- * meaningful.  For example, don't give a product version range\r
- * without vendor and product IDs; or specify a protocol without\r
- * its associated class and subclass.\r
- */   \r
-const struct usb_device_id *\r
-usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)\r
-{\r
-       struct usb_host_interface *intf;\r
-       struct usb_device *dev;\r
-\r
-       /* proc_connectinfo in devio.c may call us with id == NULL. */\r
-       if (id == NULL)\r
-               return NULL;\r
-\r
-       intf = &interface->altsetting [interface->act_altsetting];\r
-       dev = interface_to_usbdev(interface);\r
-\r
-       /* It is important to check that id->driver_info is nonzero,\r
-          since an entry that is all zeroes except for a nonzero\r
-          id->driver_info is the way to create an entry that\r
-          indicates that the driver want to examine every\r
-          device and interface. */\r
-       for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||\r
-              id->driver_info; id++) {\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&\r
-                   id->idVendor != dev->descriptor.idVendor)\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&\r
-                   id->idProduct != dev->descriptor.idProduct)\r
-                       continue;\r
-\r
-               /* No need to test id->bcdDevice_lo != 0, since 0 is never\r
-                  greater than any unsigned number. */\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&\r
-                   (id->bcdDevice_lo > dev->descriptor.bcdDevice))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&\r
-                   (id->bcdDevice_hi < dev->descriptor.bcdDevice))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&\r
-                   (id->bDeviceClass != dev->descriptor.bDeviceClass))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&\r
-                   (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&\r
-                   (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&\r
-                   (id->bInterfaceClass != intf->desc.bInterfaceClass))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&\r
-                   (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))\r
-                       continue;\r
-\r
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&\r
-                   (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))\r
-                       continue;\r
-\r
-               return id;\r
-       }\r
-\r
-       return NULL;\r
-}\r
-\r
-/**\r
- * usb_find_interface - find usb_interface pointer for driver and device\r
- * @drv: the driver whose current configuration is considered\r
- * @minor: the minor number of the desired device\r
- *\r
- * This walks the driver device list and returns a pointer to the interface \r
- * with the matching minor.  Note, this only works for devices that share the\r
- * USB major number.\r
- */\r
-struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)\r
-{\r
-       struct list_head *entry;\r
-       struct device *dev;\r
-       struct usb_interface *intf;\r
-\r
-       list_for_each(entry, &drv->driver.devices) {\r
-               dev = container_of(entry, struct device, driver_list);\r
-\r
-               /* can't look at usb devices, only interfaces */\r
-               if (dev->driver == &usb_generic_driver)\r
-                       continue;\r
-\r
-               intf = to_usb_interface(dev);\r
-               if (intf->minor == -1)\r
-                       continue;\r
-               if (intf->minor == minor)\r
-                       return intf;\r
-       }\r
-\r
-       /* no device found that matches */\r
-       return NULL;    \r
-}\r
-\r
-static int usb_device_match (struct device *dev, struct device_driver *drv)\r
-{\r
-       struct usb_interface *intf;\r
-       struct usb_driver *usb_drv;\r
-       const struct usb_device_id *id;\r
-\r
-       /* check for generic driver, which we don't match any device with */\r
-       if (drv == &usb_generic_driver)\r
-               return 0;\r
-\r
-       intf = to_usb_interface(dev);\r
-\r
-       usb_drv = to_usb_driver(drv);\r
-       id = usb_drv->id_table;\r
-       \r
-       id = usb_match_id (intf, usb_drv->id_table);\r
-       if (id)\r
-               return 1;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-#ifdef CONFIG_HOTPLUG\r
-\r
-/*\r
- * USB hotplugging invokes what /proc/sys/kernel/hotplug says\r
- * (normally /sbin/hotplug) when USB devices get added or removed.\r
- *\r
- * This invokes a user mode policy agent, typically helping to load driver\r
- * or other modules, configure the device, and more.  Drivers can provide\r
- * a MODULE_DEVICE_TABLE to help with module loading subtasks.\r
- *\r
- * We're called either from khubd (the typical case) or from root hub\r
- * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle\r
- * delays in event delivery.  Use sysfs (and DEVPATH) to make sure the\r
- * device (and this configuration!) are still present.\r
- */\r
-static int usb_hotplug (struct device *dev, char **envp, int num_envp,\r
-                       char *buffer, int buffer_size)\r
-{\r
-       struct usb_interface *intf;\r
-       struct usb_device *usb_dev;\r
-       char *scratch;\r
-       int i = 0;\r
-       int length = 0;\r
-\r
-       dbg ("%s", __FUNCTION__);\r
-\r
-       if (!dev)\r
-               return -ENODEV;\r
-\r
-       /* Must check driver_data here, as on remove driver is always NULL */\r
-       if ((dev->driver == &usb_generic_driver) || \r
-           (dev->driver_data == &usb_generic_driver_data))\r
-               return 0;\r
-\r
-       intf = to_usb_interface(dev);\r
-       usb_dev = interface_to_usbdev (intf);\r
-       \r
-       if (usb_dev->devnum < 0) {\r
-               dbg ("device already deleted ??");\r
-               return -ENODEV;\r
-       }\r
-       if (!usb_dev->bus) {\r
-               dbg ("bus already removed?");\r
-               return -ENODEV;\r
-       }\r
-\r
-       scratch = buffer;\r
-\r
-#ifdef CONFIG_USB_DEVICEFS\r
-       /* If this is available, userspace programs can directly read\r
-        * all the device descriptors we don't tell them about.  Or\r
-        * even act as usermode drivers.\r
-        *\r
-        * FIXME reduce hardwired intelligence here\r
-        */\r
-       envp [i++] = scratch;\r
-       length += snprintf (scratch, buffer_size - length,\r
-                           "DEVICE=/proc/bus/usb/%03d/%03d",\r
-                           usb_dev->bus->busnum, usb_dev->devnum);\r
-       if ((buffer_size - length <= 0) || (i >= num_envp))\r
-               return -ENOMEM;\r
-       ++length;\r
-       scratch += length;\r
-#endif\r
-\r
-       /* per-device configurations are common */\r
-       envp [i++] = scratch;\r
-       length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",\r
-                           usb_dev->descriptor.idVendor,\r
-                           usb_dev->descriptor.idProduct,\r
-                           usb_dev->descriptor.bcdDevice);\r
-       if ((buffer_size - length <= 0) || (i >= num_envp))\r
-               return -ENOMEM;\r
-       ++length;\r
-       scratch += length;\r
-\r
-       /* class-based driver binding models */\r
-       envp [i++] = scratch;\r
-       length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",\r
-                           usb_dev->descriptor.bDeviceClass,\r
-                           usb_dev->descriptor.bDeviceSubClass,\r
-                           usb_dev->descriptor.bDeviceProtocol);\r
-       if ((buffer_size - length <= 0) || (i >= num_envp))\r
-               return -ENOMEM;\r
-       ++length;\r
-       scratch += length;\r
-\r
-       if (usb_dev->descriptor.bDeviceClass == 0) {\r
-               int alt = intf->act_altsetting;\r
-\r
-               /* 2.4 only exposed interface zero.  in 2.5, hotplug\r
-                * agents are called for all interfaces, and can use\r
-                * $DEVPATH/bInterfaceNumber if necessary.\r
-                */\r
-               envp [i++] = scratch;\r
-               length += snprintf (scratch, buffer_size - length,\r
-                           "INTERFACE=%d/%d/%d",\r
-                           intf->altsetting[alt].desc.bInterfaceClass,\r
-                           intf->altsetting[alt].desc.bInterfaceSubClass,\r
-                           intf->altsetting[alt].desc.bInterfaceProtocol);\r
-               if ((buffer_size - length <= 0) || (i >= num_envp))\r
-                       return -ENOMEM;\r
-               ++length;\r
-               scratch += length;\r
-\r
-       }\r
-       envp [i++] = 0;\r
-\r
-       return 0;\r
-}\r
-\r
-#else\r
-\r
-static int usb_hotplug (struct device *dev, char **envp,\r
-                       int num_envp, char *buffer, int buffer_size)\r
-{\r
-       return -ENODEV;\r
-}\r
-\r
-#endif /* CONFIG_HOTPLUG */\r
-\r
-/**\r
- * usb_alloc_dev - allocate a usb device structure (usbcore-internal)\r
- * @parent: hub to which device is connected\r
- * @bus: bus used to access the device\r
- * Context: !in_interrupt ()\r
- *\r
- * Only hub drivers (including virtual root hub drivers for host\r
- * controllers) should ever call this.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- */\r
-struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)\r
-{\r
-       struct usb_device *dev;\r
-\r
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);\r
-       if (!dev)\r
-               return NULL;\r
-\r
-       memset(dev, 0, sizeof(*dev));\r
-\r
-       device_initialize(&dev->dev);\r
-       dev->state = USB_STATE_ATTACHED;\r
-\r
-       usb_bus_get(bus);\r
-\r
-       if (!parent)\r
-               dev->devpath [0] = '0';\r
-       dev->bus = bus;\r
-       dev->parent = parent;\r
-       INIT_LIST_HEAD(&dev->filelist);\r
-\r
-       init_MUTEX(&dev->serialize);\r
-\r
-       if (dev->bus->op->allocate)\r
-               dev->bus->op->allocate(dev);\r
-\r
-       return dev;\r
-}\r
-\r
-/**\r
- * usb_get_dev - increments the reference count of the usb device structure\r
- * @dev: the device being referenced\r
- *\r
- * Each live reference to a device should be refcounted.\r
- *\r
- * Drivers for USB interfaces should normally record such references in\r
- * their probe() methods, when they bind to an interface, and release\r
- * them by calling usb_put_dev(), in their disconnect() methods.\r
- *\r
- * A pointer to the device with the incremented reference counter is returned.\r
- */\r
-struct usb_device STDCALL *usb_get_dev (struct usb_device *dev)\r
-{\r
-       struct device *tmp;\r
-\r
-       if (!dev)\r
-               return NULL;\r
-\r
-       tmp = get_device(&dev->dev);\r
-       if (tmp)        \r
-               return to_usb_device(tmp);\r
-       else\r
-               return NULL;\r
-}\r
-\r
-/**\r
- * usb_put_dev - release a use of the usb device structure\r
- * @dev: device that's been disconnected\r
- *\r
- * Must be called when a user of a device is finished with it.  When the last\r
- * user of the device calls this function, the memory of the device is freed.\r
- */\r
-void STDCALL usb_put_dev(struct usb_device *dev)\r
-{\r
-       if (dev)\r
-               put_device(&dev->dev);\r
-}\r
-\r
-/**\r
- * usb_release_dev - free a usb device structure when all users of it are finished.\r
- * @dev: device that's been disconnected\r
- *\r
- * Will be called only by the device core when all users of this usb device are\r
- * done.\r
- */\r
-static void usb_release_dev(struct device *dev)\r
-{\r
-       struct usb_device *udev;\r
-\r
-       udev = to_usb_device(dev);\r
-\r
-       if (udev->bus && udev->bus->op && udev->bus->op->deallocate)\r
-               udev->bus->op->deallocate(udev);\r
-       usb_destroy_configuration (udev);\r
-       usb_bus_put (udev->bus);\r
-       kfree (udev);\r
-}\r
-\r
-\r
-static struct usb_device *match_device(struct usb_device *dev,\r
-                                      u16 vendor_id, u16 product_id)\r
-{\r
-       struct usb_device *ret_dev = NULL;\r
-       int child;\r
-\r
-       dbg("looking at vendor %d, product %d",\r
-           dev->descriptor.idVendor,\r
-           dev->descriptor.idProduct);\r
-\r
-       /* see if this device matches */\r
-       if ((dev->descriptor.idVendor == vendor_id) &&\r
-           (dev->descriptor.idProduct == product_id)) {\r
-               dbg ("found the device!");\r
-               ret_dev = usb_get_dev(dev);\r
-               goto exit;\r
-       }\r
-\r
-       /* look through all of the children of this device */\r
-       for (child = 0; child < dev->maxchild; ++child) {\r
-               if (dev->children[child]) {\r
-                       ret_dev = match_device(dev->children[child],\r
-                                              vendor_id, product_id);\r
-                       if (ret_dev)\r
-                               goto exit;\r
-               }\r
-       }\r
-exit:\r
-       return ret_dev;\r
-}\r
-\r
-/**\r
- * usb_find_device - find a specific usb device in the system\r
- * @vendor_id: the vendor id of the device to find\r
- * @product_id: the product id of the device to find\r
- *\r
- * Returns a pointer to a struct usb_device if such a specified usb\r
- * device is present in the system currently.  The usage count of the\r
- * device will be incremented if a device is found.  Make sure to call\r
- * usb_put_dev() when the caller is finished with the device.\r
- *\r
- * If a device with the specified vendor and product id is not found,\r
- * NULL is returned.\r
- */\r
-struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)\r
-{\r
-       struct list_head *buslist;\r
-       struct usb_bus *bus;\r
-       struct usb_device *dev = NULL;\r
-       \r
-       down(&usb_bus_list_lock);\r
-       for (buslist = usb_bus_list.next;\r
-            buslist != &usb_bus_list; \r
-            buslist = buslist->next) {\r
-               bus = container_of(buslist, struct usb_bus, bus_list);\r
-               dev = match_device(bus->root_hub, vendor_id, product_id);\r
-               if (dev)\r
-                       goto exit;\r
-       }\r
-exit:\r
-       up(&usb_bus_list_lock);\r
-       return dev;\r
-}\r
-\r
-/**\r
- * usb_get_current_frame_number - return current bus frame number\r
- * @dev: the device whose bus is being queried\r
- *\r
- * Returns the current frame number for the USB host controller\r
- * used with the given USB device.  This can be used when scheduling\r
- * isochronous requests.\r
- *\r
- * Note that different kinds of host controller have different\r
- * "scheduling horizons".  While one type might support scheduling only\r
- * 32 frames into the future, others could support scheduling up to\r
- * 1024 frames into the future.\r
- */\r
-int usb_get_current_frame_number(struct usb_device *dev)\r
-{\r
-       return dev->bus->op->get_frame_number (dev);\r
-}\r
-\r
-/*-------------------------------------------------------------------*/\r
-/*\r
- * __usb_get_extra_descriptor() finds a descriptor of specific type in the\r
- * extra field of the interface and endpoint descriptor structs.\r
- */\r
-\r
-int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)\r
-{\r
-       struct usb_descriptor_header *header;\r
-\r
-       while (size >= sizeof(struct usb_descriptor_header)) {\r
-               header = (struct usb_descriptor_header *)buffer;\r
-\r
-               if (header->bLength < 2) {\r
-                       err("invalid descriptor length of %d", header->bLength);\r
-                       return -1;\r
-               }\r
-\r
-               if (header->bDescriptorType == type) {\r
-                       *ptr = header;\r
-                       return 0;\r
-               }\r
-\r
-               buffer += header->bLength;\r
-               size -= header->bLength;\r
-       }\r
-       return -1;\r
-}\r
-\r
-/**\r
- * usb_disconnect - disconnect a device (usbcore-internal)\r
- * @pdev: pointer to device being disconnected\r
- * Context: !in_interrupt ()\r
- *\r
- * Something got disconnected. Get rid of it, and all of its children.\r
- *\r
- * Only hub drivers (including virtual root hub drivers for host\r
- * controllers) should ever call this.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- */\r
-void usb_disconnect(struct usb_device **pdev)\r
-{\r
-       struct usb_device       *dev = *pdev;\r
-       struct usb_bus          *bus;\r
-       struct usb_operations   *ops;\r
-       int                     i;\r
-\r
-       might_sleep ();\r
-\r
-       if (!dev) {\r
-               pr_debug ("%s nodev\n", __FUNCTION__);\r
-               return;\r
-       }\r
-       bus = dev->bus;\r
-       if (!bus) {\r
-               pr_debug ("%s nobus\n", __FUNCTION__);\r
-               return;\r
-       }\r
-       ops = bus->op;\r
-\r
-       *pdev = NULL;\r
-\r
-       /* mark the device as inactive, so any further urb submissions for\r
-        * this device will fail.\r
-        */\r
-       dev->state = USB_STATE_NOTATTACHED;\r
-\r
-       dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);\r
-\r
-       /* Free up all the children before we remove this device */\r
-       for (i = 0; i < USB_MAXCHILDREN; i++) {\r
-               struct usb_device **child = dev->children + i;\r
-               if (*child)\r
-                       usb_disconnect(child);\r
-       }\r
-\r
-       /* disconnect() drivers from interfaces (a key side effect) */\r
-       dev_dbg (&dev->dev, "unregistering interfaces\n");\r
-       if (dev->actconfig) {\r
-               for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {\r
-                       struct usb_interface    *interface;\r
-\r
-                       /* remove this interface */\r
-                       interface = &dev->actconfig->interface[i];\r
-                       device_unregister(&interface->dev);\r
-               }\r
-       }\r
-\r
-       /* deallocate hcd/hardware state */\r
-       if (ops->disable) {\r
-               void    (*disable)(struct usb_device *, int) = ops->disable;\r
-\r
-               for (i = 0; i < 15; i++) {\r
-                       disable (dev, i);\r
-                       disable (dev, USB_DIR_IN | i);\r
-               }\r
-       }\r
-\r
-       dev_dbg (&dev->dev, "unregistering device\n");\r
-       /* Free the device number and remove the /proc/bus/usb entry */\r
-       if (dev->devnum > 0) {\r
-               clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-               usbfs_remove_device(dev);\r
-       }\r
-       device_unregister(&dev->dev);\r
-\r
-       /* Decrement the reference count, it'll auto free everything when */\r
-       /* it hits 0 which could very well be now */\r
-       usb_put_dev(dev);\r
-}\r
-\r
-/**\r
- * usb_connect - pick device address (usbcore-internal)\r
- * @dev: newly detected device (in DEFAULT state)\r
- *\r
- * Picks a device address.  It's up to the hub (or root hub) driver\r
- * to handle and manage enumeration, starting from the DEFAULT state.\r
- * Only hub drivers (including virtual root hub drivers for host\r
- * controllers) should ever call this.\r
- */\r
-void STDCALL usb_connect(struct usb_device *dev)\r
-{\r
-       int devnum;\r
-       // FIXME needs locking for SMP!!\r
-       /* why? this is called only from the hub thread, \r
-        * which hopefully doesn't run on multiple CPU's simultaneously 8-)\r
-        * ... it's also called from modprobe/rmmod/apmd threads as part\r
-        * of virtual root hub init/reinit.  In the init case, the hub code \r
-        * won't have seen this, but not so for reinit ... \r
-        */\r
-       dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */\r
-\r
-       /* Try to allocate the next devnum beginning at bus->devnum_next. */\r
-       devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);\r
-       if (devnum >= 128)\r
-               devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);\r
-\r
-       dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);\r
-\r
-       if (devnum < 128) {\r
-               set_bit(devnum, dev->bus->devmap.devicemap);\r
-               dev->devnum = devnum;\r
-       }\r
-}\r
-\r
-\r
-// hub-only!! ... and only exported for reset/reinit path.\r
-// otherwise used internally, for usb_new_device()\r
-int usb_set_address(struct usb_device *dev)\r
-{\r
-       int retval;\r
-\r
-       if (dev->devnum == 0)\r
-               return -EINVAL;\r
-       if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)\r
-               return -EINVAL;\r
-       retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,\r
-               0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);\r
-       if (retval == 0)\r
-               dev->state = USB_STATE_ADDRESS;\r
-       return retval;\r
-}\r
-\r
-\r
-/* improve on the default device description, if we can ... and\r
- * while we're at it, maybe show the vendor and product strings.\r
- */\r
-static void set_device_description (struct usb_device *dev)\r
-{\r
-       void    *buf;\r
-       int     mfgr = dev->descriptor.iManufacturer;\r
-       int     prod = dev->descriptor.iProduct;\r
-       int     vendor_id = dev->descriptor.idVendor;\r
-       int     product_id = dev->descriptor.idProduct;\r
-       char    *mfgr_str, *prod_str;\r
-\r
-       /* set default; keep it if there are no strings, or kmalloc fails */\r
-       sprintf (dev->dev.name, "USB device %04x:%04x",\r
-                vendor_id, product_id);\r
-\r
-       if (!(buf = kmalloc(256 * 2, GFP_KERNEL)))\r
-               return;\r
-       \r
-       prod_str = (char *) buf;\r
-       mfgr_str = (char *) buf + 256;\r
-\r
-       if (prod && usb_string (dev, prod, prod_str, 256) > 0) {\r
-#ifdef DEBUG\r
-               dev_printk (KERN_INFO, &dev->dev, "Product: %s\n", prod_str);\r
-#endif\r
-       } else {\r
-               prod_str = 0;\r
-       }\r
-\r
-       if (mfgr && usb_string (dev, mfgr, mfgr_str, 256) > 0) {\r
-#ifdef DEBUG\r
-               dev_printk (KERN_INFO, &dev->dev, "Manufacturer: %s\n", mfgr_str);\r
-#endif\r
-       } else {\r
-               mfgr_str = 0;\r
-       }\r
-\r
-       /* much like pci ... describe as either:\r
-        * - both strings:   'product descr (vendor descr)'\r
-        * - product only:   'product descr (USB device vvvv:pppp)'\r
-        * - vendor only:    'USB device vvvv:pppp (vendor descr)'\r
-        * - neither string: 'USB device vvvv:pppp'\r
-        */\r
-\r
-       if (prod_str && mfgr_str) {\r
-\r
-               snprintf(dev->dev.name, sizeof dev->dev.name,\r
-                        "%s (%s)", prod_str, mfgr_str);\r
-       } else if (prod_str) {\r
-               snprintf(dev->dev.name, sizeof dev->dev.name,\r
-                        "%s (USB device %04x:%04x)",\r
-                        prod_str, vendor_id, product_id);\r
-\r
-       } else if (mfgr_str) {\r
-               snprintf(dev->dev.name, sizeof dev->dev.name,\r
-                        "USB device %04x:%04x (%s)",\r
-                        vendor_id, product_id, mfgr_str);\r
-       }\r
-       usbprintk("USB connected: %s\n",dev->dev.name);\r
-       kfree(buf);\r
-}\r
-\r
-/*\r
- * By the time we get here, we chose a new device address\r
- * and is in the default state. We need to identify the thing and\r
- * get the ball rolling..\r
- *\r
- * Returns 0 for success, != 0 for error.\r
- *\r
- * This call is synchronous, and may not be used in an interrupt context.\r
- *\r
- * Only hub drivers (including virtual root hub drivers for host\r
- * controllers) should ever call this.\r
- */\r
-#define NEW_DEVICE_RETRYS      2\r
-#define SET_ADDRESS_RETRYS     2\r
-int usb_new_device(struct usb_device *dev, struct device *parent)\r
-{\r
-       int err = 0;\r
-       int i;\r
-       int j;\r
-\r
-       /*\r
-        * Set the driver for the usb device to point to the "generic" driver.\r
-        * This prevents the main usb device from being sent to the usb bus\r
-        * probe function.  Yes, it's a hack, but a nice one :)\r
-        *\r
-        * Do it asap, so more driver model stuff (like the device.h message\r
-        * utilities) can be used in hcd submit/unlink code paths.\r
-        */\r
-       usb_generic_driver.bus = &usb_bus_type;\r
-       dev->dev.parent = parent;\r
-       dev->dev.driver = &usb_generic_driver;\r
-       dev->dev.bus = &usb_bus_type;\r
-       dev->dev.release = usb_release_dev;\r
-       dev->dev.driver_data = &usb_generic_driver_data;\r
-       usb_get_dev(dev);\r
-       if (dev->dev.bus_id[0] == 0)\r
-               sprintf (&dev->dev.bus_id[0], "%d-%s",\r
-                        dev->bus->busnum, dev->devpath);\r
-\r
-       /* dma masks come from the controller; readonly, except to hcd */\r
-       dev->dev.dma_mask = parent->dma_mask;\r
-\r
-       /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...\r
-        * it's fixed size except for full speed devices.\r
-        */\r
-       switch (dev->speed) {\r
-       case USB_SPEED_HIGH:            /* fixed at 64 */\r
-               i = 64;\r
-               break;\r
-       case USB_SPEED_FULL:            /* 8, 16, 32, or 64 */\r
-               /* to determine the ep0 maxpacket size, read the first 8\r
-                * bytes from the device descriptor to get bMaxPacketSize0;\r
-                * then correct our initial (small) guess.\r
-                */\r
-               // FALLTHROUGH\r
-       case USB_SPEED_LOW:             /* fixed at 8 */\r
-               i = 8;\r
-               break;\r
-       default:\r
-               return -EINVAL;\r
-       }\r
-       dev->epmaxpacketin [0] = i;\r
-       dev->epmaxpacketout[0] = i;\r
-\r
-       for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {\r
-\r
-               for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {\r
-                       err = usb_set_address(dev);\r
-                       if (err >= 0)\r
-                               break;\r
-                       wait_ms(200);\r
-               }\r
-               if (err < 0) {\r
-                       dev_err(&dev->dev, "USB device not accepting new address=%d (error=%d)\n",\r
-                               dev->devnum, err);\r
-                       dev->state = USB_STATE_DEFAULT;\r
-                       clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-                       dev->devnum = -1;\r
-                       return 1;\r
-               }\r
-\r
-               wait_ms(10);    /* Let the SET_ADDRESS settle */\r
-\r
-               /* high and low speed devices don't need this... */\r
-               err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);\r
-               if (err >= 8)\r
-                       break;\r
-               wait_ms(100);\r
-       }\r
-\r
-       if (err < 8) {\r
-               if (err < 0)\r
-                       dev_err(&dev->dev, "USB device not responding, giving up (error=%d)\n", err);\r
-               else\r
-                       dev_err(&dev->dev, "USB device descriptor short read (expected %i, got %i)\n", 8, err);\r
-               clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-               dev->devnum = -1;\r
-               return 1;\r
-       }\r
-       if (dev->speed == USB_SPEED_FULL) {\r
-               dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;\r
-               dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;\r
-       }\r
-\r
-       /* USB device state == addressed ... still not usable */\r
-\r
-       err = usb_get_device_descriptor(dev);\r
-       if (err < (signed)sizeof(dev->descriptor)) {\r
-               if (err < 0)\r
-                       dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n", err);\r
-               else\r
-                       dev_err(&dev->dev, "USB device descriptor short read (expected %Zi, got %i)\n",\r
-                               sizeof(dev->descriptor), err);\r
-       \r
-               clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-               dev->devnum = -1;\r
-               return 1;\r
-       }\r
-\r
-       err = usb_get_configuration(dev);\r
-       if (err < 0) {\r
-               dev_err(&dev->dev, "unable to get device %d configuration (error=%d)\n",\r
-                       dev->devnum, err);\r
-               clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-               dev->devnum = -1;\r
-               return 1;\r
-       }\r
-\r
-       /* we set the default configuration here */\r
-       err = usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue);\r
-       if (err) {\r
-               dev_err(&dev->dev, "failed to set device %d default configuration (error=%d)\n",\r
-                       dev->devnum, err);\r
-               clear_bit(dev->devnum, dev->bus->devmap.devicemap);\r
-               dev->devnum = -1;\r
-               return 1;\r
-       }\r
-\r
-       /* USB device state == configured ... tell the world! */\r
-\r
-       dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",\r
-               dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);\r
-       set_device_description (dev);\r
-\r
-#ifdef DEBUG\r
-       if (dev->descriptor.iSerialNumber)\r
-               usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);\r
-#endif\r
-       /* put into sysfs, with device and config specific files */\r
-       err = device_add (&dev->dev);\r
-       if (err)\r
-               return err;\r
-       usb_create_driverfs_dev_files (dev);\r
-\r
-       /* Register all of the interfaces for this device with the driver core.\r
-        * Remember, interfaces get bound to drivers, not devices. */\r
-       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {\r
-               struct usb_interface *interface = &dev->actconfig->interface[i];\r
-               struct usb_interface_descriptor *desc;\r
-\r
-               desc = &interface->altsetting [interface->act_altsetting].desc;\r
-               interface->dev.parent = &dev->dev;\r
-               interface->dev.driver = NULL;\r
-               interface->dev.bus = &usb_bus_type;\r
-               interface->dev.dma_mask = parent->dma_mask;\r
-               sprintf (&interface->dev.bus_id[0], "%d-%s:%d",\r
-                        dev->bus->busnum, dev->devpath,\r
-                        desc->bInterfaceNumber);\r
-               if (!desc->iInterface\r
-                               || usb_string (dev, desc->iInterface,\r
-                                       interface->dev.name,\r
-                                       sizeof interface->dev.name) <= 0) {\r
-                       /* typically devices won't bother with interface\r
-                        * descriptions; this is the normal case.  an\r
-                        * interface's driver might describe it better.\r
-                        * (also: iInterface is per-altsetting ...)\r
-                        */\r
-                       sprintf (&interface->dev.name[0],\r
-                               "usb-%s-%s interface %d",\r
-                               dev->bus->bus_name, dev->devpath,\r
-                               desc->bInterfaceNumber);\r
-                       DPRINT1("usb_new_device: %s\n", interface->dev.name);\r
-               }\r
-               dev_dbg (&dev->dev, "%s - registering interface %s\n", __FUNCTION__, interface->dev.bus_id);\r
-               device_add (&interface->dev);\r
-               usb_create_driverfs_intf_files (interface);\r
-       }\r
-       /* add a /proc/bus/usb entry */\r
-       usbfs_add_device(dev);\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP\r
- * @dev: device the buffer will be used with\r
- * @size: requested buffer size\r
- * @mem_flags: affect whether allocation may block\r
- * @dma: used to return DMA address of buffer\r
- *\r
- * Return value is either null (indicating no buffer could be allocated), or\r
- * the cpu-space pointer to a buffer that may be used to perform DMA to the\r
- * specified device.  Such cpu-space buffers are returned along with the DMA\r
- * address (through the pointer provided).\r
- *\r
- * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to\r
- * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping\r
- * hardware for long idle periods.  The implementation varies between\r
- * platforms, depending on details of how DMA will work to this device.\r
- * Using these buffers also helps prevent cacheline sharing problems on\r
- * architectures where CPU caches are not DMA-coherent.\r
- *\r
- * When the buffer is no longer used, free it with usb_buffer_free().\r
- */\r
-void *usb_buffer_alloc (\r
-       struct usb_device *dev,\r
-       size_t size,\r
-       int mem_flags,\r
-       dma_addr_t *dma\r
-)\r
-{\r
-       if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)\r
-               return 0;\r
-       return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);\r
-}\r
-\r
-/**\r
- * usb_buffer_free - free memory allocated with usb_buffer_alloc()\r
- * @dev: device the buffer was used with\r
- * @size: requested buffer size\r
- * @addr: CPU address of buffer\r
- * @dma: DMA address of buffer\r
- *\r
- * This reclaims an I/O buffer, letting it be reused.  The memory must have\r
- * been allocated using usb_buffer_alloc(), and the parameters must match\r
- * those provided in that allocation request. \r
- */\r
-void usb_buffer_free (\r
-       struct usb_device *dev,\r
-       size_t size,\r
-       void *addr,\r
-       dma_addr_t dma\r
-)\r
-{\r
-       if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)\r
-               return;\r
-       dev->bus->op->buffer_free (dev->bus, size, addr, dma);\r
-}\r
-\r
-/**\r
- * usb_buffer_map - create DMA mapping(s) for an urb\r
- * @urb: urb whose transfer_buffer will be mapped\r
- *\r
- * Return value is either null (indicating no buffer could be mapped), or\r
- * the parameter.  URB_NO_DMA_MAP is added to urb->transfer_flags if the\r
- * operation succeeds.  If the device is connected to this system through\r
- * a non-DMA controller, this operation always succeeds.\r
- *\r
- * This call would normally be used for an urb which is reused, perhaps\r
- * as the target of a large periodic transfer, with usb_buffer_dmasync()\r
- * calls to synchronize memory and dma state.  It may not be used for\r
- * control requests.\r
- *\r
- * Reverse the effect of this call with usb_buffer_unmap().\r
- */\r
-struct urb *usb_buffer_map (struct urb *urb)\r
-{\r
-       struct usb_bus          *bus;\r
-       struct device           *controller;\r
-\r
-       if (!urb\r
-                       || usb_pipecontrol (urb->pipe)\r
-                       || !urb->dev\r
-                       || !(bus = urb->dev->bus)\r
-                       || !(controller = bus->controller))\r
-               return 0;\r
-\r
-       if (controller->dma_mask) {\r
-               urb->transfer_dma = dma_map_single (controller,\r
-                       urb->transfer_buffer, urb->transfer_buffer_length,\r
-                       usb_pipein (urb->pipe)\r
-                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);\r
-       // FIXME generic api broken like pci, can't report errors\r
-       // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;\r
-       } else\r
-               urb->transfer_dma = ~0;\r
-       urb->transfer_flags |= URB_NO_DMA_MAP;\r
-       return urb;\r
-}\r
-\r
-/**\r
- * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)\r
- * @urb: urb whose transfer_buffer will be synchronized\r
- */\r
-void usb_buffer_dmasync (struct urb *urb)\r
-{\r
-       struct usb_bus          *bus;\r
-       struct device           *controller;\r
-\r
-       if (!urb\r
-                       || !(urb->transfer_flags & URB_NO_DMA_MAP)\r
-                       || !urb->dev\r
-                       || !(bus = urb->dev->bus)\r
-                       || !(controller = bus->controller))\r
-               return;\r
-\r
-       if (controller->dma_mask)\r
-               dma_sync_single (controller,\r
-                       urb->transfer_dma, urb->transfer_buffer_length,\r
-                       usb_pipein (urb->pipe)\r
-                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);\r
-}\r
-\r
-/**\r
- * usb_buffer_unmap - free DMA mapping(s) for an urb\r
- * @urb: urb whose transfer_buffer will be unmapped\r
- *\r
- * Reverses the effect of usb_buffer_map().\r
- */\r
-void usb_buffer_unmap (struct urb *urb)\r
-{\r
-       struct usb_bus          *bus;\r
-       struct device           *controller;\r
-\r
-       if (!urb\r
-                       || !(urb->transfer_flags & URB_NO_DMA_MAP)\r
-                       || !urb->dev\r
-                       || !(bus = urb->dev->bus)\r
-                       || !(controller = bus->controller))\r
-               return;\r
-\r
-       if (controller->dma_mask)\r
-               dma_unmap_single (controller,\r
-                       urb->transfer_dma, urb->transfer_buffer_length,\r
-                       usb_pipein (urb->pipe)\r
-                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);\r
-       urb->transfer_flags &= ~URB_NO_DMA_MAP;\r
-}\r
-\r
-/**\r
- * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint\r
- * @dev: device to which the scatterlist will be mapped\r
- * @pipe: endpoint defining the mapping direction\r
- * @sg: the scatterlist to map\r
- * @nents: the number of entries in the scatterlist\r
- *\r
- * Return value is either < 0 (indicating no buffers could be mapped), or\r
- * the number of DMA mapping array entries in the scatterlist.\r
- *\r
- * The caller is responsible for placing the resulting DMA addresses from\r
- * the scatterlist into URB transfer buffer pointers, and for setting the\r
- * URB_NO_DMA_MAP transfer flag in each of those URBs.\r
- *\r
- * Top I/O rates come from queuing URBs, instead of waiting for each one\r
- * to complete before starting the next I/O.   This is particularly easy\r
- * to do with scatterlists.  Just allocate and submit one URB for each DMA\r
- * mapping entry returned, stopping on the first error or when all succeed.\r
- * Better yet, use the usb_sg_*() calls, which do that (and more) for you.\r
- *\r
- * This call would normally be used when translating scatterlist requests,\r
- * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it\r
- * may be able to coalesce mappings for improved I/O efficiency.\r
- *\r
- * Reverse the effect of this call with usb_buffer_unmap_sg().\r
- */\r
-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,\r
-               struct scatterlist *sg, int nents)\r
-{\r
-       struct usb_bus          *bus;\r
-       struct device           *controller;\r
-\r
-       if (!dev\r
-                       || usb_pipecontrol (pipe)\r
-                       || !(bus = dev->bus)\r
-                       || !(controller = bus->controller)\r
-                       || !controller->dma_mask)\r
-               return -1;\r
-\r
-       // FIXME generic api broken like pci, can't report errors\r
-       return dma_map_sg (controller, sg, nents,\r
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);\r
-}\r
-\r
-/**\r
- * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)\r
- * @dev: device to which the scatterlist will be mapped\r
- * @pipe: endpoint defining the mapping direction\r
- * @sg: the scatterlist to synchronize\r
- * @n_hw_ents: the positive return value from usb_buffer_map_sg\r
- *\r
- * Use this when you are re-using a scatterlist's data buffers for\r
- * another USB request.\r
- */\r
-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,\r
-               struct scatterlist *sg, int n_hw_ents)\r
-{\r
-       struct usb_bus          *bus;\r
-       struct device           *controller;\r
-\r
-       if (!dev\r
-                       || !(bus = dev->bus)\r
-                       || !(controller = bus->controller)\r
-                       || !controller->dma_mask)\r
-               return;\r
-\r
-       dma_sync_sg (controller, sg, n_hw_ents,\r
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);\r
-}\r
-\r
-/**\r
- * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist\r
- * @dev: device to which the scatterlist will be mapped\r
- * @pipe: endpoint defining the mapping direction\r
- * @sg: the scatterlist to unmap\r
- * @n_hw_ents: the positive return value from usb_buffer_map_sg\r
- *\r
- * Reverses the effect of usb_buffer_map_sg().\r
- */\r
-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,\r
-               struct scatterlist *sg, int n_hw_ents)\r
-{\r
-       struct usb_bus          *bus;\r
-       struct device           *controller;\r
-\r
-       if (!dev\r
-                       || !(bus = dev->bus)\r
-                       || !(controller = bus->controller)\r
-                       || !controller->dma_mask)\r
-               return;\r
-\r
-       dma_unmap_sg (controller, sg, n_hw_ents,\r
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);\r
-}\r
-\r
-\r
-struct bus_type usb_bus_type = {\r
-       .name =         "usb",\r
-       .match =        usb_device_match,\r
-       .hotplug =      usb_hotplug,\r
-};\r
-\r
-#ifndef MODULE\r
-\r
-static int __init usb_setup_disable(char *str)\r
-{\r
-       nousb = 1;\r
-       return 1;\r
-}\r
-\r
-/* format to disable USB on kernel command line is: nousb */\r
-__setup("nousb", usb_setup_disable);\r
-\r
-#endif\r
-\r
-/*\r
- * for external read access to <nousb>\r
- */\r
-int STDCALL usb_disabled(void)\r
-{\r
-       return nousb;\r
-}\r
-\r
-/*\r
- * Init\r
- */\r
-int STDCALL __init usb_init(void)\r
-{\r
-       if (nousb) {\r
-               info("USB support disabled\n");\r
-               return 0;\r
-       }\r
-\r
-       bus_register(&usb_bus_type);\r
-       usb_major_init();\r
-       usbfs_init();\r
-       usb_hub_init();\r
-\r
-       driver_register(&usb_generic_driver);\r
-\r
-       return 0;\r
-}\r
-\r
-/*\r
- * Cleanup\r
- */\r
-void STDCALL __exit usb_exit(void)\r
-{\r
-       /* This will matter if shutdown/reboot does exitcalls. */\r
-       if (nousb)\r
-               return;\r
-\r
-       driver_unregister(&usb_generic_driver);\r
-       usb_major_cleanup();\r
-       usbfs_cleanup();\r
-       usb_hub_cleanup();\r
-       bus_unregister(&usb_bus_type);\r
-}\r
-\r
-subsys_initcall(usb_init);\r
-module_exit(usb_exit);\r
-\r
-/*\r
- * USB may be built into the kernel or be built as modules.\r
- * These symbols are exported for device (or host controller)\r
- * driver modules to use.\r
- */\r
-EXPORT_SYMBOL(usb_epnum_to_ep_desc);\r
-\r
-EXPORT_SYMBOL(usb_register);\r
-EXPORT_SYMBOL(usb_deregister);\r
-EXPORT_SYMBOL(usb_disabled);\r
-\r
-EXPORT_SYMBOL(usb_device_probe);\r
-EXPORT_SYMBOL(usb_device_remove);\r
-\r
-EXPORT_SYMBOL(usb_alloc_dev);\r
-EXPORT_SYMBOL(usb_put_dev);\r
-EXPORT_SYMBOL(usb_get_dev);\r
-EXPORT_SYMBOL(usb_hub_tt_clear_buffer);\r
-\r
-EXPORT_SYMBOL(usb_driver_claim_interface);\r
-EXPORT_SYMBOL(usb_interface_claimed);\r
-EXPORT_SYMBOL(usb_driver_release_interface);\r
-EXPORT_SYMBOL(usb_match_id);\r
-EXPORT_SYMBOL(usb_find_interface);\r
-EXPORT_SYMBOL(usb_ifnum_to_if);\r
-\r
-EXPORT_SYMBOL(usb_new_device);\r
-EXPORT_SYMBOL(usb_reset_device);\r
-EXPORT_SYMBOL(usb_connect);\r
-EXPORT_SYMBOL(usb_disconnect);\r
-\r
-EXPORT_SYMBOL(__usb_get_extra_descriptor);\r
-\r
-EXPORT_SYMBOL(usb_find_device);\r
-EXPORT_SYMBOL(usb_get_current_frame_number);\r
-\r
-EXPORT_SYMBOL (usb_buffer_alloc);\r
-EXPORT_SYMBOL (usb_buffer_free);\r
-\r
-EXPORT_SYMBOL (usb_buffer_map);\r
-EXPORT_SYMBOL (usb_buffer_dmasync);\r
-EXPORT_SYMBOL (usb_buffer_unmap);\r
-\r
-EXPORT_SYMBOL (usb_buffer_map_sg);\r
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);\r
-EXPORT_SYMBOL (usb_buffer_unmap_sg);\r
-\r
-MODULE_LICENSE("GPL");\r
+/*
+ * drivers/usb/usb.c
+ *
+ * (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-2001 (kernel hotplug, usb_device_id,
+       more docs, etc)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ *     (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ * NOTE! This is not actually a driver at all, rather this is
+ * just a collection of helper routines that implement the
+ * generic USB things that the real drivers can use..
+ *
+ * Think of this as a "USB library" rather than anything else.
+ * It should be considered a slave, with no callbacks. Callbacks
+ * are evil.
+ */
+
+#if 0
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>  /* for in_interrupt() */
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include "hcd.h"
+#include "usb.h"
+#else
+#include "../usb_wrapper.h"
+#include "hcd.h"
+#endif
+
+
+extern int  usb_hub_init(void);
+extern void usb_hub_cleanup(void);
+extern int usb_major_init(void);
+extern void usb_major_cleanup(void);
+
+
+int nousb;             /* Disable USB when built into kernel image */
+                       /* Not honored on modular build */
+
+
+static int generic_probe (struct device *dev)
+{
+       return 0;
+}
+static int generic_remove (struct device *dev)
+{
+       return 0;
+}
+
+static struct device_driver usb_generic_driver = {
+       .name = "usb",
+       .bus = &usb_bus_type,
+       .probe = generic_probe,
+       .remove = generic_remove,
+};
+
+static int usb_generic_driver_data;
+
+/* needs to be called with BKL held */
+int usb_device_probe(struct device *dev)
+{
+       struct usb_interface * intf = to_usb_interface(dev);
+       struct usb_driver * driver = to_usb_driver(dev->driver);
+       const struct usb_device_id *id;
+       int error = -ENODEV;
+
+       dev_dbg(dev, "%s\n", __FUNCTION__);
+
+       if (!driver->probe)
+               return error;
+
+       id = usb_match_id (intf, driver->id_table);
+       if (id) {
+               dev_dbg (dev, "%s - got id\n", __FUNCTION__);
+               down (&driver->serialize);
+               error = driver->probe (intf, id);
+               up (&driver->serialize);
+       }
+       if (!error)
+               intf->driver = driver;
+
+       return error;
+}
+
+int usb_device_remove(struct device *dev)
+{
+       struct usb_interface *intf;
+       struct usb_driver *driver;
+
+       intf = list_entry(dev,struct usb_interface,dev);
+       driver = to_usb_driver(dev->driver);
+
+       down(&driver->serialize);
+
+       if (intf->driver && intf->driver->disconnect)
+               intf->driver->disconnect(intf);
+
+       /* if driver->disconnect didn't release the interface */
+       if (intf->driver)
+               usb_driver_release_interface(driver, intf);
+
+       up(&driver->serialize);
+
+       return 0;
+}
+
+/**
+ * usb_register - register a USB driver
+ * @new_driver: USB operations for the driver
+ *
+ * Registers a USB driver with the USB core.  The list of unattached
+ * interfaces will be rescanned whenever a new driver is added, allowing
+ * the new driver to attach to any recognized devices.
+ * Returns a negative error code on failure and 0 on success.
+ * 
+ * NOTE: if you want your driver to use the USB major number, you must call
+ * usb_register_dev() to enable that functionality.  This function no longer
+ * takes care of that.
+ */
+int usb_register(struct usb_driver *new_driver)
+{
+       int retval = 0;
+
+       if (nousb)
+               return -ENODEV;
+
+       new_driver->driver.name = (char *)new_driver->name;
+       new_driver->driver.bus = &usb_bus_type;
+       new_driver->driver.probe = usb_device_probe;
+       new_driver->driver.remove = usb_device_remove;
+
+       init_MUTEX(&new_driver->serialize);
+
+       retval = driver_register(&new_driver->driver);
+
+       if (!retval) {
+               info("registered new driver %s", new_driver->name);
+               usbfs_update_special();
+       } else {
+               err("problem %d when registering driver %s",
+                       retval, new_driver->name);
+       }
+
+       return retval;
+}
+
+/**
+ * usb_deregister - unregister a USB driver
+ * @driver: USB operations of the driver to unregister
+ * Context: !in_interrupt (), must be called with BKL held
+ *
+ * Unlinks the specified driver from the internal USB driver list.
+ * 
+ * NOTE: If you called usb_register_dev(), you still need to call
+ * usb_deregister_dev() to clean up your driver's allocated minor numbers,
+ * this * call will no longer do it for you.
+ */
+void usb_deregister(struct usb_driver *driver)
+{
+       info("deregistering driver %s", driver->name);
+
+       driver_unregister (&driver->driver);
+
+       usbfs_update_special();
+}
+
+/**
+ * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)
+ * @dev: the device whose current configuration is considered
+ * @ifnum: the desired interface
+ *
+ * This walks the device descriptor for the currently active configuration
+ * and returns a pointer to the interface with that particular interface
+ * number, or null.
+ *
+ * Note that configuration descriptors are not required to assign interface
+ * numbers sequentially, so that it would be incorrect to assume that
+ * the first interface in that descriptor corresponds to interface zero.
+ * This routine helps device drivers avoid such mistakes.
+ * However, you should make sure that you do the right thing with any
+ * alternate settings available for this interfaces.
+ */
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
+{
+       int i;
+
+       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
+               if (dev->actconfig->interface[i].altsetting[0]
+                               .desc.bInterfaceNumber == ifnum)
+                       return &dev->actconfig->interface[i];
+
+       return NULL;
+}
+
+/**
+ * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
+ * @dev: the device whose current configuration is considered
+ * @epnum: the desired endpoint
+ *
+ * This walks the device descriptor for the currently active configuration,
+ * and returns a pointer to the endpoint with that particular endpoint
+ * number, or null.
+ *
+ * Note that interface descriptors are not required to assign endpont
+ * numbers sequentially, so that it would be incorrect to assume that
+ * the first endpoint in that descriptor corresponds to interface zero.
+ * This routine helps device drivers avoid such mistakes.
+ */
+struct usb_endpoint_descriptor *
+usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
+{
+       int i, j, k;
+
+       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
+               for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
+                       for (k = 0; k < dev->actconfig->interface[i]
+                               .altsetting[j].desc.bNumEndpoints; k++)
+                               if (epnum == dev->actconfig->interface[i]
+                                               .altsetting[j].endpoint[k]
+                                               .desc.bEndpointAddress)
+                                       return &dev->actconfig->interface[i]
+                                               .altsetting[j].endpoint[k]
+                                               .desc;
+
+       return NULL;
+}
+
+/**
+ * usb_driver_claim_interface - bind a driver to an interface
+ * @driver: the driver to be bound
+ * @iface: the interface to which it will be bound
+ * @priv: driver data associated with that interface
+ *
+ * This is used by usb device drivers that need to claim more than one
+ * interface on a device when probing (audio and acm are current examples).
+ * No device driver should directly modify internal usb_interface or
+ * usb_device structure members.
+ *
+ * Few drivers should need to use this routine, since the most natural
+ * way to bind to an interface is to return the private data from
+ * the driver's probe() method.  Any driver that does use this must
+ * first be sure that no other driver has claimed the interface, by
+ * checking with usb_interface_claimed().
+ */
+void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
+{
+       if (!iface || !driver)
+               return;
+
+       // FIXME change API to report an error in this case
+       if (iface->driver)
+           err ("%s driver booted %s off interface %p",
+               driver->name, iface->driver->name, iface);
+       else
+           dbg("%s driver claimed interface %p", driver->name, iface);
+
+       iface->driver = driver;
+       usb_set_intfdata(iface, priv);
+}
+
+/**
+ * usb_interface_claimed - returns true iff an interface is claimed
+ * @iface: the interface being checked
+ *
+ * This should be used by drivers to check other interfaces to see if
+ * they are available or not.  If another driver has claimed the interface,
+ * they may not claim it.  Otherwise it's OK to claim it using
+ * usb_driver_claim_interface().
+ *
+ * Returns true (nonzero) iff the interface is claimed, else false (zero).
+ */
+int usb_interface_claimed(struct usb_interface *iface)
+{
+       if (!iface)
+               return 0;
+
+       return (iface->driver != NULL);
+} /* usb_interface_claimed() */
+
+/**
+ * usb_driver_release_interface - unbind a driver from an interface
+ * @driver: the driver to be unbound
+ * @iface: the interface from which it will be unbound
+ * 
+ * This should be used by drivers to release their claimed interfaces.
+ * It is normally called in their disconnect() methods, and only for
+ * drivers that bound to more than one interface in their probe().
+ *
+ * When the USB subsystem disconnect()s a driver from some interface,
+ * it automatically invokes this method for that interface.  That
+ * means that even drivers that used usb_driver_claim_interface()
+ * usually won't need to call this.
+ */
+void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
+{
+       /* this should never happen, don't release something that's not ours */
+       if (!iface || iface->driver != driver)
+               return;
+
+       iface->driver = NULL;
+       usb_set_intfdata(iface, NULL);
+}
+
+/**
+ * usb_match_id - find first usb_device_id matching device or interface
+ * @interface: the interface of interest
+ * @id: array of usb_device_id structures, terminated by zero entry
+ *
+ * usb_match_id searches an array of usb_device_id's and returns
+ * the first one matching the device or interface, or null.
+ * This is used when binding (or rebinding) a driver to an interface.
+ * Most USB device drivers will use this indirectly, through the usb core,
+ * but some layered driver frameworks use it directly.
+ * These device tables are exported with MODULE_DEVICE_TABLE, through
+ * modutils and "modules.usbmap", to support the driver loading
+ * functionality of USB hotplugging.
+ *
+ * What Matches:
+ *
+ * The "match_flags" element in a usb_device_id controls which
+ * members are used.  If the corresponding bit is set, the
+ * value in the device_id must match its corresponding member
+ * in the device or interface descriptor, or else the device_id
+ * does not match.
+ *
+ * "driver_info" is normally used only by device drivers,
+ * but you can create a wildcard "matches anything" usb_device_id
+ * as a driver's "modules.usbmap" entry if you provide an id with
+ * only a nonzero "driver_info" field.  If you do this, the USB device
+ * driver's probe() routine should use additional intelligence to
+ * decide whether to bind to the specified interface.
+ * 
+ * What Makes Good usb_device_id Tables:
+ *
+ * The match algorithm is very simple, so that intelligence in
+ * driver selection must come from smart driver id records.
+ * Unless you have good reasons to use another selection policy,
+ * provide match elements only in related groups, and order match
+ * specifiers from specific to general.  Use the macros provided
+ * for that purpose if you can.
+ *
+ * The most specific match specifiers use device descriptor
+ * data.  These are commonly used with product-specific matches;
+ * the USB_DEVICE macro lets you provide vendor and product IDs,
+ * and you can also match against ranges of product revisions.
+ * These are widely used for devices with application or vendor
+ * specific bDeviceClass values.
+ *
+ * Matches based on device class/subclass/protocol specifications
+ * are slightly more general; use the USB_DEVICE_INFO macro, or
+ * its siblings.  These are used with single-function devices
+ * where bDeviceClass doesn't specify that each interface has
+ * its own class. 
+ *
+ * Matches based on interface class/subclass/protocol are the
+ * most general; they let drivers bind to any interface on a
+ * multiple-function device.  Use the USB_INTERFACE_INFO
+ * macro, or its siblings, to match class-per-interface style 
+ * devices (as recorded in bDeviceClass).
+ *  
+ * Within those groups, remember that not all combinations are
+ * meaningful.  For example, don't give a product version range
+ * without vendor and product IDs; or specify a protocol without
+ * its associated class and subclass.
+ */   
+const struct usb_device_id *
+usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       struct usb_host_interface *intf;
+       struct usb_device *dev;
+
+       /* proc_connectinfo in devio.c may call us with id == NULL. */
+       if (id == NULL)
+               return NULL;
+
+       intf = &interface->altsetting [interface->act_altsetting];
+       dev = interface_to_usbdev(interface);
+
+       /* It is important to check that id->driver_info is nonzero,
+          since an entry that is all zeroes except for a nonzero
+          id->driver_info is the way to create an entry that
+          indicates that the driver want to examine every
+          device and interface. */
+       for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+              id->driver_info; id++) {
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+                   id->idVendor != dev->descriptor.idVendor)
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+                   id->idProduct != dev->descriptor.idProduct)
+                       continue;
+
+               /* No need to test id->bcdDevice_lo != 0, since 0 is never
+                  greater than any unsigned number. */
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+                   (id->bcdDevice_lo > dev->descriptor.bcdDevice))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+                   (id->bcdDevice_hi < dev->descriptor.bcdDevice))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+                   (id->bDeviceClass != dev->descriptor.bDeviceClass))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+                   (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+                   (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+                   (id->bInterfaceClass != intf->desc.bInterfaceClass))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+                   (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+                   (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
+                       continue;
+
+               return id;
+       }
+
+       return NULL;
+}
+
+/**
+ * usb_find_interface - find usb_interface pointer for driver and device
+ * @drv: the driver whose current configuration is considered
+ * @minor: the minor number of the desired device
+ *
+ * This walks the driver device list and returns a pointer to the interface 
+ * with the matching minor.  Note, this only works for devices that share the
+ * USB major number.
+ */
+struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
+{
+       struct list_head *entry;
+       struct device *dev;
+       struct usb_interface *intf;
+
+       list_for_each(entry, &drv->driver.devices) {
+               dev = container_of(entry, struct device, driver_list);
+
+               /* can't look at usb devices, only interfaces */
+               if (dev->driver == &usb_generic_driver)
+                       continue;
+
+               intf = to_usb_interface(dev);
+               if (intf->minor == -1)
+                       continue;
+               if (intf->minor == minor)
+                       return intf;
+       }
+
+       /* no device found that matches */
+       return NULL;    
+}
+
+static int usb_device_match (struct device *dev, struct device_driver *drv)
+{
+       struct usb_interface *intf;
+       struct usb_driver *usb_drv;
+       const struct usb_device_id *id;
+
+       /* check for generic driver, which we don't match any device with */
+       if (drv == &usb_generic_driver)
+               return 0;
+
+       intf = to_usb_interface(dev);
+
+       usb_drv = to_usb_driver(drv);
+       id = usb_drv->id_table;
+       
+       id = usb_match_id (intf, usb_drv->id_table);
+       if (id)
+               return 1;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_HOTPLUG
+
+/*
+ * USB hotplugging invokes what /proc/sys/kernel/hotplug says
+ * (normally /sbin/hotplug) when USB devices get added or removed.
+ *
+ * This invokes a user mode policy agent, typically helping to load driver
+ * or other modules, configure the device, and more.  Drivers can provide
+ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
+ *
+ * We're called either from khubd (the typical case) or from root hub
+ * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
+ * delays in event delivery.  Use sysfs (and DEVPATH) to make sure the
+ * device (and this configuration!) are still present.
+ */
+static int usb_hotplug (struct device *dev, char **envp, int num_envp,
+                       char *buffer, int buffer_size)
+{
+       struct usb_interface *intf;
+       struct usb_device *usb_dev;
+       char *scratch;
+       int i = 0;
+       int length = 0;
+
+       dbg ("%s", __FUNCTION__);
+
+       if (!dev)
+               return -ENODEV;
+
+       /* Must check driver_data here, as on remove driver is always NULL */
+       if ((dev->driver == &usb_generic_driver) || 
+           (dev->driver_data == &usb_generic_driver_data))
+               return 0;
+
+       intf = to_usb_interface(dev);
+       usb_dev = interface_to_usbdev (intf);
+       
+       if (usb_dev->devnum < 0) {
+               dbg ("device already deleted ??");
+               return -ENODEV;
+       }
+       if (!usb_dev->bus) {
+               dbg ("bus already removed?");
+               return -ENODEV;
+       }
+
+       scratch = buffer;
+
+#ifdef CONFIG_USB_DEVICEFS
+       /* If this is available, userspace programs can directly read
+        * all the device descriptors we don't tell them about.  Or
+        * even act as usermode drivers.
+        *
+        * FIXME reduce hardwired intelligence here
+        */
+       envp [i++] = scratch;
+       length += snprintf (scratch, buffer_size - length,
+                           "DEVICE=/proc/bus/usb/%03d/%03d",
+                           usb_dev->bus->busnum, usb_dev->devnum);
+       if ((buffer_size - length <= 0) || (i >= num_envp))
+               return -ENOMEM;
+       ++length;
+       scratch += length;
+#endif
+
+       /* per-device configurations are common */
+       envp [i++] = scratch;
+       length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
+                           usb_dev->descriptor.idVendor,
+                           usb_dev->descriptor.idProduct,
+                           usb_dev->descriptor.bcdDevice);
+       if ((buffer_size - length <= 0) || (i >= num_envp))
+               return -ENOMEM;
+       ++length;
+       scratch += length;
+
+       /* class-based driver binding models */
+       envp [i++] = scratch;
+       length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
+                           usb_dev->descriptor.bDeviceClass,
+                           usb_dev->descriptor.bDeviceSubClass,
+                           usb_dev->descriptor.bDeviceProtocol);
+       if ((buffer_size - length <= 0) || (i >= num_envp))
+               return -ENOMEM;
+       ++length;
+       scratch += length;
+
+       if (usb_dev->descriptor.bDeviceClass == 0) {
+               int alt = intf->act_altsetting;
+
+               /* 2.4 only exposed interface zero.  in 2.5, hotplug
+                * agents are called for all interfaces, and can use
+                * $DEVPATH/bInterfaceNumber if necessary.
+                */
+               envp [i++] = scratch;
+               length += snprintf (scratch, buffer_size - length,
+                           "INTERFACE=%d/%d/%d",
+                           intf->altsetting[alt].desc.bInterfaceClass,
+                           intf->altsetting[alt].desc.bInterfaceSubClass,
+                           intf->altsetting[alt].desc.bInterfaceProtocol);
+               if ((buffer_size - length <= 0) || (i >= num_envp))
+                       return -ENOMEM;
+               ++length;
+               scratch += length;
+
+       }
+       envp [i++] = 0;
+
+       return 0;
+}
+
+#else
+
+static int usb_hotplug (struct device *dev, char **envp,
+                       int num_envp, char *buffer, int buffer_size)
+{
+       return -ENODEV;
+}
+
+#endif /* CONFIG_HOTPLUG */
+
+/**
+ * usb_alloc_dev - allocate a usb device structure (usbcore-internal)
+ * @parent: hub to which device is connected
+ * @bus: bus used to access the device
+ * Context: !in_interrupt ()
+ *
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ */
+struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
+{
+       struct usb_device *dev;
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       memset(dev, 0, sizeof(*dev));
+
+       device_initialize(&dev->dev);
+       dev->state = USB_STATE_ATTACHED;
+
+       usb_bus_get(bus);
+
+       if (!parent)
+               dev->devpath [0] = '0';
+       dev->bus = bus;
+       dev->parent = parent;
+       INIT_LIST_HEAD(&dev->filelist);
+
+       init_MUTEX(&dev->serialize);
+
+       if (dev->bus->op->allocate)
+               dev->bus->op->allocate(dev);
+
+       return dev;
+}
+
+/**
+ * usb_get_dev - increments the reference count of the usb device structure
+ * @dev: the device being referenced
+ *
+ * Each live reference to a device should be refcounted.
+ *
+ * Drivers for USB interfaces should normally record such references in
+ * their probe() methods, when they bind to an interface, and release
+ * them by calling usb_put_dev(), in their disconnect() methods.
+ *
+ * A pointer to the device with the incremented reference counter is returned.
+ */
+struct usb_device STDCALL *usb_get_dev (struct usb_device *dev)
+{
+       struct device *tmp;
+
+       if (!dev)
+               return NULL;
+
+       tmp = get_device(&dev->dev);
+       if (tmp)        
+               return to_usb_device(tmp);
+       else
+               return NULL;
+}
+
+/**
+ * usb_put_dev - release a use of the usb device structure
+ * @dev: device that's been disconnected
+ *
+ * Must be called when a user of a device is finished with it.  When the last
+ * user of the device calls this function, the memory of the device is freed.
+ */
+void STDCALL usb_put_dev(struct usb_device *dev)
+{
+       if (dev)
+               put_device(&dev->dev);
+}
+
+/**
+ * usb_release_dev - free a usb device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this usb device are
+ * done.
+ */
+static void usb_release_dev(struct device *dev)
+{
+       struct usb_device *udev;
+
+       udev = to_usb_device(dev);
+
+       if (udev->bus && udev->bus->op && udev->bus->op->deallocate)
+               udev->bus->op->deallocate(udev);
+       usb_destroy_configuration (udev);
+       usb_bus_put (udev->bus);
+       kfree (udev);
+}
+
+
+static struct usb_device *match_device(struct usb_device *dev,
+                                      u16 vendor_id, u16 product_id)
+{
+       struct usb_device *ret_dev = NULL;
+       int child;
+
+       dbg("looking at vendor %d, product %d",
+           dev->descriptor.idVendor,
+           dev->descriptor.idProduct);
+
+       /* see if this device matches */
+       if ((dev->descriptor.idVendor == vendor_id) &&
+           (dev->descriptor.idProduct == product_id)) {
+               dbg ("found the device!");
+               ret_dev = usb_get_dev(dev);
+               goto exit;
+       }
+
+       /* look through all of the children of this device */
+       for (child = 0; child < dev->maxchild; ++child) {
+               if (dev->children[child]) {
+                       ret_dev = match_device(dev->children[child],
+                                              vendor_id, product_id);
+                       if (ret_dev)
+                               goto exit;
+               }
+       }
+exit:
+       return ret_dev;
+}
+
+/**
+ * usb_find_device - find a specific usb device in the system
+ * @vendor_id: the vendor id of the device to find
+ * @product_id: the product id of the device to find
+ *
+ * Returns a pointer to a struct usb_device if such a specified usb
+ * device is present in the system currently.  The usage count of the
+ * device will be incremented if a device is found.  Make sure to call
+ * usb_put_dev() when the caller is finished with the device.
+ *
+ * If a device with the specified vendor and product id is not found,
+ * NULL is returned.
+ */
+struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
+{
+       struct list_head *buslist;
+       struct usb_bus *bus;
+       struct usb_device *dev = NULL;
+       
+       down(&usb_bus_list_lock);
+       for (buslist = usb_bus_list.next;
+            buslist != &usb_bus_list; 
+            buslist = buslist->next) {
+               bus = container_of(buslist, struct usb_bus, bus_list);
+               dev = match_device(bus->root_hub, vendor_id, product_id);
+               if (dev)
+                       goto exit;
+       }
+exit:
+       up(&usb_bus_list_lock);
+       return dev;
+}
+
+/**
+ * usb_get_current_frame_number - return current bus frame number
+ * @dev: the device whose bus is being queried
+ *
+ * Returns the current frame number for the USB host controller
+ * used with the given USB device.  This can be used when scheduling
+ * isochronous requests.
+ *
+ * Note that different kinds of host controller have different
+ * "scheduling horizons".  While one type might support scheduling only
+ * 32 frames into the future, others could support scheduling up to
+ * 1024 frames into the future.
+ */
+int usb_get_current_frame_number(struct usb_device *dev)
+{
+       return dev->bus->op->get_frame_number (dev);
+}
+
+/*-------------------------------------------------------------------*/
+/*
+ * __usb_get_extra_descriptor() finds a descriptor of specific type in the
+ * extra field of the interface and endpoint descriptor structs.
+ */
+
+int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
+{
+       struct usb_descriptor_header *header;
+
+       while (size >= sizeof(struct usb_descriptor_header)) {
+               header = (struct usb_descriptor_header *)buffer;
+
+               if (header->bLength < 2) {
+                       err("invalid descriptor length of %d", header->bLength);
+                       return -1;
+               }
+
+               if (header->bDescriptorType == type) {
+                       *ptr = header;
+                       return 0;
+               }
+
+               buffer += header->bLength;
+               size -= header->bLength;
+       }
+       return -1;
+}
+
+/**
+ * usb_disconnect - disconnect a device (usbcore-internal)
+ * @pdev: pointer to device being disconnected
+ * Context: !in_interrupt ()
+ *
+ * Something got disconnected. Get rid of it, and all of its children.
+ *
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ */
+void usb_disconnect(struct usb_device **pdev)
+{
+       struct usb_device       *dev = *pdev;
+       struct usb_bus          *bus;
+       struct usb_operations   *ops;
+       int                     i;
+
+       might_sleep ();
+
+       if (!dev) {
+               pr_debug ("%s nodev\n", __FUNCTION__);
+               return;
+       }
+       bus = dev->bus;
+       if (!bus) {
+               pr_debug ("%s nobus\n", __FUNCTION__);
+               return;
+       }
+       ops = bus->op;
+
+       *pdev = NULL;
+
+       /* mark the device as inactive, so any further urb submissions for
+        * this device will fail.
+        */
+       dev->state = USB_STATE_NOTATTACHED;
+
+       dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
+
+       /* Free up all the children before we remove this device */
+       for (i = 0; i < USB_MAXCHILDREN; i++) {
+               struct usb_device **child = dev->children + i;
+               if (*child)
+                       usb_disconnect(child);
+       }
+
+       /* disconnect() drivers from interfaces (a key side effect) */
+       dev_dbg (&dev->dev, "unregistering interfaces\n");
+       if (dev->actconfig) {
+               for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+                       struct usb_interface    *interface;
+
+                       /* remove this interface */
+                       interface = &dev->actconfig->interface[i];
+                       device_unregister(&interface->dev);
+               }
+       }
+
+       /* deallocate hcd/hardware state */
+       if (ops->disable) {
+               void    (*disable)(struct usb_device *, int) = ops->disable;
+
+               for (i = 0; i < 15; i++) {
+                       disable (dev, i);
+                       disable (dev, USB_DIR_IN | i);
+               }
+       }
+
+       dev_dbg (&dev->dev, "unregistering device\n");
+       /* Free the device number and remove the /proc/bus/usb entry */
+       if (dev->devnum > 0) {
+               clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+               usbfs_remove_device(dev);
+       }
+       device_unregister(&dev->dev);
+
+       /* Decrement the reference count, it'll auto free everything when */
+       /* it hits 0 which could very well be now */
+       usb_put_dev(dev);
+}
+
+/**
+ * usb_connect - pick device address (usbcore-internal)
+ * @dev: newly detected device (in DEFAULT state)
+ *
+ * Picks a device address.  It's up to the hub (or root hub) driver
+ * to handle and manage enumeration, starting from the DEFAULT state.
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ */
+void STDCALL usb_connect(struct usb_device *dev)
+{
+       int devnum;
+       // FIXME needs locking for SMP!!
+       /* why? this is called only from the hub thread, 
+        * which hopefully doesn't run on multiple CPU's simultaneously 8-)
+        * ... it's also called from modprobe/rmmod/apmd threads as part
+        * of virtual root hub init/reinit.  In the init case, the hub code 
+        * won't have seen this, but not so for reinit ... 
+        */
+       dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */
+
+       /* Try to allocate the next devnum beginning at bus->devnum_next. */
+       devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
+       if (devnum >= 128)
+               devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
+
+       dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
+
+       if (devnum < 128) {
+               set_bit(devnum, dev->bus->devmap.devicemap);
+               dev->devnum = devnum;
+       }
+}
+
+
+// hub-only!! ... and only exported for reset/reinit path.
+// otherwise used internally, for usb_new_device()
+int usb_set_address(struct usb_device *dev)
+{
+       int retval;
+
+       if (dev->devnum == 0)
+               return -EINVAL;
+       if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
+               return -EINVAL;
+       retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
+               0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+       if (retval == 0)
+               dev->state = USB_STATE_ADDRESS;
+       return retval;
+}
+
+
+/* improve on the default device description, if we can ... and
+ * while we're at it, maybe show the vendor and product strings.
+ */
+static void set_device_description (struct usb_device *dev)
+{
+       void    *buf;
+       int     mfgr = dev->descriptor.iManufacturer;
+       int     prod = dev->descriptor.iProduct;
+       int     vendor_id = dev->descriptor.idVendor;
+       int     product_id = dev->descriptor.idProduct;
+       char    *mfgr_str, *prod_str;
+
+       /* set default; keep it if there are no strings, or kmalloc fails */
+       sprintf (dev->dev.name, "USB device %04x:%04x",
+                vendor_id, product_id);
+
+       if (!(buf = kmalloc(256 * 2, GFP_KERNEL)))
+               return;
+       
+       prod_str = (char *) buf;
+       mfgr_str = (char *) buf + 256;
+
+       if (prod && usb_string (dev, prod, prod_str, 256) > 0) {
+#ifdef DEBUG
+               dev_printk (KERN_INFO, &dev->dev, "Product: %s\n", prod_str);
+#endif
+       } else {
+               prod_str = 0;
+       }
+
+       if (mfgr && usb_string (dev, mfgr, mfgr_str, 256) > 0) {
+#ifdef DEBUG
+               dev_printk (KERN_INFO, &dev->dev, "Manufacturer: %s\n", mfgr_str);
+#endif
+       } else {
+               mfgr_str = 0;
+       }
+
+       /* much like pci ... describe as either:
+        * - both strings:   'product descr (vendor descr)'
+        * - product only:   'product descr (USB device vvvv:pppp)'
+        * - vendor only:    'USB device vvvv:pppp (vendor descr)'
+        * - neither string: 'USB device vvvv:pppp'
+        */
+
+       if (prod_str && mfgr_str) {
+
+               snprintf(dev->dev.name, sizeof dev->dev.name,
+                        "%s (%s)", prod_str, mfgr_str);
+       } else if (prod_str) {
+               snprintf(dev->dev.name, sizeof dev->dev.name,
+                        "%s (USB device %04x:%04x)",
+                        prod_str, vendor_id, product_id);
+
+       } else if (mfgr_str) {
+               snprintf(dev->dev.name, sizeof dev->dev.name,
+                        "USB device %04x:%04x (%s)",
+                        vendor_id, product_id, mfgr_str);
+       }
+       usbprintk("USB connected: %s\n",dev->dev.name);
+       kfree(buf);
+}
+
+/*
+ * By the time we get here, we chose a new device address
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ */
+#define NEW_DEVICE_RETRYS      2
+#define SET_ADDRESS_RETRYS     2
+int usb_new_device(struct usb_device *dev, struct device *parent)
+{
+       int err = 0;
+       int i;
+       int j;
+
+       /*
+        * Set the driver for the usb device to point to the "generic" driver.
+        * This prevents the main usb device from being sent to the usb bus
+        * probe function.  Yes, it's a hack, but a nice one :)
+        *
+        * Do it asap, so more driver model stuff (like the device.h message
+        * utilities) can be used in hcd submit/unlink code paths.
+        */
+       usb_generic_driver.bus = &usb_bus_type;
+       dev->dev.parent = parent;
+       dev->dev.driver = &usb_generic_driver;
+       dev->dev.bus = &usb_bus_type;
+       dev->dev.release = usb_release_dev;
+       dev->dev.driver_data = &usb_generic_driver_data;
+       usb_get_dev(dev);
+       if (dev->dev.bus_id[0] == 0)
+               sprintf (&dev->dev.bus_id[0], "%d-%s",
+                        dev->bus->busnum, dev->devpath);
+
+       /* dma masks come from the controller; readonly, except to hcd */
+       dev->dev.dma_mask = parent->dma_mask;
+
+       /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
+        * it's fixed size except for full speed devices.
+        */
+       switch (dev->speed) {
+       case USB_SPEED_HIGH:            /* fixed at 64 */
+               i = 64;
+               break;
+       case USB_SPEED_FULL:            /* 8, 16, 32, or 64 */
+               /* to determine the ep0 maxpacket size, read the first 8
+                * bytes from the device descriptor to get bMaxPacketSize0;
+                * then correct our initial (small) guess.
+                */
+               // FALLTHROUGH
+       case USB_SPEED_LOW:             /* fixed at 8 */
+               i = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       dev->epmaxpacketin [0] = i;
+       dev->epmaxpacketout[0] = i;
+
+       for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
+
+               for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
+                       err = usb_set_address(dev);
+                       if (err >= 0)
+                               break;
+                       wait_ms(200);
+               }
+               if (err < 0) {
+                       dev_err(&dev->dev, "USB device not accepting new address=%d (error=%d)\n",
+                               dev->devnum, err);
+                       dev->state = USB_STATE_DEFAULT;
+                       clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+                       dev->devnum = -1;
+                       return 1;
+               }
+
+               wait_ms(10);    /* Let the SET_ADDRESS settle */
+
+               /* high and low speed devices don't need this... */
+               err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+               if (err >= 8)
+                       break;
+               wait_ms(100);
+       }
+
+       if (err < 8) {
+               if (err < 0)
+                       dev_err(&dev->dev, "USB device not responding, giving up (error=%d)\n", err);
+               else
+                       dev_err(&dev->dev, "USB device descriptor short read (expected %i, got %i)\n", 8, err);
+               clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+               dev->devnum = -1;
+               return 1;
+       }
+       if (dev->speed == USB_SPEED_FULL) {
+               dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
+               dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+       }
+
+       /* USB device state == addressed ... still not usable */
+
+       err = usb_get_device_descriptor(dev);
+       if (err < (signed)sizeof(dev->descriptor)) {
+               if (err < 0)
+                       dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n", err);
+               else
+                       dev_err(&dev->dev, "USB device descriptor short read (expected %Zi, got %i)\n",
+                               sizeof(dev->descriptor), err);
+       
+               clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+               dev->devnum = -1;
+               return 1;
+       }
+
+       err = usb_get_configuration(dev);
+       if (err < 0) {
+               dev_err(&dev->dev, "unable to get device %d configuration (error=%d)\n",
+                       dev->devnum, err);
+               clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+               dev->devnum = -1;
+               return 1;
+       }
+
+       /* we set the default configuration here */
+       err = usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue);
+       if (err) {
+               dev_err(&dev->dev, "failed to set device %d default configuration (error=%d)\n",
+                       dev->devnum, err);
+               clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+               dev->devnum = -1;
+               return 1;
+       }
+
+       /* USB device state == configured ... tell the world! */
+
+       dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
+               dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+       set_device_description (dev);
+
+#ifdef DEBUG
+       if (dev->descriptor.iSerialNumber)
+               usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+#endif
+       /* put into sysfs, with device and config specific files */
+       err = device_add (&dev->dev);
+       if (err)
+               return err;
+       usb_create_driverfs_dev_files (dev);
+
+       /* Register all of the interfaces for this device with the driver core.
+        * Remember, interfaces get bound to drivers, not devices. */
+       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+               struct usb_interface *interface = &dev->actconfig->interface[i];
+               struct usb_interface_descriptor *desc;
+
+               desc = &interface->altsetting [interface->act_altsetting].desc;
+               interface->dev.parent = &dev->dev;
+               interface->dev.driver = NULL;
+               interface->dev.bus = &usb_bus_type;
+               interface->dev.dma_mask = parent->dma_mask;
+               sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
+                        dev->bus->busnum, dev->devpath,
+                        desc->bInterfaceNumber);
+               if (!desc->iInterface
+                               || usb_string (dev, desc->iInterface,
+                                       interface->dev.name,
+                                       sizeof interface->dev.name) <= 0) {
+                       /* typically devices won't bother with interface
+                        * descriptions; this is the normal case.  an
+                        * interface's driver might describe it better.
+                        * (also: iInterface is per-altsetting ...)
+                        */
+                       sprintf (&interface->dev.name[0],
+                               "usb-%s-%s interface %d",
+                               dev->bus->bus_name, dev->devpath,
+                               desc->bInterfaceNumber);
+                       DPRINT1("usb_new_device: %s\n", interface->dev.name);
+               }
+               dev_dbg (&dev->dev, "%s - registering interface %s\n", __FUNCTION__, interface->dev.bus_id);
+               device_add (&interface->dev);
+               usb_create_driverfs_intf_files (interface);
+       }
+       /* add a /proc/bus/usb entry */
+       usbfs_add_device(dev);
+
+       return 0;
+}
+
+/**
+ * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP
+ * @dev: device the buffer will be used with
+ * @size: requested buffer size
+ * @mem_flags: affect whether allocation may block
+ * @dma: used to return DMA address of buffer
+ *
+ * Return value is either null (indicating no buffer could be allocated), or
+ * the cpu-space pointer to a buffer that may be used to perform DMA to the
+ * specified device.  Such cpu-space buffers are returned along with the DMA
+ * address (through the pointer provided).
+ *
+ * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to
+ * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
+ * hardware for long idle periods.  The implementation varies between
+ * platforms, depending on details of how DMA will work to this device.
+ * Using these buffers also helps prevent cacheline sharing problems on
+ * architectures where CPU caches are not DMA-coherent.
+ *
+ * When the buffer is no longer used, free it with usb_buffer_free().
+ */
+void *usb_buffer_alloc (
+       struct usb_device *dev,
+       size_t size,
+       int mem_flags,
+       dma_addr_t *dma
+)
+{
+       if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
+               return 0;
+       return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
+}
+
+/**
+ * usb_buffer_free - free memory allocated with usb_buffer_alloc()
+ * @dev: device the buffer was used with
+ * @size: requested buffer size
+ * @addr: CPU address of buffer
+ * @dma: DMA address of buffer
+ *
+ * This reclaims an I/O buffer, letting it be reused.  The memory must have
+ * been allocated using usb_buffer_alloc(), and the parameters must match
+ * those provided in that allocation request. 
+ */
+void usb_buffer_free (
+       struct usb_device *dev,
+       size_t size,
+       void *addr,
+       dma_addr_t dma
+)
+{
+       if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
+               return;
+       dev->bus->op->buffer_free (dev->bus, size, addr, dma);
+}
+
+/**
+ * usb_buffer_map - create DMA mapping(s) for an urb
+ * @urb: urb whose transfer_buffer will be mapped
+ *
+ * Return value is either null (indicating no buffer could be mapped), or
+ * the parameter.  URB_NO_DMA_MAP is added to urb->transfer_flags if the
+ * operation succeeds.  If the device is connected to this system through
+ * a non-DMA controller, this operation always succeeds.
+ *
+ * This call would normally be used for an urb which is reused, perhaps
+ * as the target of a large periodic transfer, with usb_buffer_dmasync()
+ * calls to synchronize memory and dma state.  It may not be used for
+ * control requests.
+ *
+ * Reverse the effect of this call with usb_buffer_unmap().
+ */
+struct urb *usb_buffer_map (struct urb *urb)
+{
+       struct usb_bus          *bus;
+       struct device           *controller;
+
+       if (!urb
+                       || usb_pipecontrol (urb->pipe)
+                       || !urb->dev
+                       || !(bus = urb->dev->bus)
+                       || !(controller = bus->controller))
+               return 0;
+
+       if (controller->dma_mask) {
+               urb->transfer_dma = dma_map_single (controller,
+                       urb->transfer_buffer, urb->transfer_buffer_length,
+                       usb_pipein (urb->pipe)
+                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       // FIXME generic api broken like pci, can't report errors
+       // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
+       } else
+               urb->transfer_dma = ~0;
+       urb->transfer_flags |= URB_NO_DMA_MAP;
+       return urb;
+}
+
+/**
+ * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
+ * @urb: urb whose transfer_buffer will be synchronized
+ */
+void usb_buffer_dmasync (struct urb *urb)
+{
+       struct usb_bus          *bus;
+       struct device           *controller;
+
+       if (!urb
+                       || !(urb->transfer_flags & URB_NO_DMA_MAP)
+                       || !urb->dev
+                       || !(bus = urb->dev->bus)
+                       || !(controller = bus->controller))
+               return;
+
+       if (controller->dma_mask)
+               dma_sync_single (controller,
+                       urb->transfer_dma, urb->transfer_buffer_length,
+                       usb_pipein (urb->pipe)
+                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+}
+
+/**
+ * usb_buffer_unmap - free DMA mapping(s) for an urb
+ * @urb: urb whose transfer_buffer will be unmapped
+ *
+ * Reverses the effect of usb_buffer_map().
+ */
+void usb_buffer_unmap (struct urb *urb)
+{
+       struct usb_bus          *bus;
+       struct device           *controller;
+
+       if (!urb
+                       || !(urb->transfer_flags & URB_NO_DMA_MAP)
+                       || !urb->dev
+                       || !(bus = urb->dev->bus)
+                       || !(controller = bus->controller))
+               return;
+
+       if (controller->dma_mask)
+               dma_unmap_single (controller,
+                       urb->transfer_dma, urb->transfer_buffer_length,
+                       usb_pipein (urb->pipe)
+                               ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       urb->transfer_flags &= ~URB_NO_DMA_MAP;
+}
+
+/**
+ * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
+ * @dev: device to which the scatterlist will be mapped
+ * @pipe: endpoint defining the mapping direction
+ * @sg: the scatterlist to map
+ * @nents: the number of entries in the scatterlist
+ *
+ * Return value is either < 0 (indicating no buffers could be mapped), or
+ * the number of DMA mapping array entries in the scatterlist.
+ *
+ * The caller is responsible for placing the resulting DMA addresses from
+ * the scatterlist into URB transfer buffer pointers, and for setting the
+ * URB_NO_DMA_MAP transfer flag in each of those URBs.
+ *
+ * Top I/O rates come from queuing URBs, instead of waiting for each one
+ * to complete before starting the next I/O.   This is particularly easy
+ * to do with scatterlists.  Just allocate and submit one URB for each DMA
+ * mapping entry returned, stopping on the first error or when all succeed.
+ * Better yet, use the usb_sg_*() calls, which do that (and more) for you.
+ *
+ * This call would normally be used when translating scatterlist requests,
+ * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
+ * may be able to coalesce mappings for improved I/O efficiency.
+ *
+ * Reverse the effect of this call with usb_buffer_unmap_sg().
+ */
+int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int nents)
+{
+       struct usb_bus          *bus;
+       struct device           *controller;
+
+       if (!dev
+                       || usb_pipecontrol (pipe)
+                       || !(bus = dev->bus)
+                       || !(controller = bus->controller)
+                       || !controller->dma_mask)
+               return -1;
+
+       // FIXME generic api broken like pci, can't report errors
+       return dma_map_sg (controller, sg, nents,
+                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+}
+
+/**
+ * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
+ * @dev: device to which the scatterlist will be mapped
+ * @pipe: endpoint defining the mapping direction
+ * @sg: the scatterlist to synchronize
+ * @n_hw_ents: the positive return value from usb_buffer_map_sg
+ *
+ * Use this when you are re-using a scatterlist's data buffers for
+ * another USB request.
+ */
+void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int n_hw_ents)
+{
+       struct usb_bus          *bus;
+       struct device           *controller;
+
+       if (!dev
+                       || !(bus = dev->bus)
+                       || !(controller = bus->controller)
+                       || !controller->dma_mask)
+               return;
+
+       dma_sync_sg (controller, sg, n_hw_ents,
+                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+}
+
+/**
+ * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
+ * @dev: device to which the scatterlist will be mapped
+ * @pipe: endpoint defining the mapping direction
+ * @sg: the scatterlist to unmap
+ * @n_hw_ents: the positive return value from usb_buffer_map_sg
+ *
+ * Reverses the effect of usb_buffer_map_sg().
+ */
+void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int n_hw_ents)
+{
+       struct usb_bus          *bus;
+       struct device           *controller;
+
+       if (!dev
+                       || !(bus = dev->bus)
+                       || !(controller = bus->controller)
+                       || !controller->dma_mask)
+               return;
+
+       dma_unmap_sg (controller, sg, n_hw_ents,
+                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+}
+
+
+struct bus_type usb_bus_type = {
+       .name =         "usb",
+       .match =        usb_device_match,
+       .hotplug =      usb_hotplug,
+};
+
+#ifndef MODULE
+
+static int __init usb_setup_disable(char *str)
+{
+       nousb = 1;
+       return 1;
+}
+
+/* format to disable USB on kernel command line is: nousb */
+__setup("nousb", usb_setup_disable);
+
+#endif
+
+/*
+ * for external read access to <nousb>
+ */
+int STDCALL usb_disabled(void)
+{
+       return nousb;
+}
+
+/*
+ * Init
+ */
+int STDCALL __init usb_init(void)
+{
+       if (nousb) {
+               info("USB support disabled\n");
+               return 0;
+       }
+
+       bus_register(&usb_bus_type);
+       usb_major_init();
+       usbfs_init();
+       usb_hub_init();
+
+       driver_register(&usb_generic_driver);
+
+       return 0;
+}
+
+/*
+ * Cleanup
+ */
+void STDCALL __exit usb_exit(void)
+{
+       /* This will matter if shutdown/reboot does exitcalls. */
+       if (nousb)
+               return;
+
+       driver_unregister(&usb_generic_driver);
+       usb_major_cleanup();
+       usbfs_cleanup();
+       usb_hub_cleanup();
+       bus_unregister(&usb_bus_type);
+}
+
+subsys_initcall(usb_init);
+module_exit(usb_exit);
+
+/*
+ * USB may be built into the kernel or be built as modules.
+ * These symbols are exported for device (or host controller)
+ * driver modules to use.
+ */
+EXPORT_SYMBOL(usb_epnum_to_ep_desc);
+
+EXPORT_SYMBOL(usb_register);
+EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL(usb_disabled);
+
+EXPORT_SYMBOL(usb_device_probe);
+EXPORT_SYMBOL(usb_device_remove);
+
+EXPORT_SYMBOL(usb_alloc_dev);
+EXPORT_SYMBOL(usb_put_dev);
+EXPORT_SYMBOL(usb_get_dev);
+EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
+
+EXPORT_SYMBOL(usb_driver_claim_interface);
+EXPORT_SYMBOL(usb_interface_claimed);
+EXPORT_SYMBOL(usb_driver_release_interface);
+EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL(usb_find_interface);
+EXPORT_SYMBOL(usb_ifnum_to_if);
+
+EXPORT_SYMBOL(usb_new_device);
+EXPORT_SYMBOL(usb_reset_device);
+EXPORT_SYMBOL(usb_connect);
+EXPORT_SYMBOL(usb_disconnect);
+
+EXPORT_SYMBOL(__usb_get_extra_descriptor);
+
+EXPORT_SYMBOL(usb_find_device);
+EXPORT_SYMBOL(usb_get_current_frame_number);
+
+EXPORT_SYMBOL (usb_buffer_alloc);
+EXPORT_SYMBOL (usb_buffer_free);
+
+EXPORT_SYMBOL (usb_buffer_map);
+EXPORT_SYMBOL (usb_buffer_dmasync);
+EXPORT_SYMBOL (usb_buffer_unmap);
+
+EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL (usb_buffer_unmap_sg);
+
+MODULE_LICENSE("GPL");
index 52210ef..09f459f 100644 (file)
@@ -1,5 +1,5 @@
-/* Functions local to drivers/usb/core/ */\r
-\r
-extern void usb_create_driverfs_dev_files (struct usb_device *dev);\r
-extern void usb_create_driverfs_intf_files (struct usb_interface *intf);\r
-\r
+/* Functions local to drivers/usb/core/ */
+
+extern void usb_create_driverfs_dev_files (struct usb_device *dev);
+extern void usb_create_driverfs_intf_files (struct usb_interface *intf);
+
index 34df7e4..650e0f4 100644 (file)
@@ -1,63 +1,63 @@
-/*\r
-   ReactOS specific functions for usbcore module\r
-   by Aleksey Bragin (aleksey@reactos.com)\r
-*/\r
-\r
-#include <ddk/ntddk.h>\r
-#include <debug.h>\r
-\r
-NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)\r
-{\r
-       DbgPrint("usbcore: AddDevice called\n");\r
-       \r
-       /* we need to do kind of this stuff here (as usual)\r
-       PDEVICE_OBJECT fdo;\r
-       IoCreateDevice(..., &fdo);\r
-       pdx->LowerDeviceObject = \r
-       IoAttachDeviceToDeviceStack(fdo, pdo);*/\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-VOID DriverUnload(PDRIVER_OBJECT DriverObject)\r
-{\r
-       // nothing to do here yet\r
-}\r
-\r
-// Dispatch PNP\r
-NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)\r
-{\r
-       ULONG fcn;\r
-       PIO_STACK_LOCATION stack;\r
-       \r
-       stack = IoGetCurrentIrpStackLocation(Irp);\r
-       fcn = stack->MinorFunction; \r
-       DbgPrint("IRP_MJ_PNP, fcn=%d\n", fcn);\r
-\r
-       if (fcn == IRP_MN_REMOVE_DEVICE)\r
-       {\r
-               IoDeleteDevice(fdo);\r
-    }\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)\r
-{\r
-       DbgPrint("IRP_MJ_POWER dispatch\n");\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * Standard DriverEntry method.\r
- */\r
-NTSTATUS STDCALL\r
-DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)\r
-{\r
-       DriverObject->DriverUnload = DriverUnload;\r
-       DriverObject->DriverExtension->AddDevice = AddDevice;\r
-       DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;\r
-       DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
+/*
+   ReactOS specific functions for usbcore module
+   by Aleksey Bragin (aleksey@reactos.com)
+*/
+
+#include <ddk/ntddk.h>
+#include <debug.h>
+
+NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)
+{
+       DbgPrint("usbcore: AddDevice called\n");
+       
+       /* we need to do kind of this stuff here (as usual)
+       PDEVICE_OBJECT fdo;
+       IoCreateDevice(..., &fdo);
+       pdx->LowerDeviceObject = 
+       IoAttachDeviceToDeviceStack(fdo, pdo);*/
+
+       return STATUS_SUCCESS;
+}
+
+VOID DriverUnload(PDRIVER_OBJECT DriverObject)
+{
+       // nothing to do here yet
+}
+
+// Dispatch PNP
+NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)
+{
+       ULONG fcn;
+       PIO_STACK_LOCATION stack;
+       
+       stack = IoGetCurrentIrpStackLocation(Irp);
+       fcn = stack->MinorFunction; 
+       DbgPrint("IRP_MJ_PNP, fcn=%d\n", fcn);
+
+       if (fcn == IRP_MN_REMOVE_DEVICE)
+       {
+               IoDeleteDevice(fdo);
+    }
+
+       return STATUS_SUCCESS;
+}
+
+NTSTATUS DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)
+{
+       DbgPrint("IRP_MJ_POWER dispatch\n");
+       return STATUS_SUCCESS;
+}
+
+/*
+ * Standard DriverEntry method.
+ */
+NTSTATUS STDCALL
+DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)
+{
+       DriverObject->DriverUnload = DriverUnload;
+       DriverObject->DriverExtension->AddDevice = AddDevice;
+       DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
+       DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
+
+       return STATUS_SUCCESS;
+}
index 25446cd..cb675e2 100644 (file)
@@ -1,32 +1,32 @@
-;\r
-; Exports definition file for usbcore.sys\r
-;\r
-EXPORTS\r
-usb_init@0\r
-usb_exit@0\r
-usb_init_urb@4\r
-usb_alloc_urb@8\r
-usb_free_urb@4\r
-usb_get_urb@4\r
-usb_get_dev@4\r
-usb_submit_urb@8\r
-usb_unlink_urb@4\r
-usb_bus_init@4\r
-usb_alloc_bus@4\r
-usb_free_bus@4\r
-usb_register_bus@4\r
-usb_deregister_bus@4\r
-usb_register_root_hub@8\r
-usb_calc_bus_time@16\r
-usb_check_bandwidth@8\r
-usb_claim_bandwidth@16\r
-usb_release_bandwidth@12\r
-usb_hcd_giveback_urb@12\r
-;usb_hcd_irq@12\r
-usb_hc_died@4\r
-usb_alloc_dev@8\r
-usb_connect@4\r
-usb_put_dev@4\r
-usb_disabled@0\r
-usb_hcd_pci_probe@8\r
+;
+; Exports definition file for usbcore.sys
+;
+EXPORTS
+usb_init@0
+usb_exit@0
+usb_init_urb@4
+usb_alloc_urb@8
+usb_free_urb@4
+usb_get_urb@4
+usb_get_dev@4
+usb_submit_urb@8
+usb_unlink_urb@4
+usb_bus_init@4
+usb_alloc_bus@4
+usb_free_bus@4
+usb_register_bus@4
+usb_deregister_bus@4
+usb_register_root_hub@8
+usb_calc_bus_time@16
+usb_check_bandwidth@8
+usb_claim_bandwidth@16
+usb_release_bandwidth@12
+usb_hcd_giveback_urb@12
+;usb_hcd_irq@12
+usb_hc_died@4
+usb_alloc_dev@8
+usb_connect@4
+usb_put_dev@4
+usb_disabled@0
+usb_hcd_pci_probe@8
 usb_hcd_pci_remove@4
\ No newline at end of file
 usb_hcd_pci_remove@4
\ No newline at end of file
index bccb64a..f12b4d6 100644 (file)
@@ -1,5 +1,5 @@
-#define REACTOS_VERSION_DLL\r
-#define REACTOS_STR_FILE_DESCRIPTION   "USB Core Device Driver\0"\r
-#define REACTOS_STR_INTERNAL_NAME      "usbcore\0"\r
-#define REACTOS_STR_ORIGINAL_FILENAME  "usbcore.sys\0"\r
-#include <reactos/version.rc>\r
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION   "USB Core Device Driver\0"
+#define REACTOS_STR_INTERNAL_NAME      "usbcore\0"
+#define REACTOS_STR_ORIGINAL_FILENAME  "usbcore.sys\0"
+#include <reactos/version.rc>
index e2e02ed..f81185f 100644 (file)
@@ -1,20 +1,20 @@
-PATH_TO_TOP = ../../../..\r
-\r
-TARGET_TYPE = export_driver\r
-\r
-TARGET_NAME = ohci\r
-\r
-TARGET_DDKLIBS = ntoskrnl.a usbcore.a\r
-\r
-TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE\r
-\r
-TARGET_OBJECTS = \\r
-  ohci-hcd.o ohci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o\r
-\r
-include $(PATH_TO_TOP)/rules.mak\r
-\r
-include $(TOOLS_PATH)/helper.mk\r
-\r
-# Automatic dependency tracking\r
-DEP_OBJECTS := $(TARGET_OBJECTS)\r
-include $(PATH_TO_TOP)/tools/depend.mk\r
+PATH_TO_TOP = ../../../..
+
+TARGET_TYPE = export_driver
+
+TARGET_NAME = ohci
+
+TARGET_DDKLIBS = ntoskrnl.a usbcore.a
+
+TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE
+
+TARGET_OBJECTS = \
+  ohci-hcd.o ohci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
+
+# Automatic dependency tracking
+DEP_OBJECTS := $(TARGET_OBJECTS)
+include $(PATH_TO_TOP)/tools/depend.mk
index c233905..d8bfc9a 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := ohci-hcd.o\r
-\r
-include $(TOPDIR)/Rules.make\r
+O_TARGET := ohci-hcd.o
+
+include $(TOPDIR)/Rules.make
index 6c9661b..0997ddf 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- *\r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- *\r
- * This file is licenced under the GPL.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#ifdef DEBUG\r
-\r
-#define edstring(ed_type) ({ char *temp; \\r
-       switch (ed_type) { \\r
-       case PIPE_CONTROL:      temp = "ctrl"; break; \\r
-       case PIPE_BULK:         temp = "bulk"; break; \\r
-       case PIPE_INTERRUPT:    temp = "intr"; break; \\r
-       default:                temp = "isoc"; break; \\r
-       }; temp;})\r
-#define pipestring(pipe) edstring(usb_pipetype(pipe))\r
-\r
-/* debug| print the main components of an URB\r
- * small: 0) header + data packets 1) just header\r
- */\r
-static void __attribute__((unused))\r
-urb_print (struct urb * urb, char * str, int small)\r
-{\r
-       unsigned int pipe= urb->pipe;\r
-\r
-       if (!urb->dev || !urb->dev->bus) {\r
-               dbg("%s URB: no dev", str);\r
-               return;\r
-       }\r
-\r
-#ifndef        OHCI_VERBOSE_DEBUG\r
-       if (urb->status != 0)\r
-#endif\r
-       dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",\r
-                   str,\r
-                   urb,\r
-                   usb_pipedevice (pipe),\r
-                   usb_pipeendpoint (pipe),\r
-                   usb_pipeout (pipe)? "out" : "in",\r
-                   pipestring (pipe),\r
-                   urb->transfer_flags,\r
-                   urb->actual_length,\r
-                   urb->transfer_buffer_length,\r
-                   urb->status);\r
-\r
-#ifdef OHCI_VERBOSE_DEBUG\r
-       if (!small) {\r
-               int i, len;\r
-\r
-               if (usb_pipecontrol (pipe)) {\r
-                       printk (KERN_DEBUG __FILE__ ": setup(8):");\r
-                       for (i = 0; i < 8 ; i++)\r
-                               printk (" %02x", ((__u8 *) urb->setup_packet) [i]);\r
-                       printk ("\n");\r
-               }\r
-               if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {\r
-                       printk (KERN_DEBUG __FILE__ ": data(%d/%d):",\r
-                               urb->actual_length,\r
-                               urb->transfer_buffer_length);\r
-                       len = usb_pipeout (pipe)?\r
-                                               urb->transfer_buffer_length: urb->actual_length;\r
-                       for (i = 0; i < 16 && i < len; i++)\r
-                               printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);\r
-                       printk ("%s stat:%d\n", i < len? "...": "", urb->status);\r
-               }\r
-       }\r
-#endif\r
-}\r
-\r
-#define ohci_dbg_sw(ohci, next, size, format, arg...) \\r
-       do { \\r
-       if (next) { \\r
-               unsigned s_len; \\r
-               s_len = snprintf (*next, *size, format, ## arg ); \\r
-               *size -= s_len; *next += s_len; \\r
-       } else \\r
-               ohci_dbg(ohci,format, ## arg ); \\r
-       } while (0);\r
-\r
-\r
-static void ohci_dump_intr_mask (\r
-       struct ohci_hcd *ohci,\r
-       char *label,\r
-       u32 mask,\r
-       char **next,\r
-       unsigned *size)\r
-{\r
-       ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n",\r
-               label,\r
-               mask,\r
-               (mask & OHCI_INTR_MIE) ? " MIE" : "",\r
-               (mask & OHCI_INTR_OC) ? " OC" : "",\r
-               (mask & OHCI_INTR_RHSC) ? " RHSC" : "",\r
-               (mask & OHCI_INTR_FNO) ? " FNO" : "",\r
-               (mask & OHCI_INTR_UE) ? " UE" : "",\r
-               (mask & OHCI_INTR_RD) ? " RD" : "",\r
-               (mask & OHCI_INTR_SF) ? " SF" : "",\r
-               (mask & OHCI_INTR_WDH) ? " WDH" : "",\r
-               (mask & OHCI_INTR_SO) ? " SO" : ""\r
-               );\r
-}\r
-\r
-static void maybe_print_eds (\r
-       struct ohci_hcd *ohci,\r
-       char *label,\r
-       u32 value,\r
-       char **next,\r
-       unsigned *size)\r
-{\r
-       if (value)\r
-               ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value);\r
-}\r
-\r
-static char *hcfs2string (int state)\r
-{\r
-       switch (state) {\r
-               case OHCI_USB_RESET:    return "reset";\r
-               case OHCI_USB_RESUME:   return "resume";\r
-               case OHCI_USB_OPER:     return "operational";\r
-               case OHCI_USB_SUSPEND:  return "suspend";\r
-       }\r
-       return "?";\r
-}\r
-\r
-// dump control and status registers\r
-static void\r
-ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)\r
-{\r
-       struct ohci_regs        *regs = controller->regs;\r
-       u32                     temp;\r
-\r
-       temp = readl (&regs->revision) & 0xff;\r
-       ohci_dbg_sw (controller, next, size,\r
-               "OHCI %d.%d, %s legacy support registers\n",\r
-               0x03 & (temp >> 4), (temp & 0x0f),\r
-               (temp & 0x10) ? "with" : "NO");\r
-\r
-       temp = readl (&regs->control);\r
-       ohci_dbg_sw (controller, next, size,\r
-               "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",\r
-               temp,\r
-               (temp & OHCI_CTRL_RWE) ? " RWE" : "",\r
-               (temp & OHCI_CTRL_RWC) ? " RWC" : "",\r
-               (temp & OHCI_CTRL_IR) ? " IR" : "",\r
-               hcfs2string (temp & OHCI_CTRL_HCFS),\r
-               (temp & OHCI_CTRL_BLE) ? " BLE" : "",\r
-               (temp & OHCI_CTRL_CLE) ? " CLE" : "",\r
-               (temp & OHCI_CTRL_IE) ? " IE" : "",\r
-               (temp & OHCI_CTRL_PLE) ? " PLE" : "",\r
-               temp & OHCI_CTRL_CBSR\r
-               );\r
-\r
-       temp = readl (&regs->cmdstatus);\r
-       ohci_dbg_sw (controller, next, size,\r
-               "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp,\r
-               (temp & OHCI_SOC) >> 16,\r
-               (temp & OHCI_OCR) ? " OCR" : "",\r
-               (temp & OHCI_BLF) ? " BLF" : "",\r
-               (temp & OHCI_CLF) ? " CLF" : "",\r
-               (temp & OHCI_HCR) ? " HCR" : ""\r
-               );\r
-\r
-       ohci_dump_intr_mask (controller, "intrstatus",\r
-                       readl (&regs->intrstatus), next, size);\r
-       ohci_dump_intr_mask (controller, "intrenable",\r
-                       readl (&regs->intrenable), next, size);\r
-       // intrdisable always same as intrenable\r
-\r
-       maybe_print_eds (controller, "ed_periodcurrent",\r
-                       readl (&regs->ed_periodcurrent), next, size);\r
-\r
-       maybe_print_eds (controller, "ed_controlhead",\r
-                       readl (&regs->ed_controlhead), next, size);\r
-       maybe_print_eds (controller, "ed_controlcurrent",\r
-                       readl (&regs->ed_controlcurrent), next, size);\r
-\r
-       maybe_print_eds (controller, "ed_bulkhead",\r
-                       readl (&regs->ed_bulkhead), next, size);\r
-       maybe_print_eds (controller, "ed_bulkcurrent",\r
-                       readl (&regs->ed_bulkcurrent), next, size);\r
-\r
-       maybe_print_eds (controller, "donehead",\r
-                       readl (&regs->donehead), next, size);\r
-}\r
-\r
-#define dbg_port_sw(hc,num,value,next,size) \\r
-       ohci_dbg_sw (hc, next, size, \\r
-               "roothub.portstatus [%d] " \\r
-               "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \\r
-               num, temp, \\r
-               (temp & RH_PS_PRSC) ? " PRSC" : "", \\r
-               (temp & RH_PS_OCIC) ? " OCIC" : "", \\r
-               (temp & RH_PS_PSSC) ? " PSSC" : "", \\r
-               (temp & RH_PS_PESC) ? " PESC" : "", \\r
-               (temp & RH_PS_CSC) ? " CSC" : "", \\r
-               \\r
-               (temp & RH_PS_LSDA) ? " LSDA" : "", \\r
-               (temp & RH_PS_PPS) ? " PPS" : "", \\r
-               (temp & RH_PS_PRS) ? " PRS" : "", \\r
-               (temp & RH_PS_POCI) ? " POCI" : "", \\r
-               (temp & RH_PS_PSS) ? " PSS" : "", \\r
-               \\r
-               (temp & RH_PS_PES) ? " PES" : "", \\r
-               (temp & RH_PS_CCS) ? " CCS" : "" \\r
-               );\r
-\r
-\r
-static void\r
-ohci_dump_roothub (\r
-       struct ohci_hcd *controller,\r
-       int verbose,\r
-       char **next,\r
-       unsigned *size)\r
-{\r
-       u32                     temp, ndp, i;\r
-\r
-       temp = roothub_a (controller);\r
-       if (temp == ~(u32)0)\r
-               return;\r
-       ndp = (temp & RH_A_NDP);\r
-\r
-       if (verbose) {\r
-               ohci_dbg_sw (controller, next, size,\r
-                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,\r
-                       ((temp & RH_A_POTPGT) >> 24) & 0xff,\r
-                       (temp & RH_A_NOCP) ? " NOCP" : "",\r
-                       (temp & RH_A_OCPM) ? " OCPM" : "",\r
-                       (temp & RH_A_DT) ? " DT" : "",\r
-                       (temp & RH_A_NPS) ? " NPS" : "",\r
-                       (temp & RH_A_PSM) ? " PSM" : "",\r
-                       ndp\r
-                       );\r
-               temp = roothub_b (controller);\r
-               ohci_dbg_sw (controller, next, size,\r
-                       "roothub.b %08x PPCM=%04x DR=%04x\n",\r
-                       temp,\r
-                       (temp & RH_B_PPCM) >> 16,\r
-                       (temp & RH_B_DR)\r
-                       );\r
-               temp = roothub_status (controller);\r
-               ohci_dbg_sw (controller, next, size,\r
-                       "roothub.status %08x%s%s%s%s%s%s\n",\r
-                       temp,\r
-                       (temp & RH_HS_CRWE) ? " CRWE" : "",\r
-                       (temp & RH_HS_OCIC) ? " OCIC" : "",\r
-                       (temp & RH_HS_LPSC) ? " LPSC" : "",\r
-                       (temp & RH_HS_DRWE) ? " DRWE" : "",\r
-                       (temp & RH_HS_OCI) ? " OCI" : "",\r
-                       (temp & RH_HS_LPS) ? " LPS" : ""\r
-                       );\r
-       }\r
-\r
-       for (i = 0; i < ndp; i++) {\r
-               temp = roothub_portstatus (controller, i);\r
-               dbg_port_sw (controller, i, temp, next, size);\r
-       }\r
-}\r
-\r
-static void ohci_dump (struct ohci_hcd *controller, int verbose)\r
-{\r
-       ohci_dbg (controller, "OHCI controller state\n");\r
-\r
-       // dumps some of the state we know about\r
-       ohci_dump_status (controller, NULL, 0);\r
-       if (controller->hcca)\r
-               ohci_dbg (controller,\r
-                       "hcca frame #%04x\n", controller->hcca->frame_no);\r
-       ohci_dump_roothub (controller, 1, NULL, 0);\r
-}\r
-\r
-static const char data0 [] = "DATA0";\r
-static const char data1 [] = "DATA1";\r
-\r
-static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td)\r
-{\r
-       u32     tmp = le32_to_cpup (&td->hwINFO);\r
-\r
-       ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x",\r
-               label, td,\r
-               (tmp & TD_DONE) ? " (DONE)" : "",\r
-               td->urb, td->index,\r
-               le32_to_cpup (&td->hwNextTD));\r
-       if ((tmp & TD_ISO) == 0) {\r
-               const char      *toggle, *pid;\r
-               u32     cbp, be;\r
-\r
-               switch (tmp & TD_T) {\r
-               case TD_T_DATA0: toggle = data0; break;\r
-               case TD_T_DATA1: toggle = data1; break;\r
-               case TD_T_TOGGLE: toggle = "(CARRY)"; break;\r
-               default: toggle = "(?)"; break;\r
-               }\r
-               switch (tmp & TD_DP) {\r
-               case TD_DP_SETUP: pid = "SETUP"; break;\r
-               case TD_DP_IN: pid = "IN"; break;\r
-               case TD_DP_OUT: pid = "OUT"; break;\r
-               default: pid = "(bad pid)"; break;\r
-               }\r
-               ohci_dbg (ohci, "     info %08x CC=%x %s DI=%d %s %s", tmp,\r
-                       TD_CC_GET(tmp), /* EC, */ toggle,\r
-                       (tmp & TD_DI) >> 21, pid,\r
-                       (tmp & TD_R) ? "R" : "");\r
-               cbp = le32_to_cpup (&td->hwCBP);\r
-               be = le32_to_cpup (&td->hwBE);\r
-               ohci_dbg (ohci, "     cbp %08x be %08x (len %d)", cbp, be,\r
-                       cbp ? (be + 1 - cbp) : 0);\r
-       } else {\r
-               unsigned        i;\r
-               ohci_dbg (ohci, "     info %08x CC=%x FC=%d DI=%d SF=%04x", tmp,\r
-                       TD_CC_GET(tmp),\r
-                       (tmp >> 24) & 0x07,\r
-                       (tmp & TD_DI) >> 21,\r
-                       tmp & 0x0000ffff);\r
-               ohci_dbg (ohci, "     bp0 %08x be %08x",\r
-                       le32_to_cpup (&td->hwCBP) & ~0x0fff,\r
-                       le32_to_cpup (&td->hwBE));\r
-               for (i = 0; i < MAXPSW; i++) {\r
-                       u16     psw = le16_to_cpup (&td->hwPSW [i]);\r
-                       int     cc = (psw >> 12) & 0x0f;\r
-                       ohci_dbg (ohci, "       psw [%d] = %2x, CC=%x %s=%d", i,\r
-                               psw, cc,\r
-                               (cc >= 0x0e) ? "OFFSET" : "SIZE",\r
-                               psw & 0x0fff);\r
-               }\r
-       }\r
-}\r
-\r
-/* caller MUST own hcd spinlock if verbose is set! */\r
-static void __attribute__((unused))\r
-ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)\r
-{\r
-       u32     tmp = ed->hwINFO;\r
-       char    *type = "";\r
-\r
-       ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x",\r
-               label,\r
-               ed, ed->state, edstring (ed->type),\r
-               le32_to_cpup (&ed->hwNextED));\r
-       switch (tmp & (ED_IN|ED_OUT)) {\r
-       case ED_OUT: type = "-OUT"; break;\r
-       case ED_IN: type = "-IN"; break;\r
-       /* else from TDs ... control */\r
-       }\r
-       ohci_dbg (ohci,\r
-               "  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),\r
-               0x03ff & (le32_to_cpu (tmp) >> 16),\r
-               (tmp & ED_DEQUEUE) ? " DQ" : "",\r
-               (tmp & ED_ISO) ? " ISO" : "",\r
-               (tmp & ED_SKIP) ? " SKIP" : "",\r
-               (tmp & ED_LOWSPEED) ? " LOW" : "",\r
-               0x000f & (le32_to_cpu (tmp) >> 7),\r
-               type,\r
-               0x007f & le32_to_cpu (tmp));\r
-       ohci_dbg (ohci, "  tds: head %08x %s%s tail %08x%s",\r
-               tmp = le32_to_cpup (&ed->hwHeadP),\r
-               (ed->hwHeadP & ED_C) ? data1 : data0,\r
-               (ed->hwHeadP & ED_H) ? " HALT" : "",\r
-               le32_to_cpup (&ed->hwTailP),\r
-               verbose ? "" : " (not listing)");\r
-       if (verbose) {\r
-               struct list_head        *tmp;\r
-\r
-               /* use ed->td_list because HC concurrently modifies\r
-                * hwNextTD as it accumulates ed_donelist.\r
-                */\r
-               list_for_each (tmp, &ed->td_list) {\r
-                       struct td               *td;\r
-                       td = list_entry (tmp, struct td, td_list);\r
-                       ohci_dump_td (ohci, "  ->", td);\r
-               }\r
-       }\r
-}\r
-\r
-#else\r
-static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {}\r
-\r
-#undef OHCI_VERBOSE_DEBUG\r
-\r
-#endif /* DEBUG */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#ifdef STUB_DEBUG_FILES\r
-\r
-static inline void create_debug_files (struct ohci_hcd *bus) { }\r
-static inline void remove_debug_files (struct ohci_hcd *bus) { }\r
-\r
-#else\r
-\r
-static inline struct ohci_hcd *dev_to_ohci (struct device *dev)\r
-{\r
-       struct usb_hcd  *hcd = dev_get_drvdata (dev);\r
-\r
-       return hcd_to_ohci (hcd);\r
-}\r
-\r
-static ssize_t\r
-show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)\r
-{\r
-       unsigned                temp, size = count;\r
-\r
-       if (!ed)\r
-               return 0;\r
-\r
-       /* print first --> last */\r
-       while (ed->ed_prev)\r
-               ed = ed->ed_prev;\r
-\r
-       /* dump a snapshot of the bulk or control schedule */\r
-       while (ed) {\r
-               u32                     info = ed->hwINFO;\r
-               u32                     scratch = cpu_to_le32p (&ed->hwINFO);\r
-               struct list_head        *entry;\r
-               struct td               *td;\r
-\r
-               temp = snprintf (buf, size,\r
-                       "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",\r
-                       ed,\r
-                       (info & ED_LOWSPEED) ? 'l' : 'f',\r
-                       scratch & 0x7f,\r
-                       (scratch >> 7) & 0xf,\r
-                       (info & ED_IN) ? "in" : "out",\r
-                       0x03ff & (scratch >> 16),\r
-                       scratch,\r
-                       (info & ED_SKIP) ? " s" : "",\r
-                       (ed->hwHeadP & ED_H) ? " H" : "",\r
-                       (ed->hwHeadP & ED_C) ? data1 : data0);\r
-               size -= temp;\r
-               buf += temp;\r
-\r
-               list_for_each (entry, &ed->td_list) {\r
-                       u32             cbp, be;\r
-\r
-                       td = list_entry (entry, struct td, td_list);\r
-                       scratch = cpu_to_le32p (&td->hwINFO);\r
-                       cbp = le32_to_cpup (&td->hwCBP);\r
-                       be = le32_to_cpup (&td->hwBE);\r
-                       temp = snprintf (buf, size,\r
-                                       "\n\ttd %p %s %d cc=%x urb %p (%08x)",\r
-                                       td,\r
-                                       ({ char *pid;\r
-                                       switch (scratch & TD_DP) {\r
-                                       case TD_DP_SETUP: pid = "setup"; break;\r
-                                       case TD_DP_IN: pid = "in"; break;\r
-                                       case TD_DP_OUT: pid = "out"; break;\r
-                                       default: pid = "(?)"; break;\r
-                                        } pid;}),\r
-                                       cbp ? (be + 1 - cbp) : 0,\r
-                                       TD_CC_GET (scratch), td->urb, scratch);\r
-                       size -= temp;\r
-                       buf += temp;\r
-               }\r
-\r
-               temp = snprintf (buf, size, "\n");\r
-               size -= temp;\r
-               buf += temp;\r
-\r
-               ed = ed->ed_next;\r
-       }\r
-       return count - size;\r
-}\r
-\r
-static ssize_t\r
-show_async (struct device *dev, char *buf)\r
-{\r
-       struct ohci_hcd         *ohci;\r
-       size_t                  temp;\r
-       unsigned long           flags;\r
-\r
-       ohci = dev_to_ohci(dev);\r
-\r
-       /* display control and bulk lists together, for simplicity */\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail);\r
-       temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail);\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-\r
-       return temp;\r
-}\r
-static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);\r
-\r
-\r
-#define DBG_SCHED_LIMIT 64\r
-\r
-static ssize_t\r
-show_periodic (struct device *dev, char *buf)\r
-{\r
-       struct ohci_hcd         *ohci;\r
-       struct ed               **seen, *ed;\r
-       unsigned long           flags;\r
-       unsigned                temp, size, seen_count;\r
-       char                    *next;\r
-       unsigned                i;\r
-\r
-       if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))\r
-               return 0;\r
-       seen_count = 0;\r
-\r
-       ohci = dev_to_ohci(dev);\r
-       next = buf;\r
-       size = PAGE_SIZE;\r
-\r
-       temp = snprintf (next, size, "size = %d\n", NUM_INTS);\r
-       size -= temp;\r
-       next += temp;\r
-\r
-       /* dump a snapshot of the periodic schedule (and load) */\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       for (i = 0; i < NUM_INTS; i++) {\r
-               if (!(ed = ohci->periodic [i]))\r
-                       continue;\r
-\r
-               temp = snprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);\r
-               size -= temp;\r
-               next += temp;\r
-\r
-               do {\r
-                       temp = snprintf (next, size, " ed%d/%p",\r
-                               ed->interval, ed);\r
-                       size -= temp;\r
-                       next += temp;\r
-                       for (temp = 0; temp < seen_count; temp++) {\r
-                               if (seen [temp] == ed)\r
-                                       break;\r
-                       }\r
-\r
-                       /* show more info the first time around */\r
-                       if (temp == seen_count) {\r
-                               u32     info = ed->hwINFO;\r
-                               u32     scratch = cpu_to_le32p (&ed->hwINFO);\r
-\r
-                               temp = snprintf (next, size,\r
-                                       " (%cs dev%d%s ep%d%s"\r
-                                       " max %d %08x%s%s)",\r
-                                       (info & ED_LOWSPEED) ? 'l' : 'f',\r
-                                       scratch & 0x7f,\r
-                                       (info & ED_ISO) ? " iso" : "",\r
-                                       (scratch >> 7) & 0xf,\r
-                                       (info & ED_IN) ? "in" : "out",\r
-                                       0x03ff & (scratch >> 16),\r
-                                       scratch,\r
-                                       (info & ED_SKIP) ? " s" : "",\r
-                                       (ed->hwHeadP & ED_H) ? " H" : "");\r
-                               size -= temp;\r
-                               next += temp;\r
-\r
-                               // FIXME some TD info too\r
-\r
-                               if (seen_count < DBG_SCHED_LIMIT)\r
-                                       seen [seen_count++] = ed;\r
-\r
-                               ed = ed->ed_next;\r
-\r
-                       } else {\r
-                               /* we've seen it and what's after */\r
-                               temp = 0;\r
-                               ed = 0;\r
-                       }\r
-\r
-               } while (ed);\r
-\r
-               temp = snprintf (next, size, "\n");\r
-               size -= temp;\r
-               next += temp;\r
-       }\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-       kfree (seen);\r
-\r
-       return PAGE_SIZE - size;\r
-}\r
-static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);\r
-\r
-\r
-#undef DBG_SCHED_LIMIT\r
-\r
-static ssize_t\r
-show_registers (struct device *dev, char *buf)\r
-{\r
-       struct ohci_hcd         *ohci;\r
-       struct ohci_regs        *regs;\r
-       unsigned long           flags;\r
-       unsigned                temp, size;\r
-       char                    *next;\r
-       u32                     rdata;\r
-\r
-       ohci = dev_to_ohci(dev);\r
-       regs = ohci->regs;\r
-       next = buf;\r
-       size = PAGE_SIZE;\r
-\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-\r
-       /* dump driver info, then registers in spec order */\r
-\r
-       ohci_dbg_sw (ohci, &next, &size,\r
-               "%s version " DRIVER_VERSION "\n", hcd_name);\r
-\r
-       ohci_dump_status(ohci, &next, &size);\r
-\r
-       /* hcca */\r
-       if (ohci->hcca)\r
-               ohci_dbg_sw (ohci, &next, &size,\r
-                       "hcca frame 0x%04x\n", ohci->hcca->frame_no);\r
-\r
-       /* other registers mostly affect frame timings */\r
-       rdata = readl (&regs->fminterval);\r
-       temp = snprintf (next, size,\r
-                       "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",\r
-                       rdata, (rdata >> 31) ? " FIT" : "",\r
-                       (rdata >> 16) & 0xefff, rdata & 0xffff);\r
-       size -= temp;\r
-       next += temp;\r
-\r
-       rdata = readl (&regs->fmremaining);\r
-       temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",\r
-                       rdata, (rdata >> 31) ? " FRT" : "",\r
-                       rdata & 0x3fff);\r
-       size -= temp;\r
-       next += temp;\r
-\r
-       rdata = readl (&regs->periodicstart);\r
-       temp = snprintf (next, size, "periodicstart 0x%04x\n",\r
-                       rdata & 0x3fff);\r
-       size -= temp;\r
-       next += temp;\r
-\r
-       rdata = readl (&regs->lsthresh);\r
-       temp = snprintf (next, size, "lsthresh 0x%04x\n",\r
-                       rdata & 0x3fff);\r
-       size -= temp;\r
-       next += temp;\r
-\r
-       /* roothub */\r
-       ohci_dump_roothub (ohci, 1, &next, &size);\r
-\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-\r
-       return PAGE_SIZE - size;\r
-}\r
-static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);\r
-\r
-\r
-static inline void create_debug_files (struct ohci_hcd *bus)\r
-{\r
-       device_create_file (bus->hcd.controller, &dev_attr_async);\r
-       device_create_file (bus->hcd.controller, &dev_attr_periodic);\r
-       device_create_file (bus->hcd.controller, &dev_attr_registers);\r
-       ohci_dbg (bus, "created debug files\n");\r
-}\r
-\r
-static inline void remove_debug_files (struct ohci_hcd *bus)\r
-{\r
-       device_remove_file (bus->hcd.controller, &dev_attr_async);\r
-       device_remove_file (bus->hcd.controller, &dev_attr_periodic);\r
-       device_remove_file (bus->hcd.controller, &dev_attr_registers);\r
-}\r
-\r
-#endif\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under the GPL.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+
+#define edstring(ed_type) ({ char *temp; \
+       switch (ed_type) { \
+       case PIPE_CONTROL:      temp = "ctrl"; break; \
+       case PIPE_BULK:         temp = "bulk"; break; \
+       case PIPE_INTERRUPT:    temp = "intr"; break; \
+       default:                temp = "isoc"; break; \
+       }; temp;})
+#define pipestring(pipe) edstring(usb_pipetype(pipe))
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header
+ */
+static void __attribute__((unused))
+urb_print (struct urb * urb, char * str, int small)
+{
+       unsigned int pipe= urb->pipe;
+
+       if (!urb->dev || !urb->dev->bus) {
+               dbg("%s URB: no dev", str);
+               return;
+       }
+
+#ifndef        OHCI_VERBOSE_DEBUG
+       if (urb->status != 0)
+#endif
+       dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
+                   str,
+                   urb,
+                   usb_pipedevice (pipe),
+                   usb_pipeendpoint (pipe),
+                   usb_pipeout (pipe)? "out" : "in",
+                   pipestring (pipe),
+                   urb->transfer_flags,
+                   urb->actual_length,
+                   urb->transfer_buffer_length,
+                   urb->status);
+
+#ifdef OHCI_VERBOSE_DEBUG
+       if (!small) {
+               int i, len;
+
+               if (usb_pipecontrol (pipe)) {
+                       printk (KERN_DEBUG __FILE__ ": setup(8):");
+                       for (i = 0; i < 8 ; i++)
+                               printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+                       printk ("\n");
+               }
+               if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+                       printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
+                               urb->actual_length,
+                               urb->transfer_buffer_length);
+                       len = usb_pipeout (pipe)?
+                                               urb->transfer_buffer_length: urb->actual_length;
+                       for (i = 0; i < 16 && i < len; i++)
+                               printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+                       printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+               }
+       }
+#endif
+}
+
+#define ohci_dbg_sw(ohci, next, size, format, arg...) \
+       do { \
+       if (next) { \
+               unsigned s_len; \
+               s_len = snprintf (*next, *size, format, ## arg ); \
+               *size -= s_len; *next += s_len; \
+       } else \
+               ohci_dbg(ohci,format, ## arg ); \
+       } while (0);
+
+
+static void ohci_dump_intr_mask (
+       struct ohci_hcd *ohci,
+       char *label,
+       u32 mask,
+       char **next,
+       unsigned *size)
+{
+       ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n",
+               label,
+               mask,
+               (mask & OHCI_INTR_MIE) ? " MIE" : "",
+               (mask & OHCI_INTR_OC) ? " OC" : "",
+               (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+               (mask & OHCI_INTR_FNO) ? " FNO" : "",
+               (mask & OHCI_INTR_UE) ? " UE" : "",
+               (mask & OHCI_INTR_RD) ? " RD" : "",
+               (mask & OHCI_INTR_SF) ? " SF" : "",
+               (mask & OHCI_INTR_WDH) ? " WDH" : "",
+               (mask & OHCI_INTR_SO) ? " SO" : ""
+               );
+}
+
+static void maybe_print_eds (
+       struct ohci_hcd *ohci,
+       char *label,
+       u32 value,
+       char **next,
+       unsigned *size)
+{
+       if (value)
+               ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+       switch (state) {
+               case OHCI_USB_RESET:    return "reset";
+               case OHCI_USB_RESUME:   return "resume";
+               case OHCI_USB_OPER:     return "operational";
+               case OHCI_USB_SUSPEND:  return "suspend";
+       }
+       return "?";
+}
+
+// dump control and status registers
+static void
+ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
+{
+       struct ohci_regs        *regs = controller->regs;
+       u32                     temp;
+
+       temp = readl (&regs->revision) & 0xff;
+       ohci_dbg_sw (controller, next, size,
+               "OHCI %d.%d, %s legacy support registers\n",
+               0x03 & (temp >> 4), (temp & 0x0f),
+               (temp & 0x10) ? "with" : "NO");
+
+       temp = readl (&regs->control);
+       ohci_dbg_sw (controller, next, size,
+               "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",
+               temp,
+               (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+               (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+               (temp & OHCI_CTRL_IR) ? " IR" : "",
+               hcfs2string (temp & OHCI_CTRL_HCFS),
+               (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+               (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+               (temp & OHCI_CTRL_IE) ? " IE" : "",
+               (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+               temp & OHCI_CTRL_CBSR
+               );
+
+       temp = readl (&regs->cmdstatus);
+       ohci_dbg_sw (controller, next, size,
+               "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp,
+               (temp & OHCI_SOC) >> 16,
+               (temp & OHCI_OCR) ? " OCR" : "",
+               (temp & OHCI_BLF) ? " BLF" : "",
+               (temp & OHCI_CLF) ? " CLF" : "",
+               (temp & OHCI_HCR) ? " HCR" : ""
+               );
+
+       ohci_dump_intr_mask (controller, "intrstatus",
+                       readl (&regs->intrstatus), next, size);
+       ohci_dump_intr_mask (controller, "intrenable",
+                       readl (&regs->intrenable), next, size);
+       // intrdisable always same as intrenable
+
+       maybe_print_eds (controller, "ed_periodcurrent",
+                       readl (&regs->ed_periodcurrent), next, size);
+
+       maybe_print_eds (controller, "ed_controlhead",
+                       readl (&regs->ed_controlhead), next, size);
+       maybe_print_eds (controller, "ed_controlcurrent",
+                       readl (&regs->ed_controlcurrent), next, size);
+
+       maybe_print_eds (controller, "ed_bulkhead",
+                       readl (&regs->ed_bulkhead), next, size);
+       maybe_print_eds (controller, "ed_bulkcurrent",
+                       readl (&regs->ed_bulkcurrent), next, size);
+
+       maybe_print_eds (controller, "donehead",
+                       readl (&regs->donehead), next, size);
+}
+
+#define dbg_port_sw(hc,num,value,next,size) \
+       ohci_dbg_sw (hc, next, size, \
+               "roothub.portstatus [%d] " \
+               "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
+               num, temp, \
+               (temp & RH_PS_PRSC) ? " PRSC" : "", \
+               (temp & RH_PS_OCIC) ? " OCIC" : "", \
+               (temp & RH_PS_PSSC) ? " PSSC" : "", \
+               (temp & RH_PS_PESC) ? " PESC" : "", \
+               (temp & RH_PS_CSC) ? " CSC" : "", \
+               \
+               (temp & RH_PS_LSDA) ? " LSDA" : "", \
+               (temp & RH_PS_PPS) ? " PPS" : "", \
+               (temp & RH_PS_PRS) ? " PRS" : "", \
+               (temp & RH_PS_POCI) ? " POCI" : "", \
+               (temp & RH_PS_PSS) ? " PSS" : "", \
+               \
+               (temp & RH_PS_PES) ? " PES" : "", \
+               (temp & RH_PS_CCS) ? " CCS" : "" \
+               );
+
+
+static void
+ohci_dump_roothub (
+       struct ohci_hcd *controller,
+       int verbose,
+       char **next,
+       unsigned *size)
+{
+       u32                     temp, ndp, i;
+
+       temp = roothub_a (controller);
+       if (temp == ~(u32)0)
+               return;
+       ndp = (temp & RH_A_NDP);
+
+       if (verbose) {
+               ohci_dbg_sw (controller, next, size,
+                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,
+                       ((temp & RH_A_POTPGT) >> 24) & 0xff,
+                       (temp & RH_A_NOCP) ? " NOCP" : "",
+                       (temp & RH_A_OCPM) ? " OCPM" : "",
+                       (temp & RH_A_DT) ? " DT" : "",
+                       (temp & RH_A_NPS) ? " NPS" : "",
+                       (temp & RH_A_PSM) ? " PSM" : "",
+                       ndp
+                       );
+               temp = roothub_b (controller);
+               ohci_dbg_sw (controller, next, size,
+                       "roothub.b %08x PPCM=%04x DR=%04x\n",
+                       temp,
+                       (temp & RH_B_PPCM) >> 16,
+                       (temp & RH_B_DR)
+                       );
+               temp = roothub_status (controller);
+               ohci_dbg_sw (controller, next, size,
+                       "roothub.status %08x%s%s%s%s%s%s\n",
+                       temp,
+                       (temp & RH_HS_CRWE) ? " CRWE" : "",
+                       (temp & RH_HS_OCIC) ? " OCIC" : "",
+                       (temp & RH_HS_LPSC) ? " LPSC" : "",
+                       (temp & RH_HS_DRWE) ? " DRWE" : "",
+                       (temp & RH_HS_OCI) ? " OCI" : "",
+                       (temp & RH_HS_LPS) ? " LPS" : ""
+                       );
+       }
+
+       for (i = 0; i < ndp; i++) {
+               temp = roothub_portstatus (controller, i);
+               dbg_port_sw (controller, i, temp, next, size);
+       }
+}
+
+static void ohci_dump (struct ohci_hcd *controller, int verbose)
+{
+       ohci_dbg (controller, "OHCI controller state\n");
+
+       // dumps some of the state we know about
+       ohci_dump_status (controller, NULL, 0);
+       if (controller->hcca)
+               ohci_dbg (controller,
+                       "hcca frame #%04x\n", controller->hcca->frame_no);
+       ohci_dump_roothub (controller, 1, NULL, 0);
+}
+
+static const char data0 [] = "DATA0";
+static const char data1 [] = "DATA1";
+
+static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td)
+{
+       u32     tmp = le32_to_cpup (&td->hwINFO);
+
+       ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x",
+               label, td,
+               (tmp & TD_DONE) ? " (DONE)" : "",
+               td->urb, td->index,
+               le32_to_cpup (&td->hwNextTD));
+       if ((tmp & TD_ISO) == 0) {
+               const char      *toggle, *pid;
+               u32     cbp, be;
+
+               switch (tmp & TD_T) {
+               case TD_T_DATA0: toggle = data0; break;
+               case TD_T_DATA1: toggle = data1; break;
+               case TD_T_TOGGLE: toggle = "(CARRY)"; break;
+               default: toggle = "(?)"; break;
+               }
+               switch (tmp & TD_DP) {
+               case TD_DP_SETUP: pid = "SETUP"; break;
+               case TD_DP_IN: pid = "IN"; break;
+               case TD_DP_OUT: pid = "OUT"; break;
+               default: pid = "(bad pid)"; break;
+               }
+               ohci_dbg (ohci, "     info %08x CC=%x %s DI=%d %s %s", tmp,
+                       TD_CC_GET(tmp), /* EC, */ toggle,
+                       (tmp & TD_DI) >> 21, pid,
+                       (tmp & TD_R) ? "R" : "");
+               cbp = le32_to_cpup (&td->hwCBP);
+               be = le32_to_cpup (&td->hwBE);
+               ohci_dbg (ohci, "     cbp %08x be %08x (len %d)", cbp, be,
+                       cbp ? (be + 1 - cbp) : 0);
+       } else {
+               unsigned        i;
+               ohci_dbg (ohci, "     info %08x CC=%x FC=%d DI=%d SF=%04x", tmp,
+                       TD_CC_GET(tmp),
+                       (tmp >> 24) & 0x07,
+                       (tmp & TD_DI) >> 21,
+                       tmp & 0x0000ffff);
+               ohci_dbg (ohci, "     bp0 %08x be %08x",
+                       le32_to_cpup (&td->hwCBP) & ~0x0fff,
+                       le32_to_cpup (&td->hwBE));
+               for (i = 0; i < MAXPSW; i++) {
+                       u16     psw = le16_to_cpup (&td->hwPSW [i]);
+                       int     cc = (psw >> 12) & 0x0f;
+                       ohci_dbg (ohci, "       psw [%d] = %2x, CC=%x %s=%d", i,
+                               psw, cc,
+                               (cc >= 0x0e) ? "OFFSET" : "SIZE",
+                               psw & 0x0fff);
+               }
+       }
+}
+
+/* caller MUST own hcd spinlock if verbose is set! */
+static void __attribute__((unused))
+ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
+{
+       u32     tmp = ed->hwINFO;
+       char    *type = "";
+
+       ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x",
+               label,
+               ed, ed->state, edstring (ed->type),
+               le32_to_cpup (&ed->hwNextED));
+       switch (tmp & (ED_IN|ED_OUT)) {
+       case ED_OUT: type = "-OUT"; break;
+       case ED_IN: type = "-IN"; break;
+       /* else from TDs ... control */
+       }
+       ohci_dbg (ohci,
+               "  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
+               0x03ff & (le32_to_cpu (tmp) >> 16),
+               (tmp & ED_DEQUEUE) ? " DQ" : "",
+               (tmp & ED_ISO) ? " ISO" : "",
+               (tmp & ED_SKIP) ? " SKIP" : "",
+               (tmp & ED_LOWSPEED) ? " LOW" : "",
+               0x000f & (le32_to_cpu (tmp) >> 7),
+               type,
+               0x007f & le32_to_cpu (tmp));
+       ohci_dbg (ohci, "  tds: head %08x %s%s tail %08x%s",
+               tmp = le32_to_cpup (&ed->hwHeadP),
+               (ed->hwHeadP & ED_C) ? data1 : data0,
+               (ed->hwHeadP & ED_H) ? " HALT" : "",
+               le32_to_cpup (&ed->hwTailP),
+               verbose ? "" : " (not listing)");
+       if (verbose) {
+               struct list_head        *tmp;
+
+               /* use ed->td_list because HC concurrently modifies
+                * hwNextTD as it accumulates ed_donelist.
+                */
+               list_for_each (tmp, &ed->td_list) {
+                       struct td               *td;
+                       td = list_entry (tmp, struct td, td_list);
+                       ohci_dump_td (ohci, "  ->", td);
+               }
+       }
+}
+
+#else
+static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {}
+
+#undef OHCI_VERBOSE_DEBUG
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files (struct ohci_hcd *bus) { }
+static inline void remove_debug_files (struct ohci_hcd *bus) { }
+
+#else
+
+static inline struct ohci_hcd *dev_to_ohci (struct device *dev)
+{
+       struct usb_hcd  *hcd = dev_get_drvdata (dev);
+
+       return hcd_to_ohci (hcd);
+}
+
+static ssize_t
+show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
+{
+       unsigned                temp, size = count;
+
+       if (!ed)
+               return 0;
+
+       /* print first --> last */
+       while (ed->ed_prev)
+               ed = ed->ed_prev;
+
+       /* dump a snapshot of the bulk or control schedule */
+       while (ed) {
+               u32                     info = ed->hwINFO;
+               u32                     scratch = cpu_to_le32p (&ed->hwINFO);
+               struct list_head        *entry;
+               struct td               *td;
+
+               temp = snprintf (buf, size,
+                       "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s",
+                       ed,
+                       (info & ED_LOWSPEED) ? 'l' : 'f',
+                       scratch & 0x7f,
+                       (scratch >> 7) & 0xf,
+                       (info & ED_IN) ? "in" : "out",
+                       0x03ff & (scratch >> 16),
+                       scratch,
+                       (info & ED_SKIP) ? " s" : "",
+                       (ed->hwHeadP & ED_H) ? " H" : "",
+                       (ed->hwHeadP & ED_C) ? data1 : data0);
+               size -= temp;
+               buf += temp;
+
+               list_for_each (entry, &ed->td_list) {
+                       u32             cbp, be;
+
+                       td = list_entry (entry, struct td, td_list);
+                       scratch = cpu_to_le32p (&td->hwINFO);
+                       cbp = le32_to_cpup (&td->hwCBP);
+                       be = le32_to_cpup (&td->hwBE);
+                       temp = snprintf (buf, size,
+                                       "\n\ttd %p %s %d cc=%x urb %p (%08x)",
+                                       td,
+                                       ({ char *pid;
+                                       switch (scratch & TD_DP) {
+                                       case TD_DP_SETUP: pid = "setup"; break;
+                                       case TD_DP_IN: pid = "in"; break;
+                                       case TD_DP_OUT: pid = "out"; break;
+                                       default: pid = "(?)"; break;
+                                        } pid;}),
+                                       cbp ? (be + 1 - cbp) : 0,
+                                       TD_CC_GET (scratch), td->urb, scratch);
+                       size -= temp;
+                       buf += temp;
+               }
+
+               temp = snprintf (buf, size, "\n");
+               size -= temp;
+               buf += temp;
+
+               ed = ed->ed_next;
+       }
+       return count - size;
+}
+
+static ssize_t
+show_async (struct device *dev, char *buf)
+{
+       struct ohci_hcd         *ohci;
+       size_t                  temp;
+       unsigned long           flags;
+
+       ohci = dev_to_ohci(dev);
+
+       /* display control and bulk lists together, for simplicity */
+       spin_lock_irqsave (&ohci->lock, flags);
+       temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail);
+       temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail);
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       return temp;
+}
+static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct device *dev, char *buf)
+{
+       struct ohci_hcd         *ohci;
+       struct ed               **seen, *ed;
+       unsigned long           flags;
+       unsigned                temp, size, seen_count;
+       char                    *next;
+       unsigned                i;
+
+       if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+               return 0;
+       seen_count = 0;
+
+       ohci = dev_to_ohci(dev);
+       next = buf;
+       size = PAGE_SIZE;
+
+       temp = snprintf (next, size, "size = %d\n", NUM_INTS);
+       size -= temp;
+       next += temp;
+
+       /* dump a snapshot of the periodic schedule (and load) */
+       spin_lock_irqsave (&ohci->lock, flags);
+       for (i = 0; i < NUM_INTS; i++) {
+               if (!(ed = ohci->periodic [i]))
+                       continue;
+
+               temp = snprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
+               size -= temp;
+               next += temp;
+
+               do {
+                       temp = snprintf (next, size, " ed%d/%p",
+                               ed->interval, ed);
+                       size -= temp;
+                       next += temp;
+                       for (temp = 0; temp < seen_count; temp++) {
+                               if (seen [temp] == ed)
+                                       break;
+                       }
+
+                       /* show more info the first time around */
+                       if (temp == seen_count) {
+                               u32     info = ed->hwINFO;
+                               u32     scratch = cpu_to_le32p (&ed->hwINFO);
+
+                               temp = snprintf (next, size,
+                                       " (%cs dev%d%s ep%d%s"
+                                       " max %d %08x%s%s)",
+                                       (info & ED_LOWSPEED) ? 'l' : 'f',
+                                       scratch & 0x7f,
+                                       (info & ED_ISO) ? " iso" : "",
+                                       (scratch >> 7) & 0xf,
+                                       (info & ED_IN) ? "in" : "out",
+                                       0x03ff & (scratch >> 16),
+                                       scratch,
+                                       (info & ED_SKIP) ? " s" : "",
+                                       (ed->hwHeadP & ED_H) ? " H" : "");
+                               size -= temp;
+                               next += temp;
+
+                               // FIXME some TD info too
+
+                               if (seen_count < DBG_SCHED_LIMIT)
+                                       seen [seen_count++] = ed;
+
+                               ed = ed->ed_next;
+
+                       } else {
+                               /* we've seen it and what's after */
+                               temp = 0;
+                               ed = 0;
+                       }
+
+               } while (ed);
+
+               temp = snprintf (next, size, "\n");
+               size -= temp;
+               next += temp;
+       }
+       spin_unlock_irqrestore (&ohci->lock, flags);
+       kfree (seen);
+
+       return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+
+#undef DBG_SCHED_LIMIT
+
+static ssize_t
+show_registers (struct device *dev, char *buf)
+{
+       struct ohci_hcd         *ohci;
+       struct ohci_regs        *regs;
+       unsigned long           flags;
+       unsigned                temp, size;
+       char                    *next;
+       u32                     rdata;
+
+       ohci = dev_to_ohci(dev);
+       regs = ohci->regs;
+       next = buf;
+       size = PAGE_SIZE;
+
+       spin_lock_irqsave (&ohci->lock, flags);
+
+       /* dump driver info, then registers in spec order */
+
+       ohci_dbg_sw (ohci, &next, &size,
+               "%s version " DRIVER_VERSION "\n", hcd_name);
+
+       ohci_dump_status(ohci, &next, &size);
+
+       /* hcca */
+       if (ohci->hcca)
+               ohci_dbg_sw (ohci, &next, &size,
+                       "hcca frame 0x%04x\n", ohci->hcca->frame_no);
+
+       /* other registers mostly affect frame timings */
+       rdata = readl (&regs->fminterval);
+       temp = snprintf (next, size,
+                       "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
+                       rdata, (rdata >> 31) ? " FIT" : "",
+                       (rdata >> 16) & 0xefff, rdata & 0xffff);
+       size -= temp;
+       next += temp;
+
+       rdata = readl (&regs->fmremaining);
+       temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
+                       rdata, (rdata >> 31) ? " FRT" : "",
+                       rdata & 0x3fff);
+       size -= temp;
+       next += temp;
+
+       rdata = readl (&regs->periodicstart);
+       temp = snprintf (next, size, "periodicstart 0x%04x\n",
+                       rdata & 0x3fff);
+       size -= temp;
+       next += temp;
+
+       rdata = readl (&regs->lsthresh);
+       temp = snprintf (next, size, "lsthresh 0x%04x\n",
+                       rdata & 0x3fff);
+       size -= temp;
+       next += temp;
+
+       /* roothub */
+       ohci_dump_roothub (ohci, 1, &next, &size);
+
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+
+static inline void create_debug_files (struct ohci_hcd *bus)
+{
+       device_create_file (bus->hcd.controller, &dev_attr_async);
+       device_create_file (bus->hcd.controller, &dev_attr_periodic);
+       device_create_file (bus->hcd.controller, &dev_attr_registers);
+       ohci_dbg (bus, "created debug files\n");
+}
+
+static inline void remove_debug_files (struct ohci_hcd *bus)
+{
+       device_remove_file (bus->hcd.controller, &dev_attr_async);
+       device_remove_file (bus->hcd.controller, &dev_attr_periodic);
+       device_remove_file (bus->hcd.controller, &dev_attr_registers);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
index 3470fa9..68c006b 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- *\r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * [ Initialisation is based on Linus'  ]\r
- * [ uhci code and gregs ohci fragments ]\r
- * [ (C) Copyright 1999 Linus Torvalds  ]\r
- * [ (C) Copyright 1999 Gregory P. Smith]\r
- * \r
- * \r
- * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller\r
- * interfaces (though some non-x86 Intel chips use it).  It supports\r
- * smarter hardware than UHCI.  A download link for the spec available\r
- * through the http://www.usb.org website.\r
- *\r
- * History:\r
- * \r
- * 2003/02/24 show registers in sysfs (Kevin Brosius)\r
- *\r
- * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and\r
- *     bandwidth accounting; if debugging, show schedules in driverfs\r
- * 2002/07/19 fixes to management of ED and schedule state.\r
- * 2002/06/09 SA-1111 support (Christopher Hoover)\r
- * 2002/06/01 remember frame when HC won't see EDs any more; use that info\r
- *     to fix urb unlink races caused by interrupt latency assumptions;\r
- *     minor ED field and function naming updates\r
- * 2002/01/18 package as a patch for 2.5.3; this should match the\r
- *     2.4.17 kernel modulo some bugs being fixed.\r
- *\r
- * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes\r
- *     from post-2.4.5 patches.\r
- * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning\r
- * 2001/09/07 match PCI PM changes, errnos from Linus' tree\r
- * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;\r
- *     pbook pci quirks gone (please fix pbook pci sw!) (db)\r
- *\r
- * 2001/04/08 Identify version on module load (gb)\r
- * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);\r
-       pci_map_single (db)\r
- * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)\r
- * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)\r
- *\r
- * 2000/09/26 fixed races in removing the private portion of the urb\r
- * 2000/09/07 disable bulk and control lists when unlinking the last\r
- *     endpoint descriptor in order to avoid unrecoverable errors on\r
- *     the Lucent chips. (rwc@sgi)\r
- * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some\r
- *     urb unlink probs, indentation fixes\r
- * 2000/08/11 various oops fixes mostly affecting iso and cleanup from\r
- *     device unplugs.\r
- * 2000/06/28 use PCI hotplug framework, for better power management\r
- *     and for Cardbus support (David Brownell)\r
- * 2000/earlier:  fixes for NEC/Lucent chips; suspend/resume handling\r
- *     when the controller loses power; handle UE; cleanup; ...\r
- *\r
- * v5.2 1999/12/07 URB 3rd preview, \r
- * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)\r
- * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume \r
- *     i386: HUB, Keyboard, Mouse, Printer \r
- *\r
- * v4.3 1999/10/27 multiple HCs, bulk_request\r
- * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes\r
- * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.\r
- * v4.0 1999/08/18 \r
- * v3.0 1999/06/25 \r
- * v2.1 1999/05/09  code clean up\r
- * v2.0 1999/05/04 \r
- * v1.0 1999/04/27 initial release\r
- *\r
- * This file is licenced under the GPL.\r
- */\r
-\r
-#if 0 \r
-#include <linux/config.h>\r
-\r
-#ifdef CONFIG_USB_DEBUG\r
-#      define DEBUG\r
-#else\r
-#      undef DEBUG\r
-#endif\r
-\r
-\r
-\r
-#include <linux/module.h>\r
-#include <linux/pci.h>\r
-#include <linux/kernel.h>\r
-#include <linux/delay.h>\r
-#include <linux/ioport.h>\r
-#include <linux/sched.h>\r
-#include <linux/slab.h>\r
-#include <linux/smp_lock.h>\r
-#include <linux/errno.h>\r
-#include <linux/init.h>\r
-#include <linux/timer.h>\r
-#include <linux/list.h>\r
-#include <linux/interrupt.h>  /* for in_interrupt () */\r
-#include <linux/usb.h>\r
-#include "../core/hcd.h"\r
-\r
-#include <asm/io.h>\r
-#include <asm/irq.h>\r
-#include <asm/system.h>\r
-#include <asm/unaligned.h>\r
-#include <asm/byteorder.h>\r
-#else\r
-#include "ohci_config.h"\r
-\r
-#include "../usb_wrapper.h"\r
-#include "../core/hcd.h"\r
-\r
-//#define OHCI_VERBOSE_DEBUG\r
-#endif\r
-\r
-/*\r
- * TO DO:\r
- *\r
- *     - "disabled" and "sleeping" should be in hcd->state\r
- *     - lots more testing!!\r
- */\r
-\r
-#define DRIVER_VERSION "2003 Feb 24"\r
-#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"\r
-#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-// #define OHCI_VERBOSE_DEBUG  /* not always helpful */\r
-\r
-/* For initializing controller (mask in an HCFS mode too) */\r
-#define        OHCI_CONTROL_INIT \\r
-        (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE\r
-\r
-#define OHCI_UNLINK_TIMEOUT     (HZ / 10)\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static const char      hcd_name [] = "ohci-hcd";\r
-\r
-#include "ohci.h"\r
-\r
-static inline void disable (struct ohci_hcd *ohci)\r
-{\r
-       ohci->disabled = 1;\r
-       ohci->hcd.state = USB_STATE_HALT;\r
-}\r
-\r
-#include "ohci-hub.c"\r
-#include "ohci-dbg.c"\r
-#include "ohci-mem.c"\r
-#include "ohci-q.c"\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * queue up an urb for anything except the root hub\r
- */\r
-static int ohci_urb_enqueue (\r
-       struct usb_hcd  *hcd,\r
-       struct urb      *urb,\r
-       int             mem_flags\r
-) {\r
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);\r
-       struct ed       *ed;\r
-       urb_priv_t      *urb_priv;\r
-       unsigned int    pipe = urb->pipe;\r
-       int             i, size = 0;\r
-       unsigned long   flags;\r
-       int             retval = 0;\r
-       \r
-#ifdef OHCI_VERBOSE_DEBUG\r
-       urb_print (urb, "SUB", usb_pipein (pipe));\r
-#endif\r
-       \r
-       /* every endpoint has a ed, locate and maybe (re)initialize it */\r
-       if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval)))\r
-               return -ENOMEM;\r
-\r
-       /* for the private part of the URB we need the number of TDs (size) */\r
-       switch (ed->type) {\r
-               case PIPE_CONTROL:\r
-                       /* td_submit_urb() doesn't yet handle these */\r
-                       if (urb->transfer_buffer_length > 4096)\r
-                               return -EMSGSIZE;\r
-\r
-                       /* 1 TD for setup, 1 for ACK, plus ... */\r
-                       size = 2;\r
-                       /* FALLTHROUGH */\r
-               // case PIPE_INTERRUPT:\r
-               // case PIPE_BULK:\r
-               default:\r
-                       /* one TD for every 4096 Bytes (can be upto 8K) */\r
-                       size += urb->transfer_buffer_length / 4096;\r
-                       /* ... and for any remaining bytes ... */\r
-                       if ((urb->transfer_buffer_length % 4096) != 0)\r
-                               size++;\r
-                       /* ... and maybe a zero length packet to wrap it up */\r
-                       if (size == 0)\r
-                               size++;\r
-                       else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0\r
-                               && (urb->transfer_buffer_length\r
-                                       % usb_maxpacket (urb->dev, pipe,\r
-                                               usb_pipeout (pipe))) == 0)\r
-                               size++;\r
-                       break;\r
-               case PIPE_ISOCHRONOUS: /* number of packets from URB */\r
-                       size = urb->number_of_packets;\r
-                       break;\r
-       }\r
-\r
-       /* allocate the private part of the URB */\r
-       urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),\r
-                       mem_flags);\r
-       if (!urb_priv)\r
-               return -ENOMEM;\r
-       memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));\r
-\r
-       /* fill the private part of the URB */\r
-       urb_priv->length = size;\r
-       urb_priv->ed = ed;      \r
-\r
-       /* allocate the TDs (deferring hash chain updates) */\r
-       for (i = 0; i < size; i++) {\r
-               urb_priv->td [i] = td_alloc (ohci, mem_flags);\r
-               if (!urb_priv->td [i]) {\r
-                       urb_priv->length = i;\r
-                       urb_free_priv (ohci, urb_priv);\r
-                       return -ENOMEM;\r
-               }\r
-       }       \r
-\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-\r
-       /* don't submit to a dead HC */\r
-       if (ohci->disabled || ohci->sleeping) {\r
-               retval = -ENODEV;\r
-               goto fail;\r
-       }\r
-\r
-       /* schedule the ed if needed */\r
-       if (ed->state == ED_IDLE) {\r
-               retval = ed_schedule (ohci, ed);\r
-               if (retval < 0)\r
-                       goto fail;\r
-               if (ed->type == PIPE_ISOCHRONOUS) {\r
-                       u16     frame = le16_to_cpu (ohci->hcca->frame_no);\r
-\r
-                       /* delay a few frames before the first TD */\r
-                       frame += max_t (u16, 8, ed->interval);\r
-                       frame &= ~(ed->interval - 1);\r
-                       frame |= ed->branch;\r
-                       urb->start_frame = frame;\r
-\r
-                       /* yes, only URB_ISO_ASAP is supported, and\r
-                        * urb->start_frame is never used as input.\r
-                        */\r
-               }\r
-       } else if (ed->type == PIPE_ISOCHRONOUS)\r
-               urb->start_frame = ed->last_iso + ed->interval;\r
-\r
-       /* fill the TDs and link them to the ed; and\r
-        * enable that part of the schedule, if needed\r
-        * and update count of queued periodic urbs\r
-        */\r
-       urb->hcpriv = urb_priv;\r
-       td_submit_urb (ohci, urb);\r
-\r
-fail:\r
-       if (retval)\r
-               urb_free_priv (ohci, urb_priv);\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-       return retval;\r
-}\r
-\r
-/*\r
- * decouple the URB from the HC queues (TDs, urb_priv); it's\r
- * already marked using urb->status.  reporting is always done\r
- * asynchronously, and we might be dealing with an urb that's\r
- * partially transferred, or an ED with other urbs being unlinked.\r
- */\r
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       unsigned long           flags;\r
-       \r
-#ifdef OHCI_VERBOSE_DEBUG\r
-       urb_print (urb, "UNLINK", 1);\r
-#endif           \r
-\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       if (!ohci->disabled) {\r
-               urb_priv_t  *urb_priv;\r
-\r
-               /* Unless an IRQ completed the unlink while it was being\r
-                * handed to us, flag it for unlink and giveback, and force\r
-                * some upcoming INTR_SF to call finish_unlinks()\r
-                */\r
-               urb_priv = urb->hcpriv;\r
-               if (urb_priv) {\r
-                       urb_priv->state = URB_DEL; \r
-                       if (urb_priv->ed->state == ED_OPER)\r
-                               start_urb_unlink (ohci, urb_priv->ed);\r
-               }\r
-       } else {\r
-               /*\r
-                * with HC dead, we won't respect hc queue pointers\r
-                * any more ... just clean up every urb's memory.\r
-                */\r
-               if (urb->hcpriv) {\r
-                       spin_unlock (&ohci->lock);\r
-                       finish_urb (ohci, urb, NULL);\r
-                       spin_lock (&ohci->lock);\r
-               }\r
-       }\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-       return 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* frees config/altsetting state for endpoints,\r
- * including ED memory, dummy TD, and bulk/intr data toggle\r
- */\r
-\r
-static void\r
-ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       int                     epnum = ep & USB_ENDPOINT_NUMBER_MASK;\r
-       unsigned long           flags;\r
-       struct ed               *ed;\r
-\r
-       /* ASSERT:  any requests/urbs are being unlinked */\r
-       /* ASSERT:  nobody can be submitting urbs for this any more */\r
-\r
-       epnum <<= 1;\r
-       if (epnum != 0 && !(ep & USB_DIR_IN))\r
-               epnum |= 1;\r
-\r
-rescan:\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       ed = dev->ep [epnum];\r
-       if (!ed)\r
-               goto done;\r
-\r
-       if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled)\r
-               ed->state = ED_IDLE;\r
-       switch (ed->state) {\r
-       case ED_UNLINK:         /* wait for hw to finish? */\r
-               spin_unlock_irqrestore (&ohci->lock, flags);\r
-               set_current_state (TASK_UNINTERRUPTIBLE);\r
-               schedule_timeout (1);\r
-               goto rescan;\r
-       case ED_IDLE:           /* fully unlinked */\r
-               if (list_empty (&ed->td_list)) {\r
-                       td_free (ohci, ed->dummy);\r
-                       ed_free (ohci, ed);\r
-                       break;\r
-               }\r
-               /* else FALL THROUGH */\r
-       default:\r
-               /* caller was supposed to have unlinked any requests;\r
-                * that's not our job.  can't recover; must leak ed.\r
-                */\r
-               ohci_err (ohci, "ed %p (#%d) state %d%s\n",\r
-                       ed, epnum, ed->state,\r
-                       list_empty (&ed->td_list) ? "" : "(has tds)");\r
-               td_free (ohci, ed->dummy);\r
-               break;\r
-       }\r
-       dev->ep [epnum] = 0;\r
-done:\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-       return;\r
-}\r
-\r
-static int ohci_get_frame (struct usb_hcd *hcd)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-\r
-       return le16_to_cpu (ohci->hcca->frame_no);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*\r
- * HC functions\r
- *-------------------------------------------------------------------------*/\r
-\r
-/* reset the HC and BUS */\r
-\r
-static int hc_reset (struct ohci_hcd *ohci)\r
-{\r
-       u32 temp;\r
-       u32 ints;\r
-       u32 control;\r
-       \r
-       /* Disable HC interrupts */\r
-       writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);\r
-       // acknowledge all pending interrupts\r
-       ints = readl(&ohci->regs->intrstatus);\r
-       writel (ints, &ohci->regs->intrstatus);\r
-\r
-       if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {\r
-               // takeover without negotiation - there is noone to negotiate with\r
-               control = readl (&ohci->regs->control) & ~OHCI_CTRL_IR;\r
-               writel (control, &ohci->regs->control);\r
-       }\r
-\r
-       ohci_dbg (ohci, "USB HC reset_hc %s: ctrl = 0x%x ;\n",\r
-               hcd_to_bus (&ohci->hcd)->bus_name,\r
-               readl (&ohci->regs->control));\r
-\r
-       /* Reset USB (needed by some controllers); RemoteWakeupConnected\r
-        * saved if boot firmware (BIOS/SMM/...) told us it's connected\r
-        */\r
-       ohci->hc_control = readl (&ohci->regs->control);\r
-       ohci->hc_control &= OHCI_CTRL_RWC;      /* hcfs 0 = RESET */\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-       // flush those pci writes\r
-       (void) readl (&ohci->regs->control);\r
-       wait_ms (50);\r
-\r
-       /* HC Reset requires max 10 us delay */\r
-       writel (OHCI_HCR,  &ohci->regs->cmdstatus);\r
-       temp = 30;      /* ... allow extra time */\r
-       while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {\r
-               if (--temp == 0) {\r
-                       ohci_err (ohci, "USB HC reset timed out!\n");\r
-                       return -1;\r
-               }\r
-               udelay (1);\r
-       }\r
-\r
-       /* now we're in the SUSPEND state ... must go OPERATIONAL\r
-        * within 2msec else HC enters RESUME\r
-        *\r
-        * ... but some hardware won't init fmInterval "by the book"\r
-        * (SiS, OPTi ...), so reset again instead.  SiS doesn't need\r
-        * this if we write fmInterval after we're OPERATIONAL.\r
-        */\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-       // flush those pci writes\r
-       (void) readl (&ohci->regs->control);\r
-\r
-       return 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#define        FI              0x2edf          /* 12000 bits per frame (-1) */\r
-#define LSTHRESH       0x628           /* lowspeed bit threshold */\r
-\r
-/* Start an OHCI controller, set the BUS operational\r
- * enable interrupts \r
- * connect the virtual root hub\r
- */\r
-static int hc_start (struct ohci_hcd *ohci)\r
-{\r
-       u32                     mask, tmp;\r
-       struct usb_device       *udev;\r
-       struct usb_bus          *bus;\r
-\r
-       spin_lock_init (&ohci->lock);\r
-       ohci->disabled = 1;\r
-       ohci->sleeping = 0;\r
-\r
-       /* Tell the controller where the control and bulk lists are\r
-        * The lists are empty now. */\r
-       writel (0, &ohci->regs->ed_controlhead);\r
-       writel (0, &ohci->regs->ed_bulkhead);\r
-\r
-       /* a reset clears this */\r
-       writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);\r
-       usbprintk("HCCA: %p \n",ohci->regs->hcca);\r
-\r
-       /* force default fmInterval (we won't adjust it); init thresholds\r
-        * for last FS and LS packets, reserve 90% for periodic.\r
-        */\r
-       writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval);\r
-       writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart);\r
-       writel (LSTHRESH, &ohci->regs->lsthresh);\r
-\r
-       /* some OHCI implementations are finicky about how they init.\r
-        * bogus values here mean not even enumeration could work.\r
-        */\r
-       if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0\r
-                       || !readl (&ohci->regs->periodicstart)) {\r
-               ohci_err (ohci, "init err\n");\r
-               return -EOVERFLOW;\r
-       }\r
-\r
-       /* start controller operations */\r
-       ohci->hc_control &= OHCI_CTRL_RWC;\r
-       ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;\r
-       ohci->disabled = 0;\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-\r
-       /* Choose the interrupts we care about now, others later on demand */\r
-       mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;\r
-       writel (mask, &ohci->regs->intrstatus);\r
-       writel (mask, &ohci->regs->intrenable);\r
-\r
-       /* handle root hub init quirks ... */\r
-       tmp = roothub_a (ohci);\r
-       tmp &= ~(RH_A_PSM | RH_A_OCPM);\r
-       if (ohci->flags & OHCI_QUIRK_SUPERIO) {\r
-               /* NSC 87560 and maybe others */\r
-               tmp |= RH_A_NOCP;\r
-               tmp &= ~(RH_A_POTPGT | RH_A_NPS);\r
-       } else {\r
-               /* hub power always on; required for AMD-756 and some\r
-                * Mac platforms, use this mode everywhere by default\r
-                */\r
-               tmp |= RH_A_NPS;\r
-       }\r
-       writel (tmp, &ohci->regs->roothub.a);\r
-       writel (RH_HS_LPSC, &ohci->regs->roothub.status);\r
-       writel (0, &ohci->regs->roothub.b);\r
-       // flush those pci writes\r
-       (void) readl (&ohci->regs->control);\r
-\r
-       // POTPGT delay is bits 24-31, in 2 ms units.\r
-       mdelay ((roothub_a (ohci) >> 23) & 0x1fe);\r
\r
-       /* connect the virtual root hub */\r
-       bus = hcd_to_bus (&ohci->hcd);\r
-       bus->root_hub = udev = usb_alloc_dev (NULL, bus);\r
-       ohci->hcd.state = USB_STATE_READY;\r
-       if (!udev) {\r
-               disable (ohci);\r
-               ohci->hc_control &= ~OHCI_CTRL_HCFS;\r
-               writel (ohci->hc_control, &ohci->regs->control);\r
-               ohci_err(ohci,"out of mem");\r
-               return -ENOMEM;\r
-       }\r
-\r
-       usb_connect (udev);\r
-       udev->speed = USB_SPEED_FULL;\r
-       if (hcd_register_root (&ohci->hcd) != 0) {\r
-               usb_put_dev (udev);\r
-               bus->root_hub = NULL;\r
-               disable (ohci);\r
-               ohci->hc_control &= ~OHCI_CTRL_HCFS;\r
-               writel (ohci->hc_control, &ohci->regs->control);\r
-               return -ENODEV;\r
-       }\r
-       create_debug_files (ohci);\r
-       return 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* an interrupt happens */\r
-\r
-static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       struct ohci_regs        *regs = ohci->regs;\r
-       int                     ints; \r
-\r
-       /* we can eliminate a (slow) readl() if _only_ WDH caused this irq */\r
-       if ((ohci->hcca->done_head != 0)\r
-                       && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {\r
-               ints =  OHCI_INTR_WDH;\r
-\r
-       /* cardbus/... hardware gone before remove() */\r
-       } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {\r
-               disable (ohci);\r
-               ohci_dbg (ohci, "device removed!\n");\r
-               return;\r
-\r
-       /* interrupt for some other device? */\r
-       } else if ((ints &= readl (&regs->intrenable)) == 0) {\r
-               return;\r
-       } \r
-\r
-       if (ints & OHCI_INTR_UE) {\r
-               disable (ohci);\r
-               ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");\r
-               // e.g. due to PCI Master/Target Abort\r
-\r
-               ohci_dump (ohci, 1);\r
-               hc_reset (ohci);\r
-       }\r
-  \r
-       if (ints & OHCI_INTR_WDH) {\r
-               writel (OHCI_INTR_WDH, &regs->intrdisable);     \r
-               dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);\r
-               writel (OHCI_INTR_WDH, &regs->intrenable); \r
-       }\r
-  \r
-       /* could track INTR_SO to reduce available PCI/... bandwidth */\r
-\r
-       /* handle any pending URB/ED unlinks, leaving INTR_SF enabled\r
-        * when there's still unlinking to be done (next frame).\r
-        */\r
-       spin_lock (&ohci->lock);\r
-       if (ohci->ed_rm_list)\r
-               finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),\r
-                               ptregs);\r
-       if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list)\r
-               writel (OHCI_INTR_SF, &regs->intrdisable);      \r
-       spin_unlock (&ohci->lock);\r
-\r
-       writel (ints, &regs->intrstatus);\r
-       writel (OHCI_INTR_MIE, &regs->intrenable);      \r
-       // flush those pci writes\r
-       (void) readl (&ohci->regs->control);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static void ohci_stop (struct usb_hcd *hcd)\r
-{      \r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       struct ohci_regs        *regs = ohci->regs;\r
-       int ints;\r
-\r
-       ohci_dbg (ohci, "stop %s controller%s\n",\r
-               hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),\r
-               ohci->disabled ? " (disabled)" : ""\r
-               );\r
-       ohci_dump (ohci, 1);\r
-\r
-       if (!ohci->disabled)\r
-               hc_reset (ohci);\r
-\r
-       // Disable all interrupts\r
-       writel (OHCI_INTR_MIE, &regs->intrdisable);     \r
-       // acknowledge all pending interrupts\r
-       ints = readl(&regs->intrstatus);\r
-       writel (ints, &regs->intrstatus);\r
-       // flush register writes\r
-       (void) readl (&ohci->regs->control);\r
-       \r
-       remove_debug_files (ohci);\r
-       ohci_mem_cleanup (ohci);\r
-       if (ohci->hcca) {\r
-               pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,\r
-                                       ohci->hcca, ohci->hcca_dma);\r
-               ohci->hcca = NULL;\r
-               ohci->hcca_dma = 0;\r
-       }\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-// FIXME:  this restart logic should be generic,\r
-// and handle full hcd state cleanup\r
-\r
-/* controller died; cleanup debris, then restart */\r
-/* must not be called from interrupt context */\r
-\r
-#ifdef CONFIG_PM\r
-static int hc_restart (struct ohci_hcd *ohci)\r
-{\r
-       int temp;\r
-       int i;\r
-\r
-       ohci->disabled = 1;\r
-       ohci->sleeping = 0;\r
-       if (hcd_to_bus (&ohci->hcd)->root_hub)\r
-               usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);\r
-       \r
-       /* empty the interrupt branches */\r
-       for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;\r
-       for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;\r
-       \r
-       /* no EDs to remove */\r
-       ohci->ed_rm_list = NULL;\r
-\r
-       /* empty control and bulk lists */       \r
-       ohci->ed_controltail = NULL;\r
-       ohci->ed_bulktail    = NULL;\r
-\r
-       if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {\r
-               ohci_err (ohci, "can't restart, %d\n", temp);\r
-               return temp;\r
-       } else\r
-               ohci_dbg (ohci, "restart complete\n");\r
-       return 0;\r
-}\r
-#endif\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC\r
-\r
-MODULE_AUTHOR (DRIVER_AUTHOR);\r
-MODULE_DESCRIPTION (DRIVER_INFO);\r
-MODULE_LICENSE ("GPL");\r
-\r
-#ifdef CONFIG_PCI\r
-#include "ohci-pci.c"\r
-#endif\r
-\r
-#ifdef CONFIG_SA1111\r
-#include "ohci-sa1111.c"\r
-#endif\r
-\r
-#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111))\r
-#error "missing bus glue for ohci-hcd"\r
-#endif\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * 
+ * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller
+ * interfaces (though some non-x86 Intel chips use it).  It supports
+ * smarter hardware than UHCI.  A download link for the spec available
+ * through the http://www.usb.org website.
+ *
+ * History:
+ * 
+ * 2003/02/24 show registers in sysfs (Kevin Brosius)
+ *
+ * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
+ *     bandwidth accounting; if debugging, show schedules in driverfs
+ * 2002/07/19 fixes to management of ED and schedule state.
+ * 2002/06/09 SA-1111 support (Christopher Hoover)
+ * 2002/06/01 remember frame when HC won't see EDs any more; use that info
+ *     to fix urb unlink races caused by interrupt latency assumptions;
+ *     minor ED field and function naming updates
+ * 2002/01/18 package as a patch for 2.5.3; this should match the
+ *     2.4.17 kernel modulo some bugs being fixed.
+ *
+ * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
+ *     from post-2.4.5 patches.
+ * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning
+ * 2001/09/07 match PCI PM changes, errnos from Linus' tree
+ * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
+ *     pbook pci quirks gone (please fix pbook pci sw!) (db)
+ *
+ * 2001/04/08 Identify version on module load (gb)
+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
+       pci_map_single (db)
+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
+ *
+ * 2000/09/26 fixed races in removing the private portion of the urb
+ * 2000/09/07 disable bulk and control lists when unlinking the last
+ *     endpoint descriptor in order to avoid unrecoverable errors on
+ *     the Lucent chips. (rwc@sgi)
+ * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
+ *     urb unlink probs, indentation fixes
+ * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
+ *     device unplugs.
+ * 2000/06/28 use PCI hotplug framework, for better power management
+ *     and for Cardbus support (David Brownell)
+ * 2000/earlier:  fixes for NEC/Lucent chips; suspend/resume handling
+ *     when the controller loses power; handle UE; cleanup; ...
+ *
+ * v5.2 1999/12/07 URB 3rd preview, 
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
+ *     i386: HUB, Keyboard, Mouse, Printer 
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
+ * v3.0 1999/06/25 
+ * v2.1 1999/05/09  code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27 initial release
+ *
+ * This file is licenced under the GPL.
+ */
+
+#if 0 
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+#      define DEBUG
+#else
+#      undef DEBUG
+#endif
+
+
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>  /* for in_interrupt () */
+#include <linux/usb.h>
+#include "../core/hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#else
+#include "ohci_config.h"
+
+#include "../usb_wrapper.h"
+#include "../core/hcd.h"
+
+//#define OHCI_VERBOSE_DEBUG
+#endif
+
+/*
+ * TO DO:
+ *
+ *     - "disabled" and "sleeping" should be in hcd->state
+ *     - lots more testing!!
+ */
+
+#define DRIVER_VERSION "2003 Feb 24"
+#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
+#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
+
+/*-------------------------------------------------------------------------*/
+
+// #define OHCI_VERBOSE_DEBUG  /* not always helpful */
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define        OHCI_CONTROL_INIT \
+        (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define OHCI_UNLINK_TIMEOUT     (HZ / 10)
+
+/*-------------------------------------------------------------------------*/
+
+static const char      hcd_name [] = "ohci-hcd";
+
+#include "ohci.h"
+
+static inline void disable (struct ohci_hcd *ohci)
+{
+       ohci->disabled = 1;
+       ohci->hcd.state = USB_STATE_HALT;
+}
+
+#include "ohci-hub.c"
+#include "ohci-dbg.c"
+#include "ohci-mem.c"
+#include "ohci-q.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * queue up an urb for anything except the root hub
+ */
+static int ohci_urb_enqueue (
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       int             mem_flags
+) {
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       struct ed       *ed;
+       urb_priv_t      *urb_priv;
+       unsigned int    pipe = urb->pipe;
+       int             i, size = 0;
+       unsigned long   flags;
+       int             retval = 0;
+       
+#ifdef OHCI_VERBOSE_DEBUG
+       urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+       
+       /* every endpoint has a ed, locate and maybe (re)initialize it */
+       if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval)))
+               return -ENOMEM;
+
+       /* for the private part of the URB we need the number of TDs (size) */
+       switch (ed->type) {
+               case PIPE_CONTROL:
+                       /* td_submit_urb() doesn't yet handle these */
+                       if (urb->transfer_buffer_length > 4096)
+                               return -EMSGSIZE;
+
+                       /* 1 TD for setup, 1 for ACK, plus ... */
+                       size = 2;
+                       /* FALLTHROUGH */
+               // case PIPE_INTERRUPT:
+               // case PIPE_BULK:
+               default:
+                       /* one TD for every 4096 Bytes (can be upto 8K) */
+                       size += urb->transfer_buffer_length / 4096;
+                       /* ... and for any remaining bytes ... */
+                       if ((urb->transfer_buffer_length % 4096) != 0)
+                               size++;
+                       /* ... and maybe a zero length packet to wrap it up */
+                       if (size == 0)
+                               size++;
+                       else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
+                               && (urb->transfer_buffer_length
+                                       % usb_maxpacket (urb->dev, pipe,
+                                               usb_pipeout (pipe))) == 0)
+                               size++;
+                       break;
+               case PIPE_ISOCHRONOUS: /* number of packets from URB */
+                       size = urb->number_of_packets;
+                       break;
+       }
+
+       /* allocate the private part of the URB */
+       urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+                       mem_flags);
+       if (!urb_priv)
+               return -ENOMEM;
+       memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
+
+       /* fill the private part of the URB */
+       urb_priv->length = size;
+       urb_priv->ed = ed;      
+
+       /* allocate the TDs (deferring hash chain updates) */
+       for (i = 0; i < size; i++) {
+               urb_priv->td [i] = td_alloc (ohci, mem_flags);
+               if (!urb_priv->td [i]) {
+                       urb_priv->length = i;
+                       urb_free_priv (ohci, urb_priv);
+                       return -ENOMEM;
+               }
+       }       
+
+       spin_lock_irqsave (&ohci->lock, flags);
+
+       /* don't submit to a dead HC */
+       if (ohci->disabled || ohci->sleeping) {
+               retval = -ENODEV;
+               goto fail;
+       }
+
+       /* schedule the ed if needed */
+       if (ed->state == ED_IDLE) {
+               retval = ed_schedule (ohci, ed);
+               if (retval < 0)
+                       goto fail;
+               if (ed->type == PIPE_ISOCHRONOUS) {
+                       u16     frame = le16_to_cpu (ohci->hcca->frame_no);
+
+                       /* delay a few frames before the first TD */
+                       frame += max_t (u16, 8, ed->interval);
+                       frame &= ~(ed->interval - 1);
+                       frame |= ed->branch;
+                       urb->start_frame = frame;
+
+                       /* yes, only URB_ISO_ASAP is supported, and
+                        * urb->start_frame is never used as input.
+                        */
+               }
+       } else if (ed->type == PIPE_ISOCHRONOUS)
+               urb->start_frame = ed->last_iso + ed->interval;
+
+       /* fill the TDs and link them to the ed; and
+        * enable that part of the schedule, if needed
+        * and update count of queued periodic urbs
+        */
+       urb->hcpriv = urb_priv;
+       td_submit_urb (ohci, urb);
+
+fail:
+       if (retval)
+               urb_free_priv (ohci, urb_priv);
+       spin_unlock_irqrestore (&ohci->lock, flags);
+       return retval;
+}
+
+/*
+ * decouple the URB from the HC queues (TDs, urb_priv); it's
+ * already marked using urb->status.  reporting is always done
+ * asynchronously, and we might be dealing with an urb that's
+ * partially transferred, or an ED with other urbs being unlinked.
+ */
+static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       unsigned long           flags;
+       
+#ifdef OHCI_VERBOSE_DEBUG
+       urb_print (urb, "UNLINK", 1);
+#endif           
+
+       spin_lock_irqsave (&ohci->lock, flags);
+       if (!ohci->disabled) {
+               urb_priv_t  *urb_priv;
+
+               /* Unless an IRQ completed the unlink while it was being
+                * handed to us, flag it for unlink and giveback, and force
+                * some upcoming INTR_SF to call finish_unlinks()
+                */
+               urb_priv = urb->hcpriv;
+               if (urb_priv) {
+                       urb_priv->state = URB_DEL; 
+                       if (urb_priv->ed->state == ED_OPER)
+                               start_urb_unlink (ohci, urb_priv->ed);
+               }
+       } else {
+               /*
+                * with HC dead, we won't respect hc queue pointers
+                * any more ... just clean up every urb's memory.
+                */
+               if (urb->hcpriv) {
+                       spin_unlock (&ohci->lock);
+                       finish_urb (ohci, urb, NULL);
+                       spin_lock (&ohci->lock);
+               }
+       }
+       spin_unlock_irqrestore (&ohci->lock, flags);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* frees config/altsetting state for endpoints,
+ * including ED memory, dummy TD, and bulk/intr data toggle
+ */
+
+static void
+ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       int                     epnum = ep & USB_ENDPOINT_NUMBER_MASK;
+       unsigned long           flags;
+       struct ed               *ed;
+
+       /* ASSERT:  any requests/urbs are being unlinked */
+       /* ASSERT:  nobody can be submitting urbs for this any more */
+
+       epnum <<= 1;
+       if (epnum != 0 && !(ep & USB_DIR_IN))
+               epnum |= 1;
+
+rescan:
+       spin_lock_irqsave (&ohci->lock, flags);
+       ed = dev->ep [epnum];
+       if (!ed)
+               goto done;
+
+       if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled)
+               ed->state = ED_IDLE;
+       switch (ed->state) {
+       case ED_UNLINK:         /* wait for hw to finish? */
+               spin_unlock_irqrestore (&ohci->lock, flags);
+               set_current_state (TASK_UNINTERRUPTIBLE);
+               schedule_timeout (1);
+               goto rescan;
+       case ED_IDLE:           /* fully unlinked */
+               if (list_empty (&ed->td_list)) {
+                       td_free (ohci, ed->dummy);
+                       ed_free (ohci, ed);
+                       break;
+               }
+               /* else FALL THROUGH */
+       default:
+               /* caller was supposed to have unlinked any requests;
+                * that's not our job.  can't recover; must leak ed.
+                */
+               ohci_err (ohci, "ed %p (#%d) state %d%s\n",
+                       ed, epnum, ed->state,
+                       list_empty (&ed->td_list) ? "" : "(has tds)");
+               td_free (ohci, ed->dummy);
+               break;
+       }
+       dev->ep [epnum] = 0;
+done:
+       spin_unlock_irqrestore (&ohci->lock, flags);
+       return;
+}
+
+static int ohci_get_frame (struct usb_hcd *hcd)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+
+       return le16_to_cpu (ohci->hcca->frame_no);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (struct ohci_hcd *ohci)
+{
+       u32 temp;
+       u32 ints;
+       u32 control;
+       
+       /* Disable HC interrupts */
+       writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       // acknowledge all pending interrupts
+       ints = readl(&ohci->regs->intrstatus);
+       writel (ints, &ohci->regs->intrstatus);
+
+       if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+               // takeover without negotiation - there is noone to negotiate with
+               control = readl (&ohci->regs->control) & ~OHCI_CTRL_IR;
+               writel (control, &ohci->regs->control);
+       }
+
+       ohci_dbg (ohci, "USB HC reset_hc %s: ctrl = 0x%x ;\n",
+               hcd_to_bus (&ohci->hcd)->bus_name,
+               readl (&ohci->regs->control));
+
+       /* Reset USB (needed by some controllers); RemoteWakeupConnected
+        * saved if boot firmware (BIOS/SMM/...) told us it's connected
+        */
+       ohci->hc_control = readl (&ohci->regs->control);
+       ohci->hc_control &= OHCI_CTRL_RWC;      /* hcfs 0 = RESET */
+       writel (ohci->hc_control, &ohci->regs->control);
+       // flush those pci writes
+       (void) readl (&ohci->regs->control);
+       wait_ms (50);
+
+       /* HC Reset requires max 10 us delay */
+       writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+       temp = 30;      /* ... allow extra time */
+       while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+               if (--temp == 0) {
+                       ohci_err (ohci, "USB HC reset timed out!\n");
+                       return -1;
+               }
+               udelay (1);
+       }
+
+       /* now we're in the SUSPEND state ... must go OPERATIONAL
+        * within 2msec else HC enters RESUME
+        *
+        * ... but some hardware won't init fmInterval "by the book"
+        * (SiS, OPTi ...), so reset again instead.  SiS doesn't need
+        * this if we write fmInterval after we're OPERATIONAL.
+        */
+       writel (ohci->hc_control, &ohci->regs->control);
+       // flush those pci writes
+       (void) readl (&ohci->regs->control);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define        FI              0x2edf          /* 12000 bits per frame (-1) */
+#define LSTHRESH       0x628           /* lowspeed bit threshold */
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts 
+ * connect the virtual root hub
+ */
+static int hc_start (struct ohci_hcd *ohci)
+{
+       u32                     mask, tmp;
+       struct usb_device       *udev;
+       struct usb_bus          *bus;
+
+       spin_lock_init (&ohci->lock);
+       ohci->disabled = 1;
+       ohci->sleeping = 0;
+
+       /* Tell the controller where the control and bulk lists are
+        * The lists are empty now. */
+       writel (0, &ohci->regs->ed_controlhead);
+       writel (0, &ohci->regs->ed_bulkhead);
+
+       /* a reset clears this */
+       writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
+       usbprintk("HCCA: %p \n",ohci->regs->hcca);
+
+       /* force default fmInterval (we won't adjust it); init thresholds
+        * for last FS and LS packets, reserve 90% for periodic.
+        */
+       writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval);
+       writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart);
+       writel (LSTHRESH, &ohci->regs->lsthresh);
+
+       /* some OHCI implementations are finicky about how they init.
+        * bogus values here mean not even enumeration could work.
+        */
+       if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0
+                       || !readl (&ohci->regs->periodicstart)) {
+               ohci_err (ohci, "init err\n");
+               return -EOVERFLOW;
+       }
+
+       /* start controller operations */
+       ohci->hc_control &= OHCI_CTRL_RWC;
+       ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+       ohci->disabled = 0;
+       writel (ohci->hc_control, &ohci->regs->control);
+
+       /* Choose the interrupts we care about now, others later on demand */
+       mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
+       writel (mask, &ohci->regs->intrstatus);
+       writel (mask, &ohci->regs->intrenable);
+
+       /* handle root hub init quirks ... */
+       tmp = roothub_a (ohci);
+       tmp &= ~(RH_A_PSM | RH_A_OCPM);
+       if (ohci->flags & OHCI_QUIRK_SUPERIO) {
+               /* NSC 87560 and maybe others */
+               tmp |= RH_A_NOCP;
+               tmp &= ~(RH_A_POTPGT | RH_A_NPS);
+       } else {
+               /* hub power always on; required for AMD-756 and some
+                * Mac platforms, use this mode everywhere by default
+                */
+               tmp |= RH_A_NPS;
+       }
+       writel (tmp, &ohci->regs->roothub.a);
+       writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+       writel (0, &ohci->regs->roothub.b);
+       // flush those pci writes
+       (void) readl (&ohci->regs->control);
+
+       // POTPGT delay is bits 24-31, in 2 ms units.
+       mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+       /* connect the virtual root hub */
+       bus = hcd_to_bus (&ohci->hcd);
+       bus->root_hub = udev = usb_alloc_dev (NULL, bus);
+       ohci->hcd.state = USB_STATE_READY;
+       if (!udev) {
+               disable (ohci);
+               ohci->hc_control &= ~OHCI_CTRL_HCFS;
+               writel (ohci->hc_control, &ohci->regs->control);
+               ohci_err(ohci,"out of mem");
+               return -ENOMEM;
+       }
+
+       usb_connect (udev);
+       udev->speed = USB_SPEED_FULL;
+       if (hcd_register_root (&ohci->hcd) != 0) {
+               usb_put_dev (udev);
+               bus->root_hub = NULL;
+               disable (ohci);
+               ohci->hc_control &= ~OHCI_CTRL_HCFS;
+               writel (ohci->hc_control, &ohci->regs->control);
+               return -ENODEV;
+       }
+       create_debug_files (ohci);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       struct ohci_regs        *regs = ohci->regs;
+       int                     ints; 
+
+       /* we can eliminate a (slow) readl() if _only_ WDH caused this irq */
+       if ((ohci->hcca->done_head != 0)
+                       && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
+               ints =  OHCI_INTR_WDH;
+
+       /* cardbus/... hardware gone before remove() */
+       } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+               disable (ohci);
+               ohci_dbg (ohci, "device removed!\n");
+               return;
+
+       /* interrupt for some other device? */
+       } else if ((ints &= readl (&regs->intrenable)) == 0) {
+               return;
+       } 
+
+       if (ints & OHCI_INTR_UE) {
+               disable (ohci);
+               ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+               // e.g. due to PCI Master/Target Abort
+
+               ohci_dump (ohci, 1);
+               hc_reset (ohci);
+       }
+  
+       if (ints & OHCI_INTR_WDH) {
+               writel (OHCI_INTR_WDH, &regs->intrdisable);     
+               dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
+               writel (OHCI_INTR_WDH, &regs->intrenable); 
+       }
+  
+       /* could track INTR_SO to reduce available PCI/... bandwidth */
+
+       /* handle any pending URB/ED unlinks, leaving INTR_SF enabled
+        * when there's still unlinking to be done (next frame).
+        */
+       spin_lock (&ohci->lock);
+       if (ohci->ed_rm_list)
+               finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
+                               ptregs);
+       if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list)
+               writel (OHCI_INTR_SF, &regs->intrdisable);      
+       spin_unlock (&ohci->lock);
+
+       writel (ints, &regs->intrstatus);
+       writel (OHCI_INTR_MIE, &regs->intrenable);      
+       // flush those pci writes
+       (void) readl (&ohci->regs->control);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ohci_stop (struct usb_hcd *hcd)
+{      
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       struct ohci_regs        *regs = ohci->regs;
+       int ints;
+
+       ohci_dbg (ohci, "stop %s controller%s\n",
+               hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+               ohci->disabled ? " (disabled)" : ""
+               );
+       ohci_dump (ohci, 1);
+
+       if (!ohci->disabled)
+               hc_reset (ohci);
+
+       // Disable all interrupts
+       writel (OHCI_INTR_MIE, &regs->intrdisable);     
+       // acknowledge all pending interrupts
+       ints = readl(&regs->intrstatus);
+       writel (ints, &regs->intrstatus);
+       // flush register writes
+       (void) readl (&ohci->regs->control);
+       
+       remove_debug_files (ohci);
+       ohci_mem_cleanup (ohci);
+       if (ohci->hcca) {
+               pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
+                                       ohci->hcca, ohci->hcca_dma);
+               ohci->hcca = NULL;
+               ohci->hcca_dma = 0;
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+// FIXME:  this restart logic should be generic,
+// and handle full hcd state cleanup
+
+/* controller died; cleanup debris, then restart */
+/* must not be called from interrupt context */
+
+#ifdef CONFIG_PM
+static int hc_restart (struct ohci_hcd *ohci)
+{
+       int temp;
+       int i;
+
+       ohci->disabled = 1;
+       ohci->sleeping = 0;
+       if (hcd_to_bus (&ohci->hcd)->root_hub)
+               usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
+       
+       /* empty the interrupt branches */
+       for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
+       for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
+       
+       /* no EDs to remove */
+       ohci->ed_rm_list = NULL;
+
+       /* empty control and bulk lists */       
+       ohci->ed_controltail = NULL;
+       ohci->ed_bulktail    = NULL;
+
+       if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
+               ohci_err (ohci, "can't restart, %d\n", temp);
+               return temp;
+       } else
+               ohci_dbg (ohci, "restart complete\n");
+       return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_LICENSE ("GPL");
+
+#ifdef CONFIG_PCI
+#include "ohci-pci.c"
+#endif
+
+#ifdef CONFIG_SA1111
+#include "ohci-sa1111.c"
+#endif
+
+#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111))
+#error "missing bus glue for ohci-hcd"
+#endif
index 03be827..a7584a4 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- * \r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * This file is licenced under GPL\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * OHCI Root Hub ... the nonsharable stuff\r
- *\r
- * Registers don't need cpu_to_le32, that happens transparently\r
- */\r
-\r
-/* AMD-756 (D2 rev) reports corrupt register contents in some cases.\r
- * The erratum (#4) description is incorrect.  AMD's workaround waits\r
- * till some bits (mostly reserved) are clear; ok for all revs.\r
- */\r
-#define read_roothub(hc, register, mask) ({ \\r
-       u32 temp = readl (&hc->regs->roothub.register); \\r
-       if (temp == -1) \\r
-               disable (hc); \\r
-       else if (hc->flags & OHCI_QUIRK_AMD756) \\r
-               while (temp & mask) \\r
-                       temp = readl (&hc->regs->roothub.register); \\r
-       temp; })\r
-\r
-static u32 roothub_a (struct ohci_hcd *hc)\r
-       { return read_roothub (hc, a, 0xfc0fe000); }\r
-static inline u32 roothub_b (struct ohci_hcd *hc)\r
-       { return readl (&hc->regs->roothub.b); }\r
-static inline u32 roothub_status (struct ohci_hcd *hc)\r
-       { return readl (&hc->regs->roothub.status); }\r
-static u32 roothub_portstatus (struct ohci_hcd *hc, int i)\r
-       { return read_roothub (hc, portstatus [i], 0xffe0fce0); }\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#define dbg_port(hc,label,num,value) \\r
-       ohci_dbg (hc, \\r
-               "%s roothub.portstatus [%d] " \\r
-               "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \\r
-               label, num, temp, \\r
-               (temp & RH_PS_PRSC) ? " PRSC" : "", \\r
-               (temp & RH_PS_OCIC) ? " OCIC" : "", \\r
-               (temp & RH_PS_PSSC) ? " PSSC" : "", \\r
-               (temp & RH_PS_PESC) ? " PESC" : "", \\r
-               (temp & RH_PS_CSC) ? " CSC" : "", \\r
-               \\r
-               (temp & RH_PS_LSDA) ? " LSDA" : "", \\r
-               (temp & RH_PS_PPS) ? " PPS" : "", \\r
-               (temp & RH_PS_PRS) ? " PRS" : "", \\r
-               (temp & RH_PS_POCI) ? " POCI" : "", \\r
-               (temp & RH_PS_PSS) ? " PSS" : "", \\r
-               \\r
-               (temp & RH_PS_PES) ? " PES" : "", \\r
-               (temp & RH_PS_CCS) ? " CCS" : "" \\r
-               );\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* build "status change" packet (one or two bytes) from HC registers */\r
-\r
-static int\r
-ohci_hub_status_data (struct usb_hcd *hcd, char *buf)\r
-{\r
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);\r
-       int             ports, i, changed = 0, length = 1;\r
-\r
-       ports = roothub_a (ohci) & RH_A_NDP; \r
-       if (ports > MAX_ROOT_PORTS) {\r
-               if (ohci->disabled)\r
-                       return -ESHUTDOWN;\r
-               ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",\r
-                       ports, readl (&ohci->regs->roothub.a) & RH_A_NDP);\r
-               /* retry later; "should not happen" */\r
-               return 0;\r
-       }\r
-\r
-       /* init status */\r
-       if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))\r
-               buf [0] = changed = 1;\r
-       else\r
-               buf [0] = 0;\r
-       if (ports > 7) {\r
-               buf [1] = 0;\r
-               length++;\r
-       }\r
-\r
-       /* look at each port */\r
-       for (i = 0; i < ports; i++) {\r
-               u32     status = roothub_portstatus (ohci, i);\r
-\r
-               status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC\r
-                               | RH_PS_OCIC | RH_PS_PRSC;\r
-               if (status) {\r
-                       changed = 1;\r
-                       if (i < 7)\r
-                           buf [0] |= 1 << (i + 1);\r
-                       else\r
-                           buf [1] |= 1 << (i - 7);\r
-               }\r
-       }\r
-       return changed ? length : 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static void\r
-ohci_hub_descriptor (\r
-       struct ohci_hcd                 *ohci,\r
-       struct usb_hub_descriptor       *desc\r
-) {\r
-       u32             rh = roothub_a (ohci);\r
-       int             ports = rh & RH_A_NDP; \r
-       u16             temp;\r
-\r
-       desc->bDescriptorType = 0x29;\r
-       desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;\r
-       desc->bHubContrCurrent = 0;\r
-\r
-       desc->bNbrPorts = ports;\r
-       temp = 1 + (ports / 8);\r
-       desc->bDescLength = 7 + 2 * temp;\r
-\r
-       temp = 0;\r
-       if (rh & RH_A_PSM)              /* per-port power switching? */\r
-           temp |= 0x0001;\r
-       if (rh & RH_A_NOCP)             /* no overcurrent reporting? */\r
-           temp |= 0x0010;\r
-       else if (rh & RH_A_OCPM)        /* per-port overcurrent reporting? */\r
-           temp |= 0x0008;\r
-       desc->wHubCharacteristics = cpu_to_le16 (temp);\r
-\r
-       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */\r
-       rh = roothub_b (ohci);\r
-       desc->bitmap [0] = rh & RH_B_DR;\r
-       if (ports > 7) {\r
-               desc->bitmap [1] = (rh & RH_B_DR) >> 8;\r
-               desc->bitmap [2] = desc->bitmap [3] = 0xff;\r
-       } else\r
-               desc->bitmap [1] = 0xff;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static int ohci_hub_control (\r
-       struct usb_hcd  *hcd,\r
-       u16             typeReq,\r
-       u16             wValue,\r
-       u16             wIndex,\r
-       char            *buf,\r
-       u16             wLength\r
-) {\r
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);\r
-       int             ports = hcd_to_bus (hcd)->root_hub->maxchild;\r
-       u32             temp;\r
-       int             retval = 0;\r
-\r
-       switch (typeReq) {\r
-       case ClearHubFeature:\r
-               switch (wValue) {\r
-               case C_HUB_OVER_CURRENT:\r
-                       writel (RH_HS_OCIC, &ohci->regs->roothub.status);\r
-               case C_HUB_LOCAL_POWER:\r
-                       break;\r
-               default:\r
-                       goto error;\r
-               }\r
-               break;\r
-       case ClearPortFeature:\r
-               if (!wIndex || wIndex > ports)\r
-                       goto error;\r
-               wIndex--;\r
-\r
-               switch (wValue) {\r
-               case USB_PORT_FEAT_ENABLE:\r
-                       temp = RH_PS_CCS;\r
-                       break;\r
-               case USB_PORT_FEAT_C_ENABLE:\r
-                       temp = RH_PS_PESC;\r
-                       break;\r
-               case USB_PORT_FEAT_SUSPEND:\r
-                       temp = RH_PS_POCI;\r
-                       break;\r
-               case USB_PORT_FEAT_C_SUSPEND:\r
-                       temp = RH_PS_PSSC;\r
-                       break;\r
-               case USB_PORT_FEAT_POWER:\r
-                       temp = RH_PS_LSDA;\r
-                       break;\r
-               case USB_PORT_FEAT_C_CONNECTION:\r
-                       temp = RH_PS_CSC;\r
-                       break;\r
-               case USB_PORT_FEAT_C_OVER_CURRENT:\r
-                       temp = RH_PS_OCIC;\r
-                       break;\r
-               case USB_PORT_FEAT_C_RESET:\r
-                       temp = RH_PS_PRSC;\r
-                       break;\r
-               default:\r
-                       goto error;\r
-               }\r
-               writel (temp, &ohci->regs->roothub.portstatus [wIndex]);\r
-               // readl (&ohci->regs->roothub.portstatus [wIndex]);\r
-               break;\r
-       case GetHubDescriptor:\r
-               ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);\r
-               break;\r
-       case GetHubStatus:\r
-               temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);\r
-               *(u32 *) buf = cpu_to_le32 (temp);\r
-               break;\r
-       case GetPortStatus:\r
-               if (!wIndex || wIndex > ports)\r
-                       goto error;\r
-               wIndex--;\r
-               temp = roothub_portstatus (ohci, wIndex);\r
-               *(u32 *) buf = cpu_to_le32 (temp);\r
-\r
-#ifndef        OHCI_VERBOSE_DEBUG\r
-       if (*(u16*)(buf+2))     /* only if wPortChange is interesting */\r
-#endif\r
-               dbg_port (ohci, "GetStatus", wIndex + 1, temp);\r
-               break;\r
-       case SetHubFeature:\r
-               switch (wValue) {\r
-               case C_HUB_OVER_CURRENT:\r
-                       // FIXME:  this can be cleared, yes?\r
-               case C_HUB_LOCAL_POWER:\r
-                       break;\r
-               default:\r
-                       goto error;\r
-               }\r
-               break;\r
-       case SetPortFeature:\r
-               if (!wIndex || wIndex > ports)\r
-                       goto error;\r
-               wIndex--;\r
-               switch (wValue) {\r
-               case USB_PORT_FEAT_SUSPEND:\r
-                       writel (RH_PS_PSS,\r
-                               &ohci->regs->roothub.portstatus [wIndex]);\r
-                       break;\r
-               case USB_PORT_FEAT_POWER:\r
-                       writel (RH_PS_PPS,\r
-                               &ohci->regs->roothub.portstatus [wIndex]);\r
-                       break;\r
-               case USB_PORT_FEAT_RESET:\r
-                       temp = readl (&ohci->regs->roothub.portstatus [wIndex]);\r
-                       if (temp & RH_PS_CCS)\r
-                               writel (RH_PS_PRS,\r
-                                   &ohci->regs->roothub.portstatus [wIndex]);\r
-                       break;\r
-               default:\r
-                       goto error;\r
-               }\r
-               break;\r
-\r
-       default:\r
-error:\r
-               /* "protocol stall" on error */\r
-               retval = -EPIPE;\r
-       }\r
-       return retval;\r
-}\r
-\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under GPL
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * OHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define read_roothub(hc, register, mask) ({ \
+       u32 temp = readl (&hc->regs->roothub.register); \
+       if (temp == -1) \
+               disable (hc); \
+       else if (hc->flags & OHCI_QUIRK_AMD756) \
+               while (temp & mask) \
+                       temp = readl (&hc->regs->roothub.register); \
+       temp; })
+
+static u32 roothub_a (struct ohci_hcd *hc)
+       { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci_hcd *hc)
+       { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci_hcd *hc)
+       { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
+       { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+/*-------------------------------------------------------------------------*/
+
+#define dbg_port(hc,label,num,value) \
+       ohci_dbg (hc, \
+               "%s roothub.portstatus [%d] " \
+               "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \
+               label, num, temp, \
+               (temp & RH_PS_PRSC) ? " PRSC" : "", \
+               (temp & RH_PS_OCIC) ? " OCIC" : "", \
+               (temp & RH_PS_PSSC) ? " PSSC" : "", \
+               (temp & RH_PS_PESC) ? " PESC" : "", \
+               (temp & RH_PS_CSC) ? " CSC" : "", \
+               \
+               (temp & RH_PS_LSDA) ? " LSDA" : "", \
+               (temp & RH_PS_PPS) ? " PPS" : "", \
+               (temp & RH_PS_PRS) ? " PRS" : "", \
+               (temp & RH_PS_POCI) ? " POCI" : "", \
+               (temp & RH_PS_PSS) ? " PSS" : "", \
+               \
+               (temp & RH_PS_PES) ? " PES" : "", \
+               (temp & RH_PS_CCS) ? " CCS" : "" \
+               );
+
+
+/*-------------------------------------------------------------------------*/
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ports, i, changed = 0, length = 1;
+
+       ports = roothub_a (ohci) & RH_A_NDP; 
+       if (ports > MAX_ROOT_PORTS) {
+               if (ohci->disabled)
+                       return -ESHUTDOWN;
+               ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",
+                       ports, readl (&ohci->regs->roothub.a) & RH_A_NDP);
+               /* retry later; "should not happen" */
+               return 0;
+       }
+
+       /* init status */
+       if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
+               buf [0] = changed = 1;
+       else
+               buf [0] = 0;
+       if (ports > 7) {
+               buf [1] = 0;
+               length++;
+       }
+
+       /* look at each port */
+       for (i = 0; i < ports; i++) {
+               u32     status = roothub_portstatus (ohci, i);
+
+               status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+                               | RH_PS_OCIC | RH_PS_PRSC;
+               if (status) {
+                       changed = 1;
+                       if (i < 7)
+                           buf [0] |= 1 << (i + 1);
+                       else
+                           buf [1] |= 1 << (i - 7);
+               }
+       }
+       return changed ? length : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ohci_hub_descriptor (
+       struct ohci_hcd                 *ohci,
+       struct usb_hub_descriptor       *desc
+) {
+       u32             rh = roothub_a (ohci);
+       int             ports = rh & RH_A_NDP; 
+       u16             temp;
+
+       desc->bDescriptorType = 0x29;
+       desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
+       desc->bHubContrCurrent = 0;
+
+       desc->bNbrPorts = ports;
+       temp = 1 + (ports / 8);
+       desc->bDescLength = 7 + 2 * temp;
+
+       temp = 0;
+       if (rh & RH_A_PSM)              /* per-port power switching? */
+           temp |= 0x0001;
+       if (rh & RH_A_NOCP)             /* no overcurrent reporting? */
+           temp |= 0x0010;
+       else if (rh & RH_A_OCPM)        /* per-port overcurrent reporting? */
+           temp |= 0x0008;
+       desc->wHubCharacteristics = cpu_to_le16 (temp);
+
+       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+       rh = roothub_b (ohci);
+       desc->bitmap [0] = rh & RH_B_DR;
+       if (ports > 7) {
+               desc->bitmap [1] = (rh & RH_B_DR) >> 8;
+               desc->bitmap [2] = desc->bitmap [3] = 0xff;
+       } else
+               desc->bitmap [1] = 0xff;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hub_control (
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength
+) {
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ports = hcd_to_bus (hcd)->root_hub->maxchild;
+       u32             temp;
+       int             retval = 0;
+
+       switch (typeReq) {
+       case ClearHubFeature:
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+                       writel (RH_HS_OCIC, &ohci->regs->roothub.status);
+               case C_HUB_LOCAL_POWER:
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       temp = RH_PS_CCS;
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+                       temp = RH_PS_PESC;
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       temp = RH_PS_POCI;
+                       break;
+               case USB_PORT_FEAT_C_SUSPEND:
+                       temp = RH_PS_PSSC;
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       temp = RH_PS_LSDA;
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       temp = RH_PS_CSC;
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       temp = RH_PS_OCIC;
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       temp = RH_PS_PRSC;
+                       break;
+               default:
+                       goto error;
+               }
+               writel (temp, &ohci->regs->roothub.portstatus [wIndex]);
+               // readl (&ohci->regs->roothub.portstatus [wIndex]);
+               break;
+       case GetHubDescriptor:
+               ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);
+               break;
+       case GetHubStatus:
+               temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
+               *(u32 *) buf = cpu_to_le32 (temp);
+               break;
+       case GetPortStatus:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = roothub_portstatus (ohci, wIndex);
+               *(u32 *) buf = cpu_to_le32 (temp);
+
+#ifndef        OHCI_VERBOSE_DEBUG
+       if (*(u16*)(buf+2))     /* only if wPortChange is interesting */
+#endif
+               dbg_port (ohci, "GetStatus", wIndex + 1, temp);
+               break;
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+                       // FIXME:  this can be cleared, yes?
+               case C_HUB_LOCAL_POWER:
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case SetPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       writel (RH_PS_PSS,
+                               &ohci->regs->roothub.portstatus [wIndex]);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       writel (RH_PS_PPS,
+                               &ohci->regs->roothub.portstatus [wIndex]);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       temp = readl (&ohci->regs->roothub.portstatus [wIndex]);
+                       if (temp & RH_PS_CCS)
+                               writel (RH_PS_PRS,
+                                   &ohci->regs->roothub.portstatus [wIndex]);
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+
+       default:
+error:
+               /* "protocol stall" on error */
+               retval = -EPIPE;
+       }
+       return retval;
+}
+
index 85371e9..4fc8393 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- * \r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * This file is licenced under the GPL.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * There's basically three types of memory:\r
- *     - data used only by the HCD ... kmalloc is fine\r
- *     - async and periodic schedules, shared by HC and HCD ... these\r
- *       need to use pci_pool or pci_alloc_consistent\r
- *     - driver buffers, read/written by HC ... the hcd glue or the\r
- *       device driver provides us with dma addresses\r
- *\r
- * There's also PCI "register" data, which is memory mapped.\r
- * No memory seen by this driver is pagable.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static struct usb_hcd *ohci_hcd_alloc (void)\r
-{\r
-       struct ohci_hcd *ohci;\r
-\r
-       ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);\r
-       if (ohci != 0) {\r
-               memset (ohci, 0, sizeof (struct ohci_hcd));\r
-               return &ohci->hcd;\r
-       }\r
-       return 0;\r
-}\r
-\r
-static void ohci_hcd_free (struct usb_hcd *hcd)\r
-{\r
-       kfree (hcd_to_ohci (hcd));\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static int ohci_mem_init (struct ohci_hcd *ohci)\r
-{\r
-       ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,\r
-               sizeof (struct td),\r
-               32 /* byte alignment */,\r
-               0 /* no page-crossing issues */);\r
-       if (!ohci->td_cache)\r
-               return -ENOMEM;\r
-       ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,\r
-               sizeof (struct ed),\r
-               16 /* byte alignment */,\r
-               0 /* no page-crossing issues */);\r
-       if (!ohci->ed_cache) {\r
-               pci_pool_destroy (ohci->td_cache);\r
-               return -ENOMEM;\r
-       }\r
-       return 0;\r
-}\r
-\r
-static void ohci_mem_cleanup (struct ohci_hcd *ohci)\r
-{\r
-       if (ohci->td_cache) {\r
-               pci_pool_destroy (ohci->td_cache);\r
-               ohci->td_cache = 0;\r
-       }\r
-       if (ohci->ed_cache) {\r
-               pci_pool_destroy (ohci->ed_cache);\r
-               ohci->ed_cache = 0;\r
-       }\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* ohci "done list" processing needs this mapping */\r
-static inline struct td *\r
-dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)\r
-{\r
-       struct td *td;\r
-\r
-       td_dma &= TD_MASK;\r
-       td = hc->td_hash [TD_HASH_FUNC(td_dma)];\r
-       while (td && td->td_dma != td_dma)\r
-               td = td->td_hash;\r
-       return td;\r
-}\r
-\r
-/* TDs ... */\r
-static struct td *\r
-td_alloc (struct ohci_hcd *hc, int mem_flags)\r
-{\r
-       dma_addr_t      dma;\r
-       struct td       *td;\r
-\r
-       td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);\r
-       if (td) {\r
-               /* in case hc fetches it, make it look dead */\r
-               memset (td, 0, sizeof *td);\r
-               td->hwNextTD = cpu_to_le32 (dma);\r
-               td->td_dma = dma;\r
-               /* hashed in td_fill */\r
-       }\r
-       return td;\r
-}\r
-\r
-static void\r
-td_free (struct ohci_hcd *hc, struct td *td)\r
-{\r
-       struct td       **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];\r
-\r
-       while (*prev && *prev != td)\r
-               prev = &(*prev)->td_hash;\r
-       if (*prev)\r
-               *prev = td->td_hash;\r
-       else if ((td->hwINFO & TD_DONE) != 0)\r
-               ohci_dbg (hc, "no hash for td %p\n", td);\r
-       pci_pool_free (hc->td_cache, td, td->td_dma);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* EDs ... */\r
-static struct ed *\r
-ed_alloc (struct ohci_hcd *hc, int mem_flags)\r
-{\r
-       dma_addr_t      dma;\r
-       struct ed       *ed;\r
-\r
-       ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);\r
-       if (ed) {\r
-               memset (ed, 0, sizeof (*ed));\r
-               INIT_LIST_HEAD (&ed->td_list);\r
-               ed->dma = dma;\r
-       }\r
-       return ed;\r
-}\r
-\r
-static void\r
-ed_free (struct ohci_hcd *hc, struct ed *ed)\r
-{\r
-       pci_pool_free (hc->ed_cache, ed, ed->dma);\r
-}\r
-\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under the GPL.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *     - data used only by the HCD ... kmalloc is fine
+ *     - async and periodic schedules, shared by HC and HCD ... these
+ *       need to use pci_pool or pci_alloc_consistent
+ *     - driver buffers, read/written by HC ... the hcd glue or the
+ *       device driver provides us with dma addresses
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_hcd *ohci_hcd_alloc (void)
+{
+       struct ohci_hcd *ohci;
+
+       ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);
+       if (ohci != 0) {
+               memset (ohci, 0, sizeof (struct ohci_hcd));
+               return &ohci->hcd;
+       }
+       return 0;
+}
+
+static void ohci_hcd_free (struct usb_hcd *hcd)
+{
+       kfree (hcd_to_ohci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_mem_init (struct ohci_hcd *ohci)
+{
+       ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
+               sizeof (struct td),
+               32 /* byte alignment */,
+               0 /* no page-crossing issues */);
+       if (!ohci->td_cache)
+               return -ENOMEM;
+       ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
+               sizeof (struct ed),
+               16 /* byte alignment */,
+               0 /* no page-crossing issues */);
+       if (!ohci->ed_cache) {
+               pci_pool_destroy (ohci->td_cache);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void ohci_mem_cleanup (struct ohci_hcd *ohci)
+{
+       if (ohci->td_cache) {
+               pci_pool_destroy (ohci->td_cache);
+               ohci->td_cache = 0;
+       }
+       if (ohci->ed_cache) {
+               pci_pool_destroy (ohci->ed_cache);
+               ohci->ed_cache = 0;
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ohci "done list" processing needs this mapping */
+static inline struct td *
+dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
+{
+       struct td *td;
+
+       td_dma &= TD_MASK;
+       td = hc->td_hash [TD_HASH_FUNC(td_dma)];
+       while (td && td->td_dma != td_dma)
+               td = td->td_hash;
+       return td;
+}
+
+/* TDs ... */
+static struct td *
+td_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+       dma_addr_t      dma;
+       struct td       *td;
+
+       td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
+       if (td) {
+               /* in case hc fetches it, make it look dead */
+               memset (td, 0, sizeof *td);
+               td->hwNextTD = cpu_to_le32 (dma);
+               td->td_dma = dma;
+               /* hashed in td_fill */
+       }
+       return td;
+}
+
+static void
+td_free (struct ohci_hcd *hc, struct td *td)
+{
+       struct td       **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
+
+       while (*prev && *prev != td)
+               prev = &(*prev)->td_hash;
+       if (*prev)
+               *prev = td->td_hash;
+       else if ((td->hwINFO & TD_DONE) != 0)
+               ohci_dbg (hc, "no hash for td %p\n", td);
+       pci_pool_free (hc->td_cache, td, td->td_dma);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* EDs ... */
+static struct ed *
+ed_alloc (struct ohci_hcd *hc, int mem_flags)
+{
+       dma_addr_t      dma;
+       struct ed       *ed;
+
+       ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
+       if (ed) {
+               memset (ed, 0, sizeof (*ed));
+               INIT_LIST_HEAD (&ed->td_list);
+               ed->dma = dma;
+       }
+       return ed;
+}
+
+static void
+ed_free (struct ohci_hcd *hc, struct ed *ed)
+{
+       pci_pool_free (hc->ed_cache, ed, ed->dma);
+}
+
index 0ce7123..a7c3980 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- *\r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * [ Initialisation is based on Linus'  ]\r
- * [ uhci code and gregs ohci fragments ]\r
- * [ (C) Copyright 1999 Linus Torvalds  ]\r
- * [ (C) Copyright 1999 Gregory P. Smith]\r
- * \r
- * PCI Bus Glue\r
- *\r
- * This file is licenced under the GPL.\r
- */\r
\r
-#ifdef CONFIG_PMAC_PBOOK\r
-#include <asm/machdep.h>\r
-#include <asm/pmac_feature.h>\r
-#include <asm/pci-bridge.h>\r
-#include <asm/prom.h>\r
-#ifndef CONFIG_PM\r
-#      define CONFIG_PM\r
-#endif\r
-#endif\r
-\r
-#ifndef CONFIG_PCI\r
-#error "This file is PCI bus glue.  CONFIG_PCI must be defined."\r
-#endif\r
-\r
-#include "../linux/pci_ids.h"\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static int __devinit\r
-ohci_pci_start (struct usb_hcd *hcd)\r
-{\r
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);\r
-       int             ret;\r
-\r
-       DPRINT("ohci_pci_start()\n");\r
-\r
-       if (hcd->pdev) {\r
-               ohci->hcca = pci_alloc_consistent (hcd->pdev,\r
-                               sizeof *ohci->hcca, &ohci->hcca_dma);\r
-               if (!ohci->hcca)\r
-                       return -ENOMEM;\r
-\r
-               /* AMD 756, for most chips (early revs), corrupts register\r
-                * values on read ... so enable the vendor workaround.\r
-                */\r
-               if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD\r
-                               && hcd->pdev->device == 0x740c) {\r
-                       ohci->flags = OHCI_QUIRK_AMD756;\r
-                       ohci_info (ohci, "AMD756 erratum 4 workaround\n");\r
-               }\r
-\r
-               /* FIXME for some of the early AMD 760 southbridges, OHCI\r
-                * won't work at all.  blacklist them.\r
-                */\r
-\r
-               /* Apple's OHCI driver has a lot of bizarre workarounds\r
-                * for this chip.  Evidently control and bulk lists\r
-                * can get confused.  (B&W G3 models, and ...)\r
-                */\r
-               else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI\r
-                               && hcd->pdev->device == 0xc861) {\r
-                       ohci_info (ohci,\r
-                               "WARNING: OPTi workarounds unavailable\n");\r
-               }\r
-\r
-               /* Check for NSC87560. We have to look at the bridge (fn1) to\r
-                * identify the USB (fn2). This quirk might apply to more or\r
-                * even all NSC stuff.\r
-                */\r
-               else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) {\r
-                       struct pci_dev  *b, *hc;\r
-\r
-                       hc = hcd->pdev;\r
-                       b  = pci_find_slot (hc->bus->number,\r
-                                       PCI_DEVFN (PCI_SLOT (hc->devfn), 1));\r
-                       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO\r
-                                       && b->vendor == PCI_VENDOR_ID_NS) {\r
-                               ohci->flags |= OHCI_QUIRK_SUPERIO;\r
-                               ohci_info (ohci, "Using NSC SuperIO setup\n");\r
-                       }\r
-               }\r
-       \r
-       }\r
-\r
-    memset (ohci->hcca, 0, sizeof (struct ohci_hcca));\r
-       if ((ret = ohci_mem_init (ohci)) < 0) {\r
-               ohci_stop (hcd);\r
-               return ret;\r
-       }\r
-       ohci->regs = hcd->regs;\r
-\r
-    DPRINT("Controller memory init done\n");\r
-\r
-       if (hc_reset (ohci) < 0) {\r
-               ohci_stop (hcd);\r
-               return -ENODEV;\r
-       }\r
-       DPRINT("Controller reset done\n");\r
-\r
-       if (hc_start (ohci) < 0) {\r
-               ohci_err (ohci, "can't start\n");\r
-               ohci_stop (hcd);\r
-               return -EBUSY;\r
-       }\r
-       DPRINT("Controller start done\n");\r
-\r
-#ifdef DEBUG\r
-       ohci_dump (ohci, 1);\r
-#endif\r
-       return 0;\r
-}\r
-\r
-#ifdef CONFIG_PM\r
-\r
-static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       unsigned long           flags;\r
-       u16                     cmd;\r
-\r
-       if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {\r
-               ohci_dbg (ohci, "can't suspend (state is %s)\n",\r
-                       hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));\r
-               return -EIO;\r
-       }\r
-\r
-       /* act as if usb suspend can always be used */\r
-       ohci_dbg (ohci, "suspend to %d\n", state);\r
-       ohci->sleeping = 1;\r
-\r
-       /* First stop processing */\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       ohci->hc_control &=\r
-               ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);\r
-       (void) readl (&ohci->regs->intrstatus);\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-\r
-       /* Wait a frame or two */\r
-       mdelay (1);\r
-       if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)\r
-               mdelay (1);\r
-               \r
-#ifdef CONFIG_PMAC_PBOOK\r
-       if (_machine == _MACH_Pmac)\r
-               disable_irq (hcd->pdev->irq);\r
-       /* else, 2.4 assumes shared irqs -- don't disable */\r
-#endif\r
-\r
-       /* Enable remote wakeup */\r
-       writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,\r
-               &ohci->regs->intrenable);\r
-\r
-       /* Suspend chip and let things settle down a bit */\r
-       ohci->hc_control = OHCI_USB_SUSPEND;\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-       (void) readl (&ohci->regs->control);\r
-       mdelay (500); /* No schedule here ! */\r
-\r
-       switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {\r
-               case OHCI_USB_RESET:\r
-                       ohci_dbg (ohci, "suspend->reset ?\n");\r
-                       break;\r
-               case OHCI_USB_RESUME:\r
-                       ohci_dbg (ohci, "suspend->resume ?\n");\r
-                       break;\r
-               case OHCI_USB_OPER:\r
-                       ohci_dbg (ohci, "suspend->operational ?\n");\r
-                       break;\r
-               case OHCI_USB_SUSPEND:\r
-                       ohci_dbg (ohci, "suspended\n");\r
-                       break;\r
-       }\r
-\r
-       /* In some rare situations, Apple's OHCI have happily trashed\r
-        * memory during sleep. We disable its bus master bit during\r
-        * suspend\r
-        */\r
-       pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);\r
-       cmd &= ~PCI_COMMAND_MASTER;\r
-       pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);\r
-#ifdef CONFIG_PMAC_PBOOK\r
-       {\r
-               struct device_node      *of_node;\r
\r
-               /* Disable USB PAD & cell clock */\r
-               of_node = pci_device_to_OF_node (hcd->pdev);\r
-               if (of_node)\r
-                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);\r
-       }\r
-#endif\r
-       return 0;\r
-}\r
-\r
-\r
-static int ohci_pci_resume (struct usb_hcd *hcd)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       int                     temp;\r
-       int                     retval = 0;\r
-       unsigned long           flags;\r
-\r
-#ifdef CONFIG_PMAC_PBOOK\r
-       {\r
-               struct device_node *of_node;\r
-\r
-               /* Re-enable USB PAD & cell clock */\r
-               of_node = pci_device_to_OF_node (hcd->pdev);\r
-               if (of_node)\r
-                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);\r
-       }\r
-#endif\r
-       /* did we suspend, or were we powered off? */\r
-       ohci->hc_control = readl (&ohci->regs->control);\r
-       temp = ohci->hc_control & OHCI_CTRL_HCFS;\r
-\r
-#ifdef DEBUG\r
-       /* the registers may look crazy here */\r
-       ohci_dump_status (ohci, 0, 0);\r
-#endif\r
-\r
-       /* Re-enable bus mastering */\r
-       pci_set_master (ohci->hcd.pdev);\r
-       \r
-       switch (temp) {\r
-\r
-       case OHCI_USB_RESET:    // lost power\r
-               ohci_info (ohci, "USB restart\n");\r
-               retval = hc_restart (ohci);\r
-               break;\r
-\r
-       case OHCI_USB_SUSPEND:  // host wakeup\r
-       case OHCI_USB_RESUME:   // remote wakeup\r
-               ohci_info (ohci, "USB continue from %s wakeup\n",\r
-                        (temp == OHCI_USB_SUSPEND)\r
-                               ? "host" : "remote");\r
-               ohci->hc_control = OHCI_USB_RESUME;\r
-               writel (ohci->hc_control, &ohci->regs->control);\r
-               (void) readl (&ohci->regs->control);\r
-               mdelay (20); /* no schedule here ! */\r
-               /* Some controllers (lucent) need a longer delay here */\r
-               mdelay (15);\r
-\r
-               temp = readl (&ohci->regs->control);\r
-               temp = ohci->hc_control & OHCI_CTRL_HCFS;\r
-               if (temp != OHCI_USB_RESUME) {\r
-                       ohci_err (ohci, "controller won't resume\n");\r
-                       ohci->disabled = 1;\r
-                       retval = -EIO;\r
-                       break;\r
-               }\r
-\r
-               /* Some chips likes being resumed first */\r
-               writel (OHCI_USB_OPER, &ohci->regs->control);\r
-               (void) readl (&ohci->regs->control);\r
-               mdelay (3);\r
-\r
-               /* Then re-enable operations */\r
-               spin_lock_irqsave (&ohci->lock, flags);\r
-               ohci->disabled = 0;\r
-               ohci->sleeping = 0;\r
-               ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;\r
-               if (!ohci->ed_rm_list) {\r
-                       if (ohci->ed_controltail)\r
-                               ohci->hc_control |= OHCI_CTRL_CLE;\r
-                       if (ohci->ed_bulktail)\r
-                               ohci->hc_control |= OHCI_CTRL_BLE;\r
-               }\r
-               hcd->state = USB_STATE_READY;\r
-               writel (ohci->hc_control, &ohci->regs->control);\r
-\r
-               /* trigger a start-frame interrupt (why?) */\r
-               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);\r
-               writel (OHCI_INTR_SF, &ohci->regs->intrenable);\r
-\r
-               /* Check for a pending done list */\r
-               writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);       \r
-               (void) readl (&ohci->regs->intrdisable);\r
-               spin_unlock_irqrestore (&ohci->lock, flags);\r
-\r
-#ifdef CONFIG_PMAC_PBOOK\r
-               if (_machine == _MACH_Pmac)\r
-                       enable_irq (hcd->pdev->irq);\r
-#endif\r
-               if (ohci->hcca->done_head)\r
-                       dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);\r
-               writel (OHCI_INTR_WDH, &ohci->regs->intrenable); \r
-\r
-               /* assume there are TDs on the bulk and control lists */\r
-               writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);\r
-\r
-// ohci_dump_status (ohci);\r
-ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",\r
-               ohci->sleeping, ohci->disabled);\r
-               break;\r
-\r
-       default:\r
-               ohci_warn (ohci, "odd PCI resume\n");\r
-       }\r
-       return retval;\r
-}\r
-\r
-#endif /* CONFIG_PM */\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static const struct hc_driver ohci_pci_hc_driver = {\r
-       .description =          hcd_name,\r
-\r
-       /*\r
-        * generic hardware linkage\r
-        */\r
-       .irq =                  ohci_irq,\r
-       .flags =                HCD_MEMORY | HCD_USB11,\r
-\r
-       /*\r
-        * basic lifecycle operations\r
-        */\r
-       .start =                ohci_pci_start,\r
-#ifdef CONFIG_PM\r
-       .suspend =              ohci_pci_suspend,\r
-       .resume =               ohci_pci_resume,\r
-#endif\r
-       .stop =                 ohci_stop,\r
-\r
-       /*\r
-        * memory lifecycle (except per-request)\r
-        */\r
-       .hcd_alloc =            ohci_hcd_alloc,\r
-       .hcd_free =             ohci_hcd_free,\r
-\r
-       /*\r
-        * managing i/o requests and associated device resources\r
-        */\r
-       .urb_enqueue =          ohci_urb_enqueue,\r
-       .urb_dequeue =          ohci_urb_dequeue,\r
-       .endpoint_disable =     ohci_endpoint_disable,\r
-\r
-       /*\r
-        * scheduling support\r
-        */\r
-       .get_frame_number =     ohci_get_frame,\r
-\r
-       /*\r
-        * root hub support\r
-        */\r
-       .hub_status_data =      ohci_hub_status_data,\r
-       .hub_control =          ohci_hub_control,\r
-};\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-const struct pci_device_id __devinitdata pci_ids [] = { {\r
-\r
-       /* handle any USB OHCI controller */\r
-       .class =        (PCI_CLASS_SERIAL_USB << 8) | 0x10,\r
-       .class_mask =   ~0,\r
-       .driver_data =  (unsigned long) &ohci_pci_hc_driver,\r
-\r
-       /* no matter who makes it */\r
-       .vendor =       PCI_ANY_ID,\r
-       .device =       PCI_ANY_ID,\r
-       .subvendor =    PCI_ANY_ID,\r
-       .subdevice =    PCI_ANY_ID,\r
-\r
-       }, { /* end: all zeroes */ }\r
-};\r
-MODULE_DEVICE_TABLE (pci, pci_ids);\r
-\r
-/* pci driver glue; this is a "new style" PCI driver module */\r
-struct pci_driver ohci_pci_driver = {\r
-       .name =         (char *) hcd_name,\r
-       .id_table =     pci_ids,\r
-\r
-       .probe =        usb_hcd_pci_probe,\r
-       .remove =       usb_hcd_pci_remove,\r
-\r
-#ifdef CONFIG_PM\r
-       .suspend =      usb_hcd_pci_suspend,\r
-       .resume =       usb_hcd_pci_resume,\r
-#endif\r
-};\r
-\r
\r
-int ohci_hcd_pci_init (void) \r
-{\r
-       printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);\r
-       if (usb_disabled())\r
-               return -ENODEV;\r
-\r
-       // causes page fault in reactos\r
-       //printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name,\r
-       //      sizeof (struct ed), sizeof (struct td));\r
-       return pci_module_init (&ohci_pci_driver);\r
-}\r
-/*module_init (ohci_hcd_pci_init);*/\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-void ohci_hcd_pci_cleanup (void) \r
-{      \r
-       pci_unregister_driver (&ohci_pci_driver);\r
-}\r
-/*module_exit (ohci_hcd_pci_cleanup);*/\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * PCI Bus Glue
+ *
+ * This file is licenced under the GPL.
+ */
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#ifndef CONFIG_PM
+#      define CONFIG_PM
+#endif
+#endif
+
+#ifndef CONFIG_PCI
+#error "This file is PCI bus glue.  CONFIG_PCI must be defined."
+#endif
+
+#include "../linux/pci_ids.h"
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_pci_start (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ret;
+
+       DPRINT("ohci_pci_start()\n");
+
+       if (hcd->pdev) {
+               ohci->hcca = pci_alloc_consistent (hcd->pdev,
+                               sizeof *ohci->hcca, &ohci->hcca_dma);
+               if (!ohci->hcca)
+                       return -ENOMEM;
+
+               /* AMD 756, for most chips (early revs), corrupts register
+                * values on read ... so enable the vendor workaround.
+                */
+               if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD
+                               && hcd->pdev->device == 0x740c) {
+                       ohci->flags = OHCI_QUIRK_AMD756;
+                       ohci_info (ohci, "AMD756 erratum 4 workaround\n");
+               }
+
+               /* FIXME for some of the early AMD 760 southbridges, OHCI
+                * won't work at all.  blacklist them.
+                */
+
+               /* Apple's OHCI driver has a lot of bizarre workarounds
+                * for this chip.  Evidently control and bulk lists
+                * can get confused.  (B&W G3 models, and ...)
+                */
+               else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI
+                               && hcd->pdev->device == 0xc861) {
+                       ohci_info (ohci,
+                               "WARNING: OPTi workarounds unavailable\n");
+               }
+
+               /* Check for NSC87560. We have to look at the bridge (fn1) to
+                * identify the USB (fn2). This quirk might apply to more or
+                * even all NSC stuff.
+                */
+               else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) {
+                       struct pci_dev  *b, *hc;
+
+                       hc = hcd->pdev;
+                       b  = pci_find_slot (hc->bus->number,
+                                       PCI_DEVFN (PCI_SLOT (hc->devfn), 1));
+                       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+                                       && b->vendor == PCI_VENDOR_ID_NS) {
+                               ohci->flags |= OHCI_QUIRK_SUPERIO;
+                               ohci_info (ohci, "Using NSC SuperIO setup\n");
+                       }
+               }
+       
+       }
+
+    memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+       if ((ret = ohci_mem_init (ohci)) < 0) {
+               ohci_stop (hcd);
+               return ret;
+       }
+       ohci->regs = hcd->regs;
+
+    DPRINT("Controller memory init done\n");
+
+       if (hc_reset (ohci) < 0) {
+               ohci_stop (hcd);
+               return -ENODEV;
+       }
+       DPRINT("Controller reset done\n");
+
+       if (hc_start (ohci) < 0) {
+               ohci_err (ohci, "can't start\n");
+               ohci_stop (hcd);
+               return -EBUSY;
+       }
+       DPRINT("Controller start done\n");
+
+#ifdef DEBUG
+       ohci_dump (ohci, 1);
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       unsigned long           flags;
+       u16                     cmd;
+
+       if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+               ohci_dbg (ohci, "can't suspend (state is %s)\n",
+                       hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+               return -EIO;
+       }
+
+       /* act as if usb suspend can always be used */
+       ohci_dbg (ohci, "suspend to %d\n", state);
+       ohci->sleeping = 1;
+
+       /* First stop processing */
+       spin_lock_irqsave (&ohci->lock, flags);
+       ohci->hc_control &=
+               ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+       writel (ohci->hc_control, &ohci->regs->control);
+       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+       (void) readl (&ohci->regs->intrstatus);
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       /* Wait a frame or two */
+       mdelay (1);
+       if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+               mdelay (1);
+               
+#ifdef CONFIG_PMAC_PBOOK
+       if (_machine == _MACH_Pmac)
+               disable_irq (hcd->pdev->irq);
+       /* else, 2.4 assumes shared irqs -- don't disable */
+#endif
+
+       /* Enable remote wakeup */
+       writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,
+               &ohci->regs->intrenable);
+
+       /* Suspend chip and let things settle down a bit */
+       ohci->hc_control = OHCI_USB_SUSPEND;
+       writel (ohci->hc_control, &ohci->regs->control);
+       (void) readl (&ohci->regs->control);
+       mdelay (500); /* No schedule here ! */
+
+       switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+               case OHCI_USB_RESET:
+                       ohci_dbg (ohci, "suspend->reset ?\n");
+                       break;
+               case OHCI_USB_RESUME:
+                       ohci_dbg (ohci, "suspend->resume ?\n");
+                       break;
+               case OHCI_USB_OPER:
+                       ohci_dbg (ohci, "suspend->operational ?\n");
+                       break;
+               case OHCI_USB_SUSPEND:
+                       ohci_dbg (ohci, "suspended\n");
+                       break;
+       }
+
+       /* In some rare situations, Apple's OHCI have happily trashed
+        * memory during sleep. We disable its bus master bit during
+        * suspend
+        */
+       pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
+       cmd &= ~PCI_COMMAND_MASTER;
+       pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+       {
+               struct device_node      *of_node;
+               /* Disable USB PAD & cell clock */
+               of_node = pci_device_to_OF_node (hcd->pdev);
+               if (of_node)
+                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+       }
+#endif
+       return 0;
+}
+
+
+static int ohci_pci_resume (struct usb_hcd *hcd)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       int                     temp;
+       int                     retval = 0;
+       unsigned long           flags;
+
+#ifdef CONFIG_PMAC_PBOOK
+       {
+               struct device_node *of_node;
+
+               /* Re-enable USB PAD & cell clock */
+               of_node = pci_device_to_OF_node (hcd->pdev);
+               if (of_node)
+                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+       }
+#endif
+       /* did we suspend, or were we powered off? */
+       ohci->hc_control = readl (&ohci->regs->control);
+       temp = ohci->hc_control & OHCI_CTRL_HCFS;
+
+#ifdef DEBUG
+       /* the registers may look crazy here */
+       ohci_dump_status (ohci, 0, 0);
+#endif
+
+       /* Re-enable bus mastering */
+       pci_set_master (ohci->hcd.pdev);
+       
+       switch (temp) {
+
+       case OHCI_USB_RESET:    // lost power
+               ohci_info (ohci, "USB restart\n");
+               retval = hc_restart (ohci);
+               break;
+
+       case OHCI_USB_SUSPEND:  // host wakeup
+       case OHCI_USB_RESUME:   // remote wakeup
+               ohci_info (ohci, "USB continue from %s wakeup\n",
+                        (temp == OHCI_USB_SUSPEND)
+                               ? "host" : "remote");
+               ohci->hc_control = OHCI_USB_RESUME;
+               writel (ohci->hc_control, &ohci->regs->control);
+               (void) readl (&ohci->regs->control);
+               mdelay (20); /* no schedule here ! */
+               /* Some controllers (lucent) need a longer delay here */
+               mdelay (15);
+
+               temp = readl (&ohci->regs->control);
+               temp = ohci->hc_control & OHCI_CTRL_HCFS;
+               if (temp != OHCI_USB_RESUME) {
+                       ohci_err (ohci, "controller won't resume\n");
+                       ohci->disabled = 1;
+                       retval = -EIO;
+                       break;
+               }
+
+               /* Some chips likes being resumed first */
+               writel (OHCI_USB_OPER, &ohci->regs->control);
+               (void) readl (&ohci->regs->control);
+               mdelay (3);
+
+               /* Then re-enable operations */
+               spin_lock_irqsave (&ohci->lock, flags);
+               ohci->disabled = 0;
+               ohci->sleeping = 0;
+               ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+               if (!ohci->ed_rm_list) {
+                       if (ohci->ed_controltail)
+                               ohci->hc_control |= OHCI_CTRL_CLE;
+                       if (ohci->ed_bulktail)
+                               ohci->hc_control |= OHCI_CTRL_BLE;
+               }
+               hcd->state = USB_STATE_READY;
+               writel (ohci->hc_control, &ohci->regs->control);
+
+               /* trigger a start-frame interrupt (why?) */
+               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+               writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+
+               /* Check for a pending done list */
+               writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);       
+               (void) readl (&ohci->regs->intrdisable);
+               spin_unlock_irqrestore (&ohci->lock, flags);
+
+#ifdef CONFIG_PMAC_PBOOK
+               if (_machine == _MACH_Pmac)
+                       enable_irq (hcd->pdev->irq);
+#endif
+               if (ohci->hcca->done_head)
+                       dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
+               writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+
+               /* assume there are TDs on the bulk and control lists */
+               writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
+
+// ohci_dump_status (ohci);
+ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",
+               ohci->sleeping, ohci->disabled);
+               break;
+
+       default:
+               ohci_warn (ohci, "odd PCI resume\n");
+       }
+       return retval;
+}
+
+#endif /* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pci_hc_driver = {
+       .description =          hcd_name,
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_MEMORY | HCD_USB11,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_pci_start,
+#ifdef CONFIG_PM
+       .suspend =              ohci_pci_suspend,
+       .resume =               ohci_pci_resume,
+#endif
+       .stop =                 ohci_stop,
+
+       /*
+        * memory lifecycle (except per-request)
+        */
+       .hcd_alloc =            ohci_hcd_alloc,
+       .hcd_free =             ohci_hcd_free,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+const struct pci_device_id __devinitdata pci_ids [] = { {
+
+       /* handle any USB OHCI controller */
+       .class =        (PCI_CLASS_SERIAL_USB << 8) | 0x10,
+       .class_mask =   ~0,
+       .driver_data =  (unsigned long) &ohci_pci_hc_driver,
+
+       /* no matter who makes it */
+       .vendor =       PCI_ANY_ID,
+       .device =       PCI_ANY_ID,
+       .subvendor =    PCI_ANY_ID,
+       .subdevice =    PCI_ANY_ID,
+
+       }, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+struct pci_driver ohci_pci_driver = {
+       .name =         (char *) hcd_name,
+       .id_table =     pci_ids,
+
+       .probe =        usb_hcd_pci_probe,
+       .remove =       usb_hcd_pci_remove,
+
+#ifdef CONFIG_PM
+       .suspend =      usb_hcd_pci_suspend,
+       .resume =       usb_hcd_pci_resume,
+#endif
+};
+
+int ohci_hcd_pci_init (void) 
+{
+       printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
+       if (usb_disabled())
+               return -ENODEV;
+
+       // causes page fault in reactos
+       //printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+       //      sizeof (struct ed), sizeof (struct td));
+       return pci_module_init (&ohci_pci_driver);
+}
+/*module_init (ohci_hcd_pci_init);*/
+
+/*-------------------------------------------------------------------------*/
+
+void ohci_hcd_pci_cleanup (void) 
+{      
+       pci_unregister_driver (&ohci_pci_driver);
+}
+/*module_exit (ohci_hcd_pci_cleanup);*/
index 71e6350..eae584a 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- * \r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * This file is licenced under the GPL.\r
- */\r
-\r
-static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)\r
-{\r
-       int             last = urb_priv->length - 1;\r
-\r
-       if (last >= 0) {\r
-               int             i;\r
-               struct td       *td;\r
-\r
-               for (i = 0; i <= last; i++) {\r
-                       td = urb_priv->td [i];\r
-                       if (td)\r
-                               td_free (hc, td);\r
-               }\r
-       }\r
-\r
-       kfree (urb_priv);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * URB goes back to driver, and isn't reissued.\r
- * It's completely gone from HC data structures.\r
- * PRECONDITION:  no locks held, irqs blocked  (Giveback can call into HCD.)\r
- */\r
-static void\r
-finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)\r
-{\r
-       // ASSERT (urb->hcpriv != 0);\r
-\r
-       urb_free_priv (ohci, urb->hcpriv);\r
-       urb->hcpriv = NULL;\r
-\r
-       spin_lock (&urb->lock);\r
-       if (likely (urb->status == -EINPROGRESS))\r
-               urb->status = 0;\r
-       spin_unlock (&urb->lock);\r
-\r
-       // what lock protects these?\r
-       switch (usb_pipetype (urb->pipe)) {\r
-       case PIPE_ISOCHRONOUS:\r
-               hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs--;\r
-               break;\r
-       case PIPE_INTERRUPT:\r
-               hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs--;\r
-               break;\r
-       }\r
-\r
-#ifdef OHCI_VERBOSE_DEBUG\r
-       urb_print (urb, "RET", usb_pipeout (urb->pipe));\r
-#endif\r
-       usb_hcd_giveback_urb (&ohci->hcd, urb, regs);\r
-}\r
-\r
-\r
-/*-------------------------------------------------------------------------*\r
- * ED handling functions\r
- *-------------------------------------------------------------------------*/  \r
-\r
-/* search for the right schedule branch to use for a periodic ed.\r
- * does some load balancing; returns the branch, or negative errno.\r
- */\r
-static int balance (struct ohci_hcd *ohci, int interval, int load)\r
-{\r
-       int     i, branch = -ENOSPC;\r
-\r
-       /* iso periods can be huge; iso tds specify frame numbers */\r
-       if (interval > NUM_INTS)\r
-               interval = NUM_INTS;\r
-\r
-       /* search for the least loaded schedule branch of that period\r
-        * that has enough bandwidth left unreserved.\r
-        */\r
-       for (i = 0; i < interval ; i++) {\r
-               if (branch < 0 || ohci->load [branch] > ohci->load [i]) {\r
-#if 1  /* CONFIG_USB_BANDWIDTH */\r
-                       int     j;\r
-\r
-                       /* usb 1.1 says 90% of one frame */\r
-                       for (j = i; j < NUM_INTS; j += interval) {\r
-                               if ((ohci->load [j] + load) > 900)\r
-                                       break;\r
-                       }\r
-                       if (j < NUM_INTS)\r
-                               continue;\r
-#endif\r
-                       branch = i; \r
-               }\r
-       }\r
-       return branch;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* both iso and interrupt requests have periods; this routine puts them\r
- * into the schedule tree in the apppropriate place.  most iso devices use\r
- * 1msec periods, but that's not required.\r
- */\r
-static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)\r
-{\r
-       unsigned        i;\r
-\r
-       ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n",\r
-               (ed->hwINFO & ED_ISO) ? "iso " : "",\r
-               ed, ed->branch, ed->load, ed->interval);\r
-\r
-       for (i = ed->branch; i < NUM_INTS; i += ed->interval) {\r
-               struct ed       **prev = &ohci->periodic [i];\r
-               u32             *prev_p = &ohci->hcca->int_table [i];\r
-               struct ed       *here = *prev;\r
-\r
-               /* sorting each branch by period (slow before fast)\r
-                * lets us share the faster parts of the tree.\r
-                * (plus maybe: put interrupt eds before iso)\r
-                */\r
-               while (here && ed != here) {\r
-                       if (ed->interval > here->interval)\r
-                               break;\r
-                       prev = &here->ed_next;\r
-                       prev_p = &here->hwNextED;\r
-                       here = *prev;\r
-               }\r
-               if (ed != here) {\r
-                       ed->ed_next = here;\r
-                       if (here)\r
-                               ed->hwNextED = *prev_p;\r
-                       wmb ();\r
-                       *prev = ed;\r
-                       *prev_p = cpu_to_le32p (&ed->dma);\r
-               }\r
-               ohci->load [i] += ed->load;\r
-       }\r
-       hcd_to_bus (&ohci->hcd)->bandwidth_allocated += ed->load / ed->interval;\r
-}\r
-\r
-/* link an ed into one of the HC chains */\r
-\r
-static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)\r
-{       \r
-       int     branch;\r
-\r
-       ed->state = ED_OPER;\r
-       ed->ed_prev = 0;\r
-       ed->ed_next = 0;\r
-       ed->hwNextED = 0;\r
-       wmb ();\r
-\r
-       /* we care about rm_list when setting CLE/BLE in case the HC was at\r
-        * work on some TD when CLE/BLE was turned off, and isn't quiesced\r
-        * yet.  finish_unlinks() restarts as needed, some upcoming INTR_SF.\r
-        *\r
-        * control and bulk EDs are doubly linked (ed_next, ed_prev), but\r
-        * periodic ones are singly linked (ed_next). that's because the\r
-        * periodic schedule encodes a tree like figure 3-5 in the ohci\r
-        * spec:  each qh can have several "previous" nodes, and the tree\r
-        * doesn't have unused/idle descriptors.\r
-        */\r
-       switch (ed->type) {\r
-       case PIPE_CONTROL:\r
-               if (ohci->ed_controltail == NULL) {\r
-                       writel (ed->dma, &ohci->regs->ed_controlhead);\r
-               } else {\r
-                       ohci->ed_controltail->ed_next = ed;\r
-                       ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);\r
-               }\r
-               ed->ed_prev = ohci->ed_controltail;\r
-               if (!ohci->ed_controltail && !ohci->ed_rm_list) {\r
-                       ohci->hc_control |= OHCI_CTRL_CLE;\r
-                       writel (0, &ohci->regs->ed_controlcurrent);\r
-                       writel (ohci->hc_control, &ohci->regs->control);\r
-               }\r
-               ohci->ed_controltail = ed;\r
-               break;\r
-\r
-       case PIPE_BULK:\r
-               if (ohci->ed_bulktail == NULL) {\r
-                       writel (ed->dma, &ohci->regs->ed_bulkhead);\r
-               } else {\r
-                       ohci->ed_bulktail->ed_next = ed;\r
-                       ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);\r
-               }\r
-               ed->ed_prev = ohci->ed_bulktail;\r
-               if (!ohci->ed_bulktail && !ohci->ed_rm_list) {\r
-                       ohci->hc_control |= OHCI_CTRL_BLE;\r
-                       writel (0, &ohci->regs->ed_bulkcurrent);\r
-                       writel (ohci->hc_control, &ohci->regs->control);\r
-               }\r
-               ohci->ed_bulktail = ed;\r
-               break;\r
-\r
-       // case PIPE_INTERRUPT:\r
-       // case PIPE_ISOCHRONOUS:\r
-       default:\r
-               branch = balance (ohci, ed->interval, ed->load);\r
-               if (branch < 0) {\r
-                       ohci_dbg (ohci,\r
-                               "ERR %d, interval %d msecs, load %d\n",\r
-                               branch, ed->interval, ed->load);\r
-                       // FIXME if there are TDs queued, fail them!\r
-                       return branch;\r
-               }\r
-               ed->branch = branch;\r
-               periodic_link (ohci, ed);\r
-       }               \r
-\r
-       /* the HC may not see the schedule updates yet, but if it does\r
-        * then they'll be properly ordered.\r
-        */\r
-       return 0;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* scan the periodic table to find and unlink this ED */\r
-static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)\r
-{\r
-       int     i;\r
-\r
-       for (i = ed->branch; i < NUM_INTS; i += ed->interval) {\r
-               struct ed       *temp;\r
-               struct ed       **prev = &ohci->periodic [i];\r
-               u32             *prev_p = &ohci->hcca->int_table [i];\r
-\r
-               while (*prev && (temp = *prev) != ed) {\r
-                       prev_p = &temp->hwNextED;\r
-                       prev = &temp->ed_next;\r
-               }\r
-               if (*prev) {\r
-                       *prev_p = ed->hwNextED;\r
-                       *prev = ed->ed_next;\r
-               }\r
-               ohci->load [i] -= ed->load;\r
-       }       \r
-       hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval;\r
-\r
-       ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",\r
-               (ed->hwINFO & ED_ISO) ? "iso " : "",\r
-               ed, ed->branch, ed->load, ed->interval);\r
-}\r
-\r
-/* unlink an ed from one of the HC chains. \r
- * just the link to the ed is unlinked.\r
- * the link from the ed still points to another operational ed or 0\r
- * so the HC can eventually finish the processing of the unlinked ed\r
- */\r
-static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) \r
-{\r
-       ed->hwINFO |= ED_SKIP;\r
-\r
-       switch (ed->type) {\r
-       case PIPE_CONTROL:\r
-               if (ed->ed_prev == NULL) {\r
-                       if (!ed->hwNextED) {\r
-                               ohci->hc_control &= ~OHCI_CTRL_CLE;\r
-                               writel (ohci->hc_control, &ohci->regs->control);\r
-                               writel (0, &ohci->regs->ed_controlcurrent);\r
-                               // post those pci writes\r
-                               (void) readl (&ohci->regs->control);\r
-                       }\r
-                       writel (le32_to_cpup (&ed->hwNextED),\r
-                               &ohci->regs->ed_controlhead);\r
-               } else {\r
-                       ed->ed_prev->ed_next = ed->ed_next;\r
-                       ed->ed_prev->hwNextED = ed->hwNextED;\r
-               }\r
-               if (ohci->ed_controltail == ed) {\r
-                       ohci->ed_controltail = ed->ed_prev;\r
-                       if (ohci->ed_controltail)\r
-                               ohci->ed_controltail->ed_next = 0;\r
-               } else if (ed->ed_next) {\r
-                       ed->ed_next->ed_prev = ed->ed_prev;\r
-               }\r
-               break;\r
-\r
-       case PIPE_BULK:\r
-               if (ed->ed_prev == NULL) {\r
-                       if (!ed->hwNextED) {\r
-                               ohci->hc_control &= ~OHCI_CTRL_BLE;\r
-                               writel (ohci->hc_control, &ohci->regs->control);\r
-                               writel (0, &ohci->regs->ed_bulkcurrent);\r
-                               // post those pci writes\r
-                               (void) readl (&ohci->regs->control);\r
-                       }\r
-                       writel (le32_to_cpup (&ed->hwNextED),\r
-                               &ohci->regs->ed_bulkhead);\r
-               } else {\r
-                       ed->ed_prev->ed_next = ed->ed_next;\r
-                       ed->ed_prev->hwNextED = ed->hwNextED;\r
-               }\r
-               if (ohci->ed_bulktail == ed) {\r
-                       ohci->ed_bulktail = ed->ed_prev;\r
-                       if (ohci->ed_bulktail)\r
-                               ohci->ed_bulktail->ed_next = 0;\r
-               } else if (ed->ed_next) {\r
-                       ed->ed_next->ed_prev = ed->ed_prev;\r
-               }\r
-               break;\r
-\r
-       // case PIPE_INTERRUPT:\r
-       // case PIPE_ISOCHRONOUS:\r
-       default:\r
-               periodic_unlink (ohci, ed);\r
-               break;\r
-       }\r
-\r
-       /* NOTE: Except for a couple of exceptionally clean unlink cases\r
-        * (like unlinking the only c/b ED, with no TDs) HCs may still be\r
-        * caching this operational ED (or its address).  Safe unlinking\r
-        * involves not marking it ED_IDLE till INTR_SF; we always do that\r
-        * if td_list isn't empty.  Otherwise the race is small; but ...\r
-        */\r
-       if (ed->state == ED_OPER) {\r
-               ed->state = ED_IDLE;\r
-               ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE);\r
-               ed->hwHeadP &= ~ED_H;\r
-               wmb ();\r
-       }\r
-}\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* get and maybe (re)init an endpoint. init _should_ be done only as part\r
- * of usb_set_configuration() or usb_set_interface() ... but the USB stack\r
- * isn't very stateful, so we re-init whenever the HC isn't looking.\r
- */\r
-static struct ed *ed_get (\r
-       struct ohci_hcd         *ohci,\r
-       struct usb_device       *udev,\r
-       unsigned int            pipe,\r
-       int                     interval\r
-) {\r
-       int                     is_out = !usb_pipein (pipe);\r
-       int                     type = usb_pipetype (pipe);\r
-       struct hcd_dev          *dev = (struct hcd_dev *) udev->hcpriv;\r
-       struct ed               *ed; \r
-       unsigned                ep;\r
-       unsigned long           flags;\r
-\r
-       ep = usb_pipeendpoint (pipe) << 1;\r
-       if (type != PIPE_CONTROL && is_out)\r
-               ep |= 1;\r
-\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-\r
-       if (!(ed = dev->ep [ep])) {\r
-               struct td       *td;\r
-\r
-               ed = ed_alloc (ohci, SLAB_ATOMIC);\r
-               if (!ed) {\r
-                       /* out of memory */\r
-                       goto done;\r
-               }\r
-               dev->ep [ep] = ed;\r
-\r
-               /* dummy td; end of td list for ed */\r
-               td = td_alloc (ohci, SLAB_ATOMIC);\r
-               if (!td) {\r
-                       /* out of memory */\r
-                       ed_free (ohci, ed);\r
-                       ed = 0;\r
-                       goto done;\r
-               }\r
-               ed->dummy = td;\r
-               ed->hwTailP = cpu_to_le32 (td->td_dma);\r
-               ed->hwHeadP = ed->hwTailP;      /* ED_C, ED_H zeroed */\r
-               ed->state = ED_IDLE;\r
-               ed->type = type;\r
-       }\r
-\r
-       /* NOTE: only ep0 currently needs this "re"init logic, during\r
-        * enumeration (after set_address, or if ep0 maxpacket >8).\r
-        */\r
-       if (ed->state == ED_IDLE) {\r
-               u32     info;\r
-\r
-               info = usb_pipedevice (pipe);\r
-               info |= (ep >> 1) << 7;\r
-               info |= usb_maxpacket (udev, pipe, is_out) << 16;\r
-               info = cpu_to_le32 (info);\r
-               if (udev->speed == USB_SPEED_LOW)\r
-                       info |= ED_LOWSPEED;\r
-               /* only control transfers store pids in tds */\r
-               if (type != PIPE_CONTROL) {\r
-                       info |= is_out ? ED_OUT : ED_IN;\r
-                       if (type != PIPE_BULK) {\r
-                               /* periodic transfers... */\r
-                               if (type == PIPE_ISOCHRONOUS)\r
-                                       info |= ED_ISO;\r
-                               else if (interval > 32) /* iso can be bigger */\r
-                                       interval = 32;\r
-                               ed->interval = interval;\r
-                               ed->load = usb_calc_bus_time (\r
-                                       udev->speed, !is_out,\r
-                                       type == PIPE_ISOCHRONOUS,\r
-                                       usb_maxpacket (udev, pipe, is_out))\r
-                                               / 1000;\r
-                       }\r
-               }\r
-               ed->hwINFO = info;\r
-       }\r
-\r
-done:\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-       return ed; \r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* request unlinking of an endpoint from an operational HC.\r
- * put the ep on the rm_list\r
- * real work is done at the next start frame (SF) hardware interrupt\r
- */\r
-static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)\r
-{    \r
-       ed->hwINFO |= ED_DEQUEUE;\r
-       ed->state = ED_UNLINK;\r
-       ed_deschedule (ohci, ed);\r
-\r
-       /* SF interrupt might get delayed; record the frame counter value that\r
-        * indicates when the HC isn't looking at it, so concurrent unlinks\r
-        * behave.  frame_no wraps every 2^16 msec, and changes right before\r
-        * SF is triggered.\r
-        */\r
-       ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;\r
-\r
-       /* rm_list is just singly linked, for simplicity */\r
-       ed->ed_next = ohci->ed_rm_list;\r
-       ed->ed_prev = 0;\r
-       ohci->ed_rm_list = ed;\r
-\r
-       /* enable SOF interrupt */\r
-       if (!ohci->sleeping) {\r
-               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);\r
-               writel (OHCI_INTR_SF, &ohci->regs->intrenable);\r
-               // flush those pci writes\r
-               (void) readl (&ohci->regs->control);\r
-       }\r
-}\r
-\r
-/*-------------------------------------------------------------------------*\r
- * TD handling functions\r
- *-------------------------------------------------------------------------*/\r
-\r
-/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */\r
-\r
-static void\r
-td_fill (struct ohci_hcd *ohci, u32 info,\r
-       dma_addr_t data, int len,\r
-       struct urb *urb, int index)\r
-{\r
-       struct td               *td, *td_pt;\r
-       struct urb_priv         *urb_priv = urb->hcpriv;\r
-       int                     is_iso = info & TD_ISO;\r
-       int                     hash;\r
-\r
-       // ASSERT (index < urb_priv->length);\r
-\r
-       /* aim for only one interrupt per urb.  mostly applies to control\r
-        * and iso; other urbs rarely need more than one TD per urb.\r
-        * this way, only final tds (or ones with an error) cause IRQs.\r
-        * at least immediately; use DI=6 in case any control request is\r
-        * tempted to die part way through.\r
-        *\r
-        * NOTE: could delay interrupts even for the last TD, and get fewer\r
-        * interrupts ... increasing per-urb latency by sharing interrupts.\r
-        * Drivers that queue bulk urbs may request that behavior.\r
-        */\r
-       if (index != (urb_priv->length - 1)\r
-                       || (urb->transfer_flags & URB_NO_INTERRUPT))\r
-               info |= TD_DI_SET (6);\r
-\r
-       /* use this td as the next dummy */\r
-       td_pt = urb_priv->td [index];\r
-\r
-       /* fill the old dummy TD */\r
-       td = urb_priv->td [index] = urb_priv->ed->dummy;\r
-       urb_priv->ed->dummy = td_pt;\r
-\r
-       td->ed = urb_priv->ed;\r
-       td->next_dl_td = NULL;\r
-       td->index = index;\r
-       td->urb = urb; \r
-       td->data_dma = data;\r
-       if (!len)\r
-               data = 0;\r
-\r
-       td->hwINFO = cpu_to_le32 (info);\r
-       if (is_iso) {\r
-               td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);\r
-               td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);\r
-               td->ed->last_iso = info & 0xffff;\r
-       } else {\r
-               td->hwCBP = cpu_to_le32 (data); \r
-       }                       \r
-       if (data)\r
-               td->hwBE = cpu_to_le32 (data + len - 1);\r
-       else\r
-               td->hwBE = 0;\r
-       td->hwNextTD = cpu_to_le32 (td_pt->td_dma);\r
-\r
-       /* append to queue */\r
-       list_add_tail (&td->td_list, &td->ed->td_list);\r
-\r
-       /* hash it for later reverse mapping */\r
-       hash = TD_HASH_FUNC (td->td_dma);\r
-       td->td_hash = ohci->td_hash [hash];\r
-       ohci->td_hash [hash] = td;\r
-\r
-       /* HC might read the TD (or cachelines) right away ... */\r
-       wmb ();\r
-       td->ed->hwTailP = td->hwNextTD;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* Prepare all TDs of a transfer, and queue them onto the ED.\r
- * Caller guarantees HC is active.\r
- * Usually the ED is already on the schedule, so TDs might be\r
- * processed as soon as they're queued.\r
- */\r
-static void td_submit_urb (\r
-       struct ohci_hcd *ohci,\r
-       struct urb      *urb\r
-) {\r
-       struct urb_priv *urb_priv = urb->hcpriv;\r
-       dma_addr_t      data;\r
-       int             data_len = urb->transfer_buffer_length;\r
-       int             cnt = 0;\r
-       u32             info = 0;\r
-       int             is_out = usb_pipeout (urb->pipe);\r
-\r
-       /* OHCI handles the bulk/interrupt data toggles itself.  We just\r
-        * use the device toggle bits for resetting, and rely on the fact\r
-        * that resetting toggle is meaningless if the endpoint is active.\r
-        */\r
-       if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {\r
-               usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),\r
-                       is_out, 1);\r
-               urb_priv->ed->hwHeadP &= ~ED_C;\r
-       }\r
-\r
-       urb_priv->td_cnt = 0;\r
-\r
-       if (data_len)\r
-               data = urb->transfer_dma;\r
-       else\r
-               data = 0;\r
-\r
-       /* NOTE:  TD_CC is set so we can tell which TDs the HC processed by\r
-        * using TD_CC_GET, as well as by seeing them on the done list.\r
-        * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.)\r
-        */\r
-       switch (urb_priv->ed->type) {\r
-\r
-       /* Bulk and interrupt are identical except for where in the schedule\r
-        * their EDs live.\r
-        */\r
-       case PIPE_INTERRUPT:\r
-               /* ... and periodic urbs have extra accounting */\r
-               hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs++;\r
-               /* FALLTHROUGH */\r
-       case PIPE_BULK:\r
-               info = is_out\r
-                       ? TD_T_TOGGLE | TD_CC | TD_DP_OUT\r
-                       : TD_T_TOGGLE | TD_CC | TD_DP_IN;\r
-               /* TDs _could_ transfer up to 8K each */\r
-               while (data_len > 4096) {\r
-                       td_fill (ohci, info, data, 4096, urb, cnt);\r
-                       data += 4096;\r
-                       data_len -= 4096;\r
-                       cnt++;\r
-               }\r
-               /* maybe avoid ED halt on final TD short read */\r
-               if (!(urb->transfer_flags & URB_SHORT_NOT_OK))\r
-                       info |= TD_R;\r
-               td_fill (ohci, info, data, data_len, urb, cnt);\r
-               cnt++;\r
-               if ((urb->transfer_flags & URB_ZERO_PACKET)\r
-                               && cnt < urb_priv->length) {\r
-                       td_fill (ohci, info, 0, 0, urb, cnt);\r
-                       cnt++;\r
-               }\r
-               /* maybe kickstart bulk list */\r
-               if (urb_priv->ed->type == PIPE_BULK) {\r
-                       wmb ();\r
-                       writel (OHCI_BLF, &ohci->regs->cmdstatus);\r
-               }\r
-               break;\r
-\r
-       /* control manages DATA0/DATA1 toggle per-request; SETUP resets it,\r
-        * any DATA phase works normally, and the STATUS ack is special.\r
-        */\r
-       case PIPE_CONTROL:\r
-               info = TD_CC | TD_DP_SETUP | TD_T_DATA0;\r
-               td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++);\r
-               if (data_len > 0) {\r
-                       info = TD_CC | TD_R | TD_T_DATA1;\r
-                       info |= is_out ? TD_DP_OUT : TD_DP_IN;\r
-                       /* NOTE:  mishandles transfers >8K, some >4K */\r
-                       td_fill (ohci, info, data, data_len, urb, cnt++);\r
-               }\r
-               info = is_out\r
-                       ? TD_CC | TD_DP_IN | TD_T_DATA1\r
-                       : TD_CC | TD_DP_OUT | TD_T_DATA1;\r
-               td_fill (ohci, info, data, 0, urb, cnt++);\r
-               /* maybe kickstart control list */\r
-               wmb ();\r
-               writel (OHCI_CLF, &ohci->regs->cmdstatus);\r
-               break;\r
-\r
-       /* ISO has no retransmit, so no toggle; and it uses special TDs.\r
-        * Each TD could handle multiple consecutive frames (interval 1);\r
-        * we could often reduce the number of TDs here.\r
-        */\r
-       case PIPE_ISOCHRONOUS:\r
-               for (cnt = 0; cnt < urb->number_of_packets; cnt++) {\r
-                       int     frame = urb->start_frame;\r
-\r
-                       // FIXME scheduling should handle frame counter\r
-                       // roll-around ... exotic case (and OHCI has\r
-                       // a 2^16 iso range, vs other HCs max of 2^10)\r
-                       frame += cnt * urb->interval;\r
-                       frame &= 0xffff;\r
-                       td_fill (ohci, TD_CC | TD_ISO | frame,\r
-                               data + urb->iso_frame_desc [cnt].offset,\r
-                               urb->iso_frame_desc [cnt].length, urb, cnt);\r
-               }\r
-               hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs++;\r
-               break;\r
-       }\r
-       // ASSERT (urb_priv->length == cnt);\r
-}\r
-\r
-/*-------------------------------------------------------------------------*\r
- * Done List handling functions\r
- *-------------------------------------------------------------------------*/\r
-\r
-/* calculate transfer length/status and update the urb\r
- * PRECONDITION:  irqsafe (only for urb->status locking)\r
- */\r
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)\r
-{\r
-       u32     tdINFO = le32_to_cpup (&td->hwINFO);\r
-       int     cc = 0;\r
-\r
-       list_del (&td->td_list);\r
-\r
-       /* ISO ... drivers see per-TD length/status */\r
-       if (tdINFO & TD_ISO) {\r
-               u16     tdPSW = le16_to_cpu (td->hwPSW [0]);\r
-               int     dlen = 0;\r
-\r
-               /* NOTE:  assumes FC in tdINFO == 0 (and MAXPSW == 1) */\r
-\r
-               cc = (tdPSW >> 12) & 0xF;\r
-               if (tdINFO & TD_CC)     /* hc didn't touch? */\r
-                       return;\r
-\r
-               if (usb_pipeout (urb->pipe))\r
-                       dlen = urb->iso_frame_desc [td->index].length;\r
-               else {\r
-                       /* short reads are always OK for ISO */\r
-                       if (cc == TD_DATAUNDERRUN)\r
-                               cc = TD_CC_NOERROR;\r
-                       dlen = tdPSW & 0x3ff;\r
-               }\r
-               urb->actual_length += dlen;\r
-               urb->iso_frame_desc [td->index].actual_length = dlen;\r
-               urb->iso_frame_desc [td->index].status = cc_to_error [cc];\r
-\r
-               if (cc != TD_CC_NOERROR)\r
-                       ohci_vdbg (ohci,\r
-                               "urb %p iso td %p (%d) len %d cc %d\n",\r
-                               urb, td, 1 + td->index, dlen, cc);\r
-\r
-       /* BULK, INT, CONTROL ... drivers see aggregate length/status,\r
-        * except that "setup" bytes aren't counted and "short" transfers\r
-        * might not be reported as errors.\r
-        */\r
-       } else {\r
-               int     type = usb_pipetype (urb->pipe);\r
-               u32     tdBE = le32_to_cpup (&td->hwBE);\r
-\r
-               cc = TD_CC_GET (tdINFO);\r
-\r
-               /* control endpoints only have soft stalls */\r
-               if (type != PIPE_CONTROL && cc == TD_CC_STALL)\r
-                       usb_endpoint_halt (urb->dev,\r
-                               usb_pipeendpoint (urb->pipe),\r
-                               usb_pipeout (urb->pipe));\r
-\r
-               /* update packet status if needed (short is normally ok) */\r
-               if (cc == TD_DATAUNDERRUN\r
-                               && !(urb->transfer_flags & URB_SHORT_NOT_OK))\r
-                       cc = TD_CC_NOERROR;\r
-               if (cc != TD_CC_NOERROR && cc < 0x0E) {\r
-                       spin_lock (&urb->lock);\r
-                       if (urb->status == -EINPROGRESS)\r
-                               urb->status = cc_to_error [cc];\r
-                       spin_unlock (&urb->lock);\r
-               }\r
-\r
-               /* count all non-empty packets except control SETUP packet */\r
-               if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {\r
-                       if (td->hwCBP == 0)\r
-                               urb->actual_length += tdBE - td->data_dma + 1;\r
-                       else\r
-                               urb->actual_length +=\r
-                                         le32_to_cpup (&td->hwCBP)\r
-                                       - td->data_dma;\r
-               }\r
-\r
-               if (cc != TD_CC_NOERROR && cc < 0x0E)\r
-                       ohci_vdbg (ohci,\r
-                               "urb %p td %p (%d) cc %d, len=%d/%d\n",\r
-                               urb, td, 1 + td->index, cc,\r
-                               urb->actual_length,\r
-                               urb->transfer_buffer_length);\r
-       }\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static inline struct td *\r
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)\r
-{\r
-       struct urb              *urb = td->urb;\r
-       struct ed               *ed = td->ed;\r
-       struct list_head        *tmp = td->td_list.next;\r
-       u32                     toggle = ed->hwHeadP & ED_C;\r
-\r
-       /* clear ed halt; this is the td that caused it, but keep it inactive\r
-        * until its urb->complete() has a chance to clean up.\r
-        */\r
-       ed->hwINFO |= ED_SKIP;\r
-       wmb ();\r
-       ed->hwHeadP &= ~ED_H; \r
-\r
-       /* put any later tds from this urb onto the donelist, after 'td',\r
-        * order won't matter here: no errors, and nothing was transferred.\r
-        * also patch the ed so it looks as if those tds completed normally.\r
-        */\r
-       while (tmp != &ed->td_list) {\r
-               struct td       *next;\r
-               u32             info;\r
-\r
-               next = list_entry (tmp, struct td, td_list);\r
-               tmp = next->td_list.next;\r
-\r
-               if (next->urb != urb)\r
-                       break;\r
-\r
-               /* NOTE: if multi-td control DATA segments get supported,\r
-                * this urb had one of them, this td wasn't the last td\r
-                * in that segment (TD_R clear), this ed halted because\r
-                * of a short read, _and_ URB_SHORT_NOT_OK is clear ...\r
-                * then we need to leave the control STATUS packet queued\r
-                * and clear ED_SKIP.\r
-                */\r
-               info = next->hwINFO;\r
-               info |= cpu_to_le32 (TD_DONE);\r
-               info &= ~cpu_to_le32 (TD_CC);\r
-               next->hwINFO = info;\r
-\r
-               next->next_dl_td = rev; \r
-               rev = next;\r
-\r
-               if (ed->hwTailP == cpu_to_le32 (next->td_dma))\r
-                       ed->hwTailP = next->hwNextTD;\r
-               ed->hwHeadP = next->hwNextTD | toggle;\r
-       }\r
-\r
-       /* help for troubleshooting:  report anything that\r
-        * looks odd ... that doesn't include protocol stalls\r
-        * (or maybe some other things)\r
-        */\r
-       if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe))\r
-               ohci_dbg (ohci,\r
-                       "urb %p path %s ep%d%s %08x cc %d --> status %d\n",\r
-                       urb, urb->dev->devpath,\r
-                       usb_pipeendpoint (urb->pipe),\r
-                       usb_pipein (urb->pipe) ? "in" : "out",\r
-                       le32_to_cpu (td->hwINFO),\r
-                       cc, cc_to_error [cc]);\r
-\r
-       return rev;\r
-}\r
-\r
-/* replies to the request have to be on a FIFO basis so\r
- * we unreverse the hc-reversed done-list\r
- */\r
-static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)\r
-{\r
-       u32             td_dma;\r
-       struct td       *td_rev = NULL;\r
-       struct td       *td = NULL;\r
-       unsigned long   flags;\r
-\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       td_dma = le32_to_cpup (&ohci->hcca->done_head);\r
-       ohci->hcca->done_head = 0;\r
-\r
-       /* get TD from hc's singly linked list, and\r
-        * prepend to ours.  ed->td_list changes later.\r
-        */\r
-       while (td_dma) {                \r
-               int             cc;\r
-\r
-               td = dma_to_td (ohci, td_dma);\r
-               if (!td) {\r
-                       ohci_err (ohci, "bad entry %8x\n", td_dma);\r
-                       break;\r
-               }\r
-\r
-               td->hwINFO |= cpu_to_le32 (TD_DONE);\r
-               cc = TD_CC_GET (le32_to_cpup (&td->hwINFO));\r
-\r
-               /* Non-iso endpoints can halt on error; un-halt,\r
-                * and dequeue any other TDs from this urb.\r
-                * No other TD could have caused the halt.\r
-                */\r
-               if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & ED_H))\r
-                       td_rev = ed_halted (ohci, td, cc, td_rev);\r
-\r
-               td->next_dl_td = td_rev;        \r
-               td_rev = td;\r
-               td_dma = le32_to_cpup (&td->hwNextTD);\r
-       }       \r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-       return td_rev;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* wrap-aware logic stolen from <linux/jiffies.h> */\r
-#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)\r
-\r
-/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */\r
-static void\r
-finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)\r
-{\r
-       struct ed       *ed, **last;\r
-\r
-rescan_all:\r
-       for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) {\r
-               struct list_head        *entry, *tmp;\r
-               int                     completed, modified;\r
-               u32                     *prev;\r
-\r
-               /* only take off EDs that the HC isn't using, accounting for\r
-                * frame counter wraps.\r
-                */\r
-               if (tick_before (tick, ed->tick) && !ohci->disabled) {\r
-                       last = &ed->ed_next;\r
-                       continue;\r
-               }\r
-\r
-               /* reentrancy:  if we drop the schedule lock, someone might\r
-                * have modified this list.  normally it's just prepending\r
-                * entries (which we'd ignore), but paranoia won't hurt.\r
-                */\r
-               *last = ed->ed_next;\r
-               ed->ed_next = 0;\r
-               modified = 0;\r
-\r
-               /* unlink urbs as requested, but rescan the list after\r
-                * we call a completion since it might have unlinked\r
-                * another (earlier) urb\r
-                */\r
-rescan_this:\r
-               completed = 0;\r
-               prev = &ed->hwHeadP;\r
-               list_for_each_safe (entry, tmp, &ed->td_list) {\r
-                       struct td       *td;\r
-                       struct urb      *urb;\r
-                       urb_priv_t      *urb_priv;\r
-                       u32             savebits;\r
-\r
-                       td = list_entry (entry, struct td, td_list);\r
-                       urb = td->urb;\r
-                       urb_priv = td->urb->hcpriv;\r
-\r
-                       if (urb_priv->state != URB_DEL) {\r
-                               prev = &td->hwNextTD;\r
-                               continue;\r
-                       }\r
-\r
-                       /* patch pointers hc uses ... tail, if we're removing\r
-                        * an otherwise active td, and whatever td pointer\r
-                        * points to this td\r
-                        */\r
-                       if (ed->hwTailP == cpu_to_le32 (td->td_dma))\r
-                               ed->hwTailP = td->hwNextTD;\r
-                       savebits = *prev & ~cpu_to_le32 (TD_MASK);\r
-                       *prev = td->hwNextTD | savebits;\r
-\r
-                       /* HC may have partly processed this TD */\r
-                       td_done (ohci, urb, td);\r
-                       urb_priv->td_cnt++;\r
-\r
-                       /* if URB is done, clean up */\r
-                       if (urb_priv->td_cnt == urb_priv->length) {\r
-                               modified = completed = 1;\r
-                               spin_unlock (&ohci->lock);\r
-                               finish_urb (ohci, urb, regs);\r
-                               spin_lock (&ohci->lock);\r
-                       }\r
-               }\r
-               if (completed && !list_empty (&ed->td_list))\r
-                       goto rescan_this;\r
-\r
-               /* ED's now officially unlinked, hc doesn't see */\r
-               ed->state = ED_IDLE;\r
-               ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE);\r
-               ed->hwHeadP &= ~ED_H;\r
-               ed->hwNextED = 0;\r
-\r
-               /* but if there's work queued, reschedule */\r
-               if (!list_empty (&ed->td_list)) {\r
-                       if (!ohci->disabled && !ohci->sleeping)\r
-                               ed_schedule (ohci, ed);\r
-               }\r
-\r
-               if (modified)\r
-                       goto rescan_all;\r
-       }\r
-\r
-       /* maybe reenable control and bulk lists */ \r
-       if (!ohci->disabled && !ohci->ed_rm_list) {\r
-               u32     command = 0, control = 0;\r
-\r
-               if (ohci->ed_controltail) {\r
-                       command |= OHCI_CLF;\r
-                       if (!(ohci->hc_control & OHCI_CTRL_CLE)) {\r
-                               control |= OHCI_CTRL_CLE;\r
-                               writel (0, &ohci->regs->ed_controlcurrent);\r
-                       }\r
-               }\r
-               if (ohci->ed_bulktail) {\r
-                       command |= OHCI_BLF;\r
-                       if (!(ohci->hc_control & OHCI_CTRL_BLE)) {\r
-                               control |= OHCI_CTRL_BLE;\r
-                               writel (0, &ohci->regs->ed_bulkcurrent);\r
-                       }\r
-               }\r
-               \r
-               /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */\r
-               if (control) {\r
-                       ohci->hc_control |= control;\r
-                       writel (ohci->hc_control, &ohci->regs->control);   \r
-               }\r
-               if (command)\r
-                       writel (command, &ohci->regs->cmdstatus);   \r
-       }\r
-}\r
-\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * Process normal completions (error or success) and clean the schedules.\r
- *\r
- * This is the main path for handing urbs back to drivers.  The only other\r
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of\r
- * scanning the (re-reversed) donelist as this does.\r
- */\r
-static void\r
-dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)\r
-{\r
-       unsigned long   flags;\r
-\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       while (td) {\r
-               struct td       *td_next = td->next_dl_td;\r
-               struct urb      *urb = td->urb;\r
-               urb_priv_t      *urb_priv = urb->hcpriv;\r
-               struct ed       *ed = td->ed;\r
-\r
-               /* update URB's length and status from TD */\r
-               td_done (ohci, urb, td);\r
-               urb_priv->td_cnt++;\r
-\r
-               /* If all this urb's TDs are done, call complete() */\r
-               if (urb_priv->td_cnt == urb_priv->length) {\r
-                       spin_unlock (&ohci->lock);\r
-                       finish_urb (ohci, urb, regs);\r
-                       spin_lock (&ohci->lock);\r
-               }\r
-\r
-               /* clean schedule:  unlink EDs that are no longer busy */\r
-               if (list_empty (&ed->td_list))\r
-                       ed_deschedule (ohci, ed);\r
-               /* ... reenabling halted EDs only after fault cleanup */\r
-               else if (!(ed->hwINFO & ED_DEQUEUE)) {\r
-                       td = list_entry (ed->td_list.next, struct td, td_list);\r
-                       if (!(td->hwINFO & TD_DONE))\r
-                               ed->hwINFO &= ~ED_SKIP;\r
-               }\r
-\r
-               td = td_next;\r
-       }  \r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-}\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under the GPL.
+ */
+
+static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
+{
+       int             last = urb_priv->length - 1;
+
+       if (last >= 0) {
+               int             i;
+               struct td       *td;
+
+               for (i = 0; i <= last; i++) {
+                       td = urb_priv->td [i];
+                       if (td)
+                               td_free (hc, td);
+               }
+       }
+
+       kfree (urb_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * URB goes back to driver, and isn't reissued.
+ * It's completely gone from HC data structures.
+ * PRECONDITION:  no locks held, irqs blocked  (Giveback can call into HCD.)
+ */
+static void
+finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
+{
+       // ASSERT (urb->hcpriv != 0);
+
+       urb_free_priv (ohci, urb->hcpriv);
+       urb->hcpriv = NULL;
+
+       spin_lock (&urb->lock);
+       if (likely (urb->status == -EINPROGRESS))
+               urb->status = 0;
+       spin_unlock (&urb->lock);
+
+       // what lock protects these?
+       switch (usb_pipetype (urb->pipe)) {
+       case PIPE_ISOCHRONOUS:
+               hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs--;
+               break;
+       case PIPE_INTERRUPT:
+               hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs--;
+               break;
+       }
+
+#ifdef OHCI_VERBOSE_DEBUG
+       urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+       usb_hcd_giveback_urb (&ohci->hcd, urb, regs);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+
+/* search for the right schedule branch to use for a periodic ed.
+ * does some load balancing; returns the branch, or negative errno.
+ */
+static int balance (struct ohci_hcd *ohci, int interval, int load)
+{
+       int     i, branch = -ENOSPC;
+
+       /* iso periods can be huge; iso tds specify frame numbers */
+       if (interval > NUM_INTS)
+               interval = NUM_INTS;
+
+       /* search for the least loaded schedule branch of that period
+        * that has enough bandwidth left unreserved.
+        */
+       for (i = 0; i < interval ; i++) {
+               if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
+#if 1  /* CONFIG_USB_BANDWIDTH */
+                       int     j;
+
+                       /* usb 1.1 says 90% of one frame */
+                       for (j = i; j < NUM_INTS; j += interval) {
+                               if ((ohci->load [j] + load) > 900)
+                                       break;
+                       }
+                       if (j < NUM_INTS)
+                               continue;
+#endif
+                       branch = i; 
+               }
+       }
+       return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* both iso and interrupt requests have periods; this routine puts them
+ * into the schedule tree in the apppropriate place.  most iso devices use
+ * 1msec periods, but that's not required.
+ */
+static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
+{
+       unsigned        i;
+
+       ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n",
+               (ed->hwINFO & ED_ISO) ? "iso " : "",
+               ed, ed->branch, ed->load, ed->interval);
+
+       for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
+               struct ed       **prev = &ohci->periodic [i];
+               u32             *prev_p = &ohci->hcca->int_table [i];
+               struct ed       *here = *prev;
+
+               /* sorting each branch by period (slow before fast)
+                * lets us share the faster parts of the tree.
+                * (plus maybe: put interrupt eds before iso)
+                */
+               while (here && ed != here) {
+                       if (ed->interval > here->interval)
+                               break;
+                       prev = &here->ed_next;
+                       prev_p = &here->hwNextED;
+                       here = *prev;
+               }
+               if (ed != here) {
+                       ed->ed_next = here;
+                       if (here)
+                               ed->hwNextED = *prev_p;
+                       wmb ();
+                       *prev = ed;
+                       *prev_p = cpu_to_le32p (&ed->dma);
+               }
+               ohci->load [i] += ed->load;
+       }
+       hcd_to_bus (&ohci->hcd)->bandwidth_allocated += ed->load / ed->interval;
+}
+
+/* link an ed into one of the HC chains */
+
+static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
+{       
+       int     branch;
+
+       ed->state = ED_OPER;
+       ed->ed_prev = 0;
+       ed->ed_next = 0;
+       ed->hwNextED = 0;
+       wmb ();
+
+       /* we care about rm_list when setting CLE/BLE in case the HC was at
+        * work on some TD when CLE/BLE was turned off, and isn't quiesced
+        * yet.  finish_unlinks() restarts as needed, some upcoming INTR_SF.
+        *
+        * control and bulk EDs are doubly linked (ed_next, ed_prev), but
+        * periodic ones are singly linked (ed_next). that's because the
+        * periodic schedule encodes a tree like figure 3-5 in the ohci
+        * spec:  each qh can have several "previous" nodes, and the tree
+        * doesn't have unused/idle descriptors.
+        */
+       switch (ed->type) {
+       case PIPE_CONTROL:
+               if (ohci->ed_controltail == NULL) {
+                       writel (ed->dma, &ohci->regs->ed_controlhead);
+               } else {
+                       ohci->ed_controltail->ed_next = ed;
+                       ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
+               }
+               ed->ed_prev = ohci->ed_controltail;
+               if (!ohci->ed_controltail && !ohci->ed_rm_list) {
+                       ohci->hc_control |= OHCI_CTRL_CLE;
+                       writel (0, &ohci->regs->ed_controlcurrent);
+                       writel (ohci->hc_control, &ohci->regs->control);
+               }
+               ohci->ed_controltail = ed;
+               break;
+
+       case PIPE_BULK:
+               if (ohci->ed_bulktail == NULL) {
+                       writel (ed->dma, &ohci->regs->ed_bulkhead);
+               } else {
+                       ohci->ed_bulktail->ed_next = ed;
+                       ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
+               }
+               ed->ed_prev = ohci->ed_bulktail;
+               if (!ohci->ed_bulktail && !ohci->ed_rm_list) {
+                       ohci->hc_control |= OHCI_CTRL_BLE;
+                       writel (0, &ohci->regs->ed_bulkcurrent);
+                       writel (ohci->hc_control, &ohci->regs->control);
+               }
+               ohci->ed_bulktail = ed;
+               break;
+
+       // case PIPE_INTERRUPT:
+       // case PIPE_ISOCHRONOUS:
+       default:
+               branch = balance (ohci, ed->interval, ed->load);
+               if (branch < 0) {
+                       ohci_dbg (ohci,
+                               "ERR %d, interval %d msecs, load %d\n",
+                               branch, ed->interval, ed->load);
+                       // FIXME if there are TDs queued, fail them!
+                       return branch;
+               }
+               ed->branch = branch;
+               periodic_link (ohci, ed);
+       }               
+
+       /* the HC may not see the schedule updates yet, but if it does
+        * then they'll be properly ordered.
+        */
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{
+       int     i;
+
+       for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
+               struct ed       *temp;
+               struct ed       **prev = &ohci->periodic [i];
+               u32             *prev_p = &ohci->hcca->int_table [i];
+
+               while (*prev && (temp = *prev) != ed) {
+                       prev_p = &temp->hwNextED;
+                       prev = &temp->ed_next;
+               }
+               if (*prev) {
+                       *prev_p = ed->hwNextED;
+                       *prev = ed->ed_next;
+               }
+               ohci->load [i] -= ed->load;
+       }       
+       hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval;
+
+       ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",
+               (ed->hwINFO & ED_ISO) ? "iso " : "",
+               ed, ed->branch, ed->load, ed->interval);
+}
+
+/* unlink an ed from one of the HC chains. 
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed
+ */
+static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) 
+{
+       ed->hwINFO |= ED_SKIP;
+
+       switch (ed->type) {
+       case PIPE_CONTROL:
+               if (ed->ed_prev == NULL) {
+                       if (!ed->hwNextED) {
+                               ohci->hc_control &= ~OHCI_CTRL_CLE;
+                               writel (ohci->hc_control, &ohci->regs->control);
+                               writel (0, &ohci->regs->ed_controlcurrent);
+                               // post those pci writes
+                               (void) readl (&ohci->regs->control);
+                       }
+                       writel (le32_to_cpup (&ed->hwNextED),
+                               &ohci->regs->ed_controlhead);
+               } else {
+                       ed->ed_prev->ed_next = ed->ed_next;
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               }
+               if (ohci->ed_controltail == ed) {
+                       ohci->ed_controltail = ed->ed_prev;
+                       if (ohci->ed_controltail)
+                               ohci->ed_controltail->ed_next = 0;
+               } else if (ed->ed_next) {
+                       ed->ed_next->ed_prev = ed->ed_prev;
+               }
+               break;
+
+       case PIPE_BULK:
+               if (ed->ed_prev == NULL) {
+                       if (!ed->hwNextED) {
+                               ohci->hc_control &= ~OHCI_CTRL_BLE;
+                               writel (ohci->hc_control, &ohci->regs->control);
+                               writel (0, &ohci->regs->ed_bulkcurrent);
+                               // post those pci writes
+                               (void) readl (&ohci->regs->control);
+                       }
+                       writel (le32_to_cpup (&ed->hwNextED),
+                               &ohci->regs->ed_bulkhead);
+               } else {
+                       ed->ed_prev->ed_next = ed->ed_next;
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               }
+               if (ohci->ed_bulktail == ed) {
+                       ohci->ed_bulktail = ed->ed_prev;
+                       if (ohci->ed_bulktail)
+                               ohci->ed_bulktail->ed_next = 0;
+               } else if (ed->ed_next) {
+                       ed->ed_next->ed_prev = ed->ed_prev;
+               }
+               break;
+
+       // case PIPE_INTERRUPT:
+       // case PIPE_ISOCHRONOUS:
+       default:
+               periodic_unlink (ohci, ed);
+               break;
+       }
+
+       /* NOTE: Except for a couple of exceptionally clean unlink cases
+        * (like unlinking the only c/b ED, with no TDs) HCs may still be
+        * caching this operational ED (or its address).  Safe unlinking
+        * involves not marking it ED_IDLE till INTR_SF; we always do that
+        * if td_list isn't empty.  Otherwise the race is small; but ...
+        */
+       if (ed->state == ED_OPER) {
+               ed->state = ED_IDLE;
+               ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE);
+               ed->hwHeadP &= ~ED_H;
+               wmb ();
+       }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* get and maybe (re)init an endpoint. init _should_ be done only as part
+ * of usb_set_configuration() or usb_set_interface() ... but the USB stack
+ * isn't very stateful, so we re-init whenever the HC isn't looking.
+ */
+static struct ed *ed_get (
+       struct ohci_hcd         *ohci,
+       struct usb_device       *udev,
+       unsigned int            pipe,
+       int                     interval
+) {
+       int                     is_out = !usb_pipein (pipe);
+       int                     type = usb_pipetype (pipe);
+       struct hcd_dev          *dev = (struct hcd_dev *) udev->hcpriv;
+       struct ed               *ed; 
+       unsigned                ep;
+       unsigned long           flags;
+
+       ep = usb_pipeendpoint (pipe) << 1;
+       if (type != PIPE_CONTROL && is_out)
+               ep |= 1;
+
+       spin_lock_irqsave (&ohci->lock, flags);
+
+       if (!(ed = dev->ep [ep])) {
+               struct td       *td;
+
+               ed = ed_alloc (ohci, SLAB_ATOMIC);
+               if (!ed) {
+                       /* out of memory */
+                       goto done;
+               }
+               dev->ep [ep] = ed;
+
+               /* dummy td; end of td list for ed */
+               td = td_alloc (ohci, SLAB_ATOMIC);
+               if (!td) {
+                       /* out of memory */
+                       ed_free (ohci, ed);
+                       ed = 0;
+                       goto done;
+               }
+               ed->dummy = td;
+               ed->hwTailP = cpu_to_le32 (td->td_dma);
+               ed->hwHeadP = ed->hwTailP;      /* ED_C, ED_H zeroed */
+               ed->state = ED_IDLE;
+               ed->type = type;
+       }
+
+       /* NOTE: only ep0 currently needs this "re"init logic, during
+        * enumeration (after set_address, or if ep0 maxpacket >8).
+        */
+       if (ed->state == ED_IDLE) {
+               u32     info;
+
+               info = usb_pipedevice (pipe);
+               info |= (ep >> 1) << 7;
+               info |= usb_maxpacket (udev, pipe, is_out) << 16;
+               info = cpu_to_le32 (info);
+               if (udev->speed == USB_SPEED_LOW)
+                       info |= ED_LOWSPEED;
+               /* only control transfers store pids in tds */
+               if (type != PIPE_CONTROL) {
+                       info |= is_out ? ED_OUT : ED_IN;
+                       if (type != PIPE_BULK) {
+                               /* periodic transfers... */
+                               if (type == PIPE_ISOCHRONOUS)
+                                       info |= ED_ISO;
+                               else if (interval > 32) /* iso can be bigger */
+                                       interval = 32;
+                               ed->interval = interval;
+                               ed->load = usb_calc_bus_time (
+                                       udev->speed, !is_out,
+                                       type == PIPE_ISOCHRONOUS,
+                                       usb_maxpacket (udev, pipe, is_out))
+                                               / 1000;
+                       }
+               }
+               ed->hwINFO = info;
+       }
+
+done:
+       spin_unlock_irqrestore (&ohci->lock, flags);
+       return ed; 
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* request unlinking of an endpoint from an operational HC.
+ * put the ep on the rm_list
+ * real work is done at the next start frame (SF) hardware interrupt
+ */
+static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{    
+       ed->hwINFO |= ED_DEQUEUE;
+       ed->state = ED_UNLINK;
+       ed_deschedule (ohci, ed);
+
+       /* SF interrupt might get delayed; record the frame counter value that
+        * indicates when the HC isn't looking at it, so concurrent unlinks
+        * behave.  frame_no wraps every 2^16 msec, and changes right before
+        * SF is triggered.
+        */
+       ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;
+
+       /* rm_list is just singly linked, for simplicity */
+       ed->ed_next = ohci->ed_rm_list;
+       ed->ed_prev = 0;
+       ohci->ed_rm_list = ed;
+
+       /* enable SOF interrupt */
+       if (!ohci->sleeping) {
+               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+               writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+               // flush those pci writes
+               (void) readl (&ohci->regs->control);
+       }
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void
+td_fill (struct ohci_hcd *ohci, u32 info,
+       dma_addr_t data, int len,
+       struct urb *urb, int index)
+{
+       struct td               *td, *td_pt;
+       struct urb_priv         *urb_priv = urb->hcpriv;
+       int                     is_iso = info & TD_ISO;
+       int                     hash;
+
+       // ASSERT (index < urb_priv->length);
+
+       /* aim for only one interrupt per urb.  mostly applies to control
+        * and iso; other urbs rarely need more than one TD per urb.
+        * this way, only final tds (or ones with an error) cause IRQs.
+        * at least immediately; use DI=6 in case any control request is
+        * tempted to die part way through.
+        *
+        * NOTE: could delay interrupts even for the last TD, and get fewer
+        * interrupts ... increasing per-urb latency by sharing interrupts.
+        * Drivers that queue bulk urbs may request that behavior.
+        */
+       if (index != (urb_priv->length - 1)
+                       || (urb->transfer_flags & URB_NO_INTERRUPT))
+               info |= TD_DI_SET (6);
+
+       /* use this td as the next dummy */
+       td_pt = urb_priv->td [index];
+
+       /* fill the old dummy TD */
+       td = urb_priv->td [index] = urb_priv->ed->dummy;
+       urb_priv->ed->dummy = td_pt;
+
+       td->ed = urb_priv->ed;
+       td->next_dl_td = NULL;
+       td->index = index;
+       td->urb = urb; 
+       td->data_dma = data;
+       if (!len)
+               data = 0;
+
+       td->hwINFO = cpu_to_le32 (info);
+       if (is_iso) {
+               td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
+               td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
+               td->ed->last_iso = info & 0xffff;
+       } else {
+               td->hwCBP = cpu_to_le32 (data); 
+       }                       
+       if (data)
+               td->hwBE = cpu_to_le32 (data + len - 1);
+       else
+               td->hwBE = 0;
+       td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
+
+       /* append to queue */
+       list_add_tail (&td->td_list, &td->ed->td_list);
+
+       /* hash it for later reverse mapping */
+       hash = TD_HASH_FUNC (td->td_dma);
+       td->td_hash = ohci->td_hash [hash];
+       ohci->td_hash [hash] = td;
+
+       /* HC might read the TD (or cachelines) right away ... */
+       wmb ();
+       td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Prepare all TDs of a transfer, and queue them onto the ED.
+ * Caller guarantees HC is active.
+ * Usually the ED is already on the schedule, so TDs might be
+ * processed as soon as they're queued.
+ */
+static void td_submit_urb (
+       struct ohci_hcd *ohci,
+       struct urb      *urb
+) {
+       struct urb_priv *urb_priv = urb->hcpriv;
+       dma_addr_t      data;
+       int             data_len = urb->transfer_buffer_length;
+       int             cnt = 0;
+       u32             info = 0;
+       int             is_out = usb_pipeout (urb->pipe);
+
+       /* OHCI handles the bulk/interrupt data toggles itself.  We just
+        * use the device toggle bits for resetting, and rely on the fact
+        * that resetting toggle is meaningless if the endpoint is active.
+        */
+       if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
+               usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+                       is_out, 1);
+               urb_priv->ed->hwHeadP &= ~ED_C;
+       }
+
+       urb_priv->td_cnt = 0;
+
+       if (data_len)
+               data = urb->transfer_dma;
+       else
+               data = 0;
+
+       /* NOTE:  TD_CC is set so we can tell which TDs the HC processed by
+        * using TD_CC_GET, as well as by seeing them on the done list.
+        * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.)
+        */
+       switch (urb_priv->ed->type) {
+
+       /* Bulk and interrupt are identical except for where in the schedule
+        * their EDs live.
+        */
+       case PIPE_INTERRUPT:
+               /* ... and periodic urbs have extra accounting */
+               hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs++;
+               /* FALLTHROUGH */
+       case PIPE_BULK:
+               info = is_out
+                       ? TD_T_TOGGLE | TD_CC | TD_DP_OUT
+                       : TD_T_TOGGLE | TD_CC | TD_DP_IN;
+               /* TDs _could_ transfer up to 8K each */
+               while (data_len > 4096) {
+                       td_fill (ohci, info, data, 4096, urb, cnt);
+                       data += 4096;
+                       data_len -= 4096;
+                       cnt++;
+               }
+               /* maybe avoid ED halt on final TD short read */
+               if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+                       info |= TD_R;
+               td_fill (ohci, info, data, data_len, urb, cnt);
+               cnt++;
+               if ((urb->transfer_flags & URB_ZERO_PACKET)
+                               && cnt < urb_priv->length) {
+                       td_fill (ohci, info, 0, 0, urb, cnt);
+                       cnt++;
+               }
+               /* maybe kickstart bulk list */
+               if (urb_priv->ed->type == PIPE_BULK) {
+                       wmb ();
+                       writel (OHCI_BLF, &ohci->regs->cmdstatus);
+               }
+               break;
+
+       /* control manages DATA0/DATA1 toggle per-request; SETUP resets it,
+        * any DATA phase works normally, and the STATUS ack is special.
+        */
+       case PIPE_CONTROL:
+               info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+               td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++);
+               if (data_len > 0) {
+                       info = TD_CC | TD_R | TD_T_DATA1;
+                       info |= is_out ? TD_DP_OUT : TD_DP_IN;
+                       /* NOTE:  mishandles transfers >8K, some >4K */
+                       td_fill (ohci, info, data, data_len, urb, cnt++);
+               }
+               info = is_out
+                       ? TD_CC | TD_DP_IN | TD_T_DATA1
+                       : TD_CC | TD_DP_OUT | TD_T_DATA1;
+               td_fill (ohci, info, data, 0, urb, cnt++);
+               /* maybe kickstart control list */
+               wmb ();
+               writel (OHCI_CLF, &ohci->regs->cmdstatus);
+               break;
+
+       /* ISO has no retransmit, so no toggle; and it uses special TDs.
+        * Each TD could handle multiple consecutive frames (interval 1);
+        * we could often reduce the number of TDs here.
+        */
+       case PIPE_ISOCHRONOUS:
+               for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+                       int     frame = urb->start_frame;
+
+                       // FIXME scheduling should handle frame counter
+                       // roll-around ... exotic case (and OHCI has
+                       // a 2^16 iso range, vs other HCs max of 2^10)
+                       frame += cnt * urb->interval;
+                       frame &= 0xffff;
+                       td_fill (ohci, TD_CC | TD_ISO | frame,
+                               data + urb->iso_frame_desc [cnt].offset,
+                               urb->iso_frame_desc [cnt].length, urb, cnt);
+               }
+               hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs++;
+               break;
+       }
+       // ASSERT (urb_priv->length == cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate transfer length/status and update the urb
+ * PRECONDITION:  irqsafe (only for urb->status locking)
+ */
+static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+{
+       u32     tdINFO = le32_to_cpup (&td->hwINFO);
+       int     cc = 0;
+
+       list_del (&td->td_list);
+
+       /* ISO ... drivers see per-TD length/status */
+       if (tdINFO & TD_ISO) {
+               u16     tdPSW = le16_to_cpu (td->hwPSW [0]);
+               int     dlen = 0;
+
+               /* NOTE:  assumes FC in tdINFO == 0 (and MAXPSW == 1) */
+
+               cc = (tdPSW >> 12) & 0xF;
+               if (tdINFO & TD_CC)     /* hc didn't touch? */
+                       return;
+
+               if (usb_pipeout (urb->pipe))
+                       dlen = urb->iso_frame_desc [td->index].length;
+               else {
+                       /* short reads are always OK for ISO */
+                       if (cc == TD_DATAUNDERRUN)
+                               cc = TD_CC_NOERROR;
+                       dlen = tdPSW & 0x3ff;
+               }
+               urb->actual_length += dlen;
+               urb->iso_frame_desc [td->index].actual_length = dlen;
+               urb->iso_frame_desc [td->index].status = cc_to_error [cc];
+
+               if (cc != TD_CC_NOERROR)
+                       ohci_vdbg (ohci,
+                               "urb %p iso td %p (%d) len %d cc %d\n",
+                               urb, td, 1 + td->index, dlen, cc);
+
+       /* BULK, INT, CONTROL ... drivers see aggregate length/status,
+        * except that "setup" bytes aren't counted and "short" transfers
+        * might not be reported as errors.
+        */
+       } else {
+               int     type = usb_pipetype (urb->pipe);
+               u32     tdBE = le32_to_cpup (&td->hwBE);
+
+               cc = TD_CC_GET (tdINFO);
+
+               /* control endpoints only have soft stalls */
+               if (type != PIPE_CONTROL && cc == TD_CC_STALL)
+                       usb_endpoint_halt (urb->dev,
+                               usb_pipeendpoint (urb->pipe),
+                               usb_pipeout (urb->pipe));
+
+               /* update packet status if needed (short is normally ok) */
+               if (cc == TD_DATAUNDERRUN
+                               && !(urb->transfer_flags & URB_SHORT_NOT_OK))
+                       cc = TD_CC_NOERROR;
+               if (cc != TD_CC_NOERROR && cc < 0x0E) {
+                       spin_lock (&urb->lock);
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = cc_to_error [cc];
+                       spin_unlock (&urb->lock);
+               }
+
+               /* count all non-empty packets except control SETUP packet */
+               if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
+                       if (td->hwCBP == 0)
+                               urb->actual_length += tdBE - td->data_dma + 1;
+                       else
+                               urb->actual_length +=
+                                         le32_to_cpup (&td->hwCBP)
+                                       - td->data_dma;
+               }
+
+               if (cc != TD_CC_NOERROR && cc < 0x0E)
+                       ohci_vdbg (ohci,
+                               "urb %p td %p (%d) cc %d, len=%d/%d\n",
+                               urb, td, 1 + td->index, cc,
+                               urb->actual_length,
+                               urb->transfer_buffer_length);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline struct td *
+ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+{
+       struct urb              *urb = td->urb;
+       struct ed               *ed = td->ed;
+       struct list_head        *tmp = td->td_list.next;
+       u32                     toggle = ed->hwHeadP & ED_C;
+
+       /* clear ed halt; this is the td that caused it, but keep it inactive
+        * until its urb->complete() has a chance to clean up.
+        */
+       ed->hwINFO |= ED_SKIP;
+       wmb ();
+       ed->hwHeadP &= ~ED_H; 
+
+       /* put any later tds from this urb onto the donelist, after 'td',
+        * order won't matter here: no errors, and nothing was transferred.
+        * also patch the ed so it looks as if those tds completed normally.
+        */
+       while (tmp != &ed->td_list) {
+               struct td       *next;
+               u32             info;
+
+               next = list_entry (tmp, struct td, td_list);
+               tmp = next->td_list.next;
+
+               if (next->urb != urb)
+                       break;
+
+               /* NOTE: if multi-td control DATA segments get supported,
+                * this urb had one of them, this td wasn't the last td
+                * in that segment (TD_R clear), this ed halted because
+                * of a short read, _and_ URB_SHORT_NOT_OK is clear ...
+                * then we need to leave the control STATUS packet queued
+                * and clear ED_SKIP.
+                */
+               info = next->hwINFO;
+               info |= cpu_to_le32 (TD_DONE);
+               info &= ~cpu_to_le32 (TD_CC);
+               next->hwINFO = info;
+
+               next->next_dl_td = rev; 
+               rev = next;
+
+               if (ed->hwTailP == cpu_to_le32 (next->td_dma))
+                       ed->hwTailP = next->hwNextTD;
+               ed->hwHeadP = next->hwNextTD | toggle;
+       }
+
+       /* help for troubleshooting:  report anything that
+        * looks odd ... that doesn't include protocol stalls
+        * (or maybe some other things)
+        */
+       if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe))
+               ohci_dbg (ohci,
+                       "urb %p path %s ep%d%s %08x cc %d --> status %d\n",
+                       urb, urb->dev->devpath,
+                       usb_pipeendpoint (urb->pipe),
+                       usb_pipein (urb->pipe) ? "in" : "out",
+                       le32_to_cpu (td->hwINFO),
+                       cc, cc_to_error [cc]);
+
+       return rev;
+}
+
+/* replies to the request have to be on a FIFO basis so
+ * we unreverse the hc-reversed done-list
+ */
+static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
+{
+       u32             td_dma;
+       struct td       *td_rev = NULL;
+       struct td       *td = NULL;
+       unsigned long   flags;
+
+       spin_lock_irqsave (&ohci->lock, flags);
+       td_dma = le32_to_cpup (&ohci->hcca->done_head);
+       ohci->hcca->done_head = 0;
+
+       /* get TD from hc's singly linked list, and
+        * prepend to ours.  ed->td_list changes later.
+        */
+       while (td_dma) {                
+               int             cc;
+
+               td = dma_to_td (ohci, td_dma);
+               if (!td) {
+                       ohci_err (ohci, "bad entry %8x\n", td_dma);
+                       break;
+               }
+
+               td->hwINFO |= cpu_to_le32 (TD_DONE);
+               cc = TD_CC_GET (le32_to_cpup (&td->hwINFO));
+
+               /* Non-iso endpoints can halt on error; un-halt,
+                * and dequeue any other TDs from this urb.
+                * No other TD could have caused the halt.
+                */
+               if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & ED_H))
+                       td_rev = ed_halted (ohci, td, cc, td_rev);
+
+               td->next_dl_td = td_rev;        
+               td_rev = td;
+               td_dma = le32_to_cpup (&td->hwNextTD);
+       }       
+       spin_unlock_irqrestore (&ohci->lock, flags);
+       return td_rev;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* wrap-aware logic stolen from <linux/jiffies.h> */
+#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
+
+/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
+static void
+finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
+{
+       struct ed       *ed, **last;
+
+rescan_all:
+       for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) {
+               struct list_head        *entry, *tmp;
+               int                     completed, modified;
+               u32                     *prev;
+
+               /* only take off EDs that the HC isn't using, accounting for
+                * frame counter wraps.
+                */
+               if (tick_before (tick, ed->tick) && !ohci->disabled) {
+                       last = &ed->ed_next;
+                       continue;
+               }
+
+               /* reentrancy:  if we drop the schedule lock, someone might
+                * have modified this list.  normally it's just prepending
+                * entries (which we'd ignore), but paranoia won't hurt.
+                */
+               *last = ed->ed_next;
+               ed->ed_next = 0;
+               modified = 0;
+
+               /* unlink urbs as requested, but rescan the list after
+                * we call a completion since it might have unlinked
+                * another (earlier) urb
+                */
+rescan_this:
+               completed = 0;
+               prev = &ed->hwHeadP;
+               list_for_each_safe (entry, tmp, &ed->td_list) {
+                       struct td       *td;
+                       struct urb      *urb;
+                       urb_priv_t      *urb_priv;
+                       u32             savebits;
+
+                       td = list_entry (entry, struct td, td_list);
+                       urb = td->urb;
+                       urb_priv = td->urb->hcpriv;
+
+                       if (urb_priv->state != URB_DEL) {
+                               prev = &td->hwNextTD;
+                               continue;
+                       }
+
+                       /* patch pointers hc uses ... tail, if we're removing
+                        * an otherwise active td, and whatever td pointer
+                        * points to this td
+                        */
+                       if (ed->hwTailP == cpu_to_le32 (td->td_dma))
+                               ed->hwTailP = td->hwNextTD;
+                       savebits = *prev & ~cpu_to_le32 (TD_MASK);
+                       *prev = td->hwNextTD | savebits;
+
+                       /* HC may have partly processed this TD */
+                       td_done (ohci, urb, td);
+                       urb_priv->td_cnt++;
+
+                       /* if URB is done, clean up */
+                       if (urb_priv->td_cnt == urb_priv->length) {
+                               modified = completed = 1;
+                               spin_unlock (&ohci->lock);
+                               finish_urb (ohci, urb, regs);
+                               spin_lock (&ohci->lock);
+                       }
+               }
+               if (completed && !list_empty (&ed->td_list))
+                       goto rescan_this;
+
+               /* ED's now officially unlinked, hc doesn't see */
+               ed->state = ED_IDLE;
+               ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE);
+               ed->hwHeadP &= ~ED_H;
+               ed->hwNextED = 0;
+
+               /* but if there's work queued, reschedule */
+               if (!list_empty (&ed->td_list)) {
+                       if (!ohci->disabled && !ohci->sleeping)
+                               ed_schedule (ohci, ed);
+               }
+
+               if (modified)
+                       goto rescan_all;
+       }
+
+       /* maybe reenable control and bulk lists */ 
+       if (!ohci->disabled && !ohci->ed_rm_list) {
+               u32     command = 0, control = 0;
+
+               if (ohci->ed_controltail) {
+                       command |= OHCI_CLF;
+                       if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
+                               control |= OHCI_CTRL_CLE;
+                               writel (0, &ohci->regs->ed_controlcurrent);
+                       }
+               }
+               if (ohci->ed_bulktail) {
+                       command |= OHCI_BLF;
+                       if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
+                               control |= OHCI_CTRL_BLE;
+                               writel (0, &ohci->regs->ed_bulkcurrent);
+                       }
+               }
+               
+               /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
+               if (control) {
+                       ohci->hc_control |= control;
+                       writel (ohci->hc_control, &ohci->regs->control);   
+               }
+               if (command)
+                       writel (command, &ohci->regs->cmdstatus);   
+       }
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Process normal completions (error or success) and clean the schedules.
+ *
+ * This is the main path for handing urbs back to drivers.  The only other
+ * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
+ * scanning the (re-reversed) donelist as this does.
+ */
+static void
+dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
+{
+       unsigned long   flags;
+
+       spin_lock_irqsave (&ohci->lock, flags);
+       while (td) {
+               struct td       *td_next = td->next_dl_td;
+               struct urb      *urb = td->urb;
+               urb_priv_t      *urb_priv = urb->hcpriv;
+               struct ed       *ed = td->ed;
+
+               /* update URB's length and status from TD */
+               td_done (ohci, urb, td);
+               urb_priv->td_cnt++;
+
+               /* If all this urb's TDs are done, call complete() */
+               if (urb_priv->td_cnt == urb_priv->length) {
+                       spin_unlock (&ohci->lock);
+                       finish_urb (ohci, urb, regs);
+                       spin_lock (&ohci->lock);
+               }
+
+               /* clean schedule:  unlink EDs that are no longer busy */
+               if (list_empty (&ed->td_list))
+                       ed_deschedule (ohci, ed);
+               /* ... reenabling halted EDs only after fault cleanup */
+               else if (!(ed->hwINFO & ED_DEQUEUE)) {
+                       td = list_entry (ed->td_list.next, struct td, td_list);
+                       if (!(td->hwINFO & TD_DONE))
+                               ed->hwINFO &= ~ED_SKIP;
+               }
+
+               td = td_next;
+       }  
+       spin_unlock_irqrestore (&ohci->lock, flags);
+}
index 632382e..8af7d88 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- * \r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * This file is licenced under the GPL.\r
- */\r
\r
-/*\r
- * OHCI Endpoint Descriptor (ED) ... holds TD queue\r
- * See OHCI spec, section 4.2\r
- *\r
- * This is a "Queue Head" for those transfers, which is why\r
- * both EHCI and UHCI call similar structures a "QH".\r
- */\r
-struct ed {\r
-       /* first fields are hardware-specified, le32 */\r
-       __u32                   hwINFO;         /* endpoint config bitmap */\r
-       /* info bits defined by hcd */\r
-#define ED_DEQUEUE     __constant_cpu_to_le32(1 << 27)\r
-       /* info bits defined by the hardware */\r
-#define ED_ISO         __constant_cpu_to_le32(1 << 15)\r
-#define ED_SKIP                __constant_cpu_to_le32(1 << 14)\r
-#define ED_LOWSPEED    __constant_cpu_to_le32(1 << 13)\r
-#define ED_OUT         __constant_cpu_to_le32(0x01 << 11)\r
-#define ED_IN          __constant_cpu_to_le32(0x02 << 11)\r
-       __u32                   hwTailP;        /* tail of TD list */\r
-       __u32                   hwHeadP;        /* head of TD list (hc r/w) */\r
-#define ED_C           __constant_cpu_to_le32(0x02)    /* toggle carry */\r
-#define ED_H           __constant_cpu_to_le32(0x01)    /* halted */\r
-       __u32                   hwNextED;       /* next ED in list */\r
-\r
-       /* rest are purely for the driver's use */\r
-       dma_addr_t              dma;            /* addr of ED */\r
-       struct td               *dummy;         /* next TD to activate */\r
-\r
-       /* host's view of schedule */\r
-       struct ed               *ed_next;       /* on schedule or rm_list */\r
-       struct ed               *ed_prev;       /* for non-interrupt EDs */\r
-       struct list_head        td_list;        /* "shadow list" of our TDs */\r
-\r
-       /* create --> IDLE --> OPER --> ... --> IDLE --> destroy\r
-        * usually:  OPER --> UNLINK --> (IDLE | OPER) --> ...\r
-        * some special cases :  OPER --> IDLE ...\r
-        */\r
-       u8                      state;          /* ED_{IDLE,UNLINK,OPER} */\r
-#define ED_IDLE        0x00            /* NOT linked to HC */\r
-#define ED_UNLINK      0x01            /* being unlinked from hc */\r
-#define ED_OPER                0x02            /* IS linked to hc */\r
-\r
-       u8                      type;           /* PIPE_{BULK,...} */\r
-\r
-       /* periodic scheduling params (for intr and iso) */\r
-       u8                      branch;\r
-       u16                     interval;\r
-       u16                     load;\r
-       u16                     last_iso;       /* iso only */\r
-\r
-       /* HC may see EDs on rm_list until next frame (frame_no == tick) */\r
-       u16                     tick;\r
-} __attribute__ ((aligned(16)));\r
-\r
-#define ED_MASK        ((u32)~0x0f)            /* strip hw status in low addr bits */\r
-\r
\r
-/*\r
- * OHCI Transfer Descriptor (TD) ... one per transfer segment\r
- * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)\r
- * and 4.3.2 (iso)\r
- */\r
-struct td {\r
-       /* first fields are hardware-specified, le32 */\r
-       __u32           hwINFO;         /* transfer info bitmask */\r
-\r
-       /* hwINFO bits for both general and iso tds: */\r
-#define TD_CC       0xf0000000                 /* condition code */\r
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)\r
-//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)\r
-#define TD_DI       0x00E00000                 /* frames before interrupt */\r
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)\r
-       /* these two bits are available for definition/use by HCDs in both\r
-        * general and iso tds ... others are available for only one type\r
-        */\r
-#define TD_DONE     0x00020000                 /* retired to donelist */\r
-#define TD_ISO      0x00010000                 /* copy of ED_ISO */\r
-\r
-       /* hwINFO bits for general tds: */\r
-#define TD_EC       0x0C000000                 /* error count */\r
-#define TD_T        0x03000000                 /* data toggle state */\r
-#define TD_T_DATA0  0x02000000                         /* DATA0 */\r
-#define TD_T_DATA1  0x03000000                         /* DATA1 */\r
-#define TD_T_TOGGLE 0x00000000                         /* uses ED_C */\r
-#define TD_DP       0x00180000                 /* direction/pid */\r
-#define TD_DP_SETUP 0x00000000                 /* SETUP pid */\r
-#define TD_DP_IN    0x00100000                         /* IN pid */\r
-#define TD_DP_OUT   0x00080000                         /* OUT pid */\r
-                                                       /* 0x00180000 rsvd */\r
-#define TD_R        0x00040000                 /* round: short packets OK? */\r
-\r
-       /* (no hwINFO #defines yet for iso tds) */\r
-\r
-       __u32           hwCBP;          /* Current Buffer Pointer (or 0) */\r
-       __u32           hwNextTD;       /* Next TD Pointer */\r
-       __u32           hwBE;           /* Memory Buffer End Pointer */\r
-\r
-       /* PSW is only for ISO */\r
-#define MAXPSW 1               /* hardware allows 8 */\r
-       __u16           hwPSW [MAXPSW];\r
-\r
-       /* rest are purely for the driver's use */\r
-       __u8            index;\r
-       struct ed       *ed;\r
-       struct td       *td_hash;       /* dma-->td hashtable */\r
-       struct td       *next_dl_td;\r
-       struct urb      *urb;\r
-\r
-       dma_addr_t      td_dma;         /* addr of this TD */\r
-       dma_addr_t      data_dma;       /* addr of data it points to */\r
-\r
-       struct list_head td_list;       /* "shadow list", TDs on same ED */\r
-} __attribute__ ((aligned(32)));       /* c/b/i need 16; only iso needs 32 */\r
-\r
-#define TD_MASK        ((u32)~0x1f)            /* strip hw status in low addr bits */\r
-\r
-/*\r
- * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW\r
- */\r
-#define TD_CC_NOERROR      0x00\r
-#define TD_CC_CRC          0x01\r
-#define TD_CC_BITSTUFFING  0x02\r
-#define TD_CC_DATATOGGLEM  0x03\r
-#define TD_CC_STALL        0x04\r
-#define TD_DEVNOTRESP      0x05\r
-#define TD_PIDCHECKFAIL    0x06\r
-#define TD_UNEXPECTEDPID   0x07\r
-#define TD_DATAOVERRUN     0x08\r
-#define TD_DATAUNDERRUN    0x09\r
-    /* 0x0A, 0x0B reserved for hardware */\r
-#define TD_BUFFEROVERRUN   0x0C\r
-#define TD_BUFFERUNDERRUN  0x0D\r
-    /* 0x0E, 0x0F reserved for HCD */\r
-#define TD_NOTACCESSED     0x0F\r
-\r
-\r
-/* map OHCI TD status codes (CC) to errno values */ \r
-static const int cc_to_error [16] = { \r
-       /* No  Error  */               0,\r
-       /* CRC Error  */               -EILSEQ,\r
-       /* Bit Stuff  */               -EPROTO,\r
-       /* Data Togg  */               -EILSEQ,\r
-       /* Stall      */               -EPIPE,\r
-       /* DevNotResp */               -ETIMEDOUT,\r
-       /* PIDCheck   */               -EPROTO,\r
-       /* UnExpPID   */               -EPROTO,\r
-       /* DataOver   */               -EOVERFLOW,\r
-       /* DataUnder  */               -EREMOTEIO,\r
-       /* (for hw)   */               -EIO,\r
-       /* (for hw)   */               -EIO,\r
-       /* BufferOver */               -ECOMM,\r
-       /* BuffUnder  */               -ENOSR,\r
-       /* (for HCD)  */               -EALREADY,\r
-       /* (for HCD)  */               -EALREADY \r
-};\r
-\r
-\r
-/*\r
- * The HCCA (Host Controller Communications Area) is a 256 byte\r
- * structure defined section 4.4.1 of the OHCI spec. The HC is\r
- * told the base address of it.  It must be 256-byte aligned.\r
- */\r
-struct ohci_hcca {\r
-#define NUM_INTS 32\r
-       __u32   int_table [NUM_INTS];   /* periodic schedule */\r
-       __u16   frame_no;               /* current frame number */\r
-       __u16   pad1;                   /* set to 0 on each frame_no change */\r
-       __u32   done_head;              /* info returned for an interrupt */\r
-       u8      reserved_for_hc [116];\r
-       u8      what [4];               /* spec only identifies 252 bytes :) */\r
-} __attribute__ ((aligned(256)));\r
-\r
-  \r
-/*\r
- * This is the structure of the OHCI controller's memory mapped I/O region.\r
- * You must use readl() and writel() (in <asm/io.h>) to access these fields!!\r
- * Layout is in section 7 (and appendix B) of the spec.\r
- */\r
-struct ohci_regs {\r
-       /* control and status registers (section 7.1) */\r
-       __u32   revision;\r
-       __u32   control;\r
-       __u32   cmdstatus;\r
-       __u32   intrstatus;\r
-       __u32   intrenable;\r
-       __u32   intrdisable;\r
-\r
-       /* memory pointers (section 7.2) */\r
-       __u32   hcca;\r
-       __u32   ed_periodcurrent;\r
-       __u32   ed_controlhead;\r
-       __u32   ed_controlcurrent;\r
-       __u32   ed_bulkhead;\r
-       __u32   ed_bulkcurrent;\r
-       __u32   donehead;\r
-\r
-       /* frame counters (section 7.3) */\r
-       __u32   fminterval;\r
-       __u32   fmremaining;\r
-       __u32   fmnumber;\r
-       __u32   periodicstart;\r
-       __u32   lsthresh;\r
-\r
-       /* Root hub ports (section 7.4) */\r
-       struct  ohci_roothub_regs {\r
-               __u32   a;\r
-               __u32   b;\r
-               __u32   status;\r
-#define MAX_ROOT_PORTS 15      /* maximum OHCI root hub ports (RH_A_NDP) */\r
-               __u32   portstatus [MAX_ROOT_PORTS];\r
-       } roothub;\r
-\r
-       /* and optional "legacy support" registers (appendix B) at 0x0100 */\r
-\r
-} __attribute__ ((aligned(32)));\r
-\r
-\r
-/* OHCI CONTROL AND STATUS REGISTER MASKS */\r
-\r
-/*\r
- * HcControl (control) register masks\r
- */\r
-#define OHCI_CTRL_CBSR (3 << 0)        /* control/bulk service ratio */\r
-#define OHCI_CTRL_PLE  (1 << 2)        /* periodic list enable */\r
-#define OHCI_CTRL_IE   (1 << 3)        /* isochronous enable */\r
-#define OHCI_CTRL_CLE  (1 << 4)        /* control list enable */\r
-#define OHCI_CTRL_BLE  (1 << 5)        /* bulk list enable */\r
-#define OHCI_CTRL_HCFS (3 << 6)        /* host controller functional state */\r
-#define OHCI_CTRL_IR   (1 << 8)        /* interrupt routing */\r
-#define OHCI_CTRL_RWC  (1 << 9)        /* remote wakeup connected */\r
-#define OHCI_CTRL_RWE  (1 << 10)       /* remote wakeup enable */\r
-\r
-/* pre-shifted values for HCFS */\r
-#define OHCI_USB_RESET (0 << 6)\r
-#define OHCI_USB_RESUME        (1 << 6)\r
-#define OHCI_USB_OPER  (2 << 6)\r
-#define OHCI_USB_SUSPEND (3 << 6)\r
-\r
-// HCFS itself\r
-static char *hcfs2string (int state)\r
-{\r
-       switch (state) {\r
-               case OHCI_USB_RESET: return "reset";\r
-               case OHCI_USB_RESUME: return "resume";\r
-               case OHCI_USB_OPER: return "operational";\r
-               case OHCI_USB_SUSPEND: return "suspend";\r
-       }\r
-       return "?";\r
-}\r
-\r
-/*\r
- * HcCommandStatus (cmdstatus) register masks\r
- */\r
-#define OHCI_HCR       (1 << 0)        /* host controller reset */\r
-#define OHCI_CLF       (1 << 1)        /* control list filled */\r
-#define OHCI_BLF       (1 << 2)        /* bulk list filled */\r
-#define OHCI_OCR       (1 << 3)        /* ownership change request */\r
-#define OHCI_SOC       (3 << 16)       /* scheduling overrun count */\r
-\r
-/*\r
- * masks used with interrupt registers:\r
- * HcInterruptStatus (intrstatus)\r
- * HcInterruptEnable (intrenable)\r
- * HcInterruptDisable (intrdisable)\r
- */\r
-#define OHCI_INTR_SO   (1 << 0)        /* scheduling overrun */\r
-#define OHCI_INTR_WDH  (1 << 1)        /* writeback of done_head */\r
-#define OHCI_INTR_SF   (1 << 2)        /* start frame */\r
-#define OHCI_INTR_RD   (1 << 3)        /* resume detect */\r
-#define OHCI_INTR_UE   (1 << 4)        /* unrecoverable error */\r
-#define OHCI_INTR_FNO  (1 << 5)        /* frame number overflow */\r
-#define OHCI_INTR_RHSC (1 << 6)        /* root hub status change */\r
-#define OHCI_INTR_OC   (1 << 30)       /* ownership change */\r
-#define OHCI_INTR_MIE  (1 << 31)       /* master interrupt enable */\r
-\r
-\r
-/* OHCI ROOT HUB REGISTER MASKS */\r
\r
-/* roothub.portstatus [i] bits */\r
-#define RH_PS_CCS            0x00000001        /* current connect status */\r
-#define RH_PS_PES            0x00000002        /* port enable status*/\r
-#define RH_PS_PSS            0x00000004        /* port suspend status */\r
-#define RH_PS_POCI           0x00000008        /* port over current indicator */\r
-#define RH_PS_PRS            0x00000010        /* port reset status */\r
-#define RH_PS_PPS            0x00000100        /* port power status */\r
-#define RH_PS_LSDA           0x00000200        /* low speed device attached */\r
-#define RH_PS_CSC            0x00010000        /* connect status change */\r
-#define RH_PS_PESC           0x00020000        /* port enable status change */\r
-#define RH_PS_PSSC           0x00040000        /* port suspend status change */\r
-#define RH_PS_OCIC           0x00080000        /* over current indicator change */\r
-#define RH_PS_PRSC           0x00100000        /* port reset status change */\r
-\r
-/* roothub.status bits */\r
-#define RH_HS_LPS           0x00000001         /* local power status */\r
-#define RH_HS_OCI           0x00000002         /* over current indicator */\r
-#define RH_HS_DRWE          0x00008000         /* device remote wakeup enable */\r
-#define RH_HS_LPSC          0x00010000         /* local power status change */\r
-#define RH_HS_OCIC          0x00020000         /* over current indicator change */\r
-#define RH_HS_CRWE          0x80000000         /* clear remote wakeup enable */\r
-\r
-/* roothub.b masks */\r
-#define RH_B_DR                0x0000ffff              /* device removable flags */\r
-#define RH_B_PPCM      0xffff0000              /* port power control mask */\r
-\r
-/* roothub.a masks */\r
-#define        RH_A_NDP        (0xff << 0)             /* number of downstream ports */\r
-#define        RH_A_PSM        (1 << 8)                /* power switching mode */\r
-#define        RH_A_NPS        (1 << 9)                /* no power switching */\r
-#define        RH_A_DT         (1 << 10)               /* device type (mbz) */\r
-#define        RH_A_OCPM       (1 << 11)               /* over current protection mode */\r
-#define        RH_A_NOCP       (1 << 12)               /* no over current protection */\r
-#define        RH_A_POTPGT     (0xff << 24)            /* power on to power good time */\r
-\r
-\r
-/* hcd-private per-urb state */\r
-typedef struct urb_priv {\r
-       struct ed               *ed;\r
-       __u16                   length;         // # tds in this request\r
-       __u16                   td_cnt;         // tds already serviced\r
-       int                     state;\r
-       struct td               *td [0];        // all TDs in this request\r
-\r
-} urb_priv_t;\r
-\r
-#define URB_DEL 1\r
-\r
-#define TD_HASH_SIZE    64    /* power'o'two */\r
-// sizeof (struct td) ~= 64 == 2^6 ... \r
-#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)\r
-\r
-\r
-/*\r
- * This is the full ohci controller description\r
- *\r
- * Note how the "proper" USB information is just\r
- * a subset of what the full implementation needs. (Linus)\r
- */\r
-\r
-struct ohci_hcd {\r
-       spinlock_t              lock;\r
-\r
-       /*\r
-        * I/O memory used to communicate with the HC (dma-consistent)\r
-        */\r
-       struct ohci_regs        *regs;\r
-\r
-       /*\r
-        * main memory used to communicate with the HC (dma-consistent).\r
-        * hcd adds to schedule for a live hc any time, but removals finish\r
-        * only at the start of the next frame.\r
-        */\r
-       struct ohci_hcca        *hcca;\r
-       dma_addr_t              hcca_dma;\r
-\r
-       struct ed               *ed_rm_list;            /* to be removed */\r
-\r
-       struct ed               *ed_bulktail;           /* last in bulk list */\r
-       struct ed               *ed_controltail;        /* last in ctrl list */\r
-       struct ed               *periodic [NUM_INTS];   /* shadow int_table */\r
-\r
-       /*\r
-        * memory management for queue data structures\r
-        */\r
-       struct pci_pool         *td_cache;\r
-       struct pci_pool         *ed_cache;\r
-       struct td               *td_hash [TD_HASH_SIZE];\r
-\r
-       /*\r
-        * driver state\r
-        */\r
-       int                     disabled;       /* e.g. got a UE, we're hung */\r
-       int                     sleeping;\r
-       int                     load [NUM_INTS];\r
-       u32                     hc_control;     /* copy of hc control reg */\r
-\r
-       unsigned long           flags;          /* for HC bugs */\r
-#define        OHCI_QUIRK_AMD756       0x01                    /* erratum #4 */\r
-#define        OHCI_QUIRK_SUPERIO      0x02                    /* natsemi */\r
-       // there are also chip quirks/bugs in init logic\r
-\r
-       /*\r
-        * framework state\r
-        */\r
-       struct usb_hcd          hcd;\r
-};\r
-\r
-#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd)\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#ifndef DEBUG\r
-#define STUB_DEBUG_FILES\r
-#endif /* DEBUG */\r
-\r
-#define ohci_dbg(ohci, fmt, args...) \\r
-       dev_dbg ((ohci)->hcd.controller , fmt , ## args )\r
-#define ohci_err(ohci, fmt, args...) \\r
-       dev_err ((ohci)->hcd.controller , fmt , ## args )\r
-#define ohci_info(ohci, fmt, args...) \\r
-       dev_info ((ohci)->hcd.controller , fmt , ## args )\r
-#define ohci_warn(ohci, fmt, args...) \\r
-       dev_warn ((ohci)->hcd.controller , fmt , ## args )\r
-\r
-#ifdef OHCI_VERBOSE_DEBUG\r
-#      define ohci_vdbg ohci_dbg\r
-#else\r
-#      define ohci_vdbg(ohci, fmt, args...) do { } while (0)\r
-#endif\r
-\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * This file is licenced under the GPL.
+ */
+/*
+ * OHCI Endpoint Descriptor (ED) ... holds TD queue
+ * See OHCI spec, section 4.2
+ *
+ * This is a "Queue Head" for those transfers, which is why
+ * both EHCI and UHCI call similar structures a "QH".
+ */
+struct ed {
+       /* first fields are hardware-specified, le32 */
+       __u32                   hwINFO;         /* endpoint config bitmap */
+       /* info bits defined by hcd */
+#define ED_DEQUEUE     __constant_cpu_to_le32(1 << 27)
+       /* info bits defined by the hardware */
+#define ED_ISO         __constant_cpu_to_le32(1 << 15)
+#define ED_SKIP                __constant_cpu_to_le32(1 << 14)
+#define ED_LOWSPEED    __constant_cpu_to_le32(1 << 13)
+#define ED_OUT         __constant_cpu_to_le32(0x01 << 11)
+#define ED_IN          __constant_cpu_to_le32(0x02 << 11)
+       __u32                   hwTailP;        /* tail of TD list */
+       __u32                   hwHeadP;        /* head of TD list (hc r/w) */
+#define ED_C           __constant_cpu_to_le32(0x02)    /* toggle carry */
+#define ED_H           __constant_cpu_to_le32(0x01)    /* halted */
+       __u32                   hwNextED;       /* next ED in list */
+
+       /* rest are purely for the driver's use */
+       dma_addr_t              dma;            /* addr of ED */
+       struct td               *dummy;         /* next TD to activate */
+
+       /* host's view of schedule */
+       struct ed               *ed_next;       /* on schedule or rm_list */
+       struct ed               *ed_prev;       /* for non-interrupt EDs */
+       struct list_head        td_list;        /* "shadow list" of our TDs */
+
+       /* create --> IDLE --> OPER --> ... --> IDLE --> destroy
+        * usually:  OPER --> UNLINK --> (IDLE | OPER) --> ...
+        * some special cases :  OPER --> IDLE ...
+        */
+       u8                      state;          /* ED_{IDLE,UNLINK,OPER} */
+#define ED_IDLE        0x00            /* NOT linked to HC */
+#define ED_UNLINK      0x01            /* being unlinked from hc */
+#define ED_OPER                0x02            /* IS linked to hc */
+
+       u8                      type;           /* PIPE_{BULK,...} */
+
+       /* periodic scheduling params (for intr and iso) */
+       u8                      branch;
+       u16                     interval;
+       u16                     load;
+       u16                     last_iso;       /* iso only */
+
+       /* HC may see EDs on rm_list until next frame (frame_no == tick) */
+       u16                     tick;
+} __attribute__ ((aligned(16)));
+
+#define ED_MASK        ((u32)~0x0f)            /* strip hw status in low addr bits */
+
+/*
+ * OHCI Transfer Descriptor (TD) ... one per transfer segment
+ * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
+ * and 4.3.2 (iso)
+ */
+struct td {
+       /* first fields are hardware-specified, le32 */
+       __u32           hwINFO;         /* transfer info bitmask */
+
+       /* hwINFO bits for both general and iso tds: */
+#define TD_CC       0xf0000000                 /* condition code */
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_DI       0x00E00000                 /* frames before interrupt */
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+       /* these two bits are available for definition/use by HCDs in both
+        * general and iso tds ... others are available for only one type
+        */
+#define TD_DONE     0x00020000                 /* retired to donelist */
+#define TD_ISO      0x00010000                 /* copy of ED_ISO */
+
+       /* hwINFO bits for general tds: */
+#define TD_EC       0x0C000000                 /* error count */
+#define TD_T        0x03000000                 /* data toggle state */
+#define TD_T_DATA0  0x02000000                         /* DATA0 */
+#define TD_T_DATA1  0x03000000                         /* DATA1 */
+#define TD_T_TOGGLE 0x00000000                         /* uses ED_C */
+#define TD_DP       0x00180000                 /* direction/pid */
+#define TD_DP_SETUP 0x00000000                 /* SETUP pid */
+#define TD_DP_IN    0x00100000                         /* IN pid */
+#define TD_DP_OUT   0x00080000                         /* OUT pid */
+                                                       /* 0x00180000 rsvd */
+#define TD_R        0x00040000                 /* round: short packets OK? */
+
+       /* (no hwINFO #defines yet for iso tds) */
+
+       __u32           hwCBP;          /* Current Buffer Pointer (or 0) */
+       __u32           hwNextTD;       /* Next TD Pointer */
+       __u32           hwBE;           /* Memory Buffer End Pointer */
+
+       /* PSW is only for ISO */
+#define MAXPSW 1               /* hardware allows 8 */
+       __u16           hwPSW [MAXPSW];
+
+       /* rest are purely for the driver's use */
+       __u8            index;
+       struct ed       *ed;
+       struct td       *td_hash;       /* dma-->td hashtable */
+       struct td       *next_dl_td;
+       struct urb      *urb;
+
+       dma_addr_t      td_dma;         /* addr of this TD */
+       dma_addr_t      data_dma;       /* addr of data it points to */
+
+       struct list_head td_list;       /* "shadow list", TDs on same ED */
+} __attribute__ ((aligned(32)));       /* c/b/i need 16; only iso needs 32 */
+
+#define TD_MASK        ((u32)~0x1f)            /* strip hw status in low addr bits */
+
+/*
+ * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW
+ */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED     0x0F
+
+
+/* map OHCI TD status codes (CC) to errno values */ 
+static const int cc_to_error [16] = { 
+       /* No  Error  */               0,
+       /* CRC Error  */               -EILSEQ,
+       /* Bit Stuff  */               -EPROTO,
+       /* Data Togg  */               -EILSEQ,
+       /* Stall      */               -EPIPE,
+       /* DevNotResp */               -ETIMEDOUT,
+       /* PIDCheck   */               -EPROTO,
+       /* UnExpPID   */               -EPROTO,
+       /* DataOver   */               -EOVERFLOW,
+       /* DataUnder  */               -EREMOTEIO,
+       /* (for hw)   */               -EIO,
+       /* (for hw)   */               -EIO,
+       /* BufferOver */               -ECOMM,
+       /* BuffUnder  */               -ENOSR,
+       /* (for HCD)  */               -EALREADY,
+       /* (for HCD)  */               -EALREADY 
+};
+
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined section 4.4.1 of the OHCI spec. The HC is
+ * told the base address of it.  It must be 256-byte aligned.
+ */
+struct ohci_hcca {
+#define NUM_INTS 32
+       __u32   int_table [NUM_INTS];   /* periodic schedule */
+       __u16   frame_no;               /* current frame number */
+       __u16   pad1;                   /* set to 0 on each frame_no change */
+       __u32   done_head;              /* info returned for an interrupt */
+       u8      reserved_for_hc [116];
+       u8      what [4];               /* spec only identifies 252 bytes :) */
+} __attribute__ ((aligned(256)));
+
+  
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O region.
+ * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
+ * Layout is in section 7 (and appendix B) of the spec.
+ */
+struct ohci_regs {
+       /* control and status registers (section 7.1) */
+       __u32   revision;
+       __u32   control;
+       __u32   cmdstatus;
+       __u32   intrstatus;
+       __u32   intrenable;
+       __u32   intrdisable;
+
+       /* memory pointers (section 7.2) */
+       __u32   hcca;
+       __u32   ed_periodcurrent;
+       __u32   ed_controlhead;
+       __u32   ed_controlcurrent;
+       __u32   ed_bulkhead;
+       __u32   ed_bulkcurrent;
+       __u32   donehead;
+
+       /* frame counters (section 7.3) */
+       __u32   fminterval;
+       __u32   fmremaining;
+       __u32   fmnumber;
+       __u32   periodicstart;
+       __u32   lsthresh;
+
+       /* Root hub ports (section 7.4) */
+       struct  ohci_roothub_regs {
+               __u32   a;
+               __u32   b;
+               __u32   status;
+#define MAX_ROOT_PORTS 15      /* maximum OHCI root hub ports (RH_A_NDP) */
+               __u32   portstatus [MAX_ROOT_PORTS];
+       } roothub;
+
+       /* and optional "legacy support" registers (appendix B) at 0x0100 */
+
+} __attribute__ ((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0)        /* control/bulk service ratio */
+#define OHCI_CTRL_PLE  (1 << 2)        /* periodic list enable */
+#define OHCI_CTRL_IE   (1 << 3)        /* isochronous enable */
+#define OHCI_CTRL_CLE  (1 << 4)        /* control list enable */
+#define OHCI_CTRL_BLE  (1 << 5)        /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6)        /* host controller functional state */
+#define OHCI_CTRL_IR   (1 << 8)        /* interrupt routing */
+#define OHCI_CTRL_RWC  (1 << 9)        /* remote wakeup connected */
+#define OHCI_CTRL_RWE  (1 << 10)       /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#define OHCI_USB_RESET (0 << 6)
+#define OHCI_USB_RESUME        (1 << 6)
+#define OHCI_USB_OPER  (2 << 6)
+#define OHCI_USB_SUSPEND (3 << 6)
+
+// HCFS itself
+static char *hcfs2string (int state)
+{
+       switch (state) {
+               case OHCI_USB_RESET: return "reset";
+               case OHCI_USB_RESUME: return "resume";
+               case OHCI_USB_OPER: return "operational";
+               case OHCI_USB_SUSPEND: return "suspend";
+       }
+       return "?";
+}
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR       (1 << 0)        /* host controller reset */
+#define OHCI_CLF       (1 << 1)        /* control list filled */
+#define OHCI_BLF       (1 << 2)        /* bulk list filled */
+#define OHCI_OCR       (1 << 3)        /* ownership change request */
+#define OHCI_SOC       (3 << 16)       /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO   (1 << 0)        /* scheduling overrun */
+#define OHCI_INTR_WDH  (1 << 1)        /* writeback of done_head */
+#define OHCI_INTR_SF   (1 << 2)        /* start frame */
+#define OHCI_INTR_RD   (1 << 3)        /* resume detect */
+#define OHCI_INTR_UE   (1 << 4)        /* unrecoverable error */
+#define OHCI_INTR_FNO  (1 << 5)        /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6)        /* root hub status change */
+#define OHCI_INTR_OC   (1 << 30)       /* ownership change */
+#define OHCI_INTR_MIE  (1 << 31)       /* master interrupt enable */
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001        /* current connect status */
+#define RH_PS_PES            0x00000002        /* port enable status*/
+#define RH_PS_PSS            0x00000004        /* port suspend status */
+#define RH_PS_POCI           0x00000008        /* port over current indicator */
+#define RH_PS_PRS            0x00000010        /* port reset status */
+#define RH_PS_PPS            0x00000100        /* port power status */
+#define RH_PS_LSDA           0x00000200        /* low speed device attached */
+#define RH_PS_CSC            0x00010000        /* connect status change */
+#define RH_PS_PESC           0x00020000        /* port enable status change */
+#define RH_PS_PSSC           0x00040000        /* port suspend status change */
+#define RH_PS_OCIC           0x00080000        /* over current indicator change */
+#define RH_PS_PRSC           0x00100000        /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS           0x00000001         /* local power status */
+#define RH_HS_OCI           0x00000002         /* over current indicator */
+#define RH_HS_DRWE          0x00008000         /* device remote wakeup enable */
+#define RH_HS_LPSC          0x00010000         /* local power status change */
+#define RH_HS_OCIC          0x00020000         /* over current indicator change */
+#define RH_HS_CRWE          0x80000000         /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR                0x0000ffff              /* device removable flags */
+#define RH_B_PPCM      0xffff0000              /* port power control mask */
+
+/* roothub.a masks */
+#define        RH_A_NDP        (0xff << 0)             /* number of downstream ports */
+#define        RH_A_PSM        (1 << 8)                /* power switching mode */
+#define        RH_A_NPS        (1 << 9)                /* no power switching */
+#define        RH_A_DT         (1 << 10)               /* device type (mbz) */
+#define        RH_A_OCPM       (1 << 11)               /* over current protection mode */
+#define        RH_A_NOCP       (1 << 12)               /* no over current protection */
+#define        RH_A_POTPGT     (0xff << 24)            /* power on to power good time */
+
+
+/* hcd-private per-urb state */
+typedef struct urb_priv {
+       struct ed               *ed;
+       __u16                   length;         // # tds in this request
+       __u16                   td_cnt;         // tds already serviced
+       int                     state;
+       struct td               *td [0];        // all TDs in this request
+
+} urb_priv_t;
+
+#define URB_DEL 1
+
+#define TD_HASH_SIZE    64    /* power'o'two */
+// sizeof (struct td) ~= 64 == 2^6 ... 
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
+
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+struct ohci_hcd {
+       spinlock_t              lock;
+
+       /*
+        * I/O memory used to communicate with the HC (dma-consistent)
+        */
+       struct ohci_regs        *regs;
+
+       /*
+        * main memory used to communicate with the HC (dma-consistent).
+        * hcd adds to schedule for a live hc any time, but removals finish
+        * only at the start of the next frame.
+        */
+       struct ohci_hcca        *hcca;
+       dma_addr_t              hcca_dma;
+
+       struct ed               *ed_rm_list;            /* to be removed */
+
+       struct ed               *ed_bulktail;           /* last in bulk list */
+       struct ed               *ed_controltail;        /* last in ctrl list */
+       struct ed               *periodic [NUM_INTS];   /* shadow int_table */
+
+       /*
+        * memory management for queue data structures
+        */
+       struct pci_pool         *td_cache;
+       struct pci_pool         *ed_cache;
+       struct td               *td_hash [TD_HASH_SIZE];
+
+       /*
+        * driver state
+        */
+       int                     disabled;       /* e.g. got a UE, we're hung */
+       int                     sleeping;
+       int                     load [NUM_INTS];
+       u32                     hc_control;     /* copy of hc control reg */
+
+       unsigned long           flags;          /* for HC bugs */
+#define        OHCI_QUIRK_AMD756       0x01                    /* erratum #4 */
+#define        OHCI_QUIRK_SUPERIO      0x02                    /* natsemi */
+       // there are also chip quirks/bugs in init logic
+
+       /*
+        * framework state
+        */
+       struct usb_hcd          hcd;
+};
+
+#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd)
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif /* DEBUG */
+
+#define ohci_dbg(ohci, fmt, args...) \
+       dev_dbg ((ohci)->hcd.controller , fmt , ## args )
+#define ohci_err(ohci, fmt, args...) \
+       dev_err ((ohci)->hcd.controller , fmt , ## args )
+#define ohci_info(ohci, fmt, args...) \
+       dev_info ((ohci)->hcd.controller , fmt , ## args )
+#define ohci_warn(ohci, fmt, args...) \
+       dev_warn ((ohci)->hcd.controller , fmt , ## args )
+
+#ifdef OHCI_VERBOSE_DEBUG
+#      define ohci_vdbg ohci_dbg
+#else
+#      define ohci_vdbg(ohci, fmt, args...) do { } while (0)
+#endif
+
index fa18324..a31d60c 100644 (file)
@@ -1,5 +1,5 @@
-#define REACTOS_VERSION_DLL\r
-#define REACTOS_STR_FILE_DESCRIPTION   "USB OHCI Device Driver\0"\r
-#define REACTOS_STR_INTERNAL_NAME      "ohci\0"\r
-#define REACTOS_STR_ORIGINAL_FILENAME  "ohci.sys\0"\r
-#include <reactos/version.rc>\r
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION   "USB OHCI Device Driver\0"
+#define REACTOS_STR_INTERNAL_NAME      "ohci\0"
+#define REACTOS_STR_ORIGINAL_FILENAME  "ohci.sys\0"
+#include <reactos/version.rc>
index ec73b90..01fd7cd 100644 (file)
@@ -1,5 +1,5 @@
-/*\r
- * Configs for OHCI\r
- */\r
-\r
-#define CONFIG_PCI\r
+/*
+ * Configs for OHCI
+ */
+
+#define CONFIG_PCI
index aba234a..57c6182 100644 (file)
-/*\r
-   ReactOS specific functions for OHCI module\r
-   by Aleksey Bragin (aleksey@reactos.com)\r
-   Some parts of code are inspired (or even just copied) from ReactOS Videoport driver\r
-*/\r
-\r
-#include <ddk/ntddk.h>\r
-#include <debug.h>\r
-#include "../linux/linux_wrapper.h"\r
-#include "ohci_main.h"\r
-\r
-// declare basic init funcs\r
-void init_wrapper(struct pci_dev *probe_dev);\r
-int ohci_hcd_pci_init (void);\r
-void ohci_hcd_pci_cleanup (void);\r
-int STDCALL usb_init(void);\r
-void STDCALL usb_exit(void);\r
-extern struct pci_driver ohci_pci_driver;\r
-extern const struct pci_device_id pci_ids[];\r
-\r
-\r
-\r
-// This should be removed, but for testing purposes it's here\r
-struct pci_dev *dev;\r
-//struct pci_device_id *dev_id;\r
-\r
-\r
-#define USB_OHCI_TAG TAG('u','s','b','o')\r
-\r
-NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)\r
-{\r
-       PDEVICE_OBJECT fdo;\r
-       NTSTATUS Status;\r
-       WCHAR DeviceBuffer[20];\r
-       UNICODE_STRING DeviceName;\r
-       POHCI_DRIVER_EXTENSION DriverExtension;\r
-       POHCI_DEVICE_EXTENSION DeviceExtension;\r
-       ULONG Size, DeviceNumber;\r
-\r
-       DPRINT1("ohci: AddDevice called\n");\r
-\r
-       // Allocate driver extension now\r
-       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);\r
-       if (DriverExtension == NULL)\r
-       {\r
-               Status = IoAllocateDriverObjectExtension(\r
-                                       DriverObject,\r
-                                       DriverObject,\r
-                                       sizeof(OHCI_DRIVER_EXTENSION),\r
-                                       (PVOID *)&DriverExtension);\r
-\r
-               if (!NT_SUCCESS(Status))\r
-               {\r
-                       DPRINT1("Allocating DriverObjectExtension failed.\n");\r
-                       return Status;\r
-               }\r
-       }\r
-   \r
-       // Create a unicode device name\r
-       DeviceNumber = 0; //TODO: Allocate new device number every time\r
-       swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber);\r
-       RtlInitUnicodeString(&DeviceName, DeviceBuffer);\r
-\r
-       Status = IoCreateDevice(DriverObject,\r
-                                   sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/,\r
-                                                       &DeviceName,\r
-                                                       FILE_DEVICE_CONTROLLER,\r
-                                                       0,\r
-                                                       FALSE,\r
-                                                       &fdo);\r
-\r
-       if (!NT_SUCCESS(Status))\r
-       {\r
-               DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);\r
-               return Status;\r
-       }\r
-\r
-       // zerofill device extension\r
-       DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension;\r
-       RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION));\r
-       DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);\r
-\r
-       fdo->Flags &= ~DO_DEVICE_INITIALIZING;\r
-\r
-       // Initialize device extension\r
-       DeviceExtension->DeviceNumber = DeviceNumber;\r
-       DeviceExtension->PhysicalDeviceObject = pdo;\r
-       DeviceExtension->FunctionalDeviceObject = fdo;\r
-       DeviceExtension->DriverExtension = DriverExtension;\r
-\r
-       /* Get bus number from the upper level bus driver. */\r
-       Size = sizeof(ULONG);\r
-       Status = IoGetDeviceProperty(\r
-                               pdo,\r
-                               DevicePropertyBusNumber,\r
-                               Size,\r
-                               &DeviceExtension->SystemIoBusNumber,\r
-                               &Size);\r
-       \r
-       if (!NT_SUCCESS(Status))\r
-       {\r
-               DPRINT("Couldn't get an information from bus driver. Panic!!!\n");\r
-               return Status;\r
-       }\r
-\r
-       DPRINT("Done AddDevice\n");\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject)\r
-{\r
-       DPRINT1("DriverUnload()\n");\r
-\r
-       // Exit usb device\r
-       usb_exit();\r
-\r
-       // Remove device (ohci_pci_driver.remove)\r
-       ohci_pci_driver.remove(dev);\r
-\r
-       ExFreePool(dev->slot_name);\r
-       ExFreePool(dev);\r
-\r
-       // Perform some cleanup\r
-       ohci_hcd_pci_cleanup();\r
-}\r
-\r
-NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject)\r
-{\r
-       NTSTATUS Status;\r
-       POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-       // Fill generic linux structs\r
-       dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_OHCI_TAG);\r
-       \r
-       init_wrapper(dev);\r
-       dev->irq = DeviceExtension->InterruptLevel;\r
-       dev->dev_ext = (PVOID)DeviceExtension;\r
-       dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_OHCI_TAG); // 128 max len for slot name\r
-\r
-       strcpy(dev->dev.name, "OpenHCI PCI-USB Controller");\r
-       strcpy(dev->slot_name, "OHCD PCI Slot");\r
-\r
-       // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL\r
-       Status = ohci_hcd_pci_init();\r
-       //FIXME: Check status returned value\r
-\r
-       // Init core usb\r
-       usb_init();\r
-\r
-       // Probe device with real id now\r
-       ohci_pci_driver.probe(dev, pci_ids);\r
-\r
-       DPRINT("InitLinuxWrapper() done\n");\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS STDCALL\r
-OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject,\r
-                                       IN PIRP Irp)\r
-{\r
-       PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);\r
-       PDRIVER_OBJECT DriverObject;\r
-       POHCI_DRIVER_EXTENSION DriverExtension;\r
-       POHCI_DEVICE_EXTENSION DeviceExtension;\r
-       PCM_RESOURCE_LIST AllocatedResources;\r
-\r
-       /*\r
-       * Get the initialization data we saved in VideoPortInitialize.\r
-       */\r
-       DriverObject = DeviceObject->DriverObject;\r
-       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);\r
-       DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-       /*\r
-       * Store some resources in the DeviceExtension.\r
-       */\r
-       AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;\r
-       if (AllocatedResources != NULL)\r
-       {\r
-               CM_FULL_RESOURCE_DESCRIPTOR     *FullList;\r
-               CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;\r
-               ULONG ResourceCount;\r
-               ULONG ResourceListSize;\r
-\r
-               /* Save the     resource list */\r
-               ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;\r
-               ResourceListSize =\r
-                       FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.\r
-                       PartialDescriptors[ResourceCount]);\r
-               DeviceExtension->AllocatedResources     = ExAllocatePool(PagedPool,     ResourceListSize);\r
-               if (DeviceExtension->AllocatedResources == NULL)\r
-               {\r
-                       return STATUS_INSUFFICIENT_RESOURCES;\r
-               }\r
-\r
-               RtlCopyMemory(DeviceExtension->AllocatedResources,\r
-                       AllocatedResources,\r
-                       ResourceListSize);\r
-\r
-               /* Get the interrupt level/vector -     needed by HwFindAdapter sometimes */\r
-               for     (FullList =     AllocatedResources->List;\r
-                       FullList < AllocatedResources->List     + AllocatedResources->Count;\r
-                       FullList++)\r
-               {\r
-                       /* FIXME: Is this ASSERT ok     for     resources from the PNP manager? */\r
-                       /*ASSERT(FullList->InterfaceType == PCIBus &&\r
-                               FullList->BusNumber     == DeviceExtension->SystemIoBusNumber &&\r
-                               1 == FullList->PartialResourceList.Version &&\r
-                               1 == FullList->PartialResourceList.Revision);*/\r
-                       for     (Descriptor     = FullList->PartialResourceList.PartialDescriptors;\r
-                               Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;\r
-                               Descriptor++)\r
-                       {\r
-                               if (Descriptor->Type == CmResourceTypeInterrupt)\r
-                               {\r
-                                       DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;\r
-                                       DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;\r
-                               }\r
-                               else if (Descriptor->Type ==    CmResourceTypeMemory)\r
-                               {\r
-                                       DeviceExtension->BaseAddress    = Descriptor->u.Memory.Start;\r
-                                       DeviceExtension->BaseAddrLength = Descriptor->u.Memory.Length;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       DPRINT1("Interrupt level: 0x%x Interrupt        Vector: 0x%x\n",\r
-               DeviceExtension->InterruptLevel,\r
-               DeviceExtension->InterruptVector);\r
-\r
-       /*\r
-       * Init wrapper with this object\r
-       */\r
-       return InitLinuxWrapper(DeviceObject);\r
-}\r
-\r
-// Dispatch PNP\r
-NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)\r
-{\r
-   PIO_STACK_LOCATION IrpSp;\r
-   NTSTATUS Status;\r
-\r
-   IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-   switch (IrpSp->MinorFunction)\r
-   {\r
-      case IRP_MN_START_DEVICE:\r
-         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);\r
-         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))\r
-         \r
-                Status = OHCD_PnPStartDevice(DeviceObject, Irp);\r
-         Irp->IoStatus.Status = Status;\r
-         Irp->IoStatus.Information = 0;\r
-         IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-         break;\r
-\r
-\r
-      case IRP_MN_REMOVE_DEVICE:\r
-      case IRP_MN_QUERY_REMOVE_DEVICE:\r
-      case IRP_MN_CANCEL_REMOVE_DEVICE:\r
-      case IRP_MN_SURPRISE_REMOVAL:\r
-\r
-      case IRP_MN_STOP_DEVICE:\r
-         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);\r
-         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))\r
-            Status = STATUS_SUCCESS;\r
-         Irp->IoStatus.Status = Status;\r
-         Irp->IoStatus.Information = 0;\r
-         IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-\r
-                IoDeleteDevice(DeviceObject); // just delete device for now\r
-         break;\r
-\r
-      case IRP_MN_QUERY_STOP_DEVICE:\r
-      case IRP_MN_CANCEL_STOP_DEVICE:\r
-         Status = STATUS_SUCCESS;\r
-         Irp->IoStatus.Status = STATUS_SUCCESS;\r
-         Irp->IoStatus.Information = 0;\r
-         IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-         break;\r
-         \r
-      default:\r
-         return STATUS_NOT_IMPLEMENTED;\r
-         break;\r
-   }\r
-   \r
-   return Status;\r
-}\r
-\r
-NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)\r
-{\r
-       DbgPrint("IRP_MJ_POWER dispatch\n");\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * Standard DriverEntry method.\r
- */\r
-NTSTATUS STDCALL\r
-DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)\r
-{\r
-       DriverObject->DriverUnload = DriverUnload;\r
-       DriverObject->DriverExtension->AddDevice = AddDevice;\r
-       DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;\r
-       DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
+/*
+   ReactOS specific functions for OHCI module
+   by Aleksey Bragin (aleksey@reactos.com)
+   Some parts of code are inspired (or even just copied) from ReactOS Videoport driver
+*/
+
+#include <ddk/ntddk.h>
+#include <debug.h>
+#include "../linux/linux_wrapper.h"
+#include "ohci_main.h"
+
+// declare basic init funcs
+void init_wrapper(struct pci_dev *probe_dev);
+int ohci_hcd_pci_init (void);
+void ohci_hcd_pci_cleanup (void);
+int STDCALL usb_init(void);
+void STDCALL usb_exit(void);
+extern struct pci_driver ohci_pci_driver;
+extern const struct pci_device_id pci_ids[];
+
+
+
+// This should be removed, but for testing purposes it's here
+struct pci_dev *dev;
+//struct pci_device_id *dev_id;
+
+
+#define USB_OHCI_TAG TAG('u','s','b','o')
+
+NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)
+{
+       PDEVICE_OBJECT fdo;
+       NTSTATUS Status;
+       WCHAR DeviceBuffer[20];
+       UNICODE_STRING DeviceName;
+       POHCI_DRIVER_EXTENSION DriverExtension;
+       POHCI_DEVICE_EXTENSION DeviceExtension;
+       ULONG Size, DeviceNumber;
+
+       DPRINT1("ohci: AddDevice called\n");
+
+       // Allocate driver extension now
+       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+       if (DriverExtension == NULL)
+       {
+               Status = IoAllocateDriverObjectExtension(
+                                       DriverObject,
+                                       DriverObject,
+                                       sizeof(OHCI_DRIVER_EXTENSION),
+                                       (PVOID *)&DriverExtension);
+
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT1("Allocating DriverObjectExtension failed.\n");
+                       return Status;
+               }
+       }
+   
+       // Create a unicode device name
+       DeviceNumber = 0; //TODO: Allocate new device number every time
+       swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber);
+       RtlInitUnicodeString(&DeviceName, DeviceBuffer);
+
+       Status = IoCreateDevice(DriverObject,
+                                   sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/,
+                                                       &DeviceName,
+                                                       FILE_DEVICE_CONTROLLER,
+                                                       0,
+                                                       FALSE,
+                                                       &fdo);
+
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);
+               return Status;
+       }
+
+       // zerofill device extension
+       DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension;
+       RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION));
+       DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
+
+       fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+       // Initialize device extension
+       DeviceExtension->DeviceNumber = DeviceNumber;
+       DeviceExtension->PhysicalDeviceObject = pdo;
+       DeviceExtension->FunctionalDeviceObject = fdo;
+       DeviceExtension->DriverExtension = DriverExtension;
+
+       /* Get bus number from the upper level bus driver. */
+       Size = sizeof(ULONG);
+       Status = IoGetDeviceProperty(
+                               pdo,
+                               DevicePropertyBusNumber,
+                               Size,
+                               &DeviceExtension->SystemIoBusNumber,
+                               &Size);
+       
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("Couldn't get an information from bus driver. Panic!!!\n");
+               return Status;
+       }
+
+       DPRINT("Done AddDevice\n");
+       return STATUS_SUCCESS;
+}
+
+VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject)
+{
+       DPRINT1("DriverUnload()\n");
+
+       // Exit usb device
+       usb_exit();
+
+       // Remove device (ohci_pci_driver.remove)
+       ohci_pci_driver.remove(dev);
+
+       ExFreePool(dev->slot_name);
+       ExFreePool(dev);
+
+       // Perform some cleanup
+       ohci_hcd_pci_cleanup();
+}
+
+NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject)
+{
+       NTSTATUS Status;
+       POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+       // Fill generic linux structs
+       dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_OHCI_TAG);
+       
+       init_wrapper(dev);
+       dev->irq = DeviceExtension->InterruptLevel;
+       dev->dev_ext = (PVOID)DeviceExtension;
+       dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_OHCI_TAG); // 128 max len for slot name
+
+       strcpy(dev->dev.name, "OpenHCI PCI-USB Controller");
+       strcpy(dev->slot_name, "OHCD PCI Slot");
+
+       // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL
+       Status = ohci_hcd_pci_init();
+       //FIXME: Check status returned value
+
+       // Init core usb
+       usb_init();
+
+       // Probe device with real id now
+       ohci_pci_driver.probe(dev, pci_ids);
+
+       DPRINT("InitLinuxWrapper() done\n");
+
+       return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject,
+                                       IN PIRP Irp)
+{
+       PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
+       PDRIVER_OBJECT DriverObject;
+       POHCI_DRIVER_EXTENSION DriverExtension;
+       POHCI_DEVICE_EXTENSION DeviceExtension;
+       PCM_RESOURCE_LIST AllocatedResources;
+
+       /*
+       * Get the initialization data we saved in VideoPortInitialize.
+       */
+       DriverObject = DeviceObject->DriverObject;
+       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+       DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+       /*
+       * Store some resources in the DeviceExtension.
+       */
+       AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;
+       if (AllocatedResources != NULL)
+       {
+               CM_FULL_RESOURCE_DESCRIPTOR     *FullList;
+               CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
+               ULONG ResourceCount;
+               ULONG ResourceListSize;
+
+               /* Save the     resource list */
+               ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;
+               ResourceListSize =
+                       FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
+                       PartialDescriptors[ResourceCount]);
+               DeviceExtension->AllocatedResources     = ExAllocatePool(PagedPool,     ResourceListSize);
+               if (DeviceExtension->AllocatedResources == NULL)
+               {
+                       return STATUS_INSUFFICIENT_RESOURCES;
+               }
+
+               RtlCopyMemory(DeviceExtension->AllocatedResources,
+                       AllocatedResources,
+                       ResourceListSize);
+
+               /* Get the interrupt level/vector -     needed by HwFindAdapter sometimes */
+               for     (FullList =     AllocatedResources->List;
+                       FullList < AllocatedResources->List     + AllocatedResources->Count;
+                       FullList++)
+               {
+                       /* FIXME: Is this ASSERT ok     for     resources from the PNP manager? */
+                       /*ASSERT(FullList->InterfaceType == PCIBus &&
+                               FullList->BusNumber     == DeviceExtension->SystemIoBusNumber &&
+                               1 == FullList->PartialResourceList.Version &&
+                               1 == FullList->PartialResourceList.Revision);*/
+                       for     (Descriptor     = FullList->PartialResourceList.PartialDescriptors;
+                               Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
+                               Descriptor++)
+                       {
+                               if (Descriptor->Type == CmResourceTypeInterrupt)
+                               {
+                                       DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
+                                       DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
+                               }
+                               else if (Descriptor->Type ==    CmResourceTypeMemory)
+                               {
+                                       DeviceExtension->BaseAddress    = Descriptor->u.Memory.Start;
+                                       DeviceExtension->BaseAddrLength = Descriptor->u.Memory.Length;
+                               }
+                       }
+               }
+       }
+       DPRINT1("Interrupt level: 0x%x Interrupt        Vector: 0x%x\n",
+               DeviceExtension->InterruptLevel,
+               DeviceExtension->InterruptVector);
+
+       /*
+       * Init wrapper with this object
+       */
+       return InitLinuxWrapper(DeviceObject);
+}
+
+// Dispatch PNP
+NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+   PIO_STACK_LOCATION IrpSp;
+   NTSTATUS Status;
+
+   IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+   switch (IrpSp->MinorFunction)
+   {
+      case IRP_MN_START_DEVICE:
+         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
+         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+         
+                Status = OHCD_PnPStartDevice(DeviceObject, Irp);
+         Irp->IoStatus.Status = Status;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+         break;
+
+
+      case IRP_MN_REMOVE_DEVICE:
+      case IRP_MN_QUERY_REMOVE_DEVICE:
+      case IRP_MN_CANCEL_REMOVE_DEVICE:
+      case IRP_MN_SURPRISE_REMOVAL:
+
+      case IRP_MN_STOP_DEVICE:
+         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
+         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+            Status = STATUS_SUCCESS;
+         Irp->IoStatus.Status = Status;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+                IoDeleteDevice(DeviceObject); // just delete device for now
+         break;
+
+      case IRP_MN_QUERY_STOP_DEVICE:
+      case IRP_MN_CANCEL_STOP_DEVICE:
+         Status = STATUS_SUCCESS;
+         Irp->IoStatus.Status = STATUS_SUCCESS;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+         break;
+         
+      default:
+         return STATUS_NOT_IMPLEMENTED;
+         break;
+   }
+   
+   return Status;
+}
+
+NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)
+{
+       DbgPrint("IRP_MJ_POWER dispatch\n");
+       return STATUS_SUCCESS;
+}
+
+/*
+ * Standard DriverEntry method.
+ */
+NTSTATUS STDCALL
+DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)
+{
+       DriverObject->DriverUnload = DriverUnload;
+       DriverObject->DriverExtension->AddDevice = AddDevice;
+       DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
+       DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
+
+       return STATUS_SUCCESS;
+}
index 0ee0992..06e3b4e 100644 (file)
@@ -1,47 +1,47 @@
-/*\r
- * OHCI WDM/PNP driver\r
- *\r
- * Copyright (C) 2005 ReactOS Team\r
- *\r
- * Author: Aleksey Bragin (aleksey@reactos.com)\r
- *\r
- */\r
-\r
-#ifndef OHCI_MAIN_H\r
-#define OHCI_MAIN_H\r
-\r
-typedef struct _OHCI_DRIVER_EXTENSION\r
-{\r
-   //OHCI_HW_INITIALIZATION_DATA InitializationData;\r
-   PVOID HwContext;\r
-   //UNICODE_STRING RegistryPath;\r
-} OHCI_DRIVER_EXTENSION, *POHCI_DRIVER_EXTENSION;\r
-\r
-typedef struct _OHCI_DEVICE_EXTENSTION\r
-{\r
-   ULONG DeviceNumber;\r
-   PDEVICE_OBJECT PhysicalDeviceObject;\r
-   PDEVICE_OBJECT FunctionalDeviceObject;\r
-   PDEVICE_OBJECT NextDeviceObject;\r
-   //UNICODE_STRING RegistryPath;\r
-   PKINTERRUPT InterruptObject;\r
-   KSPIN_LOCK InterruptSpinLock;\r
-   PCM_RESOURCE_LIST AllocatedResources;\r
-   ULONG InterruptVector;\r
-   ULONG InterruptLevel;\r
-   PHYSICAL_ADDRESS BaseAddress;\r
-   ULONG BaseAddrLength;\r
-   ULONG Flags;\r
-   ULONG AdapterInterfaceType;\r
-   ULONG SystemIoBusNumber;\r
-   ULONG SystemIoSlotNumber;\r
-   LIST_ENTRY AddressMappingListHead;\r
-   //KDPC DpcObject;\r
-   OHCI_DRIVER_EXTENSION *DriverExtension;\r
-   ULONG DeviceOpened;\r
-   //KMUTEX DeviceLock;\r
-   //CHAR MiniPortDeviceExtension[1];\r
-} OHCI_DEVICE_EXTENSION, *POHCI_DEVICE_EXTENSION;\r
-\r
-\r
-#endif\r
+/*
+ * OHCI WDM/PNP driver
+ *
+ * Copyright (C) 2005 ReactOS Team
+ *
+ * Author: Aleksey Bragin (aleksey@reactos.com)
+ *
+ */
+
+#ifndef OHCI_MAIN_H
+#define OHCI_MAIN_H
+
+typedef struct _OHCI_DRIVER_EXTENSION
+{
+   //OHCI_HW_INITIALIZATION_DATA InitializationData;
+   PVOID HwContext;
+   //UNICODE_STRING RegistryPath;
+} OHCI_DRIVER_EXTENSION, *POHCI_DRIVER_EXTENSION;
+
+typedef struct _OHCI_DEVICE_EXTENSTION
+{
+   ULONG DeviceNumber;
+   PDEVICE_OBJECT PhysicalDeviceObject;
+   PDEVICE_OBJECT FunctionalDeviceObject;
+   PDEVICE_OBJECT NextDeviceObject;
+   //UNICODE_STRING RegistryPath;
+   PKINTERRUPT InterruptObject;
+   KSPIN_LOCK InterruptSpinLock;
+   PCM_RESOURCE_LIST AllocatedResources;
+   ULONG InterruptVector;
+   ULONG InterruptLevel;
+   PHYSICAL_ADDRESS BaseAddress;
+   ULONG BaseAddrLength;
+   ULONG Flags;
+   ULONG AdapterInterfaceType;
+   ULONG SystemIoBusNumber;
+   ULONG SystemIoSlotNumber;
+   LIST_ENTRY AddressMappingListHead;
+   //KDPC DpcObject;
+   OHCI_DRIVER_EXTENSION *DriverExtension;
+   ULONG DeviceOpened;
+   //KMUTEX DeviceLock;
+   //CHAR MiniPortDeviceExtension[1];
+} OHCI_DEVICE_EXTENSION, *POHCI_DEVICE_EXTENSION;
+
+
+#endif
index f16396a..bb194fa 100644 (file)
-#ifndef _I386_BITOPS_H\r
-#define _I386_BITOPS_H\r
-\r
-/*\r
- * Copyright 1992, Linus Torvalds.\r
- */\r
-\r
-//#include <linux/config.h>\r
-\r
-/*\r
- * These have to be done with inline assembly: that way the bit-setting\r
- * is guaranteed to be atomic. All bit operations return 0 if the bit\r
- * was cleared before the operation and != 0 if it was not.\r
- *\r
- * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).\r
- */\r
-\r
-#ifdef CONFIG_SMP\r
-#define LOCK_PREFIX "lock ; "\r
-#else\r
-#define LOCK_PREFIX ""\r
-#endif\r
-\r
-#define ADDR (*(volatile long *) addr)\r
-\r
-/**\r
- * set_bit - Atomically set a bit in memory\r
- * @nr: the bit to set\r
- * @addr: the address to start counting from\r
- *\r
- * This function is atomic and may not be reordered.  See __set_bit()\r
- * if you do not require the atomic guarantees.\r
- * Note that @nr may be almost arbitrarily large; this function is not\r
- * restricted to acting on a single-word quantity.\r
- */\r
-static __inline__ void set_bit(int nr, volatile void * addr)\r
-{\r
-       __asm__ __volatile__( LOCK_PREFIX\r
-               "btsl %1,%0"\r
-               :"=m" (ADDR)\r
-               :"Ir" (nr));\r
-}\r
-\r
-/**\r
- * __set_bit - Set a bit in memory\r
- * @nr: the bit to set\r
- * @addr: the address to start counting from\r
- *\r
- * Unlike set_bit(), this function is non-atomic and may be reordered.\r
- * If it's called on the same region of memory simultaneously, the effect\r
- * may be that only one operation succeeds.\r
- */\r
-static __inline__ void __set_bit(int nr, volatile void * addr)\r
-{\r
-       __asm__(\r
-               "btsl %1,%0"\r
-               :"=m" (ADDR)\r
-               :"Ir" (nr));\r
-}\r
-\r
-/**\r
- * clear_bit - Clears a bit in memory\r
- * @nr: Bit to clear\r
- * @addr: Address to start counting from\r
- *\r
- * clear_bit() is atomic and may not be reordered.  However, it does\r
- * not contain a memory barrier, so if it is used for locking purposes,\r
- * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()\r
- * in order to ensure changes are visible on other processors.\r
- */\r
-static __inline__ void clear_bit(int nr, volatile void * addr)\r
-{\r
-       __asm__ __volatile__( LOCK_PREFIX\r
-               "btrl %1,%0"\r
-               :"=m" (ADDR)\r
-               :"Ir" (nr));\r
-}\r
-#define smp_mb__before_clear_bit()     barrier()\r
-#define smp_mb__after_clear_bit()      barrier()\r
-\r
-/**\r
- * __change_bit - Toggle a bit in memory\r
- * @nr: the bit to set\r
- * @addr: the address to start counting from\r
- *\r
- * Unlike change_bit(), this function is non-atomic and may be reordered.\r
- * If it's called on the same region of memory simultaneously, the effect\r
- * may be that only one operation succeeds.\r
- */\r
-static __inline__ void __change_bit(int nr, volatile void * addr)\r
-{\r
-       __asm__ __volatile__(\r
-               "btcl %1,%0"\r
-               :"=m" (ADDR)\r
-               :"Ir" (nr));\r
-}\r
-\r
-/**\r
- * change_bit - Toggle a bit in memory\r
- * @nr: Bit to clear\r
- * @addr: Address to start counting from\r
- *\r
- * change_bit() is atomic and may not be reordered.\r
- * Note that @nr may be almost arbitrarily large; this function is not\r
- * restricted to acting on a single-word quantity.\r
- */\r
-static __inline__ void change_bit(int nr, volatile void * addr)\r
-{\r
-       __asm__ __volatile__( LOCK_PREFIX\r
-               "btcl %1,%0"\r
-               :"=m" (ADDR)\r
-               :"Ir" (nr));\r
-}\r
-\r
-/**\r
- * test_and_set_bit - Set a bit and return its old value\r
- * @nr: Bit to set\r
- * @addr: Address to count from\r
- *\r
- * This operation is atomic and cannot be reordered.  \r
- * It also implies a memory barrier.\r
- */\r
-static __inline__ int test_and_set_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__ __volatile__( LOCK_PREFIX\r
-               "btsl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit),"=m" (ADDR)\r
-               :"Ir" (nr) : "memory");\r
-       return oldbit;\r
-}\r
-\r
-/**\r
- * __test_and_set_bit - Set a bit and return its old value\r
- * @nr: Bit to set\r
- * @addr: Address to count from\r
- *\r
- * This operation is non-atomic and can be reordered.  \r
- * If two examples of this operation race, one can appear to succeed\r
- * but actually fail.  You must protect multiple accesses with a lock.\r
- */\r
-static __inline__ int __test_and_set_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__(\r
-               "btsl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit),"=m" (ADDR)\r
-               :"Ir" (nr));\r
-       return oldbit;\r
-}\r
-\r
-/**\r
- * test_and_clear_bit - Clear a bit and return its old value\r
- * @nr: Bit to set\r
- * @addr: Address to count from\r
- *\r
- * This operation is atomic and cannot be reordered.  \r
- * It also implies a memory barrier.\r
- */\r
-static __inline__ int test_and_clear_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__ __volatile__( LOCK_PREFIX\r
-               "btrl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit),"=m" (ADDR)\r
-               :"Ir" (nr) : "memory");\r
-       return oldbit;\r
-}\r
-\r
-/**\r
- * __test_and_clear_bit - Clear a bit and return its old value\r
- * @nr: Bit to set\r
- * @addr: Address to count from\r
- *\r
- * This operation is non-atomic and can be reordered.  \r
- * If two examples of this operation race, one can appear to succeed\r
- * but actually fail.  You must protect multiple accesses with a lock.\r
- */\r
-static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__(\r
-               "btrl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit),"=m" (ADDR)\r
-               :"Ir" (nr));\r
-       return oldbit;\r
-}\r
-\r
-/* WARNING: non atomic and it can be reordered! */\r
-static __inline__ int __test_and_change_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__ __volatile__(\r
-               "btcl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit),"=m" (ADDR)\r
-               :"Ir" (nr) : "memory");\r
-       return oldbit;\r
-}\r
-\r
-/**\r
- * test_and_change_bit - Change a bit and return its new value\r
- * @nr: Bit to set\r
- * @addr: Address to count from\r
- *\r
- * This operation is atomic and cannot be reordered.  \r
- * It also implies a memory barrier.\r
- */\r
-static __inline__ int test_and_change_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__ __volatile__( LOCK_PREFIX\r
-               "btcl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit),"=m" (ADDR)\r
-               :"Ir" (nr) : "memory");\r
-       return oldbit;\r
-}\r
-\r
-#if 0 /* Fool kernel-doc since it doesn't do macros yet */\r
-/**\r
- * test_bit - Determine whether a bit is set\r
- * @nr: bit number to test\r
- * @addr: Address to start counting from\r
- */\r
-static int test_bit(int nr, const volatile void * addr);\r
-#endif\r
-\r
-static __inline__ int constant_test_bit(int nr, const volatile void * addr)\r
-{\r
-       return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;\r
-}\r
-\r
-static __inline__ int variable_test_bit(int nr, volatile void * addr)\r
-{\r
-       int oldbit;\r
-\r
-       __asm__ __volatile__(\r
-               "btl %2,%1\n\tsbbl %0,%0"\r
-               :"=r" (oldbit)\r
-               :"m" (ADDR),"Ir" (nr));\r
-       return oldbit;\r
-}\r
-\r
-#define test_bit(nr,addr) \\r
-(__builtin_constant_p(nr) ? \\r
- constant_test_bit((nr),(addr)) : \\r
- variable_test_bit((nr),(addr)))\r
-\r
-/**\r
- * find_first_zero_bit - find the first zero bit in a memory region\r
- * @addr: The address to start the search at\r
- * @size: The maximum size to search\r
- *\r
- * Returns the bit-number of the first zero bit, not the number of the byte\r
- * containing a bit.\r
- */\r
-static __inline__ int find_first_zero_bit(void * addr, unsigned size)\r
-{\r
-       int d0, d1, d2;\r
-       int res;\r
-\r
-       if (!size)\r
-               return 0;\r
-       /* This looks at memory. Mark it volatile to tell gcc not to move it around */\r
-       __asm__ __volatile__(\r
-               "movl $-1,%%eax\n\t"\r
-               "xorl %%edx,%%edx\n\t"\r
-               "repe; scasl\n\t"\r
-               "je 1f\n\t"\r
-               "xorl -4(%%edi),%%eax\n\t"\r
-               "subl $4,%%edi\n\t"\r
-               "bsfl %%eax,%%edx\n"\r
-               "1:\tsubl %%ebx,%%edi\n\t"\r
-               "shll $3,%%edi\n\t"\r
-               "addl %%edi,%%edx"\r
-               :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)\r
-               :"1" ((size + 31) >> 5), "2" (addr), "b" (addr));\r
-       return res;\r
-}\r
-\r
-/**\r
- * find_next_zero_bit - find the first zero bit in a memory region\r
- * @addr: The address to base the search on\r
- * @offset: The bitnumber to start searching at\r
- * @size: The maximum size to search\r
- */\r
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)\r
-{\r
-       unsigned long * p = ((unsigned long *) addr) + (offset >> 5);\r
-       int set = 0, bit = offset & 31, res;\r
-       \r
-       if (bit) {\r
-               /*\r
-                * Look for zero in first byte\r
-                */\r
-               __asm__("bsfl %1,%0\n\t"\r
-                       "jne 1f\n\t"\r
-                       "movl $32, %0\n"\r
-                       "1:"\r
-                       : "=r" (set)\r
-                       : "r" (~(*p >> bit)));\r
-               if (set < (32 - bit))\r
-                       return set + offset;\r
-               set = 32 - bit;\r
-               p++;\r
-       }\r
-       /*\r
-        * No zero yet, search remaining full bytes for a zero\r
-        */\r
-       res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));\r
-       return (offset + set + res);\r
-}\r
-\r
-/**\r
- * ffz - find first zero in word.\r
- * @word: The word to search\r
- *\r
- * Undefined if no zero exists, so code should check against ~0UL first.\r
- */\r
-static __inline__ unsigned long ffz(unsigned long word)\r
-{\r
-       __asm__("bsfl %1,%0"\r
-               :"=r" (word)\r
-               :"r" (~word));\r
-       return word;\r
-}\r
-\r
-#ifdef __KERNEL__\r
-\r
-/**\r
- * ffs - find first bit set\r
- * @x: the word to search\r
- *\r
- * This is defined the same way as\r
- * the libc and compiler builtin ffs routines, therefore\r
- * differs in spirit from the above ffz (man ffs).\r
- */\r
-static __inline__ int ffs(int x)\r
-{\r
-       int r;\r
-\r
-       __asm__("bsfl %1,%0\n\t"\r
-               "jnz 1f\n\t"\r
-               "movl $-1,%0\n"\r
-               "1:" : "=r" (r) : "rm" (x));\r
-       return r+1;\r
-}\r
-\r
-/**\r
- * hweightN - returns the hamming weight of a N-bit word\r
- * @x: the word to weigh\r
- *\r
- * The Hamming Weight of a number is the total number of bits set in it.\r
- */\r
-\r
-#define hweight32(x) generic_hweight32(x)\r
-#define hweight16(x) generic_hweight16(x)\r
-#define hweight8(x) generic_hweight8(x)\r
-\r
-#endif /* __KERNEL__ */\r
-\r
-#ifdef __KERNEL__\r
-\r
-#define ext2_set_bit                 __test_and_set_bit\r
-#define ext2_clear_bit               __test_and_clear_bit\r
-#define ext2_test_bit                test_bit\r
-#define ext2_find_first_zero_bit     find_first_zero_bit\r
-#define ext2_find_next_zero_bit      find_next_zero_bit\r
-\r
-/* Bitmap functions for the minix filesystem.  */\r
-#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr)\r
-#define minix_set_bit(nr,addr) __set_bit(nr,addr)\r
-#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr)\r
-#define minix_test_bit(nr,addr) test_bit(nr,addr)\r
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)\r
-\r
-#endif /* __KERNEL__ */\r
-\r
-#endif /* _I386_BITOPS_H */\r
+#ifndef _I386_BITOPS_H
+#define _I386_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ */
+
+//#include <linux/config.h>
+
+/*
+ * These have to be done with inline assembly: that way the bit-setting
+ * is guaranteed to be atomic. All bit operations return 0 if the bit
+ * was cleared before the operation and != 0 if it was not.
+ *
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX "lock ; "
+#else
+#define LOCK_PREFIX ""
+#endif
+
+#define ADDR (*(volatile long *) addr)
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static __inline__ void set_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__( LOCK_PREFIX
+               "btsl %1,%0"
+               :"=m" (ADDR)
+               :"Ir" (nr));
+}
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void __set_bit(int nr, volatile void * addr)
+{
+       __asm__(
+               "btsl %1,%0"
+               :"=m" (ADDR)
+               :"Ir" (nr));
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
+static __inline__ void clear_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__( LOCK_PREFIX
+               "btrl %1,%0"
+               :"=m" (ADDR)
+               :"Ir" (nr));
+}
+#define smp_mb__before_clear_bit()     barrier()
+#define smp_mb__after_clear_bit()      barrier()
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__(
+               "btcl %1,%0"
+               :"=m" (ADDR)
+               :"Ir" (nr));
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static __inline__ void change_bit(int nr, volatile void * addr)
+{
+       __asm__ __volatile__( LOCK_PREFIX
+               "btcl %1,%0"
+               :"=m" (ADDR)
+               :"Ir" (nr));
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__( LOCK_PREFIX
+               "btsl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr) : "memory");
+       return oldbit;
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__(
+               "btsl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr));
+       return oldbit;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__( LOCK_PREFIX
+               "btrl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr) : "memory");
+       return oldbit;
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__(
+               "btrl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr));
+       return oldbit;
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "btcl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr) : "memory");
+       return oldbit;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its new value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
+static __inline__ int test_and_change_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__( LOCK_PREFIX
+               "btcl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr) : "memory");
+       return oldbit;
+}
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet */
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static int test_bit(int nr, const volatile void * addr);
+#endif
+
+static __inline__ int constant_test_bit(int nr, const volatile void * addr)
+{
+       return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
+}
+
+static __inline__ int variable_test_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "btl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit)
+               :"m" (ADDR),"Ir" (nr));
+       return oldbit;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ constant_test_bit((nr),(addr)) : \
+ variable_test_bit((nr),(addr)))
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+static __inline__ int find_first_zero_bit(void * addr, unsigned size)
+{
+       int d0, d1, d2;
+       int res;
+
+       if (!size)
+               return 0;
+       /* This looks at memory. Mark it volatile to tell gcc not to move it around */
+       __asm__ __volatile__(
+               "movl $-1,%%eax\n\t"
+               "xorl %%edx,%%edx\n\t"
+               "repe; scasl\n\t"
+               "je 1f\n\t"
+               "xorl -4(%%edi),%%eax\n\t"
+               "subl $4,%%edi\n\t"
+               "bsfl %%eax,%%edx\n"
+               "1:\tsubl %%ebx,%%edi\n\t"
+               "shll $3,%%edi\n\t"
+               "addl %%edi,%%edx"
+               :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+               :"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
+       return res;
+}
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+{
+       unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+       int set = 0, bit = offset & 31, res;
+       
+       if (bit) {
+               /*
+                * Look for zero in first byte
+                */
+               __asm__("bsfl %1,%0\n\t"
+                       "jne 1f\n\t"
+                       "movl $32, %0\n"
+                       "1:"
+                       : "=r" (set)
+                       : "r" (~(*p >> bit)));
+               if (set < (32 - bit))
+                       return set + offset;
+               set = 32 - bit;
+               p++;
+       }
+       /*
+        * No zero yet, search remaining full bytes for a zero
+        */
+       res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+       return (offset + set + res);
+}
+
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static __inline__ unsigned long ffz(unsigned long word)
+{
+       __asm__("bsfl %1,%0"
+               :"=r" (word)
+               :"r" (~word));
+       return word;
+}
+
+#ifdef __KERNEL__
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static __inline__ int ffs(int x)
+{
+       int r;
+
+       __asm__("bsfl %1,%0\n\t"
+               "jnz 1f\n\t"
+               "movl $-1,%0\n"
+               "1:" : "=r" (r) : "rm" (x));
+       return r+1;
+}
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif /* __KERNEL__ */
+
+#ifdef __KERNEL__
+
+#define ext2_set_bit                 __test_and_set_bit
+#define ext2_clear_bit               __test_and_clear_bit
+#define ext2_test_bit                test_bit
+#define ext2_find_first_zero_bit     find_first_zero_bit
+#define ext2_find_next_zero_bit      find_next_zero_bit
+
+/* Bitmap functions for the minix filesystem.  */
+#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr)
+#define minix_set_bit(nr,addr) __set_bit(nr,addr)
+#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+
+#endif /* __KERNEL__ */
+
+#endif /* _I386_BITOPS_H */
index 6509d07..ac05ed6 100644 (file)
@@ -1,72 +1,72 @@
-#ifndef _LINUX_BITOPS_H\r
-#define _LINUX_BITOPS_H\r
-\r
-\r
-/*\r
- * ffs: find first bit set. This is defined the same way as\r
- * the libc and compiler builtin ffs routines, therefore\r
- * differs in spirit from the above ffz (man ffs).\r
- */\r
-\r
-static inline int generic_ffs(int x)\r
-{\r
-       int r = 1;\r
-\r
-       if (!x)\r
-               return 0;\r
-       if (!(x & 0xffff)) {\r
-               x >>= 16;\r
-               r += 16;\r
-       }\r
-       if (!(x & 0xff)) {\r
-               x >>= 8;\r
-               r += 8;\r
-       }\r
-       if (!(x & 0xf)) {\r
-               x >>= 4;\r
-               r += 4;\r
-       }\r
-       if (!(x & 3)) {\r
-               x >>= 2;\r
-               r += 2;\r
-       }\r
-       if (!(x & 1)) {\r
-               x >>= 1;\r
-               r += 1;\r
-       }\r
-       return r;\r
-}\r
-\r
-/*\r
- * hweightN: returns the hamming weight (i.e. the number\r
- * of bits set) of a N-bit word\r
- */\r
-\r
-static inline unsigned int generic_hweight32(unsigned int w)\r
-{\r
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);\r
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);\r
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);\r
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);\r
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);\r
-}\r
-\r
-static inline unsigned int generic_hweight16(unsigned int w)\r
-{\r
-        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);\r
-        res = (res & 0x3333) + ((res >> 2) & 0x3333);\r
-        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);\r
-        return (res & 0x00FF) + ((res >> 8) & 0x00FF);\r
-}\r
-\r
-static inline unsigned int generic_hweight8(unsigned int w)\r
-{\r
-        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);\r
-        res = (res & 0x33) + ((res >> 2) & 0x33);\r
-        return (res & 0x0F) + ((res >> 4) & 0x0F);\r
-}\r
-\r
-#include "asm/bitops.h"\r
-\r
-\r
-#endif\r
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+static inline int generic_ffs(int x)
+{
+       int r = 1;
+
+       if (!x)
+               return 0;
+       if (!(x & 0xffff)) {
+               x >>= 16;
+               r += 16;
+       }
+       if (!(x & 0xff)) {
+               x >>= 8;
+               r += 8;
+       }
+       if (!(x & 0xf)) {
+               x >>= 4;
+               r += 4;
+       }
+       if (!(x & 3)) {
+               x >>= 2;
+               r += 2;
+       }
+       if (!(x & 1)) {
+               x >>= 1;
+               r += 1;
+       }
+       return r;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+static inline unsigned int generic_hweight32(unsigned int w)
+{
+        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+static inline unsigned int generic_hweight16(unsigned int w)
+{
+        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+        res = (res & 0x3333) + ((res >> 2) & 0x3333);
+        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+static inline unsigned int generic_hweight8(unsigned int w)
+{
+        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+        res = (res & 0x33) + ((res >> 2) & 0x33);
+        return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+#include "asm/bitops.h"
+
+
+#endif
index d99b7f2..db64976 100644 (file)
-#ifndef _Boot_H_\r
-#define _Boot_H_\r
-\r
-#include "config.h"\r
-\r
-/***************************************************************************\r
-      Includes used by XBox boot code\r
- ***************************************************************************/\r
-/***************************************************************************\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- ***************************************************************************/\r
-\r
-/////////////////////////////////\r
-// configuration\r
-\r
-#include "consts.h"\r
-#include "stdint.h"\r
-#include "cromwell_types.h"\r
-\r
-\r
-unsigned int cromwell_config;\r
-unsigned int cromwell_retryload;\r
-unsigned int cromwell_loadbank;\r
-unsigned int cromwell_Biostype;\r
-\r
-unsigned int xbox_ram;\r
-\r
-#define XROMWELL       0\r
-#define CROMWELL       1\r
-\r
-#define ICON_WIDTH 64\r
-#define ICON_HEIGHT 64\r
-/*\r
-static double min (double a, double b)\r
-{\r
-       if (a < b) return a; else return b;\r
-}\r
-\r
-static inline double max (double a, double b)\r
-{\r
-       if (a > b) return a; else return b;\r
-}\r
-*/\r
-//#include "iso_fs.h"\r
-//#include "BootVideo.h"\r
-\r
-//#define ASSERT(exp) { if(!(exp)) { bprintf("Assert failed file " __FILE__ " line %d\n", __LINE__); } }\r
-\r
-#if 0\r
-extern volatile CURRENT_VIDEO_MODE_DETAILS vmode;\r
-unsigned int video_encoder;\r
-\r
-volatile u32 VIDEO_CURSOR_POSX;\r
-volatile u32 VIDEO_CURSOR_POSY;\r
-volatile u32 VIDEO_ATTR;\r
-volatile u32 VIDEO_LUMASCALING;\r
-volatile u32 VIDEO_RSCALING;\r
-volatile u32 VIDEO_BSCALING;\r
-volatile u32 BIOS_TICK_COUNT;\r
-volatile u32 VIDEO_VSYNC_POSITION;\r
-volatile u32 VIDEO_VSYNC_DIR;\r
-volatile u32 DVD_TRAY_STATE;\r
-\r
-u8 VIDEO_AV_MODE ;\r
-\r
-#define DVD_CLOSED             0\r
-#define DVD_CLOSING            1\r
-#define DVD_OPEN               2\r
-#define DVD_OPENING            3\r
-\r
-/////////////////////////////////\r
-// Superfunky i386 internal structures\r
-\r
-typedef struct gdt_t {\r
-        unsigned short       m_wSize __attribute__ ((packed));\r
-        unsigned long m_dwBase32 __attribute__ ((packed));\r
-        unsigned short       m_wDummy __attribute__ ((packed));\r
-} ts_descriptor_pointer;\r
-\r
-typedef struct {  // inside an 8-byte protected mode interrupt vector\r
-       u16 m_wHandlerHighAddressLow16;\r
-       u16 m_wSelector;\r
-       u16 m_wType;\r
-       u16 m_wHandlerLinearAddressHigh16;\r
-} ts_pm_interrupt;\r
-\r
-typedef enum {\r
-       EDT_UNKNOWN= 0,\r
-       EDT_XBOXFS\r
-} enumDriveType;\r
-\r
-typedef struct tsHarddiskInfo {  // this is the retained knowledge about an IDE device after init\r
-    unsigned short m_fwPortBase;\r
-    unsigned short m_wCountHeads;\r
-    unsigned short m_wCountCylinders;\r
-    unsigned short m_wCountSectorsPerTrack;\r
-    unsigned long m_dwCountSectorsTotal; /* total */\r
-    unsigned char m_bLbaMode;  /* am i lba (0x40) or chs (0x00) */\r
-    unsigned char m_szIdentityModelNumber[40];\r
-    unsigned char term_space_1[2];\r
-    unsigned char m_szSerial[20];\r
-    unsigned char term_space_2[2];\r
-    char m_szFirmware[8];\r
-    unsigned char term_space_3[2];\r
-    unsigned char m_fDriveExists;\r
-    unsigned char m_fAtapi;  // true if a CDROM, etc\r
-    enumDriveType m_enumDriveType;\r
-    unsigned char m_bCableConductors;  // valid for device 0 if present\r
-    unsigned short m_wAtaRevisionSupported;\r
-    unsigned char s_length;\r
-    unsigned char m_length;\r
-    unsigned char m_fHasMbr;\r
-    unsigned short m_securitySettings; //This contains the contents of the ATA security regs\r
-} tsHarddiskInfo;\r
-\r
-/////////////////////////////////\r
-// LED-flashing codes\r
-// or these together as argument to I2cSetFrontpanelLed\r
-\r
-enum {\r
-       I2C_LED_RED0 = 0x80,\r
-       I2C_LED_RED1 = 0x40,\r
-       I2C_LED_RED2 = 0x20,\r
-       I2C_LED_RED3 = 0x10,\r
-       I2C_LED_GREEN0 = 0x08,\r
-       I2C_LED_GREEN1 = 0x04,\r
-       I2C_LED_GREEN2 = 0x02,\r
-       I2C_LED_GREEN3 = 0x01\r
-};\r
-\r
-///////////////////////////////\r
-/* BIOS-wide error codes               all have b31 set  */\r
-\r
-enum {\r
-       ERR_SUCCESS = 0,  // completed without error\r
-\r
-       ERR_I2C_ERROR_TIMEOUT = 0x80000001,  // I2C action failed because it did not complete in a reasonable time\r
-       ERR_I2C_ERROR_BUS = 0x80000002, // I2C action failed due to non retryable bus error\r
-\r
-       ERR_BOOT_PIC_ALG_BROKEN = 0x80000101 // PIC algorithm did not pass its self-test\r
-};\r
-\r
-/////////////////////////////////\r
-// some Boot API prototypes\r
-\r
-//////// BootPerformPicChallengeResponseAction.c\r
-\r
-/* ----------------------------  IO primitives -----------------------------------------------------------\r
-*/\r
-\r
-static __inline void IoOutputByte(u16 wAds, u8 bValue) {\r
-//     __asm__  ("                          out        %%al,%%dx" : : "edx" (dwAds), "al" (bValue)  );\r
-    __asm__ __volatile__ ("outb %b0,%w1": :"a" (bValue), "Nd" (wAds));\r
-}\r
-\r
-static __inline void IoOutputWord(u16 wAds, u16 wValue) {\r
-//     __asm__  ("      out    %%ax,%%dx       " : : "edx" (dwAds), "ax" (wValue)  );\r
-    __asm__ __volatile__ ("outw %0,%w1": :"a" (wValue), "Nd" (wAds));\r
-       }\r
-\r
-static __inline void IoOutputDword(u16 wAds, u32 dwValue) {\r
-//     __asm__  ("      out    %%eax,%%dx      " : : "edx" (dwAds), "ax" (wValue)  );\r
-    __asm__ __volatile__ ("outl %0,%w1": :"a" (dwValue), "Nd" (wAds));\r
-}\r
-\r
-\r
-static __inline u8 IoInputByte(u16 wAds) {\r
-  unsigned char _v;\r
-\r
-  __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (wAds));\r
-  return _v;\r
-}\r
-\r
-static __inline u16 IoInputWord(u16 wAds) {\r
-  u16 _v;\r
-\r
-  __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd" (wAds));\r
-  return _v;\r
-}\r
-\r
-static __inline u32 IoInputDword(u16 wAds) {\r
-  u32 _v;\r
-\r
-  __asm__ __volatile__ ("inl %w1,%0":"=a" (_v):"Nd" (wAds));\r
-  return _v;\r
-}\r
-\r
-#define rdmsr(msr,val1,val2) \\r
-       __asm__ __volatile__("rdmsr" \\r
-                           : "=a" (val1), "=d" (val2) \\r
-                           : "c" (msr))\r
-\r
-#define wrmsr(msr,val1,val2) \\r
-     __asm__ __volatile__("wrmsr" \\r
-                         : /* no outputs */ \\r
-                         : "c" (msr), "a" (val1), "d" (val2))\r
-\r
-\r
-void BootPciInterruptEnable(void);\r
-\r
-       // boot process\r
-int BootPerformPicChallengeResponseAction(void);\r
-       // LED control (see associated enum above)\r
-int I2cSetFrontpanelLed(u8 b);\r
-\r
-#define bprintf(...)\r
-\r
-#if PRINT_TRACE\r
-#define TRACE bprintf(__FILE__ " :%d\n\r",__LINE__);\r
-#else\r
-#define TRACE\r
-#endif\r
-\r
-typedef struct _LIST_ENTRY {\r
-       struct _LIST_ENTRY *m_plistentryNext;\r
-       struct _LIST_ENTRY *m_plistentryPrevious;\r
-} LIST_ENTRY;\r
-\r
-void ListEntryInsertAfterCurrent(LIST_ENTRY *plistentryCurrent, LIST_ENTRY *plistentryNew);\r
-void ListEntryRemove(LIST_ENTRY *plistentryCurrent);\r
-\r
-////////// BootPerformXCodeActions.c\r
-\r
-int BootPerformXCodeActions(void);\r
-\r
-#include "BootEEPROM.h"\r
-#include "BootParser.h"\r
-\r
-////////// BootStartBios.c\r
-\r
-void StartBios(CONFIGENTRY *config,int nActivePartition, int nFATXPresent,int bootfrom);\r
-int BootMenu(CONFIGENTRY *config,int nDrive,int nActivePartition, int nFATXPresent);\r
-\r
-////////// BootResetActions.c\r
-void ClearIDT (void);\r
-void BootResetAction(void);\r
-void BootCpuCache(bool fEnable) ;\r
-int printk(const char *szFormat, ...);\r
-void BiosCmosWrite(u8 bAds, u8 bData);\r
-u8 BiosCmosRead(u8 bAds);\r
-\r
-\r
-///////// BootPciPeripheralInitialization.c\r
-void BootPciPeripheralInitialization(void);\r
-void BootAGPBUSInitialization(void);\r
-void BootDetectMemorySize(void);\r
-extern void    ReadPCIByte(unsigned int bus, unsigned int dev, unsigned intfunc,       unsigned int reg_off, unsigned char *pbyteval);\r
-extern void    WritePCIByte(unsigned int bus, unsigned int dev, unsigned int func,     unsigned int reg_off, unsigned char byteval);\r
-extern void    ReadPCIDword(unsigned int bus, unsigned int dev, unsigned int func,     unsigned int reg_off, unsigned int *pdwordval);\r
-extern void    WritePCIDword(unsigned int bus, unsigned int dev, unsigned int func,            unsigned int reg_off, unsigned int dwordval);\r
-extern void    ReadPCIBlock(unsigned int bus, unsigned int dev, unsigned int func,             unsigned int reg_off, unsigned char *buf,       unsigned int nbytes);\r
-extern void    WritePCIBlock(unsigned int bus, unsigned int dev, unsigned int func,    unsigned int reg_off, unsigned char *buf, unsigned int nbytes);\r
-\r
-void PciWriteByte (unsigned int bus, unsigned int dev, unsigned int func,\r
-               unsigned int reg_off, unsigned char byteval);\r
-u8 PciReadByte(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off);\r
-u32 PciWriteDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, u32 dw);\r
-u32 PciReadDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off);\r
-\r
-///////// BootPerformPicChallengeResponseAction.c\r
-\r
-int I2CTransmitWord(u8 bPicAddressI2cFormat, u16 wDataToWrite);\r
-int I2CTransmitByteGetReturn(u8 bPicAddressI2cFormat, u8 bDataToWrite);\r
-bool I2CGetTemperature(int *, int *);\r
-void I2CModifyBits(u8 bAds, u8 bReg, u8 bData, u8 bMask);\r
-\r
-///////// BootIde.c\r
-\r
-extern tsHarddiskInfo tsaHarddiskInfo[];  // static struct stores data about attached drives\r
-int BootIdeInit(void);\r
-int BootIdeReadSector(int nDriveIndex, void * pbBuffer, unsigned int block, int byte_offset, int n_bytes);\r
-int BootIdeBootSectorHddOrElTorito(int nDriveIndex, u8 * pbaResult);\r
-int BootIdeAtapiAdditionalSenseCode(int nDrive, u8 * pba, int nLengthMaxReturn);\r
-int BootIdeSetTransferMode(int nIndexDrive, int nMode);\r
-int BootIdeWaitNotBusy(unsigned uIoBase);\r
-bool BootIdeAtapiReportFriendlyError(int nDriveIndex, char * szErrorReturn, int nMaxLengthError);\r
-void BootIdeAtapiPrintkFriendlyError(int nDriveIndex);\r
-\r
-///////// BootUSB.c\r
-\r
-void BootStopUSB(void);\r
-void BootStartUSB(void);\r
-void USBGetEvents(void);\r
-\r
-#include "xpad.h"\r
-\r
-extern struct xpad_data XPAD_current[4];\r
-extern struct xpad_data XPAD_last[4];\r
-\r
-extern void wait_ms(u32 ticks);\r
-extern void wait_us(u32 ticks);\r
-extern void wait_smalldelay(void);\r
-\r
-\r
-void * memcpy(void *dest, const void *src,  size_t size);\r
-void * memset(void *dest, int data,  size_t size);\r
-int memcmp(const void *buffer1, const void *buffer2, size_t num);\r
-int _strncmp(const char *sz1, const char *sz2, int nMax);\r
-char * strcpy(char *sz, const char *szc);\r
-char * _strncpy (char * dest, const char * src, size_t n);\r
-void chrreplace(char *string, char search, char ch);\r
-\r
-#define printf printk\r
-#define sleep wait_ms\r
-int tolower(int ch);\r
-int isspace (int c);\r
-\r
-void MemoryManagementInitialization(void * pvStartAddress, u32 dwTotalMemoryAllocLength);\r
-void * malloc(size_t size);\r
-void free(void *);\r
-\r
-extern volatile int nCountI2cinterrupts, nCountUnusedInterrupts, nCountUnusedInterruptsPic2, nCountInterruptsSmc, nCountInterruptsIde;\r
-extern volatile bool fSeenPowerdown;\r
-typedef enum {\r
-       ETS_OPEN_OR_OPENING=0,\r
-       ETS_CLOSING,\r
-       ETS_CLOSED\r
-} TRAY_STATE;\r
-extern volatile TRAY_STATE traystate;\r
-\r
-\r
-extern void BootInterruptsWriteIdt(void);\r
-#endif\r
-int copy_swap_trim(unsigned char *dst, unsigned char *src, int len);\r
-void HMAC_SHA1( unsigned char *result,\r
-                unsigned char *key, int key_length,\r
-                unsigned char *text1, int text1_length,\r
-                unsigned char *text2, int text2_length );\r
-\r
-char *strrchr0(char *string, char ch);\r
-\r
-#endif // _Boot_H_\r
+#ifndef _Boot_H_
+#define _Boot_H_
+
+#include "config.h"
+
+/***************************************************************************
+      Includes used by XBox boot code
+ ***************************************************************************/
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/////////////////////////////////
+// configuration
+
+#include "consts.h"
+#include "stdint.h"
+#include "cromwell_types.h"
+
+
+unsigned int cromwell_config;
+unsigned int cromwell_retryload;
+unsigned int cromwell_loadbank;
+unsigned int cromwell_Biostype;
+
+unsigned int xbox_ram;
+
+#define XROMWELL       0
+#define CROMWELL       1
+
+#define ICON_WIDTH 64
+#define ICON_HEIGHT 64
+/*
+static double min (double a, double b)
+{
+       if (a < b) return a; else return b;
+}
+
+static inline double max (double a, double b)
+{
+       if (a > b) return a; else return b;
+}
+*/
+//#include "iso_fs.h"
+//#include "BootVideo.h"
+
+//#define ASSERT(exp) { if(!(exp)) { bprintf("Assert failed file " __FILE__ " line %d\n", __LINE__); } }
+
+#if 0
+extern volatile CURRENT_VIDEO_MODE_DETAILS vmode;
+unsigned int video_encoder;
+
+volatile u32 VIDEO_CURSOR_POSX;
+volatile u32 VIDEO_CURSOR_POSY;
+volatile u32 VIDEO_ATTR;
+volatile u32 VIDEO_LUMASCALING;
+volatile u32 VIDEO_RSCALING;
+volatile u32 VIDEO_BSCALING;
+volatile u32 BIOS_TICK_COUNT;
+volatile u32 VIDEO_VSYNC_POSITION;
+volatile u32 VIDEO_VSYNC_DIR;
+volatile u32 DVD_TRAY_STATE;
+
+u8 VIDEO_AV_MODE ;
+
+#define DVD_CLOSED             0
+#define DVD_CLOSING            1
+#define DVD_OPEN               2
+#define DVD_OPENING            3
+
+/////////////////////////////////
+// Superfunky i386 internal structures
+
+typedef struct gdt_t {
+        unsigned short       m_wSize __attribute__ ((packed));
+        unsigned long m_dwBase32 __attribute__ ((packed));
+        unsigned short       m_wDummy __attribute__ ((packed));
+} ts_descriptor_pointer;
+
+typedef struct {  // inside an 8-byte protected mode interrupt vector
+       u16 m_wHandlerHighAddressLow16;
+       u16 m_wSelector;
+       u16 m_wType;
+       u16 m_wHandlerLinearAddressHigh16;
+} ts_pm_interrupt;
+
+typedef enum {
+       EDT_UNKNOWN= 0,
+       EDT_XBOXFS
+} enumDriveType;
+
+typedef struct tsHarddiskInfo {  // this is the retained knowledge about an IDE device after init
+    unsigned short m_fwPortBase;
+    unsigned short m_wCountHeads;
+    unsigned short m_wCountCylinders;
+    unsigned short m_wCountSectorsPerTrack;
+    unsigned long m_dwCountSectorsTotal; /* total */
+    unsigned char m_bLbaMode;  /* am i lba (0x40) or chs (0x00) */
+    unsigned char m_szIdentityModelNumber[40];
+    unsigned char term_space_1[2];
+    unsigned char m_szSerial[20];
+    unsigned char term_space_2[2];
+    char m_szFirmware[8];
+    unsigned char term_space_3[2];
+    unsigned char m_fDriveExists;
+    unsigned char m_fAtapi;  // true if a CDROM, etc
+    enumDriveType m_enumDriveType;
+    unsigned char m_bCableConductors;  // valid for device 0 if present
+    unsigned short m_wAtaRevisionSupported;
+    unsigned char s_length;
+    unsigned char m_length;
+    unsigned char m_fHasMbr;
+    unsigned short m_securitySettings; //This contains the contents of the ATA security regs
+} tsHarddiskInfo;
+
+/////////////////////////////////
+// LED-flashing codes
+// or these together as argument to I2cSetFrontpanelLed
+
+enum {
+       I2C_LED_RED0 = 0x80,
+       I2C_LED_RED1 = 0x40,
+       I2C_LED_RED2 = 0x20,
+       I2C_LED_RED3 = 0x10,
+       I2C_LED_GREEN0 = 0x08,
+       I2C_LED_GREEN1 = 0x04,
+       I2C_LED_GREEN2 = 0x02,
+       I2C_LED_GREEN3 = 0x01
+};
+
+///////////////////////////////
+/* BIOS-wide error codes               all have b31 set  */
+
+enum {
+       ERR_SUCCESS = 0,  // completed without error
+
+       ERR_I2C_ERROR_TIMEOUT = 0x80000001,  // I2C action failed because it did not complete in a reasonable time
+       ERR_I2C_ERROR_BUS = 0x80000002, // I2C action failed due to non retryable bus error
+
+       ERR_BOOT_PIC_ALG_BROKEN = 0x80000101 // PIC algorithm did not pass its self-test
+};
+
+/////////////////////////////////
+// some Boot API prototypes
+
+//////// BootPerformPicChallengeResponseAction.c
+
+/* ----------------------------  IO primitives -----------------------------------------------------------
+*/
+
+static __inline void IoOutputByte(u16 wAds, u8 bValue) {
+//     __asm__  ("                          out        %%al,%%dx" : : "edx" (dwAds), "al" (bValue)  );
+    __asm__ __volatile__ ("outb %b0,%w1": :"a" (bValue), "Nd" (wAds));
+}
+
+static __inline void IoOutputWord(u16 wAds, u16 wValue) {
+//     __asm__  ("      out    %%ax,%%dx       " : : "edx" (dwAds), "ax" (wValue)  );
+    __asm__ __volatile__ ("outw %0,%w1": :"a" (wValue), "Nd" (wAds));
+       }
+
+static __inline void IoOutputDword(u16 wAds, u32 dwValue) {
+//     __asm__  ("      out    %%eax,%%dx      " : : "edx" (dwAds), "ax" (wValue)  );
+    __asm__ __volatile__ ("outl %0,%w1": :"a" (dwValue), "Nd" (wAds));
+}
+
+
+static __inline u8 IoInputByte(u16 wAds) {
+  unsigned char _v;
+
+  __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (wAds));
+  return _v;
+}
+
+static __inline u16 IoInputWord(u16 wAds) {
+  u16 _v;
+
+  __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd" (wAds));
+  return _v;
+}
+
+static __inline u32 IoInputDword(u16 wAds) {
+  u32 _v;
+
+  __asm__ __volatile__ ("inl %w1,%0":"=a" (_v):"Nd" (wAds));
+  return _v;
+}
+
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+                           : "=a" (val1), "=d" (val2) \
+                           : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+                         : /* no outputs */ \
+                         : "c" (msr), "a" (val1), "d" (val2))
+
+
+void BootPciInterruptEnable(void);
+
+       // boot process
+int BootPerformPicChallengeResponseAction(void);
+       // LED control (see associated enum above)
+int I2cSetFrontpanelLed(u8 b);
+
+#define bprintf(...)
+
+#if PRINT_TRACE
+#define TRACE bprintf(__FILE__ " :%d\n\r",__LINE__);
+#else
+#define TRACE
+#endif
+
+typedef struct _LIST_ENTRY {
+       struct _LIST_ENTRY *m_plistentryNext;
+       struct _LIST_ENTRY *m_plistentryPrevious;
+} LIST_ENTRY;
+
+void ListEntryInsertAfterCurrent(LIST_ENTRY *plistentryCurrent, LIST_ENTRY *plistentryNew);
+void ListEntryRemove(LIST_ENTRY *plistentryCurrent);
+
+////////// BootPerformXCodeActions.c
+
+int BootPerformXCodeActions(void);
+
+#include "BootEEPROM.h"
+#include "BootParser.h"
+
+////////// BootStartBios.c
+
+void StartBios(CONFIGENTRY *config,int nActivePartition, int nFATXPresent,int bootfrom);
+int BootMenu(CONFIGENTRY *config,int nDrive,int nActivePartition, int nFATXPresent);
+
+////////// BootResetActions.c
+void ClearIDT (void);
+void BootResetAction(void);
+void BootCpuCache(bool fEnable) ;
+int printk(const char *szFormat, ...);
+void BiosCmosWrite(u8 bAds, u8 bData);
+u8 BiosCmosRead(u8 bAds);
+
+
+///////// BootPciPeripheralInitialization.c
+void BootPciPeripheralInitialization(void);
+void BootAGPBUSInitialization(void);
+void BootDetectMemorySize(void);
+extern void    ReadPCIByte(unsigned int bus, unsigned int dev, unsigned intfunc,       unsigned int reg_off, unsigned char *pbyteval);
+extern void    WritePCIByte(unsigned int bus, unsigned int dev, unsigned int func,     unsigned int reg_off, unsigned char byteval);
+extern void    ReadPCIDword(unsigned int bus, unsigned int dev, unsigned int func,     unsigned int reg_off, unsigned int *pdwordval);
+extern void    WritePCIDword(unsigned int bus, unsigned int dev, unsigned int func,            unsigned int reg_off, unsigned int dwordval);
+extern void    ReadPCIBlock(unsigned int bus, unsigned int dev, unsigned int func,             unsigned int reg_off, unsigned char *buf,       unsigned int nbytes);
+extern void    WritePCIBlock(unsigned int bus, unsigned int dev, unsigned int func,    unsigned int reg_off, unsigned char *buf, unsigned int nbytes);
+
+void PciWriteByte (unsigned int bus, unsigned int dev, unsigned int func,
+               unsigned int reg_off, unsigned char byteval);
+u8 PciReadByte(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off);
+u32 PciWriteDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, u32 dw);
+u32 PciReadDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off);
+
+///////// BootPerformPicChallengeResponseAction.c
+
+int I2CTransmitWord(u8 bPicAddressI2cFormat, u16 wDataToWrite);
+int I2CTransmitByteGetReturn(u8 bPicAddressI2cFormat, u8 bDataToWrite);
+bool I2CGetTemperature(int *, int *);
+void I2CModifyBits(u8 bAds, u8 bReg, u8 bData, u8 bMask);
+
+///////// BootIde.c
+
+extern tsHarddiskInfo tsaHarddiskInfo[];  // static struct stores data about attached drives
+int BootIdeInit(void);
+int BootIdeReadSector(int nDriveIndex, void * pbBuffer, unsigned int block, int byte_offset, int n_bytes);
+int BootIdeBootSectorHddOrElTorito(int nDriveIndex, u8 * pbaResult);
+int BootIdeAtapiAdditionalSenseCode(int nDrive, u8 * pba, int nLengthMaxReturn);
+int BootIdeSetTransferMode(int nIndexDrive, int nMode);
+int BootIdeWaitNotBusy(unsigned uIoBase);
+bool BootIdeAtapiReportFriendlyError(int nDriveIndex, char * szErrorReturn, int nMaxLengthError);
+void BootIdeAtapiPrintkFriendlyError(int nDriveIndex);
+
+///////// BootUSB.c
+
+void BootStopUSB(void);
+void BootStartUSB(void);
+void USBGetEvents(void);
+
+#include "xpad.h"
+
+extern struct xpad_data XPAD_current[4];
+extern struct xpad_data XPAD_last[4];
+
+extern void wait_ms(u32 ticks);
+extern void wait_us(u32 ticks);
+extern void wait_smalldelay(void);
+
+
+void * memcpy(void *dest, const void *src,  size_t size);
+void * memset(void *dest, int data,  size_t size);
+int memcmp(const void *buffer1, const void *buffer2, size_t num);
+int _strncmp(const char *sz1, const char *sz2, int nMax);
+char * strcpy(char *sz, const char *szc);
+char * _strncpy (char * dest, const char * src, size_t n);
+void chrreplace(char *string, char search, char ch);
+
+#define printf printk
+#define sleep wait_ms
+int tolower(int ch);
+int isspace (int c);
+
+void MemoryManagementInitialization(void * pvStartAddress, u32 dwTotalMemoryAllocLength);
+void * malloc(size_t size);
+void free(void *);
+
+extern volatile int nCountI2cinterrupts, nCountUnusedInterrupts, nCountUnusedInterruptsPic2, nCountInterruptsSmc, nCountInterruptsIde;
+extern volatile bool fSeenPowerdown;
+typedef enum {
+       ETS_OPEN_OR_OPENING=0,
+       ETS_CLOSING,
+       ETS_CLOSED
+} TRAY_STATE;
+extern volatile TRAY_STATE traystate;
+
+
+extern void BootInterruptsWriteIdt(void);
+#endif
+int copy_swap_trim(unsigned char *dst, unsigned char *src, int len);
+void HMAC_SHA1( unsigned char *result,
+                unsigned char *key, int key_length,
+                unsigned char *text1, int text1_length,
+                unsigned char *text2, int text2_length );
+
+char *strrchr0(char *string, char ch);
+
+#endif // _Boot_H_
index 755bf6a..d3fb6ce 100644 (file)
@@ -1,70 +1,70 @@
-#ifndef _Consts_H_\r
-#define _Consts_H_\r
-\r
-/*\r
- *\r
- * includes for startup code in a form usable by the .S files\r
- *\r
- */\r
-\r
-  /***************************************************************************\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- ***************************************************************************/\r
-\r
-#define PCI_CFG_ADDR 0x0CF8\r
-#define PCI_CFG_DATA 0x0CFC\r
-\r
-\r
-#define I2C_IO_BASE 0xc000\r
-\r
-#define BUS_0 0\r
-#define BUS_1 1\r
-\r
-#define DEV_0 0\r
-#define DEV_1 1\r
-#define DEV_2 2\r
-#define DEV_3 3\r
-#define DEV_4 4\r
-#define DEV_5 5\r
-#define DEV_6 6\r
-#define DEV_7 7\r
-#define DEV_8 8\r
-#define DEV_9 9\r
-#define DEV_a 0xa\r
-#define DEV_b 0xb\r
-#define DEV_c 0xc\r
-#define DEV_d 0xd\r
-#define DEV_e 0xe\r
-#define DEV_f 0xf\r
-#define DEV_10 0x10\r
-#define DEV_11 0x11\r
-#define DEV_12 0x12\r
-#define DEV_13 0x13\r
-#define DEV_14 0x14\r
-#define DEV_15 0x15\r
-#define DEV_16 0x16\r
-#define DEV_17 0x17\r
-#define DEV_18 0x18\r
-#define DEV_19 0x19\r
-#define DEV_1a 0x1a\r
-#define DEV_1b 0x1b\r
-#define DEV_1c 0x1c\r
-#define DEV_1d 0x1d\r
-#define DEV_1e 0x1e\r
-#define DEV_1f 0x1f\r
-\r
-#define FUNC_0 0\r
-/*\r
-#define boot_post_macro(value)                     \\r
-               movb    $(value), %al                           ;\\r
-               outb    %al, $0x80 \r
-*/\r
-\r
-#endif // _Consts_H_\r
-\r
-\r
+#ifndef _Consts_H_
+#define _Consts_H_
+
+/*
+ *
+ * includes for startup code in a form usable by the .S files
+ *
+ */
+
+  /***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#define PCI_CFG_ADDR 0x0CF8
+#define PCI_CFG_DATA 0x0CFC
+
+
+#define I2C_IO_BASE 0xc000
+
+#define BUS_0 0
+#define BUS_1 1
+
+#define DEV_0 0
+#define DEV_1 1
+#define DEV_2 2
+#define DEV_3 3
+#define DEV_4 4
+#define DEV_5 5
+#define DEV_6 6
+#define DEV_7 7
+#define DEV_8 8
+#define DEV_9 9
+#define DEV_a 0xa
+#define DEV_b 0xb
+#define DEV_c 0xc
+#define DEV_d 0xd
+#define DEV_e 0xe
+#define DEV_f 0xf
+#define DEV_10 0x10
+#define DEV_11 0x11
+#define DEV_12 0x12
+#define DEV_13 0x13
+#define DEV_14 0x14
+#define DEV_15 0x15
+#define DEV_16 0x16
+#define DEV_17 0x17
+#define DEV_18 0x18
+#define DEV_19 0x19
+#define DEV_1a 0x1a
+#define DEV_1b 0x1b
+#define DEV_1c 0x1c
+#define DEV_1d 0x1d
+#define DEV_1e 0x1e
+#define DEV_1f 0x1f
+
+#define FUNC_0 0
+/*
+#define boot_post_macro(value)                     \
+               movb    $(value), %al                           ;\
+               outb    %al, $0x80 
+*/
+
+#endif // _Consts_H_
+
+
index d03e915..cccc05c 100644 (file)
@@ -1,27 +1,27 @@
-#ifndef cromwell_types_h\r
-#define cromwell_types_h\r
-\r
-/////////////////////////////////\r
-// some typedefs to make for easy sizing\r
-\r
-//typedef unsigned long ULONG;\r
-typedef unsigned int u32;\r
-typedef unsigned short u16;\r
-typedef unsigned char u8;\r
-#ifndef bool_already_defined_\r
-       typedef int bool;\r
-#endif\r
-typedef unsigned long RGBA; // LSB=R -> MSB = A\r
-//typedef long long __int64;\r
-\r
-#define guint int\r
-#define guint8 unsigned char\r
-\r
-#define true 1\r
-#define false 0\r
-\r
-#ifndef NULL\r
-#define NULL ((void *)0)\r
-#endif\r
-\r
-#endif /* #ifndef cromwell_types_h */\r
+#ifndef cromwell_types_h
+#define cromwell_types_h
+
+/////////////////////////////////
+// some typedefs to make for easy sizing
+
+//typedef unsigned long ULONG;
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+#ifndef bool_already_defined_
+       typedef int bool;
+#endif
+typedef unsigned long RGBA; // LSB=R -> MSB = A
+//typedef long long __int64;
+
+#define guint int
+#define guint8 unsigned char
+
+#define true 1
+#define false 0
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#endif /* #ifndef cromwell_types_h */
index dcd2ede..1b66789 100644 (file)
-#ifndef _I386_ERRNO_H\r
-#define _I386_ERRNO_H\r
-\r
-#define        EPERM            1      /* Operation not permitted */\r
-#define        ENOENT           2      /* No such file or directory */\r
-#define        ESRCH            3      /* No such process */\r
-#define        EINTR            4      /* Interrupted system call */\r
-#define        EIO              5      /* I/O error */\r
-#define        ENXIO            6      /* No such device or address */\r
-#define        E2BIG            7      /* Argument list too long */\r
-#define        ENOEXEC          8      /* Exec format error */\r
-#define        EBADF            9      /* Bad file number */\r
-#define        ECHILD          10      /* No child processes */\r
-#define        EAGAIN          11      /* Try again */\r
-#define        ENOMEM          12      /* Out of memory */\r
-#define        EACCES          13      /* Permission denied */\r
-#define        EFAULT          14      /* Bad address */\r
-#define        ENOTBLK         15      /* Block device required */\r
-#define        EBUSY           16      /* Device or resource busy */\r
-#define        EEXIST          17      /* File exists */\r
-#define        EXDEV           18      /* Cross-device link */\r
-#define        ENODEV          19      /* No such device */\r
-#define        ENOTDIR         20      /* Not a directory */\r
-#define        EISDIR          21      /* Is a directory */\r
-#define        EINVAL          22      /* Invalid argument */\r
-#define        ENFILE          23      /* File table overflow */\r
-#define        EMFILE          24      /* Too many open files */\r
-#define        ENOTTY          25      /* Not a typewriter */\r
-#define        ETXTBSY         26      /* Text file busy */\r
-#define        EFBIG           27      /* File too large */\r
-#define        ENOSPC          28      /* No space left on device */\r
-#define        ESPIPE          29      /* Illegal seek */\r
-#define        EROFS           30      /* Read-only file system */\r
-#define        EMLINK          31      /* Too many links */\r
-#define        EPIPE           32      /* Broken pipe */\r
-#define        EDOM            33      /* Math argument out of domain of func */\r
-#define        ERANGE          34      /* Math result not representable */\r
-#define        EDEADLK         35      /* Resource deadlock would occur */\r
-#define        ENAMETOOLONG    36      /* File name too long */\r
-#define        ENOLCK          37      /* No record locks available */\r
-#define        ENOSYS          38      /* Function not implemented */\r
-#define        ENOTEMPTY       39      /* Directory not empty */\r
-#define        ELOOP           40      /* Too many symbolic links encountered */\r
-#define        EWOULDBLOCK     EAGAIN  /* Operation would block */\r
-#define        ENOMSG          42      /* No message of desired type */\r
-#define        EIDRM           43      /* Identifier removed */\r
-#define        ECHRNG          44      /* Channel number out of range */\r
-#define        EL2NSYNC        45      /* Level 2 not synchronized */\r
-#define        EL3HLT          46      /* Level 3 halted */\r
-#define        EL3RST          47      /* Level 3 reset */\r
-#define        ELNRNG          48      /* Link number out of range */\r
-#define        EUNATCH         49      /* Protocol driver not attached */\r
-#define        ENOCSI          50      /* No CSI structure available */\r
-#define        EL2HLT          51      /* Level 2 halted */\r
-#define        EBADE           52      /* Invalid exchange */\r
-#define        EBADR           53      /* Invalid request descriptor */\r
-#define        EXFULL          54      /* Exchange full */\r
-#define        ENOANO          55      /* No anode */\r
-#define        EBADRQC         56      /* Invalid request code */\r
-#define        EBADSLT         57      /* Invalid slot */\r
-\r
-#define        EDEADLOCK       EDEADLK\r
-\r
-#define        EBFONT          59      /* Bad font file format */\r
-#define        ENOSTR          60      /* Device not a stream */\r
-#define        ENODATA         61      /* No data available */\r
-#define        ETIME           62      /* Timer expired */\r
-#define        ENOSR           63      /* Out of streams resources */\r
-#define        ENONET          64      /* Machine is not on the network */\r
-#define        ENOPKG          65      /* Package not installed */\r
-#define        EREMOTE         66      /* Object is remote */\r
-#define        ENOLINK         67      /* Link has been severed */\r
-#define        EADV            68      /* Advertise error */\r
-#define        ESRMNT          69      /* Srmount error */\r
-#define        ECOMM           70      /* Communication error on send */\r
-#define        EPROTO          71      /* Protocol error */\r
-#define        EMULTIHOP       72      /* Multihop attempted */\r
-#define        EDOTDOT         73      /* RFS specific error */\r
-#define        EBADMSG         74      /* Not a data message */\r
-#define        EOVERFLOW       75      /* Value too large for defined data type */\r
-#define        ENOTUNIQ        76      /* Name not unique on network */\r
-#define        EBADFD          77      /* File descriptor in bad state */\r
-#define        EREMCHG         78      /* Remote address changed */\r
-#define        ELIBACC         79      /* Can not access a needed shared library */\r
-#define        ELIBBAD         80      /* Accessing a corrupted shared library */\r
-#define        ELIBSCN         81      /* .lib section in a.out corrupted */\r
-#define        ELIBMAX         82      /* Attempting to link in too many shared libraries */\r
-#define        ELIBEXEC        83      /* Cannot exec a shared library directly */\r
-#define        EILSEQ          84      /* Illegal byte sequence */\r
-#define        ERESTART        85      /* Interrupted system call should be restarted */\r
-#define        ESTRPIPE        86      /* Streams pipe error */\r
-#define        EUSERS          87      /* Too many users */\r
-#define        ENOTSOCK        88      /* Socket operation on non-socket */\r
-#define        EDESTADDRREQ    89      /* Destination address required */\r
-#define        EMSGSIZE        90      /* Message too long */\r
-#define        EPROTOTYPE      91      /* Protocol wrong type for socket */\r
-#define        ENOPROTOOPT     92      /* Protocol not available */\r
-#define        EPROTONOSUPPORT 93      /* Protocol not supported */\r
-#define        ESOCKTNOSUPPORT 94      /* Socket type not supported */\r
-#define        EOPNOTSUPP      95      /* Operation not supported on transport endpoint */\r
-#define        EPFNOSUPPORT    96      /* Protocol family not supported */\r
-#define        EAFNOSUPPORT    97      /* Address family not supported by protocol */\r
-#define        EADDRINUSE      98      /* Address already in use */\r
-#define        EADDRNOTAVAIL   99      /* Cannot assign requested address */\r
-#define        ENETDOWN        100     /* Network is down */\r
-#define        ENETUNREACH     101     /* Network is unreachable */\r
-#define        ENETRESET       102     /* Network dropped connection because of reset */\r
-#define        ECONNABORTED    103     /* Software caused connection abort */\r
-#define        ECONNRESET      104     /* Connection reset by peer */\r
-#define        ENOBUFS         105     /* No buffer space available */\r
-#define        EISCONN         106     /* Transport endpoint is already connected */\r
-#define        ENOTCONN        107     /* Transport endpoint is not connected */\r
-#define        ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */\r
-#define        ETOOMANYREFS    109     /* Too many references: cannot splice */\r
-#define        ETIMEDOUT       110     /* Connection timed out */\r
-#define        ECONNREFUSED    111     /* Connection refused */\r
-#define        EHOSTDOWN       112     /* Host is down */\r
-#define        EHOSTUNREACH    113     /* No route to host */\r
-#define        EALREADY        114     /* Operation already in progress */\r
-#define        EINPROGRESS     115     /* Operation now in progress */\r
-#define        ESTALE          116     /* Stale NFS file handle */\r
-#define        EUCLEAN         117     /* Structure needs cleaning */\r
-#define        ENOTNAM         118     /* Not a XENIX named type file */\r
-#define        ENAVAIL         119     /* No XENIX semaphores available */\r
-#define        EISNAM          120     /* Is a named type file */\r
-#define        EREMOTEIO       121     /* Remote I/O error */\r
-#define        EDQUOT          122     /* Quota exceeded */\r
-\r
-#define        ENOMEDIUM       123     /* No medium found */\r
-#define        EMEDIUMTYPE     124     /* Wrong medium type */\r
-\r
-#endif\r
+#ifndef _I386_ERRNO_H
+#define _I386_ERRNO_H
+
+#define        EPERM            1      /* Operation not permitted */
+#define        ENOENT           2      /* No such file or directory */
+#define        ESRCH            3      /* No such process */
+#define        EINTR            4      /* Interrupted system call */
+#define        EIO              5      /* I/O error */
+#define        ENXIO            6      /* No such device or address */
+#define        E2BIG            7      /* Argument list too long */
+#define        ENOEXEC          8      /* Exec format error */
+#define        EBADF            9      /* Bad file number */
+#define        ECHILD          10      /* No child processes */
+#define        EAGAIN          11      /* Try again */
+#define        ENOMEM          12      /* Out of memory */
+#define        EACCES          13      /* Permission denied */
+#define        EFAULT          14      /* Bad address */
+#define        ENOTBLK         15      /* Block device required */
+#define        EBUSY           16      /* Device or resource busy */
+#define        EEXIST          17      /* File exists */
+#define        EXDEV           18      /* Cross-device link */
+#define        ENODEV          19      /* No such device */
+#define        ENOTDIR         20      /* Not a directory */
+#define        EISDIR          21      /* Is a directory */
+#define        EINVAL          22      /* Invalid argument */
+#define        ENFILE          23      /* File table overflow */
+#define        EMFILE          24      /* Too many open files */
+#define        ENOTTY          25      /* Not a typewriter */
+#define        ETXTBSY         26      /* Text file busy */
+#define        EFBIG           27      /* File too large */
+#define        ENOSPC          28      /* No space left on device */
+#define        ESPIPE          29      /* Illegal seek */
+#define        EROFS           30      /* Read-only file system */
+#define        EMLINK          31      /* Too many links */
+#define        EPIPE           32      /* Broken pipe */
+#define        EDOM            33      /* Math argument out of domain of func */
+#define        ERANGE          34      /* Math result not representable */
+#define        EDEADLK         35      /* Resource deadlock would occur */
+#define        ENAMETOOLONG    36      /* File name too long */
+#define        ENOLCK          37      /* No record locks available */
+#define        ENOSYS          38      /* Function not implemented */
+#define        ENOTEMPTY       39      /* Directory not empty */
+#define        ELOOP           40      /* Too many symbolic links encountered */
+#define        EWOULDBLOCK     EAGAIN  /* Operation would block */
+#define        ENOMSG          42      /* No message of desired type */
+#define        EIDRM           43      /* Identifier removed */
+#define        ECHRNG          44      /* Channel number out of range */
+#define        EL2NSYNC        45      /* Level 2 not synchronized */
+#define        EL3HLT          46      /* Level 3 halted */
+#define        EL3RST          47      /* Level 3 reset */
+#define        ELNRNG          48      /* Link number out of range */
+#define        EUNATCH         49      /* Protocol driver not attached */
+#define        ENOCSI          50      /* No CSI structure available */
+#define        EL2HLT          51      /* Level 2 halted */
+#define        EBADE           52      /* Invalid exchange */
+#define        EBADR           53      /* Invalid request descriptor */
+#define        EXFULL          54      /* Exchange full */
+#define        ENOANO          55      /* No anode */
+#define        EBADRQC         56      /* Invalid request code */
+#define        EBADSLT         57      /* Invalid slot */
+
+#define        EDEADLOCK       EDEADLK
+
+#define        EBFONT          59      /* Bad font file format */
+#define        ENOSTR          60      /* Device not a stream */
+#define        ENODATA         61      /* No data available */
+#define        ETIME           62      /* Timer expired */
+#define        ENOSR           63      /* Out of streams resources */
+#define        ENONET          64      /* Machine is not on the network */
+#define        ENOPKG          65      /* Package not installed */
+#define        EREMOTE         66      /* Object is remote */
+#define        ENOLINK         67      /* Link has been severed */
+#define        EADV            68      /* Advertise error */
+#define        ESRMNT          69      /* Srmount error */
+#define        ECOMM           70      /* Communication error on send */
+#define        EPROTO          71      /* Protocol error */
+#define        EMULTIHOP       72      /* Multihop attempted */
+#define        EDOTDOT         73      /* RFS specific error */
+#define        EBADMSG         74      /* Not a data message */
+#define        EOVERFLOW       75      /* Value too large for defined data type */
+#define        ENOTUNIQ        76      /* Name not unique on network */
+#define        EBADFD          77      /* File descriptor in bad state */
+#define        EREMCHG         78      /* Remote address changed */
+#define        ELIBACC         79      /* Can not access a needed shared library */
+#define        ELIBBAD         80      /* Accessing a corrupted shared library */
+#define        ELIBSCN         81      /* .lib section in a.out corrupted */
+#define        ELIBMAX         82      /* Attempting to link in too many shared libraries */
+#define        ELIBEXEC        83      /* Cannot exec a shared library directly */
+#define        EILSEQ          84      /* Illegal byte sequence */
+#define        ERESTART        85      /* Interrupted system call should be restarted */
+#define        ESTRPIPE        86      /* Streams pipe error */
+#define        EUSERS          87      /* Too many users */
+#define        ENOTSOCK        88      /* Socket operation on non-socket */
+#define        EDESTADDRREQ    89      /* Destination address required */
+#define        EMSGSIZE        90      /* Message too long */
+#define        EPROTOTYPE      91      /* Protocol wrong type for socket */
+#define        ENOPROTOOPT     92      /* Protocol not available */
+#define        EPROTONOSUPPORT 93      /* Protocol not supported */
+#define        ESOCKTNOSUPPORT 94      /* Socket type not supported */
+#define        EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
+#define        EPFNOSUPPORT    96      /* Protocol family not supported */
+#define        EAFNOSUPPORT    97      /* Address family not supported by protocol */
+#define        EADDRINUSE      98      /* Address already in use */
+#define        EADDRNOTAVAIL   99      /* Cannot assign requested address */
+#define        ENETDOWN        100     /* Network is down */
+#define        ENETUNREACH     101     /* Network is unreachable */
+#define        ENETRESET       102     /* Network dropped connection because of reset */
+#define        ECONNABORTED    103     /* Software caused connection abort */
+#define        ECONNRESET      104     /* Connection reset by peer */
+#define        ENOBUFS         105     /* No buffer space available */
+#define        EISCONN         106     /* Transport endpoint is already connected */
+#define        ENOTCONN        107     /* Transport endpoint is not connected */
+#define        ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
+#define        ETOOMANYREFS    109     /* Too many references: cannot splice */
+#define        ETIMEDOUT       110     /* Connection timed out */
+#define        ECONNREFUSED    111     /* Connection refused */
+#define        EHOSTDOWN       112     /* Host is down */
+#define        EHOSTUNREACH    113     /* No route to host */
+#define        EALREADY        114     /* Operation already in progress */
+#define        EINPROGRESS     115     /* Operation now in progress */
+#define        ESTALE          116     /* Stale NFS file handle */
+#define        EUCLEAN         117     /* Structure needs cleaning */
+#define        ENOTNAM         118     /* Not a XENIX named type file */
+#define        ENAVAIL         119     /* No XENIX semaphores available */
+#define        EISNAM          120     /* Is a named type file */
+#define        EREMOTEIO       121     /* Remote I/O error */
+#define        EDQUOT          122     /* Quota exceeded */
+
+#define        ENOMEDIUM       123     /* No medium found */
+#define        EMEDIUMTYPE     124     /* Wrong medium type */
+
+#endif
index 0c759ef..dd79888 100644 (file)
-/*\r
- * linux-wrapper.h\r
- *\r
- * Hard coded Linux kernel replacements for x86\r
- *\r
- * (c) 2003 Georg Acher (georg@acher.org)\r
- *\r
- * Emulation of:\r
- * typedefs\r
- * structs\r
- * macros\r
- *\r
- * All structs and prototypes are based on kernel source 2.5.72\r
- *\r
- * Modified by Aleksey Bragin (aleksey@reactos.com) for ReactOS needs\r
- *\r
- *\r
- * #include <standard-GPL-header.h>\r
- */\r
-\r
-/*------------------------------------------------------------------------*/\r
-/* Typedefs */\r
-/*------------------------------------------------------------------------*/ \r
-#include "cromwell_types.h"\r
-\r
-typedef unsigned int __u32;\r
-//typedef __u32 u32;\r
-typedef unsigned short __u16;\r
-//typedef __u16 u16;\r
-typedef unsigned char __u8;\r
-//typedef __u8 u8;\r
-\r
-typedef short s16;\r
-\r
-typedef u32 dma_addr_t;\r
-\r
-typedef  int spinlock_t;\r
-typedef int atomic_t;\r
-#ifndef STANDALONE\r
-typedef int mode_t;\r
-typedef int pid_t;\r
-typedef int ssize_t;\r
-\r
-#endif\r
-typedef int irqreturn_t;\r
-typedef unsigned long kernel_ulong_t;\r
-\r
-typedef int wait_queue_head_t;\r
-/*------------------------------------------------------------------------*/ \r
-/* Stuff from xbox/linux environment */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#include "list.h"\r
-\r
-#ifndef STANDALONE\r
-#ifdef MODULE\r
-typedef int size_t;\r
-#define NULL ((void*)0)\r
-extern void * memset(void *,int,unsigned int);\r
-extern void * memcpy(void *,const void *,unsigned int);\r
-#if 0\r
-extern char * strcpy(char *,const char *);\r
-#else\r
-static inline char * strcpy(char * dest,const char *src)\r
-{\r
-int d0, d1, d2;\r
-__asm__ __volatile__(\r
-        "1:\tlodsb\n\t"\r
-        "stosb\n\t"\r
-        "testb %%al,%%al\n\t"\r
-        "jne 1b"\r
-        : "=&S" (d0), "=&D" (d1), "=&a" (d2)\r
-        :"0" (src),"1" (dest) : "memory");\r
-return dest;\r
-}\r
-#endif\r
-extern size_t strlen(const char *);\r
-\r
-extern int memcmp(const void *,const void *,unsigned int);\r
-\r
-#else\r
-#include "boot.h"\r
-#include "config.h"\r
-#endif\r
-#else\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include "consts.h"\r
-#include <string.h>\r
-#endif\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* General structs */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-struct timer_list { \r
-       void (*function)(unsigned long);\r
-       unsigned long data;\r
-       int expires;\r
-       struct list_head timer_list;\r
-};\r
-\r
-struct work_struct {\r
-       void (*func)(void *);\r
-};\r
-struct device {\r
-       char name[128];\r
-       struct bus_type *bus;\r
-       int dma_mask;\r
-       char    bus_id[16];\r
-       struct device_driver* driver;\r
-       void            *driver_data;\r
-       struct device *parent;\r
-       struct list_head driver_list;\r
-       void    (*release)(struct device * dev);\r
-};\r
-struct class_device{int a;};\r
-struct semaphore{int a;};\r
-\r
-struct device_driver{\r
-       char *name;\r
-       struct bus_type *bus;\r
-       int     (*probe)        (struct device * dev);\r
-        int     (*remove)       (struct device * dev);\r
-       struct list_head        devices;\r
-};\r
-\r
-struct bus_type {\r
-        char                    * name;       \r
-        int             (*match)(struct device * dev, struct device_driver * drv);\r
-        struct device * (*add)  (struct device * parent, char * bus_id);\r
-        int             (*hotplug) (struct device *dev, char **envp, \r
-                                    int num_envp, char *buffer, int buffer_size);\r
-};\r
-\r
-struct dummy_process\r
-{\r
-       int flags;\r
-};\r
-\r
-struct pt_regs\r
-{\r
-       int a;\r
-};\r
-struct completion {\r
-        unsigned int done;\r
-        wait_queue_head_t wait;\r
-};\r
-\r
-// windows lookaside list head\r
-typedef void* kmem_cache_t;\r
-\r
-struct dma_pool\r
-{\r
-       int dummy;\r
-};\r
-\r
-/* from mod_devicetable.h */\r
-\r
-struct usb_device_id {\r
-        /* which fields to match against? */\r
-        __u16           match_flags;\r
-\r
-        /* Used for product specific matches; range is inclusive */\r
-        __u16           idVendor;\r
-        __u16           idProduct;\r
-        __u16           bcdDevice_lo;\r
-        __u16           bcdDevice_hi;\r
-\r
-        /* Used for device class matches */\r
-        __u8            bDeviceClass;\r
-        __u8            bDeviceSubClass;\r
-        __u8            bDeviceProtocol;\r
-\r
-        /* Used for interface class matches */\r
-        __u8            bInterfaceClass;\r
-        __u8            bInterfaceSubClass;\r
-        __u8            bInterfaceProtocol;\r
-\r
-        /* not matched against */\r
-        kernel_ulong_t  driver_info;\r
-};\r
-\r
-/* Some useful macros to use to create struct usb_device_id */\r
-#define USB_DEVICE_ID_MATCH_VENDOR              0x0001\r
-#define USB_DEVICE_ID_MATCH_PRODUCT             0x0002\r
-#define USB_DEVICE_ID_MATCH_DEV_LO              0x0004\r
-#define USB_DEVICE_ID_MATCH_DEV_HI              0x0008\r
-#define USB_DEVICE_ID_MATCH_DEV_CLASS           0x0010\r
-#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS        0x0020\r
-#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL        0x0040\r
-#define USB_DEVICE_ID_MATCH_INT_CLASS           0x0080\r
-#define USB_DEVICE_ID_MATCH_INT_SUBCLASS        0x0100\r
-#define USB_DEVICE_ID_MATCH_INT_PROTOCOL        0x0200\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* imported functions from top-level */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-//void zxprintf(char* fmt, ...);\r
-//void zxsprintf(char *buffer, char* fmt, ...);\r
-//int zxsnprintf(char *buffer, size_t s, char* fmt, ...);\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* PCI structs (taken from linux/pci.h et al., but slightly modified) */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-struct pci_dev {\r
-       int vendor;\r
-       int device;\r
-       struct pci_bus  *bus;\r
-       int irq;\r
-       char *slot_name;\r
-       struct device dev;\r
-       int base[4];\r
-       int flags[4];\r
-       void * data;\r
-       void * dev_ext; // link to Windows DeviceExtension\r
-};\r
-\r
-struct pci_bus {\r
-       unsigned char   number;\r
-};\r
-\r
-struct pci_device_id {\r
-        __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/\r
-        __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */\r
-        __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */\r
-        kernel_ulong_t driver_data;     /* Data private to the driver */\r
-};\r
-\r
-struct pci_driver {\r
-        struct list_head node;\r
-        char *name;\r
-        const struct pci_device_id *id_table;   /* must be non-NULL for probe to be called */\r
-        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New device inserted */\r
-        void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug capable driver) */\r
-        int  (*save_state) (struct pci_dev *dev, u32 state);    /* Save Device Context */\r
-        int  (*suspend) (struct pci_dev *dev, u32 state);       /* Device suspended */\r
-        int  (*resume) (struct pci_dev *dev);                   /* Device woken up */\r
-        int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */\r
-};\r
-\r
-struct scatterlist\r
-{\r
-       int page;\r
-       int offset;\r
-       int length;\r
-};\r
-\r
-struct usbdevfs_hub_portinfo\r
-{\r
-       int nports;\r
-       int port[8];\r
-};\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* constant defines */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define TASK_UNINTERRUPTIBLE 0\r
-#define HZ 100    /* Don't rely on that... */\r
-#define KERN_DEBUG "DBG: "\r
-#define KERN_ERR "ERR: "\r
-#define KERN_WARNING "WRN: "\r
-#define KERN_INFO "INF: "\r
-#define GFP_KERNEL 0\r
-#define GFP_ATOMIC 0x20\r
-#define GFP_NOIO 0\r
-#define SLAB_ATOMIC 0\r
-#define PCI_ANY_ID (~0)\r
-#define SIGKILL 9\r
-#define THIS_MODULE 0\r
-//#define PAGE_SIZE 4096\r
-\r
-\r
-#define CLONE_FS 0\r
-#define CLONE_FILES 0\r
-#define CLONE_SIGHAND 0\r
-#define PF_FREEZE 0\r
-#define PF_IOTHREAD 0\r
-\r
-\r
-#define USBDEVFS_HUB_PORTINFO 1234\r
-#define SA_SHIRQ 0\r
-\r
-#undef PCI_COMMAND\r
-#define PCI_COMMAND 0\r
-#undef PCI_COMMAND_MASTER\r
-#define PCI_COMMAND_MASTER 0\r
-/*------------------------------------------------------------------------*/ \r
-/* Module/export macros */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define MODULE_AUTHOR(a)\r
-#define MODULE_DESCRIPTION(a)\r
-#define MODULE_LICENSE(a)\r
-#define MODULE_DEVICE_TABLE(type,name) void* module_table_##name=&name\r
-#define MODULE_PARM(a,b)\r
-#define MODULE_PARM_DESC(a,b)\r
-\r
-#define __devinit\r
-#define __exit\r
-#define __init\r
-#define __devinitdata\r
-#define module_init(x) static void module_init_##x(void){ x();}\r
-#define module_exit(x) void module_exit_##x(void){ x();}\r
-#define EXPORT_SYMBOL_GPL(x)\r
-#define EXPORT_SYMBOL(x)\r
-\r
-#define __setup(x,y) int setup_##y=(int)y\r
-#define subsys_initcall(x) void subsys_##x(void){x();}\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Access macros */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define dev_get_drvdata(a) (a)->driver_data\r
-#define dev_set_drvdata(a,b) (a)->driver_data=(b)\r
-\r
-#define __io_virt(x) ((void *)(x))\r
-#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))\r
-#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))\r
-#define likely(x) (x)\r
-#define unlikely(x) (x)\r
-#define prefetch(x) 1\r
-\r
-#define inw(x) READ_PORT_USHORT((PUSHORT)(x))\r
-#define outw(x,p) WRITE_PORT_USHORT((PUSHORT)(p),(x))\r
-#define outl(x,p) WRITE_PORT_ULONG((PUSHORT)(p),(x))\r
-\r
-/* The kernel macro for list_for_each_entry makes nonsense (have no clue\r
- * why, this is just the same definition...) */\r
-\r
-#undef list_for_each_entry\r
-#define list_for_each_entry(pos, head, member)                          \\r
-        for (pos = list_entry((head)->next, typeof(*pos), member),      \\r
-                     prefetch(pos->member.next);                        \\r
-             &pos->member != (head);                                    \\r
-             pos = list_entry(pos->member.next, typeof(*pos), member),  \\r
-                     prefetch(pos->member.next))\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* function wrapper macros */\r
-/*------------------------------------------------------------------------*/ \r
-#define kmalloc(x,y) ExAllocatePool(PagedPool,x)\r
-#define kfree(x) ExFreePool(x)\r
-\r
-//#define sprintf(a,b,format, arg...) zxsprintf((a),(b),format, ## arg)\r
-//#define snprintf(a,b,format, arg...) zxsnprintf((a),(b),format, ##arg)\r
-//#define printk(format, arg...) zxprintf(format, ## arg)\r
-#define snprintf(a,b,format, arg...) _snprintf((a),(b),format, ##arg)\r
-#define printk(format, arg...) DPRINT1(format, ## arg)\r
-#define BUG(...) do {} while(0)\r
-\r
-/* Locks & friends */\r
-\r
-#define DECLARE_MUTEX(x) struct semaphore x\r
-#define init_MUTEX(x)\r
-\r
-#define SPIN_LOCK_UNLOCKED 0\r
-#define spin_lock_init(a)  do {} while(0)\r
-#define spin_lock(a) *(int*)a=1\r
-#define spin_unlock(a) do {} while(0)\r
-\r
-#define spin_lock_irqsave(a,b) b=0\r
-#define spin_unlock_irqrestore(a,b)\r
-\r
-#if 0\r
-#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")\r
-#define local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")\r
-#else\r
-#define local_irq_save(x) do {} while(0) \r
-#define local_irq_restore(x) do {} while(0) \r
-#endif\r
-\r
-#define atomic_inc(x) *(x)+=1\r
-#define atomic_dec(x) *(x)-=1\r
-#define atomic_dec_and_test(x) (*(x)-=1,(*(x))==0)\r
-#define atomic_set(x,a) *(x)=a\r
-#define atomic_read(x) *(x)\r
-#define ATOMIC_INIT(x) (x)\r
-\r
-#define down(x) do {} while(0) \r
-#define up(x) do {} while(0)\r
-#define down_trylock(a) 0\r
-\r
-#define down_read(a) do {} while(0)\r
-#define up_read(a) do {} while(0)\r
-\r
-#define DECLARE_WAIT_QUEUE_HEAD(x) KEVENT x\r
-\r
-#define DECLARE_COMPLETION(x) struct completion x\r
-\r
-/* driver */\r
-\r
-#define driver_unregister(a)    do {} while(0)\r
-#define put_device(a)           do {} while(0)\r
-\r
-\r
-/* PCI */\r
-#define        to_pci_dev(n) container_of(n, struct pci_dev, dev)\r
-\r
-#define pci_pool_create(a,b,c,d,e) (void*)1\r
-\r
-#define pci_pool_alloc(a,b,c)  my_pci_pool_alloc(a,b,c) \r
-\r
-static void __inline__ *my_pci_pool_alloc(void* pool, size_t size,\r
-                                               dma_addr_t *dma_handle)\r
-{\r
-       void* a;\r
-       a=kmalloc(size,0); //FIXME\r
-#ifdef MODULE\r
-       *dma_handle=((u32)a)&0xfffffff;\r
-#else\r
-       *dma_handle=(u32)a;\r
-#endif\r
-       return a;\r
-}\r
-\r
-\r
-#define pci_pool_free(a,b,c)    kfree(b)\r
-#define pci_alloc_consistent(a,b,c) my_pci_alloc_consistent(a,b,c)\r
-\r
-static void  __inline__ *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size,\r
-                                               dma_addr_t *dma_handle)\r
-{\r
-       void* a;\r
-\r
-       a=kmalloc(size+256,0); //FIXME\r
-       a=(void*)(((int)a+255)&~255); // 256 alignment\r
-       *dma_handle=((u32)a)&0xfffffff;\r
-\r
-       return a;\r
-}\r
-\r
-#define pci_free_consistent(a,b,c,d)  kfree(c)\r
-#define pci_pool_destroy(a)           do {} while(0)\r
-\r
-#define pci_module_init(x) my_pci_module_init(x)\r
-int my_pci_module_init(struct pci_driver *x);\r
-\r
-#define pci_unregister_driver(a)      do {} while(0)  \r
-\r
-#define pci_write_config_word(a,b,c) my_pci_write_config_word(a,b,c)\r
-\r
-#define bus_register(a) do {} while(0)\r
-#define bus_unregister(a) do {} while(0)\r
-\r
-/* DMA */\r
-//#define dma_pool_alloc(a,b,c) my_dma_pool_alloc((a),(b),(c))\r
-#define dma_pool_alloc(a,b,c) pci_pool_alloc(a,b,c)\r
-#define dma_pool_create(a,b,c,d,e) pci_pool_create(a,b,c,d,e)\r
-#define dma_pool_free(a,b,c) pci_pool_free(a,b,c)\r
-#define dma_pool_destroy(a) pci_pool_destroy(a)\r
-\r
-#define dma_alloc_coherent(a,b,c,d) NULL\r
-#define dma_free_coherent(a,b,c,d) do {} while(0)\r
-\r
-#define dma_map_single(a,b,c,d) ((u32)(b)&0xfffffff)\r
-#define dma_unmap_single(a,b,c,d)     do {} while(0)\r
-#define pci_unmap_single(a,b,c,d)     do {} while(0)\r
-#define dma_sync_single(a,b,c,d)      do {} while(0)\r
-#define dma_sync_sg(a,b,c,d)          do {} while(0)\r
-#define dma_map_sg(a,b,c,d)           0\r
-#define dma_unmap_sg(a,b,c,d)         do {} while(0)\r
-\r
-#define usb_create_driverfs_dev_files(a) do {} while(0)\r
-#define usb_create_driverfs_intf_files(a) do {} while(0)\r
-#define sg_dma_address(x) ((u32)((x)->page*4096 + (x)->offset))\r
-#define sg_dma_len(x) ((x)->length) \r
-\r
-#define page_address(x) ((void*)(x/4096))\r
-\r
-#define DMA_TO_DEVICE 0\r
-#define DMA_FROM_DEVICE 0\r
-#define PCI_DMA_TODEVICE\r
-#define PCI_DMA_FROMDEVICE\r
-#define PCI_DMA_TODEVICE\r
-\r
-#define PCI_ROM_RESOURCE 1\r
-#define IORESOURCE_IO CM_RESOURCE_PORT_IO\r
-\r
-#define DECLARE_WAITQUEUE(a,b) KEVENT a=0\r
-#define init_waitqueue_head(a) my_init_waitqueue_head(a)\r
-#define add_wait_queue(a,b) do {} while(0)\r
-#define remove_wait_queue(a,b) do {} while(0)\r
-void my_init_waitqueue_head(PKEVENT a);\r
-\r
-VOID KeMemoryBarrier(VOID);\r
-\r
-#define mb() KeMemoryBarrier()\r
-#define wmb() __asm__ __volatile__ ("": : :"memory")\r
-#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")\r
-\r
-#define in_interrupt() 0\r
-\r
-#define init_completion(x) (x)->done=0\r
-#define wait_for_completion(x) my_wait_for_completion(x)\r
-void my_wait_for_completion(struct completion*);\r
-\r
-#define IRQ_NONE 0\r
-#define IRQ_HANDLED 1\r
-\r
-#define INIT_WORK(a,b,c) (a)->func=b\r
-\r
-#define set_current_state(a) do {} while(0)\r
-\r
-#define might_sleep()        do {} while(0)\r
-#define daemonize(a)         do {} while(0)\r
-#define allow_signal(a)      do {} while(0)\r
-#define wait_event_interruptible(x,y) do {} while(0)\r
-\r
-#define interruptible_sleep_on(a) my_interruptible_sleep_on(a)\r
-void my_interruptible_sleep_on(PKEVENT evnt);\r
-\r
-#define flush_scheduled_work() do {} while(0)\r
-#define refrigerator(x)        do {} while(0)\r
-#define signal_pending(x)      1  // fall through threads\r
-#define complete_and_exit(a,b) return 0\r
-\r
-//#define kill_proc(a,b,c)     0\r
-#define kill_proc(a,b,c) my_kill_proc(a, b, c);\r
-int my_kill_proc(int pid, int signal, int unk);\r
-\r
-#define yield() do {} while(0)\r
-#define cpu_relax() do {} while(0)\r
-\r
-#define WARN_ON(a) do {} while(0)\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Lookaside lists funcs */\r
-/*------------------------------------------------------------------------*/ \r
-#define kmem_cache_create(a,b,c,d,e,f) my_kmem_cache_create((a),(b),(c),(d),(e),(f))\r
-#define kmem_cache_destroy(a) my_kmem_cache_destroy((a))\r
-#define kmem_cache_alloc(co, flags) my_kmem_cache_alloc((co), (flags))\r
-#define kmem_cache_free(co, ptr) my_kmem_cache_free((co), (ptr))\r
-\r
-kmem_cache_t *my_kmem_cache_create(const char *tag, size_t alloc_size,\r
-                                                                  size_t offset, unsigned long flags,\r
-                                                                  void *ctor,\r
-                                                                  void *dtor);\r
-\r
-BOOLEAN my_kmem_cache_destroy(kmem_cache_t *co);\r
-void *my_kmem_cache_alloc(kmem_cache_t *co, int flags);\r
-void my_kmem_cache_free(kmem_cache_t *co, void *ptr);\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Kernel macros */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define LINUX_VERSION_CODE 0x020572\r
-#define UTS_SYSNAME "XBOX"\r
-#define UTS_RELEASE "----"\r
-\r
-/* from linux/kernel.h */\r
-#define max_t(type,x,y) \\r
-        ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })\r
-\r
-#define min_t(type,x,y) \\r
-        ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })\r
-\r
-#define container_of(ptr, type, member) ({                      \\r
-        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \\r
-        (type *)( (char *)__mptr - offsetof(type,member) );})\r
-\r
-/* from linux/stddef.h */\r
-\r
-#undef offsetof\r
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Conversion macros */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define __constant_cpu_to_le32(x) (x)\r
-#define cpu_to_le16(x) (x)\r
-#define le16_to_cpu(x) (x)\r
-#define cpu_to_le32(x) (x)\r
-#define cpu_to_le32p(x) (*(__u32*)(x))\r
-#define le32_to_cpup(x) (*(__u32*)(x))\r
-#define le32_to_cpu(x) ((u32)x)\r
-#define le16_to_cpus(x) do {} while (0)\r
-#define le16_to_cpup(x) (*(__u16*)(x))\r
-#define cpu_to_le16p(x) (*(__u16*)(x))\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Debug output */\r
-/*------------------------------------------------------------------------*/ \r
-#ifdef DEBUG_MODE\r
-#define dev_printk(lvl,x,f,arg...) printk(f, ## arg)\r
-#define dev_dbg(x,f,arg...) printk(f, ## arg)\r
-#define dev_info(x,f,arg...) printk(f,## arg)\r
-#define dev_warn(x,f,arg...) printk(f,## arg)\r
-#define dev_err(x,f,arg...) printk(f,## arg)\r
-#define pr_debug(x,f,arg...) printk(f,## arg)\r
-#define usbprintk printk\r
-#endif\r
-\r
-#ifndef DEBUG_MODE\r
-#define dev_printk(lvl,x,f,arg...) do {} while (0)\r
-#define dev_dbg(x,f,arg...) do {} while (0) //printk(f, ## arg)\r
-#define dev_info(x,f,arg...) do {} while (0)\r
-#define dev_warn(x,f,arg...) do {} while (0)\r
-#define dev_err(x,f,arg...) do {} while (0)\r
-#define pr_debug(x,f,arg...) do {} while (0)\r
-#define usbprintk\r
-#endif\r
-\r
-\r
-\r
-#define PCI_DEVFN(a,b) 0\r
-#define PCI_SLOT(a) 0\r
-\r
-/**\r
- * PCI_DEVICE_CLASS - macro used to describe a specific pci device class\r
- * @dev_class: the class, subclass, prog-if triple for this device\r
- * @dev_class_mask: the class mask for this device\r
- *\r
- * This macro is used to create a struct pci_device_id that matches a\r
- * specific PCI class.  The vendor, device, subvendor, and subdevice \r
- * fields will be set to PCI_ANY_ID.\r
- */\r
-#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \\r
-       .class = (dev_class), .class_mask = (dev_class_mask), \\r
-       .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \\r
-       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID\r
-\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Stuff from kernel */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#include "errno.h"\r
-#include "bitops.h"\r
-//#include "linux/pci_ids.h"\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* global variables */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define jiffies my_jiffies\r
-extern int my_jiffies;\r
-#define current my_current\r
-extern struct dummy_process *my_current;\r
-\r
-extern struct list_head interrupt_list;\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Function prototypes */\r
-/*------------------------------------------------------------------------*/ \r
-void STDCALL usb_hcd_pci_remove (struct pci_dev *dev);\r
-\r
-#define my_wait_ms(x) wait_ms(x)\r
-\r
-#define my_udelay(x) wait_ms(x)\r
-#define udelay(x) my_udelay(x)\r
-\r
-#define my_mdelay(x) wait_ms(1+x/1000);\r
-#define mdelay(x) my_mdelay(x);\r
-\r
-#define pci_find_slot(a,b) my_pci_find_slot(a,b)\r
-struct pci_dev *my_pci_find_slot(int a,int b);\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Timer management */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define MAX_TIMERS 20\r
-extern struct timer_list *main_timer_list[MAX_TIMERS];\r
-\r
-static void __inline__ init_timer(struct timer_list* t)\r
-{\r
-       INIT_LIST_HEAD(&t->timer_list);\r
-       t->function=NULL;\r
-       t->expires=0;\r
-}\r
-\r
-static void __inline__ add_timer(struct timer_list* t)\r
-{\r
-       int n;\r
-       for(n=0;n<MAX_TIMERS;n++)\r
-               if (main_timer_list[n]==0)\r
-               {\r
-                       main_timer_list[n]=t;\r
-                       break;\r
-               }\r
-}\r
-\r
-static void __inline__ del_timer(struct timer_list* t)\r
-{\r
-       int n;\r
-       for(n=0;n<MAX_TIMERS;n++)\r
-               if (main_timer_list[n]==t)\r
-               {\r
-                       main_timer_list[n]=0;\r
-                       break;\r
-               }\r
-}\r
-static void __inline__ del_timer_sync(struct timer_list* t)\r
-{\r
-       int n;\r
-       for(n=0;n<MAX_TIMERS;n++)\r
-               if (main_timer_list[n]==t)\r
-               {\r
-                       main_timer_list[n]=0;\r
-                       break;\r
-               }\r
-\r
-}\r
-static void __inline__ mod_timer(struct timer_list* t, int ex)\r
-{\r
-       del_timer(t);\r
-       t->expires=ex;\r
-       add_timer(t);\r
-}\r
-\r
-#define time_after_eq(a,b)     \\r
-       (((long)(a) - (long)(b) >= 0))\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Device driver and process related stuff */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-static int __inline__ usb_major_init(void){return 0;}\r
-static void __inline__ usb_major_cleanup(void){}\r
-static void __inline__ schedule_work(void* p){}\r
-\r
-#define device_initialize(x) my_device_initialize(x)\r
-void my_device_initialize(struct device *dev);\r
-\r
-#define get_device(x) my_get_device(x)\r
-struct device *my_get_device(struct device *dev);\r
-\r
-#define device_add(x) my_device_add(x)\r
-int my_device_add(struct device *dev);\r
-\r
-#define driver_register(x) my_driver_register(x)\r
-int my_driver_register(struct device_driver *driver);\r
-\r
-#define device_unregister(a)    my_device_unregister(a)\r
-int my_device_unregister(struct device *dev);\r
-\r
-#define DEVICE_ATTR(a,b,c,d) int xxx_##a\r
-#define device_create_file(a,b)  do {} while(0)\r
-#define device_remove_file(a,b)  do {} while(0)\r
-\r
-#define schedule_timeout(x) my_schedule_timeout(x)\r
-int my_schedule_timeout(int x);\r
-\r
-#define wake_up(x) my_wake_up(x)\r
-void my_wake_up(PKEVENT);\r
-\r
-// cannot be mapped via macro due to collision with urb->complete\r
-static void __inline__ complete(struct completion *p)\r
-{\r
-       /* Wake up x->wait */\r
-       p->done++;\r
-       wake_up(&p->wait);\r
-}\r
-\r
-#define kernel_thread(a,b,c) my_kernel_thread(a,b,c)\r
-int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags);\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* PCI, simple and inlined... */\r
-/*------------------------------------------------------------------------*/ \r
-#include "pci_hal.c"\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* IRQ handling */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-#define request_irq(a,b,c,d,e) my_request_irq(a,b,c,d,e)\r
-int my_request_irq(unsigned int irq,\r
-                       int  (*handler)(int, void *, struct pt_regs *),\r
-               unsigned long mode, const char *desc, void *data);\r
-\r
-#define free_irq(a,b) my_free_irq(a,b)\r
-int free_irq(int irq, void* p);\r
-\r
-\r
-\r
-struct my_irqs {\r
-       int  (*handler)(int, void *, struct pt_regs *);\r
-       int irq;\r
-       void* data;\r
-};\r
-\r
-#define MAX_IRQS 8\r
-\r
-// Exported to top level\r
-\r
-void handle_irqs(int irq);\r
-void inc_jiffies(int);\r
-void init_wrapper(struct pci_dev *pci_dev);\r
-void do_all_timers(void);\r
-\r
-#define __KERNEL_DS   0x18\r
-\r
-\r
+/*
+ * linux-wrapper.h
+ *
+ * Hard coded Linux kernel replacements for x86
+ *
+ * (c) 2003 Georg Acher (georg@acher.org)
+ *
+ * Emulation of:
+ * typedefs
+ * structs
+ * macros
+ *
+ * All structs and prototypes are based on kernel source 2.5.72
+ *
+ * Modified by Aleksey Bragin (aleksey@reactos.com) for ReactOS needs
+ *
+ *
+ * #include <standard-GPL-header.h>
+ */
+
+/*------------------------------------------------------------------------*/
+/* Typedefs */
+/*------------------------------------------------------------------------*/ 
+#include "cromwell_types.h"
+
+typedef unsigned int __u32;
+//typedef __u32 u32;
+typedef unsigned short __u16;
+//typedef __u16 u16;
+typedef unsigned char __u8;
+//typedef __u8 u8;
+
+typedef short s16;
+
+typedef u32 dma_addr_t;
+
+typedef  int spinlock_t;
+typedef int atomic_t;
+#ifndef STANDALONE
+typedef int mode_t;
+typedef int pid_t;
+typedef int ssize_t;
+
+#endif
+typedef int irqreturn_t;
+typedef unsigned long kernel_ulong_t;
+
+typedef int wait_queue_head_t;
+/*------------------------------------------------------------------------*/ 
+/* Stuff from xbox/linux environment */
+/*------------------------------------------------------------------------*/ 
+
+#include "list.h"
+
+#ifndef STANDALONE
+#ifdef MODULE
+typedef int size_t;
+#define NULL ((void*)0)
+extern void * memset(void *,int,unsigned int);
+extern void * memcpy(void *,const void *,unsigned int);
+#if 0
+extern char * strcpy(char *,const char *);
+#else
+static inline char * strcpy(char * dest,const char *src)
+{
+int d0, d1, d2;
+__asm__ __volatile__(
+        "1:\tlodsb\n\t"
+        "stosb\n\t"
+        "testb %%al,%%al\n\t"
+        "jne 1b"
+        : "=&S" (d0), "=&D" (d1), "=&a" (d2)
+        :"0" (src),"1" (dest) : "memory");
+return dest;
+}
+#endif
+extern size_t strlen(const char *);
+
+extern int memcmp(const void *,const void *,unsigned int);
+
+#else
+#include "boot.h"
+#include "config.h"
+#endif
+#else
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "consts.h"
+#include <string.h>
+#endif
+
+/*------------------------------------------------------------------------*/ 
+/* General structs */
+/*------------------------------------------------------------------------*/ 
+
+struct timer_list { 
+       void (*function)(unsigned long);
+       unsigned long data;
+       int expires;
+       struct list_head timer_list;
+};
+
+struct work_struct {
+       void (*func)(void *);
+};
+struct device {
+       char name[128];
+       struct bus_type *bus;
+       int dma_mask;
+       char    bus_id[16];
+       struct device_driver* driver;
+       void            *driver_data;
+       struct device *parent;
+       struct list_head driver_list;
+       void    (*release)(struct device * dev);
+};
+struct class_device{int a;};
+struct semaphore{int a;};
+
+struct device_driver{
+       char *name;
+       struct bus_type *bus;
+       int     (*probe)        (struct device * dev);
+        int     (*remove)       (struct device * dev);
+       struct list_head        devices;
+};
+
+struct bus_type {
+        char                    * name;       
+        int             (*match)(struct device * dev, struct device_driver * drv);
+        struct device * (*add)  (struct device * parent, char * bus_id);
+        int             (*hotplug) (struct device *dev, char **envp, 
+                                    int num_envp, char *buffer, int buffer_size);
+};
+
+struct dummy_process
+{
+       int flags;
+};
+
+struct pt_regs
+{
+       int a;
+};
+struct completion {
+        unsigned int done;
+        wait_queue_head_t wait;
+};
+
+// windows lookaside list head
+typedef void* kmem_cache_t;
+
+struct dma_pool
+{
+       int dummy;
+};
+
+/* from mod_devicetable.h */
+
+struct usb_device_id {
+        /* which fields to match against? */
+        __u16           match_flags;
+
+        /* Used for product specific matches; range is inclusive */
+        __u16           idVendor;
+        __u16           idProduct;
+        __u16           bcdDevice_lo;
+        __u16           bcdDevice_hi;
+
+        /* Used for device class matches */
+        __u8            bDeviceClass;
+        __u8            bDeviceSubClass;
+        __u8            bDeviceProtocol;
+
+        /* Used for interface class matches */
+        __u8            bInterfaceClass;
+        __u8            bInterfaceSubClass;
+        __u8            bInterfaceProtocol;
+
+        /* not matched against */
+        kernel_ulong_t  driver_info;
+};
+
+/* Some useful macros to use to create struct usb_device_id */
+#define USB_DEVICE_ID_MATCH_VENDOR              0x0001
+#define USB_DEVICE_ID_MATCH_PRODUCT             0x0002
+#define USB_DEVICE_ID_MATCH_DEV_LO              0x0004
+#define USB_DEVICE_ID_MATCH_DEV_HI              0x0008
+#define USB_DEVICE_ID_MATCH_DEV_CLASS           0x0010
+#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS        0x0020
+#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL        0x0040
+#define USB_DEVICE_ID_MATCH_INT_CLASS           0x0080
+#define USB_DEVICE_ID_MATCH_INT_SUBCLASS        0x0100
+#define USB_DEVICE_ID_MATCH_INT_PROTOCOL        0x0200
+
+/*------------------------------------------------------------------------*/ 
+/* imported functions from top-level */
+/*------------------------------------------------------------------------*/ 
+
+//void zxprintf(char* fmt, ...);
+//void zxsprintf(char *buffer, char* fmt, ...);
+//int zxsnprintf(char *buffer, size_t s, char* fmt, ...);
+
+/*------------------------------------------------------------------------*/ 
+/* PCI structs (taken from linux/pci.h et al., but slightly modified) */
+/*------------------------------------------------------------------------*/ 
+
+struct pci_dev {
+       int vendor;
+       int device;
+       struct pci_bus  *bus;
+       int irq;
+       char *slot_name;
+       struct device dev;
+       int base[4];
+       int flags[4];
+       void * data;
+       void * dev_ext; // link to Windows DeviceExtension
+};
+
+struct pci_bus {
+       unsigned char   number;
+};
+
+struct pci_device_id {
+        __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/
+        __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */
+        __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */
+        kernel_ulong_t driver_data;     /* Data private to the driver */
+};
+
+struct pci_driver {
+        struct list_head node;
+        char *name;
+        const struct pci_device_id *id_table;   /* must be non-NULL for probe to be called */
+        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New device inserted */
+        void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug capable driver) */
+        int  (*save_state) (struct pci_dev *dev, u32 state);    /* Save Device Context */
+        int  (*suspend) (struct pci_dev *dev, u32 state);       /* Device suspended */
+        int  (*resume) (struct pci_dev *dev);                   /* Device woken up */
+        int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
+};
+
+struct scatterlist
+{
+       int page;
+       int offset;
+       int length;
+};
+
+struct usbdevfs_hub_portinfo
+{
+       int nports;
+       int port[8];
+};
+
+/*------------------------------------------------------------------------*/ 
+/* constant defines */
+/*------------------------------------------------------------------------*/ 
+
+#define TASK_UNINTERRUPTIBLE 0
+#define HZ 100    /* Don't rely on that... */
+#define KERN_DEBUG "DBG: "
+#define KERN_ERR "ERR: "
+#define KERN_WARNING "WRN: "
+#define KERN_INFO "INF: "
+#define GFP_KERNEL 0
+#define GFP_ATOMIC 0x20
+#define GFP_NOIO 0
+#define SLAB_ATOMIC 0
+#define PCI_ANY_ID (~0)
+#define SIGKILL 9
+#define THIS_MODULE 0
+//#define PAGE_SIZE 4096
+
+
+#define CLONE_FS 0
+#define CLONE_FILES 0
+#define CLONE_SIGHAND 0
+#define PF_FREEZE 0
+#define PF_IOTHREAD 0
+
+
+#define USBDEVFS_HUB_PORTINFO 1234
+#define SA_SHIRQ 0
+
+#undef PCI_COMMAND
+#define PCI_COMMAND 0
+#undef PCI_COMMAND_MASTER
+#define PCI_COMMAND_MASTER 0
+/*------------------------------------------------------------------------*/ 
+/* Module/export macros */
+/*------------------------------------------------------------------------*/ 
+
+#define MODULE_AUTHOR(a)
+#define MODULE_DESCRIPTION(a)
+#define MODULE_LICENSE(a)
+#define MODULE_DEVICE_TABLE(type,name) void* module_table_##name=&name
+#define MODULE_PARM(a,b)
+#define MODULE_PARM_DESC(a,b)
+
+#define __devinit
+#define __exit
+#define __init
+#define __devinitdata
+#define module_init(x) static void module_init_##x(void){ x();}
+#define module_exit(x) void module_exit_##x(void){ x();}
+#define EXPORT_SYMBOL_GPL(x)
+#define EXPORT_SYMBOL(x)
+
+#define __setup(x,y) int setup_##y=(int)y
+#define subsys_initcall(x) void subsys_##x(void){x();}
+
+/*------------------------------------------------------------------------*/ 
+/* Access macros */
+/*------------------------------------------------------------------------*/ 
+
+#define dev_get_drvdata(a) (a)->driver_data
+#define dev_set_drvdata(a,b) (a)->driver_data=(b)
+
+#define __io_virt(x) ((void *)(x))
+#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define likely(x) (x)
+#define unlikely(x) (x)
+#define prefetch(x) 1
+
+#define inw(x) READ_PORT_USHORT((PUSHORT)(x))
+#define outw(x,p) WRITE_PORT_USHORT((PUSHORT)(p),(x))
+#define outl(x,p) WRITE_PORT_ULONG((PUSHORT)(p),(x))
+
+/* The kernel macro for list_for_each_entry makes nonsense (have no clue
+ * why, this is just the same definition...) */
+
+#undef list_for_each_entry
+#define list_for_each_entry(pos, head, member)                          \
+        for (pos = list_entry((head)->next, typeof(*pos), member),      \
+                     prefetch(pos->member.next);                        \
+             &pos->member != (head);                                    \
+             pos = list_entry(pos->member.next, typeof(*pos), member),  \
+                     prefetch(pos->member.next))
+
+/*------------------------------------------------------------------------*/ 
+/* function wrapper macros */
+/*------------------------------------------------------------------------*/ 
+#define kmalloc(x,y) ExAllocatePool(PagedPool,x)
+#define kfree(x) ExFreePool(x)
+
+//#define sprintf(a,b,format, arg...) zxsprintf((a),(b),format, ## arg)
+//#define snprintf(a,b,format, arg...) zxsnprintf((a),(b),format, ##arg)
+//#define printk(format, arg...) zxprintf(format, ## arg)
+#define snprintf(a,b,format, arg...) _snprintf((a),(b),format, ##arg)
+#define printk(format, arg...) DPRINT1(format, ## arg)
+#define BUG(...) do {} while(0)
+
+/* Locks & friends */
+
+#define DECLARE_MUTEX(x) struct semaphore x
+#define init_MUTEX(x)
+
+#define SPIN_LOCK_UNLOCKED 0
+#define spin_lock_init(a)  do {} while(0)
+#define spin_lock(a) *(int*)a=1
+#define spin_unlock(a) do {} while(0)
+
+#define spin_lock_irqsave(a,b) b=0
+#define spin_unlock_irqrestore(a,b)
+
+#if 0
+#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+#else
+#define local_irq_save(x) do {} while(0) 
+#define local_irq_restore(x) do {} while(0) 
+#endif
+
+#define atomic_inc(x) *(x)+=1
+#define atomic_dec(x) *(x)-=1
+#define atomic_dec_and_test(x) (*(x)-=1,(*(x))==0)
+#define atomic_set(x,a) *(x)=a
+#define atomic_read(x) *(x)
+#define ATOMIC_INIT(x) (x)
+
+#define down(x) do {} while(0) 
+#define up(x) do {} while(0)
+#define down_trylock(a) 0
+
+#define down_read(a) do {} while(0)
+#define up_read(a) do {} while(0)
+
+#define DECLARE_WAIT_QUEUE_HEAD(x) KEVENT x
+
+#define DECLARE_COMPLETION(x) struct completion x
+
+/* driver */
+
+#define driver_unregister(a)    do {} while(0)
+#define put_device(a)           do {} while(0)
+
+
+/* PCI */
+#define        to_pci_dev(n) container_of(n, struct pci_dev, dev)
+
+#define pci_pool_create(a,b,c,d,e) (void*)1
+
+#define pci_pool_alloc(a,b,c)  my_pci_pool_alloc(a,b,c) 
+
+static void __inline__ *my_pci_pool_alloc(void* pool, size_t size,
+                                               dma_addr_t *dma_handle)
+{
+       void* a;
+       a=kmalloc(size,0); //FIXME
+#ifdef MODULE
+       *dma_handle=((u32)a)&0xfffffff;
+#else
+       *dma_handle=(u32)a;
+#endif
+       return a;
+}
+
+
+#define pci_pool_free(a,b,c)    kfree(b)
+#define pci_alloc_consistent(a,b,c) my_pci_alloc_consistent(a,b,c)
+
+static void  __inline__ *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                                               dma_addr_t *dma_handle)
+{
+       void* a;
+
+       a=kmalloc(size+256,0); //FIXME
+       a=(void*)(((int)a+255)&~255); // 256 alignment
+       *dma_handle=((u32)a)&0xfffffff;
+
+       return a;
+}
+
+#define pci_free_consistent(a,b,c,d)  kfree(c)
+#define pci_pool_destroy(a)           do {} while(0)
+
+#define pci_module_init(x) my_pci_module_init(x)
+int my_pci_module_init(struct pci_driver *x);
+
+#define pci_unregister_driver(a)      do {} while(0)  
+
+#define pci_write_config_word(a,b,c) my_pci_write_config_word(a,b,c)
+
+#define bus_register(a) do {} while(0)
+#define bus_unregister(a) do {} while(0)
+
+/* DMA */
+//#define dma_pool_alloc(a,b,c) my_dma_pool_alloc((a),(b),(c))
+#define dma_pool_alloc(a,b,c) pci_pool_alloc(a,b,c)
+#define dma_pool_create(a,b,c,d,e) pci_pool_create(a,b,c,d,e)
+#define dma_pool_free(a,b,c) pci_pool_free(a,b,c)
+#define dma_pool_destroy(a) pci_pool_destroy(a)
+
+#define dma_alloc_coherent(a,b,c,d) NULL
+#define dma_free_coherent(a,b,c,d) do {} while(0)
+
+#define dma_map_single(a,b,c,d) ((u32)(b)&0xfffffff)
+#define dma_unmap_single(a,b,c,d)     do {} while(0)
+#define pci_unmap_single(a,b,c,d)     do {} while(0)
+#define dma_sync_single(a,b,c,d)      do {} while(0)
+#define dma_sync_sg(a,b,c,d)          do {} while(0)
+#define dma_map_sg(a,b,c,d)           0
+#define dma_unmap_sg(a,b,c,d)         do {} while(0)
+
+#define usb_create_driverfs_dev_files(a) do {} while(0)
+#define usb_create_driverfs_intf_files(a) do {} while(0)
+#define sg_dma_address(x) ((u32)((x)->page*4096 + (x)->offset))
+#define sg_dma_len(x) ((x)->length) 
+
+#define page_address(x) ((void*)(x/4096))
+
+#define DMA_TO_DEVICE 0
+#define DMA_FROM_DEVICE 0
+#define PCI_DMA_TODEVICE
+#define PCI_DMA_FROMDEVICE
+#define PCI_DMA_TODEVICE
+
+#define PCI_ROM_RESOURCE 1
+#define IORESOURCE_IO CM_RESOURCE_PORT_IO
+
+#define DECLARE_WAITQUEUE(a,b) KEVENT a=0
+#define init_waitqueue_head(a) my_init_waitqueue_head(a)
+#define add_wait_queue(a,b) do {} while(0)
+#define remove_wait_queue(a,b) do {} while(0)
+void my_init_waitqueue_head(PKEVENT a);
+
+VOID KeMemoryBarrier(VOID);
+
+#define mb() KeMemoryBarrier()
+#define wmb() __asm__ __volatile__ ("": : :"memory")
+#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+
+#define in_interrupt() 0
+
+#define init_completion(x) (x)->done=0
+#define wait_for_completion(x) my_wait_for_completion(x)
+void my_wait_for_completion(struct completion*);
+
+#define IRQ_NONE 0
+#define IRQ_HANDLED 1
+
+#define INIT_WORK(a,b,c) (a)->func=b
+
+#define set_current_state(a) do {} while(0)
+
+#define might_sleep()        do {} while(0)
+#define daemonize(a)         do {} while(0)
+#define allow_signal(a)      do {} while(0)
+#define wait_event_interruptible(x,y) do {} while(0)
+
+#define interruptible_sleep_on(a) my_interruptible_sleep_on(a)
+void my_interruptible_sleep_on(PKEVENT evnt);
+
+#define flush_scheduled_work() do {} while(0)
+#define refrigerator(x)        do {} while(0)
+#define signal_pending(x)      1  // fall through threads
+#define complete_and_exit(a,b) return 0
+
+//#define kill_proc(a,b,c)     0
+#define kill_proc(a,b,c) my_kill_proc(a, b, c);
+int my_kill_proc(int pid, int signal, int unk);
+
+#define yield() do {} while(0)
+#define cpu_relax() do {} while(0)
+
+#define WARN_ON(a) do {} while(0)
+
+/*------------------------------------------------------------------------*/ 
+/* Lookaside lists funcs */
+/*------------------------------------------------------------------------*/ 
+#define kmem_cache_create(a,b,c,d,e,f) my_kmem_cache_create((a),(b),(c),(d),(e),(f))
+#define kmem_cache_destroy(a) my_kmem_cache_destroy((a))
+#define kmem_cache_alloc(co, flags) my_kmem_cache_alloc((co), (flags))
+#define kmem_cache_free(co, ptr) my_kmem_cache_free((co), (ptr))
+
+kmem_cache_t *my_kmem_cache_create(const char *tag, size_t alloc_size,
+                                                                  size_t offset, unsigned long flags,
+                                                                  void *ctor,
+                                                                  void *dtor);
+
+BOOLEAN my_kmem_cache_destroy(kmem_cache_t *co);
+void *my_kmem_cache_alloc(kmem_cache_t *co, int flags);
+void my_kmem_cache_free(kmem_cache_t *co, void *ptr);
+
+/*------------------------------------------------------------------------*/ 
+/* Kernel macros */
+/*------------------------------------------------------------------------*/ 
+
+#define LINUX_VERSION_CODE 0x020572
+#define UTS_SYSNAME "XBOX"
+#define UTS_RELEASE "----"
+
+/* from linux/kernel.h */
+#define max_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+#define min_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/* from linux/stddef.h */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/*------------------------------------------------------------------------*/ 
+/* Conversion macros */
+/*------------------------------------------------------------------------*/ 
+
+#define __constant_cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le32p(x) (*(__u32*)(x))
+#define le32_to_cpup(x) (*(__u32*)(x))
+#define le32_to_cpu(x) ((u32)x)
+#define le16_to_cpus(x) do {} while (0)
+#define le16_to_cpup(x) (*(__u16*)(x))
+#define cpu_to_le16p(x) (*(__u16*)(x))
+
+/*------------------------------------------------------------------------*/ 
+/* Debug output */
+/*------------------------------------------------------------------------*/ 
+#ifdef DEBUG_MODE
+#define dev_printk(lvl,x,f,arg...) printk(f, ## arg)
+#define dev_dbg(x,f,arg...) printk(f, ## arg)
+#define dev_info(x,f,arg...) printk(f,## arg)
+#define dev_warn(x,f,arg...) printk(f,## arg)
+#define dev_err(x,f,arg...) printk(f,## arg)
+#define pr_debug(x,f,arg...) printk(f,## arg)
+#define usbprintk printk
+#endif
+
+#ifndef DEBUG_MODE
+#define dev_printk(lvl,x,f,arg...) do {} while (0)
+#define dev_dbg(x,f,arg...) do {} while (0) //printk(f, ## arg)
+#define dev_info(x,f,arg...) do {} while (0)
+#define dev_warn(x,f,arg...) do {} while (0)
+#define dev_err(x,f,arg...) do {} while (0)
+#define pr_debug(x,f,arg...) do {} while (0)
+#define usbprintk
+#endif
+
+
+
+#define PCI_DEVFN(a,b) 0
+#define PCI_SLOT(a) 0
+
+/**
+ * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
+ * @dev_class: the class, subclass, prog-if triple for this device
+ * @dev_class_mask: the class mask for this device
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI class.  The vendor, device, subvendor, and subdevice 
+ * fields will be set to PCI_ANY_ID.
+ */
+#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \
+       .class = (dev_class), .class_mask = (dev_class_mask), \
+       .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+
+/*------------------------------------------------------------------------*/ 
+/* Stuff from kernel */
+/*------------------------------------------------------------------------*/ 
+
+#include "errno.h"
+#include "bitops.h"
+//#include "linux/pci_ids.h"
+
+/*------------------------------------------------------------------------*/ 
+/* global variables */
+/*------------------------------------------------------------------------*/ 
+
+#define jiffies my_jiffies
+extern int my_jiffies;
+#define current my_current
+extern struct dummy_process *my_current;
+
+extern struct list_head interrupt_list;
+
+/*------------------------------------------------------------------------*/ 
+/* Function prototypes */
+/*------------------------------------------------------------------------*/ 
+void STDCALL usb_hcd_pci_remove (struct pci_dev *dev);
+
+#define my_wait_ms(x) wait_ms(x)
+
+#define my_udelay(x) wait_ms(x)
+#define udelay(x) my_udelay(x)
+
+#define my_mdelay(x) wait_ms(1+x/1000);
+#define mdelay(x) my_mdelay(x);
+
+#define pci_find_slot(a,b) my_pci_find_slot(a,b)
+struct pci_dev *my_pci_find_slot(int a,int b);
+
+/*------------------------------------------------------------------------*/ 
+/* Timer management */
+/*------------------------------------------------------------------------*/ 
+
+#define MAX_TIMERS 20
+extern struct timer_list *main_timer_list[MAX_TIMERS];
+
+static void __inline__ init_timer(struct timer_list* t)
+{
+       INIT_LIST_HEAD(&t->timer_list);
+       t->function=NULL;
+       t->expires=0;
+}
+
+static void __inline__ add_timer(struct timer_list* t)
+{
+       int n;
+       for(n=0;n<MAX_TIMERS;n++)
+               if (main_timer_list[n]==0)
+               {
+                       main_timer_list[n]=t;
+                       break;
+               }
+}
+
+static void __inline__ del_timer(struct timer_list* t)
+{
+       int n;
+       for(n=0;n<MAX_TIMERS;n++)
+               if (main_timer_list[n]==t)
+               {
+                       main_timer_list[n]=0;
+                       break;
+               }
+}
+static void __inline__ del_timer_sync(struct timer_list* t)
+{
+       int n;
+       for(n=0;n<MAX_TIMERS;n++)
+               if (main_timer_list[n]==t)
+               {
+                       main_timer_list[n]=0;
+                       break;
+               }
+
+}
+static void __inline__ mod_timer(struct timer_list* t, int ex)
+{
+       del_timer(t);
+       t->expires=ex;
+       add_timer(t);
+}
+
+#define time_after_eq(a,b)     \
+       (((long)(a) - (long)(b) >= 0))
+
+/*------------------------------------------------------------------------*/ 
+/* Device driver and process related stuff */
+/*------------------------------------------------------------------------*/ 
+
+static int __inline__ usb_major_init(void){return 0;}
+static void __inline__ usb_major_cleanup(void){}
+static void __inline__ schedule_work(void* p){}
+
+#define device_initialize(x) my_device_initialize(x)
+void my_device_initialize(struct device *dev);
+
+#define get_device(x) my_get_device(x)
+struct device *my_get_device(struct device *dev);
+
+#define device_add(x) my_device_add(x)
+int my_device_add(struct device *dev);
+
+#define driver_register(x) my_driver_register(x)
+int my_driver_register(struct device_driver *driver);
+
+#define device_unregister(a)    my_device_unregister(a)
+int my_device_unregister(struct device *dev);
+
+#define DEVICE_ATTR(a,b,c,d) int xxx_##a
+#define device_create_file(a,b)  do {} while(0)
+#define device_remove_file(a,b)  do {} while(0)
+
+#define schedule_timeout(x) my_schedule_timeout(x)
+int my_schedule_timeout(int x);
+
+#define wake_up(x) my_wake_up(x)
+void my_wake_up(PKEVENT);
+
+// cannot be mapped via macro due to collision with urb->complete
+static void __inline__ complete(struct completion *p)
+{
+       /* Wake up x->wait */
+       p->done++;
+       wake_up(&p->wait);
+}
+
+#define kernel_thread(a,b,c) my_kernel_thread(a,b,c)
+int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags);
+
+/*------------------------------------------------------------------------*/ 
+/* PCI, simple and inlined... */
+/*------------------------------------------------------------------------*/ 
+#include "pci_hal.c"
+
+/*------------------------------------------------------------------------*/ 
+/* IRQ handling */
+/*------------------------------------------------------------------------*/ 
+
+#define request_irq(a,b,c,d,e) my_request_irq(a,b,c,d,e)
+int my_request_irq(unsigned int irq,
+                       int  (*handler)(int, void *, struct pt_regs *),
+               unsigned long mode, const char *desc, void *data);
+
+#define free_irq(a,b) my_free_irq(a,b)
+int free_irq(int irq, void* p);
+
+
+
+struct my_irqs {
+       int  (*handler)(int, void *, struct pt_regs *);
+       int irq;
+       void* data;
+};
+
+#define MAX_IRQS 8
+
+// Exported to top level
+
+void handle_irqs(int irq);
+void inc_jiffies(int);
+void init_wrapper(struct pci_dev *pci_dev);
+void do_all_timers(void);
+
+#define __KERNEL_DS   0x18
+
+
index fbbfabe..ef8fdd2 100644 (file)
-#ifndef _BOOT_LIST_H\r
-#define _BOOT_LIST_H\r
-\r
-/*\r
- * Simple doubly linked list implementation.\r
- *\r
- * Some of the internal functions ("__xxx") are useful when\r
- * manipulating whole lists rather than single entries, as\r
- * sometimes we already know the next/prev entries and we can\r
- * generate better code by using them directly rather than\r
- * using the generic single-entry routines.\r
- */\r
-\r
-struct list_head {\r
-       struct list_head *next, *prev;\r
-};\r
-\r
-#define LIST_HEAD_INIT(name) { &(name), &(name) }\r
-\r
-#define LIST_HEAD(name) \\r
-       struct list_head name = LIST_HEAD_INIT(name)\r
-\r
-#define INIT_LIST_HEAD(ptr) do { \\r
-       (ptr)->next = (ptr); (ptr)->prev = (ptr); \\r
-} while (0)\r
-\r
-/*\r
- * Insert a new entry between two known consecutive entries. \r
- *\r
- * This is only for internal list manipulation where we know\r
- * the prev/next entries already!\r
- */\r
-static inline void __list_add(struct list_head *new,\r
-                             struct list_head *prev,\r
-                             struct list_head *next)\r
-{\r
-       next->prev = new;\r
-       new->next = next;\r
-       new->prev = prev;\r
-       prev->next = new;\r
-}\r
-\r
-/**\r
- * list_add - add a new entry\r
- * @new: new entry to be added\r
- * @head: list head to add it after\r
- *\r
- * Insert a new entry after the specified head.\r
- * This is good for implementing stacks.\r
- */\r
-static inline void list_add(struct list_head *new, struct list_head *head)\r
-{\r
-       __list_add(new, head, head->next);\r
-}\r
-\r
-/**\r
- * list_add_tail - add a new entry\r
- * @new: new entry to be added\r
- * @head: list head to add it before\r
- *\r
- * Insert a new entry before the specified head.\r
- * This is useful for implementing queues.\r
- */\r
-static inline void list_add_tail(struct list_head *new, struct list_head *head)\r
-{\r
-       __list_add(new, head->prev, head);\r
-}\r
-\r
-/*\r
- * Delete a list entry by making the prev/next entries\r
- * point to each other.\r
- *\r
- * This is only for internal list manipulation where we know\r
- * the prev/next entries already!\r
- */\r
-static inline void __list_del(struct list_head *prev, struct list_head *next)\r
-{\r
-       next->prev = prev;\r
-       prev->next = next;\r
-}\r
-\r
-/**\r
- * list_del - deletes entry from list.\r
- * @entry: the element to delete from the list.\r
- * Note: list_empty on entry does not return true after this, the entry is in an undefined state.\r
- */\r
-static inline void list_del(struct list_head *entry)\r
-{\r
-       __list_del(entry->prev, entry->next);\r
-       entry->next = (void *) 0;\r
-       entry->prev = (void *) 0;\r
-}\r
-\r
-/**\r
- * list_del_init - deletes entry from list and reinitialize it.\r
- * @entry: the element to delete from the list.\r
- */\r
-static inline void list_del_init(struct list_head *entry)\r
-{\r
-       __list_del(entry->prev, entry->next);\r
-       INIT_LIST_HEAD(entry); \r
-}\r
-\r
-/**\r
- * list_move - delete from one list and add as another's head\r
- * @list: the entry to move\r
- * @head: the head that will precede our entry\r
- */\r
-static inline void list_move(struct list_head *list, struct list_head *head)\r
-{\r
-        __list_del(list->prev, list->next);\r
-        list_add(list, head);\r
-}\r
-\r
-/**\r
- * list_move_tail - delete from one list and add as another's tail\r
- * @list: the entry to move\r
- * @head: the head that will follow our entry\r
- */\r
-static inline void list_move_tail(struct list_head *list,\r
-                                 struct list_head *head)\r
-{\r
-        __list_del(list->prev, list->next);\r
-        list_add_tail(list, head);\r
-}\r
-\r
-/**\r
- * list_empty - tests whether a list is empty\r
- * @head: the list to test.\r
- */\r
-static inline int list_empty(struct list_head *head)\r
-{\r
-       return head->next == head;\r
-}\r
-\r
-static inline void __list_splice(struct list_head *list,\r
-                                struct list_head *head)\r
-{\r
-       struct list_head *first = list->next;\r
-       struct list_head *last = list->prev;\r
-       struct list_head *at = head->next;\r
-\r
-       first->prev = head;\r
-       head->next = first;\r
-\r
-       last->next = at;\r
-       at->prev = last;\r
-}\r
-\r
-/**\r
- * list_splice - join two lists\r
- * @list: the new list to add.\r
- * @head: the place to add it in the first list.\r
- */\r
-static inline void list_splice(struct list_head *list, struct list_head *head)\r
-{\r
-       if (!list_empty(list))\r
-               __list_splice(list, head);\r
-}\r
-\r
-/**\r
- * list_splice_init - join two lists and reinitialise the emptied list.\r
- * @list: the new list to add.\r
- * @head: the place to add it in the first list.\r
- *\r
- * The list at @list is reinitialised\r
- */\r
-static inline void list_splice_init(struct list_head *list,\r
-                                   struct list_head *head)\r
-{\r
-       if (!list_empty(list)) {\r
-               __list_splice(list, head);\r
-               INIT_LIST_HEAD(list);\r
-       }\r
-}\r
-\r
-/**\r
- * list_entry - get the struct for this entry\r
- * @ptr:       the &struct list_head pointer.\r
- * @type:      the type of the struct this is embedded in.\r
- * @member:    the name of the list_struct within the struct.\r
- */\r
-#define list_entry(ptr, type, member) \\r
-       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))\r
-\r
-/**\r
- * list_for_each       -       iterate over a list\r
- * @pos:       the &struct list_head to use as a loop counter.\r
- * @head:      the head for your list.\r
- */\r
-#define list_for_each(pos, head) \\r
-       for (pos = (head)->next; pos != (head); \\r
-               pos = pos->next)\r
-/**\r
- * list_for_each_prev  -       iterate over a list backwards\r
- * @pos:       the &struct list_head to use as a loop counter.\r
- * @head:      the head for your list.\r
- */\r
-#define list_for_each_prev(pos, head) \\r
-       for (pos = (head)->prev; pos != (head); \\r
-               pos = pos->prev)\r
-               \r
-/**\r
- * list_for_each_safe  -       iterate over a list safe against removal of list entry\r
- * @pos:       the &struct list_head to use as a loop counter.\r
- * @n:         another &struct list_head to use as temporary storage\r
- * @head:      the head for your list.\r
- */\r
-#define list_for_each_safe(pos, n, head) \\r
-       for (pos = (head)->next, n = pos->next; pos != (head); \\r
-               pos = n, n = pos->next)\r
-\r
-/**\r
- * list_for_each_entry -       iterate over list of given type\r
- * @pos:       the type * to use as a loop counter.\r
- * @head:      the head for your list.\r
- * @member:    the name of the list_struct within the struct.\r
- */\r
-#define list_for_each_entry(pos, head, member)                         \\r
-       for (pos = list_entry((head)->next, typeof(*pos), member)       \\r
-            &pos->member != (head);                                    \\r
-            pos = list_entry(pos->member.next, typeof(*pos), member))\r
-\r
-#endif\r
+#ifndef _BOOT_LIST_H
+#define _BOOT_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = (void *) 0;
+       entry->prev = (void *) 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry); 
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                 struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+       return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+                                struct list_head *head)
+{
+       struct list_head *first = list->next;
+       struct list_head *last = list->prev;
+       struct list_head *at = head->next;
+
+       first->prev = head;
+       head->next = first;
+
+       last->next = at;
+       at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+       if (!list_empty(list))
+               __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+                                   struct list_head *head)
+{
+       if (!list_empty(list)) {
+               __list_splice(list, head);
+               INIT_LIST_HEAD(list);
+       }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); \
+               pos = pos->next)
+/**
+ * list_for_each_prev  -       iterate over a list backwards
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+       for (pos = (head)->prev; pos != (head); \
+               pos = pos->prev)
+               
+/**
+ * list_for_each_safe  -       iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry -       iterate over list of given type
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_entry((head)->next, typeof(*pos), member)       \
+            &pos->member != (head);                                    \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#endif
index f3d538f..625fc90 100644 (file)
-// PCI -> HAL interface\r
-// this file is part of linux_wrapper.h\r
-\r
-//FIXME: Move this file, make its definitions more general\r
-#include "../host/ohci_main.h"\r
-\r
-/*\r
-  Initialize device before it's used by a driver. Ask low-level code to enable I/O and memory.\r
-  Wake up the device if it was suspended. Beware, this function can fail. \r
- */\r
-static int __inline__ pci_enable_device(struct pci_dev *dev)\r
-{\r
-       DPRINT1("pci_enable_device() called...\n");\r
-       return 0;\r
-}\r
-\r
-// Get physical address where resource x resides\r
-static PHYSICAL_ADDRESS __inline__ pci_resource_start (struct pci_dev *dev, int x)\r
-{\r
-       POHCI_DEVICE_EXTENSION dev_ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext;\r
-       DPRINT1("pci_resource_start() called, x=0x%x\n", x);\r
-       \r
-       //FIXME: Take x into account\r
-    return dev_ext->BaseAddress;\r
-       //return dev->base[x];\r
-}\r
-\r
-// ???\r
-static unsigned long __inline__ pci_resource_len (struct pci_dev *dev, int x)\r
-{\r
-       POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext;\r
-\r
-       DPRINT1("pci_resource_len() called, x=0x%x\n", x);\r
-\r
-       //FIXME: Take x into account\r
-    return ext->BaseAddrLength;\r
-}\r
-\r
-// ???\r
-static int __inline__ pci_resource_flags(struct pci_dev *dev, int x)\r
-{\r
-       POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext;\r
-       \r
-       DPRINT1("pci_resource_flags() called, x=0x%x\n", x);\r
-       \r
-               //FIXME: Take x into account\r
-    return ext->Flags;\r
-}\r
-\r
-/*\r
-   Enables bus-mastering for device dev\r
-*/\r
-static int __inline__ pci_set_master(struct pci_dev *dev) {return 0;}\r
-\r
-// Store pointer to data for this device\r
-static int __inline__ pci_set_drvdata(struct pci_dev *dev, void* d)\r
-{\r
-       DPRINT1("pci_set_drvdata() called...\n");\r
-       dev->data=(void*)d;\r
-       return 0;\r
-}\r
-\r
-// Get pointer to previously saved data\r
-static void __inline__ *pci_get_drvdata(struct pci_dev *dev)\r
-{\r
-       DPRINT1("pci_get_drvdata() called...\n");\r
-       return dev->data;\r
-}\r
-\r
-\r
-/*\r
-   ===========================================================================\r
-   I/O mem related stuff below\r
-*/\r
-\r
-/*\r
-Allocate I/O memory region. \r
-\r
-Parameters:\r
-start  begin of region  \r
-n      length of region  \r
-name   name of requester \r
-*/\r
-static int __inline__ request_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d)\r
-{\r
-       DPRINT1("request_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len);\r
-       return ~0;\r
-}\r
-\r
-/*\r
-Unmap I/O memory from kernel address space. \r
-\r
-Parameters:\r
-addr  virtual start address \r
-\r
-*/\r
-static int __inline__ iounmap(void* p)\r
-{\r
-       DPRINT1("iounmap(): p=0x%x. FIXME - how to obtain len of mapped region?\n", p);\r
-       \r
-       //MmUnnapIoSpace(p);\r
-       \r
-       return 0;\r
-}\r
-\r
-/*\r
-Release I/O port region. \r
-\r
-Parameters:\r
-start  begin of region  \r
-n  length of region  \r
-*/\r
-static int __inline__ release_region(PHYSICAL_ADDRESS addr, unsigned long len)\r
-{\r
-       DPRINT1("release_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len);\r
-       return 0;\r
-}\r
-\r
-/*\r
-Allocate I/O memory region. \r
-\r
-Parameters:\r
-start  begin of region  \r
-n      length of region  \r
-name   name of requester \r
-*/\r
-static int __inline__ request_mem_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d)\r
-{\r
-       DPRINT1("request_mem_region(): addr=0x%x, len=0x%x\n", addr, len);\r
-       return 1;\r
-}\r
-\r
-/*\r
-Remap I/O memory into kernel address space (no cache). \r
-\r
-Parameters:\r
-phys_addr  begin of physical address range  \r
-size       size of physical address range \r
-\r
-Returns:\r
-virtual start address of mapped range\r
-*/\r
-static void __inline__ *ioremap_nocache(PHYSICAL_ADDRESS addr, unsigned long len)\r
-{\r
-       // MmMapIoSpace with NoCache param\r
-       DPRINT1("ioremap_nocache(): addr=0x%x, len=0x%x\n", addr, len);\r
-\r
-       return MmMapIoSpace(addr, len, MmNonCached);\r
-}\r
-\r
-/*\r
-Release I/O memory region. \r
-\r
-Parameters:\r
-start  begin of region  \r
-n      length of region  \r
-*/\r
-static int __inline__ release_mem_region(PHYSICAL_ADDRESS addr, unsigned long len)\r
-{\r
-       DPRINT1("release_mem_region(): addr=0x%x, len=0x%x\n", addr, len);\r
-       return 0;\r
-}\r
+// PCI -> HAL interface
+// this file is part of linux_wrapper.h
+
+//FIXME: Move this file, make its definitions more general
+#include "../host/ohci_main.h"
+
+/*
+  Initialize device before it's used by a driver. Ask low-level code to enable I/O and memory.
+  Wake up the device if it was suspended. Beware, this function can fail. 
+ */
+static int __inline__ pci_enable_device(struct pci_dev *dev)
+{
+       DPRINT1("pci_enable_device() called...\n");
+       return 0;
+}
+
+// Get physical address where resource x resides
+static PHYSICAL_ADDRESS __inline__ pci_resource_start (struct pci_dev *dev, int x)
+{
+       POHCI_DEVICE_EXTENSION dev_ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext;
+       DPRINT1("pci_resource_start() called, x=0x%x\n", x);
+       
+       //FIXME: Take x into account
+    return dev_ext->BaseAddress;
+       //return dev->base[x];
+}
+
+// ???
+static unsigned long __inline__ pci_resource_len (struct pci_dev *dev, int x)
+{
+       POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext;
+
+       DPRINT1("pci_resource_len() called, x=0x%x\n", x);
+
+       //FIXME: Take x into account
+    return ext->BaseAddrLength;
+}
+
+// ???
+static int __inline__ pci_resource_flags(struct pci_dev *dev, int x)
+{
+       POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext;
+       
+       DPRINT1("pci_resource_flags() called, x=0x%x\n", x);
+       
+               //FIXME: Take x into account
+    return ext->Flags;
+}
+
+/*
+   Enables bus-mastering for device dev
+*/
+static int __inline__ pci_set_master(struct pci_dev *dev) {return 0;}
+
+// Store pointer to data for this device
+static int __inline__ pci_set_drvdata(struct pci_dev *dev, void* d)
+{
+       DPRINT1("pci_set_drvdata() called...\n");
+       dev->data=(void*)d;
+       return 0;
+}
+
+// Get pointer to previously saved data
+static void __inline__ *pci_get_drvdata(struct pci_dev *dev)
+{
+       DPRINT1("pci_get_drvdata() called...\n");
+       return dev->data;
+}
+
+
+/*
+   ===========================================================================
+   I/O mem related stuff below
+*/
+
+/*
+Allocate I/O memory region. 
+
+Parameters:
+start  begin of region  
+n      length of region  
+name   name of requester 
+*/
+static int __inline__ request_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d)
+{
+       DPRINT1("request_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len);
+       return ~0;
+}
+
+/*
+Unmap I/O memory from kernel address space. 
+
+Parameters:
+addr  virtual start address 
+
+*/
+static int __inline__ iounmap(void* p)
+{
+       DPRINT1("iounmap(): p=0x%x. FIXME - how to obtain len of mapped region?\n", p);
+       
+       //MmUnnapIoSpace(p);
+       
+       return 0;
+}
+
+/*
+Release I/O port region. 
+
+Parameters:
+start  begin of region  
+n  length of region  
+*/
+static int __inline__ release_region(PHYSICAL_ADDRESS addr, unsigned long len)
+{
+       DPRINT1("release_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len);
+       return 0;
+}
+
+/*
+Allocate I/O memory region. 
+
+Parameters:
+start  begin of region  
+n      length of region  
+name   name of requester 
+*/
+static int __inline__ request_mem_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d)
+{
+       DPRINT1("request_mem_region(): addr=0x%x, len=0x%x\n", addr, len);
+       return 1;
+}
+
+/*
+Remap I/O memory into kernel address space (no cache). 
+
+Parameters:
+phys_addr  begin of physical address range  
+size       size of physical address range 
+
+Returns:
+virtual start address of mapped range
+*/
+static void __inline__ *ioremap_nocache(PHYSICAL_ADDRESS addr, unsigned long len)
+{
+       // MmMapIoSpace with NoCache param
+       DPRINT1("ioremap_nocache(): addr=0x%x, len=0x%x\n", addr, len);
+
+       return MmMapIoSpace(addr, len, MmNonCached);
+}
+
+/*
+Release I/O memory region. 
+
+Parameters:
+start  begin of region  
+n      length of region  
+*/
+static int __inline__ release_mem_region(PHYSICAL_ADDRESS addr, unsigned long len)
+{
+       DPRINT1("release_mem_region(): addr=0x%x, len=0x%x\n", addr, len);
+       return 0;
+}
index 5d0f018..8cb847e 100644 (file)
@@ -1,16 +1,16 @@
-#ifndef PCI_IDS__H\r
-#define PCI_IDS__H\r
-\r
-#define PCI_VENDOR_ID_NS               0x100b\r
-#define        PCI_VENDOR_ID_AMD               0x1022\r
-#define PCI_VENDOR_ID_OPTI             0x1045\r
-#define PCI_VENDOR_ID_VIA              0x1106\r
-#define PCI_VENDOR_ID_INTEL            0x8086\r
-\r
-#define PCI_DEVICE_ID_NS_87560_LIO     0x000e\r
-#define PCI_DEVICE_ID_INTEL_82371AB_2  0x7112\r
-\r
-#define PCI_CLASS_SERIAL_USB (PCI_CLASS_SERIAL_BUS_CTLR << 8 + PCI_SUBCLASS_SB_USB)\r
-\r
-#endif\r
-\r
+#ifndef PCI_IDS__H
+#define PCI_IDS__H
+
+#define PCI_VENDOR_ID_NS               0x100b
+#define        PCI_VENDOR_ID_AMD               0x1022
+#define PCI_VENDOR_ID_OPTI             0x1045
+#define PCI_VENDOR_ID_VIA              0x1106
+#define PCI_VENDOR_ID_INTEL            0x8086
+
+#define PCI_DEVICE_ID_NS_87560_LIO     0x000e
+#define PCI_DEVICE_ID_INTEL_82371AB_2  0x7112
+
+#define PCI_CLASS_SERIAL_USB (PCI_CLASS_SERIAL_BUS_CTLR << 8 + PCI_SUBCLASS_SB_USB)
+
+#endif
+
index 0e3d67f..ef1c1f7 100644 (file)
-#ifndef __LINUX_USB_H\r
-#define __LINUX_USB_H\r
-\r
-\r
-#include "usb_ch9.h"\r
-\r
-#define USB_MAJOR                      180\r
-\r
-\r
-#ifdef __KERNEL__\r
-#if 0\r
-#include <linux/config.h>\r
-#include <linux/errno.h>        /* for -ENODEV */\r
-#include <linux/delay.h>       /* for mdelay() */\r
-#include <linux/interrupt.h>   /* for in_interrupt() */\r
-#include <linux/list.h>                /* for struct list_head */\r
-#include <linux/device.h>      /* for struct device */\r
-#include <linux/fs.h>          /* for struct file_operations */\r
-#include <linux/completion.h>  /* for struct completion */\r
-#include <linux/sched.h>       /* for current && schedule_timeout */\r
-\r
-\r
-static __inline__ void wait_ms(unsigned int ms)\r
-{\r
-       if(!in_interrupt()) {\r
-               current->state = TASK_UNINTERRUPTIBLE;\r
-               schedule_timeout(1 + ms * HZ / 1000);\r
-       }\r
-       else\r
-               mdelay(ms);\r
-}\r
-#endif\r
-struct usb_device;\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * Host-side wrappers for standard USB descriptors ... these are parsed\r
- * from the data provided by devices.  Parsing turns them from a flat\r
- * sequence of descriptors into a hierarchy:\r
- *\r
- *  - devices have one (usually) or more configs;\r
- *  - configs have one (often) or more interfaces;\r
- *  - interfaces have one (usually) or more settings;\r
- *  - each interface setting has zero or (usually) more endpoints.\r
- *\r
- * And there might be other descriptors mixed in with those.\r
- *\r
- * Devices may also have class-specific or vendor-specific descriptors.\r
- */\r
-\r
-/* host-side wrapper for parsed endpoint descriptors */\r
-struct usb_host_endpoint {\r
-       struct usb_endpoint_descriptor  desc;\r
-\r
-       unsigned char *extra;   /* Extra descriptors */\r
-       int extralen;\r
-};\r
-\r
-/* host-side wrapper for one interface setting's parsed descriptors */\r
-struct usb_host_interface {\r
-       struct usb_interface_descriptor desc;\r
-\r
-       /* array of desc.bNumEndpoint endpoints associated with this\r
-        * interface setting.  these will be in no particular order.\r
-        */\r
-       struct usb_host_endpoint *endpoint;\r
-\r
-       unsigned char *extra;   /* Extra descriptors */\r
-       int extralen;\r
-};\r
-\r
-/**\r
- * struct usb_interface - what usb device drivers talk to\r
- * @altsetting: array of interface descriptors, one for each alternate\r
- *     setting that may be selected.  Each one includes a set of\r
- *     endpoint configurations and will be in numberic order,\r
- *     0..num_altsetting.\r
- * @num_altsetting: number of altsettings defined.\r
- * @act_altsetting: index of current altsetting.  this number is always\r
- *     less than num_altsetting.  after the device is configured, each\r
- *     interface uses its default setting of zero.\r
- * @max_altsetting:\r
- * @minor: the minor number assigned to this interface, if this\r
- *     interface is bound to a driver that uses the USB major number.\r
- *     If this interface does not use the USB major, this field should\r
- *     be unused.  The driver should set this value in the probe()\r
- *     function of the driver, after it has been assigned a minor\r
- *     number from the USB core by calling usb_register_dev().\r
- * @dev: driver model's view of this device\r
- * @class_dev: driver model's class view of this device.\r
- *\r
- * USB device drivers attach to interfaces on a physical device.  Each\r
- * interface encapsulates a single high level function, such as feeding\r
- * an audio stream to a speaker or reporting a change in a volume control.\r
- * Many USB devices only have one interface.  The protocol used to talk to\r
- * an interface's endpoints can be defined in a usb "class" specification,\r
- * or by a product's vendor.  The (default) control endpoint is part of\r
- * every interface, but is never listed among the interface's descriptors.\r
- *\r
- * The driver that is bound to the interface can use standard driver model\r
- * calls such as dev_get_drvdata() on the dev member of this structure.\r
- *\r
- * Each interface may have alternate settings.  The initial configuration\r
- * of a device sets the first of these, but the device driver can change\r
- * that setting using usb_set_interface().  Alternate settings are often\r
- * used to control the the use of periodic endpoints, such as by having\r
- * different endpoints use different amounts of reserved USB bandwidth.\r
- * All standards-conformant USB devices that use isochronous endpoints\r
- * will use them in non-default settings.\r
- */\r
-struct usb_interface {\r
-       /* array of alternate settings for this interface.\r
-        * these will be in numeric order, 0..num_altsettting\r
-        */\r
-       struct usb_host_interface *altsetting;\r
-\r
-       unsigned act_altsetting;        /* active alternate setting */\r
-       unsigned num_altsetting;        /* number of alternate settings */\r
-       unsigned max_altsetting;        /* total memory allocated */\r
-\r
-       struct usb_driver *driver;      /* driver */\r
-       int minor;                      /* minor number this interface is bound to */\r
-       struct device dev;              /* interface specific device info */\r
-       struct class_device class_dev;\r
-};\r
-#define        to_usb_interface(d) container_of(d, struct usb_interface, dev)\r
-#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev)\r
-#define        interface_to_usbdev(intf) \\r
-       container_of(intf->dev.parent, struct usb_device, dev)\r
-\r
-static inline void *usb_get_intfdata (struct usb_interface *intf)\r
-{\r
-       return dev_get_drvdata (&intf->dev);\r
-}\r
-\r
-static inline void usb_set_intfdata (struct usb_interface *intf, void *data)\r
-{\r
-       dev_set_drvdata(&intf->dev, data);\r
-}\r
-\r
-/* USB_DT_CONFIG: Configuration descriptor information.\r
- *\r
- * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the\r
- * descriptor type is different.  Highspeed-capable devices can look\r
- * different depending on what speed they're currently running.  Only\r
- * devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG.\r
- */\r
-struct usb_host_config {\r
-       struct usb_config_descriptor    desc;\r
-\r
-       /* the interfaces associated with this configuration\r
-        * these will be in numeric order, 0..desc.bNumInterfaces\r
-        */\r
-       struct usb_interface *interface;\r
-\r
-       unsigned char *extra;   /* Extra descriptors */\r
-       int extralen;\r
-};\r
-\r
-// FIXME remove; exported only for drivers/usb/misc/auserwald.c\r
-// prefer usb_device->epnum[0..31]\r
-extern struct usb_endpoint_descriptor *\r
-       usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);\r
-\r
-int __usb_get_extra_descriptor(char *buffer, unsigned size,\r
-       unsigned char type, void **ptr);\r
-#define usb_get_extra_descriptor(ifpoint,type,ptr)\\r
-       __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\\r
-               type,(void**)ptr)\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-struct usb_operations;\r
-\r
-/* USB device number allocation bitmap */\r
-struct usb_devmap {\r
-       unsigned long devicemap[128 / (8*sizeof(unsigned long))];\r
-};\r
-\r
-/*\r
- * Allocated per bus (tree of devices) we have:\r
- */\r
-struct usb_bus {\r
-       struct device *controller;      /* host/master side hardware */\r
-       int busnum;                     /* Bus number (in order of reg) */\r
-       char *bus_name;                 /* stable id (PCI slot_name etc) */\r
-\r
-       int devnum_next;                /* Next open device number in round-robin allocation */\r
-\r
-       struct usb_devmap devmap;       /* device address allocation map */\r
-       struct usb_operations *op;      /* Operations (specific to the HC) */\r
-       struct usb_device *root_hub;    /* Root hub */\r
-       struct list_head bus_list;      /* list of busses */\r
-       void *hcpriv;                   /* Host Controller private data */\r
-\r
-       int bandwidth_allocated;        /* on this bus: how much of the time\r
-                                        * reserved for periodic (intr/iso)\r
-                                        * requests is used, on average?\r
-                                        * Units: microseconds/frame.\r
-                                        * Limits: Full/low speed reserve 90%,\r
-                                        * while high speed reserves 80%.\r
-                                        */\r
-       int bandwidth_int_reqs;         /* number of Interrupt requests */\r
-       int bandwidth_isoc_reqs;        /* number of Isoc. requests */\r
-\r
-       struct dentry *usbfs_dentry;    /* usbfs dentry entry for the bus */\r
-       struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the bus */\r
-\r
-       atomic_t refcnt;\r
-};\r
-\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/* This is arbitrary.\r
- * From USB 2.0 spec Table 11-13, offset 7, a hub can\r
- * have up to 255 ports. The most yet reported is 10.\r
- */\r
-#define USB_MAXCHILDREN                (16)\r
-\r
-struct usb_tt;\r
-\r
-struct usb_device {\r
-       int             devnum;         /* Address on USB bus */\r
-       char            devpath [16];   /* Use in messages: /port/port/... */\r
-       enum usb_device_state   state;  /* configured, not attached, etc */\r
-       enum usb_device_speed   speed;  /* high/full/low (or error) */\r
-\r
-       struct usb_tt   *tt;            /* low/full speed dev, highspeed hub */\r
-       int             ttport;         /* device port on that tt hub */\r
-\r
-       struct semaphore serialize;\r
-\r
-       unsigned int toggle[2];         /* one bit for each endpoint ([0] = IN, [1] = OUT) */\r
-       unsigned int halted[2];         /* endpoint halts; one bit per endpoint # & direction; */\r
-                                       /* [0] = IN, [1] = OUT */\r
-       int epmaxpacketin[16];          /* INput endpoint specific maximums */\r
-       int epmaxpacketout[16];         /* OUTput endpoint specific maximums */\r
-\r
-       struct usb_device *parent;      /* our hub, unless we're the root */\r
-       struct usb_bus *bus;            /* Bus we're part of */\r
-\r
-       struct device dev;              /* Generic device interface */\r
-\r
-       struct usb_device_descriptor descriptor;/* Descriptor */\r
-       struct usb_host_config *config; /* All of the configs */\r
-       struct usb_host_config *actconfig;/* the active configuration */\r
-\r
-       char **rawdescriptors;          /* Raw descriptors for each config */\r
-\r
-       int have_langid;                /* whether string_langid is valid yet */\r
-       int string_langid;              /* language ID for strings */\r
-\r
-       void *hcpriv;                   /* Host Controller private data */\r
-       \r
-       struct list_head filelist;\r
-       struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */\r
-       struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the device */\r
-\r
-       /*\r
-        * Child devices - these can be either new devices\r
-        * (if this is a hub device), or different instances\r
-        * of this same device.\r
-        *\r
-        * Each instance needs its own set of data structures.\r
-        */\r
-\r
-       int maxchild;                   /* Number of ports if hub */\r
-       struct usb_device *children[USB_MAXCHILDREN];\r
-};\r
-#define        to_usb_device(d) container_of(d, struct usb_device, dev)\r
-\r
-extern struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *);\r
-extern struct usb_device STDCALL *usb_get_dev(struct usb_device *dev);\r
-extern void STDCALL usb_put_dev(struct usb_device *dev);\r
-\r
-/* mostly for devices emulating SCSI over USB */\r
-extern int usb_reset_device(struct usb_device *dev);\r
-\r
-extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);\r
-\r
-/* for drivers using iso endpoints */\r
-extern int usb_get_current_frame_number (struct usb_device *usb_dev);\r
-\r
-/* used these for multi-interface device registration */\r
-extern void usb_driver_claim_interface(struct usb_driver *driver,\r
-                       struct usb_interface *iface, void* priv);\r
-extern int usb_interface_claimed(struct usb_interface *iface);\r
-extern void usb_driver_release_interface(struct usb_driver *driver,\r
-                       struct usb_interface *iface);\r
-const struct usb_device_id *usb_match_id(struct usb_interface *interface,\r
-                                        const struct usb_device_id *id);\r
-\r
-extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor);\r
-extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);\r
-\r
-\r
-/**\r
- * usb_make_path - returns stable device path in the usb tree\r
- * @dev: the device whose path is being constructed\r
- * @buf: where to put the string\r
- * @size: how big is "buf"?\r
- *\r
- * Returns length of the string (> 0) or negative if size was too small.\r
- *\r
- * This identifier is intended to be "stable", reflecting physical paths in\r
- * hardware such as physical bus addresses for host controllers or ports on\r
- * USB hubs.  That makes it stay the same until systems are physically\r
- * reconfigured, by re-cabling a tree of USB devices or by moving USB host\r
- * controllers.  Adding and removing devices, including virtual root hubs\r
- * in host controller driver modules, does not change these path identifers;\r
- * neither does rebooting or re-enumerating.  These are more useful identifiers\r
- * than changeable ("unstable") ones like bus numbers or device addresses.\r
- *\r
- * With a partial exception for devices connected to USB 2.0 root hubs, these\r
- * identifiers are also predictable.  So long as the device tree isn't changed,\r
- * plugging any USB device into a given hub port always gives it the same path.\r
- * Because of the use of "companion" controllers, devices connected to ports on\r
- * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are\r
- * high speed, and a different one if they are full or low speed.\r
- */\r
-static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)\r
-{\r
-       int actual;\r
-       actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath);\r
-       return (actual >= size) ? -1 : actual;\r
-}\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-#define USB_DEVICE_ID_MATCH_DEVICE             (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)\r
-#define USB_DEVICE_ID_MATCH_DEV_RANGE          (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)\r
-#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)\r
-#define USB_DEVICE_ID_MATCH_DEV_INFO \\r
-       (USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL)\r
-#define USB_DEVICE_ID_MATCH_INT_INFO \\r
-       (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)\r
-\r
-/**\r
- * USB_DEVICE - macro used to describe a specific usb device\r
- * @vend: the 16 bit USB Vendor ID\r
- * @prod: the 16 bit USB Product ID\r
- *\r
- * This macro is used to create a struct usb_device_id that matches a\r
- * specific device.\r
- */\r
-#define USB_DEVICE(vend,prod) \\r
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), .idProduct = (prod)\r
-/**\r
- * USB_DEVICE_VER - macro used to describe a specific usb device with a version range\r
- * @vend: the 16 bit USB Vendor ID\r
- * @prod: the 16 bit USB Product ID\r
- * @lo: the bcdDevice_lo value\r
- * @hi: the bcdDevice_hi value\r
- *\r
- * This macro is used to create a struct usb_device_id that matches a\r
- * specific device, with a version range.\r
- */\r
-#define USB_DEVICE_VER(vend,prod,lo,hi) \\r
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)\r
-\r
-/**\r
- * USB_DEVICE_INFO - macro used to describe a class of usb devices\r
- * @cl: bDeviceClass value\r
- * @sc: bDeviceSubClass value\r
- * @pr: bDeviceProtocol value\r
- *\r
- * This macro is used to create a struct usb_device_id that matches a\r
- * specific class of devices.\r
- */\r
-#define USB_DEVICE_INFO(cl,sc,pr) \\r
-       .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), .bDeviceSubClass = (sc), .bDeviceProtocol = (pr)\r
-\r
-/**\r
- * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces \r
- * @cl: bInterfaceClass value\r
- * @sc: bInterfaceSubClass value\r
- * @pr: bInterfaceProtocol value\r
- *\r
- * This macro is used to create a struct usb_device_id that matches a\r
- * specific class of interfaces.\r
- */\r
-#define USB_INTERFACE_INFO(cl,sc,pr) \\r
-       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/**\r
- * struct usb_driver - identifies USB driver to usbcore\r
- * @owner: Pointer to the module owner of this driver; initialize\r
- *     it using THIS_MODULE.\r
- * @name: The driver name should be unique among USB drivers,\r
- *     and should normally be the same as the module name.\r
- * @probe: Called to see if the driver is willing to manage a particular\r
- *     interface on a device.  If it is, probe returns zero and uses\r
- *     dev_set_drvdata() to associate driver-specific data with the\r
- *     interface.  It may also use usb_set_interface() to specify the\r
- *     appropriate altsetting.  If unwilling to manage the interface,\r
- *     return a negative errno value.\r
- * @disconnect: Called when the interface is no longer accessible, usually\r
- *     because its device has been (or is being) disconnected or the\r
- *     driver module is being unloaded.\r
- * @ioctl: Used for drivers that want to talk to userspace through\r
- *     the "usbfs" filesystem.  This lets devices provide ways to\r
- *     expose information to user space regardless of where they\r
- *     do (or don't) show up otherwise in the filesystem.\r
- * @id_table: USB drivers use ID table to support hotplugging.\r
- *     Export this with MODULE_DEVICE_TABLE(usb,...).  This must be set\r
- *     or your driver's probe function will never get called. \r
- *\r
- * USB drivers must provide a name, probe() and disconnect() methods,\r
- * and an id_table.  Other driver fields are optional.\r
- *\r
- * The id_table is used in hotplugging.  It holds a set of descriptors,\r
- * and specialized data may be associated with each entry.  That table\r
- * is used by both user and kernel mode hotplugging support.\r
- *\r
- * The probe() and disconnect() methods are called in a context where\r
- * they can sleep, but they should avoid abusing the privilege.  Most\r
- * work to connect to a device should be done when the device is opened,\r
- * and undone at the last close.  The disconnect code needs to address\r
- * concurrency issues with respect to open() and close() methods, as\r
- * well as forcing all pending I/O requests to complete (by unlinking\r
- * them as necessary, and blocking until the unlinks complete).\r
- */\r
-struct usb_driver {\r
-       struct module *owner;\r
-\r
-       const char *name;\r
-\r
-       int (*probe) (struct usb_interface *intf,\r
-                     const struct usb_device_id *id);\r
-\r
-       void (*disconnect) (struct usb_interface *intf);\r
-\r
-       int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);\r
-\r
-       const struct usb_device_id *id_table;\r
-\r
-       struct device_driver driver;\r
-\r
-       struct semaphore serialize;\r
-};\r
-#define        to_usb_driver(d) container_of(d, struct usb_driver, driver)\r
-\r
-extern struct bus_type usb_bus_type;\r
-\r
-/**\r
- * struct usb_class_driver - identifies a USB driver that wants to use the USB major number\r
- * @name: devfs name for this driver.  Will also be used by the driver\r
- *     class code to create a usb class device.\r
- * @fops: pointer to the struct file_operations of this driver.\r
- * @mode: the mode for the devfs file to be created for this driver.\r
- * @minor_base: the start of the minor range for this driver.\r
- *\r
- * This structure is used for the usb_register_dev() and\r
- * usb_unregister_dev() functions, to consolodate a number of the\r
- * paramaters used for them.\r
- */\r
-struct usb_class_driver {\r
-       char *name;\r
-       struct file_operations *fops;\r
-       mode_t mode;\r
-       int minor_base; \r
-};\r
-\r
-/*\r
- * use these in module_init()/module_exit()\r
- * and don't forget MODULE_DEVICE_TABLE(usb, ...)\r
- */\r
-extern int usb_register(struct usb_driver *);\r
-extern void usb_deregister(struct usb_driver *);\r
-\r
-extern int usb_register_dev(struct usb_interface *intf,\r
-                           struct usb_class_driver *class_driver);\r
-extern void usb_deregister_dev(struct usb_interface *intf,\r
-                              struct usb_class_driver *class_driver);\r
-\r
-extern int usb_device_probe(struct device *dev);\r
-extern int usb_device_remove(struct device *dev);\r
-extern int STDCALL usb_disabled(void);\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/*\r
- * URB support, for asynchronous request completions\r
- */\r
-\r
-/*\r
- * urb->transfer_flags:\r
- */\r
-#define URB_SHORT_NOT_OK       0x0001  /* report short reads as errors */\r
-#define URB_ISO_ASAP           0x0002  /* iso-only, urb->start_frame ignored */\r
-#define URB_NO_DMA_MAP         0x0004  /* urb->*_dma are valid on submit */\r
-#define URB_ASYNC_UNLINK       0x0008  /* usb_unlink_urb() returns asap */\r
-#define URB_NO_FSBR            0x0020  /* UHCI-specific */\r
-#define URB_ZERO_PACKET                0x0040  /* Finish bulk OUTs with short packet */\r
-#define URB_NO_INTERRUPT       0x0080  /* HINT: no non-error interrupt needed */\r
-\r
-struct usb_iso_packet_descriptor {\r
-       unsigned int offset;\r
-       unsigned int length;            /* expected length */\r
-       unsigned int actual_length;\r
-       unsigned int status;\r
-};\r
-\r
-struct urb;\r
-struct pt_regs;\r
-\r
-typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);\r
-\r
-/**\r
- * struct urb - USB Request Block\r
- * @urb_list: For use by current owner of the URB.\r
- * @pipe: Holds endpoint number, direction, type, and more.\r
- *     Create these values with the eight macros available;\r
- *     usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl"\r
- *     (control), "bulk", "int" (interrupt), or "iso" (isochronous).\r
- *     For example usb_sndbulkpipe() or usb_rcvintpipe().  Endpoint\r
- *     numbers range from zero to fifteen.  Note that "in" endpoint two\r
- *     is a different endpoint (and pipe) from "out" endpoint two.\r
- *     The current configuration controls the existence, type, and\r
- *     maximum packet size of any given endpoint.\r
- * @dev: Identifies the USB device to perform the request.\r
- * @status: This is read in non-iso completion functions to get the\r
- *     status of the particular request.  ISO requests only use it\r
- *     to tell whether the URB was unlinked; detailed status for\r
- *     each frame is in the fields of the iso_frame-desc.\r
- * @transfer_flags: A variety of flags may be used to affect how URB\r
- *     submission, unlinking, or operation are handled.  Different\r
- *     kinds of URB can use different flags.\r
- * @transfer_buffer:  This identifies the buffer to (or from) which\r
- *     the I/O request will be performed (unless URB_NO_DMA_MAP is set).\r
- *     This buffer must be suitable for DMA; allocate it with kmalloc()\r
- *     or equivalent.  For transfers to "in" endpoints, contents of\r
- *     this buffer will be modified.  This buffer is used for data\r
- *     phases of control transfers.\r
- * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device\r
- *     driver is saying that it provided this DMA address, which the host\r
- *     controller driver should use instead of the transfer_buffer.\r
- * @transfer_buffer_length: How big is transfer_buffer.  The transfer may\r
- *     be broken up into chunks according to the current maximum packet\r
- *     size for the endpoint, which is a function of the configuration\r
- *     and is encoded in the pipe.  When the length is zero, neither\r
- *     transfer_buffer nor transfer_dma is used.\r
- * @actual_length: This is read in non-iso completion functions, and\r
- *     it tells how many bytes (out of transfer_buffer_length) were\r
- *     transferred.  It will normally be the same as requested, unless\r
- *     either an error was reported or a short read was performed.\r
- *     The URB_SHORT_NOT_OK transfer flag may be used to make such\r
- *     short reads be reported as errors. \r
- * @setup_packet: Only used for control transfers, this points to eight bytes\r
- *     of setup data.  Control transfers always start by sending this data\r
- *     to the device.  Then transfer_buffer is read or written, if needed.\r
- *     (Not used when URB_NO_DMA_MAP is set.)\r
- * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device\r
- *     driver has provided this DMA address for the setup packet.  The\r
- *     host controller driver should use this instead of setup_buffer.\r
- *     If there is a data phase, its buffer is identified by transfer_dma.\r
- * @start_frame: Returns the initial frame for interrupt or isochronous\r
- *     transfers.\r
- * @number_of_packets: Lists the number of ISO transfer buffers.\r
- * @interval: Specifies the polling interval for interrupt or isochronous\r
- *     transfers.  The units are frames (milliseconds) for for full and low\r
- *     speed devices, and microframes (1/8 millisecond) for highspeed ones.\r
- * @error_count: Returns the number of ISO transfers that reported errors.\r
- * @context: For use in completion functions.  This normally points to\r
- *     request-specific driver context.\r
- * @complete: Completion handler. This URB is passed as the parameter to the\r
- *     completion function.  The completion function may then do what\r
- *     it likes with the URB, including resubmitting or freeing it.\r
- * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to \r
- *     collect the transfer status for each buffer.\r
- *\r
- * This structure identifies USB transfer requests.  URBs must be allocated by\r
- * calling usb_alloc_urb() and freed with a call to usb_free_urb().\r
- * Initialization may be done using various usb_fill_*_urb() functions.  URBs\r
- * are submitted using usb_submit_urb(), and pending requests may be canceled\r
- * using usb_unlink_urb().\r
- *\r
- * Data Transfer Buffers:\r
- *\r
- * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise\r
- * taken from the general page pool.  That is provided by transfer_buffer\r
- * (control requests also use setup_packet), and host controller drivers\r
- * perform a dma mapping (and unmapping) for each buffer transferred.  Those\r
- * mapping operations can be expensive on some platforms (perhaps using a dma\r
- * bounce buffer or talking to an IOMMU),\r
- * although they're cheap on commodity x86 and ppc hardware.\r
- *\r
- * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which\r
- * tells the host controller driver that no such mapping is needed since\r
- * the device driver is DMA-aware.  For example, they might allocate a DMA\r
- * buffer with usb_buffer_alloc(), or call usb_buffer_map().\r
- * When this transfer flag is provided, host controller drivers will use the\r
- * dma addresses found in the transfer_dma and/or setup_dma fields rather than\r
- * determing a dma address themselves.\r
- *\r
- * Initialization:\r
- *\r
- * All URBs submitted must initialize dev, pipe,\r
- * transfer_flags (may be zero), complete, timeout (may be zero).\r
- * The URB_ASYNC_UNLINK transfer flag affects later invocations of\r
- * the usb_unlink_urb() routine.\r
- *\r
- * All URBs must also initialize \r
- * transfer_buffer and transfer_buffer_length.  They may provide the\r
- * URB_SHORT_NOT_OK transfer flag, indicating that short reads are\r
- * to be treated as errors; that flag is invalid for write requests.\r
- *\r
- * Bulk URBs may\r
- * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers\r
- * should always terminate with a short packet, even if it means adding an\r
- * extra zero length packet.\r
- *\r
- * Control URBs must provide a setup_packet.\r
- *\r
- * Interrupt UBS must provide an interval, saying how often (in milliseconds\r
- * or, for highspeed devices, 125 microsecond units)\r
- * to poll for transfers.  After the URB has been submitted, the interval\r
- * and start_frame fields reflect how the transfer was actually scheduled.\r
- * The polling interval may be more frequent than requested.\r
- * For example, some controllers have a maximum interval of 32 microseconds,\r
- * while others support intervals of up to 1024 microseconds.\r
- * Isochronous URBs also have transfer intervals.  (Note that for isochronous\r
- * endpoints, as well as high speed interrupt endpoints, the encoding of\r
- * the transfer interval in the endpoint descriptor is logarithmic.)\r
- *\r
- * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling\r
- * the host controller to schedule the transfer as soon as bandwidth\r
- * utilization allows, and then set start_frame to reflect the actual frame\r
- * selected during submission.  Otherwise drivers must specify the start_frame\r
- * and handle the case where the transfer can't begin then.  However, drivers\r
- * won't know how bandwidth is currently allocated, and while they can\r
- * find the current frame using usb_get_current_frame_number () they can't\r
- * know the range for that frame number.  (Ranges for frame counter values\r
- * are HC-specific, and can go from 256 to 65536 frames from "now".)\r
- *\r
- * Isochronous URBs have a different data transfer model, in part because\r
- * the quality of service is only "best effort".  Callers provide specially\r
- * allocated URBs, with number_of_packets worth of iso_frame_desc structures\r
- * at the end.  Each such packet is an individual ISO transfer.  Isochronous\r
- * URBs are normally queued, submitted by drivers to arrange that\r
- * transfers are at least double buffered, and then explicitly resubmitted\r
- * in completion handlers, so\r
- * that data (such as audio or video) streams at as constant a rate as the\r
- * host controller scheduler can support.\r
- *\r
- * Completion Callbacks:\r
- *\r
- * The completion callback is made in_interrupt(), and one of the first\r
- * things that a completion handler should do is check the status field.\r
- * The status field is provided for all URBs.  It is used to report\r
- * unlinked URBs, and status for all non-ISO transfers.  It should not\r
- * be examined before the URB is returned to the completion handler.\r
- *\r
- * The context field is normally used to link URBs back to the relevant\r
- * driver or request state.\r
- *\r
- * When completion callback is invoked for non-isochronous URBs, the\r
- * actual_length field tells how many bytes were transferred.\r
- *\r
- * ISO transfer status is reported in the status and actual_length fields\r
- * of the iso_frame_desc array, and the number of errors is reported in\r
- * error_count.  Completion callbacks for ISO transfers will normally\r
- * (re)submit URBs to ensure a constant transfer rate.\r
- */\r
-struct urb\r
-{\r
-       spinlock_t lock;                /* lock for the URB */\r
-       atomic_t count;                 /* reference count of the URB */\r
-       void *hcpriv;                   /* private data for host controller */\r
-       struct list_head urb_list;      /* list pointer to all active urbs */\r
-       struct usb_device *dev;         /* (in) pointer to associated device */\r
-       unsigned int pipe;              /* (in) pipe information */\r
-       int status;                     /* (return) non-ISO status */\r
-       unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/\r
-       void *transfer_buffer;          /* (in) associated data buffer */\r
-       dma_addr_t transfer_dma;        /* (in) dma addr for transfer_buffer */\r
-       int transfer_buffer_length;     /* (in) data buffer length */\r
-       int actual_length;              /* (return) actual transfer length */\r
-       int bandwidth;                  /* bandwidth for INT/ISO request */\r
-       unsigned char *setup_packet;    /* (in) setup packet (control only) */\r
-       dma_addr_t setup_dma;           /* (in) dma addr for setup_packet */\r
-       int start_frame;                /* (modify) start frame (INT/ISO) */\r
-       int number_of_packets;          /* (in) number of ISO packets */\r
-       int interval;                   /* (in) transfer interval (INT/ISO) */\r
-       int error_count;                /* (return) number of ISO errors */\r
-       int timeout;                    /* (in) timeout, in jiffies */\r
-       void *context;                  /* (in) context for completion */\r
-       usb_complete_t complete;        /* (in) completion routine */\r
-       struct usb_iso_packet_descriptor iso_frame_desc[0];     /* (in) ISO ONLY */\r
-};\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/**\r
- * usb_fill_control_urb - initializes a control urb\r
- * @urb: pointer to the urb to initialize.\r
- * @dev: pointer to the struct usb_device for this urb.\r
- * @pipe: the endpoint pipe\r
- * @setup_packet: pointer to the setup_packet buffer\r
- * @transfer_buffer: pointer to the transfer buffer\r
- * @buffer_length: length of the transfer buffer\r
- * @complete: pointer to the usb_complete_t function\r
- * @context: what to set the urb context to.\r
- *\r
- * Initializes a control urb with the proper information needed to submit\r
- * it to a device.\r
- */\r
-static inline void usb_fill_control_urb (struct urb *urb,\r
-                                        struct usb_device *dev,\r
-                                        unsigned int pipe,\r
-                                        unsigned char *setup_packet,\r
-                                        void *transfer_buffer,\r
-                                        int buffer_length,\r
-                                        usb_complete_t complete,\r
-                                        void *context)\r
-{\r
-       spin_lock_init(&urb->lock);\r
-       urb->dev = dev;\r
-       urb->pipe = pipe;\r
-       urb->setup_packet = setup_packet;\r
-       urb->transfer_buffer = transfer_buffer;\r
-       urb->transfer_buffer_length = buffer_length;\r
-       urb->complete = complete;\r
-       urb->context = context;\r
-}\r
-\r
-/**\r
- * usb_fill_bulk_urb - macro to help initialize a bulk urb\r
- * @urb: pointer to the urb to initialize.\r
- * @dev: pointer to the struct usb_device for this urb.\r
- * @pipe: the endpoint pipe\r
- * @transfer_buffer: pointer to the transfer buffer\r
- * @buffer_length: length of the transfer buffer\r
- * @complete: pointer to the usb_complete_t function\r
- * @context: what to set the urb context to.\r
- *\r
- * Initializes a bulk urb with the proper information needed to submit it\r
- * to a device.\r
- */\r
-static inline void usb_fill_bulk_urb (struct urb *urb,\r
-                                     struct usb_device *dev,\r
-                                     unsigned int pipe,\r
-                                     void *transfer_buffer,\r
-                                     int buffer_length,\r
-                                     usb_complete_t complete,\r
-                                     void *context)\r
-{\r
-       spin_lock_init(&urb->lock);\r
-       urb->dev = dev;\r
-       urb->pipe = pipe;\r
-       urb->transfer_buffer = transfer_buffer;\r
-       urb->transfer_buffer_length = buffer_length;\r
-       urb->complete = complete;\r
-       urb->context = context;\r
-}\r
-\r
-/**\r
- * usb_fill_int_urb - macro to help initialize a interrupt urb\r
- * @urb: pointer to the urb to initialize.\r
- * @dev: pointer to the struct usb_device for this urb.\r
- * @pipe: the endpoint pipe\r
- * @transfer_buffer: pointer to the transfer buffer\r
- * @buffer_length: length of the transfer buffer\r
- * @complete: pointer to the usb_complete_t function\r
- * @context: what to set the urb context to.\r
- * @interval: what to set the urb interval to, encoded like\r
- *     the endpoint descriptor's bInterval value.\r
- *\r
- * Initializes a interrupt urb with the proper information needed to submit\r
- * it to a device.\r
- * Note that high speed interrupt endpoints use a logarithmic encoding of\r
- * the endpoint interval, and express polling intervals in microframes\r
- * (eight per millisecond) rather than in frames (one per millisecond).\r
- */\r
-static inline void usb_fill_int_urb (struct urb *urb,\r
-                                    struct usb_device *dev,\r
-                                    unsigned int pipe,\r
-                                    void *transfer_buffer,\r
-                                    int buffer_length,\r
-                                    usb_complete_t complete,\r
-                                    void *context,\r
-                                    int interval)\r
-{\r
-       spin_lock_init(&urb->lock);\r
-       urb->dev = dev;\r
-       urb->pipe = pipe;\r
-       urb->transfer_buffer = transfer_buffer;\r
-       urb->transfer_buffer_length = buffer_length;\r
-       urb->complete = complete;\r
-       urb->context = context;\r
-       if (dev->speed == USB_SPEED_HIGH)\r
-               urb->interval = 1 << (interval - 1);\r
-       else\r
-               urb->interval = interval;\r
-       urb->start_frame = -1;\r
-}\r
-\r
-extern void STDCALL usb_init_urb(struct urb *urb);\r
-extern struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags);\r
-extern void STDCALL usb_free_urb(struct urb *urb);\r
-#define usb_put_urb usb_free_urb\r
-extern struct urb STDCALL *usb_get_urb(struct urb *urb);\r
-extern int STDCALL usb_submit_urb(struct urb *urb, int mem_flags);\r
-extern int STDCALL usb_unlink_urb(struct urb *urb);\r
-\r
-#define HAVE_USB_BUFFERS\r
-void *usb_buffer_alloc (struct usb_device *dev, size_t size,\r
-       int mem_flags, dma_addr_t *dma);\r
-void usb_buffer_free (struct usb_device *dev, size_t size,\r
-       void *addr, dma_addr_t dma);\r
-\r
-struct urb *usb_buffer_map (struct urb *urb);\r
-void usb_buffer_dmasync (struct urb *urb);\r
-void usb_buffer_unmap (struct urb *urb);\r
-\r
-struct scatterlist;\r
-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,\r
-               struct scatterlist *sg, int nents);\r
-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,\r
-               struct scatterlist *sg, int n_hw_ents);\r
-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,\r
-               struct scatterlist *sg, int n_hw_ents);\r
-\r
-/*-------------------------------------------------------------------*\r
- *                         SYNCHRONOUS CALL SUPPORT                  *\r
- *-------------------------------------------------------------------*/\r
-\r
-extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,\r
-       __u8 request, __u8 requesttype, __u16 value, __u16 index,\r
-       void *data, __u16 size, int timeout);\r
-extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,\r
-       void *data, int len, int *actual_length,\r
-       int timeout);\r
-\r
-/* wrappers around usb_control_msg() for the most common standard requests */\r
-extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,\r
-       unsigned char descindex, void *buf, int size);\r
-extern int usb_get_device_descriptor(struct usb_device *dev);\r
-extern int usb_get_status(struct usb_device *dev,\r
-       int type, int target, void *data);\r
-extern int usb_get_string(struct usb_device *dev,\r
-       unsigned short langid, unsigned char index, void *buf, int size);\r
-extern int usb_string(struct usb_device *dev, int index,\r
-       char *buf, size_t size);\r
-\r
-/* wrappers that also update important state inside usbcore */\r
-extern int usb_clear_halt(struct usb_device *dev, int pipe);\r
-extern int usb_set_configuration(struct usb_device *dev, int configuration);\r
-extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);\r
-\r
-/*\r
- * timeouts, in seconds, used for sending/receiving control messages\r
- * they typically complete within a few frames (msec) after they're issued\r
- * USB identifies 5 second timeouts, maybe more in a few cases, and a few\r
- * slow devices (like some MGE Ellipse UPSes) actually push that limit.\r
- */\r
-#define USB_CTRL_GET_TIMEOUT   5\r
-#define USB_CTRL_SET_TIMEOUT   5\r
-\r
-\r
-/**\r
- * struct usb_sg_request - support for scatter/gather I/O\r
- * @status: zero indicates success, else negative errno\r
- * @bytes: counts bytes transferred.\r
- *\r
- * These requests are initialized using usb_sg_init(), and then are used\r
- * as request handles passed to usb_sg_wait() or usb_sg_cancel().  Most\r
- * members of the request object aren't for driver access.\r
- *\r
- * The status and bytecount values are valid only after usb_sg_wait()\r
- * returns.  If the status is zero, then the bytecount matches the total\r
- * from the request.\r
- *\r
- * After an error completion, drivers may need to clear a halt condition\r
- * on the endpoint.\r
- */\r
-struct usb_sg_request {\r
-       int                     status;\r
-       size_t                  bytes;\r
-\r
-       // members not documented above are private to usbcore,\r
-       // and are not provided for driver access!\r
-       spinlock_t              lock;\r
-\r
-       struct usb_device       *dev;\r
-       int                     pipe;\r
-       struct scatterlist      *sg;\r
-       int                     nents;\r
-\r
-       int                     entries;\r
-       struct urb              **urbs;\r
-\r
-       int                     count;\r
-       struct completion       complete;\r
-};\r
-\r
-int usb_sg_init (\r
-       struct usb_sg_request   *io,\r
-       struct usb_device       *dev,\r
-       unsigned                pipe, \r
-       unsigned                period,\r
-       struct scatterlist      *sg,\r
-       int                     nents,\r
-       size_t                  length,\r
-       int                     mem_flags\r
-);\r
-void usb_sg_cancel (struct usb_sg_request *io);\r
-void usb_sg_wait (struct usb_sg_request *io);\r
-\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/*\r
- * Calling this entity a "pipe" is glorifying it. A USB pipe\r
- * is something embarrassingly simple: it basically consists\r
- * of the following information:\r
- *  - device number (7 bits)\r
- *  - endpoint number (4 bits)\r
- *  - current Data0/1 state (1 bit) [Historical; now gone]\r
- *  - direction (1 bit)\r
- *  - speed (1 bit) [Historical and specific to USB 1.1; now gone.]\r
- *  - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.]\r
- *  - pipe type (2 bits: control, interrupt, bulk, isochronous)\r
- *\r
- * That's 18 bits. Really. Nothing more. And the USB people have\r
- * documented these eighteen bits as some kind of glorious\r
- * virtual data structure.\r
- *\r
- * Let's not fall in that trap. We'll just encode it as a simple\r
- * unsigned int. The encoding is:\r
- *\r
- *  - max size:                bits 0-1        [Historical; now gone.]\r
- *  - direction:       bit 7           (0 = Host-to-Device [Out],\r
- *                                      1 = Device-to-Host [In] ...\r
- *                                     like endpoint bEndpointAddress)\r
- *  - device:          bits 8-14       ... bit positions known to uhci-hcd\r
- *  - endpoint:                bits 15-18      ... bit positions known to uhci-hcd\r
- *  - Data0/1:         bit 19          [Historical; now gone. ]\r
- *  - lowspeed:                bit 26          [Historical; now gone. ]\r
- *  - pipe type:       bits 30-31      (00 = isochronous, 01 = interrupt,\r
- *                                      10 = control, 11 = bulk)\r
- *\r
- * Why? Because it's arbitrary, and whatever encoding we select is really\r
- * up to us. This one happens to share a lot of bit positions with the UHCI\r
- * specification, so that much of the uhci driver can just mask the bits\r
- * appropriately.\r
- */\r
-\r
-/* NOTE:  these are not the standard USB_ENDPOINT_XFER_* values!! */\r
-#define PIPE_ISOCHRONOUS               0\r
-#define PIPE_INTERRUPT                 1\r
-#define PIPE_CONTROL                   2\r
-#define PIPE_BULK                      3\r
-\r
-#define usb_maxpacket(dev, pipe, out)  (out \\r
-                               ? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \\r
-                               : (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )\r
-\r
-#define usb_pipein(pipe)       ((pipe) & USB_DIR_IN)\r
-#define usb_pipeout(pipe)      (!usb_pipein(pipe))\r
-#define usb_pipedevice(pipe)   (((pipe) >> 8) & 0x7f)\r
-#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)\r
-#define usb_pipetype(pipe)     (((pipe) >> 30) & 3)\r
-#define usb_pipeisoc(pipe)     (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)\r
-#define usb_pipeint(pipe)      (usb_pipetype((pipe)) == PIPE_INTERRUPT)\r
-#define usb_pipecontrol(pipe)  (usb_pipetype((pipe)) == PIPE_CONTROL)\r
-#define usb_pipebulk(pipe)     (usb_pipetype((pipe)) == PIPE_BULK)\r
-\r
-/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */\r
-#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)\r
-#define        usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))\r
-#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))\r
-\r
-/* Endpoint halt control/status ... likewise USE WITH CAUTION */\r
-#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))\r
-#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))\r
-\r
-\r
-static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)\r
-{\r
-       return (dev->devnum << 8) | (endpoint << 15);\r
-}\r
-\r
-/* Create various pipes... */\r
-#define usb_sndctrlpipe(dev,endpoint)  ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))\r
-#define usb_rcvctrlpipe(dev,endpoint)  ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)\r
-#define usb_sndisocpipe(dev,endpoint)  ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))\r
-#define usb_rcvisocpipe(dev,endpoint)  ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)\r
-#define usb_sndbulkpipe(dev,endpoint)  ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))\r
-#define usb_rcvbulkpipe(dev,endpoint)  ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)\r
-#define usb_sndintpipe(dev,endpoint)   ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))\r
-#define usb_rcvintpipe(dev,endpoint)   ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)\r
-\r
-/* -------------------------------------------------------------------------- */\r
-\r
-/*\r
- * Debugging and troubleshooting/diagnostic helpers.\r
- */\r
-void usb_show_device_descriptor(struct usb_device_descriptor *);\r
-void usb_show_config_descriptor(struct usb_config_descriptor *);\r
-void usb_show_interface_descriptor(struct usb_interface_descriptor *);\r
-void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);\r
-void usb_show_device(struct usb_device *);\r
-void usb_show_string(struct usb_device *dev, char *id, int index);\r
-\r
-#ifdef DEBUG\r
-#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg)\r
-#else\r
-#define dbg(format, arg...) do {} while (0)\r
-#endif\r
-\r
-\r
-\r
-#ifdef DEBUG_MODE\r
-#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)\r
-#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)\r
-#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)\r
-#endif\r
-\r
-#ifndef DEBUG_MODE                                                               \r
-#define info(format, arg...) do {} while (0)\r
-#define err(format, arg...) do {} while (0)\r
-#define warn(format, arg...) do {} while (0)\r
-#endif\r
-\r
-#endif  /* __KERNEL__ */\r
-\r
-#endif\r
+#ifndef __LINUX_USB_H
+#define __LINUX_USB_H
+
+
+#include "usb_ch9.h"
+
+#define USB_MAJOR                      180
+
+
+#ifdef __KERNEL__
+#if 0
+#include <linux/config.h>
+#include <linux/errno.h>        /* for -ENODEV */
+#include <linux/delay.h>       /* for mdelay() */
+#include <linux/interrupt.h>   /* for in_interrupt() */
+#include <linux/list.h>                /* for struct list_head */
+#include <linux/device.h>      /* for struct device */
+#include <linux/fs.h>          /* for struct file_operations */
+#include <linux/completion.h>  /* for struct completion */
+#include <linux/sched.h>       /* for current && schedule_timeout */
+
+
+static __inline__ void wait_ms(unsigned int ms)
+{
+       if(!in_interrupt()) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(1 + ms * HZ / 1000);
+       }
+       else
+               mdelay(ms);
+}
+#endif
+struct usb_device;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Host-side wrappers for standard USB descriptors ... these are parsed
+ * from the data provided by devices.  Parsing turns them from a flat
+ * sequence of descriptors into a hierarchy:
+ *
+ *  - devices have one (usually) or more configs;
+ *  - configs have one (often) or more interfaces;
+ *  - interfaces have one (usually) or more settings;
+ *  - each interface setting has zero or (usually) more endpoints.
+ *
+ * And there might be other descriptors mixed in with those.
+ *
+ * Devices may also have class-specific or vendor-specific descriptors.
+ */
+
+/* host-side wrapper for parsed endpoint descriptors */
+struct usb_host_endpoint {
+       struct usb_endpoint_descriptor  desc;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+/* host-side wrapper for one interface setting's parsed descriptors */
+struct usb_host_interface {
+       struct usb_interface_descriptor desc;
+
+       /* array of desc.bNumEndpoint endpoints associated with this
+        * interface setting.  these will be in no particular order.
+        */
+       struct usb_host_endpoint *endpoint;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+/**
+ * struct usb_interface - what usb device drivers talk to
+ * @altsetting: array of interface descriptors, one for each alternate
+ *     setting that may be selected.  Each one includes a set of
+ *     endpoint configurations and will be in numberic order,
+ *     0..num_altsetting.
+ * @num_altsetting: number of altsettings defined.
+ * @act_altsetting: index of current altsetting.  this number is always
+ *     less than num_altsetting.  after the device is configured, each
+ *     interface uses its default setting of zero.
+ * @max_altsetting:
+ * @minor: the minor number assigned to this interface, if this
+ *     interface is bound to a driver that uses the USB major number.
+ *     If this interface does not use the USB major, this field should
+ *     be unused.  The driver should set this value in the probe()
+ *     function of the driver, after it has been assigned a minor
+ *     number from the USB core by calling usb_register_dev().
+ * @dev: driver model's view of this device
+ * @class_dev: driver model's class view of this device.
+ *
+ * USB device drivers attach to interfaces on a physical device.  Each
+ * interface encapsulates a single high level function, such as feeding
+ * an audio stream to a speaker or reporting a change in a volume control.
+ * Many USB devices only have one interface.  The protocol used to talk to
+ * an interface's endpoints can be defined in a usb "class" specification,
+ * or by a product's vendor.  The (default) control endpoint is part of
+ * every interface, but is never listed among the interface's descriptors.
+ *
+ * The driver that is bound to the interface can use standard driver model
+ * calls such as dev_get_drvdata() on the dev member of this structure.
+ *
+ * Each interface may have alternate settings.  The initial configuration
+ * of a device sets the first of these, but the device driver can change
+ * that setting using usb_set_interface().  Alternate settings are often
+ * used to control the the use of periodic endpoints, such as by having
+ * different endpoints use different amounts of reserved USB bandwidth.
+ * All standards-conformant USB devices that use isochronous endpoints
+ * will use them in non-default settings.
+ */
+struct usb_interface {
+       /* array of alternate settings for this interface.
+        * these will be in numeric order, 0..num_altsettting
+        */
+       struct usb_host_interface *altsetting;
+
+       unsigned act_altsetting;        /* active alternate setting */
+       unsigned num_altsetting;        /* number of alternate settings */
+       unsigned max_altsetting;        /* total memory allocated */
+
+       struct usb_driver *driver;      /* driver */
+       int minor;                      /* minor number this interface is bound to */
+       struct device dev;              /* interface specific device info */
+       struct class_device class_dev;
+};
+#define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
+#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev)
+#define        interface_to_usbdev(intf) \
+       container_of(intf->dev.parent, struct usb_device, dev)
+
+static inline void *usb_get_intfdata (struct usb_interface *intf)
+{
+       return dev_get_drvdata (&intf->dev);
+}
+
+static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
+{
+       dev_set_drvdata(&intf->dev, data);
+}
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different.  Highspeed-capable devices can look
+ * different depending on what speed they're currently running.  Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG.
+ */
+struct usb_host_config {
+       struct usb_config_descriptor    desc;
+
+       /* the interfaces associated with this configuration
+        * these will be in numeric order, 0..desc.bNumInterfaces
+        */
+       struct usb_interface *interface;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+// FIXME remove; exported only for drivers/usb/misc/auserwald.c
+// prefer usb_device->epnum[0..31]
+extern struct usb_endpoint_descriptor *
+       usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);
+
+int __usb_get_extra_descriptor(char *buffer, unsigned size,
+       unsigned char type, void **ptr);
+#define usb_get_extra_descriptor(ifpoint,type,ptr)\
+       __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\
+               type,(void**)ptr)
+
+/* -------------------------------------------------------------------------- */
+
+struct usb_operations;
+
+/* USB device number allocation bitmap */
+struct usb_devmap {
+       unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+};
+
+/*
+ * Allocated per bus (tree of devices) we have:
+ */
+struct usb_bus {
+       struct device *controller;      /* host/master side hardware */
+       int busnum;                     /* Bus number (in order of reg) */
+       char *bus_name;                 /* stable id (PCI slot_name etc) */
+
+       int devnum_next;                /* Next open device number in round-robin allocation */
+
+       struct usb_devmap devmap;       /* device address allocation map */
+       struct usb_operations *op;      /* Operations (specific to the HC) */
+       struct usb_device *root_hub;    /* Root hub */
+       struct list_head bus_list;      /* list of busses */
+       void *hcpriv;                   /* Host Controller private data */
+
+       int bandwidth_allocated;        /* on this bus: how much of the time
+                                        * reserved for periodic (intr/iso)
+                                        * requests is used, on average?
+                                        * Units: microseconds/frame.
+                                        * Limits: Full/low speed reserve 90%,
+                                        * while high speed reserves 80%.
+                                        */
+       int bandwidth_int_reqs;         /* number of Interrupt requests */
+       int bandwidth_isoc_reqs;        /* number of Isoc. requests */
+
+       struct dentry *usbfs_dentry;    /* usbfs dentry entry for the bus */
+       struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the bus */
+
+       atomic_t refcnt;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+/* This is arbitrary.
+ * From USB 2.0 spec Table 11-13, offset 7, a hub can
+ * have up to 255 ports. The most yet reported is 10.
+ */
+#define USB_MAXCHILDREN                (16)
+
+struct usb_tt;
+
+struct usb_device {
+       int             devnum;         /* Address on USB bus */
+       char            devpath [16];   /* Use in messages: /port/port/... */
+       enum usb_device_state   state;  /* configured, not attached, etc */
+       enum usb_device_speed   speed;  /* high/full/low (or error) */
+
+       struct usb_tt   *tt;            /* low/full speed dev, highspeed hub */
+       int             ttport;         /* device port on that tt hub */
+
+       struct semaphore serialize;
+
+       unsigned int toggle[2];         /* one bit for each endpoint ([0] = IN, [1] = OUT) */
+       unsigned int halted[2];         /* endpoint halts; one bit per endpoint # & direction; */
+                                       /* [0] = IN, [1] = OUT */
+       int epmaxpacketin[16];          /* INput endpoint specific maximums */
+       int epmaxpacketout[16];         /* OUTput endpoint specific maximums */
+
+       struct usb_device *parent;      /* our hub, unless we're the root */
+       struct usb_bus *bus;            /* Bus we're part of */
+
+       struct device dev;              /* Generic device interface */
+
+       struct usb_device_descriptor descriptor;/* Descriptor */
+       struct usb_host_config *config; /* All of the configs */
+       struct usb_host_config *actconfig;/* the active configuration */
+
+       char **rawdescriptors;          /* Raw descriptors for each config */
+
+       int have_langid;                /* whether string_langid is valid yet */
+       int string_langid;              /* language ID for strings */
+
+       void *hcpriv;                   /* Host Controller private data */
+       
+       struct list_head filelist;
+       struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */
+       struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the device */
+
+       /*
+        * Child devices - these can be either new devices
+        * (if this is a hub device), or different instances
+        * of this same device.
+        *
+        * Each instance needs its own set of data structures.
+        */
+
+       int maxchild;                   /* Number of ports if hub */
+       struct usb_device *children[USB_MAXCHILDREN];
+};
+#define        to_usb_device(d) container_of(d, struct usb_device, dev)
+
+extern struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *);
+extern struct usb_device STDCALL *usb_get_dev(struct usb_device *dev);
+extern void STDCALL usb_put_dev(struct usb_device *dev);
+
+/* mostly for devices emulating SCSI over USB */
+extern int usb_reset_device(struct usb_device *dev);
+
+extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
+
+/* for drivers using iso endpoints */
+extern int usb_get_current_frame_number (struct usb_device *usb_dev);
+
+/* used these for multi-interface device registration */
+extern void usb_driver_claim_interface(struct usb_driver *driver,
+                       struct usb_interface *iface, void* priv);
+extern int usb_interface_claimed(struct usb_interface *iface);
+extern void usb_driver_release_interface(struct usb_driver *driver,
+                       struct usb_interface *iface);
+const struct usb_device_id *usb_match_id(struct usb_interface *interface,
+                                        const struct usb_device_id *id);
+
+extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor);
+extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+
+
+/**
+ * usb_make_path - returns stable device path in the usb tree
+ * @dev: the device whose path is being constructed
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ *
+ * Returns length of the string (> 0) or negative if size was too small.
+ *
+ * This identifier is intended to be "stable", reflecting physical paths in
+ * hardware such as physical bus addresses for host controllers or ports on
+ * USB hubs.  That makes it stay the same until systems are physically
+ * reconfigured, by re-cabling a tree of USB devices or by moving USB host
+ * controllers.  Adding and removing devices, including virtual root hubs
+ * in host controller driver modules, does not change these path identifers;
+ * neither does rebooting or re-enumerating.  These are more useful identifiers
+ * than changeable ("unstable") ones like bus numbers or device addresses.
+ *
+ * With a partial exception for devices connected to USB 2.0 root hubs, these
+ * identifiers are also predictable.  So long as the device tree isn't changed,
+ * plugging any USB device into a given hub port always gives it the same path.
+ * Because of the use of "companion" controllers, devices connected to ports on
+ * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
+ * high speed, and a different one if they are full or low speed.
+ */
+static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
+{
+       int actual;
+       actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath);
+       return (actual >= size) ? -1 : actual;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define USB_DEVICE_ID_MATCH_DEVICE             (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+#define USB_DEVICE_ID_MATCH_DEV_RANGE          (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)
+#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)
+#define USB_DEVICE_ID_MATCH_DEV_INFO \
+       (USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
+#define USB_DEVICE_ID_MATCH_INT_INFO \
+       (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)
+
+/**
+ * USB_DEVICE - macro used to describe a specific usb device
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific device.
+ */
+#define USB_DEVICE(vend,prod) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), .idProduct = (prod)
+/**
+ * USB_DEVICE_VER - macro used to describe a specific usb device with a version range
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ * @lo: the bcdDevice_lo value
+ * @hi: the bcdDevice_hi value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific device, with a version range.
+ */
+#define USB_DEVICE_VER(vend,prod,lo,hi) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
+
+/**
+ * USB_DEVICE_INFO - macro used to describe a class of usb devices
+ * @cl: bDeviceClass value
+ * @sc: bDeviceSubClass value
+ * @pr: bDeviceProtocol value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific class of devices.
+ */
+#define USB_DEVICE_INFO(cl,sc,pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), .bDeviceSubClass = (sc), .bDeviceProtocol = (pr)
+
+/**
+ * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces 
+ * @cl: bInterfaceClass value
+ * @sc: bInterfaceSubClass value
+ * @pr: bInterfaceProtocol value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific class of interfaces.
+ */
+#define USB_INTERFACE_INFO(cl,sc,pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct usb_driver - identifies USB driver to usbcore
+ * @owner: Pointer to the module owner of this driver; initialize
+ *     it using THIS_MODULE.
+ * @name: The driver name should be unique among USB drivers,
+ *     and should normally be the same as the module name.
+ * @probe: Called to see if the driver is willing to manage a particular
+ *     interface on a device.  If it is, probe returns zero and uses
+ *     dev_set_drvdata() to associate driver-specific data with the
+ *     interface.  It may also use usb_set_interface() to specify the
+ *     appropriate altsetting.  If unwilling to manage the interface,
+ *     return a negative errno value.
+ * @disconnect: Called when the interface is no longer accessible, usually
+ *     because its device has been (or is being) disconnected or the
+ *     driver module is being unloaded.
+ * @ioctl: Used for drivers that want to talk to userspace through
+ *     the "usbfs" filesystem.  This lets devices provide ways to
+ *     expose information to user space regardless of where they
+ *     do (or don't) show up otherwise in the filesystem.
+ * @id_table: USB drivers use ID table to support hotplugging.
+ *     Export this with MODULE_DEVICE_TABLE(usb,...).  This must be set
+ *     or your driver's probe function will never get called. 
+ *
+ * USB drivers must provide a name, probe() and disconnect() methods,
+ * and an id_table.  Other driver fields are optional.
+ *
+ * The id_table is used in hotplugging.  It holds a set of descriptors,
+ * and specialized data may be associated with each entry.  That table
+ * is used by both user and kernel mode hotplugging support.
+ *
+ * The probe() and disconnect() methods are called in a context where
+ * they can sleep, but they should avoid abusing the privilege.  Most
+ * work to connect to a device should be done when the device is opened,
+ * and undone at the last close.  The disconnect code needs to address
+ * concurrency issues with respect to open() and close() methods, as
+ * well as forcing all pending I/O requests to complete (by unlinking
+ * them as necessary, and blocking until the unlinks complete).
+ */
+struct usb_driver {
+       struct module *owner;
+
+       const char *name;
+
+       int (*probe) (struct usb_interface *intf,
+                     const struct usb_device_id *id);
+
+       void (*disconnect) (struct usb_interface *intf);
+
+       int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
+
+       const struct usb_device_id *id_table;
+
+       struct device_driver driver;
+
+       struct semaphore serialize;
+};
+#define        to_usb_driver(d) container_of(d, struct usb_driver, driver)
+
+extern struct bus_type usb_bus_type;
+
+/**
+ * struct usb_class_driver - identifies a USB driver that wants to use the USB major number
+ * @name: devfs name for this driver.  Will also be used by the driver
+ *     class code to create a usb class device.
+ * @fops: pointer to the struct file_operations of this driver.
+ * @mode: the mode for the devfs file to be created for this driver.
+ * @minor_base: the start of the minor range for this driver.
+ *
+ * This structure is used for the usb_register_dev() and
+ * usb_unregister_dev() functions, to consolodate a number of the
+ * paramaters used for them.
+ */
+struct usb_class_driver {
+       char *name;
+       struct file_operations *fops;
+       mode_t mode;
+       int minor_base; 
+};
+
+/*
+ * use these in module_init()/module_exit()
+ * and don't forget MODULE_DEVICE_TABLE(usb, ...)
+ */
+extern int usb_register(struct usb_driver *);
+extern void usb_deregister(struct usb_driver *);
+
+extern int usb_register_dev(struct usb_interface *intf,
+                           struct usb_class_driver *class_driver);
+extern void usb_deregister_dev(struct usb_interface *intf,
+                              struct usb_class_driver *class_driver);
+
+extern int usb_device_probe(struct device *dev);
+extern int usb_device_remove(struct device *dev);
+extern int STDCALL usb_disabled(void);
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * URB support, for asynchronous request completions
+ */
+
+/*
+ * urb->transfer_flags:
+ */
+#define URB_SHORT_NOT_OK       0x0001  /* report short reads as errors */
+#define URB_ISO_ASAP           0x0002  /* iso-only, urb->start_frame ignored */
+#define URB_NO_DMA_MAP         0x0004  /* urb->*_dma are valid on submit */
+#define URB_ASYNC_UNLINK       0x0008  /* usb_unlink_urb() returns asap */
+#define URB_NO_FSBR            0x0020  /* UHCI-specific */
+#define URB_ZERO_PACKET                0x0040  /* Finish bulk OUTs with short packet */
+#define URB_NO_INTERRUPT       0x0080  /* HINT: no non-error interrupt needed */
+
+struct usb_iso_packet_descriptor {
+       unsigned int offset;
+       unsigned int length;            /* expected length */
+       unsigned int actual_length;
+       unsigned int status;
+};
+
+struct urb;
+struct pt_regs;
+
+typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
+
+/**
+ * struct urb - USB Request Block
+ * @urb_list: For use by current owner of the URB.
+ * @pipe: Holds endpoint number, direction, type, and more.
+ *     Create these values with the eight macros available;
+ *     usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl"
+ *     (control), "bulk", "int" (interrupt), or "iso" (isochronous).
+ *     For example usb_sndbulkpipe() or usb_rcvintpipe().  Endpoint
+ *     numbers range from zero to fifteen.  Note that "in" endpoint two
+ *     is a different endpoint (and pipe) from "out" endpoint two.
+ *     The current configuration controls the existence, type, and
+ *     maximum packet size of any given endpoint.
+ * @dev: Identifies the USB device to perform the request.
+ * @status: This is read in non-iso completion functions to get the
+ *     status of the particular request.  ISO requests only use it
+ *     to tell whether the URB was unlinked; detailed status for
+ *     each frame is in the fields of the iso_frame-desc.
+ * @transfer_flags: A variety of flags may be used to affect how URB
+ *     submission, unlinking, or operation are handled.  Different
+ *     kinds of URB can use different flags.
+ * @transfer_buffer:  This identifies the buffer to (or from) which
+ *     the I/O request will be performed (unless URB_NO_DMA_MAP is set).
+ *     This buffer must be suitable for DMA; allocate it with kmalloc()
+ *     or equivalent.  For transfers to "in" endpoints, contents of
+ *     this buffer will be modified.  This buffer is used for data
+ *     phases of control transfers.
+ * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device
+ *     driver is saying that it provided this DMA address, which the host
+ *     controller driver should use instead of the transfer_buffer.
+ * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
+ *     be broken up into chunks according to the current maximum packet
+ *     size for the endpoint, which is a function of the configuration
+ *     and is encoded in the pipe.  When the length is zero, neither
+ *     transfer_buffer nor transfer_dma is used.
+ * @actual_length: This is read in non-iso completion functions, and
+ *     it tells how many bytes (out of transfer_buffer_length) were
+ *     transferred.  It will normally be the same as requested, unless
+ *     either an error was reported or a short read was performed.
+ *     The URB_SHORT_NOT_OK transfer flag may be used to make such
+ *     short reads be reported as errors. 
+ * @setup_packet: Only used for control transfers, this points to eight bytes
+ *     of setup data.  Control transfers always start by sending this data
+ *     to the device.  Then transfer_buffer is read or written, if needed.
+ *     (Not used when URB_NO_DMA_MAP is set.)
+ * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device
+ *     driver has provided this DMA address for the setup packet.  The
+ *     host controller driver should use this instead of setup_buffer.
+ *     If there is a data phase, its buffer is identified by transfer_dma.
+ * @start_frame: Returns the initial frame for interrupt or isochronous
+ *     transfers.
+ * @number_of_packets: Lists the number of ISO transfer buffers.
+ * @interval: Specifies the polling interval for interrupt or isochronous
+ *     transfers.  The units are frames (milliseconds) for for full and low
+ *     speed devices, and microframes (1/8 millisecond) for highspeed ones.
+ * @error_count: Returns the number of ISO transfers that reported errors.
+ * @context: For use in completion functions.  This normally points to
+ *     request-specific driver context.
+ * @complete: Completion handler. This URB is passed as the parameter to the
+ *     completion function.  The completion function may then do what
+ *     it likes with the URB, including resubmitting or freeing it.
+ * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to 
+ *     collect the transfer status for each buffer.
+ *
+ * This structure identifies USB transfer requests.  URBs must be allocated by
+ * calling usb_alloc_urb() and freed with a call to usb_free_urb().
+ * Initialization may be done using various usb_fill_*_urb() functions.  URBs
+ * are submitted using usb_submit_urb(), and pending requests may be canceled
+ * using usb_unlink_urb().
+ *
+ * Data Transfer Buffers:
+ *
+ * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise
+ * taken from the general page pool.  That is provided by transfer_buffer
+ * (control requests also use setup_packet), and host controller drivers
+ * perform a dma mapping (and unmapping) for each buffer transferred.  Those
+ * mapping operations can be expensive on some platforms (perhaps using a dma
+ * bounce buffer or talking to an IOMMU),
+ * although they're cheap on commodity x86 and ppc hardware.
+ *
+ * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which
+ * tells the host controller driver that no such mapping is needed since
+ * the device driver is DMA-aware.  For example, they might allocate a DMA
+ * buffer with usb_buffer_alloc(), or call usb_buffer_map().
+ * When this transfer flag is provided, host controller drivers will use the
+ * dma addresses found in the transfer_dma and/or setup_dma fields rather than
+ * determing a dma address themselves.
+ *
+ * Initialization:
+ *
+ * All URBs submitted must initialize dev, pipe,
+ * transfer_flags (may be zero), complete, timeout (may be zero).
+ * The URB_ASYNC_UNLINK transfer flag affects later invocations of
+ * the usb_unlink_urb() routine.
+ *
+ * All URBs must also initialize 
+ * transfer_buffer and transfer_buffer_length.  They may provide the
+ * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
+ * to be treated as errors; that flag is invalid for write requests.
+ *
+ * Bulk URBs may
+ * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers
+ * should always terminate with a short packet, even if it means adding an
+ * extra zero length packet.
+ *
+ * Control URBs must provide a setup_packet.
+ *
+ * Interrupt UBS must provide an interval, saying how often (in milliseconds
+ * or, for highspeed devices, 125 microsecond units)
+ * to poll for transfers.  After the URB has been submitted, the interval
+ * and start_frame fields reflect how the transfer was actually scheduled.
+ * The polling interval may be more frequent than requested.
+ * For example, some controllers have a maximum interval of 32 microseconds,
+ * while others support intervals of up to 1024 microseconds.
+ * Isochronous URBs also have transfer intervals.  (Note that for isochronous
+ * endpoints, as well as high speed interrupt endpoints, the encoding of
+ * the transfer interval in the endpoint descriptor is logarithmic.)
+ *
+ * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling
+ * the host controller to schedule the transfer as soon as bandwidth
+ * utilization allows, and then set start_frame to reflect the actual frame
+ * selected during submission.  Otherwise drivers must specify the start_frame
+ * and handle the case where the transfer can't begin then.  However, drivers
+ * won't know how bandwidth is currently allocated, and while they can
+ * find the current frame using usb_get_current_frame_number () they can't
+ * know the range for that frame number.  (Ranges for frame counter values
+ * are HC-specific, and can go from 256 to 65536 frames from "now".)
+ *
+ * Isochronous URBs have a different data transfer model, in part because
+ * the quality of service is only "best effort".  Callers provide specially
+ * allocated URBs, with number_of_packets worth of iso_frame_desc structures
+ * at the end.  Each such packet is an individual ISO transfer.  Isochronous
+ * URBs are normally queued, submitted by drivers to arrange that
+ * transfers are at least double buffered, and then explicitly resubmitted
+ * in completion handlers, so
+ * that data (such as audio or video) streams at as constant a rate as the
+ * host controller scheduler can support.
+ *
+ * Completion Callbacks:
+ *
+ * The completion callback is made in_interrupt(), and one of the first
+ * things that a completion handler should do is check the status field.
+ * The status field is provided for all URBs.  It is used to report
+ * unlinked URBs, and status for all non-ISO transfers.  It should not
+ * be examined before the URB is returned to the completion handler.
+ *
+ * The context field is normally used to link URBs back to the relevant
+ * driver or request state.
+ *
+ * When completion callback is invoked for non-isochronous URBs, the
+ * actual_length field tells how many bytes were transferred.
+ *
+ * ISO transfer status is reported in the status and actual_length fields
+ * of the iso_frame_desc array, and the number of errors is reported in
+ * error_count.  Completion callbacks for ISO transfers will normally
+ * (re)submit URBs to ensure a constant transfer rate.
+ */
+struct urb
+{
+       spinlock_t lock;                /* lock for the URB */
+       atomic_t count;                 /* reference count of the URB */
+       void *hcpriv;                   /* private data for host controller */
+       struct list_head urb_list;      /* list pointer to all active urbs */
+       struct usb_device *dev;         /* (in) pointer to associated device */
+       unsigned int pipe;              /* (in) pipe information */
+       int status;                     /* (return) non-ISO status */
+       unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
+       void *transfer_buffer;          /* (in) associated data buffer */
+       dma_addr_t transfer_dma;        /* (in) dma addr for transfer_buffer */
+       int transfer_buffer_length;     /* (in) data buffer length */
+       int actual_length;              /* (return) actual transfer length */
+       int bandwidth;                  /* bandwidth for INT/ISO request */
+       unsigned char *setup_packet;    /* (in) setup packet (control only) */
+       dma_addr_t setup_dma;           /* (in) dma addr for setup_packet */
+       int start_frame;                /* (modify) start frame (INT/ISO) */
+       int number_of_packets;          /* (in) number of ISO packets */
+       int interval;                   /* (in) transfer interval (INT/ISO) */
+       int error_count;                /* (return) number of ISO errors */
+       int timeout;                    /* (in) timeout, in jiffies */
+       void *context;                  /* (in) context for completion */
+       usb_complete_t complete;        /* (in) completion routine */
+       struct usb_iso_packet_descriptor iso_frame_desc[0];     /* (in) ISO ONLY */
+};
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * usb_fill_control_urb - initializes a control urb
+ * @urb: pointer to the urb to initialize.
+ * @dev: pointer to the struct usb_device for this urb.
+ * @pipe: the endpoint pipe
+ * @setup_packet: pointer to the setup_packet buffer
+ * @transfer_buffer: pointer to the transfer buffer
+ * @buffer_length: length of the transfer buffer
+ * @complete: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ *
+ * Initializes a control urb with the proper information needed to submit
+ * it to a device.
+ */
+static inline void usb_fill_control_urb (struct urb *urb,
+                                        struct usb_device *dev,
+                                        unsigned int pipe,
+                                        unsigned char *setup_packet,
+                                        void *transfer_buffer,
+                                        int buffer_length,
+                                        usb_complete_t complete,
+                                        void *context)
+{
+       spin_lock_init(&urb->lock);
+       urb->dev = dev;
+       urb->pipe = pipe;
+       urb->setup_packet = setup_packet;
+       urb->transfer_buffer = transfer_buffer;
+       urb->transfer_buffer_length = buffer_length;
+       urb->complete = complete;
+       urb->context = context;
+}
+
+/**
+ * usb_fill_bulk_urb - macro to help initialize a bulk urb
+ * @urb: pointer to the urb to initialize.
+ * @dev: pointer to the struct usb_device for this urb.
+ * @pipe: the endpoint pipe
+ * @transfer_buffer: pointer to the transfer buffer
+ * @buffer_length: length of the transfer buffer
+ * @complete: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ *
+ * Initializes a bulk urb with the proper information needed to submit it
+ * to a device.
+ */
+static inline void usb_fill_bulk_urb (struct urb *urb,
+                                     struct usb_device *dev,
+                                     unsigned int pipe,
+                                     void *transfer_buffer,
+                                     int buffer_length,
+                                     usb_complete_t complete,
+                                     void *context)
+{
+       spin_lock_init(&urb->lock);
+       urb->dev = dev;
+       urb->pipe = pipe;
+       urb->transfer_buffer = transfer_buffer;
+       urb->transfer_buffer_length = buffer_length;
+       urb->complete = complete;
+       urb->context = context;
+}
+
+/**
+ * usb_fill_int_urb - macro to help initialize a interrupt urb
+ * @urb: pointer to the urb to initialize.
+ * @dev: pointer to the struct usb_device for this urb.
+ * @pipe: the endpoint pipe
+ * @transfer_buffer: pointer to the transfer buffer
+ * @buffer_length: length of the transfer buffer
+ * @complete: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ * @interval: what to set the urb interval to, encoded like
+ *     the endpoint descriptor's bInterval value.
+ *
+ * Initializes a interrupt urb with the proper information needed to submit
+ * it to a device.
+ * Note that high speed interrupt endpoints use a logarithmic encoding of
+ * the endpoint interval, and express polling intervals in microframes
+ * (eight per millisecond) rather than in frames (one per millisecond).
+ */
+static inline void usb_fill_int_urb (struct urb *urb,
+                                    struct usb_device *dev,
+                                    unsigned int pipe,
+                                    void *transfer_buffer,
+                                    int buffer_length,
+                                    usb_complete_t complete,
+                                    void *context,
+                                    int interval)
+{
+       spin_lock_init(&urb->lock);
+       urb->dev = dev;
+       urb->pipe = pipe;
+       urb->transfer_buffer = transfer_buffer;
+       urb->transfer_buffer_length = buffer_length;
+       urb->complete = complete;
+       urb->context = context;
+       if (dev->speed == USB_SPEED_HIGH)
+               urb->interval = 1 << (interval - 1);
+       else
+               urb->interval = interval;
+       urb->start_frame = -1;
+}
+
+extern void STDCALL usb_init_urb(struct urb *urb);
+extern struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags);
+extern void STDCALL usb_free_urb(struct urb *urb);
+#define usb_put_urb usb_free_urb
+extern struct urb STDCALL *usb_get_urb(struct urb *urb);
+extern int STDCALL usb_submit_urb(struct urb *urb, int mem_flags);
+extern int STDCALL usb_unlink_urb(struct urb *urb);
+
+#define HAVE_USB_BUFFERS
+void *usb_buffer_alloc (struct usb_device *dev, size_t size,
+       int mem_flags, dma_addr_t *dma);
+void usb_buffer_free (struct usb_device *dev, size_t size,
+       void *addr, dma_addr_t dma);
+
+struct urb *usb_buffer_map (struct urb *urb);
+void usb_buffer_dmasync (struct urb *urb);
+void usb_buffer_unmap (struct urb *urb);
+
+struct scatterlist;
+int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int nents);
+void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int n_hw_ents);
+void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
+               struct scatterlist *sg, int n_hw_ents);
+
+/*-------------------------------------------------------------------*
+ *                         SYNCHRONOUS CALL SUPPORT                  *
+ *-------------------------------------------------------------------*/
+
+extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
+       __u8 request, __u8 requesttype, __u16 value, __u16 index,
+       void *data, __u16 size, int timeout);
+extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
+       void *data, int len, int *actual_length,
+       int timeout);
+
+/* wrappers around usb_control_msg() for the most common standard requests */
+extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
+       unsigned char descindex, void *buf, int size);
+extern int usb_get_device_descriptor(struct usb_device *dev);
+extern int usb_get_status(struct usb_device *dev,
+       int type, int target, void *data);
+extern int usb_get_string(struct usb_device *dev,
+       unsigned short langid, unsigned char index, void *buf, int size);
+extern int usb_string(struct usb_device *dev, int index,
+       char *buf, size_t size);
+
+/* wrappers that also update important state inside usbcore */
+extern int usb_clear_halt(struct usb_device *dev, int pipe);
+extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+
+/*
+ * timeouts, in seconds, used for sending/receiving control messages
+ * they typically complete within a few frames (msec) after they're issued
+ * USB identifies 5 second timeouts, maybe more in a few cases, and a few
+ * slow devices (like some MGE Ellipse UPSes) actually push that limit.
+ */
+#define USB_CTRL_GET_TIMEOUT   5
+#define USB_CTRL_SET_TIMEOUT   5
+
+
+/**
+ * struct usb_sg_request - support for scatter/gather I/O
+ * @status: zero indicates success, else negative errno
+ * @bytes: counts bytes transferred.
+ *
+ * These requests are initialized using usb_sg_init(), and then are used
+ * as request handles passed to usb_sg_wait() or usb_sg_cancel().  Most
+ * members of the request object aren't for driver access.
+ *
+ * The status and bytecount values are valid only after usb_sg_wait()
+ * returns.  If the status is zero, then the bytecount matches the total
+ * from the request.
+ *
+ * After an error completion, drivers may need to clear a halt condition
+ * on the endpoint.
+ */
+struct usb_sg_request {
+       int                     status;
+       size_t                  bytes;
+
+       // members not documented above are private to usbcore,
+       // and are not provided for driver access!
+       spinlock_t              lock;
+
+       struct usb_device       *dev;
+       int                     pipe;
+       struct scatterlist      *sg;
+       int                     nents;
+
+       int                     entries;
+       struct urb              **urbs;
+
+       int                     count;
+       struct completion       complete;
+};
+
+int usb_sg_init (
+       struct usb_sg_request   *io,
+       struct usb_device       *dev,
+       unsigned                pipe, 
+       unsigned                period,
+       struct scatterlist      *sg,
+       int                     nents,
+       size_t                  length,
+       int                     mem_flags
+);
+void usb_sg_cancel (struct usb_sg_request *io);
+void usb_sg_wait (struct usb_sg_request *io);
+
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Calling this entity a "pipe" is glorifying it. A USB pipe
+ * is something embarrassingly simple: it basically consists
+ * of the following information:
+ *  - device number (7 bits)
+ *  - endpoint number (4 bits)
+ *  - current Data0/1 state (1 bit) [Historical; now gone]
+ *  - direction (1 bit)
+ *  - speed (1 bit) [Historical and specific to USB 1.1; now gone.]
+ *  - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.]
+ *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
+ *
+ * That's 18 bits. Really. Nothing more. And the USB people have
+ * documented these eighteen bits as some kind of glorious
+ * virtual data structure.
+ *
+ * Let's not fall in that trap. We'll just encode it as a simple
+ * unsigned int. The encoding is:
+ *
+ *  - max size:                bits 0-1        [Historical; now gone.]
+ *  - direction:       bit 7           (0 = Host-to-Device [Out],
+ *                                      1 = Device-to-Host [In] ...
+ *                                     like endpoint bEndpointAddress)
+ *  - device:          bits 8-14       ... bit positions known to uhci-hcd
+ *  - endpoint:                bits 15-18      ... bit positions known to uhci-hcd
+ *  - Data0/1:         bit 19          [Historical; now gone. ]
+ *  - lowspeed:                bit 26          [Historical; now gone. ]
+ *  - pipe type:       bits 30-31      (00 = isochronous, 01 = interrupt,
+ *                                      10 = control, 11 = bulk)
+ *
+ * Why? Because it's arbitrary, and whatever encoding we select is really
+ * up to us. This one happens to share a lot of bit positions with the UHCI
+ * specification, so that much of the uhci driver can just mask the bits
+ * appropriately.
+ */
+
+/* NOTE:  these are not the standard USB_ENDPOINT_XFER_* values!! */
+#define PIPE_ISOCHRONOUS               0
+#define PIPE_INTERRUPT                 1
+#define PIPE_CONTROL                   2
+#define PIPE_BULK                      3
+
+#define usb_maxpacket(dev, pipe, out)  (out \
+                               ? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
+                               : (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
+
+#define usb_pipein(pipe)       ((pipe) & USB_DIR_IN)
+#define usb_pipeout(pipe)      (!usb_pipein(pipe))
+#define usb_pipedevice(pipe)   (((pipe) >> 8) & 0x7f)
+#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
+#define usb_pipetype(pipe)     (((pipe) >> 30) & 3)
+#define usb_pipeisoc(pipe)     (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
+#define usb_pipeint(pipe)      (usb_pipetype((pipe)) == PIPE_INTERRUPT)
+#define usb_pipecontrol(pipe)  (usb_pipetype((pipe)) == PIPE_CONTROL)
+#define usb_pipebulk(pipe)     (usb_pipetype((pipe)) == PIPE_BULK)
+
+/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
+#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
+#define        usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
+#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))
+
+/* Endpoint halt control/status ... likewise USE WITH CAUTION */
+#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
+#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
+
+
+static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
+{
+       return (dev->devnum << 8) | (endpoint << 15);
+}
+
+/* Create various pipes... */
+#define usb_sndctrlpipe(dev,endpoint)  ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvctrlpipe(dev,endpoint)  ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndisocpipe(dev,endpoint)  ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvisocpipe(dev,endpoint)  ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndbulkpipe(dev,endpoint)  ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvbulkpipe(dev,endpoint)  ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndintpipe(dev,endpoint)   ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvintpipe(dev,endpoint)   ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Debugging and troubleshooting/diagnostic helpers.
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *);
+void usb_show_config_descriptor(struct usb_config_descriptor *);
+void usb_show_interface_descriptor(struct usb_interface_descriptor *);
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
+void usb_show_device(struct usb_device *);
+void usb_show_string(struct usb_device *dev, char *id, int index);
+
+#ifdef DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+
+
+#ifdef DEBUG_MODE
+#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
+#endif
+
+#ifndef DEBUG_MODE                                                               
+#define info(format, arg...) do {} while (0)
+#define err(format, arg...) do {} while (0)
+#define warn(format, arg...) do {} while (0)
+#endif
+
+#endif  /* __KERNEL__ */
+
+#endif
index a679168..109ec38 100644 (file)
-/*\r
- * This file holds USB constants and structures that are needed for USB\r
- * device APIs.  These are used by the USB device model, which is defined\r
- * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C\r
- * that need these:\r
- *\r
- * - the master/host side Linux-USB kernel driver API;\r
- * - the "usbfs" user space API; and\r
- * - (eventually) a Linux "gadget" slave/device side driver API.\r
- *\r
- * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems\r
- * act either as a USB master/host or as a USB slave/device.  That means\r
- * the master and slave side APIs will benefit from working well together.\r
- */\r
-\r
-#ifndef __LINUX_USB_CH9_H\r
-#define __LINUX_USB_CH9_H\r
-#if 0\r
-#include <asm/types.h>         /* __u8 etc */\r
-#endif\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* CONTROL REQUEST SUPPORT */\r
-\r
-/*\r
- * USB directions\r
- *\r
- * This bit flag is used in endpoint descriptors' bEndpointAddress field.\r
- * It's also one of three fields in control requests bRequestType.\r
- */\r
-#define USB_DIR_OUT                    0               /* to device */\r
-#define USB_DIR_IN                     0x80            /* to host */\r
-\r
-/*\r
- * USB types, the second of three bRequestType fields\r
- */\r
-#define USB_TYPE_MASK                  (0x03 << 5)\r
-#define USB_TYPE_STANDARD              (0x00 << 5)\r
-#define USB_TYPE_CLASS                 (0x01 << 5)\r
-#define USB_TYPE_VENDOR                        (0x02 << 5)\r
-#define USB_TYPE_RESERVED              (0x03 << 5)\r
-\r
-/*\r
- * USB recipients, the third of three bRequestType fields\r
- */\r
-#define USB_RECIP_MASK                 0x1f\r
-#define USB_RECIP_DEVICE               0x00\r
-#define USB_RECIP_INTERFACE            0x01\r
-#define USB_RECIP_ENDPOINT             0x02\r
-#define USB_RECIP_OTHER                        0x03\r
-\r
-/*\r
- * Standard requests, for the bRequest field of a SETUP packet.\r
- *\r
- * These are qualified by the bRequestType field, so that for example\r
- * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved\r
- * by a GET_STATUS request.\r
- */\r
-#define USB_REQ_GET_STATUS             0x00\r
-#define USB_REQ_CLEAR_FEATURE          0x01\r
-#define USB_REQ_SET_FEATURE            0x03\r
-#define USB_REQ_SET_ADDRESS            0x05\r
-#define USB_REQ_GET_DESCRIPTOR         0x06\r
-#define USB_REQ_SET_DESCRIPTOR         0x07\r
-#define USB_REQ_GET_CONFIGURATION      0x08\r
-#define USB_REQ_SET_CONFIGURATION      0x09\r
-#define USB_REQ_GET_INTERFACE          0x0A\r
-#define USB_REQ_SET_INTERFACE          0x0B\r
-#define USB_REQ_SYNCH_FRAME            0x0C\r
-\r
-\r
-/**\r
- * struct usb_ctrlrequest - SETUP data for a USB device control request\r
- * @bRequestType: matches the USB bmRequestType field\r
- * @bRequest: matches the USB bRequest field\r
- * @wValue: matches the USB wValue field (le16 byte order)\r
- * @wIndex: matches the USB wIndex field (le16 byte order)\r
- * @wLength: matches the USB wLength field (le16 byte order)\r
- *\r
- * This structure is used to send control requests to a USB device.  It matches\r
- * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the\r
- * USB spec for a fuller description of the different fields, and what they are\r
- * used for.\r
- *\r
- * Note that the driver for any interface can issue control requests.\r
- * For most devices, interfaces don't coordinate with each other, so\r
- * such requests may be made at any time.\r
- */\r
-struct usb_ctrlrequest {\r
-       __u8 bRequestType;\r
-       __u8 bRequest;\r
-       __u16 wValue;\r
-       __u16 wIndex;\r
-       __u16 wLength;\r
-} __attribute__ ((packed));\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/*\r
- * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or\r
- * (rarely) accepted by SET_DESCRIPTOR.\r
- *\r
- * Note that all multi-byte values here are encoded in little endian\r
- * byte order "on the wire".  But when exposed through Linux-USB APIs,\r
- * they've been converted to cpu byte order.\r
- */\r
-\r
-/*\r
- * Descriptor types ... USB 2.0 spec table 9.5\r
- */\r
-#define USB_DT_DEVICE                  0x01\r
-#define USB_DT_CONFIG                  0x02\r
-#define USB_DT_STRING                  0x03\r
-#define USB_DT_INTERFACE               0x04\r
-#define USB_DT_ENDPOINT                        0x05\r
-#define USB_DT_DEVICE_QUALIFIER                0x06\r
-#define USB_DT_OTHER_SPEED_CONFIG      0x07\r
-#define USB_DT_INTERFACE_POWER         0x08\r
-\r
-/* All standard descriptors have these 2 fields at the beginning */\r
-struct usb_descriptor_header {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-} __attribute__ ((packed));\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB_DT_DEVICE: Device descriptor */\r
-struct usb_device_descriptor {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-\r
-       __u16 bcdUSB;\r
-       __u8  bDeviceClass;\r
-       __u8  bDeviceSubClass;\r
-       __u8  bDeviceProtocol;\r
-       __u8  bMaxPacketSize0;\r
-       __u16 idVendor;\r
-       __u16 idProduct;\r
-       __u16 bcdDevice;\r
-       __u8  iManufacturer;\r
-       __u8  iProduct;\r
-       __u8  iSerialNumber;\r
-       __u8  bNumConfigurations;\r
-} __attribute__ ((packed));\r
-\r
-#define USB_DT_DEVICE_SIZE             18\r
-\r
-\r
-/*\r
- * Device and/or Interface Class codes\r
- * as found in bDeviceClass or bInterfaceClass\r
- * and defined by www.usb.org documents\r
- */\r
-#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */\r
-#define USB_CLASS_AUDIO                        1\r
-#define USB_CLASS_COMM                 2\r
-#define USB_CLASS_HID                  3\r
-#define USB_CLASS_PHYSICAL             5\r
-#define USB_CLASS_STILL_IMAGE          6\r
-#define USB_CLASS_PRINTER              7\r
-#define USB_CLASS_MASS_STORAGE         8\r
-#define USB_CLASS_HUB                  9\r
-#define USB_CLASS_CDC_DATA             0x0a\r
-#define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */\r
-#define USB_CLASS_CONTENT_SEC          0x0d    /* content security */\r
-#define USB_CLASS_APP_SPEC             0xfe\r
-#define USB_CLASS_VENDOR_SPEC          0xff\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB_DT_CONFIG: Configuration descriptor information.\r
- *\r
- * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the\r
- * descriptor type is different.  Highspeed-capable devices can look\r
- * different depending on what speed they're currently running.  Only\r
- * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG\r
- * descriptors.\r
- */\r
-struct usb_config_descriptor {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-\r
-       __u16 wTotalLength;\r
-       __u8  bNumInterfaces;\r
-       __u8  bConfigurationValue;\r
-       __u8  iConfiguration;\r
-       __u8  bmAttributes;\r
-       __u8  bMaxPower;\r
-} __attribute__ ((packed));\r
-\r
-#define USB_DT_CONFIG_SIZE             9\r
-\r
-/* from config descriptor bmAttributes */\r
-#define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */\r
-#define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */\r
-#define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB_DT_STRING: String descriptor */\r
-struct usb_string_descriptor {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-\r
-       __u16 wData[1];         /* UTF-16LE encoded */\r
-} __attribute__ ((packed));\r
-\r
-/* note that "string" zero is special, it holds language codes that\r
- * the device supports, not Unicode characters.\r
- */\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB_DT_INTERFACE: Interface descriptor */\r
-struct usb_interface_descriptor {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-\r
-       __u8  bInterfaceNumber;\r
-       __u8  bAlternateSetting;\r
-       __u8  bNumEndpoints;\r
-       __u8  bInterfaceClass;\r
-       __u8  bInterfaceSubClass;\r
-       __u8  bInterfaceProtocol;\r
-       __u8  iInterface;\r
-} __attribute__ ((packed));\r
-\r
-#define USB_DT_INTERFACE_SIZE          9\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB_DT_ENDPOINT: Endpoint descriptor */\r
-struct usb_endpoint_descriptor {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-\r
-       __u8  bEndpointAddress;\r
-       __u8  bmAttributes;\r
-       __u16 wMaxPacketSize;\r
-       __u8  bInterval;\r
-\r
-       // NOTE:  these two are _only_ in audio endpoints.\r
-       // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof.\r
-       __u8  bRefresh;\r
-       __u8  bSynchAddress;\r
-} __attribute__ ((packed));\r
-\r
-#define USB_DT_ENDPOINT_SIZE           7\r
-#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */\r
-\r
-\r
-/*\r
- * Endpoints\r
- */\r
-#define USB_ENDPOINT_NUMBER_MASK       0x0f    /* in bEndpointAddress */\r
-#define USB_ENDPOINT_DIR_MASK          0x80\r
-\r
-#define USB_ENDPOINT_XFERTYPE_MASK     0x03    /* in bmAttributes */\r
-#define USB_ENDPOINT_XFER_CONTROL      0\r
-#define USB_ENDPOINT_XFER_ISOC         1\r
-#define USB_ENDPOINT_XFER_BULK         2\r
-#define USB_ENDPOINT_XFER_INT          3\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */\r
-struct usb_qualifier_descriptor {\r
-       __u8  bLength;\r
-       __u8  bDescriptorType;\r
-\r
-       __u16 bcdUSB;\r
-       __u8  bDeviceClass;\r
-       __u8  bDeviceSubClass;\r
-       __u8  bDeviceProtocol;\r
-       __u8  bMaxPacketSize0;\r
-       __u8  bNumConfigurations;\r
-       __u8  bRESERVED;\r
-} __attribute__ ((packed));\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-/* USB 2.0 defines three speeds, here's how Linux identifies them */\r
-\r
-enum usb_device_speed {\r
-       USB_SPEED_UNKNOWN = 0,                  /* enumerating */\r
-       USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */\r
-       USB_SPEED_HIGH                          /* usb 2.0 */\r
-};\r
-\r
-enum usb_device_state {\r
-       /* NOTATTACHED isn't in the USB spec, and this state acts\r
-        * the same as ATTACHED ... but it's clearer this way.\r
-        */\r
-       USB_STATE_NOTATTACHED = 0,\r
-\r
-       /* the chapter 9 device states */\r
-       USB_STATE_ATTACHED,\r
-       USB_STATE_POWERED,\r
-       USB_STATE_DEFAULT,                      /* limited function */\r
-       USB_STATE_ADDRESS,\r
-       USB_STATE_CONFIGURED,                   /* most functions */\r
-\r
-       USB_STATE_SUSPENDED\r
-\r
-       /* NOTE:  there are actually four different SUSPENDED\r
-        * states, returning to POWERED, DEFAULT, ADDRESS, or\r
-        * CONFIGURED respectively when SOF tokens flow again.\r
-        */\r
-};\r
-\r
-#endif /* __LINUX_USB_CH9_H */\r
+/*
+ * This file holds USB constants and structures that are needed for USB
+ * device APIs.  These are used by the USB device model, which is defined
+ * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
+ * that need these:
+ *
+ * - the master/host side Linux-USB kernel driver API;
+ * - the "usbfs" user space API; and
+ * - (eventually) a Linux "gadget" slave/device side driver API.
+ *
+ * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
+ * act either as a USB master/host or as a USB slave/device.  That means
+ * the master and slave side APIs will benefit from working well together.
+ */
+
+#ifndef __LINUX_USB_CH9_H
+#define __LINUX_USB_CH9_H
+#if 0
+#include <asm/types.h>         /* __u8 etc */
+#endif
+/*-------------------------------------------------------------------------*/
+
+/* CONTROL REQUEST SUPPORT */
+
+/*
+ * USB directions
+ *
+ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
+ * It's also one of three fields in control requests bRequestType.
+ */
+#define USB_DIR_OUT                    0               /* to device */
+#define USB_DIR_IN                     0x80            /* to host */
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_MASK                  (0x03 << 5)
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK                 0x1f
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+
+/*
+ * Standard requests, for the bRequest field of a SETUP packet.
+ *
+ * These are qualified by the bRequestType field, so that for example
+ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
+ * by a GET_STATUS request.
+ */
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+#define USB_REQ_SET_FEATURE            0x03
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+
+/**
+ * struct usb_ctrlrequest - SETUP data for a USB device control request
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (le16 byte order)
+ * @wIndex: matches the USB wIndex field (le16 byte order)
+ * @wLength: matches the USB wLength field (le16 byte order)
+ *
+ * This structure is used to send control requests to a USB device.  It matches
+ * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
+ * USB spec for a fuller description of the different fields, and what they are
+ * used for.
+ *
+ * Note that the driver for any interface can issue control requests.
+ * For most devices, interfaces don't coordinate with each other, so
+ * such requests may be made at any time.
+ */
+struct usb_ctrlrequest {
+       __u8 bRequestType;
+       __u8 bRequest;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
+ * (rarely) accepted by SET_DESCRIPTOR.
+ *
+ * Note that all multi-byte values here are encoded in little endian
+ * byte order "on the wire".  But when exposed through Linux-USB APIs,
+ * they've been converted to cpu byte order.
+ */
+
+/*
+ * Descriptor types ... USB 2.0 spec table 9.5
+ */
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+#define USB_DT_DEVICE_QUALIFIER                0x06
+#define USB_DT_OTHER_SPEED_CONFIG      0x07
+#define USB_DT_INTERFACE_POWER         0x08
+
+/* All standard descriptors have these 2 fields at the beginning */
+struct usb_descriptor_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE: Device descriptor */
+struct usb_device_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __u16 idVendor;
+       __u16 idProduct;
+       __u16 bcdDevice;
+       __u8  iManufacturer;
+       __u8  iProduct;
+       __u8  iSerialNumber;
+       __u8  bNumConfigurations;
+} __attribute__ ((packed));
+
+#define USB_DT_DEVICE_SIZE             18
+
+
+/*
+ * Device and/or Interface Class codes
+ * as found in bDeviceClass or bInterfaceClass
+ * and defined by www.usb.org documents
+ */
+#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PHYSICAL             5
+#define USB_CLASS_STILL_IMAGE          6
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_CDC_DATA             0x0a
+#define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC          0x0d    /* content security */
+#define USB_CLASS_APP_SPEC             0xfe
+#define USB_CLASS_VENDOR_SPEC          0xff
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different.  Highspeed-capable devices can look
+ * different depending on what speed they're currently running.  Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
+ * descriptors.
+ */
+struct usb_config_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u16 wTotalLength;
+       __u8  bNumInterfaces;
+       __u8  bConfigurationValue;
+       __u8  iConfiguration;
+       __u8  bmAttributes;
+       __u8  bMaxPower;
+} __attribute__ ((packed));
+
+#define USB_DT_CONFIG_SIZE             9
+
+/* from config descriptor bmAttributes */
+#define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */
+#define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */
+#define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_STRING: String descriptor */
+struct usb_string_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u16 wData[1];         /* UTF-16LE encoded */
+} __attribute__ ((packed));
+
+/* note that "string" zero is special, it holds language codes that
+ * the device supports, not Unicode characters.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE: Interface descriptor */
+struct usb_interface_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bInterfaceNumber;
+       __u8  bAlternateSetting;
+       __u8  bNumEndpoints;
+       __u8  bInterfaceClass;
+       __u8  bInterfaceSubClass;
+       __u8  bInterfaceProtocol;
+       __u8  iInterface;
+} __attribute__ ((packed));
+
+#define USB_DT_INTERFACE_SIZE          9
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+struct usb_endpoint_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bEndpointAddress;
+       __u8  bmAttributes;
+       __u16 wMaxPacketSize;
+       __u8  bInterval;
+
+       // NOTE:  these two are _only_ in audio endpoints.
+       // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof.
+       __u8  bRefresh;
+       __u8  bSynchAddress;
+} __attribute__ ((packed));
+
+#define USB_DT_ENDPOINT_SIZE           7
+#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
+
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK       0x0f    /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK          0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK     0x03    /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL      0
+#define USB_ENDPOINT_XFER_ISOC         1
+#define USB_ENDPOINT_XFER_BULK         2
+#define USB_ENDPOINT_XFER_INT          3
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+struct usb_qualifier_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __u8  bNumConfigurations;
+       __u8  bRESERVED;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB 2.0 defines three speeds, here's how Linux identifies them */
+
+enum usb_device_speed {
+       USB_SPEED_UNKNOWN = 0,                  /* enumerating */
+       USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
+       USB_SPEED_HIGH                          /* usb 2.0 */
+};
+
+enum usb_device_state {
+       /* NOTATTACHED isn't in the USB spec, and this state acts
+        * the same as ATTACHED ... but it's clearer this way.
+        */
+       USB_STATE_NOTATTACHED = 0,
+
+       /* the chapter 9 device states */
+       USB_STATE_ATTACHED,
+       USB_STATE_POWERED,
+       USB_STATE_DEFAULT,                      /* limited function */
+       USB_STATE_ADDRESS,
+       USB_STATE_CONFIGURED,                   /* most functions */
+
+       USB_STATE_SUSPENDED
+
+       /* NOTE:  there are actually four different SUSPENDED
+        * states, returning to POWERED, DEFAULT, ADDRESS, or
+        * CONFIGURED respectively when SOF tokens flow again.
+        */
+};
+
+#endif /* __LINUX_USB_CH9_H */
index 2f582c5..243d101 100644 (file)
@@ -1,90 +1,90 @@
-/*\r
- * USB support for XBOX, based on Linux kernel source\r
- *\r
- * 2003-06-21 Georg Acher (georg@acher.org)\r
- *\r
-*/\r
-          \r
-#include "../usb_wrapper.h"\r
-\r
-void subsys_usb_init(void);\r
-void module_exit_usb_exit(void);\r
-\r
-extern struct pci_device_id  *module_table_pci_ids;\r
-\r
-// straigth call...\r
-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id);\r
-void usb_hcd_pci_remove (struct pci_dev *dev);\r
-\r
-void XPADInit(void);\r
-void XPADRemove(void);\r
-void XRemoteInit(void);\r
-void XRemoteRemove(void);\r
-\r
-extern int (*thread_handler)(void*);\r
-int (*hub_thread_handler)(void*);\r
-\r
-extern int nousb;\r
-extern int xpad_num;\r
-\r
-struct pci_dev xx_ohci_dev={\r
-        .vendor = 0,\r
-        .device = 0,\r
-        .bus = NULL,\r
-        .irq = 1, // currently not used...\r
-        .slot_name = "OHCI",\r
-        .dev = {.name = "PCI",.dma_mask=1},\r
-        .base = {0xfed00000}, \r
-        .flags = {}\r
-};\r
-\r
-/*------------------------------------------------------------------------*/ \r
-void BootStartUSB(void)\r
-{\r
-       int n;\r
-\r
-       nousb=0;\r
-\r
-        init_wrapper();\r
-        subsys_usb_init();\r
-        hub_thread_handler=thread_handler;\r
-       usb_hcd_pci_probe(&xx_ohci_dev, module_table_pci_ids);  \r
-       XPADInit();\r
-       \r
-       XRemoteInit();\r
-       \r
-       UsbKeyBoardInit();\r
-\r
-       for(n=0;n<30;n++) {\r
-               USBGetEvents();\r
-               wait_ms(1);\r
-       }\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void USBGetEvents(void)\r
-{      \r
-       inc_jiffies(1);\r
-        do_all_timers();\r
-        hub_thread_handler(NULL);\r
-        handle_irqs(-1);       \r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void BootStopUSB(void)\r
-{\r
-       int n;\r
-        \r
-        XPADRemove();\r
-       XRemoteRemove();\r
-       UsbKeyBoardRemove();\r
-       \r
-       for(n=0;n<100;n++)\r
-       {\r
-               USBGetEvents();\r
-               wait_ms(1);\r
-       }       \r
-\r
-       module_exit_usb_exit();\r
-       usb_hcd_pci_remove(&xx_ohci_dev);\r
-       \r
-}      \r
-/*------------------------------------------------------------------------*/   \r
+/*
+ * USB support for XBOX, based on Linux kernel source
+ *
+ * 2003-06-21 Georg Acher (georg@acher.org)
+ *
+*/
+          
+#include "../usb_wrapper.h"
+
+void subsys_usb_init(void);
+void module_exit_usb_exit(void);
+
+extern struct pci_device_id  *module_table_pci_ids;
+
+// straigth call...
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id);
+void usb_hcd_pci_remove (struct pci_dev *dev);
+
+void XPADInit(void);
+void XPADRemove(void);
+void XRemoteInit(void);
+void XRemoteRemove(void);
+
+extern int (*thread_handler)(void*);
+int (*hub_thread_handler)(void*);
+
+extern int nousb;
+extern int xpad_num;
+
+struct pci_dev xx_ohci_dev={
+        .vendor = 0,
+        .device = 0,
+        .bus = NULL,
+        .irq = 1, // currently not used...
+        .slot_name = "OHCI",
+        .dev = {.name = "PCI",.dma_mask=1},
+        .base = {0xfed00000}, 
+        .flags = {}
+};
+
+/*------------------------------------------------------------------------*/ 
+void BootStartUSB(void)
+{
+       int n;
+
+       nousb=0;
+
+        init_wrapper();
+        subsys_usb_init();
+        hub_thread_handler=thread_handler;
+       usb_hcd_pci_probe(&xx_ohci_dev, module_table_pci_ids);  
+       XPADInit();
+       
+       XRemoteInit();
+       
+       UsbKeyBoardInit();
+
+       for(n=0;n<30;n++) {
+               USBGetEvents();
+               wait_ms(1);
+       }
+}
+/*------------------------------------------------------------------------*/ 
+void USBGetEvents(void)
+{      
+       inc_jiffies(1);
+        do_all_timers();
+        hub_thread_handler(NULL);
+        handle_irqs(-1);       
+}
+/*------------------------------------------------------------------------*/ 
+void BootStopUSB(void)
+{
+       int n;
+        
+        XPADRemove();
+       XRemoteRemove();
+       UsbKeyBoardRemove();
+       
+       for(n=0;n<100;n++)
+       {
+               USBGetEvents();
+               wait_ms(1);
+       }       
+
+       module_exit_usb_exit();
+       usb_hcd_pci_remove(&xx_ohci_dev);
+       
+}      
+/*------------------------------------------------------------------------*/   
index a57d8ce..bdac3da 100644 (file)
@@ -1,4 +1,4 @@
-\r
-O_TARGET :=  usbwrapper.o BootUSB.o linuxwrapper.o xpad.o xremote.o usbkey.o risefall.o\r
-\r
-include $(TOPDIR)/Rules.make\r
+
+O_TARGET :=  usbwrapper.o BootUSB.o linuxwrapper.o xpad.o xremote.o usbkey.o risefall.o
+
+include $(TOPDIR)/Rules.make
index 616cbd7..1a8f783 100644 (file)
-/*\r
- * USB support based on Linux kernel source\r
- *\r
- * 2003-06-21 Georg Acher (georg@acher.org)\r
- *\r
- * Concept:\r
- * \r
- * 1) Forget all device interrupts, scheduling, semaphores, threads etc.\r
- * 1a) Forget all DMA and PCI helper functions\r
- * 2) Forget usbdevfs, procfs and ioctls\r
- * 3) Emulate OHCI interrupts and root hub timer by polling\r
- * 4) Emulate hub kernel thread by polling\r
- * 5) Emulate synchronous USB-messages (usb_*_msg) with busy waiting\r
- *\r
- * To be done:\r
- * 6) Remove code bloat  \r
- *\r
- */\r
-\r
-#include "../usb_wrapper.h"\r
-\r
-/* internal state */\r
-\r
-static struct pci_dev *pci_probe_dev;\r
-extern int (*thread_handler)(void*);\r
-extern void* thread_parm;\r
-\r
-struct my_irqs reg_irqs[MAX_IRQS];\r
-int num_irqs;\r
-int need_wakeup;\r
-\r
-int my_jiffies;\r
-\r
-struct timer_list *main_timer_list[MAX_TIMERS];\r
-struct dummy_process act_cur={0};\r
-struct dummy_process *my_current;\r
-\r
-int (*thread_handler)(void*);\r
-void* thread_parm;\r
-\r
-#define MAX_DRVS 8\r
-static struct device_driver *m_drivers[MAX_DRVS];\r
-static int drvs_num;\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* \r
- * Helper functions for top-level system\r
- */\r
-/*------------------------------------------------------------------------*/ \r
-void init_wrapper(struct pci_dev *probe_dev)\r
-{\r
-       int n;\r
-       for(n=0;n<MAX_TIMERS;n++)\r
-       {\r
-               main_timer_list[n]=NULL;\r
-       }\r
-\r
-       my_jiffies=0;\r
-       num_irqs=0;\r
-       my_current=&act_cur;\r
-       pci_probe_dev=probe_dev;\r
-\r
-       for(n=0;n<MAX_IRQS;n++)\r
-       {\r
-               reg_irqs[n].handler=NULL;\r
-               reg_irqs[n].irq=-1;\r
-       }\r
-       drvs_num=0;\r
-       need_wakeup=0;\r
-       for(n=0;n<MAX_DRVS;n++)\r
-               m_drivers[n]=NULL;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void handle_irqs(int irq)\r
-{\r
-       int n;\r
-//     printk("handle irqs\n");\r
-       for(n=0;n<MAX_IRQS;n++)\r
-       {\r
-               if (reg_irqs[n].handler && (irq==reg_irqs[n].irq || irq==-1))\r
-                       reg_irqs[n].handler(reg_irqs[n].irq,reg_irqs[n].data,NULL);\r
-       }\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void inc_jiffies(int n)\r
-{\r
-       my_jiffies+=n;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void do_all_timers(void)\r
-{\r
-       int n;\r
-       for(n=0;n<MAX_TIMERS;n++)\r
-       {\r
-               if (main_timer_list[n] &&\r
-                   main_timer_list[n]->function && main_timer_list[n]->expires) \r
-               {\r
-                       void (*function)(unsigned long)=main_timer_list[n]->function;\r
-                       unsigned long data=main_timer_list[n]->data;\r
-                       main_timer_list[n]->expires=0;\r
-\r
-                       main_timer_list[n]=NULL; // remove timer\r
-//                     printk("do timer %i fn %p\n",n,function);\r
-\r
-                       function(data);\r
-               }\r
-       }\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-// Purpose: Remember thread procedure and data in global var\r
-// ReactOS Purpose: Create real kernel thread\r
-int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags)\r
-{\r
-       HANDLE hThread;\r
-       //thread_handler=handler;\r
-       //thread_parm=parm;\r
-       //return 42; // PID :-)\r
-       \r
-       ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
-\r
-       PsCreateSystemThread(&hThread,\r
-                            THREAD_ALL_ACCESS,\r
-                            NULL,\r
-                            NULL,\r
-                            NULL,\r
-                            (PKSTART_ROUTINE)handler,\r
-                                parm);\r
-\r
-    return (int)hThread; // FIXME: Correct?\r
-}\r
-\r
-// Kill the process\r
-int my_kill_proc(int pid, int signal, int unk)\r
-{\r
-       HANDLE hThread;\r
-\r
-       // TODO: Implement actual process killing\r
-\r
-       hThread = (HANDLE)pid;\r
-       ZwClose(hThread);\r
-\r
-       return 0;\r
-}\r
-\r
-/*------------------------------------------------------------------------*/ \r
-/* Device management\r
- * As simple as possible, but as complete as necessary ...\r
- */\r
-/*------------------------------------------------------------------------*/ \r
-\r
-\r
-/* calls probe function for hotplug (which does device matching), this is the\r
-only link between usbcore and the registered device drivers! */\r
-int my_device_add(struct device *dev)\r
-{\r
-       int n,found=0;\r
-//     printk("drv_num %i %p %p\n",drvs_num,m_drivers[0]->probe,m_drivers[1]->probe);\r
-       if (dev->driver)\r
-       {\r
-               if (dev->driver->probe)\r
-                       return dev->driver->probe(dev);\r
-       }\r
-       else\r
-       {\r
-               for(n=0;n<drvs_num;n++)\r
-               {\r
-                       if (m_drivers[n]->probe)\r
-                       {\r
-                               dev->driver=m_drivers[n];\r
-//                             printk("probe%i %p ",n,m_drivers[n]->probe);\r
-                               if (m_drivers[n]->probe(dev) == 0)\r
-                               {\r
-//                                     return 0;\r
-                                       found=1;\r
-                               }\r
-                       }\r
-               }\r
-               if (found) return 0;\r
-       }\r
-       dev->driver=NULL;\r
-       return -ENODEV;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int my_driver_register(struct device_driver *driver)\r
-{\r
-\r
-       if (drvs_num<MAX_DRVS)\r
-       {\r
-//             printk("driver_register %i: %p %p",drvs_num,driver,driver->probe);\r
-               m_drivers[drvs_num++]=driver;\r
-               return 0;\r
-       }\r
-       return -1;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int my_device_unregister(struct device *dev)\r
-{\r
-       if (dev->driver && dev->driver->remove)\r
-               dev->driver->remove(dev);\r
-       return 0;\r
-               \r
-}\r
-/*------------------------------------------------------------------------*/ \r
-struct device *my_get_device(struct device *dev)\r
-{\r
-       return NULL;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void my_device_initialize(struct device *dev)\r
-{\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void my_wake_up(PKEVENT evnt)\r
-{\r
-       need_wakeup=1;\r
-\r
-       KeSetEvent(evnt, 0, FALSE); // Signal event\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void my_init_waitqueue_head(PKEVENT evnt)\r
-{\r
-       // this is used only in core/message.c, and it isn't needed there\r
-       //KeInitializeEvent(evnt, NotificationEvent, TRUE); // signalled state\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-/* wait until woken up (only one wait allowed!) */\r
-int my_schedule_timeout(int x)\r
-{\r
-       int wait=1;\r
-       x+=10; // safety\r
-//     printk("schedule_timeout %i\n",x);\r
-       while(x>0)\r
-       {\r
-               do_all_timers();\r
-#ifndef HAVE_IRQS\r
-               handle_irqs(-1);\r
-\r
-#endif\r
-               if (need_wakeup)\r
-                       break;\r
-               wait_ms(wait);\r
-               inc_jiffies(wait);\r
-               x-=wait;\r
-       }\r
-       need_wakeup=0;\r
-//     printk("schedule DONE!!!!!!\n");\r
-       return x;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void my_wait_for_completion(struct completion *x)\r
-{\r
-       int n=100;\r
-//     printk("wait for completion\n");\r
-       while(!x->done && (n>0))\r
-       {\r
-               do_all_timers();        \r
-#ifndef HAVE_IRQS\r
-               handle_irqs(-1);\r
-\r
-#endif\r
-               wait_ms(10);    \r
-               n--;\r
-       }\r
-//     printk("wait for completion done %i\n",x->done);\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void my_interruptible_sleep_on(PKEVENT evnt)\r
-{\r
-       KeWaitForSingleObject(evnt, Executive, KernelMode, FALSE, NULL);\r
-       KeClearEvent(evnt); // reset to not-signalled\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-// Helper for pci_module_init\r
-/*------------------------------------------------------------------------*/ \r
-int my_pci_module_init(struct pci_driver *x)\r
-{\r
-       struct pci_dev *dev=pci_probe_dev;\r
-       const struct pci_device_id *id=NULL;\r
-       if (!pci_probe_dev)\r
-       {\r
-               printk(KERN_ERR "PCI device not set!\n");\r
-               return 0;\r
-       }\r
-       x->probe(dev, id);\r
-       return 0;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-struct pci_dev *my_pci_find_slot(int a,int b)\r
-{\r
-       return NULL;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int my_pci_write_config_word(struct pci_dev *dev, int where, u16 val)\r
-{\r
-       //dev->bus, dev->devfn, where, val\r
-       OHCI_DEVICE_EXTENSION *dev_ext = (OHCI_DEVICE_EXTENSION *)dev->dev_ext;\r
-\r
-       //FIXME: Is returning this value correct?\r
-       //FIXME: Mixing pci_dev and win structs isn't a good thing at all\r
-       return HalSetBusDataByOffset(PCIConfiguration, dev->bus->number, dev_ext->SystemIoSlotNumber, &val, where, sizeof(val));\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int my_request_irq(unsigned int irq,\r
-                       int  (*handler)(int,void *, struct pt_regs *),\r
-                       unsigned long mode, const char *desc, void *data)\r
-{\r
-       if (num_irqs<MAX_IRQS)\r
-       {\r
-               reg_irqs[num_irqs].handler=handler;\r
-               reg_irqs[num_irqs].irq=irq;\r
-               reg_irqs[num_irqs].data=data;\r
-               num_irqs++;\r
-               return 0;\r
-       }\r
-       return 1;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int my_free_irq(int irq, void* p)\r
-{\r
-       /* No free... */\r
-       return 0;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-// Lookaside funcs\r
-/*------------------------------------------------------------------------*/ \r
-kmem_cache_t *my_kmem_cache_create(const char *tag, size_t alloc_size,\r
-                                                                  size_t offset, unsigned long flags,\r
-                                                                  void *ctor,\r
-                                                                  void *dtor)\r
-{\r
-       //TODO: Take in account ctor and dtor - callbacks for alloc/free, flags and offset\r
-       //FIXME: We assume this cache is always NPaged\r
-       PNPAGED_LOOKASIDE_LIST Lookaside;\r
-       ULONG Tag=0x11223344; //FIXME: Make this from tag\r
-\r
-       Lookaside = ExAllocatePool(NonPagedPool, sizeof(NPAGED_LOOKASIDE_LIST));\r
-       \r
-       ExInitializeNPagedLookasideList(\r
-               Lookaside,\r
-               NULL,\r
-               NULL,\r
-               0,\r
-               alloc_size,\r
-               Tag,\r
-               0);\r
-\r
-       return (kmem_cache_t *)Lookaside;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-BOOLEAN my_kmem_cache_destroy(kmem_cache_t *co)\r
-{\r
-       ExDeleteNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co);\r
-\r
-       ExFreePool(co);\r
-       return FALSE;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void *my_kmem_cache_alloc(kmem_cache_t *co, int flags)\r
-{\r
-       return ExAllocateFromNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co);\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void my_kmem_cache_free(kmem_cache_t *co, void *ptr)\r
-{\r
-       ExFreeToNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co, ptr);\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-// DMA, not used now\r
-/*------------------------------------------------------------------------*/ \r
-void *my_dma_pool_alloc(struct dma_pool *pool, int gfp_flags, dma_addr_t *dma_handle)\r
-{\r
-       // HalAllocCommonBuffer\r
-       // But ideally IoGetDmaAdapter\r
-       return NULL;\r
-}\r
+/*
+ * USB support based on Linux kernel source
+ *
+ * 2003-06-21 Georg Acher (georg@acher.org)
+ *
+ * Concept:
+ * 
+ * 1) Forget all device interrupts, scheduling, semaphores, threads etc.
+ * 1a) Forget all DMA and PCI helper functions
+ * 2) Forget usbdevfs, procfs and ioctls
+ * 3) Emulate OHCI interrupts and root hub timer by polling
+ * 4) Emulate hub kernel thread by polling
+ * 5) Emulate synchronous USB-messages (usb_*_msg) with busy waiting
+ *
+ * To be done:
+ * 6) Remove code bloat  
+ *
+ */
+
+#include "../usb_wrapper.h"
+
+/* internal state */
+
+static struct pci_dev *pci_probe_dev;
+extern int (*thread_handler)(void*);
+extern void* thread_parm;
+
+struct my_irqs reg_irqs[MAX_IRQS];
+int num_irqs;
+int need_wakeup;
+
+int my_jiffies;
+
+struct timer_list *main_timer_list[MAX_TIMERS];
+struct dummy_process act_cur={0};
+struct dummy_process *my_current;
+
+int (*thread_handler)(void*);
+void* thread_parm;
+
+#define MAX_DRVS 8
+static struct device_driver *m_drivers[MAX_DRVS];
+static int drvs_num;
+
+/*------------------------------------------------------------------------*/ 
+/* 
+ * Helper functions for top-level system
+ */
+/*------------------------------------------------------------------------*/ 
+void init_wrapper(struct pci_dev *probe_dev)
+{
+       int n;
+       for(n=0;n<MAX_TIMERS;n++)
+       {
+               main_timer_list[n]=NULL;
+       }
+
+       my_jiffies=0;
+       num_irqs=0;
+       my_current=&act_cur;
+       pci_probe_dev=probe_dev;
+
+       for(n=0;n<MAX_IRQS;n++)
+       {
+               reg_irqs[n].handler=NULL;
+               reg_irqs[n].irq=-1;
+       }
+       drvs_num=0;
+       need_wakeup=0;
+       for(n=0;n<MAX_DRVS;n++)
+               m_drivers[n]=NULL;
+}
+/*------------------------------------------------------------------------*/ 
+void handle_irqs(int irq)
+{
+       int n;
+//     printk("handle irqs\n");
+       for(n=0;n<MAX_IRQS;n++)
+       {
+               if (reg_irqs[n].handler && (irq==reg_irqs[n].irq || irq==-1))
+                       reg_irqs[n].handler(reg_irqs[n].irq,reg_irqs[n].data,NULL);
+       }
+}
+/*------------------------------------------------------------------------*/ 
+void inc_jiffies(int n)
+{
+       my_jiffies+=n;
+}
+/*------------------------------------------------------------------------*/ 
+void do_all_timers(void)
+{
+       int n;
+       for(n=0;n<MAX_TIMERS;n++)
+       {
+               if (main_timer_list[n] &&
+                   main_timer_list[n]->function && main_timer_list[n]->expires) 
+               {
+                       void (*function)(unsigned long)=main_timer_list[n]->function;
+                       unsigned long data=main_timer_list[n]->data;
+                       main_timer_list[n]->expires=0;
+
+                       main_timer_list[n]=NULL; // remove timer
+//                     printk("do timer %i fn %p\n",n,function);
+
+                       function(data);
+               }
+       }
+}
+/*------------------------------------------------------------------------*/ 
+// Purpose: Remember thread procedure and data in global var
+// ReactOS Purpose: Create real kernel thread
+int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags)
+{
+       HANDLE hThread;
+       //thread_handler=handler;
+       //thread_parm=parm;
+       //return 42; // PID :-)
+       
+       ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+       PsCreateSystemThread(&hThread,
+                            THREAD_ALL_ACCESS,
+                            NULL,
+                            NULL,
+                            NULL,
+                            (PKSTART_ROUTINE)handler,
+                                parm);
+
+    return (int)hThread; // FIXME: Correct?
+}
+
+// Kill the process
+int my_kill_proc(int pid, int signal, int unk)
+{
+       HANDLE hThread;
+
+       // TODO: Implement actual process killing
+
+       hThread = (HANDLE)pid;
+       ZwClose(hThread);
+
+       return 0;
+}
+
+/*------------------------------------------------------------------------*/ 
+/* Device management
+ * As simple as possible, but as complete as necessary ...
+ */
+/*------------------------------------------------------------------------*/ 
+
+
+/* calls probe function for hotplug (which does device matching), this is the
+only link between usbcore and the registered device drivers! */
+int my_device_add(struct device *dev)
+{
+       int n,found=0;
+//     printk("drv_num %i %p %p\n",drvs_num,m_drivers[0]->probe,m_drivers[1]->probe);
+       if (dev->driver)
+       {
+               if (dev->driver->probe)
+                       return dev->driver->probe(dev);
+       }
+       else
+       {
+               for(n=0;n<drvs_num;n++)
+               {
+                       if (m_drivers[n]->probe)
+                       {
+                               dev->driver=m_drivers[n];
+//                             printk("probe%i %p ",n,m_drivers[n]->probe);
+                               if (m_drivers[n]->probe(dev) == 0)
+                               {
+//                                     return 0;
+                                       found=1;
+                               }
+                       }
+               }
+               if (found) return 0;
+       }
+       dev->driver=NULL;
+       return -ENODEV;
+}
+/*------------------------------------------------------------------------*/ 
+int my_driver_register(struct device_driver *driver)
+{
+
+       if (drvs_num<MAX_DRVS)
+       {
+//             printk("driver_register %i: %p %p",drvs_num,driver,driver->probe);
+               m_drivers[drvs_num++]=driver;
+               return 0;
+       }
+       return -1;
+}
+/*------------------------------------------------------------------------*/ 
+int my_device_unregister(struct device *dev)
+{
+       if (dev->driver && dev->driver->remove)
+               dev->driver->remove(dev);
+       return 0;
+               
+}
+/*------------------------------------------------------------------------*/ 
+struct device *my_get_device(struct device *dev)
+{
+       return NULL;
+}
+/*------------------------------------------------------------------------*/ 
+void my_device_initialize(struct device *dev)
+{
+}
+/*------------------------------------------------------------------------*/ 
+void my_wake_up(PKEVENT evnt)
+{
+       need_wakeup=1;
+
+       KeSetEvent(evnt, 0, FALSE); // Signal event
+}
+/*------------------------------------------------------------------------*/ 
+void my_init_waitqueue_head(PKEVENT evnt)
+{
+       // this is used only in core/message.c, and it isn't needed there
+       //KeInitializeEvent(evnt, NotificationEvent, TRUE); // signalled state
+}
+/*------------------------------------------------------------------------*/ 
+/* wait until woken up (only one wait allowed!) */
+int my_schedule_timeout(int x)
+{
+       int wait=1;
+       x+=10; // safety
+//     printk("schedule_timeout %i\n",x);
+       while(x>0)
+       {
+               do_all_timers();
+#ifndef HAVE_IRQS
+               handle_irqs(-1);
+
+#endif
+               if (need_wakeup)
+                       break;
+               wait_ms(wait);
+               inc_jiffies(wait);
+               x-=wait;
+       }
+       need_wakeup=0;
+//     printk("schedule DONE!!!!!!\n");
+       return x;
+}
+/*------------------------------------------------------------------------*/ 
+void my_wait_for_completion(struct completion *x)
+{
+       int n=100;
+//     printk("wait for completion\n");
+       while(!x->done && (n>0))
+       {
+               do_all_timers();        
+#ifndef HAVE_IRQS
+               handle_irqs(-1);
+
+#endif
+               wait_ms(10);    
+               n--;
+       }
+//     printk("wait for completion done %i\n",x->done);
+}
+/*------------------------------------------------------------------------*/ 
+void my_interruptible_sleep_on(PKEVENT evnt)
+{
+       KeWaitForSingleObject(evnt, Executive, KernelMode, FALSE, NULL);
+       KeClearEvent(evnt); // reset to not-signalled
+}
+/*------------------------------------------------------------------------*/ 
+// Helper for pci_module_init
+/*------------------------------------------------------------------------*/ 
+int my_pci_module_init(struct pci_driver *x)
+{
+       struct pci_dev *dev=pci_probe_dev;
+       const struct pci_device_id *id=NULL;
+       if (!pci_probe_dev)
+       {
+               printk(KERN_ERR "PCI device not set!\n");
+               return 0;
+       }
+       x->probe(dev, id);
+       return 0;
+}
+/*------------------------------------------------------------------------*/ 
+struct pci_dev *my_pci_find_slot(int a,int b)
+{
+       return NULL;
+}
+/*------------------------------------------------------------------------*/ 
+int my_pci_write_config_word(struct pci_dev *dev, int where, u16 val)
+{
+       //dev->bus, dev->devfn, where, val
+       OHCI_DEVICE_EXTENSION *dev_ext = (OHCI_DEVICE_EXTENSION *)dev->dev_ext;
+
+       //FIXME: Is returning this value correct?
+       //FIXME: Mixing pci_dev and win structs isn't a good thing at all
+       return HalSetBusDataByOffset(PCIConfiguration, dev->bus->number, dev_ext->SystemIoSlotNumber, &val, where, sizeof(val));
+}
+/*------------------------------------------------------------------------*/ 
+int my_request_irq(unsigned int irq,
+                       int  (*handler)(int,void *, struct pt_regs *),
+                       unsigned long mode, const char *desc, void *data)
+{
+       if (num_irqs<MAX_IRQS)
+       {
+               reg_irqs[num_irqs].handler=handler;
+               reg_irqs[num_irqs].irq=irq;
+               reg_irqs[num_irqs].data=data;
+               num_irqs++;
+               return 0;
+       }
+       return 1;
+}
+/*------------------------------------------------------------------------*/ 
+int my_free_irq(int irq, void* p)
+{
+       /* No free... */
+       return 0;
+}
+/*------------------------------------------------------------------------*/ 
+// Lookaside funcs
+/*------------------------------------------------------------------------*/ 
+kmem_cache_t *my_kmem_cache_create(const char *tag, size_t alloc_size,
+                                                                  size_t offset, unsigned long flags,
+                                                                  void *ctor,
+                                                                  void *dtor)
+{
+       //TODO: Take in account ctor and dtor - callbacks for alloc/free, flags and offset
+       //FIXME: We assume this cache is always NPaged
+       PNPAGED_LOOKASIDE_LIST Lookaside;
+       ULONG Tag=0x11223344; //FIXME: Make this from tag
+
+       Lookaside = ExAllocatePool(NonPagedPool, sizeof(NPAGED_LOOKASIDE_LIST));
+       
+       ExInitializeNPagedLookasideList(
+               Lookaside,
+               NULL,
+               NULL,
+               0,
+               alloc_size,
+               Tag,
+               0);
+
+       return (kmem_cache_t *)Lookaside;
+}
+/*------------------------------------------------------------------------*/ 
+BOOLEAN my_kmem_cache_destroy(kmem_cache_t *co)
+{
+       ExDeleteNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co);
+
+       ExFreePool(co);
+       return FALSE;
+}
+/*------------------------------------------------------------------------*/ 
+void *my_kmem_cache_alloc(kmem_cache_t *co, int flags)
+{
+       return ExAllocateFromNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co);
+}
+/*------------------------------------------------------------------------*/ 
+void my_kmem_cache_free(kmem_cache_t *co, void *ptr)
+{
+       ExFreeToNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co, ptr);
+}
+/*------------------------------------------------------------------------*/ 
+// DMA, not used now
+/*------------------------------------------------------------------------*/ 
+void *my_dma_pool_alloc(struct dma_pool *pool, int gfp_flags, dma_addr_t *dma_handle)
+{
+       // HalAllocCommonBuffer
+       // But ideally IoGetDmaAdapter
+       return NULL;
+}
index b870731..c1df183 100644 (file)
-#include "../usb_wrapper.h"\r
-#include "config.h"\r
-#include "xremote.h"\r
-\r
-// This is for the Xpad\r
-extern unsigned char xpad_button_history[7];\r
-\r
-// This is for the Keyboard\r
-extern unsigned int current_keyboard_key;\r
-\r
-int risefall_xpad_BUTTON(unsigned char selected_Button) {\r
-       \r
-       int xpad_id; \r
-       int match;\r
-       extern int xpad_num;\r
-       \r
-       // USB keyboard section \r
-       \r
-       match=0;\r
-       if (current_keyboard_key!=0) {\r
-               switch (selected_Button) {\r
-                       case TRIGGER_XPAD_KEY_A :\r
-                               if (current_keyboard_key == 0x28) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_KEY_B :\r
-                               if (current_keyboard_key == 0x29) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_UP :\r
-                               if (current_keyboard_key == 0x52) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_DOWN :\r
-                               if (current_keyboard_key == 0x51) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_LEFT :\r
-                               if (current_keyboard_key == 0x50) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_RIGHT :\r
-                               if (current_keyboard_key == 0x4f) match=1;\r
-                               break;\r
-               }\r
-\r
-               if (match) {\r
-                       //A match occurred, so the event has now been processed\r
-                       //Clear it, and return success\r
-                       current_keyboard_key=0;\r
-                       return 1;\r
-               }\r
-       }\r
-       \r
-       // Xbox IR remote section\r
-       \r
-       match=0;\r
-       if (!remotekeyIsRepeat) {\r
-               /* We only grab the key event when the button is first pressed.\r
-                * If it's being held down, we ignore the multiple events this \r
-                * generates */\r
-               \r
-               switch (selected_Button) {\r
-                       case TRIGGER_XPAD_KEY_A:\r
-                               if (current_remote_key == RC_KEY_SELECT) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_UP:\r
-                               if (current_remote_key == RC_KEY_UP) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_DOWN:\r
-                               if (current_remote_key == RC_KEY_DOWN) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_LEFT:\r
-                               if (current_remote_key == RC_KEY_LEFT) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_PAD_RIGHT:\r
-                               if (current_remote_key == RC_KEY_RIGHT) match=1;\r
-                               break;\r
-                       case TRIGGER_XPAD_KEY_BACK:\r
-                               if (current_remote_key == RC_KEY_BACK) match=1;\r
-                               break;\r
-               }\r
-               if (match) {\r
-                       //A match occurred, so the event has now been processed\r
-                       //Clear it, and return success\r
-                       current_remote_key=0;\r
-                       remotekeyIsRepeat=0;\r
-                       return 1;\r
-               }\r
-       }\r
-               \r
-       // Xbox controller section\r
-       if (selected_Button < 6) {\r
-               \r
-                       unsigned char Button;\r
-               \r
-                       Button = XPAD_current[0].keys[selected_Button];\r
-       \r
-               if ((Button>0x30)&&(xpad_button_history[selected_Button]==0)) {\r
-                       // Button Rising Edge\r
-                       xpad_button_history[selected_Button] = 1;               \r
-                       return 1;\r
-               }       \r
-               \r
-               if ((Button==0x00)&&(xpad_button_history[selected_Button]==1)) {\r
-                       // Button Falling Edge\r
-                       xpad_button_history[selected_Button] = 0;               \r
-                       return -1;\r
-               }       \r
-       }\r
-       \r
-       if ((selected_Button > 5) & (selected_Button < 10) ) {\r
-       \r
-               unsigned char Buttonmask;\r
-                     \r
-               switch (selected_Button) {\r
-                       case TRIGGER_XPAD_PAD_UP :\r
-                                  Buttonmask = XPAD_PAD_UP; \r
-                                  break;\r
-                       case TRIGGER_XPAD_PAD_DOWN :\r
-                                  Buttonmask = XPAD_PAD_DOWN;\r
-                                  break;\r
-                       case TRIGGER_XPAD_PAD_LEFT :\r
-                                  Buttonmask = XPAD_PAD_LEFT;\r
-                                  break;\r
-                       case TRIGGER_XPAD_PAD_RIGHT :\r
-                                  Buttonmask = XPAD_PAD_RIGHT;\r
-                                  break;\r
-               }               \r
-                   \r
-               // Rising Edge\r
-               if (((XPAD_current[0].pad&Buttonmask) != 0) & ((xpad_button_history[6]&Buttonmask) == 0)) {\r
-                       xpad_button_history[6] ^= Buttonmask;  // Flip the Bit\r
-                       return 1;\r
-               }                               \r
-               // Falling Edge\r
-               if (((XPAD_current[0].pad&Buttonmask) == 0) & ((xpad_button_history[6]&Buttonmask) != 0)) {\r
-                       xpad_button_history[6] ^= Buttonmask;  // Flip the Bit\r
-                       return -1;\r
-               }\r
-       }\r
-       return 0;\r
-}\r
+#include "../usb_wrapper.h"
+#include "config.h"
+#include "xremote.h"
+
+// This is for the Xpad
+extern unsigned char xpad_button_history[7];
+
+// This is for the Keyboard
+extern unsigned int current_keyboard_key;
+
+int risefall_xpad_BUTTON(unsigned char selected_Button) {
+       
+       int xpad_id; 
+       int match;
+       extern int xpad_num;
+       
+       // USB keyboard section 
+       
+       match=0;
+       if (current_keyboard_key!=0) {
+               switch (selected_Button) {
+                       case TRIGGER_XPAD_KEY_A :
+                               if (current_keyboard_key == 0x28) match=1;
+                               break;
+                       case TRIGGER_XPAD_KEY_B :
+                               if (current_keyboard_key == 0x29) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_UP :
+                               if (current_keyboard_key == 0x52) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_DOWN :
+                               if (current_keyboard_key == 0x51) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_LEFT :
+                               if (current_keyboard_key == 0x50) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_RIGHT :
+                               if (current_keyboard_key == 0x4f) match=1;
+                               break;
+               }
+
+               if (match) {
+                       //A match occurred, so the event has now been processed
+                       //Clear it, and return success
+                       current_keyboard_key=0;
+                       return 1;
+               }
+       }
+       
+       // Xbox IR remote section
+       
+       match=0;
+       if (!remotekeyIsRepeat) {
+               /* We only grab the key event when the button is first pressed.
+                * If it's being held down, we ignore the multiple events this 
+                * generates */
+               
+               switch (selected_Button) {
+                       case TRIGGER_XPAD_KEY_A:
+                               if (current_remote_key == RC_KEY_SELECT) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_UP:
+                               if (current_remote_key == RC_KEY_UP) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_DOWN:
+                               if (current_remote_key == RC_KEY_DOWN) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_LEFT:
+                               if (current_remote_key == RC_KEY_LEFT) match=1;
+                               break;
+                       case TRIGGER_XPAD_PAD_RIGHT:
+                               if (current_remote_key == RC_KEY_RIGHT) match=1;
+                               break;
+                       case TRIGGER_XPAD_KEY_BACK:
+                               if (current_remote_key == RC_KEY_BACK) match=1;
+                               break;
+               }
+               if (match) {
+                       //A match occurred, so the event has now been processed
+                       //Clear it, and return success
+                       current_remote_key=0;
+                       remotekeyIsRepeat=0;
+                       return 1;
+               }
+       }
+               
+       // Xbox controller section
+       if (selected_Button < 6) {
+               
+                       unsigned char Button;
+               
+                       Button = XPAD_current[0].keys[selected_Button];
+       
+               if ((Button>0x30)&&(xpad_button_history[selected_Button]==0)) {
+                       // Button Rising Edge
+                       xpad_button_history[selected_Button] = 1;               
+                       return 1;
+               }       
+               
+               if ((Button==0x00)&&(xpad_button_history[selected_Button]==1)) {
+                       // Button Falling Edge
+                       xpad_button_history[selected_Button] = 0;               
+                       return -1;
+               }       
+       }
+       
+       if ((selected_Button > 5) & (selected_Button < 10) ) {
+       
+               unsigned char Buttonmask;
+                     
+               switch (selected_Button) {
+                       case TRIGGER_XPAD_PAD_UP :
+                                  Buttonmask = XPAD_PAD_UP; 
+                                  break;
+                       case TRIGGER_XPAD_PAD_DOWN :
+                                  Buttonmask = XPAD_PAD_DOWN;
+                                  break;
+                       case TRIGGER_XPAD_PAD_LEFT :
+                                  Buttonmask = XPAD_PAD_LEFT;
+                                  break;
+                       case TRIGGER_XPAD_PAD_RIGHT :
+                                  Buttonmask = XPAD_PAD_RIGHT;
+                                  break;
+               }               
+                   
+               // Rising Edge
+               if (((XPAD_current[0].pad&Buttonmask) != 0) & ((xpad_button_history[6]&Buttonmask) == 0)) {
+                       xpad_button_history[6] ^= Buttonmask;  // Flip the Bit
+                       return 1;
+               }                               
+               // Falling Edge
+               if (((XPAD_current[0].pad&Buttonmask) == 0) & ((xpad_button_history[6]&Buttonmask) != 0)) {
+                       xpad_button_history[6] ^= Buttonmask;  // Flip the Bit
+                       return -1;
+               }
+       }
+       return 0;
+}
index d97f1c6..9a27f77 100644 (file)
@@ -1,10 +1,10 @@
-#include "../usb_wrapper.h"\r
-\r
-\r
-void wait_ms(int mils)\r
-{\r
-       LARGE_INTEGER Interval;\r
-\r
-       Interval.QuadPart = -mils*10;\r
-       KeDelayExecutionThread(KernelMode, FALSE, &Interval);\r
-}\r
+#include "../usb_wrapper.h"
+
+
+void wait_ms(int mils)
+{
+       LARGE_INTEGER Interval;
+
+       Interval.QuadPart = -mils*10;
+       KeDelayExecutionThread(KernelMode, FALSE, &Interval);
+}
index efb237d..cab2d1e 100644 (file)
-#include "../usb_wrapper.h"\r
-\r
-#define keyboarddebug  0\r
-\r
-#if keyboarddebug\r
-extern int printe(const char *szFormat, ...);\r
-int ycoffset = 0;\r
-#endif\r
-\r
-unsigned int current_keyboard_key;\r
-\r
-struct usb_kbd_info {\r
-       struct urb *urb;\r
-       unsigned char kbd_pkt[8];\r
-       unsigned char old[8];\r
-\r
-       /*\r
-       struct input_dev dev;\r
-       struct usb_device *usbdev;\r
-       struct urb irq, led;\r
-       struct usb_ctrlrequest dr;\r
-       unsigned char leds, newleds;\r
-       char name[128];\r
-       int open;\r
-       */\r
-};\r
-\r
-static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct usb_kbd_info *kbd = urb->context;\r
-       int i;\r
-\r
-       if (urb->status) return;\r
-       \r
-       memcpy(kbd->kbd_pkt, urb->transfer_buffer, 8);\r
-       \r
-       current_keyboard_key = kbd->kbd_pkt[2];\r
-       \r
-       \r
-       #if keyboarddebug\r
-       ycoffset += 15;\r
-       ycoffset = ycoffset % 600;\r
-       VIDEO_CURSOR_POSX=20;\r
-       VIDEO_CURSOR_POSY=ycoffset;     \r
-       printe(" -%02x %02x %02x %02x %02x %02x\n",kbd->kbd_pkt[0],kbd->kbd_pkt[1],kbd->kbd_pkt[2],kbd->kbd_pkt[3],kbd->kbd_pkt[4],kbd->kbd_pkt[5]);\r
-       #endif\r
-       \r
-       usb_submit_urb(urb,GFP_ATOMIC);\r
-               \r
-}\r
-\r
-static int usb_kbd_probe(struct usb_interface *intf, const struct usb_device_id *id)\r
-{\r
-       struct urb *urb;\r
-       struct usb_device *udev = interface_to_usbdev (intf);\r
-       struct usb_endpoint_descriptor *ep_irq_in;\r
-       struct usb_endpoint_descriptor *ep_irq_out;\r
-       struct usb_kbd_info *usbk;\r
-\r
-       int i, pipe, maxp;\r
-       char *buf;\r
-\r
-       usbk=(struct usb_kbd_info *)kmalloc(sizeof(struct usb_kbd_info),0);\r
-       if (!usbk) return -1;\r
-\r
-       urb=usb_alloc_urb(0,0);\r
-       if (!urb) return -1;\r
-\r
-       usbk->urb=urb;\r
-\r
-       ep_irq_in = &intf->altsetting[0].endpoint[0].desc;\r
-       usb_fill_int_urb(urb, udev,\r
-                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),\r
-                         usbk->kbd_pkt, 8, usb_kbd_irq,\r
-                         usbk, 8);\r
-\r
-       usb_submit_urb(urb,GFP_ATOMIC);\r
-       usb_set_intfdata(intf,usbk);\r
-       #if keyboarddebug\r
-       printe("USB Keyboard Connected\n");     \r
-       #endif\r
-}\r
-\r
-\r
-static void usb_kbd_disconnect(struct usb_interface *intf)\r
-{\r
-       struct usb_kbd_info *usbk = usb_get_intfdata (intf);\r
-       usbprintk("Keyboard disconnected\n ");\r
-       usb_unlink_urb(usbk->urb);\r
-       usb_free_urb(usbk->urb);\r
-       kfree(usbk);\r
-}\r
-\r
-static struct usb_device_id usb_kbd_id_table [] = {\r
-       { USB_INTERFACE_INFO(3, 1, 1) },\r
-       { }                                             /* Terminating entry */\r
-};\r
-\r
-\r
-static struct usb_driver usb_kbd_driver = {\r
-       .owner =                THIS_MODULE,\r
-       .name =                 "keyboard",\r
-       .probe =                usb_kbd_probe,\r
-       .disconnect =           usb_kbd_disconnect,\r
-       .id_table =             usb_kbd_id_table,\r
-};\r
-\r
-void UsbKeyBoardInit(void)\r
-{\r
-\r
-       //current_remote_key=0;\r
-       //sbprintk("Keyboard probe %p ",xremote_probe);\r
-       if (usb_register(&usb_kbd_driver) < 0) {\r
-               #if keyboarddebug\r
-               printe("Unable to register Keyboard driver");\r
-               #endif\r
-               return;\r
-       }       \r
-}\r
-\r
-void UsbKeyBoardRemove(void) {\r
-       usb_deregister(&usb_kbd_driver);\r
-}\r
+#include "../usb_wrapper.h"
+
+#define keyboarddebug  0
+
+#if keyboarddebug
+extern int printe(const char *szFormat, ...);
+int ycoffset = 0;
+#endif
+
+unsigned int current_keyboard_key;
+
+struct usb_kbd_info {
+       struct urb *urb;
+       unsigned char kbd_pkt[8];
+       unsigned char old[8];
+
+       /*
+       struct input_dev dev;
+       struct usb_device *usbdev;
+       struct urb irq, led;
+       struct usb_ctrlrequest dr;
+       unsigned char leds, newleds;
+       char name[128];
+       int open;
+       */
+};
+
+static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_kbd_info *kbd = urb->context;
+       int i;
+
+       if (urb->status) return;
+       
+       memcpy(kbd->kbd_pkt, urb->transfer_buffer, 8);
+       
+       current_keyboard_key = kbd->kbd_pkt[2];
+       
+       
+       #if keyboarddebug
+       ycoffset += 15;
+       ycoffset = ycoffset % 600;
+       VIDEO_CURSOR_POSX=20;
+       VIDEO_CURSOR_POSY=ycoffset;     
+       printe(" -%02x %02x %02x %02x %02x %02x\n",kbd->kbd_pkt[0],kbd->kbd_pkt[1],kbd->kbd_pkt[2],kbd->kbd_pkt[3],kbd->kbd_pkt[4],kbd->kbd_pkt[5]);
+       #endif
+       
+       usb_submit_urb(urb,GFP_ATOMIC);
+               
+}
+
+static int usb_kbd_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct urb *urb;
+       struct usb_device *udev = interface_to_usbdev (intf);
+       struct usb_endpoint_descriptor *ep_irq_in;
+       struct usb_endpoint_descriptor *ep_irq_out;
+       struct usb_kbd_info *usbk;
+
+       int i, pipe, maxp;
+       char *buf;
+
+       usbk=(struct usb_kbd_info *)kmalloc(sizeof(struct usb_kbd_info),0);
+       if (!usbk) return -1;
+
+       urb=usb_alloc_urb(0,0);
+       if (!urb) return -1;
+
+       usbk->urb=urb;
+
+       ep_irq_in = &intf->altsetting[0].endpoint[0].desc;
+       usb_fill_int_urb(urb, udev,
+                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
+                         usbk->kbd_pkt, 8, usb_kbd_irq,
+                         usbk, 8);
+
+       usb_submit_urb(urb,GFP_ATOMIC);
+       usb_set_intfdata(intf,usbk);
+       #if keyboarddebug
+       printe("USB Keyboard Connected\n");     
+       #endif
+}
+
+
+static void usb_kbd_disconnect(struct usb_interface *intf)
+{
+       struct usb_kbd_info *usbk = usb_get_intfdata (intf);
+       usbprintk("Keyboard disconnected\n ");
+       usb_unlink_urb(usbk->urb);
+       usb_free_urb(usbk->urb);
+       kfree(usbk);
+}
+
+static struct usb_device_id usb_kbd_id_table [] = {
+       { USB_INTERFACE_INFO(3, 1, 1) },
+       { }                                             /* Terminating entry */
+};
+
+
+static struct usb_driver usb_kbd_driver = {
+       .owner =                THIS_MODULE,
+       .name =                 "keyboard",
+       .probe =                usb_kbd_probe,
+       .disconnect =           usb_kbd_disconnect,
+       .id_table =             usb_kbd_id_table,
+};
+
+void UsbKeyBoardInit(void)
+{
+
+       //current_remote_key=0;
+       //sbprintk("Keyboard probe %p ",xremote_probe);
+       if (usb_register(&usb_kbd_driver) < 0) {
+               #if keyboarddebug
+               printe("Unable to register Keyboard driver");
+               #endif
+               return;
+       }       
+}
+
+void UsbKeyBoardRemove(void) {
+       usb_deregister(&usb_kbd_driver);
+}
index f2de220..ce952e4 100644 (file)
@@ -1,65 +1,65 @@
-/*\r
- * Interface calls to BIOS\r
- *\r
- * 2003-06-21 Georg Acher (georg@acher.org)\r
- *\r
- */\r
-\r
-#include "boot.h"\r
-#include <stdarg.h>\r
-#include "video.h"\r
-\r
-/*------------------------------------------------------------------------*/ \r
-// Output window for USB messages\r
-int usb_curs_x=0;\r
-int usb_curs_y=0;\r
-\r
-void zxprintf(char* fmt, ...)\r
-{\r
-        va_list ap;\r
-        char buffer[1024];\r
-       int tmp_x, tmp_y;\r
-       tmp_x=VIDEO_CURSOR_POSX;\r
-       tmp_y=VIDEO_CURSOR_POSY;\r
-       \r
-       VIDEO_CURSOR_POSX=usb_curs_x;\r
-       VIDEO_CURSOR_POSY=usb_curs_y;\r
-              \r
-       if ((VIDEO_CURSOR_POSY==0) || (VIDEO_CURSOR_POSY > (vmode.height -16)))\r
-       {\r
-               BootVideoClearScreen(&jpegBackdrop, 3*vmode.height/4, \r
-                                    vmode.height);\r
-               VIDEO_CURSOR_POSY=3*vmode.height/4;\r
-       }\r
-\r
-        va_start(ap, fmt);\r
-        vsprintf(buffer,fmt,ap);\r
-        //printk(buffer);\r
-        va_end(ap);\r
-\r
-       usb_curs_x=VIDEO_CURSOR_POSX;\r
-       usb_curs_y=VIDEO_CURSOR_POSY;\r
-       VIDEO_CURSOR_POSX=tmp_x;\r
-       VIDEO_CURSOR_POSY=tmp_y;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int zxsnprintf(char *buffer, size_t s, char* fmt, ...)\r
-{\r
-        va_list ap;\r
-        int x;\r
-        va_start(ap, fmt);\r
-        x=vsprintf(buffer,fmt,ap);\r
-        va_end(ap);\r
-        return x;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-int zxsprintf(char *buffer, char* fmt, ...)\r
-{\r
-        va_list ap;\r
-        int x;\r
-        va_start(ap, fmt);\r
-        x=vsprintf(buffer,fmt,ap);\r
-        va_end(ap);\r
-        return x;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
+/*
+ * Interface calls to BIOS
+ *
+ * 2003-06-21 Georg Acher (georg@acher.org)
+ *
+ */
+
+#include "boot.h"
+#include <stdarg.h>
+#include "video.h"
+
+/*------------------------------------------------------------------------*/ 
+// Output window for USB messages
+int usb_curs_x=0;
+int usb_curs_y=0;
+
+void zxprintf(char* fmt, ...)
+{
+        va_list ap;
+        char buffer[1024];
+       int tmp_x, tmp_y;
+       tmp_x=VIDEO_CURSOR_POSX;
+       tmp_y=VIDEO_CURSOR_POSY;
+       
+       VIDEO_CURSOR_POSX=usb_curs_x;
+       VIDEO_CURSOR_POSY=usb_curs_y;
+              
+       if ((VIDEO_CURSOR_POSY==0) || (VIDEO_CURSOR_POSY > (vmode.height -16)))
+       {
+               BootVideoClearScreen(&jpegBackdrop, 3*vmode.height/4, 
+                                    vmode.height);
+               VIDEO_CURSOR_POSY=3*vmode.height/4;
+       }
+
+        va_start(ap, fmt);
+        vsprintf(buffer,fmt,ap);
+        //printk(buffer);
+        va_end(ap);
+
+       usb_curs_x=VIDEO_CURSOR_POSX;
+       usb_curs_y=VIDEO_CURSOR_POSY;
+       VIDEO_CURSOR_POSX=tmp_x;
+       VIDEO_CURSOR_POSY=tmp_y;
+}
+/*------------------------------------------------------------------------*/ 
+int zxsnprintf(char *buffer, size_t s, char* fmt, ...)
+{
+        va_list ap;
+        int x;
+        va_start(ap, fmt);
+        x=vsprintf(buffer,fmt,ap);
+        va_end(ap);
+        return x;
+}
+/*------------------------------------------------------------------------*/ 
+int zxsprintf(char *buffer, char* fmt, ...)
+{
+        va_list ap;
+        int x;
+        va_start(ap, fmt);
+        x=vsprintf(buffer,fmt,ap);
+        va_end(ap);
+        return x;
+}
+/*------------------------------------------------------------------------*/ 
index e6d3122..5536036 100644 (file)
-/*\r
- * Simple XPAD driver for XBOX\r
- *\r
- * (c) 2003-07-04, Georg Acher (georg@acher.org)\r
- *\r
- * Inspired by linux/drivers/usb/input/xpad.c\r
- * by Marko Friedemann <mfr@bmx-chemnitz.de>\r
- *\r
- */\r
-\r
-\r
-\r
-#include "../usb_wrapper.h"\r
-#include "config.h"\r
-\r
-// history for the Rising - falling events\r
-unsigned char xpad_button_history[7];\r
-\r
-/* Stores time and XPAD state */\r
-struct xpad_data XPAD_current[4];\r
-struct xpad_data XPAD_last[4];\r
-\r
-struct xpad_info\r
-{\r
-       struct urb *urb;\r
-       int num;\r
-       unsigned char data[32];\r
-};\r
-\r
-int xpad_num=0;\r
-/*------------------------------------------------------------------------*/ \r
-static void xpad_irq(struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct xpad_info *xpi = urb->context;\r
-       unsigned char* data= urb->transfer_buffer;\r
-       \r
-//     struct xpad_data *xp=&XPAD_current[xpi->num];\r
-//     struct xpad_data *xpo=&XPAD_last[xpi->num];\r
-\r
-       /* This hack means the xpad event always gets posted to the\r
-        * first xpad - avoids problems iterating over multiple xpads\r
-        * as the xpi->num entries are not reused when xpads are\r
-        * connected, then removed */\r
-\r
-       struct xpad_data *xp=&XPAD_current[0];\r
-       struct xpad_data *xpo=&XPAD_last[0];\r
-       \r
-       if (xpi->num<0 || xpi->num>3)\r
-               return;\r
-       \r
-       memcpy(xpo,xp,sizeof(struct xpad_data));\r
-       \r
-       xp->stick_left_x=(short) (((short)data[13] << 8) | data[12]);\r
-       xp->stick_left_y=(short) (((short)data[15] << 8) | data[14]);\r
-       xp->stick_right_x=(short) (((short)data[17] << 8) | data[16]);\r
-       xp->stick_right_y=(short) (((short)data[19] << 8) | data[18]);\r
-       xp->trig_left= data[10];\r
-       xp->trig_right= data[11];\r
-       xp->pad = data[2]&0xf;\r
-       xp->state = (data[2]>>4)&0xf;\r
-       xp->keys[0] = data[4]; // a\r
-       xp->keys[1] = data[5]; // b\r
-       xp->keys[2] = data[6]; // x\r
-       xp->keys[3] = data[7]; // y\r
-       xp->keys[4] = data[8]; // black\r
-       xp->keys[5] = data[9]; // white\r
-       xp->timestamp=jiffies; // FIXME: A more uniform flowing time would be better...         \r
-       usb_submit_urb(urb,GFP_ATOMIC);\r
-\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)\r
-{\r
-       struct urb *urb;\r
-       struct usb_device *udev = interface_to_usbdev (intf);\r
-       struct usb_endpoint_descriptor *ep_irq_in;\r
-       struct usb_endpoint_descriptor *ep_irq_out;\r
-       struct xpad_info *xpi;\r
-\r
-       xpi=kmalloc(sizeof(struct xpad_info),GFP_KERNEL);\r
-       if (!xpi) return -1;\r
-\r
-       urb=usb_alloc_urb(0,0);\r
-       if (!urb) return -1;\r
-\r
-       xpi->urb=urb;\r
-       xpi->num=xpad_num;\r
-       ep_irq_in = &intf->altsetting[0].endpoint[0].desc;\r
-       usb_fill_int_urb(urb, udev,\r
-                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),\r
-                         xpi->data, 32, xpad_irq,\r
-                         xpi, 32);\r
-\r
-       usb_submit_urb(urb,GFP_ATOMIC);\r
-\r
-       usb_set_intfdata(intf,xpi);\r
-       usbprintk("XPAD #%i connected\n",xpad_num);\r
-       #ifdef XPAD_VIBRA_STARTUP\r
-       {\r
-               // Brum Brum\r
-               char data1[6]={0,6,0,120,0,120};\r
-               char data2[6]={0,6,0,0,0,0};\r
-               int dummy;                      \r
-\r
-               usb_bulk_msg(udev, usb_sndbulkpipe(udev,2),\r
-                       data1, 6, &dummy, 500);\r
-               wait_ms(500);\r
-               usb_bulk_msg(udev, usb_sndbulkpipe(udev,2),\r
-                       data2, 6, &dummy, 500);         \r
-       }\r
-       #endif\r
-       xpad_num++;\r
-       return 0;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-static void xpad_disconnect(struct usb_interface *intf)\r
-{\r
-       struct xpad_info *xpi=usb_get_intfdata (intf);\r
-       usb_unlink_urb(xpi->urb);\r
-       usb_free_urb(xpi->urb);\r
-       kfree(xpi);\r
-       xpad_num--;\r
-}\r
-/*------------------------------------------------------------------------*/ \r
-static struct usb_device_id xpad_ids [] = {\r
-       { USB_DEVICE(0x044f, 0x0f07) },//Thrustmaster, Inc. Controller\r
-       { USB_DEVICE(0x045e, 0x0202) },//Microsoft Xbox Controller\r
-       { USB_DEVICE(0x045e, 0x0285) },//Microsoft Xbox Controller S\r
-       { USB_DEVICE(0x045e, 0x0289) },//Microsoft Xbox Controller S\r
-       { USB_DEVICE(0x046d, 0xca88) },//Logitech Compact Controller for Xbox\r
-       { USB_DEVICE(0x05fd, 0x1007) },//???Mad Catz Controller???\r
-       { USB_DEVICE(0x05fd, 0x107a) },//InterAct PowerPad Pro\r
-       { USB_DEVICE(0x0738, 0x4516) },//Mad Catz Control Pad\r
-       { USB_DEVICE(0x0738, 0x4522) },//Mad Catz LumiCON\r
-       { USB_DEVICE(0x0738, 0x4526) },//Mad Catz Control Pad Pro\r
-       { USB_DEVICE(0x0738, 0x4536) },//Mad Catz MicroCON\r
-       { USB_DEVICE(0x0738, 0x4556) },//Mad Catz Lynx Wireless Controller\r
-       { USB_DEVICE(0x0c12, 0x9902) },//HAMA VibraX - *FAULTY HARDWARE*\r
-       { USB_DEVICE(0x0e4c, 0x1097) },//Radica Gamester Controller\r
-       { USB_DEVICE(0x0e4c, 0x2390) },//Radica Games Jtech Controller\r
-       { USB_DEVICE(0x0e6f, 0x0003) },//Logic3 Freebird wireless Controller\r
-       { USB_DEVICE(0x0e6f, 0x0005) },//Eclipse wireless Controlle\r
-       { USB_DEVICE(0x0f30, 0x0202) },//Joytech Advanced Controller \r
-       { USB_DEVICE(0xffff, 0xffff) },//Chinese-made Xbox Controller \r
-       { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL\r
-        { }                            /* Terminating entry */   \r
-};\r
-\r
-\r
-static struct usb_driver xpad_driver = {\r
-       .owner =        THIS_MODULE,\r
-       .name =         "XPAD",\r
-       .probe =        xpad_probe,\r
-       .disconnect =   xpad_disconnect,\r
-       .id_table =     xpad_ids,\r
-};\r
-\r
-/*------------------------------------------------------------------------*/ \r
-void XPADInit(void)\r
-{\r
-       int n;\r
-       for(n=0;n<4;n++)\r
-       {\r
-               memset(&XPAD_current[n], 0, sizeof(struct xpad_data));\r
-               memset(&XPAD_last[n], 0, sizeof(struct xpad_data));\r
-       }\r
-       memset(&xpad_button_history, 0, sizeof(xpad_button_history));\r
-       \r
-       usbprintk("XPAD probe %p ",xpad_probe);\r
-       if (usb_register(&xpad_driver) < 0) {\r
-               err("Unable to register XPAD driver");\r
-               return;\r
-       }       \r
-}\r
-/*------------------------------------------------------------------------*/ \r
-void XPADRemove(void) {\r
-       usb_deregister(&xpad_driver);\r
-}\r
-\r
-/*------------------------------------------------------------------------*/ \r
-\r
-\r
-\r
+/*
+ * Simple XPAD driver for XBOX
+ *
+ * (c) 2003-07-04, Georg Acher (georg@acher.org)
+ *
+ * Inspired by linux/drivers/usb/input/xpad.c
+ * by Marko Friedemann <mfr@bmx-chemnitz.de>
+ *
+ */
+
+
+
+#include "../usb_wrapper.h"
+#include "config.h"
+
+// history for the Rising - falling events
+unsigned char xpad_button_history[7];
+
+/* Stores time and XPAD state */
+struct xpad_data XPAD_current[4];
+struct xpad_data XPAD_last[4];
+
+struct xpad_info
+{
+       struct urb *urb;
+       int num;
+       unsigned char data[32];
+};
+
+int xpad_num=0;
+/*------------------------------------------------------------------------*/ 
+static void xpad_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct xpad_info *xpi = urb->context;
+       unsigned char* data= urb->transfer_buffer;
+       
+//     struct xpad_data *xp=&XPAD_current[xpi->num];
+//     struct xpad_data *xpo=&XPAD_last[xpi->num];
+
+       /* This hack means the xpad event always gets posted to the
+        * first xpad - avoids problems iterating over multiple xpads
+        * as the xpi->num entries are not reused when xpads are
+        * connected, then removed */
+
+       struct xpad_data *xp=&XPAD_current[0];
+       struct xpad_data *xpo=&XPAD_last[0];
+       
+       if (xpi->num<0 || xpi->num>3)
+               return;
+       
+       memcpy(xpo,xp,sizeof(struct xpad_data));
+       
+       xp->stick_left_x=(short) (((short)data[13] << 8) | data[12]);
+       xp->stick_left_y=(short) (((short)data[15] << 8) | data[14]);
+       xp->stick_right_x=(short) (((short)data[17] << 8) | data[16]);
+       xp->stick_right_y=(short) (((short)data[19] << 8) | data[18]);
+       xp->trig_left= data[10];
+       xp->trig_right= data[11];
+       xp->pad = data[2]&0xf;
+       xp->state = (data[2]>>4)&0xf;
+       xp->keys[0] = data[4]; // a
+       xp->keys[1] = data[5]; // b
+       xp->keys[2] = data[6]; // x
+       xp->keys[3] = data[7]; // y
+       xp->keys[4] = data[8]; // black
+       xp->keys[5] = data[9]; // white
+       xp->timestamp=jiffies; // FIXME: A more uniform flowing time would be better...         
+       usb_submit_urb(urb,GFP_ATOMIC);
+
+}
+/*------------------------------------------------------------------------*/ 
+static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct urb *urb;
+       struct usb_device *udev = interface_to_usbdev (intf);
+       struct usb_endpoint_descriptor *ep_irq_in;
+       struct usb_endpoint_descriptor *ep_irq_out;
+       struct xpad_info *xpi;
+
+       xpi=kmalloc(sizeof(struct xpad_info),GFP_KERNEL);
+       if (!xpi) return -1;
+
+       urb=usb_alloc_urb(0,0);
+       if (!urb) return -1;
+
+       xpi->urb=urb;
+       xpi->num=xpad_num;
+       ep_irq_in = &intf->altsetting[0].endpoint[0].desc;
+       usb_fill_int_urb(urb, udev,
+                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
+                         xpi->data, 32, xpad_irq,
+                         xpi, 32);
+
+       usb_submit_urb(urb,GFP_ATOMIC);
+
+       usb_set_intfdata(intf,xpi);
+       usbprintk("XPAD #%i connected\n",xpad_num);
+       #ifdef XPAD_VIBRA_STARTUP
+       {
+               // Brum Brum
+               char data1[6]={0,6,0,120,0,120};
+               char data2[6]={0,6,0,0,0,0};
+               int dummy;                      
+
+               usb_bulk_msg(udev, usb_sndbulkpipe(udev,2),
+                       data1, 6, &dummy, 500);
+               wait_ms(500);
+               usb_bulk_msg(udev, usb_sndbulkpipe(udev,2),
+                       data2, 6, &dummy, 500);         
+       }
+       #endif
+       xpad_num++;
+       return 0;
+}
+/*------------------------------------------------------------------------*/ 
+static void xpad_disconnect(struct usb_interface *intf)
+{
+       struct xpad_info *xpi=usb_get_intfdata (intf);
+       usb_unlink_urb(xpi->urb);
+       usb_free_urb(xpi->urb);
+       kfree(xpi);
+       xpad_num--;
+}
+/*------------------------------------------------------------------------*/ 
+static struct usb_device_id xpad_ids [] = {
+       { USB_DEVICE(0x044f, 0x0f07) },//Thrustmaster, Inc. Controller
+       { USB_DEVICE(0x045e, 0x0202) },//Microsoft Xbox Controller
+       { USB_DEVICE(0x045e, 0x0285) },//Microsoft Xbox Controller S
+       { USB_DEVICE(0x045e, 0x0289) },//Microsoft Xbox Controller S
+       { USB_DEVICE(0x046d, 0xca88) },//Logitech Compact Controller for Xbox
+       { USB_DEVICE(0x05fd, 0x1007) },//???Mad Catz Controller???
+       { USB_DEVICE(0x05fd, 0x107a) },//InterAct PowerPad Pro
+       { USB_DEVICE(0x0738, 0x4516) },//Mad Catz Control Pad
+       { USB_DEVICE(0x0738, 0x4522) },//Mad Catz LumiCON
+       { USB_DEVICE(0x0738, 0x4526) },//Mad Catz Control Pad Pro
+       { USB_DEVICE(0x0738, 0x4536) },//Mad Catz MicroCON
+       { USB_DEVICE(0x0738, 0x4556) },//Mad Catz Lynx Wireless Controller
+       { USB_DEVICE(0x0c12, 0x9902) },//HAMA VibraX - *FAULTY HARDWARE*
+       { USB_DEVICE(0x0e4c, 0x1097) },//Radica Gamester Controller
+       { USB_DEVICE(0x0e4c, 0x2390) },//Radica Games Jtech Controller
+       { USB_DEVICE(0x0e6f, 0x0003) },//Logic3 Freebird wireless Controller
+       { USB_DEVICE(0x0e6f, 0x0005) },//Eclipse wireless Controlle
+       { USB_DEVICE(0x0f30, 0x0202) },//Joytech Advanced Controller 
+       { USB_DEVICE(0xffff, 0xffff) },//Chinese-made Xbox Controller 
+       { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL
+        { }                            /* Terminating entry */   
+};
+
+
+static struct usb_driver xpad_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "XPAD",
+       .probe =        xpad_probe,
+       .disconnect =   xpad_disconnect,
+       .id_table =     xpad_ids,
+};
+
+/*------------------------------------------------------------------------*/ 
+void XPADInit(void)
+{
+       int n;
+       for(n=0;n<4;n++)
+       {
+               memset(&XPAD_current[n], 0, sizeof(struct xpad_data));
+               memset(&XPAD_last[n], 0, sizeof(struct xpad_data));
+       }
+       memset(&xpad_button_history, 0, sizeof(xpad_button_history));
+       
+       usbprintk("XPAD probe %p ",xpad_probe);
+       if (usb_register(&xpad_driver) < 0) {
+               err("Unable to register XPAD driver");
+               return;
+       }       
+}
+/*------------------------------------------------------------------------*/ 
+void XPADRemove(void) {
+       usb_deregister(&xpad_driver);
+}
+
+/*------------------------------------------------------------------------*/ 
+
+
+
index 7f53f21..3b98dec 100644 (file)
-/*\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or \r
- * (at your option) any later version.\r
- * \r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- * \r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- * \r
- */\r
-\r
-/*\r
- *  $Id: xremote.c,v 1.5 2004/11/22 19:10:57 davidmpye Exp $\r
- *\r
- *  Copyright (c) 2002 Steven Toth <steve@toth.demon.co.uk>\r
- *\r
- *  XBOX DVD dongle infrared device driver for the input driver suite.\r
- *\r
- *  This work was derived from the usbkbd.c kernel module.\r
- *\r
- *  History:\r
- *\r
- *  2002_08_31 - 0.1 - Initial release\r
- *  2002_09_02 - 0.2 - Added IOCTL support enabling user space administration\r
- *                     of the translation matrix.\r
- *\r
- */\r
-\r
-#include "../usb_wrapper.h"\r
-\r
-\r
-u16 current_remote_key;\r
-u8 remotekeyIsRepeat;\r
-\r
-struct xremote_info \r
-{\r
-       struct urb *urb;\r
-       unsigned char irpkt[8];\r
-};\r
-\r
-/*  USB callback completion handler\r
- *  Code in transfer_buffer is received as six unsigned chars\r
- *  Example PLAY=00 06 ea 0a 40 00\r
- *  The command is located in byte[2], the rest are ignored.\r
- *  Key position is byte[4] bit0 (7-0 format) 0=down, 1=up\r
- *  All other bits are unknown / now required.\r
- */\r
-\r
-static void xremote_irq(struct urb *urb, struct pt_regs *regs)\r
-{\r
-       struct xremote_info *xri = urb->context;\r
-        \r
-       if (urb->status) return;\r
-       if (urb->actual_length < 6) return;\r
-\r
-       /* Messy/unnecessary, fix this */\r
-       memcpy(xri->irpkt, urb->transfer_buffer, 6);\r
-\r
-       /* Set the key action based in the sent action */\r
-       current_remote_key = ((xri->irpkt[2] & 0xff)<<8) | (xri->irpkt[3] & 0xff);\r
-\r
-       if (((xri->irpkt[4] & 0xff) + ((xri->irpkt[5] & 0xff ) << 8))>0x41) {\r
-               remotekeyIsRepeat=0;\r
-       }\r
-       else remotekeyIsRepeat=1;\r
-                            \r
-       usb_submit_urb(urb,GFP_ATOMIC);\r
-}\r
-\r
-static int xremote_probe(struct usb_interface *intf, const struct usb_device_id *id)\r
-{\r
-       struct urb *urb;\r
-       struct usb_device *udev = interface_to_usbdev (intf);\r
-       struct usb_endpoint_descriptor *ep_irq_in;\r
-       struct usb_endpoint_descriptor *ep_irq_out;\r
-       struct xremote_info *xri;\r
-\r
-       xri=(struct xremote_info *)kmalloc(sizeof(struct xremote_info),0);\r
-       if (!xri) return -1;\r
-\r
-       urb=usb_alloc_urb(0,0);\r
-       if (!urb) return -1;\r
-\r
-       xri->urb=urb;\r
-\r
-       ep_irq_in = &intf->altsetting[0].endpoint[0].desc;\r
-       usb_fill_int_urb(urb, udev,\r
-                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),\r
-                         xri->irpkt, 8, xremote_irq,\r
-                         xri, 8);\r
-\r
-       usb_submit_urb(urb,GFP_ATOMIC);\r
-       usb_set_intfdata(intf,xri);\r
-\r
-       usbprintk("DVD Remote connected\n");\r
-       return 0;\r
-}\r
-\r
-static void xremote_disconnect(struct usb_interface *intf)\r
-{\r
-       struct xremote_info *xri = usb_get_intfdata (intf);\r
-       usbprintk("DVD Remote disconnected\n ");\r
-       usb_unlink_urb(xri->urb);\r
-       usb_free_urb(xri->urb);\r
-       kfree(xri);\r
-}\r
-\r
-static struct usb_device_id xremote_id_table [] = {\r
-       { USB_DEVICE(0x040b, 0x6521) }, /* Gamester Xbox DVD Movie Playback Kit IR */\r
-       { USB_DEVICE(0x045e, 0x0284) }, /* Microsoft Xbox DVD Movie Playback Kit IR */\r
-       { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL\r
-       { } /* Terminating entry */\r
-};\r
-\r
-static struct usb_driver xremote_driver = {\r
-       .owner =                THIS_MODULE,\r
-       .name =                 "XRemote",\r
-       .probe =                xremote_probe,\r
-       .disconnect =           xremote_disconnect,\r
-       .id_table =             xremote_id_table,\r
-};\r
-\r
-void XRemoteInit(void)\r
-{\r
-\r
-       current_remote_key=0;\r
-       usbprintk("XRemote probe %p ",xremote_probe);\r
-       if (usb_register(&xremote_driver) < 0) {\r
-               err("Unable to register XRemote driver");\r
-               return;\r
-       }       \r
-}\r
-\r
-void XRemoteRemove(void) {\r
-       usb_deregister(&xremote_driver);\r
-}\r
+/*
+ * 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
+ * 
+ */
+
+/*
+ *  $Id$
+ *
+ *  Copyright (c) 2002 Steven Toth <steve@toth.demon.co.uk>
+ *
+ *  XBOX DVD dongle infrared device driver for the input driver suite.
+ *
+ *  This work was derived from the usbkbd.c kernel module.
+ *
+ *  History:
+ *
+ *  2002_08_31 - 0.1 - Initial release
+ *  2002_09_02 - 0.2 - Added IOCTL support enabling user space administration
+ *                     of the translation matrix.
+ *
+ */
+
+#include "../usb_wrapper.h"
+
+
+u16 current_remote_key;
+u8 remotekeyIsRepeat;
+
+struct xremote_info 
+{
+       struct urb *urb;
+       unsigned char irpkt[8];
+};
+
+/*  USB callback completion handler
+ *  Code in transfer_buffer is received as six unsigned chars
+ *  Example PLAY=00 06 ea 0a 40 00
+ *  The command is located in byte[2], the rest are ignored.
+ *  Key position is byte[4] bit0 (7-0 format) 0=down, 1=up
+ *  All other bits are unknown / now required.
+ */
+
+static void xremote_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct xremote_info *xri = urb->context;
+        
+       if (urb->status) return;
+       if (urb->actual_length < 6) return;
+
+       /* Messy/unnecessary, fix this */
+       memcpy(xri->irpkt, urb->transfer_buffer, 6);
+
+       /* Set the key action based in the sent action */
+       current_remote_key = ((xri->irpkt[2] & 0xff)<<8) | (xri->irpkt[3] & 0xff);
+
+       if (((xri->irpkt[4] & 0xff) + ((xri->irpkt[5] & 0xff ) << 8))>0x41) {
+               remotekeyIsRepeat=0;
+       }
+       else remotekeyIsRepeat=1;
+                            
+       usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+static int xremote_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct urb *urb;
+       struct usb_device *udev = interface_to_usbdev (intf);
+       struct usb_endpoint_descriptor *ep_irq_in;
+       struct usb_endpoint_descriptor *ep_irq_out;
+       struct xremote_info *xri;
+
+       xri=(struct xremote_info *)kmalloc(sizeof(struct xremote_info),0);
+       if (!xri) return -1;
+
+       urb=usb_alloc_urb(0,0);
+       if (!urb) return -1;
+
+       xri->urb=urb;
+
+       ep_irq_in = &intf->altsetting[0].endpoint[0].desc;
+       usb_fill_int_urb(urb, udev,
+                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
+                         xri->irpkt, 8, xremote_irq,
+                         xri, 8);
+
+       usb_submit_urb(urb,GFP_ATOMIC);
+       usb_set_intfdata(intf,xri);
+
+       usbprintk("DVD Remote connected\n");
+       return 0;
+}
+
+static void xremote_disconnect(struct usb_interface *intf)
+{
+       struct xremote_info *xri = usb_get_intfdata (intf);
+       usbprintk("DVD Remote disconnected\n ");
+       usb_unlink_urb(xri->urb);
+       usb_free_urb(xri->urb);
+       kfree(xri);
+}
+
+static struct usb_device_id xremote_id_table [] = {
+       { USB_DEVICE(0x040b, 0x6521) }, /* Gamester Xbox DVD Movie Playback Kit IR */
+       { USB_DEVICE(0x045e, 0x0284) }, /* Microsoft Xbox DVD Movie Playback Kit IR */
+       { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL
+       { } /* Terminating entry */
+};
+
+static struct usb_driver xremote_driver = {
+       .owner =                THIS_MODULE,
+       .name =                 "XRemote",
+       .probe =                xremote_probe,
+       .disconnect =           xremote_disconnect,
+       .id_table =             xremote_id_table,
+};
+
+void XRemoteInit(void)
+{
+
+       current_remote_key=0;
+       usbprintk("XRemote probe %p ",xremote_probe);
+       if (usb_register(&xremote_driver) < 0) {
+               err("Unable to register XRemote driver");
+               return;
+       }       
+}
+
+void XRemoteRemove(void) {
+       usb_deregister(&xremote_driver);
+}
index b117052..02196fe 100644 (file)
@@ -1,16 +1,16 @@
-PATH_TO_TOP = ../../../..\r
-\r
-TARGET_TYPE = export_driver\r
-\r
-TARGET_NAME = uhci\r
-\r
-TARGET_DDKLIBS = ntoskrnl.a usbcore.a\r
-\r
-TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE\r
-\r
-TARGET_OBJECTS = \\r
-  uhci-hcd.o uhci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o\r
-\r
-include $(PATH_TO_TOP)/rules.mak\r
-\r
-include $(TOOLS_PATH)/helper.mk\r
+PATH_TO_TOP = ../../../..
+
+TARGET_TYPE = export_driver
+
+TARGET_NAME = uhci
+
+TARGET_DDKLIBS = ntoskrnl.a usbcore.a
+
+TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE
+
+TARGET_OBJECTS = \
+  uhci-hcd.o uhci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
index d5eb940..5acdfd3 100644 (file)
@@ -1,5 +1,5 @@
-#define REACTOS_VERSION_DLL\r
-#define REACTOS_STR_FILE_DESCRIPTION   "USB UHCI Device Driver\0"\r
-#define REACTOS_STR_INTERNAL_NAME      "uhci\0"\r
-#define REACTOS_STR_ORIGINAL_FILENAME  "uhci.sys\0"\r
-#include <reactos/version.rc>\r
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION   "USB UHCI Device Driver\0"
+#define REACTOS_STR_INTERNAL_NAME      "uhci\0"
+#define REACTOS_STR_ORIGINAL_FILENAME  "uhci.sys\0"
+#include <reactos/version.rc>
index cd59c84..207aa32 100644 (file)
@@ -1,5 +1,5 @@
-/*\r
- * Configs for UHCI\r
- */\r
-\r
-#define CONFIG_PCI\r
+/*
+ * Configs for UHCI
+ */
+
+#define CONFIG_PCI
index b5cc952..d329f5f 100644 (file)
-/*\r
-   ReactOS specific functions for UHCI module\r
-   by Aleksey Bragin (aleksey@reactos.com)\r
-   Some parts of code are inspired (or even just copied) from ReactOS Videoport driver\r
-*/\r
-\r
-#include <ddk/ntddk.h>\r
-#include <debug.h>\r
-#include "../linux/linux_wrapper.h"\r
-#include "../host/ohci_main.h"\r
-\r
-// declare basic init funcs\r
-void init_wrapper(struct pci_dev *probe_dev);\r
-int uhci_hcd_init(void);\r
-void uhci_hcd_cleanup(void);\r
-int STDCALL usb_init(void);\r
-void STDCALL usb_exit(void);\r
-extern struct pci_driver uhci_pci_driver;\r
-extern const struct pci_device_id uhci_pci_ids[];\r
-\r
-\r
-\r
-// This should be removed, but for testing purposes it's here\r
-struct pci_dev *dev;\r
-//struct pci_device_id *dev_id;\r
-\r
-\r
-#define USB_UHCI_TAG TAG('u','s','b','u')\r
-\r
-NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)\r
-{\r
-       PDEVICE_OBJECT fdo;\r
-       NTSTATUS Status;\r
-       WCHAR DeviceBuffer[20];\r
-       UNICODE_STRING DeviceName;\r
-       POHCI_DRIVER_EXTENSION DriverExtension;\r
-       POHCI_DEVICE_EXTENSION DeviceExtension;\r
-       ULONG Size, DeviceNumber;\r
-\r
-       DPRINT1("uhci: AddDevice called\n");\r
-\r
-       // Allocate driver extension now\r
-       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);\r
-       if (DriverExtension == NULL)\r
-       {\r
-               Status = IoAllocateDriverObjectExtension(\r
-                                       DriverObject,\r
-                                       DriverObject,\r
-                                       sizeof(OHCI_DRIVER_EXTENSION),\r
-                                       (PVOID *)&DriverExtension);\r
-\r
-               if (!NT_SUCCESS(Status))\r
-               {\r
-                       DPRINT1("Allocating DriverObjectExtension failed.\n");\r
-                       return Status;\r
-               }\r
-       }\r
-   \r
-       // Create a unicode device name\r
-       DeviceNumber = 0; //TODO: Allocate new device number every time\r
-       swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber);\r
-       RtlInitUnicodeString(&DeviceName, DeviceBuffer);\r
-\r
-       Status = IoCreateDevice(DriverObject,\r
-                                   sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/,\r
-                                                       &DeviceName,\r
-                                                       FILE_DEVICE_CONTROLLER,\r
-                                                       0,\r
-                                                       FALSE,\r
-                                                       &fdo);\r
-\r
-       if (!NT_SUCCESS(Status))\r
-       {\r
-               DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);\r
-               return Status;\r
-       }\r
-\r
-       // zerofill device extension\r
-       DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension;\r
-       RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION));\r
-       DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);\r
-\r
-       fdo->Flags &= ~DO_DEVICE_INITIALIZING;\r
-\r
-       // Initialize device extension\r
-       DeviceExtension->DeviceNumber = DeviceNumber;\r
-       DeviceExtension->PhysicalDeviceObject = pdo;\r
-       DeviceExtension->FunctionalDeviceObject = fdo;\r
-       DeviceExtension->DriverExtension = DriverExtension;\r
-\r
-       /* Get bus number from the upper level bus driver. */\r
-       Size = sizeof(ULONG);\r
-       Status = IoGetDeviceProperty(\r
-                               pdo,\r
-                               DevicePropertyBusNumber,\r
-                               Size,\r
-                               &DeviceExtension->SystemIoBusNumber,\r
-                               &Size);\r
-       \r
-       if (!NT_SUCCESS(Status))\r
-       {\r
-               DPRINT("Couldn't get an information from bus driver. Panic!!!\n");\r
-               return Status;\r
-       }\r
-\r
-       DPRINT("Done AddDevice\n");\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject)\r
-{\r
-       DPRINT1("DriverUnload()\n");\r
-\r
-       // Exit usb device\r
-       usb_exit();\r
-\r
-       // Remove device (ohci_pci_driver.remove)\r
-       uhci_pci_driver.remove(dev);\r
-\r
-       ExFreePool(dev->slot_name);\r
-       ExFreePool(dev);\r
-\r
-       // Perform some cleanup\r
-       uhci_hcd_cleanup();\r
-}\r
-\r
-NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject)\r
-{\r
-       NTSTATUS Status;\r
-       POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-       // Fill generic linux structs\r
-       dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_UHCI_TAG);\r
-       \r
-       init_wrapper(dev);\r
-       dev->irq = DeviceExtension->InterruptVector;\r
-       dev->dev_ext = (PVOID)DeviceExtension;\r
-       dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_UHCI_TAG); // 128 max len for slot name\r
-\r
-       strcpy(dev->dev.name, "UnivHCI PCI-USB Controller");\r
-       strcpy(dev->slot_name, "UHCD PCI Slot");\r
-\r
-       // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL\r
-       Status = uhci_hcd_init();\r
-       //FIXME: Check status returned value\r
-\r
-       // Init core usb\r
-       usb_init();\r
-\r
-       // Probe device with real id now\r
-       uhci_pci_driver.probe(dev, uhci_pci_ids);\r
-\r
-       DPRINT("InitLinuxWrapper() done\n");\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS STDCALL\r
-OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject,\r
-                                       IN PIRP Irp)\r
-{\r
-       PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);\r
-       PDRIVER_OBJECT DriverObject;\r
-       POHCI_DRIVER_EXTENSION DriverExtension;\r
-       POHCI_DEVICE_EXTENSION DeviceExtension;\r
-       PCM_RESOURCE_LIST AllocatedResources;\r
-\r
-       /*\r
-       * Get the initialization data we saved in VideoPortInitialize.\r
-       */\r
-       DriverObject = DeviceObject->DriverObject;\r
-       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);\r
-       DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;\r
-\r
-       /*\r
-       * Store some resources in the DeviceExtension.\r
-       */\r
-       AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;\r
-       if (AllocatedResources != NULL)\r
-       {\r
-               CM_FULL_RESOURCE_DESCRIPTOR     *FullList;\r
-               CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;\r
-               ULONG ResourceCount;\r
-               ULONG ResourceListSize;\r
-\r
-               /* Save the     resource list */\r
-               ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;\r
-               ResourceListSize =\r
-                       FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.\r
-                       PartialDescriptors[ResourceCount]);\r
-               DeviceExtension->AllocatedResources     = ExAllocatePool(PagedPool,     ResourceListSize);\r
-               if (DeviceExtension->AllocatedResources == NULL)\r
-               {\r
-                       return STATUS_INSUFFICIENT_RESOURCES;\r
-               }\r
-\r
-               RtlCopyMemory(DeviceExtension->AllocatedResources,\r
-                       AllocatedResources,\r
-                       ResourceListSize);\r
-\r
-               /* Get the interrupt level/vector -     needed by HwFindAdapter sometimes */\r
-               for     (FullList =     AllocatedResources->List;\r
-                       FullList < AllocatedResources->List     + AllocatedResources->Count;\r
-                       FullList++)\r
-               {\r
-                       /* FIXME: Is this ASSERT ok     for     resources from the PNP manager? */\r
-                       /*ASSERT(FullList->InterfaceType == PCIBus &&\r
-                               FullList->BusNumber     == DeviceExtension->SystemIoBusNumber &&\r
-                               1 == FullList->PartialResourceList.Version &&\r
-                               1 == FullList->PartialResourceList.Revision);*/\r
-                       DPRINT1("AllocRess->Count: %d, PartResList.Count: %d\n",\r
-                                       AllocatedResources->Count, FullList->PartialResourceList.Count);\r
-\r
-                       for     (Descriptor     = FullList->PartialResourceList.PartialDescriptors;\r
-                               Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;\r
-                               Descriptor++)\r
-                       {\r
-                               if (Descriptor->Type == CmResourceTypeInterrupt)\r
-                               {\r
-                                       DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;\r
-                                       DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;\r
-\r
-                       DPRINT1("Interrupt level: 0x%x Interrupt        Vector: 0x%x\n",\r
-                                 DeviceExtension->InterruptLevel,\r
-                                 DeviceExtension->InterruptVector);\r
-                               }\r
-                               else if (Descriptor->Type == CmResourceTypePort)\r
-                               {\r
-                                       DeviceExtension->BaseAddress    = Descriptor->u.Port.Start;\r
-                                       DeviceExtension->BaseAddrLength = Descriptor->u.Port.Length;\r
-                                       DeviceExtension->Flags          = Descriptor->Flags;\r
-                                       \r
-                               DPRINT1("I/O resource: start=0x%x, length=0x%x\n",\r
-                                 DeviceExtension->BaseAddress.u.LowPart, DeviceExtension->BaseAddrLength);\r
-                               }\r
-                               else\r
-                               DPRINT1("Get resource type: %d, Generic start=0x%x Generic length=0x%x\n",\r
-                                       Descriptor->Type, Descriptor->u.Generic.Start.u.LowPart, Descriptor->u.Generic.Length);\r
-                               \r
-                       }\r
-               }\r
-       }\r
-\r
-       /*\r
-       * Init wrapper with this object\r
-       */\r
-       return InitLinuxWrapper(DeviceObject);\r
-}\r
-\r
-// Dispatch PNP\r
-NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)\r
-{\r
-   PIO_STACK_LOCATION IrpSp;\r
-   NTSTATUS Status;\r
-\r
-   IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-   switch (IrpSp->MinorFunction)\r
-   {\r
-      case IRP_MN_START_DEVICE:\r
-         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);\r
-         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))\r
-         \r
-                Status = OHCD_PnPStartDevice(DeviceObject, Irp);\r
-         Irp->IoStatus.Status = Status;\r
-         Irp->IoStatus.Information = 0;\r
-         IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-         break;\r
-\r
-\r
-      case IRP_MN_REMOVE_DEVICE:\r
-      case IRP_MN_QUERY_REMOVE_DEVICE:\r
-      case IRP_MN_CANCEL_REMOVE_DEVICE:\r
-      case IRP_MN_SURPRISE_REMOVAL:\r
-\r
-      case IRP_MN_STOP_DEVICE:\r
-         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);\r
-         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))\r
-            Status = STATUS_SUCCESS;\r
-         Irp->IoStatus.Status = Status;\r
-         Irp->IoStatus.Information = 0;\r
-         IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-\r
-                IoDeleteDevice(DeviceObject); // just delete device for now\r
-         break;\r
-\r
-      case IRP_MN_QUERY_STOP_DEVICE:\r
-      case IRP_MN_CANCEL_STOP_DEVICE:\r
-         Status = STATUS_SUCCESS;\r
-         Irp->IoStatus.Status = STATUS_SUCCESS;\r
-         Irp->IoStatus.Information = 0;\r
-         IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-         break;\r
-         \r
-      default:\r
-         return STATUS_NOT_IMPLEMENTED;\r
-         break;\r
-   }\r
-   \r
-   return Status;\r
-}\r
-\r
-NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)\r
-{\r
-       DbgPrint("IRP_MJ_POWER dispatch\n");\r
-       return STATUS_SUCCESS;\r
-}\r
-\r
-/*\r
- * Standard DriverEntry method.\r
- */\r
-NTSTATUS STDCALL\r
-DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)\r
-{\r
-       DriverObject->DriverUnload = DriverUnload;\r
-       DriverObject->DriverExtension->AddDevice = AddDevice;\r
-       DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;\r
-       DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;\r
-\r
-       return STATUS_SUCCESS;\r
-}\r
+/*
+   ReactOS specific functions for UHCI module
+   by Aleksey Bragin (aleksey@reactos.com)
+   Some parts of code are inspired (or even just copied) from ReactOS Videoport driver
+*/
+
+#include <ddk/ntddk.h>
+#include <debug.h>
+#include "../linux/linux_wrapper.h"
+#include "../host/ohci_main.h"
+
+// declare basic init funcs
+void init_wrapper(struct pci_dev *probe_dev);
+int uhci_hcd_init(void);
+void uhci_hcd_cleanup(void);
+int STDCALL usb_init(void);
+void STDCALL usb_exit(void);
+extern struct pci_driver uhci_pci_driver;
+extern const struct pci_device_id uhci_pci_ids[];
+
+
+
+// This should be removed, but for testing purposes it's here
+struct pci_dev *dev;
+//struct pci_device_id *dev_id;
+
+
+#define USB_UHCI_TAG TAG('u','s','b','u')
+
+NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)
+{
+       PDEVICE_OBJECT fdo;
+       NTSTATUS Status;
+       WCHAR DeviceBuffer[20];
+       UNICODE_STRING DeviceName;
+       POHCI_DRIVER_EXTENSION DriverExtension;
+       POHCI_DEVICE_EXTENSION DeviceExtension;
+       ULONG Size, DeviceNumber;
+
+       DPRINT1("uhci: AddDevice called\n");
+
+       // Allocate driver extension now
+       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+       if (DriverExtension == NULL)
+       {
+               Status = IoAllocateDriverObjectExtension(
+                                       DriverObject,
+                                       DriverObject,
+                                       sizeof(OHCI_DRIVER_EXTENSION),
+                                       (PVOID *)&DriverExtension);
+
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT1("Allocating DriverObjectExtension failed.\n");
+                       return Status;
+               }
+       }
+   
+       // Create a unicode device name
+       DeviceNumber = 0; //TODO: Allocate new device number every time
+       swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber);
+       RtlInitUnicodeString(&DeviceName, DeviceBuffer);
+
+       Status = IoCreateDevice(DriverObject,
+                                   sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/,
+                                                       &DeviceName,
+                                                       FILE_DEVICE_CONTROLLER,
+                                                       0,
+                                                       FALSE,
+                                                       &fdo);
+
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status);
+               return Status;
+       }
+
+       // zerofill device extension
+       DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension;
+       RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION));
+       DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
+
+       fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+       // Initialize device extension
+       DeviceExtension->DeviceNumber = DeviceNumber;
+       DeviceExtension->PhysicalDeviceObject = pdo;
+       DeviceExtension->FunctionalDeviceObject = fdo;
+       DeviceExtension->DriverExtension = DriverExtension;
+
+       /* Get bus number from the upper level bus driver. */
+       Size = sizeof(ULONG);
+       Status = IoGetDeviceProperty(
+                               pdo,
+                               DevicePropertyBusNumber,
+                               Size,
+                               &DeviceExtension->SystemIoBusNumber,
+                               &Size);
+       
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("Couldn't get an information from bus driver. Panic!!!\n");
+               return Status;
+       }
+
+       DPRINT("Done AddDevice\n");
+       return STATUS_SUCCESS;
+}
+
+VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject)
+{
+       DPRINT1("DriverUnload()\n");
+
+       // Exit usb device
+       usb_exit();
+
+       // Remove device (ohci_pci_driver.remove)
+       uhci_pci_driver.remove(dev);
+
+       ExFreePool(dev->slot_name);
+       ExFreePool(dev);
+
+       // Perform some cleanup
+       uhci_hcd_cleanup();
+}
+
+NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject)
+{
+       NTSTATUS Status;
+       POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+       // Fill generic linux structs
+       dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_UHCI_TAG);
+       
+       init_wrapper(dev);
+       dev->irq = DeviceExtension->InterruptVector;
+       dev->dev_ext = (PVOID)DeviceExtension;
+       dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_UHCI_TAG); // 128 max len for slot name
+
+       strcpy(dev->dev.name, "UnivHCI PCI-USB Controller");
+       strcpy(dev->slot_name, "UHCD PCI Slot");
+
+       // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL
+       Status = uhci_hcd_init();
+       //FIXME: Check status returned value
+
+       // Init core usb
+       usb_init();
+
+       // Probe device with real id now
+       uhci_pci_driver.probe(dev, uhci_pci_ids);
+
+       DPRINT("InitLinuxWrapper() done\n");
+
+       return STATUS_SUCCESS;
+}
+
+NTSTATUS STDCALL
+OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject,
+                                       IN PIRP Irp)
+{
+       PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
+       PDRIVER_OBJECT DriverObject;
+       POHCI_DRIVER_EXTENSION DriverExtension;
+       POHCI_DEVICE_EXTENSION DeviceExtension;
+       PCM_RESOURCE_LIST AllocatedResources;
+
+       /*
+       * Get the initialization data we saved in VideoPortInitialize.
+       */
+       DriverObject = DeviceObject->DriverObject;
+       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+       DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+       /*
+       * Store some resources in the DeviceExtension.
+       */
+       AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources;
+       if (AllocatedResources != NULL)
+       {
+               CM_FULL_RESOURCE_DESCRIPTOR     *FullList;
+               CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
+               ULONG ResourceCount;
+               ULONG ResourceListSize;
+
+               /* Save the     resource list */
+               ResourceCount = AllocatedResources->List[0].PartialResourceList.Count;
+               ResourceListSize =
+                       FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
+                       PartialDescriptors[ResourceCount]);
+               DeviceExtension->AllocatedResources     = ExAllocatePool(PagedPool,     ResourceListSize);
+               if (DeviceExtension->AllocatedResources == NULL)
+               {
+                       return STATUS_INSUFFICIENT_RESOURCES;
+               }
+
+               RtlCopyMemory(DeviceExtension->AllocatedResources,
+                       AllocatedResources,
+                       ResourceListSize);
+
+               /* Get the interrupt level/vector -     needed by HwFindAdapter sometimes */
+               for     (FullList =     AllocatedResources->List;
+                       FullList < AllocatedResources->List     + AllocatedResources->Count;
+                       FullList++)
+               {
+                       /* FIXME: Is this ASSERT ok     for     resources from the PNP manager? */
+                       /*ASSERT(FullList->InterfaceType == PCIBus &&
+                               FullList->BusNumber     == DeviceExtension->SystemIoBusNumber &&
+                               1 == FullList->PartialResourceList.Version &&
+                               1 == FullList->PartialResourceList.Revision);*/
+                       DPRINT1("AllocRess->Count: %d, PartResList.Count: %d\n",
+                                       AllocatedResources->Count, FullList->PartialResourceList.Count);
+
+                       for     (Descriptor     = FullList->PartialResourceList.PartialDescriptors;
+                               Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
+                               Descriptor++)
+                       {
+                               if (Descriptor->Type == CmResourceTypeInterrupt)
+                               {
+                                       DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
+                                       DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
+
+                       DPRINT1("Interrupt level: 0x%x Interrupt        Vector: 0x%x\n",
+                                 DeviceExtension->InterruptLevel,
+                                 DeviceExtension->InterruptVector);
+                               }
+                               else if (Descriptor->Type == CmResourceTypePort)
+                               {
+                                       DeviceExtension->BaseAddress    = Descriptor->u.Port.Start;
+                                       DeviceExtension->BaseAddrLength = Descriptor->u.Port.Length;
+                                       DeviceExtension->Flags          = Descriptor->Flags;
+                                       
+                               DPRINT1("I/O resource: start=0x%x, length=0x%x\n",
+                                 DeviceExtension->BaseAddress.u.LowPart, DeviceExtension->BaseAddrLength);
+                               }
+                               else
+                               DPRINT1("Get resource type: %d, Generic start=0x%x Generic length=0x%x\n",
+                                       Descriptor->Type, Descriptor->u.Generic.Start.u.LowPart, Descriptor->u.Generic.Length);
+                               
+                       }
+               }
+       }
+
+       /*
+       * Init wrapper with this object
+       */
+       return InitLinuxWrapper(DeviceObject);
+}
+
+// Dispatch PNP
+NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+   PIO_STACK_LOCATION IrpSp;
+   NTSTATUS Status;
+
+   IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+   switch (IrpSp->MinorFunction)
+   {
+      case IRP_MN_START_DEVICE:
+         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
+         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+         
+                Status = OHCD_PnPStartDevice(DeviceObject, Irp);
+         Irp->IoStatus.Status = Status;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+         break;
+
+
+      case IRP_MN_REMOVE_DEVICE:
+      case IRP_MN_QUERY_REMOVE_DEVICE:
+      case IRP_MN_CANCEL_REMOVE_DEVICE:
+      case IRP_MN_SURPRISE_REMOVAL:
+
+      case IRP_MN_STOP_DEVICE:
+         //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp);
+         //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+            Status = STATUS_SUCCESS;
+         Irp->IoStatus.Status = Status;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+                IoDeleteDevice(DeviceObject); // just delete device for now
+         break;
+
+      case IRP_MN_QUERY_STOP_DEVICE:
+      case IRP_MN_CANCEL_STOP_DEVICE:
+         Status = STATUS_SUCCESS;
+         Irp->IoStatus.Status = STATUS_SUCCESS;
+         Irp->IoStatus.Information = 0;
+         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+         break;
+         
+      default:
+         return STATUS_NOT_IMPLEMENTED;
+         break;
+   }
+   
+   return Status;
+}
+
+NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp)
+{
+       DbgPrint("IRP_MJ_POWER dispatch\n");
+       return STATUS_SUCCESS;
+}
+
+/*
+ * Standard DriverEntry method.
+ */
+NTSTATUS STDCALL
+DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath)
+{
+       DriverObject->DriverUnload = DriverUnload;
+       DriverObject->DriverExtension->AddDevice = AddDevice;
+       DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
+       DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
+
+       return STATUS_SUCCESS;
+}
index 4b810ca..74b46f9 100644 (file)
@@ -1,15 +1,15 @@
-//#include <stdlib.h>\r
-//#include <ntos/types.h>\r
-//#include <ddk/extypes.h>\r
-#include <ddk/ntddk.h>\r
-#include <debug.h>\r
-\r
-void wait_ms(int mils);\r
-\r
-#include "linux/linux_wrapper.h"\r
-#define __KERNEL__\r
-#undef CONFIG_PCI\r
-#define CONFIG_PCI\r
-\r
-#include "linux/usb.h"\r
+//#include <stdlib.h>
+//#include <ntos/types.h>
+//#include <ddk/extypes.h>
+#include <ddk/ntddk.h>
+#include <debug.h>
+
+void wait_ms(int mils);
+
+#include "linux/linux_wrapper.h"
+#define __KERNEL__
+#undef CONFIG_PCI
+#define CONFIG_PCI
+
+#include "linux/usb.h"
 #include "linux/pci_ids.h"
\ No newline at end of file
 #include "linux/pci_ids.h"
\ No newline at end of file