]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[usb] Add functions for manual device address assignment
authorMichael Brown <mcb30@ipxe.org>
Mon, 16 Mar 2015 15:37:39 +0000 (15:37 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 16 Mar 2015 15:42:29 +0000 (15:42 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/bus/usb.c
src/include/ipxe/usb.h

index 57a2533208b484737d5c6261b78ac544a7276104..548aa7b08ef50099c34c418be45ca526239bf84c 100644 (file)
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
@@ -1849,6 +1850,49 @@ void free_usb_bus ( struct usb_bus *bus ) {
        free ( bus );
 }
 
+/******************************************************************************
+ *
+ * USB address assignment
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate device address
+ *
+ * @v bus              USB bus
+ * @ret address                Device address, or negative error
+ */
+int usb_alloc_address ( struct usb_bus *bus ) {
+       unsigned int address;
+
+       /* Find first free device address */
+       address = ffsll ( ~bus->addresses );
+       if ( ! address )
+               return -ENOENT;
+
+       /* Mark address as used */
+       bus->addresses |= ( 1ULL << ( address - 1 ) );
+
+       return address;
+}
+
+/**
+ * Free device address
+ *
+ * @v bus              USB bus
+ * @v address          Device address
+ */
+void usb_free_address ( struct usb_bus *bus, unsigned int address ) {
+
+       /* Sanity check */
+       assert ( address > 0 );
+       assert ( bus->addresses & ( 1ULL << ( address - 1 ) ) );
+
+       /* Mark address as free */
+       bus->addresses &= ~( 1ULL << ( address - 1 ) );
+}
+
 /******************************************************************************
  *
  * USB bus topology
index fd027d188d7306fc942acdf8a47c6075a37b926a..70038368b1a161fe88bb9a94b28853720e2f08bb 100644 (file)
@@ -867,6 +867,17 @@ struct usb_bus {
 
        /** Largest transfer allowed on the bus */
        size_t mtu;
+       /** Address in-use mask
+        *
+        * This is used only by buses which perform manual address
+        * assignment.  USB allows for addresses in the range [1,127].
+        * We use a simple bitmask which restricts us to the range
+        * [1,64]; this is unlikely to be a problem in practice.  For
+        * comparison: controllers which perform autonomous address
+        * assignment (such as xHCI) typically allow for only 32
+        * devices per bus anyway.
+        */
+       unsigned long long addresses;
 
        /** Root hub */
        struct usb_hub *hub;
@@ -1021,6 +1032,19 @@ usb_set_feature ( struct usb_device *usb, unsigned int type,
                             feature, index, NULL, 0 );
 }
 
+/**
+ * Set address
+ *
+ * @v usb              USB device
+ * @v address          Device address
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_address ( struct usb_device *usb, unsigned int address ) {
+
+       return usb_control ( usb, USB_SET_ADDRESS, address, 0, NULL, 0 );
+}
+
 /**
  * Get USB descriptor
  *
@@ -1148,6 +1172,8 @@ extern int register_usb_bus ( struct usb_bus *bus );
 extern void unregister_usb_bus ( struct usb_bus *bus );
 extern void free_usb_bus ( struct usb_bus *bus );
 
+extern int usb_alloc_address ( struct usb_bus *bus );
+extern void usb_free_address ( struct usb_bus *bus, unsigned int address );
 extern unsigned int usb_route_string ( struct usb_device *usb );
 extern unsigned int usb_depth ( struct usb_device *usb );
 extern struct usb_port * usb_root_hub_port ( struct usb_device *usb );