mirror of https://github.com/ipxe/ipxe.git
[usb] Add "usbscan" command for iterating over USB devices
Implement a "usbscan" command as a direct analogy of the existing "pciscan" command, allowing scripts to iterate over all detected USB devices. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/875/merge
parent
2bf16c6ffc
commit
c219b5d8a9
|
@ -302,6 +302,9 @@ REQUIRE_OBJECT ( shim_cmd );
|
||||||
#ifdef IMAGE_CRYPT_CMD
|
#ifdef IMAGE_CRYPT_CMD
|
||||||
REQUIRE_OBJECT ( image_crypt_cmd );
|
REQUIRE_OBJECT ( image_crypt_cmd );
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USB_CMD
|
||||||
|
REQUIRE_OBJECT ( usb_cmd );
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drag in miscellaneous objects
|
* Drag in miscellaneous objects
|
||||||
|
|
|
@ -171,6 +171,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
//#define IMAGE_MEM_CMD /* Read memory command */
|
//#define IMAGE_MEM_CMD /* Read memory command */
|
||||||
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
|
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
|
||||||
#define SHIM_CMD /* EFI shim command (or dummy command) */
|
#define SHIM_CMD /* EFI shim command (or dummy command) */
|
||||||
|
//#define USB_CMD /* USB commands */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ROM-specific options
|
* ROM-specific options
|
||||||
|
|
|
@ -1323,7 +1323,8 @@ usb_probe_all ( struct usb_device *usb,
|
||||||
func->name = func->dev.name;
|
func->name = func->dev.name;
|
||||||
func->usb = usb;
|
func->usb = usb;
|
||||||
func->dev.desc.bus_type = BUS_TYPE_USB;
|
func->dev.desc.bus_type = BUS_TYPE_USB;
|
||||||
func->dev.desc.location = usb->address;
|
func->dev.desc.location =
|
||||||
|
USB_BUSDEV ( bus->address, usb->address );
|
||||||
func->dev.desc.vendor = le16_to_cpu ( usb->device.vendor );
|
func->dev.desc.vendor = le16_to_cpu ( usb->device.vendor );
|
||||||
func->dev.desc.device = le16_to_cpu ( usb->device.product );
|
func->dev.desc.device = le16_to_cpu ( usb->device.product );
|
||||||
snprintf ( func->dev.name, sizeof ( func->dev.name ),
|
snprintf ( func->dev.name, sizeof ( func->dev.name ),
|
||||||
|
@ -1725,6 +1726,25 @@ static void free_usb ( struct usb_device *usb ) {
|
||||||
free ( usb );
|
free ( usb );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find USB device by address
|
||||||
|
*
|
||||||
|
* @v bus USB bus
|
||||||
|
* @v address Device address
|
||||||
|
* @ret usb USB device, or NULL if not found
|
||||||
|
*/
|
||||||
|
struct usb_device * find_usb ( struct usb_bus *bus, unsigned int address ) {
|
||||||
|
struct usb_device *usb;
|
||||||
|
|
||||||
|
/* Search for a matching non-zero address */
|
||||||
|
list_for_each_entry ( usb, &bus->devices, list ) {
|
||||||
|
if ( address && ( usb->address == address ) )
|
||||||
|
return usb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* USB device hotplug event handling
|
* USB device hotplug event handling
|
||||||
|
@ -2115,6 +2135,11 @@ int register_usb_bus ( struct usb_bus *bus ) {
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
assert ( bus->hub != NULL );
|
assert ( bus->hub != NULL );
|
||||||
|
|
||||||
|
/* Assign the first available bus address */
|
||||||
|
bus->address = 0;
|
||||||
|
while ( find_usb_bus ( bus->address ) != NULL )
|
||||||
|
bus->address++;
|
||||||
|
|
||||||
/* Open bus */
|
/* Open bus */
|
||||||
if ( ( rc = bus->host->open ( bus ) ) != 0 )
|
if ( ( rc = bus->host->open ( bus ) ) != 0 )
|
||||||
goto err_open;
|
goto err_open;
|
||||||
|
@ -2187,6 +2212,23 @@ void free_usb_bus ( struct usb_bus *bus ) {
|
||||||
free ( bus );
|
free ( bus );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find USB bus by address
|
||||||
|
*
|
||||||
|
* @v address Bus address
|
||||||
|
* @ret bus USB bus, or NULL
|
||||||
|
*/
|
||||||
|
struct usb_bus * find_usb_bus ( unsigned int address ) {
|
||||||
|
struct usb_bus *bus;
|
||||||
|
|
||||||
|
for_each_usb_bus ( bus ) {
|
||||||
|
if ( bus->address == address )
|
||||||
|
return bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find USB bus by device location
|
* Find USB bus by device location
|
||||||
*
|
*
|
||||||
|
@ -2209,7 +2251,7 @@ struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type,
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* USB address assignment
|
* USB device addressing
|
||||||
*
|
*
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -2250,6 +2292,35 @@ void usb_free_address ( struct usb_bus *bus, unsigned int address ) {
|
||||||
bus->addresses &= ~( 1ULL << ( address - 1 ) );
|
bus->addresses &= ~( 1ULL << ( address - 1 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find next USB device
|
||||||
|
*
|
||||||
|
* @v usb USB device to fill in
|
||||||
|
* @v busdev Starting bus:dev address
|
||||||
|
* @ret busdev Bus:dev address of next USB device
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int usb_find_next ( struct usb_device **usb, uint16_t *busdev ) {
|
||||||
|
struct usb_bus *bus;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Find USB bus, if any */
|
||||||
|
bus = find_usb_bus ( USB_BUS ( *busdev ) );
|
||||||
|
if ( ! bus ) {
|
||||||
|
*busdev |= ( USB_BUS ( 1 ) - 1 );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find USB device, if any */
|
||||||
|
*usb = find_usb ( bus, USB_DEV ( *busdev ) );
|
||||||
|
if ( *usb )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} while ( ++(*busdev) );
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* USB bus topology
|
* USB bus topology
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* 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 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* You can also choose to distribute this program under the terms of
|
||||||
|
* the Unmodified Binary Distribution Licence (as given in the file
|
||||||
|
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <ipxe/usb.h>
|
||||||
|
#include <ipxe/command.h>
|
||||||
|
#include <ipxe/parseopt.h>
|
||||||
|
|
||||||
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
*
|
||||||
|
* USB commands
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** "usbscan" options */
|
||||||
|
struct usbscan_options {};
|
||||||
|
|
||||||
|
/** "usbscan" option list */
|
||||||
|
static struct option_descriptor usbscan_opts[] = {};
|
||||||
|
|
||||||
|
/** "usbscan" command descriptor */
|
||||||
|
static struct command_descriptor usbscan_cmd =
|
||||||
|
COMMAND_DESC ( struct usbscan_options, usbscan_opts, 1, 1,
|
||||||
|
"<setting>" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "usbscan" command
|
||||||
|
*
|
||||||
|
* @v argc Argument count
|
||||||
|
* @v argv Argument list
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int usbscan_exec ( int argc, char **argv ) {
|
||||||
|
struct usbscan_options opts;
|
||||||
|
struct named_setting setting;
|
||||||
|
struct usb_device *usb;
|
||||||
|
unsigned long prev;
|
||||||
|
uint16_t busdev;
|
||||||
|
int len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Parse options */
|
||||||
|
if ( ( rc = parse_options ( argc, argv, &usbscan_cmd, &opts ) ) != 0 )
|
||||||
|
goto err_parse_options;
|
||||||
|
|
||||||
|
/* Parse setting name */
|
||||||
|
if ( ( rc = parse_autovivified_setting ( argv[optind],
|
||||||
|
&setting ) ) != 0 )
|
||||||
|
goto err_parse_setting;
|
||||||
|
|
||||||
|
/* Determine starting bus:dev.fn address */
|
||||||
|
if ( ( len = fetchn_setting ( setting.settings, &setting.setting,
|
||||||
|
NULL, &setting.setting, &prev ) ) < 0 ) {
|
||||||
|
/* Setting not yet defined: start searching from 00:00 */
|
||||||
|
busdev = 0;
|
||||||
|
} else {
|
||||||
|
/* Setting is defined: start searching from next location */
|
||||||
|
busdev = ( prev + 1 );
|
||||||
|
if ( ! busdev ) {
|
||||||
|
rc = -ENOENT;
|
||||||
|
goto err_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find next existent USB device */
|
||||||
|
if ( ( rc = usb_find_next ( &usb, &busdev ) ) != 0 )
|
||||||
|
goto err_find_next;
|
||||||
|
|
||||||
|
/* Apply default type if necessary. Use ":uint16" rather than
|
||||||
|
* ":hex" to allow for easy inclusion within a
|
||||||
|
* "${usb/${location}....}" constructed setting.
|
||||||
|
*/
|
||||||
|
if ( ! setting.setting.type )
|
||||||
|
setting.setting.type = &setting_type_uint16;
|
||||||
|
|
||||||
|
/* Store setting */
|
||||||
|
if ( ( rc = storen_setting ( setting.settings, &setting.setting,
|
||||||
|
busdev ) ) != 0 ) {
|
||||||
|
printf ( "Could not store \"%s\": %s\n",
|
||||||
|
setting.setting.name, strerror ( rc ) );
|
||||||
|
goto err_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_store:
|
||||||
|
err_end:
|
||||||
|
err_find_next:
|
||||||
|
err_parse_setting:
|
||||||
|
err_parse_options:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** USB commands */
|
||||||
|
struct command usb_commands[] __command = {
|
||||||
|
{
|
||||||
|
.name = "usbscan",
|
||||||
|
.exec = usbscan_exec,
|
||||||
|
},
|
||||||
|
};
|
|
@ -423,6 +423,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
#define ERRFILE_editstring ( ERRFILE_OTHER | 0x00610000 )
|
#define ERRFILE_editstring ( ERRFILE_OTHER | 0x00610000 )
|
||||||
#define ERRFILE_widget_ui ( ERRFILE_OTHER | 0x00620000 )
|
#define ERRFILE_widget_ui ( ERRFILE_OTHER | 0x00620000 )
|
||||||
#define ERRFILE_form_ui ( ERRFILE_OTHER | 0x00630000 )
|
#define ERRFILE_form_ui ( ERRFILE_OTHER | 0x00630000 )
|
||||||
|
#define ERRFILE_usb_cmd ( ERRFILE_OTHER | 0x00640000 )
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,20 @@ enum usb_speed {
|
||||||
USB_SPEED_SUPER = USB_SPEED ( 5, 3 ),
|
USB_SPEED_SUPER = USB_SPEED ( 5, 3 ),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Define a USB bus:device address
|
||||||
|
*
|
||||||
|
* @v bus Bus address
|
||||||
|
* @v dev Device address
|
||||||
|
* @ret busdev Bus:device address
|
||||||
|
*/
|
||||||
|
#define USB_BUSDEV( bus, dev ) ( ( (bus) << 8 ) | (dev) )
|
||||||
|
|
||||||
|
/** Extract USB bus address */
|
||||||
|
#define USB_BUS( busdev ) ( (busdev) >> 8 )
|
||||||
|
|
||||||
|
/** Extract USB device address */
|
||||||
|
#define USB_DEV( busdev ) ( (busdev) & 0xff )
|
||||||
|
|
||||||
/** USB packet IDs */
|
/** USB packet IDs */
|
||||||
enum usb_pid {
|
enum usb_pid {
|
||||||
/** IN PID */
|
/** IN PID */
|
||||||
|
@ -956,6 +970,12 @@ struct usb_bus {
|
||||||
/** Host controller operations set */
|
/** Host controller operations set */
|
||||||
struct usb_host_operations *op;
|
struct usb_host_operations *op;
|
||||||
|
|
||||||
|
/** Bus address
|
||||||
|
*
|
||||||
|
* This is an internal index used only to allow a USB device
|
||||||
|
* to be identified via a nominal bus:device address.
|
||||||
|
*/
|
||||||
|
unsigned int address;
|
||||||
/** Largest transfer allowed on the bus */
|
/** Largest transfer allowed on the bus */
|
||||||
size_t mtu;
|
size_t mtu;
|
||||||
/** Address in-use mask
|
/** Address in-use mask
|
||||||
|
@ -1269,6 +1289,9 @@ extern struct usb_endpoint_companion_descriptor *
|
||||||
usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config,
|
usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config,
|
||||||
struct usb_endpoint_descriptor *desc );
|
struct usb_endpoint_descriptor *desc );
|
||||||
|
|
||||||
|
extern struct usb_device * find_usb ( struct usb_bus *bus,
|
||||||
|
unsigned int address );
|
||||||
|
|
||||||
extern struct usb_hub * alloc_usb_hub ( struct usb_bus *bus,
|
extern struct usb_hub * alloc_usb_hub ( struct usb_bus *bus,
|
||||||
struct usb_device *usb,
|
struct usb_device *usb,
|
||||||
unsigned int ports,
|
unsigned int ports,
|
||||||
|
@ -1285,11 +1308,13 @@ extern struct usb_bus * alloc_usb_bus ( struct device *dev,
|
||||||
extern int register_usb_bus ( struct usb_bus *bus );
|
extern int register_usb_bus ( struct usb_bus *bus );
|
||||||
extern void unregister_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 void free_usb_bus ( struct usb_bus *bus );
|
||||||
|
extern struct usb_bus * find_usb_bus ( unsigned int address );
|
||||||
extern struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type,
|
extern struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type,
|
||||||
unsigned int location );
|
unsigned int location );
|
||||||
|
|
||||||
extern int usb_alloc_address ( 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 void usb_free_address ( struct usb_bus *bus, unsigned int address );
|
||||||
|
extern int usb_find_next ( struct usb_device **usb, uint16_t *busdev );
|
||||||
extern unsigned int usb_route_string ( struct usb_device *usb );
|
extern unsigned int usb_route_string ( struct usb_device *usb );
|
||||||
extern struct usb_port * usb_root_hub_port ( struct usb_device *usb );
|
extern struct usb_port * usb_root_hub_port ( struct usb_device *usb );
|
||||||
extern struct usb_port * usb_transaction_translator ( struct usb_device *usb );
|
extern struct usb_port * usb_transaction_translator ( struct usb_device *usb );
|
||||||
|
|
Loading…
Reference in New Issue