/*****************************************************************************/
/*
* lsusb.c -- lspci like utility for the USB bus
*
* Copyright (C) 1999-2001, 2003
* Thomas Sailer (t.sailer@alumni.ethz.ch)
* Copyright (C) 2003-2005 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.
*/
/*****************************************************************************/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <byteswap.h>
#include <usb.h>
#include "names.h"
#include "devtree.h"
#include "usbmisc.h"
#include <getopt.h>
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define le16_to_cpu(x) (x)
#elif (__BYTE_ORDER == __BIG_ENDIAN)
#define le16_to_cpu(x) bswap_16(x)
#else
#error missing BYTE_ORDER
#endif
/* from USB 2.0 spec and updates */
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_OTG 0x09
#define USB_DT_DEBUG 0x0a
#define USB_DT_INTERFACE_ASSOCIATION 0x0b
#define USB_DT_SECURITY 0x0c
#define USB_DT_KEY 0x0d
#define USB_DT_ENCRYPTION_TYPE 0x0e
#define USB_DT_BOS 0x0f
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
#define USB_DT_WIRE_ADAPTER 0x21
#define USB_DT_RPIPE 0x22
#define USB_DT_RC_INTERFACE 0x23
/* Conventional codes for class-specific descriptors. The convention is
* defined in the USB "Common Class" Spec (3.11). Individual class specs
* are authoritative for their usage, not the "common class" writeup.
*/
#define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE)
#define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG)
#define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING)
#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
#ifndef USB_CLASS_VIDEO
#define USB_CLASS_VIDEO 0x0e
#endif
#ifndef USB_CLASS_APPLICATION
#define USB_CLASS_APPLICATION 0xfe
#endif
#define VERBLEVEL_DEFAULT 0 /* 0 gives lspci behaviour; 1, lsusb-0.9 */
#define CTRL_RETRIES 2
#define CTRL_TIMEOUT (5*1000) /* milliseconds */
#define HUB_STATUS_BYTELEN 3 /* max 3 bytes status = hub + 23 ports */
extern int lsusb_t(void);
static const char *procbususb = "/proc/bus/usb";
static unsigned int verblevel = VERBLEVEL_DEFAULT;
static int do_report_desc = 1;
static const char *encryption_type[] = {"UNSECURE", "WIRED", "CCM_1", "RSA_1", "RESERVED"};
static void dump_interface(struct usb_dev_handle *dev, struct usb_interface *interface);
static void dump_endpoint(struct usb_dev_handle *dev, struct usb_interface_descriptor *interface, struct usb_endpoint_descriptor *endpoint);
static void dump_audiocontrol_interface(struct usb_dev_handle *dev, unsigned char *buf);
static void dump_audiostreaming_interface(unsigned char *buf);
static void dump_midistreaming_interface(struct usb_dev_handle *dev, unsigned char *buf);
static void dump_videocontrol_interface(struct usb_dev_handle *dev, unsigned char *buf);
static void dump_videostreaming_interface(unsigned char *buf);
static void dump_dfu_interface(unsigned char *buf);
static char *dump_comm_descriptor(struct usb_dev_handle *dev, unsigned char *buf, char *indent);
static void dump_hid_device(struct usb_dev_handle *dev, struct usb_interface_descriptor *interface, unsigned char *buf);
static void dump_audiostreaming_endpoint(unsigned char *buf);
static void dump_midistreaming_endpoint(unsigned char *buf);
static void dump_hub(char *prefix, unsigned char *p, int has_tt);
static void dump_ccid_device(unsigned char *buf);
/* ---------------------------------------------------------------------- */
static unsigned int convert_le_u32 (const unsigned char *buf)
{
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}
/* ---------------------------------------------------------------------- */
/* workaround libusb API goofs: "byte" should never be sign extended;
* using "char" is trouble. Likewise, sizes should never be negative.
*/
static inline int typesafe_control_msg(usb_dev_handle *dev,
unsigned char requesttype, unsigned char request,
int value, int index,
unsigned char *bytes, unsigned size, int timeout)
{
return usb_control_msg(dev, requesttype, request, value, index,
(char *) bytes, (int) size, timeout);
}
#define usb_control_msg typesafe_control_msg
/* ---------------------------------------------------------------------- */
int lprintf(unsigned int vl, const char *format, ...)
{
va_list ap;
int r;
if (vl > verblevel)
return 0;
va_start(ap, format);
r = vfprintf(stderr, format, ap);
va_end(ap);
if (!vl)
exit(1);
return r;
}
/* ---------------------------------------------------------------------- */
static int get_string(struct usb_dev_handle *dev, char* buf, size_t size, u_int8_t id)
{
int ret;
if (!dev) {
buf[0] = 0;
return 0;
}
if (id) {
ret = usb_get_string_simple(dev, id, buf, size);
if (ret <= 0) {
buf[0] = 0;
return 0;
}
else
return ret;
}
else {
buf[0] = 0;
return 0;
}
}
static int get_vendor_string(char *buf, size_t size, u_int16_t vid)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_vendor(vid)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static int get_product_string(char *buf, size_t size, u_int16_t vid, u_int16_t pid)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_product(vid, pid)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static int get_class_string(char *buf, size_t size, u_int8_t cls)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_class(cls)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static int get_subclass_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_subclass(cls, subcls)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static int get_protocol_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls, u_int8_t proto)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_protocol(cls, subcls, proto)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static int get_audioterminal_string(char *buf, size_t size, u_int16_t termt)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_audioterminal(termt)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static int get_videoterminal_string(char *buf, size_t size, u_int16_t termt)
{
const char *cp;
if (size < 1)
return 0;
*buf = 0;
if (!(cp = names_videoterminal(termt)))
return 0;
return snprintf(buf, size, "%s", cp);
}
static const char *get_guid(unsigned char *buf)
{
static char guid[39];
/* NOTE: see RFC 4122 for more information about GUID/UUID
* structure. The first fields fields are historically big
* endian numbers, dating from Apollo mc68000 workstations.
*/
sprintf(guid, "{%02x%02x%02x%02x"
"-%02x%02x"
"-%02x%02x"
"-%02x%02x"
"-%02x%02x%02x%02x%02x%02x}",
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5],
buf[6], buf[7],
buf[8], buf[9],
buf[10], buf[11], buf[12], buf[13], buf[14], b
评论0