diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ef9604 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..19dbca5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.12) + +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) + if(DEFINED ENV{VITASDK}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") + else() + message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") + endif() +endif() + +set(SHORT_NAME lsusb) +project(${SHORT_NAME}) +include("${VITASDK}/share/vita.cmake" REQUIRED) + +set(VITA_APP_NAME "lsusb") +set(VITA_TITLEID "LUSB00000") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") + +add_executable(${SHORT_NAME} + main.c +) + +target_link_libraries(${SHORT_NAME} + SceUsbd_stub +) + +vita_create_self(${SHORT_NAME}.self ${SHORT_NAME} UNSAFE) + +vita_create_vpk(${SHORT_NAME}.vpk ${VITA_TITLEID} ${SHORT_NAME}.self + VERSION ${VITA_VERSION} + NAME ${VITA_APP_NAME} +) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f471eb4 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# vita-lsusb + +lsusb-alike app for PSVita. +Dumps currently connected usb devices info into stdout and `ux0:/data/lsusb.txt` diff --git a/main.c b/main.c new file mode 100755 index 0000000..19e76a8 --- /dev/null +++ b/main.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include "usbd.h" + +#define dump(...) do { \ + sceClibPrintf(__VA_ARGS__); \ + fprintf(fp, __VA_ARGS__); \ +} while (0); + + +int main(int argc, char *argv[]) { + SceUID uid; + SceUsbdDeviceInfo info[8]; + + sceUsbdInit(&uid); + + sceUsbdGetDeviceList(uid, 8, (SceUsbdDeviceInfo *)&info); + + FILE* fp = fopen("ux0:/data/lsusb.txt","wb"); + + static const char * const typeattr[] = { + "Control", + "Isochronous", + "Bulk", + "Interrupt" + }; + static const char * const syncattr[] = { + "None", + "Asynchronous", + "Adaptive", + "Synchronous" + }; + static const char * const usage[] = { + "Data", + "Feedback", + "Implicit feedback Data", + "(reserved)" + }; + + int i = 0; + while (i < 8 && info[i].device_num != 0xffffffff) { + unsigned int device_id = (info[i].port << 16) + info[i].device_num; + int size = sceUsbdGetDescriptorSize(uid, device_id); + + uint8_t* descr = malloc(size); + + sceUsbdGetDescriptor(uid, device_id, descr, size); + int speed; + sceUsbdGetDeviceSpeed(uid, device_id, &speed); + + dump("Bus %x Device %x (%s):\n", info[i].port, info[i].device_num, (speed == 0) ? "Low-speed" : ((speed == 1) ? "High-speed" : "Full-speed") ); + + uint8_t *ptr = descr; + while (ptr - descr < size) + { + switch(ptr[1]) { + case USB_DESCRIPTOR_DEVICE: + { + USB_DEVICE_DESCRIPTOR *d = (USB_DEVICE_DESCRIPTOR*)ptr; + ptr += ptr[0]; + dump("Device Descriptor:\n"); + dump(" bLength: 0x%02x\n", d->bLength); + dump(" bDescriptorType: 0x%02x\n", d->bDescriptorType); + dump(" bcdUSB: %2x.%02x\n", d->bcdUSB >> 8, d->bcdUSB & 0xff); + dump(" bDeviceClass: 0x%02x\n", d->bDeviceClass); + dump(" bDeviceSubClass: 0x%02x\n", d->bDeviceSubClass); + dump(" bDeviceProtocol: 0x%02x\n", d->bDeviceProtocol); + dump(" bMaxPacketSize0: 0x%02x\n", d->bMaxPacketSize0); + dump(" idVendor: 0x%04x\n", d->idVendor); + dump(" idProduct: 0x%04x\n", d->idProduct); + dump(" bcdDevice: %2x.%02x\n", d->bcdDevice >> 8, d->bcdDevice & 0xff); + dump(" iManufacturer: 0x%02x\n", d->iManufacturer); + dump(" iProduct: 0x%02x\n", d->iProduct); + dump(" iSerialNumber: 0x%02x\n", d->iSerialNumber); + dump(" bNumConfigurations: 0x%02x\n", d->bNumConfigurations); + + break; + } + case USB_DESCRIPTOR_CONFIGURATION: + { + USB_CONFIGURATION_DESCRIPTOR *d = (USB_CONFIGURATION_DESCRIPTOR*)ptr; + ptr += ptr[0]; + dump(" Configuration Descriptor:\n"); + dump(" bLength: 0x%02x\n", d->bLength); + dump(" bDescriptorType: 0x%02x\n", d->bDescriptorType); + dump(" wTotalLength: 0x%04x\n", d->wTotalLength); + dump(" bNumInterfaces: 0x%02x\n", d->bNumInterfaces); + dump(" bConfigurationValue: 0x%02x\n", d->bConfigurationValue); + dump(" iConfiguration: 0x%02x\n", d->iConfiguration); + dump(" bmAttributes: 0x%02x\n", d->bmAttributes); + if (!(d->bmAttributes & 0x80)) + { + dump(" (Missing must-be-set bit!)\n"); + } + if (d->bmAttributes & 0x40) + { + dump(" Self Powered\n"); + } + else + { + dump(" (Bus Powered)\n"); + } + if (d->bmAttributes & 0x20) + { + dump(" Remote Wakeup\n"); + } + if (d->bmAttributes & 0x10) + { + dump(" Battery Powered\n"); + } + dump(" bMaxPower: 0x%04x (%5umA)\n", d->bMaxPower, d->bMaxPower * 2); + break; + } + case USB_DESCRIPTOR_INTERFACE: + { + USB_INTERFACE_DESCRIPTOR *d = (USB_INTERFACE_DESCRIPTOR*)ptr; + ptr += ptr[0]; + dump(" Interface Descriptor:\n"); + dump(" bLength: 0x%02x\n", d->bLength); + dump(" bDescriptorType: 0x%02x\n", d->bDescriptorType); + dump(" bInterfaceNumber: 0x%04x\n", d->bInterfaceNumber); + dump(" bAlternateSetting: 0x%02x\n", d->bAlternateSetting); + dump(" bNumEndpoints: 0x%02x\n", d->bNumEndpoints); + dump(" bInterfaceClass: 0x%02x\n", d->bInterfaceClass); + dump(" bInterfaceSubClass: 0x%02x\n", d->bInterfaceSubClass); + dump(" bInterfaceProtocol: 0x%02x\n", d->bInterfaceProtocol); + dump(" iInterface: 0x%02x\n", d->iInterface); + break; + } + case USB_DESCRIPTOR_ENDPOINT: + { + USB_ENDPOINT_DESCRIPTOR *d = (USB_ENDPOINT_DESCRIPTOR*)ptr; + ptr += ptr[0]; + dump(" Endpoint Descriptor:\n"); + dump(" bLength: 0x%02x\n", d->bLength); + dump(" bDescriptorType: 0x%02x\n", d->bDescriptorType); + dump(" bEndpointAddress: 0x%02x EP %u %s\n", d->bEndpointAddress, d->bEndpointAddress & 0x0f, (d->bEndpointAddress & 0x80) ? "IN" : "OUT"); + + dump(" bmAttributes: 0x%02x\n", d->bmAttributes); + dump(" Transfer Type: %s\n", typeattr[d->bmAttributes & 3]); + dump(" Synch Type: %s\n", syncattr[(d->bmAttributes >> 2) & 3]); + dump(" Usage Type: %s\n", usage[(d->bmAttributes >> 4) & 3]); + + dump(" wMaxPacketSize: 0x%02x\n", d->wMaxPacketSize); + dump(" bInterval: 0x%02x\n", d->bInterval); + break; + } + default: + dump("unhandled dtype: %x\n", ptr[1]); + ptr += ptr[0]; + break; + }; + } + dump("\n\n", ptr[1]); + + free(descr); + i++; + } + + fclose(fp); + + sceUsbdEnd(uid); + + return 0; +} diff --git a/usbd.h b/usbd.h new file mode 100644 index 0000000..311a74b --- /dev/null +++ b/usbd.h @@ -0,0 +1,83 @@ +#ifndef _USBD_H_ +#define _USBD_H_ + +typedef struct SceUsbdDeviceInfo { + unsigned int port; + unsigned int device_num; + unsigned int unk3; // handled? 0, 1, 2 +} SceUsbdDeviceInfo; + +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} __attribute__((packed)) USB_DEVICE_DESCRIPTOR; + +/* Configuration descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR; + +/* Interface descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR; + +/* Endpoint descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR; + +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. + +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +int sceUsbdInit(SceUID *uid); +int sceUsbdEnd(SceUID uid); + +int sceUsbdGetDeviceList(SceUID uid, unsigned int num, SceUsbdDeviceInfo *info); // 8 devices max +// returns all descriptors (device, config, interface, etc.) +int sceUsbdGetDescriptor(SceUID uid, unsigned int device_id, unsigned char *descriptor, unsigned int size); +int sceUsbdGetDescriptorSize(SceUID uid, unsigned int device_id); +// 0, 1, 2 = Low, Full, High +int sceUsbdGetDeviceSpeed(SceUID uid, unsigned int device_id, unsigned int *speed); + +#endif /* _USBD_H_ */