同步 IO 有二種(其實還有第三種叫 stream, 似乎沒被實作):
libusb_bulk_transfer() : Perform a USB bulk transfer.
及 libusb_interrupt_transfer() : Perform a USB interrupt transfer.
而要跟 device 溝通,很重要的一個函數叫 libusb_control_transfer()
Function Documentation int libusb_control_transfer ( libusb_device_handle * dev_handle, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char * data, uint16_t wLength, unsigned int timeout ) Perform a USB control transfer. The direction of the transfer is inferred from the bmRequestType field of the setup packet. The wValue, wIndex and wLength fields values should be given in host-endian byte order. Parameters: dev_handle a handle for the device to communicate with bmRequestType the request type field for the setup packet bRequest the request field for the setup packet wValue the value field for the setup packet wIndex the index field for the setup packet data a suitably-sized data buffer for either input or output (depending on direction bits within bmRequestType) wLength the length field for the setup packet. The data buffer should be at least this size. timeout timeout (in millseconds) that this function should wait before giving up due to no response being received. For an unlimited timeout, use value 0. Returns: on success, the number of bytes actually transferred LIBUSB_ERROR_TIMEOUT if the transfer timed out LIBUSB_ERROR_PIPE if the control request was not supported by the device LIBUSB_ERROR_NO_DEVICE if the device has been disconnected another LIBUSB_ERROR code on other failures上面有句話不知道有沒注意到: The wValue, wIndex and wLength fields values should be given in host-endian byte order
底下來寫一點心得:
.首先就是找到 usb device 有兩種方法,一種是透過 cnt = libusb_get_device_list(NULL, &devs) 這樣的呼叫,另一種則是透過 devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
.在 libusb_get_device_list() 的第一個參數 libusb_context,這是讓你可以同時控制兩個 libusb sessions, 一般情況不必管這個值的話就給 NULL 即可
.底下有一段利用 libusb_control_transfer() 來跟 device 溝通的範例:
#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) #define USB_RQ 0x04 static int print_f0_data(void) { unsigned char data[0x10]; int r; unsigned int i; r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, sizeof(data), 0); if (r < 0) { fprintf(stderr, "F0 error %d\n", r); return r; } if ((unsigned int) r < sizeof(data)) { fprintf(stderr, "short read (%d)\n", r); return -1; } printf("F0 data:"); for (i = 0; i < sizeof(data); i++) printf("%02x ", data[i]); printf("\n"); return 0; }其中libusb_control_transfer() 裡的第二個參數決定 request 的型態,以上例是 LIBUSB_REQUEST_TYPE_VENDOR, 這個是非 STANDARD, 因此視 application(device) 而定。 .這邊再舉個例子:
int config; uint8_t tmp = 0; r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000); if (r == 1) { config = tmp; }.最後再來看一個例子
void check_device(libusb_device *dev) { ... int r = libusb_get_device_descriptor(dev, &desc); // 先取得 device descriptor,因為內藏豐富資訊 ... if (!is_adb_interface (desc.idVendor, desc.idProduct, ADB_CLASS, ADB_SUBCLASS, ADB_PROTOCOL)) { .... } /* 底下兩行再取得 device handler 的 bus, address 資訊, 以便給 libusb_open() 使用 */ uh.dev_bus = libusb_get_bus_number(dev); uh.dev_addr = libusb_get_device_address(dev); /* 底下四行取得 device 的 active config descriptor,必須其 interface 有值才合法 因為每個 usb device 是可以 config 成多個不同 device type, 在此只需要取回現行的 config 即可(即 active config) */ r = libusb_get_active_config_descriptor(dev, &config); if (config->interface != NULL) { found = check_usb_interfaces(config, &desc, &uh); // 檢查是否 support android adb } /* 底下開始要進一步與 device 溝通取回更多資訊 */ r = libusb_open(dev, &uh.devh); // 類似 libusb_open_device_with_vid_pid() uh.dev = dev; if (found >= 0) { .... // 在對 endpoint 進行 I/O 之前,一定要 claim interface uh.interface = found; r = libusb_claim_interface(uh.devh, uh.interface); .... if (desc.iSerialNumber) { // reading serial uint16_t buffer[128] = {0}; uint16_t languages[128] = {0}; int languageCount = 0; memset(languages, 0, sizeof(languages)); r = libusb_control_transfer(uh.devh, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8, 0, (uint8_t *)languages, sizeof(languages), 0); .... languageCount = (r - 2) / 2; for (i = 1; i <= languageCount; ++i) { memset(buffer, 0, sizeof(buffer)); /* 底下透過 request type 為 LIBUSB_REQUEST_TYPE_STANDARD 來指定 LIBUSB_REQUEST_GET_DESCRIPTOR 的方式取回 android device ID string 其傳回值型態由 LIBUSB_DT_STRING 指定,其值為 iSerialNumber */ r = libusb_control_transfer(uh.devh, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber, languages[i], (uint8_t *)buffer, sizeof(buffer), 0); .... // 處理存在 buffer 中的 serial 資訊,也就是 android device ID } if (register_device(&uh, serial) == 0) { ..... // fail } else { // success libusb_ref_device(dev); } } } ...... }
0 意見:
張貼留言