Martin Vejnár avatar Martin Vejnár committed dfc969d

Added string descriptors, control_read, control_write.

Comments (0)

Files changed (5)

libyb/usb/detail/libusb0_win32_intf.h

 #define LIBUSB_IOCTL_GET_DESCRIPTOR           CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED,   FILE_ANY_ACCESS)
 #define LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_IN_DIRECT,  FILE_ANY_ACCESS)
 #define LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define LIBUSB_IOCTL_VENDOR_WRITE             CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, METHOD_BUFFERED,   FILE_ANY_ACCESS) // 0x00222030
+#define LIBUSB_IOCTL_VENDOR_READ              CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80D, METHOD_BUFFERED,   FILE_ANY_ACCESS) // 0x00222034
 #define LIBUSB_IOCTL_ABORT_ENDPOINT           CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80F, METHOD_BUFFERED,   FILE_ANY_ACCESS)
 #define LIBUSB_IOCTL_RESET_DEVICE             CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED,   FILE_ANY_ACCESS)
 #define LIBUSB_IOCTL_CLAIM_INTERFACE          CTL_CODE(FILE_DEVICE_UNKNOWN, 0x815, METHOD_BUFFERED,   FILE_ANY_ACCESS)
 			uint16_t wIndex;
 			uint16_t wLength;
 		} control;
+
+		struct {
+			uint32_t type;
+			uint32_t recipient;
+			uint32_t bRequest;
+			uint32_t wValue;
+			uint32_t wIndex;
+		} vendor;
+
 	};
 } libusb0_win32_request;
 
 class usb_device
 {
 public:
+	usb_device();
 	~usb_device();
 
 	usb_device_descriptor descriptor() const;
 	usb_config_descriptor get_config_descriptor() const;
 
+	std::vector<uint16_t> get_langid_list();
+	std::string get_string_descriptor(uint8_t index, uint16_t langid);
+
 	task<void> claim_interface(uint8_t intfno);
 	task<void> release_interface(uint8_t intfno);
 
 	task<size_t> bulk_read(usb_endpoint_t ep, uint8_t * buffer, size_t size);
 	task<size_t> bulk_write(usb_endpoint_t ep, uint8_t const * buffer, size_t size);
 
+	task<size_t> control_read(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t * buffer, size_t size);
+	task<size_t> control_write(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t const * buffer, size_t size);
+
 private:
 	usb_device(std::shared_ptr<usb_device_core> core);
 	std::shared_ptr<usb_device_core> m_core;

libyb/usb/usb_device.cpp

 #include "../async/detail/win32_handle_task.hpp"
 #include "../async/sync_runner.hpp"
 #include "../vector_ref.hpp"
+#include "../utils/utf.hpp"
 #include <map>
 #include <memory>
 #include <Windows.h>
 	task<size_t> get_descriptor(HANDLE hFile, uint8_t desc_type, uint8_t desc_index, uint16_t langid, unsigned char * data, int length)
 	{
 		req = libusb0_win32_request();
+		req.timeout = 5000;
 		req.descriptor.type = desc_type;
 		req.descriptor.index = desc_index;
 		req.descriptor.language_id = langid;
 		assert((ep & 0x80) != 0);
 
 		req = libusb0_win32_request();
+		req.timeout = 5000;
 		req.endpoint.endpoint = ep;
 		return opctx.ioctl(
 			hFile,
 		assert((ep & 0x80) == 0);
 
 		req = libusb0_win32_request();
+		req.timeout = 5000;
 		req.endpoint.endpoint = ep;
 		return opctx.ioctl(
 			hFile,
 			size);
 	}
 
+	task<size_t> control_read(HANDLE hFile, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t * buffer, size_t size)
+	{
+		assert((bmRequestType & 0x80) != 0);
+		assert((bmRequestType & 0x60) < (3<<5));
+		assert((bmRequestType & 0x1f) < 3);
+
+		req = libusb0_win32_request();
+		req.timeout = 5000;
+		req.vendor.type = (bmRequestType & 0x60) >> 5;
+		req.vendor.recipient = (bmRequestType & 0x1f);
+		req.vendor.bRequest = bRequest;
+		req.vendor.wValue = wValue;
+		req.vendor.wIndex = wIndex;
+
+		return opctx.ioctl(
+			hFile,
+			LIBUSB_IOCTL_VENDOR_READ,
+			&req,
+			sizeof req,
+			buffer,
+			size);
+	}
+
+	task<size_t> control_write(HANDLE hFile, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t const * buffer, size_t size)
+	{
+		assert((bmRequestType & 0x80) == 0);
+		assert((bmRequestType & 0x60) < (3<<5));
+		assert((bmRequestType & 0x1f) < 3);
+
+		req = libusb0_win32_request();
+		req.timeout = 5000;
+		req.vendor.type = (bmRequestType & 0x60) >> 5;
+		req.vendor.recipient = (bmRequestType & 0x1f);
+		req.vendor.bRequest = bRequest;
+		req.vendor.wValue = wValue;
+		req.vendor.wIndex = wIndex;
+
+		buf.resize(sizeof(libusb0_win32_request) + size);
+		std::copy(reinterpret_cast<uint8_t const *>(&req), reinterpret_cast<uint8_t const *>(&req) + sizeof req, buf.begin());
+		std::copy(buffer, buffer + size, buf.begin() + sizeof req);
+
+		return opctx.ioctl(
+			hFile,
+			LIBUSB_IOCTL_VENDOR_WRITE,
+			buf.data(),
+			buf.size(),
+			0,
+			0);
+	}
+
 	task<void> claim_interface(HANDLE hFile, uint8_t intfno)
 	{
 		req = libusb0_win32_request();
 
 private:
 	libusb0_win32_request req;
+	std::vector<uint8_t> buf;
 	win32_file_operation opctx;
 };
 
 	return res;
 }
 
+usb_device::usb_device()
+{
+}
+
 usb_device::usb_device(std::shared_ptr<usb_device_core> core)
 	: m_core(core)
 {
 	return parse_config_descriptor(desc);
 }
 
+std::vector<uint16_t> usb_device::get_langid_list()
+{
+	usb_request_context ctx;
+
+	uint8_t buf[256];
+	size_t read = run(ctx.get_descriptor(m_core->hFile.get(), 3, 0, 0, buf, sizeof buf));
+	if (read < 2 || buf[0] != read || buf[1] != 3 || read % 2 != 0)
+		throw std::runtime_error("invalid string descriptor");
+
+	std::vector<uint16_t> res;
+	for (size_t i = 2; i < read; i += 2)
+		res.push_back(buf[i] | (buf[i+1] << 8));
+	return res;
+}
+
+std::string usb_device::get_string_descriptor(uint8_t index, uint16_t langid)
+{
+	usb_request_context ctx;
+
+	uint8_t buf[256];
+	size_t read = run(ctx.get_descriptor(m_core->hFile.get(), 3, index, langid, buf, sizeof buf));
+	if (read < 2 || buf[0] != read || buf[1] != 3)
+		throw std::runtime_error("invalid string descriptor");
+
+	return utf16le_to_utf8(yb::buffer_ref(buf + 2, read - 2));
+}
+
 task<void> usb_device::claim_interface(uint8_t intfno)
 {
 	try
 		return async::raise<size_t>();
 	}
 }
+
+task<size_t> usb_device::control_read(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t * buffer, size_t size)
+{
+	try
+	{
+		std::shared_ptr<usb_request_context> ctx(new usb_request_context());
+		return ctx->control_read(m_core->hFile.get(), bmRequestType, bRequest, wValue, wIndex, buffer, size).follow_with([ctx](size_t){});
+	}
+	catch (...)
+	{
+		return async::raise<size_t>();
+	}
+}
+
+task<size_t> usb_device::control_write(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t const * buffer, size_t size)
+{
+	try
+	{
+		std::shared_ptr<usb_request_context> ctx(new usb_request_context());
+		return ctx->control_write(m_core->hFile.get(), bmRequestType, bRequest, wValue, wIndex, buffer, size).follow_with([ctx](size_t){});
+	}
+	catch (...)
+	{
+		return async::raise<size_t>();
+	}
+}

test/test.vcxproj

     <ClCompile Include="..\libyb\usb\bulk_stream.cpp" />
     <ClCompile Include="..\libyb\usb\interface_guard.cpp" />
     <ClCompile Include="..\libyb\usb\usb_device.cpp" />
+    <ClCompile Include="..\libyb\utils\utf.cpp" />
     <ClCompile Include="main.cpp" />
     <ClCompile Include="memmock.cpp" />
     <ClCompile Include="shupito_flash.cpp" />
     <ClInclude Include="..\libyb\usb\interface_guard.hpp" />
     <ClInclude Include="..\libyb\usb\usb.h" />
     <ClInclude Include="..\libyb\utils\noncopyable.hpp" />
+    <ClInclude Include="..\libyb\utils\signal.hpp" />
+    <ClInclude Include="..\libyb\utils\utf.hpp" />
     <ClInclude Include="..\libyb\vector_ref.hpp" />
     <ClInclude Include="memmock.h" />
     <ClInclude Include="test.h" />

test/test.vcxproj.filters

     <ClCompile Include="..\libyb\async\cancellation_token.cpp">
       <Filter>libyb\async</Filter>
     </ClCompile>
+    <ClCompile Include="..\libyb\utils\utf.cpp">
+      <Filter>libyb\utils</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\libyb\async\task.hpp">
     <ClInclude Include="..\libyb\async\cancellation_token.hpp">
       <Filter>libyb\async</Filter>
     </ClInclude>
+    <ClInclude Include="..\libyb\utils\signal.hpp">
+      <Filter>libyb\utils</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libyb\utils\utf.hpp">
+      <Filter>libyb\utils</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="libyb">
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.