mirror of
https://github.com/ipxe/ipxe.git
synced 2025-01-06 14:03:09 -06:00
[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>
This commit is contained in:
parent
2bf16c6ffc
commit
c219b5d8a9
@ -302,6 +302,9 @@ REQUIRE_OBJECT ( shim_cmd );
|
||||
#ifdef IMAGE_CRYPT_CMD
|
||||
REQUIRE_OBJECT ( image_crypt_cmd );
|
||||
#endif
|
||||
#ifdef USB_CMD
|
||||
REQUIRE_OBJECT ( usb_cmd );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in miscellaneous objects
|
||||
|
@ -171,6 +171,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
//#define IMAGE_MEM_CMD /* Read memory command */
|
||||
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
|
||||
#define SHIM_CMD /* EFI shim command (or dummy command) */
|
||||
//#define USB_CMD /* USB commands */
|
||||
|
||||
/*
|
||||
* ROM-specific options
|
||||
|
@ -1323,7 +1323,8 @@ usb_probe_all ( struct usb_device *usb,
|
||||
func->name = func->dev.name;
|
||||
func->usb = 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.device = le16_to_cpu ( usb->device.product );
|
||||
snprintf ( func->dev.name, sizeof ( func->dev.name ),
|
||||
@ -1725,6 +1726,25 @@ static void free_usb ( struct usb_device *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
|
||||
@ -2115,6 +2135,11 @@ int register_usb_bus ( struct usb_bus *bus ) {
|
||||
/* Sanity checks */
|
||||
assert ( bus->hub != NULL );
|
||||
|
||||
/* Assign the first available bus address */
|
||||
bus->address = 0;
|
||||
while ( find_usb_bus ( bus->address ) != NULL )
|
||||
bus->address++;
|
||||
|
||||
/* Open bus */
|
||||
if ( ( rc = bus->host->open ( bus ) ) != 0 )
|
||||
goto err_open;
|
||||
@ -2187,6 +2212,23 @@ void free_usb_bus ( struct usb_bus *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
|
||||
*
|
||||
@ -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 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
122
src/hci/commands/usb_cmd.c
Normal file
122
src/hci/commands/usb_cmd.c
Normal file
@ -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_widget_ui ( ERRFILE_OTHER | 0x00620000 )
|
||||
#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 ),
|
||||
};
|
||||
|
||||
/** 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 */
|
||||
enum usb_pid {
|
||||
/** IN PID */
|
||||
@ -956,6 +970,12 @@ struct usb_bus {
|
||||
/** Host controller operations set */
|
||||
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 */
|
||||
size_t mtu;
|
||||
/** Address in-use mask
|
||||
@ -1269,6 +1289,9 @@ extern struct usb_endpoint_companion_descriptor *
|
||||
usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config,
|
||||
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,
|
||||
struct usb_device *usb,
|
||||
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 void unregister_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,
|
||||
unsigned int location );
|
||||
|
||||
extern int usb_alloc_address ( struct usb_bus *bus );
|
||||
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 struct usb_port * usb_root_hub_port ( struct usb_device *usb );
|
||||
extern struct usb_port * usb_transaction_translator ( struct usb_device *usb );
|
||||
|
Loading…
Reference in New Issue
Block a user