壊れたメガネ

ホッチキスの達人の意識の高いブログ。

usbview

マシンにつながっている USB デバイスに対して、 libusb の descriptor を traverse するだけのコードです。
まだよく分かっちゃいないです。これで出てくる値と USB Viewer が示す値を比べっこしています。
いや〜、しかし C は難シ〜

パッケージングしたいな〜と思い、それっぽいの無いかとちょっと漁りました。
autoconf とか automake っていう便利なものがあるのもんなんですね。
実際にパッケージ作れるかなぁと試しましたが、いくら何でも考えなしには出来ない様です。
次にやるかな。しかし、人手で一からスクリプトなり Makefile なりを書くのに比べると全然早いし、正確だろうし、いろんな GNU なシステムで動くのだろう。

/* 
 * File:   main.c
 * Author: oasynnoum
 *
 * Created on 2011/06/26, 12:15
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libusb.h>

char *get_str_usb_version(int bcdUSB) {
    return bcdUSB == 0x0200 ? "USB 2.0" : bcdUSB == 0x0110 ? "USB 1.1" : "unknown";
}

char *get_str_device_type(int dt) {
    return dt == LIBUSB_DT_DEVICE ? "LIBUSB_DT_DEVICE" : 
        dt == LIBUSB_DT_CONFIG ? "LIBUSB_DT_CONFIG" : 
        dt == LIBUSB_DT_STRING ? "LIBUSB_DT_STRING" : 
        dt == LIBUSB_DT_INTERFACE ? "LIBUSB_DT_INTERFACE" : 
        dt == LIBUSB_DT_ENDPOINT ? "LIBUSB_DT_ENDPOINT" : 
        dt == LIBUSB_DT_HID ? "LIBUSB_DT_HID" : 
        dt == LIBUSB_DT_REPORT ? "LIBUSB_DT_REPORT" : 
        dt == LIBUSB_DT_PHYSICAL ? "LIBUSB_DT_PHYSICAL" : 
        dt == LIBUSB_DT_HUB ? "LIBUSB_DT_HUB" : "unknown";
}

char *get_str_usb_class(int cls) {
    return cls == LIBUSB_CLASS_PER_INTERFACE ? "LIBUSB_CLASS_PER_INTERFACE" :
        cls == LIBUSB_CLASS_AUDIO ? "LIBUSB_CLASS_AUDIO" :
        cls == LIBUSB_CLASS_COMM ? "LIBUSB_CLASS_COMM" :
        cls == LIBUSB_CLASS_HID ? "LIBUSB_CLASS_HID" : 
        cls == LIBUSB_CLASS_PRINTER ? "LIBUSB_CLASS_PRINTER" :
        cls == LIBUSB_CLASS_PTP ? "LIBUSB_CLASS_PTP" : 
        cls == LIBUSB_CLASS_MASS_STORAGE ? "LIBUSB_CLASS_MASS_STORAGE" :
        cls == LIBUSB_CLASS_HUB ? "LIBUSB_CLASS_HUB" : 
        cls == LIBUSB_CLASS_DATA ? "LIBUSB_CLASS_DATA" : 
        cls == LIBUSB_CLASS_WIRELESS ? "LIBUSB_CLASS_WIRELESS" : 
        cls == LIBUSB_CLASS_APPLICATION ? "LIBUSB_CLASS_APPLICATION" :
        cls == LIBUSB_CLASS_VENDOR_SPEC ? "LIBUSB_CLASS_VENDOR_SPEC" : "unknown";
}

void output_device_descriptor(libusb_device *device) {
    struct libusb_device_descriptor *device_descriptor = calloc(1, sizeof(struct libusb_device_descriptor));
    if (LIBUSB_SUCCESS != libusb_get_device_descriptor(device, device_descriptor)) {
        printf("%s\n", "failed to get device descriptor.");
        return;
    }
    
    printf("device descriptor\n"
            "\tdevice_address: %d\n"
            "\tbus_number: %d\n"
            "\tbLength: %d\n"
            "\tbDescriptorType: %s\n"
            "\tbcdUSB: %s\n"
            "\tbDeviceClass: %s\n"
            "\tbDeviceSubClass: %02x\n"
            "\tbDeviceProtocol: %02x\n"
            "\tbMaxPacketSize0: %02x\n"
            "\tidVendor: %04x\n"
            "\tidProduct: %04x\n"
            "\tbcdDevice: %04x\n"
            "\tiManufacturere: %02x\n"
            "\tiProduct: %02x\n"
            "\tiSerialNumber: %02x\n"
            "\tbNumConfigurations: %02x\n\n",
            libusb_get_device_address(device),
            libusb_get_bus_number(device),
            device_descriptor->bLength,
            get_str_device_type(device_descriptor->bDescriptorType),
            get_str_usb_version(device_descriptor->bcdUSB),
            get_str_usb_class(device_descriptor->bDeviceClass),
            device_descriptor->bDeviceSubClass,
            device_descriptor->bDeviceProtocol,
            device_descriptor->bMaxPacketSize0,
            device_descriptor->idVendor,
            device_descriptor->idProduct,
            device_descriptor->bcdDevice,
            device_descriptor->iManufacturer,
            device_descriptor->iProduct,
            device_descriptor->iSerialNumber,
            device_descriptor->bNumConfigurations);
    free(device_descriptor);
    return;
}

void output_device_list() {
    ssize_t result = -1;
    libusb_device **devices;
    struct libusb_device_descriptor device_descriptor;
    
    result = libusb_init(NULL);
    if (LIBUSB_SUCCESS != result) {
        printf("%s\n", "libusb init error.");
        exit(result);
    }
    
    result = libusb_get_device_list(NULL, &devices);
    if (result < 0) {
        printf("%s\n", "libusb failed to get device list.");
        libusb_exit(NULL);
        exit(result);
    }
    
    int i = 0;
    for (i = 0; i < result; i++) {
        libusb_device *device = devices[i];
        output_device_descriptor(device);
    }
    
    libusb_free_device_list(devices, 1);
    libusb_exit(NULL);
}


void output_endpoint_descriptor(const struct libusb_endpoint_descriptor *endpoint_descriptor) {
    printf("\t\tendpoint descriptor\n"
            "\t\t\tbLength: %d\n"
            "\t\t\tbDescriptorType: %s\n"
            "\t\t\tbEndPointAddress: %02x\n"
            "\t\t\tbmAttributes: %02x\n"
            "\t\t\twMaxPacketSize: %d\n"
            "\t\t\tbInterval: %02x\n"
            "\t\t\tbRefresh: %02x\n"
            "\t\t\tbSynchAddress: %02x\n\n",
            endpoint_descriptor->bLength,
            get_str_device_type(endpoint_descriptor->bDescriptorType),
            endpoint_descriptor->bEndpointAddress,
            endpoint_descriptor->bmAttributes,
            endpoint_descriptor->wMaxPacketSize,
            endpoint_descriptor->bInterval,
            endpoint_descriptor->bRefresh,
            endpoint_descriptor->bSynchAddress);
}

void output_interface_descriptor(const struct libusb_interface *ifs) {
    struct libusb_interface_descriptor interface_descriptor;
    int i;
    for (i = 0; i < ifs->num_altsetting; i++) {
        interface_descriptor = ifs->altsetting[i];
        printf("\tinterface descriptor(%d):\n"
                "\t\tbLength: %d\n"
                "\t\tbDescriptorType: %s\n"
                "\t\tbInterfaceNumber: %d\n"
                "\t\tbAlternateSetting: %02x\n"
                "\t\tbNumEndpoints: %d\n"
                "\t\tbInterfaceClass: %s\n"
                "\t\tbInterfaceSubClass: %02x\n"
                "\t\tbInterfaceProtocol: %02x\n"
                "\t\tiInterface: %02x\n\n",
                i,
                interface_descriptor.bLength,
                get_str_device_type(interface_descriptor.bDescriptorType),
                interface_descriptor.bInterfaceNumber,
                interface_descriptor.bAlternateSetting,
                interface_descriptor.bNumEndpoints,
                get_str_usb_class(interface_descriptor.bInterfaceClass),
                interface_descriptor.bInterfaceSubClass,
                interface_descriptor.bInterfaceProtocol,
                interface_descriptor.iInterface);
        
        int j;
        for (j = 0; j < interface_descriptor.bNumEndpoints; j++) {
            const struct libusb_endpoint_descriptor ep_desc = interface_descriptor.endpoint[j];
            output_endpoint_descriptor(&ep_desc);
        }
    }
}

void output_active_config_descriptor(libusb_device *device) {
    struct libusb_config_descriptor *config_descriptor;
    int result = -1;
    result = libusb_get_active_config_descriptor(device, &config_descriptor);
    if (result != LIBUSB_SUCCESS) {
        printf("%s\n", "failed to get active config descriptor.");
        return;
    }
    printf("active config descriptor\n"
            "\tbLength: %d\n"
            "\tbDescriptorType: %s\n"
            "\twTotalLength: %04x\n"
            "\tbNumInterfaces: %d\n"
            "\tbConfigurationValue: %02x\n"
            "\tiConfiguration: %02x\n"
            "\tbmAttributes: %02x\n"
            "\tMaxPower: %dmA\n\n",
            config_descriptor->bLength,
            get_str_device_type(config_descriptor->bDescriptorType),
            config_descriptor->wTotalLength,
            config_descriptor->bNumInterfaces,
            config_descriptor->bConfigurationValue,
            config_descriptor->iConfiguration,
            config_descriptor->bmAttributes,
            config_descriptor->MaxPower * 2);
    output_interface_descriptor(config_descriptor->interface);
    libusb_free_config_descriptor(config_descriptor);
    return;
}

void output_device_details(uint8_t address, uint8_t bus_number) {
    //printf("address: %d, bus_number: %d\n", address, bus_number);
    libusb_device **device_list;
    int result;
    
    libusb_init(NULL);
    result = libusb_get_device_list(NULL, &device_list);
    if (result < 0) {
        printf("%s\n", "failed to get device list.");
        libusb_exit(NULL);
        return;
    }
    
    libusb_device *device = NULL;
    int i;
    for (i = 0; i < result; i++) {
        device = device_list[i];
        uint8_t _address = libusb_get_device_address(device);
        if (_address != address) {
            device = NULL;
            continue;
        }
            
        uint8_t _bus_number = libusb_get_bus_number(device);
        if (_bus_number != bus_number) {
            device = NULL;
            continue; 
        } else {
            break;
        }
    }
    
    if (device == NULL) {
        printf("%s\n", "device not found.");
        libusb_free_device_list(device_list, 1);
        libusb_exit(NULL);
        return;
    }
    
    output_device_descriptor(device);
    output_active_config_descriptor(device);
}

void output_help() {
    printf("Usage: \n"
                "\tlist\n"
                "\tdetail -a device_address -b bus_number\n");
}

/*
 * 
 */
int main(int argc, char** argv) {

    if (argc < 2) {
        output_help();
        return (EXIT_SUCCESS);
    }
    
    if (strcmp("list", argv[1]) == 0) {
        output_device_list();
    } else if (strcmp("detail", argv[1]) == 0) {
        char *detail_usage = "detail -a device_address -b bus_number";
        uint8_t address = -1;
        uint8_t bus_number = -1;
        
        int result;
        while((result = getopt(argc, argv, "a:b:")) != -1) {
            switch (result) {
                case 'a':
                    address = (uint8_t)atoi(optarg);
                    break;
                case 'b':
                    bus_number =  (uint8_t)atoi(optarg);
                    break;
            }
        }
        if (address < 0) {
            printf("%s\n%s\n", detail_usage, "specify legal address.");
            exit(address);
        }
        if (bus_number < 0) {
            printf("%s\n%s\n", detail_usage, "specify legal bus_number.");
            exit(bus_number);
        }
        
        output_device_details(address, bus_number);
    }
    
    return (EXIT_SUCCESS);
}