├── driver ├── GNUmakefile ├── MAKEFILE.INC ├── README ├── USAGE ├── USBIPEnum.inf ├── USBIP_TestCert.cer ├── USBIP_TestCert.pfx ├── USBIP_TestCert.pvk ├── Wmi.c ├── b.bat ├── busenum.c ├── busenum.h ├── busenum.mof ├── busenum.rc ├── buspdo.c ├── code2name.c ├── createcert.bat ├── driver.h ├── i.bat ├── makefile ├── pnp.c ├── power.c ├── public.h ├── r.bat ├── sources └── usbip_protocol.h └── userspace ├── AUTHORS ├── COPYING ├── INSTALL ├── Makefile.am ├── README ├── autogen.sh ├── cleanup.sh ├── config.h ├── configure.ac ├── doc ├── usbip.8 ├── usbip_bind_driver.8 └── usbipd.8 ├── libsrc ├── Makefile.am ├── names.c ├── names.h ├── stub_driver.c ├── stub_driver.h ├── usbip.h ├── usbip_common.c ├── usbip_common.h ├── usbip_common.vcxproj ├── vhci_driver.c └── vhci_driver.h ├── src ├── Makefile.am ├── bind-driver.c ├── usbip.c ├── usbip.vcxproj ├── usbip_linux.c ├── usbip_network.c ├── usbip_network.h ├── usbip_osspecific.h ├── usbip_windows.c ├── usbipd.c ├── utils.c ├── utils.h └── windows │ ├── getopt.c │ ├── getopt.h │ ├── getopt_long.c │ ├── usbip_vbus_ui.c │ ├── usbip_vbus_ui.h │ └── usbip_windows_kernel_api.h ├── usb.ids └── usbip.sln /driver/GNUmakefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean all 2 | #CC:=i586-mingw32msvc-gcc 3 | #LD:=i586-mingw32msvc-ld 4 | #STRIP:=i586-mingw32msvc-strip 5 | CC=gcc 6 | LD=ld 7 | STRIP=strip 8 | ALL_TARGET:=output/usbip.exe #driver.sys 9 | all:$(ALL_TARGET) 10 | source:=busenum.c buspdo.c pnp.c power.c Wmi.c 11 | usbip_source:=usbip.c usbip_network.c usbip_common.c usbip_vbus_ui.c 12 | usbip_include:=public.h usbip_protocol.h usbip_network.h usbip_common.h usbip_vbus_ui.h win_stub.h 13 | output/usbip.exe:$(usbip_source) $(usbip_include) 14 | $(CC) -Wall -o $@ $(usbip_source) -lsetupapi -lws2_32 15 | driver.sys:$(source) busenum.h driver.h public.h 16 | $(CC) -D__USE_DIRECT__ -DDBG -Wall -Wl,-subsystem,native -Wl,-entry,_DriverEntry@8 -shared -nostartfiles -nostdlib -o $@ $(source) -lntoskrnl 17 | # $(LD) entry.o functions.o -mdll --subsystem,native --image-base=0x10000 --file-alignment=0x1000 --section-alignment=0x1000 --entry=_DriverEntry -nostartfiles -nostdlib -L/usr/i586-mingw32msvc/lib/ -lntoskrnl -o $@ 18 | # $(STRIP) $@ 19 | clean: 20 | rm -f $(ALL_TARGET) 21 | cscope: 22 | cscope -b -I/usr/i586-mingw32msvc/include -I/usr/i586-mingw32msvc/include/ddk -------------------------------------------------------------------------------- /driver/MAKEFILE.INC: -------------------------------------------------------------------------------- 1 | $(OBJ_PATH)\$(O)\busenum.bmf : busenum.mof 2 | mofcomp -B:$@ busenum.mof 3 | wmimofck $@ 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /driver/README: -------------------------------------------------------------------------------- 1 | Addition by Arjan Mels on 2 Apr 2011: 2 | 3 | Fixed various issues: 4 | - USB Mass Storage working under Vista & Win 7 5 | - Drivers accesible as normal user (eliminates need for elevation of client 6 | apps in Vista & Win7) 7 | - Fixed handling of isochronous packets (mainly in linux driver, but 8 | one fix in windows driver here) 9 | - Fixed unplug handling 10 | - Fixed usb port reset handling 11 | - Adjusted code to allow compilation under and included project files for 12 | Visual Studio 2010 13 | - Added CTRL-C Handling in client 14 | - Various smaller bugfixes/typos 15 | 16 | Addition by Arjan Mels on 16 Feb 2011: 17 | 18 | I modified the build script and code slightly to allow a x64 driver to compile. 19 | I have tested this and it works. 20 | 21 | x64 drivers for Vista & Windows 7 need to be signed with a special type of 22 | code signing certificate (kernel mode driver code signing certificate) 23 | otherwise they will not operate. 24 | Workaround in a administrative command prompt enter: "bcdedit /set testsigning on" 25 | Now all drivers will be accepted: THIS IS A SECURITY RISK 26 | 27 | I will try to get a version signed by the people of ReactOS 28 | (http://reactos.org/wiki/Driver_Signing) 29 | 30 | 31 | Original by Lepton Wu: 32 | 33 | Because I haven't implemented all the interfaces that a windows usb bus 34 | driver should provided, and perhaps some bug in my code, so some devices 35 | won't work now. 36 | 37 | Because I don't know enough about PNP management in windows, one big problem 38 | is that "stop device" is buggy now. 39 | 40 | USB devices I have tested ok for me: 41 | 42 | one usb mouse 43 | two usb flash disk 44 | (one disk only work with user space usbipd daemon, it need reset device function) 45 | two hid device compatible usb token key 46 | one dlink DWL-G122 usb wireless card 47 | usb camera on asus eeepc 701 model 48 | one usb microphone (only work with user space usbipd daemon) 49 | one usb sound card (only work with user space usbipd daemon) 50 | one usb webcam (only work with user space usbipd daemon) 51 | one usb TVBOX (it will display one or two screensoft and freeze, I don't know why, 52 | perhaps because the iso transfer is not so iso...) 53 | one bluetooth dongle (just test file transfter from my phone) 54 | 55 | To build userspace usbip tool: 56 | 57 | On a linux host: 58 | 59 | 1. install mingw32 60 | 61 | For debian based linux distribution, run like this; 62 | 63 | apt-get install mingw32 64 | 65 | 2. run "make" in this directory 66 | 67 | 68 | To build kernel driver: 69 | 70 | On a windows host: 71 | 72 | 1. install windows DDK 73 | 74 | I download version 6001.18002 from MSDN site. I think the other 75 | version perhaps will be ok too. 76 | 77 | 2. enter windows xp build env, and run b.bat in this directroy to 78 | build and install the kernel driver. 79 | 80 | you need devcon (from windows DDK sample) to install it. 81 | 82 | To test: 83 | 84 | You'd better test the kernel driver in a virtual windows guest. Then 85 | it won't crash your pc when this stuff BSOD. 86 | 87 | To show the exported usb device from linux 88 | c:\wxp>usbip -l xxx.xxx.xxx.xxx 89 | To attach it 90 | c:\wxp>usbip -a xxx.xxx.xxx.xxx x-x to use it. 91 | To detach it (open another cmd window) 92 | c:\wxp>usbip -d 1 93 | 94 | About LICENSE: 95 | 96 | I'd like to release these code under GPL, 97 | but since the kernel driver is started from a ddk sample (toaster sample), 98 | there is some MS license stuff at the beginning of every driver file. 99 | 100 | But I think I will change/rewrite the driver codes heavyly and at last I will 101 | make the driver compiled with mingw32, then I will delete all of the MS license 102 | stuff. 103 | 104 | Any question, pleas contact me with address Lepton Wu 105 | -------------------------------------------------------------------------------- /driver/USAGE: -------------------------------------------------------------------------------- 1 | To install the virtual usb bus driver on Windows XP: 2 | 3 | 1. Uncompress the downloaded binary package to a directory. 4 | 2. Double-click the 'Add Hardware' wizard in Control Panel. 5 | 3. At the 'Welcome to the Add Hardware Wizard', click 'Next'. 6 | 4. Select 'Yes, I have already connected the hardware', then click Next. 7 | 5. Select 'Add a new hardware device' from the list, then click Next. 8 | 6. Select 'Install the hardware that I manually select from a list(Advanced)', and then click next. 9 | 7. Select 'System Devices', then click Next. 10 | 8. Click 'Have Disk', click 'Browse', choose the uncompressed directory, and click OK. 11 | 9. Click on the 'USB/IP Enumerator', and then click Next. 12 | 10. At 'The wizard is ready to install your hardware', click Next. 13 | 11. Click Finish at 'Completing the Add/Remove Hardware Wizard.' 14 | 15 | For Window 7 : 16 | 1. (Only necessary for custom builds: For x64 allow unsigned drivers: Enter "bcdedit /set testsigning on" in an administrative cmd window) 17 | 2. Uncompress the downloaded binary package to a directory. 18 | 3. Start a the Device Manager 19 | 4. Click Any hardware node 20 | 5. Choose "Add Legacy Hardware" from the "Action" menu 21 | 6. At the 'Welcome to the Add Hardware Wizard', click 'Next'. 22 | 7. Select 'Install the hardware that I manually select from the list' 23 | 8. click 'Next' 24 | 9. Click 'Have Disk', click 'Browse', choose the uncompressed directory, and click OK. 25 | 10. Click on the 'USB/IP Enumerator', and then click Next. 26 | 11. At 'The wizard is ready to install your hardware', click Next. 27 | 12. Click Finish at 'Completing the Add/Remove Hardware Wizard.' 28 | 29 | To use it: 30 | 31 | 1. open a command prompt window, cd to the uncompressed directory. 32 | 33 | 2. run usbip -l 192.168.2.1 to list the exported devices from ip 192.168.2.1 34 | 35 | 3. run usbip -a 192.168.2.1 2-1 to imported the device. 36 | 37 | (Of course, you should change 192.168.2.1 and 2-1 to something else) 38 | -------------------------------------------------------------------------------- /driver/USBIPEnum.inf: -------------------------------------------------------------------------------- 1 | ;/*++ 2 | ; 3 | ; INF file for installing USB/IP bus enumerator driver 4 | ; 5 | ;--*/ 6 | [Version] 7 | Signature="$WINDOWS NT$" 8 | ; USB class cannot be installed via legacy hardware. It can be done via devcon 9 | ;Class=USB 10 | ;ClassGUID={36FC9E60-C465-11CF-8056-444553540000} 11 | Class=System 12 | ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} 13 | Provider=%OpenSource% 14 | DriverVer=04/22/2011,0.2.0.0 15 | CatalogFile=USBIPEnum.cat 16 | 17 | [Manufacturer] 18 | %StdMfg%=Standard 19 | %StdMfg%=Standard,NTamd64 20 | 21 | [Standard] 22 | %DeviceDesc%=USBIP_Device, root\USBIPEnum 23 | 24 | [Standard.NTamd64] 25 | %DeviceDesc%=USBIP_Device, root\USBIPEnum 26 | 27 | [DestinationDirs] 28 | DefaultDestDir = 12 29 | 30 | [SourceDisksNames] 31 | 1 = %DiskId1%,,,"" 32 | 33 | [SourceDisksFiles] 34 | USBIPEnum_x86.sys = 1,, 35 | USBIPEnum_x64.sys = 1,, 36 | 37 | [Drivers_Dir_x86] 38 | USBIPEnum.sys,USBIPEnum_x86.sys 39 | 40 | [Drivers_Dir_x64] 41 | USBIPEnum.sys,USBIPEnum_x64.sys 42 | 43 | [USBIP_Device] 44 | CopyFiles=Drivers_Dir_x86 45 | 46 | [USBIP_Device.NTamd64] 47 | CopyFiles=Drivers_Dir_x64 48 | 49 | [USBIP_Device.NT.HW] 50 | AddReg=USBIP_Device_AddReg 51 | 52 | [USBIP_Device.NTamd64.HW] 53 | AddReg=USBIP_Device_AddReg 54 | 55 | [USBIP_Device_AddReg] 56 | HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens 57 | ;Using default permissions so comment out next lines 58 | ;HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)" ; Allow generic-all access to all users 59 | ;HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system 60 | 61 | ;-------------- Service installation 62 | [USBIP_Device.Services] 63 | AddService = USBIPEnum,%SPSVCINST_ASSOCSERVICE%, USBIP_Service_Inst 64 | 65 | [USBIP_Device.NTamd64.Services] 66 | AddService = USBIPEnum,%SPSVCINST_ASSOCSERVICE%, USBIP_Service_Inst 67 | 68 | ; -------------- busenum driver install sections 69 | [USBIP_Service_Inst] 70 | DisplayName = %ServiceDesc% 71 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 72 | StartType = 3 ; SERVICE_DEMAND_START 73 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 74 | ServiceBinary = %12%\USBIPEnum.sys 75 | LoadOrderGroup = Extended Base 76 | 77 | 78 | [Strings] 79 | SPSVCINST_ASSOCSERVICE= 0x00000002 80 | OpenSource = "Open Source" 81 | StdMfg = "USB/IP Project" 82 | DiskId1 = "USB/IP Enumerator Disk" 83 | DeviceDesc = "USB/IP Enumerator" 84 | ServiceDesc = "USB/IP Enumerator Service" 85 | 86 | -------------------------------------------------------------------------------- /driver/USBIP_TestCert.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spurious/usbip-windows-mirror/1e5e567eec456da0c73c37d6f3d6b11cfae2e388/driver/USBIP_TestCert.cer -------------------------------------------------------------------------------- /driver/USBIP_TestCert.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spurious/usbip-windows-mirror/1e5e567eec456da0c73c37d6f3d6b11cfae2e388/driver/USBIP_TestCert.pfx -------------------------------------------------------------------------------- /driver/USBIP_TestCert.pvk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spurious/usbip-windows-mirror/1e5e567eec456da0c73c37d6f3d6b11cfae2e388/driver/USBIP_TestCert.pvk -------------------------------------------------------------------------------- /driver/b.bat: -------------------------------------------------------------------------------- 1 | rem batch file to build complete drivers: output will be put in output directory 2 | 3 | rem build 32-bit version in XP environment 4 | rem build 64-bit version in Windows Server 2003 environment 5 | 6 | set OCD=%CD% 7 | 8 | set TYPE=chk 9 | 10 | IF "%BASEDIR%"=="" ( 11 | set BASEDIR=D:\WinDDK\7600.16385.1 12 | CALL D:\WinDDK\7600.16385.1\bin\setenv.bat D:\WinDDK\7600.16385.1 %TYPE% WLH 13 | cd /d %OCD% 14 | ) 15 | 16 | cmd /C "set DDKBUILDENV=&& %BASEDIR%\bin\setenv.bat %BASEDIR% %TYPE% WLH && cd /d %OCD% && build" 17 | cmd /C "set DDKBUILDENV=&& %BASEDIR%\bin\setenv.bat %BASEDIR% %TYPE% x64 WLH && cd /d %OCD% && build" 18 | 19 | rem copy files to output folder 20 | rem del /Q output 21 | mkdir output 22 | copy USBIPEnum.inf output 23 | copy obj%TYPE%_wlh_x86\i386\USBIPEnum.sys output\USBIPEnum_x86.sys 24 | copy obj%TYPE%_wlh_amd64\amd64\USBIPEnum.sys output\USBIPEnum_x64.sys 25 | 26 | rem sign files and create catalog file 27 | signtool sign /f USBIP_TestCert.pfx /t http://timestamp.verisign.com/scripts/timestamp.dll output\USBIPEnum_x86.sys 28 | signtool sign /f USBIP_TestCert.pfx /t http://timestamp.verisign.com/scripts/timestamp.dll output\USBIPEnum_x64.sys 29 | 30 | inf2cat /driver:output /os:XP_x86,XP_x64,Server2003_X86,Server2003_X64,Vista_X86,Vista_X64,Server2008_X86,Server2008_X64,7_X86,7_X64,Server2008R2_X64 31 | 32 | signtool sign /f USBIP_TestCert.pfx /t http://timestamp.verisign.com/scripts/timestamp.dll output\USBIPEnum.cat 33 | 34 | -------------------------------------------------------------------------------- /driver/busenum.mof: -------------------------------------------------------------------------------- 1 | [Dynamic, Provider("WMIProv"), 2 | WMI, 3 | Description("Virtual USB Bus driver information"), 4 | guid("{0006A660-8F12-11d2-B854-00C04FAD5171}"), 5 | locale("MS\\0x409")] 6 | class ToasterBusInformation 7 | { 8 | [key, read] 9 | string InstanceName; 10 | [read] boolean Active; 11 | 12 | [WmiDataId(1), 13 | read, 14 | Description("Number of errors that occurred on this device")] 15 | uint32 ErrorCount; 16 | 17 | [WmiDataId(2), 18 | read, 19 | write, 20 | Description("The DebugPrintLevel property indicates the debug output level of toaster bus device.")] 21 | uint32 DebugPrintLevel; 22 | 23 | }; 24 | 25 | 26 | -------------------------------------------------------------------------------- /driver/busenum.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #define VER_FILETYPE VFT_DLL 6 | #define VER_FILESUBTYPE VFT2_UNKNOWN 7 | #define VER_FILEDESCRIPTION_STR "USB/IP Enumerator" 8 | #define VER_INTERNALNAME_STR "USBIPEnum.sys" 9 | #define VER_ORIGINALFILENAME_STR "USBIPEnum.sys" 10 | #define VER_PRODUCTVERSION 0.2.0.0 11 | #define VER_PRODUCTVERSION_STR "0.2.0.0" 12 | #define VER_LEGALCOPYRIGHT_STR "Open Source Software" 13 | #define VER_PRODUCTNAME_STR "USB/IP" 14 | 15 | #include "common.ver" 16 | 17 | BusEnumWMI MOFDATA busenum.bmf 18 | -------------------------------------------------------------------------------- /driver/code2name.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define K_V(a) {#a, a}, 4 | 5 | struct macro { 6 | const char *name; 7 | unsigned int code; 8 | }; 9 | 10 | struct macro usb_io_ctrls[]={ 11 | K_V( IOCTL_INTERNAL_USB_CYCLE_PORT ) 12 | K_V( IOCTL_INTERNAL_USB_ENABLE_PORT ) 13 | K_V( IOCTL_INTERNAL_USB_GET_BUS_INFO ) 14 | K_V( IOCTL_INTERNAL_USB_GET_BUSGUID_INFO ) 15 | K_V( IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME ) 16 | K_V( IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE ) 17 | K_V( IOCTL_INTERNAL_USB_GET_HUB_COUNT ) 18 | K_V( IOCTL_INTERNAL_USB_GET_HUB_NAME ) 19 | K_V( IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO ) 20 | K_V( IOCTL_INTERNAL_USB_GET_PORT_STATUS ) 21 | K_V( IOCTL_INTERNAL_USB_RESET_PORT ) 22 | K_V( IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO ) 23 | K_V( IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION ) 24 | K_V( IOCTL_INTERNAL_USB_SUBMIT_URB ) 25 | K_V( IOCTL_INTERNAL_USB_GET_TOPOLOGY_ADDRESS ) 26 | K_V( IOCTL_USB_DIAG_IGNORE_HUBS_ON ) 27 | K_V( IOCTL_USB_DIAG_IGNORE_HUBS_OFF ) 28 | K_V( IOCTL_USB_DIAGNOSTIC_MODE_OFF ) 29 | K_V( IOCTL_USB_DIAGNOSTIC_MODE_ON ) 30 | K_V( IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION ) 31 | K_V( IOCTL_USB_GET_HUB_CAPABILITIES ) 32 | K_V( IOCTL_USB_GET_ROOT_HUB_NAME ) 33 | K_V( IOCTL_GET_HCD_DRIVERKEY_NAME ) 34 | K_V( IOCTL_USB_GET_NODE_INFORMATION ) 35 | K_V( IOCTL_USB_GET_NODE_CONNECTION_INFORMATION ) 36 | K_V( IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES ) 37 | K_V( IOCTL_USB_GET_NODE_CONNECTION_NAME ) 38 | K_V( IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME ) 39 | K_V( IOCTL_USB_HCD_DISABLE_PORT ) 40 | K_V( IOCTL_USB_HCD_ENABLE_PORT ) 41 | K_V( IOCTL_USB_HCD_GET_STATS_1 ) 42 | K_V( IOCTL_USB_HCD_GET_STATS_2 ) 43 | {0,0}}; 44 | 45 | struct macro usb_funcs[]={ 46 | K_V( URB_FUNCTION_SELECT_CONFIGURATION ) 47 | K_V( URB_FUNCTION_SELECT_INTERFACE ) 48 | K_V( URB_FUNCTION_ABORT_PIPE ) 49 | K_V( URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL ) 50 | K_V( URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL ) 51 | K_V( URB_FUNCTION_GET_FRAME_LENGTH ) 52 | K_V( URB_FUNCTION_SET_FRAME_LENGTH ) 53 | K_V( URB_FUNCTION_GET_CURRENT_FRAME_NUMBER ) 54 | K_V( URB_FUNCTION_CONTROL_TRANSFER ) 55 | K_V( URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER ) 56 | K_V( URB_FUNCTION_ISOCH_TRANSFER ) 57 | K_V( URB_FUNCTION_RESET_PIPE ) 58 | K_V( URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE ) 59 | K_V( URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT ) 60 | K_V( URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE ) 61 | K_V( URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE ) 62 | K_V( URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT ) 63 | K_V( URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE ) 64 | K_V( URB_FUNCTION_SET_FEATURE_TO_DEVICE ) 65 | K_V( URB_FUNCTION_SET_FEATURE_TO_INTERFACE ) 66 | K_V( URB_FUNCTION_SET_FEATURE_TO_ENDPOINT ) 67 | K_V( URB_FUNCTION_SET_FEATURE_TO_OTHER ) 68 | K_V( URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE ) 69 | K_V( URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE ) 70 | K_V( URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT ) 71 | K_V( URB_FUNCTION_CLEAR_FEATURE_TO_OTHER ) 72 | K_V( URB_FUNCTION_GET_STATUS_FROM_DEVICE ) 73 | K_V( URB_FUNCTION_GET_STATUS_FROM_INTERFACE ) 74 | K_V( URB_FUNCTION_GET_STATUS_FROM_ENDPOINT ) 75 | K_V( URB_FUNCTION_GET_STATUS_FROM_OTHER ) 76 | K_V( URB_FUNCTION_RESERVED0 ) 77 | K_V( URB_FUNCTION_VENDOR_DEVICE ) 78 | K_V( URB_FUNCTION_VENDOR_INTERFACE ) 79 | K_V( URB_FUNCTION_VENDOR_ENDPOINT ) 80 | K_V( URB_FUNCTION_VENDOR_OTHER ) 81 | K_V( URB_FUNCTION_CLASS_DEVICE ) 82 | K_V( URB_FUNCTION_CLASS_INTERFACE ) 83 | K_V( URB_FUNCTION_CLASS_ENDPOINT ) 84 | K_V( URB_FUNCTION_CLASS_OTHER ) 85 | K_V( URB_FUNCTION_RESERVED ) 86 | K_V( URB_FUNCTION_GET_CONFIGURATION ) 87 | K_V( URB_FUNCTION_GET_INTERFACE ) 88 | K_V( URB_FUNCTION_LAST ) 89 | {0,0}}; 90 | 91 | const char * code2name(unsigned int code) 92 | { 93 | int i; 94 | for(i=0;usb_io_ctrls[i].name;i++){ 95 | if(code==usb_io_ctrls[i].code) 96 | return usb_io_ctrls[i].name; 97 | } 98 | return "Unknown ioctl code"; 99 | } 100 | 101 | const char * func2name(unsigned int func) 102 | { 103 | int i; 104 | for(i=0;usb_funcs[i].name;i++){ 105 | if(func==usb_funcs[i].code) 106 | return usb_funcs[i].name; 107 | } 108 | return "Unknown func code"; 109 | } 110 | -------------------------------------------------------------------------------- /driver/createcert.bat: -------------------------------------------------------------------------------- 1 | 2 | makecert -r -pe -n "CN=USB/IP Test Certificate" -ss CA -sr CurrentUser -a sha1 -sky signature -sv USBIP_TestCert.pvk USBIP_TestCert.cer 3 | pvk2pfx -pvk USBIP_TestCert.pvk -spc USBIP_TestCert.cer -pfx USBIP_TestCert.pfx 4 | 5 | rem certutil -user -addstore Root USBIP_TestCert.cer 6 | 7 | rem Bcdedit.exe /set TESTSIGNING ON 8 | -------------------------------------------------------------------------------- /driver/driver.h: -------------------------------------------------------------------------------- 1 | // 2 | // This guid is used in IoCreateDeviceSecure call to create PDOs. The idea is to 3 | // allow the administrators to control access to the child device, in case the 4 | // device gets enumerated as a raw device - no function driver, by modifying the 5 | // registry. If a function driver is loaded for the device, the system will override 6 | // the security descriptor specified in the call to IoCreateDeviceSecure with the 7 | // one specifyied for the setup class of the child device. 8 | // 9 | 10 | DEFINE_GUID(GUID_SD_BUSENUM_PDO, 11 | 0x9d3039dd, 0xcca5, 0x4b4d, 0xb3, 0x3d, 0xe2, 0xdd, 0xc8, 0xa8, 0xc5, 0x2e); 12 | // {9D3039DD-CCA5-4b4d-B33D-E2DDC8A8C52E} 13 | 14 | // 15 | // GUID definition are required to be outside of header inclusion pragma to avoid 16 | // error during precompiled headers. 17 | // 18 | 19 | #ifndef __DRIVER_H 20 | #define __DRIVER_H 21 | 22 | // 23 | // Define Interface reference/dereference routines for 24 | // Interfaces exported by IRP_MN_QUERY_INTERFACE 25 | // 26 | 27 | typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context); 28 | typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context); 29 | 30 | typedef 31 | BOOLEAN 32 | (*PUSBIP_GET_CRISPINESS_LEVEL)( 33 | __in PVOID Context, 34 | __out PUCHAR Level 35 | ); 36 | 37 | typedef 38 | BOOLEAN 39 | (*PUSBIP_SET_CRISPINESS_LEVEL)( 40 | __in PVOID Context, 41 | __out UCHAR Level 42 | ); 43 | 44 | typedef 45 | BOOLEAN 46 | (*PUSBIP_IS_CHILD_PROTECTED)( 47 | __in PVOID Context 48 | ); 49 | 50 | // 51 | // Interface for getting and setting power level etc., 52 | // 53 | 54 | #ifndef STATUS_CONTINUE_COMPLETION //required to build driver in Win2K and XP build environment 55 | // 56 | // This value should be returned from completion routines to continue 57 | // completing the IRP upwards. Otherwise, STATUS_MORE_PROCESSING_REQUIRED 58 | // should be returned. 59 | // 60 | #define STATUS_CONTINUE_COMPLETION STATUS_SUCCESS 61 | 62 | #endif 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /driver/i.bat: -------------------------------------------------------------------------------- 1 | 2 | rem bcdedit /set testsigning on 3 | 4 | rem certutil -enterprise -addstore Root USBIP_TestCert.cer 5 | rem certutil -enterprise -addstore TrustedPublisher USBIP_TestCert.cer 6 | 7 | cd output 8 | 9 | ..\devcon install USBIPEnum.inf "root\USBIPEnum" 10 | 11 | cd .. 12 | -------------------------------------------------------------------------------- /driver/makefile: -------------------------------------------------------------------------------- 1 | # 2 | # DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source 3 | # file to this component. This file merely indirects to the real make file 4 | # that is shared by all the driver components of the Windows NT DDK 5 | # 6 | 7 | !INCLUDE $(NTMAKEENV)\makefile.def 8 | 9 | 10 | -------------------------------------------------------------------------------- /driver/power.c: -------------------------------------------------------------------------------- 1 | #include "busenum.h" 2 | 3 | 4 | 5 | NTSTATUS 6 | Bus_Power ( 7 | __in PDEVICE_OBJECT DeviceObject, 8 | __in PIRP Irp 9 | ) 10 | /*++ 11 | Handles power Irps sent to both FDO and child PDOs. 12 | Note: Currently we do not implement full power handling 13 | for the FDO. 14 | 15 | Arguments: 16 | 17 | DeviceObject - Pointer to the device object. 18 | Irp - Pointer to the irp. 19 | 20 | Return Value: 21 | 22 | NT status is returned. 23 | 24 | --*/ 25 | { 26 | PIO_STACK_LOCATION irpStack; 27 | NTSTATUS status; 28 | PCOMMON_DEVICE_DATA commonData; 29 | 30 | 31 | KdPrint(("Bus_Power\r\n")); 32 | 33 | status = STATUS_SUCCESS; 34 | irpStack = IoGetCurrentIrpStackLocation (Irp); 35 | ASSERT (IRP_MJ_POWER == irpStack->MajorFunction); 36 | 37 | commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension; 38 | 39 | // 40 | // If the device has been removed, the driver should 41 | // not pass the IRP down to the next lower driver. 42 | // 43 | 44 | if (commonData->DevicePnPState == Deleted) { 45 | PoStartNextPowerIrp (Irp); 46 | Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE ; 47 | IoCompleteRequest (Irp, IO_NO_INCREMENT); 48 | return status; 49 | } 50 | 51 | if (commonData->IsFDO) { 52 | 53 | Bus_KdPrint (commonData, BUS_DBG_POWER_TRACE, 54 | ("FDO %s IRP:0x%p %s %s\n", 55 | PowerMinorFunctionString(irpStack->MinorFunction), Irp, 56 | DbgSystemPowerString(commonData->SystemPowerState), 57 | DbgDevicePowerString(commonData->DevicePowerState))); 58 | 59 | 60 | status = Bus_FDO_Power ((PFDO_DEVICE_DATA)DeviceObject->DeviceExtension, 61 | Irp); 62 | } else { 63 | 64 | Bus_KdPrint (commonData, BUS_DBG_POWER_TRACE, 65 | ("PDO %s IRP:0x%p %s %s\n", 66 | PowerMinorFunctionString(irpStack->MinorFunction), Irp, 67 | DbgSystemPowerString(commonData->SystemPowerState), 68 | DbgDevicePowerString(commonData->DevicePowerState))); 69 | 70 | status = Bus_PDO_Power ((PPDO_DEVICE_DATA)DeviceObject->DeviceExtension, 71 | Irp); 72 | } 73 | 74 | return status; 75 | } 76 | 77 | 78 | NTSTATUS 79 | Bus_FDO_Power ( 80 | PFDO_DEVICE_DATA Data, 81 | PIRP Irp 82 | ) 83 | /*++ 84 | Handles power Irps sent to the FDO. 85 | This driver is power policy owner for the bus itself 86 | (not the devices on the bus).Power handling for the bus FDO 87 | should be implemented similar to the function driver (USBIP.sys) 88 | power code. We will just print some debug outputs and 89 | forward this Irp to the next level. 90 | 91 | Arguments: 92 | 93 | Data - Pointer to the FDO device extension. 94 | Irp - Pointer to the irp. 95 | 96 | Return Value: 97 | 98 | NT status is returned. 99 | 100 | --*/ 101 | 102 | { 103 | NTSTATUS status; 104 | POWER_STATE powerState; 105 | POWER_STATE_TYPE powerType; 106 | PIO_STACK_LOCATION stack; 107 | 108 | stack = IoGetCurrentIrpStackLocation (Irp); 109 | powerType = stack->Parameters.Power.Type; 110 | powerState = stack->Parameters.Power.State; 111 | 112 | Bus_IncIoCount (Data); 113 | 114 | // 115 | // If the device is not stated yet, just pass it down. 116 | // 117 | 118 | if (Data->DevicePnPState == NotStarted) { 119 | PoStartNextPowerIrp(Irp); 120 | IoSkipCurrentIrpStackLocation(Irp); 121 | status = PoCallDriver(Data->NextLowerDriver, Irp); 122 | Bus_DecIoCount (Data); 123 | return status; 124 | 125 | } 126 | 127 | if (stack->MinorFunction == IRP_MN_SET_POWER) { 128 | Bus_KdPrint_Cont(Data, BUS_DBG_POWER_TRACE, 129 | ("\tRequest to set %s state to %s\n", 130 | ((powerType == SystemPowerState) ? "System" : "Device"), 131 | ((powerType == SystemPowerState) ? \ 132 | DbgSystemPowerString(powerState.SystemState) :\ 133 | DbgDevicePowerString(powerState.DeviceState)))); 134 | } 135 | 136 | PoStartNextPowerIrp (Irp); 137 | IoSkipCurrentIrpStackLocation(Irp); 138 | status = PoCallDriver (Data->NextLowerDriver, Irp); 139 | Bus_DecIoCount (Data); 140 | return status; 141 | } 142 | 143 | 144 | NTSTATUS 145 | Bus_PDO_Power ( 146 | PPDO_DEVICE_DATA PdoData, 147 | PIRP Irp 148 | ) 149 | /*++ 150 | Handles power Irps sent to the PDOs. 151 | Typically a bus driver, that is not a power 152 | policy owner for the device, does nothing 153 | more than starting the next power IRP and 154 | completing this one. 155 | 156 | Arguments: 157 | 158 | PdoData - Pointer to the PDO device extension. 159 | Irp - Pointer to the irp. 160 | 161 | Return Value: 162 | 163 | NT status is returned. 164 | 165 | --*/ 166 | 167 | { 168 | NTSTATUS status; 169 | PIO_STACK_LOCATION stack; 170 | POWER_STATE powerState; 171 | POWER_STATE_TYPE powerType; 172 | 173 | stack = IoGetCurrentIrpStackLocation (Irp); 174 | powerType = stack->Parameters.Power.Type; 175 | powerState = stack->Parameters.Power.State; 176 | 177 | switch (stack->MinorFunction) { 178 | case IRP_MN_SET_POWER: 179 | 180 | Bus_KdPrint_Cont(PdoData, BUS_DBG_POWER_TRACE, 181 | ("\tSetting %s power state to %s\n", 182 | ((powerType == SystemPowerState) ? "System" : "Device"), 183 | ((powerType == SystemPowerState) ? \ 184 | DbgSystemPowerString(powerState.SystemState) : \ 185 | DbgDevicePowerString(powerState.DeviceState)))); 186 | 187 | switch (powerType) { 188 | case DevicePowerState: 189 | PoSetPowerState (PdoData->Self, powerType, powerState); 190 | PdoData->DevicePowerState = powerState.DeviceState; 191 | status = STATUS_SUCCESS; 192 | break; 193 | 194 | case SystemPowerState: 195 | PdoData->SystemPowerState = powerState.SystemState; 196 | status = STATUS_SUCCESS; 197 | break; 198 | 199 | default: 200 | status = STATUS_NOT_SUPPORTED; 201 | break; 202 | } 203 | break; 204 | 205 | case IRP_MN_QUERY_POWER: 206 | status = STATUS_SUCCESS; 207 | break; 208 | 209 | case IRP_MN_WAIT_WAKE: 210 | // 211 | // We cannot support wait-wake because we are root-enumerated 212 | // driver, and our parent, the PnP manager, doesn't support wait-wake. 213 | // If you are a bus enumerated device, and if your parent bus supports 214 | // wait-wake, you should send a wait/wake IRP (PoRequestPowerIrp) 215 | // in response to this request. 216 | // If you want to test the wait/wake logic implemented in the function 217 | // driver (USBIP.sys), you could do the following simulation: 218 | // a) Mark this IRP pending. 219 | // b) Set a cancel routine. 220 | // c) Save this IRP in the device extension 221 | // d) Return STATUS_PENDING. 222 | // Later on if you suspend and resume your system, your BUS_FDO_POWER 223 | // will be called to power the bus. In response to IRP_MN_SET_POWER, if the 224 | // powerstate is PowerSystemWorking, complete this Wake IRP. 225 | // If the function driver, decides to cancel the wake IRP, your cancel routine 226 | // will be called. There you just complete the IRP with STATUS_CANCELLED. 227 | // 228 | case IRP_MN_POWER_SEQUENCE: 229 | default: 230 | status = STATUS_NOT_SUPPORTED; 231 | break; 232 | } 233 | 234 | if (status != STATUS_NOT_SUPPORTED) { 235 | 236 | Irp->IoStatus.Status = status; 237 | } 238 | 239 | PoStartNextPowerIrp(Irp); 240 | status = Irp->IoStatus.Status; 241 | IoCompleteRequest (Irp, IO_NO_INCREMENT); 242 | 243 | return status; 244 | } 245 | 246 | #if DBG 247 | 248 | PCHAR 249 | PowerMinorFunctionString ( 250 | UCHAR MinorFunction 251 | ) 252 | { 253 | switch (MinorFunction) 254 | { 255 | case IRP_MN_SET_POWER: 256 | return "IRP_MN_SET_POWER"; 257 | case IRP_MN_QUERY_POWER: 258 | return "IRP_MN_QUERY_POWER"; 259 | case IRP_MN_POWER_SEQUENCE: 260 | return "IRP_MN_POWER_SEQUENCE"; 261 | case IRP_MN_WAIT_WAKE: 262 | return "IRP_MN_WAIT_WAKE"; 263 | 264 | default: 265 | return "unknown_power_irp"; 266 | } 267 | } 268 | 269 | PCHAR 270 | DbgSystemPowerString( 271 | __in SYSTEM_POWER_STATE Type 272 | ) 273 | { 274 | switch (Type) 275 | { 276 | case PowerSystemUnspecified: 277 | return "PowerSystemUnspecified"; 278 | case PowerSystemWorking: 279 | return "PowerSystemWorking"; 280 | case PowerSystemSleeping1: 281 | return "PowerSystemSleeping1"; 282 | case PowerSystemSleeping2: 283 | return "PowerSystemSleeping2"; 284 | case PowerSystemSleeping3: 285 | return "PowerSystemSleeping3"; 286 | case PowerSystemHibernate: 287 | return "PowerSystemHibernate"; 288 | case PowerSystemShutdown: 289 | return "PowerSystemShutdown"; 290 | case PowerSystemMaximum: 291 | return "PowerSystemMaximum"; 292 | default: 293 | return "UnKnown System Power State"; 294 | } 295 | } 296 | 297 | PCHAR 298 | DbgDevicePowerString( 299 | __in DEVICE_POWER_STATE Type 300 | ) 301 | { 302 | switch (Type) 303 | { 304 | case PowerDeviceUnspecified: 305 | return "PowerDeviceUnspecified"; 306 | case PowerDeviceD0: 307 | return "PowerDeviceD0"; 308 | case PowerDeviceD1: 309 | return "PowerDeviceD1"; 310 | case PowerDeviceD2: 311 | return "PowerDeviceD2"; 312 | case PowerDeviceD3: 313 | return "PowerDeviceD3"; 314 | case PowerDeviceMaximum: 315 | return "PowerDeviceMaximum"; 316 | default: 317 | return "UnKnown Device Power State"; 318 | } 319 | } 320 | 321 | #endif 322 | 323 | 324 | -------------------------------------------------------------------------------- /driver/public.h: -------------------------------------------------------------------------------- 1 | // 2 | // Define an Interface Guid for bus enumerator class. 3 | // This GUID is used to register (IoRegisterDeviceInterface) 4 | // an instance of an interface so that enumerator application 5 | // can send an ioctl to the bus driver. 6 | // 7 | 8 | DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_USBIP, 9 | 0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 10 | 11 | 12 | // 13 | // Define a Setup Class GUID for USBIP Class. This is same 14 | // as the TOASTSER CLASS guid in the INF files. 15 | // 16 | 17 | DEFINE_GUID (GUID_DEVCLASS_USBIP, 18 | 0xB85B7C50, 0x6A01, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 19 | //{B85B7C50-6A01-11d2-B841-00C04FAD5171} 20 | 21 | // 22 | // Define a WMI GUID to get busenum info. 23 | // 24 | 25 | DEFINE_GUID (USBIP_BUS_WMI_STD_DATA_GUID, 26 | 0x0006A660, 0x8F12, 0x11d2, 0xB8, 0x54, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 27 | //{0006A660-8F12-11d2-B854-00C04FAD5171} 28 | 29 | // 30 | // Define a WMI GUID to get USBIP device info. 31 | // 32 | 33 | DEFINE_GUID (USBIP_WMI_STD_DATA_GUID, 34 | 0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 35 | 36 | // 37 | // Define a WMI GUID to represent device arrival notification WMIEvent class. 38 | // 39 | 40 | DEFINE_GUID (USBIP_NOTIFY_DEVICE_ARRIVAL_EVENT, 41 | 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c); 42 | // {01CDAFF1-C901-45b4-B359-B5542725E29C} 43 | 44 | 45 | // 46 | // GUID definition are required to be outside of header inclusion pragma to avoid 47 | // error during precompiled headers. 48 | // 49 | 50 | #ifndef __PUBLIC_H 51 | #define __PUBLIC_H 52 | 53 | #define USBVBUS_IOCTL(_index_) \ 54 | CTL_CODE (FILE_DEVICE_BUS_EXTENDER, _index_, METHOD_BUFFERED, FILE_READ_DATA) 55 | 56 | #define IOCTL_USBVBUS_PLUGIN_HARDWARE USBVBUS_IOCTL (0x0) 57 | #define IOCTL_USBVBUS_UNPLUG_HARDWARE USBVBUS_IOCTL (0x1) 58 | #define IOCTL_USBVBUS_EJECT_HARDWARE USBVBUS_IOCTL (0x2) 59 | #define IOCTL_USBVBUS_GET_PORTS_STATUS USBVBUS_IOCTL (0x3) 60 | 61 | #define COMPATIBLE_IDS_SAMPLE L"USB\\Class_00&SubClass_00&Prot_00\0USB\\Class_00&SubClass_00\0USB\\Class_00\0" 62 | 63 | #define BUSENUM_COMPATIBLE_IDS_LENGTH sizeof(COMPATIBLE_IDS_SAMPLE) 64 | 65 | typedef struct _ioctl_usbvbus_plugin 66 | { 67 | unsigned int devid; 68 | /* 4 bytes */ 69 | unsigned short vendor; 70 | unsigned short product; 71 | /* 8 bytes */ 72 | unsigned short version; 73 | unsigned char speed; 74 | unsigned char inum; 75 | /* 12 bytes */ 76 | unsigned char int0_class; 77 | unsigned char int0_subclass; 78 | unsigned char int0_protocol; 79 | signed char addr; /* then it can not be bigger then 127 */ 80 | /* 16 bytes */ 81 | } ioctl_usbvbus_plugin; 82 | 83 | typedef struct _ioctl_usbvbus_get_ports_status 84 | { 85 | union { 86 | signed char max_used_port; /* then it can not be bigger than 127 */ 87 | unsigned char port_status[128]; 88 | /* 128 bytes */ 89 | }; 90 | } ioctl_usbvbus_get_ports_status; 91 | 92 | typedef struct _ioctl_usbvbus_unplug 93 | { 94 | signed char addr; 95 | char unused[3]; 96 | 97 | } ioctl_usbvbus_unplug; 98 | 99 | typedef struct _BUSENUM_EJECT_HARDWARE 100 | { 101 | // 102 | // sizeof (struct _EJECT_HARDWARE) 103 | // 104 | 105 | ULONG Size; 106 | 107 | // 108 | // Serial number of the device to be ejected 109 | // 110 | 111 | ULONG SerialNo; 112 | 113 | ULONG Reserved[2]; 114 | 115 | } BUSENUM_EJECT_HARDWARE, *PBUSENUM_EJECT_HARDWARE; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /driver/r.bat: -------------------------------------------------------------------------------- 1 | devcon remove "root\USBIPEnum" 2 | 3 | 4 | -------------------------------------------------------------------------------- /driver/sources: -------------------------------------------------------------------------------- 1 | TARGETNAME=USBIPEnum 2 | TARGETTYPE=DRIVER 3 | 4 | INCLUDES = ..\inc 5 | 6 | NTTARGETFILE0=$(OBJ_PATH)\$(O)\busenum.bmf 7 | 8 | 9 | TARGETLIBS= $(DDK_LIB_PATH)\wdmsec.lib \ 10 | $(DDK_LIB_PATH)\ntstrsafe.lib 11 | 12 | SOURCES= busenum.rc \ 13 | busenum.c \ 14 | pnp.c \ 15 | power.c \ 16 | buspdo.c \ 17 | wmi.c 18 | 19 | #_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WINXP) 20 | -------------------------------------------------------------------------------- /driver/usbip_protocol.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef _USBIP_PROTOCOL_H 6 | #define _USBIP_PROTOCOL_H 7 | #pragma pack(push,1) 8 | #ifdef __GNUC__ 9 | #define __attribute__(x) __attribute__(x) 10 | #else 11 | #define __attribute__(x) /* x */ 12 | #endif 13 | #define USBIP_VERSION 0x000106 14 | 15 | /* -------------------------------------------------- */ 16 | /* Define Protocol Format */ 17 | /* -------------------------------------------------- */ 18 | 19 | 20 | /* ---------------------------------------------------------------------- */ 21 | /* Common header for all the kinds of PDUs. */ 22 | struct op_common { 23 | uint16_t version; 24 | 25 | #define OP_REQUEST (0x80 << 8) 26 | #define OP_REPLY (0x00 << 8) 27 | uint16_t code; 28 | 29 | /* add more error code */ 30 | #define ST_OK 0x00 31 | #define ST_NA 0x01 32 | uint32_t status; /* op_code status (for reply) */ 33 | 34 | } __attribute__((packed)); 35 | 36 | #define PACK_OP_COMMON(pack, op_common) do {\ 37 | pack_uint16_t(pack, &(op_common)->version);\ 38 | pack_uint16_t(pack, &(op_common)->code );\ 39 | pack_uint32_t(pack, &(op_common)->status );\ 40 | } while (0) 41 | 42 | /* ---------------------------------------------------------------------- */ 43 | /* Dummy Code */ 44 | #define OP_UNSPEC 0x00 45 | #define OP_REQ_UNSPEC OP_UNSPEC 46 | #define OP_REP_UNSPEC OP_UNSPEC 47 | 48 | /* ---------------------------------------------------------------------- */ 49 | /* Retrieve USB device information. (still not used) */ 50 | #define OP_DEVINFO 0x02 51 | #define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO) 52 | #define OP_REP_DEVINFO (OP_REPLY | OP_DEVINFO) 53 | 54 | #define USBIP_BUS_ID_SIZE 32 55 | #define USBIP_DEV_PATH_MAX 256 56 | 57 | 58 | struct op_devinfo_request { 59 | char busid[USBIP_BUS_ID_SIZE]; 60 | } __attribute__((packed)); 61 | 62 | enum usb_device_speed { 63 | USB_SPEED_UNKNOWN = 0, /* enumerating */ 64 | USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ 65 | USB_SPEED_HIGH, /* usb 2.0 */ 66 | USB_SPEED_VARIABLE /* wireless (usb 2.5) */ 67 | }; 68 | 69 | struct usb_device { 70 | char path[USBIP_DEV_PATH_MAX]; 71 | char busid[USBIP_BUS_ID_SIZE]; 72 | uint32_t busnum; 73 | uint32_t devnum; 74 | uint32_t speed; 75 | 76 | uint16_t idVendor; 77 | uint16_t idProduct; 78 | uint16_t bcdDevice; 79 | 80 | uint8_t bDeviceClass; 81 | uint8_t bDeviceSubClass; 82 | uint8_t bDeviceProtocol; 83 | uint8_t bConfigurationValue; 84 | uint8_t bNumConfigurations; 85 | uint8_t bNumInterfaces; 86 | } __attribute__((packed)); 87 | 88 | struct usb_interface { 89 | uint8_t bInterfaceClass; 90 | uint8_t bInterfaceSubClass; 91 | uint8_t bInterfaceProtocol; 92 | uint8_t padding; /* alignment */ 93 | } __attribute__((packed)); 94 | 95 | struct op_devinfo_reply { 96 | struct usb_device udev; 97 | struct usb_interface uinf[]; 98 | } __attribute__((packed)); 99 | 100 | 101 | /* ---------------------------------------------------------------------- */ 102 | /* Import a remote USB device. */ 103 | #define OP_IMPORT 0x03 104 | #define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT) 105 | #define OP_REP_IMPORT (OP_REPLY | OP_IMPORT) 106 | 107 | struct op_import_request { 108 | char busid[USBIP_BUS_ID_SIZE]; 109 | } __attribute__((packed)); 110 | 111 | struct op_import_reply { 112 | struct usb_device udev; 113 | // struct usb_interface uinf[]; 114 | } __attribute__((packed)); 115 | 116 | #define PACK_OP_IMPORT_REQUEST(pack, request) do {\ 117 | } while (0) 118 | 119 | #define PACK_OP_IMPORT_REPLY(pack, reply) do {\ 120 | pack_usb_device(pack, &(reply)->udev);\ 121 | } while (0) 122 | 123 | 124 | 125 | /* ---------------------------------------------------------------------- */ 126 | /* Export a USB device to a remote host. */ 127 | #define OP_EXPORT 0x06 128 | #define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT) 129 | #define OP_REP_EXPORT (OP_REPLY | OP_EXPORT) 130 | 131 | struct op_export_request { 132 | struct usb_device udev; 133 | } __attribute__((packed)); 134 | 135 | struct op_export_reply { 136 | int returncode; 137 | } __attribute__((packed)); 138 | 139 | 140 | #define PACK_OP_EXPORT_REQUEST(pack, request) do {\ 141 | pack_usb_device(pack, &(request)->udev);\ 142 | } while (0) 143 | 144 | #define PACK_OP_EXPORT_REPLY(pack, reply) do {\ 145 | } while (0) 146 | 147 | /* ---------------------------------------------------------------------- */ 148 | /* un-Export a USB device from a remote host. */ 149 | #define OP_UNEXPORT 0x07 150 | #define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT) 151 | #define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT) 152 | 153 | struct op_unexport_request { 154 | struct usb_device udev; 155 | } __attribute__((packed)); 156 | 157 | struct op_unexport_reply { 158 | int returncode; 159 | } __attribute__((packed)); 160 | 161 | #define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\ 162 | pack_usb_device(pack, &(request)->udev);\ 163 | } while (0) 164 | 165 | #define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\ 166 | } while (0) 167 | 168 | 169 | 170 | /* ---------------------------------------------------------------------- */ 171 | /* Negotiate IPSec encryption key. (still not used) */ 172 | #define OP_CRYPKEY 0x04 173 | #define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY) 174 | #define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY) 175 | 176 | struct op_crypkey_request { 177 | /* 128bit key */ 178 | uint32_t key[4]; 179 | } __attribute__((packed)); 180 | 181 | struct op_crypkey_reply { 182 | uint32_t _reserved; 183 | } __attribute__((packed)); 184 | 185 | 186 | /* ---------------------------------------------------------------------- */ 187 | /* Retrieve the list of exported USB devices. */ 188 | #define OP_DEVLIST 0x05 189 | #define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST) 190 | #define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST) 191 | 192 | struct op_devlist_request { 193 | uint32_t _reserved; 194 | } __attribute__((packed)); 195 | 196 | struct op_devlist_reply { 197 | uint32_t ndev; 198 | /* followed by reply_extra[] */ 199 | } __attribute__((packed)); 200 | 201 | struct op_devlist_reply_extra { 202 | struct usb_device udev; 203 | struct usb_interface uinf[]; 204 | } __attribute__((packed)); 205 | 206 | #define PACK_OP_DEVLIST_REQUEST(pack, request) do {\ 207 | } while (0) 208 | 209 | #define PACK_OP_DEVLIST_REPLY(pack, reply) do {\ 210 | pack_uint32_t(pack, &(reply)->ndev);\ 211 | } while (0) 212 | 213 | /* 214 | * A basic header followed by other additional headers. 215 | */ 216 | struct usbip_header_basic { 217 | #define USBIP_CMD_SUBMIT 0x0001 218 | #define USBIP_CMD_UNLINK 0x0002 219 | #define USBIP_RET_SUBMIT 0x0003 220 | #define USBIP_RET_UNLINK 0x0004 221 | #define USBIP_RESET_DEV 0xFFFF 222 | unsigned int command; 223 | 224 | /* sequencial number which identifies requests. 225 | * incremented per connections */ 226 | unsigned int seqnum; 227 | 228 | /* devid is used to specify a remote USB device uniquely instead 229 | * of busnum and devnum in Linux. In the case of Linux stub_driver, 230 | * this value is ((busnum << 16) | devnum) */ 231 | unsigned int devid; 232 | 233 | #define USBIP_DIR_OUT 0 234 | #define USBIP_DIR_IN 1 235 | unsigned int direction; 236 | unsigned int ep; /* endpoint number */ 237 | } __attribute__ ((packed)); 238 | 239 | /* 240 | * An additional header for a CMD_SUBMIT packet. 241 | */ 242 | struct usbip_header_cmd_submit { 243 | /* these values are basically the same as in a URB. */ 244 | 245 | /* the same in a URB. */ 246 | unsigned int transfer_flags; 247 | 248 | /* set the following data size (out), 249 | * or expected reading data size (in) */ 250 | int transfer_buffer_length; 251 | 252 | /* it is difficult for usbip to sync frames (reserved only?) */ 253 | int start_frame; 254 | 255 | /* the number of iso descriptors that follows this header */ 256 | int number_of_packets; 257 | 258 | /* the maximum time within which this request works in a host 259 | * controller of a server side */ 260 | int interval; 261 | 262 | /* set setup packet data for a CTRL request */ 263 | unsigned char setup[8]; 264 | }__attribute__ ((packed)); 265 | 266 | /* 267 | * An additional header for a RET_SUBMIT packet. 268 | */ 269 | struct usbip_header_ret_submit { 270 | int status; 271 | int actual_length; /* returned data length */ 272 | int start_frame; /* ISO and INT */ 273 | int number_of_packets; /* ISO only */ 274 | int error_count; /* ISO only */ 275 | }__attribute__ ((packed)); 276 | 277 | /* 278 | * An additional header for a CMD_UNLINK packet. 279 | */ 280 | struct usbip_header_cmd_unlink { 281 | unsigned int seqnum; /* URB's seqnum which will be unlinked */ 282 | }__attribute__ ((packed)); 283 | 284 | 285 | /* 286 | * An additional header for a RET_UNLINK packet. 287 | */ 288 | struct usbip_header_ret_unlink { 289 | int status; 290 | }__attribute__ ((packed)); 291 | 292 | 293 | /* the same as usb_iso_packet_descriptor but packed for pdu */ 294 | struct usbip_iso_packet_descriptor { 295 | unsigned int offset; 296 | unsigned int length; /* expected length */ 297 | unsigned int actual_length; 298 | unsigned int status; 299 | }__attribute__ ((packed)); 300 | 301 | 302 | /* 303 | * All usbip packets use a common header to keep code simple. 304 | */ 305 | struct usbip_header { 306 | struct usbip_header_basic base; 307 | 308 | union { 309 | struct usbip_header_cmd_submit cmd_submit; 310 | struct usbip_header_ret_submit ret_submit; 311 | struct usbip_header_cmd_unlink cmd_unlink; 312 | struct usbip_header_ret_unlink ret_unlink; 313 | } u; 314 | }__attribute__ ((packed)); 315 | 316 | 317 | 318 | 319 | /* -------------------------------------------------- */ 320 | /* Declare Prototype Function */ 321 | /* -------------------------------------------------- */ 322 | 323 | void pack_uint32_t(int pack, uint32_t *num); 324 | void pack_uint16_t(int pack, uint16_t *num); 325 | void pack_usb_device(int pack, struct usb_device *udev); 326 | void pack_usb_interface(int pack, struct usb_interface *uinf); 327 | 328 | #define USBIP_PORT 3240 329 | #define USBIP_PORT_STRING "3240" 330 | 331 | #pragma pack(pop) 332 | #endif 333 | -------------------------------------------------------------------------------- /userspace/AUTHORS: -------------------------------------------------------------------------------- 1 | Takahiro Hirofuchi 2 | Robert Leibl 3 | -------------------------------------------------------------------------------- /userspace/INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | 6. Often, you can also type `make uninstall' to remove the installed 71 | files again. 72 | 73 | Compilers and Options 74 | ===================== 75 | 76 | Some systems require unusual options for compilation or linking that the 77 | `configure' script does not know about. Run `./configure --help' for 78 | details on some of the pertinent environment variables. 79 | 80 | You can give `configure' initial values for configuration parameters 81 | by setting variables in the command line or in the environment. Here 82 | is an example: 83 | 84 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 85 | 86 | *Note Defining Variables::, for more details. 87 | 88 | Compiling For Multiple Architectures 89 | ==================================== 90 | 91 | You can compile the package for more than one kind of computer at the 92 | same time, by placing the object files for each architecture in their 93 | own directory. To do this, you can use GNU `make'. `cd' to the 94 | directory where you want the object files and executables to go and run 95 | the `configure' script. `configure' automatically checks for the 96 | source code in the directory that `configure' is in and in `..'. 97 | 98 | With a non-GNU `make', it is safer to compile the package for one 99 | architecture at a time in the source code directory. After you have 100 | installed the package for one architecture, use `make distclean' before 101 | reconfiguring for another architecture. 102 | 103 | Installation Names 104 | ================== 105 | 106 | By default, `make install' installs the package's commands under 107 | `/usr/local/bin', include files under `/usr/local/include', etc. You 108 | can specify an installation prefix other than `/usr/local' by giving 109 | `configure' the option `--prefix=PREFIX'. 110 | 111 | You can specify separate installation prefixes for 112 | architecture-specific files and architecture-independent files. If you 113 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 114 | PREFIX as the prefix for installing programs and libraries. 115 | Documentation and other data files still use the regular prefix. 116 | 117 | In addition, if you use an unusual directory layout you can give 118 | options like `--bindir=DIR' to specify different values for particular 119 | kinds of files. Run `configure --help' for a list of the directories 120 | you can set and what kinds of files go in them. 121 | 122 | If the package supports it, you can cause programs to be installed 123 | with an extra prefix or suffix on their names by giving `configure' the 124 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 125 | 126 | Optional Features 127 | ================= 128 | 129 | Some packages pay attention to `--enable-FEATURE' options to 130 | `configure', where FEATURE indicates an optional part of the package. 131 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 132 | is something like `gnu-as' or `x' (for the X Window System). The 133 | `README' should mention any `--enable-' and `--with-' options that the 134 | package recognizes. 135 | 136 | For packages that use the X Window System, `configure' can usually 137 | find the X include and library files automatically, but if it doesn't, 138 | you can use the `configure' options `--x-includes=DIR' and 139 | `--x-libraries=DIR' to specify their locations. 140 | 141 | Specifying the System Type 142 | ========================== 143 | 144 | There may be some features `configure' cannot figure out automatically, 145 | but needs to determine by the type of machine the package will run on. 146 | Usually, assuming the package is built to be run on the _same_ 147 | architectures, `configure' can figure that out, but if it prints a 148 | message saying it cannot guess the machine type, give it the 149 | `--build=TYPE' option. TYPE can either be a short name for the system 150 | type, such as `sun4', or a canonical name which has the form: 151 | 152 | CPU-COMPANY-SYSTEM 153 | 154 | where SYSTEM can have one of these forms: 155 | 156 | OS KERNEL-OS 157 | 158 | See the file `config.sub' for the possible values of each field. If 159 | `config.sub' isn't included in this package, then this package doesn't 160 | need to know the machine type. 161 | 162 | If you are _building_ compiler tools for cross-compiling, you should 163 | use the option `--target=TYPE' to select the type of system they will 164 | produce code for. 165 | 166 | If you want to _use_ a cross compiler, that generates code for a 167 | platform different from the build platform, you should specify the 168 | "host" platform (i.e., that on which the generated programs will 169 | eventually be run) with `--host=TYPE'. 170 | 171 | Sharing Defaults 172 | ================ 173 | 174 | If you want to set default values for `configure' scripts to share, you 175 | can create a site shell script called `config.site' that gives default 176 | values for variables like `CC', `cache_file', and `prefix'. 177 | `configure' looks for `PREFIX/share/config.site' if it exists, then 178 | `PREFIX/etc/config.site' if it exists. Or, you can set the 179 | `CONFIG_SITE' environment variable to the location of the site script. 180 | A warning: not all `configure' scripts look for a site script. 181 | 182 | Defining Variables 183 | ================== 184 | 185 | Variables not defined in a site shell script can be set in the 186 | environment passed to `configure'. However, some packages may run 187 | configure again during the build, and the customized values of these 188 | variables may be lost. In order to avoid this problem, you should set 189 | them in the `configure' command line, using `VAR=value'. For example: 190 | 191 | ./configure CC=/usr/local2/bin/gcc 192 | 193 | causes the specified `gcc' to be used as the C compiler (unless it is 194 | overridden in the site shell script). 195 | 196 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 197 | an Autoconf bug. Until the bug is fixed you can use this workaround: 198 | 199 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 200 | 201 | `configure' Invocation 202 | ====================== 203 | 204 | `configure' recognizes the following options to control how it operates. 205 | 206 | `--help' 207 | `-h' 208 | Print a summary of the options to `configure', and exit. 209 | 210 | `--version' 211 | `-V' 212 | Print the version of Autoconf used to generate the `configure' 213 | script, and exit. 214 | 215 | `--cache-file=FILE' 216 | Enable the cache: use and save the results of the tests in FILE, 217 | traditionally `config.cache'. FILE defaults to `/dev/null' to 218 | disable caching. 219 | 220 | `--config-cache' 221 | `-C' 222 | Alias for `--cache-file=config.cache'. 223 | 224 | `--quiet' 225 | `--silent' 226 | `-q' 227 | Do not print messages saying which checks are being made. To 228 | suppress all normal output, redirect it to `/dev/null' (any error 229 | messages will still be shown). 230 | 231 | `--srcdir=DIR' 232 | Look for the package's source code in directory DIR. Usually 233 | `configure' can determine that directory automatically. 234 | 235 | `configure' also accepts some other, not widely useful, options. Run 236 | `configure --help' for more details. 237 | 238 | -------------------------------------------------------------------------------- /userspace/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS := libsrc src 2 | includedir := @includedir@/usbip 3 | include_HEADERS := $(addprefix libsrc/, \ 4 | usbip.h usbip_common.h vhci_driver.h stub_driver.h) 5 | 6 | dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8 usbip_bind_driver.8) 7 | 8 | if INSTALL_USBIDS 9 | pkgdata_DATA := usb.ids 10 | EXTRA_DIST := $(pkgdata_DATA) 11 | endif 12 | -------------------------------------------------------------------------------- /userspace/README: -------------------------------------------------------------------------------- 1 | # vim:tw=78:ts=4:expandtab:ai:sw=4 2 | # 3 | # README for usbip-utils 4 | # 5 | # Copyright (C) 2005-2008 Takahiro Hirofuchi 6 | 7 | 8 | [Requirements] 9 | - USB/IP device drivers 10 | Its source code is included under $(top)/drivers/. 11 | 12 | - sysfsutils >= 2.0.0 13 | sysfsutils library 14 | 15 | - libwrap0-dev 16 | tcp wrapper library 17 | 18 | - gcc >= 4.0 19 | 20 | - libglib2.0-dev >= 2.6.0 21 | 22 | - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config 23 | 24 | [Install] 25 | 0. Skip here if you see a configure script. 26 | $ ./autogen.sh 27 | 28 | 1. Compile & install. 29 | $ ./configure 30 | $ make install 31 | 32 | 2. Compile & install USB/IP drivers if not yet. 33 | 34 | [Usage] 35 | server:# (Attach your USB device physically.) 36 | 37 | server:# insmod usbip-core.ko 38 | server:# insmod usbip-host.ko 39 | - It was formerly named as stub.ko. 40 | 41 | server:# usbipd -D 42 | - Start usbip daemon. 43 | 44 | server:# usbip_bind_driver --list 45 | - List driver assignments for usb devices. 46 | 47 | server:# usbip_bind_driver --usbip 1-2 48 | - Bind usbip-host.ko to the device of busid 1-2. 49 | - A usb device 1-2 is now exportable to other hosts! 50 | - Use 'usbip_bind_driver --other 1-2' when you want to shutdown exporting 51 | and use the device locally. 52 | 53 | 54 | client:# insmod usbip-core.ko 55 | client:# insmod vhci-hcd.ko 56 | - It was formerly named as vhci.ko. 57 | 58 | client:# usbip --list server 59 | - List exportable usb devices on the server. 60 | 61 | client:# usbip --attach server 1-2 62 | - Connect the remote USB device. 63 | 64 | client:# usbip --port 65 | - Show virtual port status. 66 | 67 | client:# usbip --detach 0 68 | - Detach the usb device. 69 | 70 | 71 | [Output Example] 72 | -------------------------------------------------------------------------------------------------------- 73 | - SERVER SIDE (physically attach your USB devices to this host) ---------------------------------------- 74 | -------------------------------------------------------------------------------------------------------- 75 | trois:# insmod (somewhere)/usbip-core.ko 76 | trois:# insmod (somewhere)/usbip-host.ko 77 | trois:# usbipd -D 78 | 79 | -------------------------------------------------------------------------------------------------------- 80 | In another terminal, let's look up what usb devices are physically attached to 81 | this host. We can see a usb storage device of busid 3-3.2 is now bound to 82 | usb-storage driver. To export this device, we first mark the device as 83 | "exportable"; the device is bound to usbip driver. Please remember you can not 84 | export a usb hub. 85 | 86 | trois:# usbip_bind_driver --list 87 | List USB devices 88 | - busid 3-3.2 (04bb:0206) 89 | 3-3.2:1.0 -> usb-storage 90 | 91 | - busid 3-3.1 (08bb:2702) 92 | 3-3.1:1.0 -> snd-usb-audio 93 | 3-3.1:1.1 -> snd-usb-audio 94 | 95 | - busid 3-3 (0409:0058) 96 | 3-3:1.0 -> hub 97 | 98 | - busid 3-2 (0711:0902) 99 | 3-2:1.0 -> none 100 | 101 | - busid 1-1 (05a9:a511) 102 | 1-1:1.0 -> ov511 103 | 104 | - busid 4-1 (046d:08b2) 105 | 4-1:1.0 -> none 106 | 4-1:1.1 -> none 107 | 4-1:1.2 -> none 108 | 109 | - busid 5-2 (058f:9254) 110 | 5-2:1.0 -> hub 111 | 112 | -------------------------------------------------------------------------------------------------------- 113 | Mark the device of busid 3-3.2 as exportable. 114 | 115 | trois:# usbip_bind_driver --usbip 3-3.2 116 | ** (process:24621): DEBUG: 3-3.2:1.0 -> none 117 | ** (process:24621): DEBUG: write "add 3-3.2" to /sys/bus/usb/drivers/usbip/match_busid 118 | ** Message: bind 3-3.2 to usbip, complete! 119 | 120 | trois:# usbip_bind_driver --list 121 | List USB devices 122 | - busid 3-3.2 (04bb:0206) 123 | 3-3.2:1.0 -> usbip 124 | (snip) 125 | 126 | Iterate the above operation for other devices if you like. 127 | 128 | 129 | -------------------------------------------------------------------------------------------------------- 130 | - CLIENT SIDE ------------------------------------------------------------------------------------------ 131 | -------------------------------------------------------------------------------------------------------- 132 | First, let's list available remote devices which are marked as exportable in 133 | the server host. 134 | 135 | deux:# insmod (somewhere)/usbip-core.ko 136 | deux:# insmod (somewhere)/vhci_hcd.ko 137 | 138 | deux:# usbip --list 10.0.0.3 139 | - 10.0.0.3 140 | 1-1: Prolific Technology, Inc. : unknown product (067b:3507) 141 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1 142 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 143 | : 0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50) 144 | 145 | 1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203) 146 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1 147 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 148 | : 0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01) 149 | 150 | 1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511) 151 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3 152 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 153 | : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00) 154 | 155 | 3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2) 156 | : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1 157 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 158 | : 0 - Data / unknown subclass / unknown protocol (0a/ff/00) 159 | : 1 - Audio / Control Device / unknown protocol (01/01/00) 160 | : 2 - Audio / Streaming / unknown protocol (01/02/00) 161 | 162 | 4-1: Logitech, Inc. : QuickCam Express (046d:0870) 163 | : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.1/usb4/4-1 164 | : Vendor Specific Class / Vendor Specific Subclass / Vendor Specific Protocol (ff/ff/ff) 165 | : 0 - Vendor Specific Class / Vendor Specific Subclass / Vendor Specific Protocol (ff/ff/ff) 166 | 167 | 4-2: Texas Instruments Japan : unknown product (08bb:2702) 168 | : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.1/usb4/4-2 169 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 170 | : 0 - Audio / Control Device / unknown protocol (01/01/00) 171 | : 1 - Audio / Streaming / unknown protocol (01/02/00) 172 | 173 | -------------------------------------------------------------------------------------------------------- 174 | Attach a remote usb device! 175 | 176 | deux:# usbip --attach 10.0.0.3 1-1 177 | port 0 attached 178 | 179 | -------------------------------------------------------------------------------------------------------- 180 | Show what devices are attached to this client. 181 | 182 | deux:# usbip --port 183 | Port 00: at Full Speed(12Mbps) 184 | Prolific Technology, Inc. : unknown product (067b:3507) 185 | 6-1 -> usbip://10.0.0.3:3240/1-1 (remote bus/dev 001/004) 186 | 6-1:1.0 used by usb-storage 187 | /sys/class/scsi_device/0:0:0:0/device 188 | /sys/class/scsi_host/host0/device 189 | /sys/block/sda/device 190 | 191 | -------------------------------------------------------------------------------------------------------- 192 | Detach the imported device. 193 | 194 | deux:# usbip --detach 0 195 | port 0 detached 196 | 197 | -------------------------------------------------------------------------------------------------------- 198 | 199 | 200 | [Check List] 201 | - See Debug Tips in the project wiki. 202 | - http://usbip.wiki.sourceforge.net/how-to-debug-usbip 203 | - usbip-host.ko must be bound to the target device. 204 | - See /proc/bus/usb/devices and find "Driver=..." lines of the device. 205 | - Shutdown firewall. 206 | - usbip now uses TCP port 3240. 207 | - Disable SELinux. 208 | - If possible, compile your kernel with CONFIG_USB_DEBUG flag and try 209 | again. 210 | - Check your kernel and daemon messages. 211 | ex. /var/log/{messages, kern.log, daemon.log, syslog} 212 | 213 | 214 | [Contact] 215 | Mailing List: usbip-devel _at_ lists.sourceforge.net 216 | -------------------------------------------------------------------------------- /userspace/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | #aclocal 4 | #autoheader 5 | #libtoolize --copy --force 6 | #automake-1.9 -acf 7 | #autoconf 8 | 9 | autoreconf -i -f -v 10 | -------------------------------------------------------------------------------- /userspace/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | 4 | if [ -r Makefile ]; then 5 | make distclean 6 | fi 7 | 8 | FILES="configure cscope.out Makefile.in depcomp compile config.guess config.sub config.h.in~ config.log config.status ltmain.sh libtool config.h.in autom4te.cache missing aclocal.m4 install-sh cmd/Makefile.in lib/Makefile.in Makefile lib/Makefile cmd/Makefile" 9 | 10 | rm -Rf $FILES 11 | -------------------------------------------------------------------------------- /userspace/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define to 1 if you have the header file. */ 5 | #define HAVE_ARPA_INET_H 1 6 | 7 | /* Define to 1 if you have the `bzero' function. */ 8 | #define HAVE_BZERO 1 9 | 10 | /* Define to 1 if you have the header file, and it defines `DIR'. 11 | */ 12 | #define HAVE_DIRENT_H 1 13 | 14 | /* Define to 1 if you have the header file. */ 15 | #define HAVE_DLFCN_H 1 16 | 17 | /* Define to 1 if you have the `dnl' function. */ 18 | /* #undef HAVE_DNL */ 19 | 20 | /* Define to 1 if you have the header file. */ 21 | #define HAVE_FCNTL_H 1 22 | 23 | /* Define to 1 if you have the header file. */ 24 | #define HAVE_INTTYPES_H 1 25 | 26 | /* use tcp wrapper */ 27 | /* #undef HAVE_LIBWRAP */ 28 | 29 | /* Define to 1 if you have the header file. */ 30 | #define HAVE_MEMORY_H 1 31 | 32 | /* Define to 1 if you have the `memset' function. */ 33 | #define HAVE_MEMSET 1 34 | 35 | /* Define to 1 if you have the `mkdir' function. */ 36 | #define HAVE_MKDIR 1 37 | 38 | /* Define to 1 if you have the header file, and it defines `DIR'. */ 39 | /* #undef HAVE_NDIR_H */ 40 | 41 | /* Define to 1 if you have the header file. */ 42 | #define HAVE_NETDB_H 1 43 | 44 | /* Define to 1 if you have the header file. */ 45 | #define HAVE_NETINET_IN_H 1 46 | 47 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 48 | and to 0 otherwise. */ 49 | #define HAVE_REALLOC 1 50 | 51 | /* Define to 1 if you have the `regcomp' function. */ 52 | #define HAVE_REGCOMP 1 53 | 54 | /* Define to 1 if you have the `socket' function. */ 55 | #define HAVE_SOCKET 1 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #define HAVE_STDINT_H 1 59 | 60 | /* Define to 1 if you have the header file. */ 61 | #define HAVE_STDLIB_H 1 62 | 63 | /* Define to 1 if you have the `strchr' function. */ 64 | #define HAVE_STRCHR 1 65 | 66 | /* Define to 1 if you have the `strerror' function. */ 67 | #define HAVE_STRERROR 1 68 | 69 | /* Define to 1 if you have the header file. */ 70 | #define HAVE_STRINGS_H 1 71 | 72 | /* Define to 1 if you have the header file. */ 73 | #define HAVE_STRING_H 1 74 | 75 | /* Define to 1 if you have the `strstr' function. */ 76 | #define HAVE_STRSTR 1 77 | 78 | /* Define to 1 if you have the `strtoul' function. */ 79 | #define HAVE_STRTOUL 1 80 | 81 | /* Define to 1 if you have the header file. */ 82 | #define HAVE_SYSLOG_H 1 83 | 84 | /* Define to 1 if you have the header file, and it defines `DIR'. 85 | */ 86 | /* #undef HAVE_SYS_DIR_H */ 87 | 88 | /* Define to 1 if you have the header file, and it defines `DIR'. 89 | */ 90 | /* #undef HAVE_SYS_NDIR_H */ 91 | 92 | /* Define to 1 if you have the header file. */ 93 | #define HAVE_SYS_SOCKET_H 1 94 | 95 | /* Define to 1 if you have the header file. */ 96 | #define HAVE_SYS_STAT_H 1 97 | 98 | /* Define to 1 if you have the header file. */ 99 | #define HAVE_SYS_TYPES_H 1 100 | 101 | /* Define to 1 if you have the header file. */ 102 | #define HAVE_UNISTD_H 1 103 | 104 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 105 | */ 106 | #define LT_OBJDIR ".libs/" 107 | 108 | /* Name of package */ 109 | #define PACKAGE "usbip" 110 | 111 | /* Define to the address where bug reports for this package should be sent. */ 112 | #define PACKAGE_BUGREPORT "usbip-devel@lists.sourceforge.net" 113 | 114 | /* Define to the full name of this package. */ 115 | #define PACKAGE_NAME "usbip" 116 | 117 | /* Define to the full name and version of this package. */ 118 | #define PACKAGE_STRING "usbip 0.2.0" 119 | 120 | /* Define to the one symbol short name of this package. */ 121 | #define PACKAGE_TARNAME "usbip" 122 | 123 | /* Define to the home page for this package. */ 124 | #define PACKAGE_URL "" 125 | 126 | /* Define to the version of this package. */ 127 | #define PACKAGE_VERSION "0.2.0" 128 | 129 | /* Define to 1 if you have the ANSI C header files. */ 130 | #define STDC_HEADERS 1 131 | 132 | /* numeric version number */ 133 | #define USBIP_VERSION 0x000111 134 | 135 | /* Version number of package */ 136 | #define VERSION "0.2.0" 137 | 138 | /* Define for Solaris 2.5.1 so the uint32_t typedef from , 139 | , or is not used. If the typedef were allowed, the 140 | #define below would cause a syntax error. */ 141 | /* #undef _UINT32_T */ 142 | 143 | /* Define for Solaris 2.5.1 so the uint8_t typedef from , 144 | , or is not used. If the typedef were allowed, the 145 | #define below would cause a syntax error. */ 146 | /* #undef _UINT8_T */ 147 | 148 | /* Define to the type of a signed integer type of width exactly 32 bits if 149 | such a type exists and the standard includes do not define it. */ 150 | /* #undef int32_t */ 151 | 152 | /* Define to rpl_realloc if the replacement function should be used. */ 153 | /* #undef realloc */ 154 | 155 | /* Define to `unsigned int' if does not define. */ 156 | /* #undef size_t */ 157 | 158 | /* Define to `int' if does not define. */ 159 | /* #undef ssize_t */ 160 | 161 | /* Define to the type of an unsigned integer type of width exactly 16 bits if 162 | such a type exists and the standard includes do not define it. */ 163 | /* #undef uint16_t */ 164 | 165 | /* Define to the type of an unsigned integer type of width exactly 32 bits if 166 | such a type exists and the standard includes do not define it. */ 167 | /* #undef uint32_t */ 168 | 169 | /* Define to the type of an unsigned integer type of width exactly 8 bits if 170 | such a type exists and the standard includes do not define it. */ 171 | /* #undef uint8_t */ 172 | -------------------------------------------------------------------------------- /userspace/configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | 3 | AC_PREREQ(2.59) 4 | AC_INIT([usbip], [0.2.0], [usbip-devel@lists.sourceforge.net]) 5 | AC_DEFINE([USBIP_VERSION], [0x000106], [numeric version number]) 6 | 7 | CURRENT=0 8 | REVISION=1 9 | AGE=0 10 | AC_SUBST([LIBUSBIP_VERSION], [$CURRENT:$REVISION:$AGE], [library version]) 11 | 12 | AC_CONFIG_SRCDIR([src/usbipd.c]) 13 | AC_CONFIG_HEADERS([config.h]) 14 | 15 | AM_INIT_AUTOMAKE([foreign]) 16 | LT_INIT 17 | 18 | # Silent build for automake >= 1.11 19 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 20 | 21 | AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu89"]) 22 | 23 | # Checks for programs. 24 | AC_PROG_CC 25 | AC_PROG_INSTALL 26 | AC_PROG_MAKE_SET 27 | 28 | # Checks for header files. 29 | AC_HEADER_DIRENT 30 | AC_HEADER_STDC 31 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl 32 | string.h strings.h sys/socket.h syslog.h unistd.h]) 33 | 34 | # Checks for typedefs, structures, and compiler characteristics. 35 | AC_TYPE_INT32_T 36 | AC_TYPE_SIZE_T 37 | AC_TYPE_SSIZE_T 38 | AC_TYPE_UINT16_T 39 | AC_TYPE_UINT32_T 40 | AC_TYPE_UINT8_T 41 | 42 | # Checks for library functions. 43 | AC_FUNC_REALLOC 44 | AC_CHECK_FUNCS([bzero memset mkdir regcomp socket strchr strerror strstr dnl 45 | strtoul]) 46 | 47 | AC_CHECK_HEADER([sysfs/libsysfs.h], 48 | [AC_CHECK_LIB([sysfs], [sysfs_open_directory_list], 49 | [LIBS="$LIBS -lsysfs"], 50 | [AC_MSG_ERROR([Missing sysfs2 library!])])], 51 | [AC_MSG_ERROR([Missing /usr/include/sysfs/libsysfs.h])]) 52 | 53 | # Checks for libwrap library. 54 | AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library]) 55 | AC_ARG_WITH([tcp-wrappers], 56 | [AS_HELP_STRING([--with-tcp-wrappers], 57 | [use the libwrap (TCP wrappers) library])], 58 | dnl [ACTION-IF-GIVEN] 59 | [saved_LIBS="$LIBS" 60 | if test "$withval" = "yes"; then 61 | AC_MSG_RESULT([yes]) 62 | AC_MSG_CHECKING([for hosts_access in -lwrap]) 63 | LIBS="-lwrap $LIBS" 64 | AC_TRY_LINK( 65 | [int hosts_access(); int allow_severity, deny_severity;], 66 | [hosts_access()], 67 | [AC_MSG_RESULT([yes]); 68 | AC_DEFINE([HAVE_LIBWRAP], [1], 69 | [use tcp wrapper]) wrap_LIB="-lwrap"], 70 | [AC_MSG_RESULT([not found]); exit 1]) 71 | else 72 | AC_MSG_RESULT([no]) 73 | fi 74 | LIBS="$saved_LIBS"], 75 | dnl [ACTION-IF-NOT-GIVEN] 76 | [AC_MSG_RESULT([(default)]) 77 | AC_MSG_CHECKING([for hosts_access in -lwrap]) 78 | saved_LIBS="$LIBS" 79 | LIBS="-lwrap $saved_LIBS" 80 | AC_TRY_LINK( 81 | [int hosts_access(); int allow_severity, deny_severity;], 82 | [hosts_access()], 83 | [AC_MSG_RESULT([yes]); 84 | AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])], 85 | [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])]) 86 | 87 | # Sets directory containing usb.ids. 88 | USBIDS_DIR='${datadir}/usbip' 89 | AC_ARG_WITH([usbids-dir], 90 | [AS_HELP_STRING([--with-usbids-dir=DIR], 91 | [where usb.ids is found (default ${datadir}/usbip)])], 92 | [USBIDS_DIR=$withval]) 93 | AC_SUBST([USBIDS_DIR]) 94 | 95 | dnl FIXME: when disabled, empty directry is created 96 | usbids=install 97 | AC_ARG_ENABLE([usbids-install], 98 | [AS_HELP_STRING([--enable-usbids-install], 99 | [install usb.ids (default)])], 100 | [AS_CASE([$enableval], 101 | [yes], [usbids=install], 102 | [no], [usbids=notinstall], 103 | [AC_MSG_ERROR( 104 | [bad value ${enableval} for --enable-usbids-install])] 105 | )]) 106 | AM_CONDITIONAL([INSTALL_USBIDS], [test x$usbids = xinstall]) 107 | 108 | GLIB2_REQUIRED=2.6.0 109 | PKG_CHECK_MODULES([PACKAGE], [glib-2.0 >= $GLIB2_REQUIRED]) 110 | AC_SUBST([PACKAGE_CFLAGS]) 111 | AC_SUBST([PACKAGE_LIBS]) 112 | 113 | AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile]) 114 | AC_OUTPUT 115 | -------------------------------------------------------------------------------- /userspace/doc/usbip.8: -------------------------------------------------------------------------------- 1 | .TH USBIP "8" "February 2009" "usbip" "System Administration Utilities" 2 | .SH NAME 3 | usbip \- manage USB/IP devices 4 | .SH SYNOPSIS 5 | .B usbip 6 | [\fIoptions\fR] 7 | 8 | .SH DESCRIPTION 9 | Devices exported by USB/IP servers can be listed, attached and 10 | detached using this program. 11 | 12 | .SH OPTIONS 13 | .HP 14 | \fB\-a\fR, \fB\-\-attach\fR 15 | .IP 16 | Attach a remote USB device. 17 | .PP 18 | 19 | .HP 20 | \fB\-x\fR, \fB\-\-attachall\fR 21 | .IP 22 | Attach all remote USB devices on the specific host. 23 | .PP 24 | 25 | .HP 26 | \fB\-d\fR, \fB\-\-detach\fR 27 | .IP 28 | Detach an imported USB device. 29 | .PP 30 | 31 | .HP 32 | \fB\-l\fR, \fB\-\-list\fR 33 | .IP 34 | List exported USB devices. 35 | .PP 36 | 37 | .HP 38 | \fB\-p\fR, \fB\-\-port\fR 39 | .IP 40 | List virtual USB port status. 41 | .PP 42 | 43 | .HP 44 | \fB\-D\fR, \fB\-\-debug\fR 45 | .IP 46 | Print debugging information. 47 | .PP 48 | 49 | .HP 50 | \fB\-v\fR, \fB\-\-version\fR 51 | .IP 52 | Show version. 53 | .PP 54 | 55 | .SH EXAMPLES 56 | 57 | client:# usbip --list server 58 | - List exportable usb devices on the server. 59 | 60 | client:# usbip --attach server 1-2 61 | - Connect the remote USB device. 62 | 63 | client:# usbip --port 64 | - Show virtual port status. 65 | 66 | client:# usbip --detach 0 67 | - Detach the usb device. 68 | 69 | .SH "SEE ALSO" 70 | \fBusbipd\fP\fB(8)\fB\fP, 71 | \fBusbip_attach_driver\fP\fB(8)\fB\fP 72 | -------------------------------------------------------------------------------- /userspace/doc/usbip_bind_driver.8: -------------------------------------------------------------------------------- 1 | .TH USBIP_BIND_DRIVER "8" "February 2009" "usbip" "System Administration Utilities" 2 | .SH NAME 3 | usbip_bind_driver \- change driver binding for USB/IP 4 | 5 | .SH SYNOPSIS 6 | .B usbip_bind_driver 7 | [\fIoptions\fR] 8 | 9 | .SH DESCRIPTION 10 | Driver bindings for USB devices can be changed using 11 | this program. It is used to export and unexport USB 12 | devices over USB/IP. 13 | 14 | .SH OPTIONS 15 | .TP 16 | \fB\-u\fR, \fB\-\-usbip\fR 17 | Make a device exportable 18 | .TP 19 | \fB\-o\fR, \fB\-\-other\fR 20 | Use a device by a local driver 21 | .TP 22 | \fB\-l\fR, \fB\-\-list\fR 23 | Print usb devices and their drivers 24 | .TP 25 | \fB\-L\fR, \fB\-\-list2\fR 26 | Print usb devices and their drivers in parseable mode 27 | 28 | .SH EXAMPLES 29 | 30 | server:# usbip_bind_driver --list 31 | - List driver assignments for usb devices. 32 | 33 | server:# usbip_bind_driver --usbip 1-2 34 | - Bind usbip-host.ko to the device of busid 1-2. 35 | - A usb device 1-2 is now exportable to other hosts! 36 | 37 | server:# usbip_bind_driver --other 1-2 38 | - Shutdown exporting and use the device locally. 39 | 40 | .SH "SEE ALSO" 41 | \fBusbip\fP\fB(8)\fB\fP, 42 | \fBusbipd\fP\fB(8)\fB\fP 43 | -------------------------------------------------------------------------------- /userspace/doc/usbipd.8: -------------------------------------------------------------------------------- 1 | .TH USBIP "8" "February 2009" "usbip" "System Administration Utilities" 2 | .SH NAME 3 | usbipd \- USB/IP server daemon 4 | .SH SYNOPSIS 5 | .B usbipd 6 | [\fIoptions\fR] 7 | 8 | .SH DESCRIPTION 9 | .B usbipd 10 | provides USB/IP clients access to exported USB devices. 11 | 12 | Devices have to explicitly be exported using 13 | .B usbip_bind_driver 14 | before usbipd makes them available to other hosts. 15 | 16 | The daemon accepts connections from USB/IP clients 17 | on TCP port 3240. 18 | 19 | .SH OPTIONS 20 | .HP 21 | \fB\-D\fR, \fB\-\-daemon\fR 22 | .IP 23 | Run as a daemon process. 24 | .PP 25 | 26 | .HP 27 | \fB\-d\fR, \fB\-\-debug\fR 28 | .IP 29 | Print debugging information. 30 | .PP 31 | 32 | .HP 33 | \fB\-v\fR, \fB\-\-version\fR 34 | .IP 35 | Show version. 36 | .PP 37 | 38 | .SH LIMITATIONS 39 | 40 | .B usbipd 41 | offers no authentication or authorization for USB/IP. Any 42 | USB/IP client can connect and use exported devices. 43 | 44 | .SH EXAMPLES 45 | 46 | server:# modprobe usbip 47 | 48 | server:# usbipd -D 49 | - Start usbip daemon. 50 | 51 | server:# usbip_bind_driver --list 52 | - List driver assignments for usb devices. 53 | 54 | server:# usbip_bind_driver --usbip 1-2 55 | - Bind usbip-host.ko to the device of busid 1-2. 56 | - A usb device 1-2 is now exportable to other hosts! 57 | - Use 'usbip_bind_driver --other 1-2' when you want to shutdown exporting and use the device locally. 58 | 59 | .SH "SEE ALSO" 60 | \fBusbip\fP\fB(8)\fB\fP, 61 | \fBusbip_attach_driver\fP\fB(8)\fB\fP 62 | 63 | -------------------------------------------------------------------------------- /userspace/libsrc/Makefile.am: -------------------------------------------------------------------------------- 1 | libusbip_la_CPPFLAGS := -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' 2 | libusbip_la_CFLAGS := @EXTRA_CFLAGS@ 3 | libusbip_la_LDFLAGS := -version-info @LIBUSBIP_VERSION@ 4 | 5 | lib_LTLIBRARIES := libusbip.la 6 | libusbip_la_SOURCES := names.c names.h stub_driver.c stub_driver.h usbip.h \ 7 | usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h 8 | -------------------------------------------------------------------------------- /userspace/libsrc/names.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * names.h -- USB name database manipulation routines 5 | * 6 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | * 23 | */ 24 | 25 | /* 26 | * Copyright (C) 2005 Takahiro Hirofuchi 27 | * - names_free() is added. 28 | */ 29 | 30 | /*****************************************************************************/ 31 | 32 | #ifndef _NAMES_H 33 | #define _NAMES_H 34 | 35 | #include 36 | 37 | /* ---------------------------------------------------------------------- */ 38 | 39 | extern const char *names_vendor(u_int16_t vendorid); 40 | extern const char *names_product(u_int16_t vendorid, u_int16_t productid); 41 | extern const char *names_class(u_int8_t classid); 42 | extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid); 43 | extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid); 44 | extern const char *names_audioterminal(u_int16_t termt); 45 | extern const char *names_hid(u_int8_t hidd); 46 | extern const char *names_reporttag(u_int8_t rt); 47 | extern const char *names_huts(unsigned int data); 48 | extern const char *names_hutus(unsigned int data); 49 | extern const char *names_langid(u_int16_t langid); 50 | extern const char *names_physdes(u_int8_t ph); 51 | extern const char *names_bias(u_int8_t b); 52 | extern const char *names_countrycode(unsigned int countrycode); 53 | extern int names_init(char *n); 54 | extern void names_free(void); 55 | 56 | /* ---------------------------------------------------------------------- */ 57 | #endif /* _NAMES_H */ 58 | -------------------------------------------------------------------------------- /userspace/libsrc/stub_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #include "usbip.h" 6 | 7 | /* kernel module name */ 8 | static const char *usbip_stub_driver_name = "usbip-host"; 9 | 10 | 11 | struct usbip_stub_driver *stub_driver; 12 | 13 | static struct sysfs_driver *open_sysfs_stub_driver(void) 14 | { 15 | int ret; 16 | 17 | char sysfs_mntpath[SYSFS_PATH_MAX]; 18 | char stub_driver_path[SYSFS_PATH_MAX]; 19 | struct sysfs_driver *stub_driver; 20 | 21 | 22 | ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); 23 | if (ret < 0) { 24 | err("sysfs must be mounted"); 25 | return NULL; 26 | } 27 | 28 | snprintf(stub_driver_path, SYSFS_PATH_MAX, "%s/%s/usb/%s/%s", 29 | sysfs_mntpath, SYSFS_BUS_NAME, SYSFS_DRIVERS_NAME, 30 | usbip_stub_driver_name); 31 | 32 | stub_driver = sysfs_open_driver_path(stub_driver_path); 33 | if (!stub_driver) { 34 | err("usbip-core.ko and usbip-host.ko must be loaded"); 35 | return NULL; 36 | } 37 | 38 | return stub_driver; 39 | } 40 | 41 | 42 | #define SYSFS_OPEN_RETRIES 100 43 | 44 | /* only the first interface value is true! */ 45 | static int32_t read_attr_usbip_status(struct usb_device *udev) 46 | { 47 | char attrpath[SYSFS_PATH_MAX]; 48 | struct sysfs_attribute *attr; 49 | int value = 0; 50 | int ret; 51 | struct stat s; 52 | int retries = SYSFS_OPEN_RETRIES; 53 | 54 | /* This access is racy! 55 | * 56 | * Just after detach, our driver removes the sysfs 57 | * files and recreates them. 58 | * 59 | * We may try and fail to open the usbip_status of 60 | * an exported device in the (short) window where 61 | * it has been removed and not yet recreated. 62 | * 63 | * This is a bug in the interface. Nothing we can do 64 | * except work around it here by polling for the sysfs 65 | * usbip_status to reappear. 66 | */ 67 | 68 | snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status", 69 | udev->path, udev->busid, 70 | udev->bConfigurationValue, 71 | 0); 72 | 73 | while (retries > 0) { 74 | if (stat(attrpath, &s) == 0) 75 | break; 76 | 77 | if (errno != ENOENT) { 78 | err("error stat'ing %s", attrpath); 79 | return -1; 80 | } 81 | 82 | usleep(10000); /* 10ms */ 83 | retries--; 84 | } 85 | 86 | if (retries == 0) 87 | err("usbip_status not ready after %d retries", 88 | SYSFS_OPEN_RETRIES); 89 | else if (retries < SYSFS_OPEN_RETRIES) 90 | info("warning: usbip_status ready after %d retries", 91 | SYSFS_OPEN_RETRIES - retries); 92 | 93 | attr = sysfs_open_attribute(attrpath); 94 | if (!attr) { 95 | err("open %s", attrpath); 96 | return -1; 97 | } 98 | 99 | ret = sysfs_read_attribute(attr); 100 | if (ret) { 101 | err("read %s", attrpath); 102 | sysfs_close_attribute(attr); 103 | return -1; 104 | } 105 | 106 | value = atoi(attr->value); 107 | 108 | sysfs_close_attribute(attr); 109 | 110 | return value; 111 | } 112 | 113 | 114 | static void usbip_exported_device_delete(void *dev) 115 | { 116 | struct usbip_exported_device *edev = 117 | (struct usbip_exported_device *) dev; 118 | 119 | sysfs_close_device(edev->sudev); 120 | free(dev); 121 | } 122 | 123 | 124 | static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) 125 | { 126 | struct usbip_exported_device *edev = NULL; 127 | int i; 128 | 129 | edev = (struct usbip_exported_device *) calloc(1, sizeof(*edev)); 130 | if (!edev) { 131 | err("alloc device"); 132 | return NULL; 133 | } 134 | 135 | edev->sudev = sysfs_open_device_path(sdevpath); 136 | if (!edev->sudev) { 137 | err("open %s", sdevpath); 138 | goto err; 139 | } 140 | 141 | read_usb_device(edev->sudev, &edev->udev); 142 | 143 | edev->status = read_attr_usbip_status(&edev->udev); 144 | if (edev->status < 0) 145 | goto err; 146 | 147 | /* reallocate buffer to include usb interface data */ 148 | size_t size = sizeof(*edev) + edev->udev.bNumInterfaces * sizeof(struct usb_interface); 149 | edev = (struct usbip_exported_device *) realloc(edev, size); 150 | if (!edev) { 151 | err("alloc device"); 152 | goto err; 153 | } 154 | 155 | for (i=0; i < edev->udev.bNumInterfaces; i++) 156 | read_usb_interface(&edev->udev, i, &edev->uinf[i]); 157 | 158 | return edev; 159 | 160 | err: 161 | if (edev && edev->sudev) 162 | sysfs_close_device(edev->sudev); 163 | if (edev) 164 | free(edev); 165 | return NULL; 166 | } 167 | 168 | 169 | static int check_new(struct dlist *dlist, struct sysfs_device *target) 170 | { 171 | struct sysfs_device *dev; 172 | 173 | dlist_for_each_data(dlist, dev, struct sysfs_device) { 174 | if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE)) 175 | /* found. not new */ 176 | return 0; 177 | } 178 | 179 | return 1; 180 | } 181 | 182 | static void delete_nothing(void * dev) 183 | { 184 | UNUSED(dev); 185 | /* do not delete anything. but, its container will be deleted. */ 186 | } 187 | 188 | static int refresh_exported_devices(void) 189 | { 190 | struct sysfs_device *suinf; /* sysfs_device of usb_interface */ 191 | struct dlist *suinf_list; 192 | 193 | struct sysfs_device *sudev; /* sysfs_device of usb_device */ 194 | struct dlist *sudev_list; 195 | 196 | 197 | sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), delete_nothing); 198 | 199 | suinf_list = sysfs_get_driver_devices(stub_driver->sysfs_driver); 200 | if (!suinf_list) { 201 | printf("Bind usbip-host.ko to a usb device to be exportable!\n"); 202 | goto bye; 203 | } 204 | 205 | /* collect unique USB devices (not interfaces) */ 206 | dlist_for_each_data(suinf_list, suinf, struct sysfs_device) { 207 | 208 | /* get usb device of this usb interface */ 209 | sudev = sysfs_get_device_parent(suinf); 210 | if (!sudev) { 211 | err("get parent dev of %s", suinf->name); 212 | continue; 213 | } 214 | 215 | if (check_new(sudev_list, sudev)) { 216 | dlist_unshift(sudev_list, sudev); 217 | } 218 | } 219 | 220 | dlist_for_each_data(sudev_list, sudev, struct sysfs_device) { 221 | struct usbip_exported_device *edev; 222 | 223 | edev = usbip_exported_device_new(sudev->path); 224 | if (!edev) { 225 | err("usbip_exported_device new"); 226 | continue; 227 | } 228 | 229 | dlist_unshift(stub_driver->edev_list, (void *) edev); 230 | stub_driver->ndevs++; 231 | } 232 | 233 | 234 | dlist_destroy(sudev_list); 235 | 236 | bye: 237 | 238 | return 0; 239 | } 240 | 241 | int usbip_stub_refresh_device_list(void) 242 | { 243 | int ret; 244 | 245 | if (stub_driver->edev_list) 246 | dlist_destroy(stub_driver->edev_list); 247 | 248 | stub_driver->ndevs = 0; 249 | 250 | stub_driver->edev_list = dlist_new_with_delete(sizeof(struct usbip_exported_device), 251 | usbip_exported_device_delete); 252 | if (!stub_driver->edev_list) { 253 | err("alloc dlist"); 254 | return -1; 255 | } 256 | 257 | ret = refresh_exported_devices(); 258 | if (ret < 0) 259 | return ret; 260 | 261 | return 0; 262 | } 263 | 264 | int usbip_stub_driver_open(void) 265 | { 266 | int ret; 267 | 268 | 269 | stub_driver = (struct usbip_stub_driver *) calloc(1, sizeof(*stub_driver)); 270 | if (!stub_driver) { 271 | err("alloc stub_driver"); 272 | return -1; 273 | } 274 | 275 | stub_driver->ndevs = 0; 276 | 277 | stub_driver->edev_list = dlist_new_with_delete(sizeof(struct usbip_exported_device), 278 | usbip_exported_device_delete); 279 | if (!stub_driver->edev_list) { 280 | err("alloc dlist"); 281 | goto err; 282 | } 283 | 284 | stub_driver->sysfs_driver = open_sysfs_stub_driver(); 285 | if (!stub_driver->sysfs_driver) 286 | goto err; 287 | 288 | ret = refresh_exported_devices(); 289 | if (ret < 0) 290 | goto err; 291 | 292 | return 0; 293 | 294 | 295 | err: 296 | if (stub_driver->sysfs_driver) 297 | sysfs_close_driver(stub_driver->sysfs_driver); 298 | if (stub_driver->edev_list) 299 | dlist_destroy(stub_driver->edev_list); 300 | free(stub_driver); 301 | 302 | stub_driver = NULL; 303 | return -1; 304 | } 305 | 306 | 307 | void usbip_stub_driver_close(void) 308 | { 309 | if (!stub_driver) 310 | return; 311 | 312 | if (stub_driver->edev_list) 313 | dlist_destroy(stub_driver->edev_list); 314 | if (stub_driver->sysfs_driver) 315 | sysfs_close_driver(stub_driver->sysfs_driver); 316 | free(stub_driver); 317 | 318 | stub_driver = NULL; 319 | } 320 | 321 | int usbip_stub_export_device(struct usbip_exported_device *edev, int sockfd) 322 | { 323 | char attrpath[SYSFS_PATH_MAX]; 324 | struct sysfs_attribute *attr; 325 | char sockfd_buff[30]; 326 | int ret; 327 | 328 | 329 | if (edev->status != SDEV_ST_AVAILABLE) { 330 | info("device not available, %s", edev->udev.busid); 331 | switch( edev->status ) { 332 | case SDEV_ST_ERROR: 333 | info(" status SDEV_ST_ERROR"); 334 | break; 335 | case SDEV_ST_USED: 336 | info(" status SDEV_ST_USED"); 337 | break; 338 | default: 339 | info(" status unknown: 0x%x", edev->status); 340 | } 341 | return -1; 342 | } 343 | 344 | /* only the first interface is true */ 345 | snprintf(attrpath, sizeof(attrpath), "%s/%s:%d.%d/%s", 346 | edev->udev.path, 347 | edev->udev.busid, 348 | edev->udev.bConfigurationValue, 0, 349 | "usbip_sockfd"); 350 | 351 | attr = sysfs_open_attribute(attrpath); 352 | if (!attr) { 353 | err("open %s", attrpath); 354 | return -1; 355 | } 356 | 357 | snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); 358 | 359 | dbg("write: %s", sockfd_buff); 360 | 361 | ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff)); 362 | if (ret < 0) { 363 | err("write sockfd %s to %s", sockfd_buff, attrpath); 364 | goto err_write_sockfd; 365 | } 366 | 367 | info("connect %s", edev->udev.busid); 368 | 369 | err_write_sockfd: 370 | sysfs_close_attribute(attr); 371 | 372 | return ret; 373 | } 374 | 375 | struct usbip_exported_device *usbip_stub_get_device(int num) 376 | { 377 | struct usbip_exported_device *edev; 378 | struct dlist *dlist = stub_driver->edev_list; 379 | int count = 0; 380 | 381 | dlist_for_each_data(dlist, edev, struct usbip_exported_device) { 382 | if (num == count) 383 | return edev; 384 | else 385 | count++ ; 386 | } 387 | 388 | return NULL; 389 | } 390 | -------------------------------------------------------------------------------- /userspace/libsrc/stub_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef _USBIP_STUB_DRIVER_H 6 | #define _USBIP_STUB_DRIVER_H 7 | 8 | #include "usbip.h" 9 | 10 | 11 | struct usbip_stub_driver { 12 | int ndevs; 13 | struct sysfs_driver *sysfs_driver; 14 | 15 | struct dlist *edev_list; /* list of exported device */ 16 | }; 17 | 18 | struct usbip_exported_device { 19 | struct sysfs_device *sudev; 20 | 21 | int32_t status; 22 | struct usb_device udev; 23 | struct usb_interface uinf[]; 24 | }; 25 | 26 | 27 | extern struct usbip_stub_driver *stub_driver; 28 | 29 | int usbip_stub_driver_open(void); 30 | void usbip_stub_driver_close(void); 31 | 32 | int usbip_stub_refresh_device_list(void); 33 | int usbip_stub_export_device(struct usbip_exported_device *edev, int sockfd); 34 | 35 | struct usbip_exported_device *usbip_stub_get_device(int num); 36 | #endif 37 | -------------------------------------------------------------------------------- /userspace/libsrc/usbip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef _USBIP_H 6 | #define _USBIP_H 7 | 8 | #include "../config.h" 9 | 10 | #define _CRT_SECURE_NO_WARNINGS 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define UNUSED(x) (void)(x) 20 | 21 | #ifdef __linux__ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | 38 | #define closesocket close 39 | 40 | #else 41 | 42 | #define USBIDS_FILE "usb.ids" 43 | 44 | #include 45 | #include 46 | #include 47 | 48 | typedef unsigned int u_int16_t; 49 | typedef unsigned char u_int8_t; 50 | typedef signed int ssize_t; 51 | 52 | #define SYSFS_PATH_MAX 256 53 | #define SYSFS_BUS_ID_SIZE 32 54 | 55 | #define snprintf _snprintf 56 | #define syslog(...) /* ... */ 57 | 58 | #endif 59 | 60 | #include "usbip_common.h" 61 | #include "stub_driver.h" 62 | #include "vhci_driver.h" 63 | #ifdef DMALLOC 64 | #include 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /userspace/libsrc/usbip_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #include "usbip.h" 6 | #include "names.h" 7 | 8 | int usbip_use_syslog = 0; 9 | int usbip_use_stderr = 0; 10 | int usbip_use_debug = 0; 11 | 12 | struct speed_string { 13 | int num; 14 | char *speed; 15 | char *desc; 16 | }; 17 | 18 | static const struct speed_string speed_strings[] = { 19 | { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"}, 20 | { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, 21 | { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, 22 | { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, 23 | { 0, NULL, NULL } 24 | }; 25 | 26 | struct portst_string { 27 | int num; 28 | char *desc; 29 | }; 30 | 31 | static struct portst_string portst_strings[] = { 32 | { SDEV_ST_AVAILABLE, "Device Available" }, 33 | { SDEV_ST_USED, "Device in Use" }, 34 | { SDEV_ST_ERROR, "Device Error"}, 35 | { VDEV_ST_NULL, "Port Available"}, 36 | { VDEV_ST_NOTASSIGNED, "Port Initializing"}, 37 | { VDEV_ST_USED, "Port in Use"}, 38 | { VDEV_ST_ERROR, "Port Error"}, 39 | { 0, NULL} 40 | }; 41 | 42 | const char *usbip_status_string(int32_t status) 43 | { 44 | int i; 45 | for (i=0; portst_strings[i].desc != NULL; i++) 46 | if (portst_strings[i].num == status) 47 | return portst_strings[i].desc; 48 | 49 | return "Unknown Status"; 50 | } 51 | 52 | const char *usbip_speed_string(int num) 53 | { 54 | int i; 55 | for (i=0; speed_strings[i].speed != NULL; i++) 56 | if (speed_strings[i].num == num) 57 | return speed_strings[i].desc; 58 | 59 | return "Unknown Speed"; 60 | } 61 | 62 | 63 | #define DBG_UDEV_INTEGER(name)\ 64 | dbg("%-20s = %x", to_string(name), (int) udev->name) 65 | 66 | #define DBG_UINF_INTEGER(name)\ 67 | dbg("%-20s = %x", to_string(name), (int) uinf->name) 68 | 69 | void dump_usb_interface(struct usb_interface *uinf) 70 | { 71 | char buff[100]; 72 | usbip_names_get_class(buff, sizeof(buff), 73 | uinf->bInterfaceClass, 74 | uinf->bInterfaceSubClass, 75 | uinf->bInterfaceProtocol); 76 | dbg("%-20s = %s", "Interface(C/SC/P)", buff); 77 | } 78 | 79 | void dump_usb_device(struct usb_device *udev) 80 | { 81 | char buff[100]; 82 | 83 | 84 | dbg("%-20s = %s", "path", udev->path); 85 | dbg("%-20s = %s", "busid", udev->busid); 86 | 87 | usbip_names_get_class(buff, sizeof(buff), 88 | udev->bDeviceClass, 89 | udev->bDeviceSubClass, 90 | udev->bDeviceProtocol); 91 | dbg("%-20s = %s", "Device(C/SC/P)", buff); 92 | 93 | DBG_UDEV_INTEGER(bcdDevice); 94 | 95 | usbip_names_get_product(buff, sizeof(buff), 96 | udev->idVendor, 97 | udev->idProduct); 98 | dbg("%-20s = %s", "Vendor/Product", buff); 99 | 100 | DBG_UDEV_INTEGER(bNumConfigurations); 101 | DBG_UDEV_INTEGER(bNumInterfaces); 102 | 103 | dbg("%-20s = %s", "speed", 104 | usbip_speed_string(udev->speed)); 105 | 106 | DBG_UDEV_INTEGER(busnum); 107 | DBG_UDEV_INTEGER(devnum); 108 | } 109 | 110 | #ifdef __linux__ 111 | int read_attr_value(struct sysfs_device *dev, const char *name, const char *format) 112 | { 113 | char attrpath[SYSFS_PATH_MAX]; 114 | struct sysfs_attribute *attr; 115 | int num = 0; 116 | int ret; 117 | 118 | snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, name); 119 | 120 | attr = sysfs_open_attribute(attrpath); 121 | if (!attr) { 122 | err("open attr %s", attrpath); 123 | return 0; 124 | } 125 | 126 | ret = sysfs_read_attribute(attr); 127 | if (ret < 0) { 128 | err("read attr"); 129 | goto err; 130 | } 131 | 132 | ret = sscanf(attr->value, format, &num); 133 | if (ret < 1) { 134 | err("sscanf"); 135 | goto err; 136 | } 137 | 138 | err: 139 | sysfs_close_attribute(attr); 140 | 141 | return num; 142 | } 143 | 144 | 145 | int read_attr_speed(struct sysfs_device *dev) 146 | { 147 | char attrpath[SYSFS_PATH_MAX]; 148 | struct sysfs_attribute *attr; 149 | char speed[100]; 150 | int ret; 151 | int i; 152 | 153 | snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, "speed"); 154 | 155 | attr = sysfs_open_attribute(attrpath); 156 | if (!attr) { 157 | err("open attr"); 158 | return 0; 159 | } 160 | 161 | ret = sysfs_read_attribute(attr); 162 | if (ret < 0) { 163 | err("read attr"); 164 | goto err; 165 | } 166 | 167 | ret = sscanf(attr->value, "%s\n", speed); 168 | if (ret < 1) { 169 | err("sscanf"); 170 | goto err; 171 | } 172 | err: 173 | sysfs_close_attribute(attr); 174 | 175 | for (i=0; speed_strings[i].speed != NULL; i++) { 176 | if (!strcmp(speed, speed_strings[i].speed)) 177 | return speed_strings[i].num; 178 | } 179 | 180 | return USB_SPEED_UNKNOWN; 181 | } 182 | 183 | #define READ_ATTR(object, type, dev, name, format)\ 184 | do { (object)->name = (type) read_attr_value(dev, to_string(name), format); } while (0) 185 | 186 | 187 | int read_usb_device(struct sysfs_device *sdev, struct usb_device *udev) 188 | { 189 | uint32_t busnum, devnum; 190 | 191 | READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); 192 | READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); 193 | READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n"); 194 | 195 | READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n"); 196 | READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n"); 197 | READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n"); 198 | 199 | READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n"); 200 | READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n"); 201 | READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n"); 202 | 203 | READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); 204 | udev->speed = read_attr_speed(sdev); 205 | 206 | strncpy(udev->path, sdev->path, SYSFS_PATH_MAX); 207 | strncpy(udev->busid, sdev->name, SYSFS_BUS_ID_SIZE); 208 | 209 | sscanf(sdev->name, "%u-%u", &busnum, &devnum); 210 | udev->busnum = busnum; 211 | 212 | return 0; 213 | } 214 | 215 | int read_usb_interface(struct usb_device *udev, int i, struct usb_interface *uinf) 216 | { 217 | char busid[SYSFS_BUS_ID_SIZE]; 218 | struct sysfs_device *sif; 219 | 220 | sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); 221 | 222 | sif = sysfs_open_device("usb", busid); 223 | if (!sif) { 224 | err("open sif of %s", busid); 225 | return -1; 226 | } 227 | 228 | READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n"); 229 | READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); 230 | READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); 231 | 232 | sysfs_close_device(sif); 233 | 234 | return 0; 235 | } 236 | #endif 237 | 238 | int usbip_names_init(char *f) 239 | { 240 | return names_init(f); 241 | } 242 | 243 | void usbip_names_free() 244 | { 245 | names_free(); 246 | } 247 | 248 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t product) 249 | { 250 | const char *prod, *vend; 251 | 252 | prod = names_product(vendor, product); 253 | if (!prod) 254 | prod = "unknown product"; 255 | 256 | 257 | vend = names_vendor(vendor); 258 | if (!vend) 259 | vend = "unknown vendor"; 260 | 261 | snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product); 262 | } 263 | 264 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, uint8_t subclass, uint8_t protocol) 265 | { 266 | const char *c, *s, *p; 267 | 268 | if (class == 0 && subclass == 0 && protocol == 0) { 269 | snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol); 270 | return; 271 | } 272 | 273 | p = names_protocol(class, subclass, protocol); 274 | if (!p) 275 | p = "unknown protocol"; 276 | 277 | s = names_subclass(class, subclass); 278 | if (!s) 279 | s = "unknown subclass"; 280 | 281 | c = names_class(class); 282 | if (!c) 283 | c = "unknown class"; 284 | 285 | snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol); 286 | } 287 | -------------------------------------------------------------------------------- /userspace/libsrc/usbip_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef _USBIP_COMMON_H 6 | #define _USBIP_COMMON_H 7 | 8 | #ifdef __GNUC__ 9 | #define PACKED __attribute__((__packed__)) 10 | #else 11 | #pragma pack(push,1) 12 | #define PACKED /* */ 13 | #endif 14 | 15 | 16 | #ifndef USBIDS_FILE 17 | #define USBIDS_FILE "/usr/share/hwdata/usb.ids" 18 | #endif 19 | 20 | #ifndef VHCI_STATE_PATH 21 | #define VHCI_STATE_PATH "/var/run/vhci_hcd" 22 | #endif 23 | 24 | enum usb_device_speed { 25 | USB_SPEED_UNKNOWN = 0, /* enumerating */ 26 | USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ 27 | USB_SPEED_HIGH, /* usb 2.0 */ 28 | USB_SPEED_VARIABLE /* wireless (usb 2.5) */ 29 | }; 30 | 31 | /* FIXME: how to sync with drivers/usbip_common.h ? */ 32 | enum usbip_device_status{ 33 | /* sdev is available. */ 34 | SDEV_ST_AVAILABLE = 0x01, 35 | /* sdev is now used. */ 36 | SDEV_ST_USED, 37 | /* sdev is unusable because of a fatal error. */ 38 | SDEV_ST_ERROR, 39 | 40 | /* vdev does not connect a remote device. */ 41 | VDEV_ST_NULL, 42 | /* vdev is used, but the USB address is not assigned yet */ 43 | VDEV_ST_NOTASSIGNED, 44 | VDEV_ST_USED, 45 | VDEV_ST_ERROR 46 | }; 47 | 48 | extern int usbip_use_syslog; 49 | extern int usbip_use_stderr; 50 | extern int usbip_use_debug ; 51 | 52 | 53 | #define err(fmt, ...) do { \ 54 | if (usbip_use_syslog) { \ 55 | syslog(LOG_ERR, "usbip err: %13s:%4d (%-12s) " fmt "\n", \ 56 | __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ 57 | } \ 58 | if (usbip_use_stderr) { \ 59 | fprintf(stderr, "usbip err: %13s:%4d (%-12s) " fmt "\n", \ 60 | __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ 61 | } \ 62 | } while (0) 63 | 64 | #define notice(fmt, ...) do { \ 65 | if (usbip_use_syslog) { \ 66 | syslog(LOG_DEBUG, "usbip: " fmt, ##__VA_ARGS__); \ 67 | } \ 68 | if (usbip_use_stderr) { \ 69 | fprintf(stderr, "usbip: " fmt "\n", ##__VA_ARGS__); \ 70 | } \ 71 | } while (0) 72 | 73 | #define info(fmt, ...) do { \ 74 | if (usbip_use_syslog) { \ 75 | syslog(LOG_DEBUG, fmt, ##__VA_ARGS__); \ 76 | } \ 77 | if (usbip_use_stderr) { \ 78 | fprintf(stderr, fmt "\n", ##__VA_ARGS__); \ 79 | } \ 80 | } while (0) 81 | 82 | #define dbg(fmt, ...) do { \ 83 | if (usbip_use_debug) { \ 84 | if (usbip_use_syslog) { \ 85 | syslog(LOG_DEBUG, "usbip dbg: %13s:%4d (%-12s) " fmt, \ 86 | __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ 87 | } \ 88 | if (usbip_use_stderr) { \ 89 | fprintf(stderr, "usbip dbg: %13s:%4d (%-12s) " fmt "\n", \ 90 | __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ 91 | } \ 92 | } \ 93 | } while (0) 94 | 95 | #define BUG() do { err("sorry, it's a bug"); abort(); } while (0) 96 | 97 | 98 | struct usb_interface { 99 | uint8_t bInterfaceClass; 100 | uint8_t bInterfaceSubClass; 101 | uint8_t bInterfaceProtocol; 102 | uint8_t padding; /* alignment */ 103 | } PACKED; 104 | 105 | 106 | 107 | struct usb_device { 108 | char path[SYSFS_PATH_MAX]; 109 | char busid[SYSFS_BUS_ID_SIZE]; 110 | 111 | uint32_t busnum; 112 | uint32_t devnum; 113 | uint32_t speed; 114 | 115 | uint16_t idVendor; 116 | uint16_t idProduct; 117 | uint16_t bcdDevice; 118 | 119 | uint8_t bDeviceClass; 120 | uint8_t bDeviceSubClass; 121 | uint8_t bDeviceProtocol; 122 | uint8_t bConfigurationValue; 123 | uint8_t bNumConfigurations; 124 | uint8_t bNumInterfaces; 125 | } PACKED; 126 | 127 | /* 128 | * USB/IP request headers. 129 | * Currently, we define 4 request types: 130 | * 131 | * - CMD_SUBMIT transfers a USB request, corresponding to usb_submit_urb(). 132 | * (client to server) 133 | * - RET_RETURN transfers the result of CMD_SUBMIT. 134 | * (server to client) 135 | * - CMD_UNLINK transfers an unlink request of a pending USB request. 136 | * (client to server) 137 | * - RET_UNLINK transfers the result of CMD_UNLINK. 138 | * (server to client) 139 | * 140 | * Note: The below request formats are based on the USB subsystem of Linux. Its 141 | * details will be defined when other implementations come. 142 | * 143 | * 144 | */ 145 | 146 | 147 | typedef uint32_t __u32; 148 | typedef int32_t __s32; 149 | 150 | /* 151 | * A basic header followed by other additional headers. 152 | */ 153 | struct usbip_header_basic { 154 | #define USBIP_CMD_SUBMIT 0x0001 155 | #define USBIP_CMD_UNLINK 0x0002 156 | #define USBIP_RET_SUBMIT 0x0003 157 | #define USBIP_RET_UNLINK 0x0004 158 | __u32 command; 159 | 160 | /* sequential number which identifies requests. 161 | * incremented per connections */ 162 | __u32 seqnum; 163 | 164 | /* devid is used to specify a remote USB device uniquely instead 165 | * of busnum and devnum in Linux. In the case of Linux stub_driver, 166 | * this value is ((busnum << 16) | devnum) */ 167 | __u32 devid; 168 | 169 | #define USBIP_DIR_OUT 0 170 | #define USBIP_DIR_IN 1 171 | __u32 direction; 172 | __u32 ep; /* endpoint number */ 173 | } PACKED; 174 | 175 | /* 176 | * An additional header for a CMD_SUBMIT packet. 177 | */ 178 | struct usbip_header_cmd_submit { 179 | /* these values are basically the same as in a URB. */ 180 | 181 | /* the same in a URB. */ 182 | __u32 transfer_flags; 183 | 184 | /* set the following data size (out), 185 | * or expected reading data size (in) */ 186 | __s32 transfer_buffer_length; 187 | 188 | /* it is difficult for usbip to sync frames (reserved only?) */ 189 | __s32 start_frame; 190 | 191 | /* the number of iso descriptors that follows this header */ 192 | __s32 number_of_packets; 193 | 194 | /* the maximum time within which this request works in a host 195 | * controller of a server side */ 196 | __s32 interval; 197 | 198 | /* set setup packet data for a CTRL request */ 199 | unsigned char setup[8]; 200 | } PACKED; 201 | 202 | /* 203 | * An additional header for a RET_SUBMIT packet. 204 | */ 205 | struct usbip_header_ret_submit { 206 | __s32 status; 207 | __s32 actual_length; /* returned data length */ 208 | __s32 start_frame; /* ISO and INT */ 209 | __s32 number_of_packets; /* ISO only */ 210 | __s32 error_count; /* ISO only */ 211 | } PACKED; 212 | 213 | /* 214 | * An additional header for a CMD_UNLINK packet. 215 | */ 216 | struct usbip_header_cmd_unlink { 217 | __u32 seqnum; /* URB's seqnum that will be unlinked */ 218 | } PACKED; 219 | 220 | /* 221 | * An additional header for a RET_UNLINK packet. 222 | */ 223 | struct usbip_header_ret_unlink { 224 | __s32 status; 225 | } PACKED; 226 | 227 | /* the same as usb_iso_packet_descriptor but packed for pdu */ 228 | struct usbip_iso_packet_descriptor { 229 | __u32 offset; 230 | __u32 length; /* expected length */ 231 | __u32 actual_length; 232 | __u32 status; 233 | } PACKED; 234 | 235 | /* 236 | * All usbip packets use a common header to keep code simple. 237 | */ 238 | struct usbip_header { 239 | struct usbip_header_basic base; 240 | 241 | union { 242 | struct usbip_header_cmd_submit cmd_submit; 243 | struct usbip_header_ret_submit ret_submit; 244 | struct usbip_header_cmd_unlink cmd_unlink; 245 | struct usbip_header_ret_unlink ret_unlink; 246 | } u; 247 | } PACKED; 248 | 249 | 250 | #define to_string(s) #s 251 | 252 | void dump_usb_interface(struct usb_interface *); 253 | void dump_usb_device(struct usb_device *); 254 | int read_usb_device(struct sysfs_device *sdev, struct usb_device *udev); 255 | int read_attr_value(struct sysfs_device *dev, const char *name, const char *format); 256 | int read_usb_interface(struct usb_device *udev, int i, struct usb_interface *uinf); 257 | 258 | const char *usbip_speed_string(int num); 259 | const char *usbip_status_string(int32_t status); 260 | 261 | int usbip_names_init(char *); 262 | void usbip_names_free(void); 263 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t product); 264 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, uint8_t subclass, uint8_t protocol); 265 | 266 | #ifdef __GNUC__ 267 | #else 268 | #pragma pack(pop) 269 | #endif 270 | 271 | #endif 272 | -------------------------------------------------------------------------------- /userspace/libsrc/usbip_common.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {2C173853-88C0-4334-85BF-0B46CFD5A007} 15 | usbip_common 16 | 17 | 18 | 19 | StaticLibrary 20 | true 21 | NotSet 22 | 23 | 24 | StaticLibrary 25 | false 26 | true 27 | NotSet 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Level3 43 | Disabled 44 | MultiThreadedDebug 45 | 46 | 47 | true 48 | 49 | 50 | 51 | 52 | Level3 53 | MaxSpeed 54 | true 55 | true 56 | MultiThreaded 57 | 58 | 59 | true 60 | true 61 | true 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /userspace/libsrc/vhci_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | 6 | #include "usbip.h" 7 | 8 | 9 | static const char vhci_driver_name[] = "vhci_hcd"; 10 | 11 | struct usbip_vhci_driver *vhci_driver; 12 | 13 | static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid) 14 | { 15 | struct sysfs_device *sudev; 16 | 17 | sudev = sysfs_open_device("usb", busid); 18 | if (!sudev) { 19 | err("sysfs_open_device %s", busid); 20 | goto err; 21 | } 22 | read_usb_device(sudev, &idev->udev); 23 | sysfs_close_device(sudev); 24 | 25 | /* add class devices of this imported device */ 26 | struct class_device *cdev; 27 | dlist_for_each_data(vhci_driver->cdev_list, cdev, struct class_device) { 28 | if (!strncmp(cdev->devpath, idev->udev.path, strlen(idev->udev.path))) { 29 | struct class_device *new_cdev; 30 | 31 | /* alloc and copy because dlist is linked from only one list */ 32 | new_cdev = calloc(1, sizeof(*new_cdev)); 33 | if (!new_cdev) 34 | goto err; 35 | 36 | memcpy(new_cdev, cdev, sizeof(*new_cdev)); 37 | dlist_unshift(idev->cdev_list, (void*) new_cdev); 38 | } 39 | } 40 | 41 | return idev; 42 | 43 | err: 44 | return NULL; 45 | } 46 | 47 | 48 | 49 | static int parse_status(char *value) 50 | { 51 | int ret = 0; 52 | char *c; 53 | int i; 54 | 55 | for (i = 0; i < vhci_driver->nports; i++) 56 | bzero(&vhci_driver->idev[i], sizeof(struct usbip_imported_device)); 57 | 58 | 59 | /* skip a header line */ 60 | c = strchr(value, '\n') + 1; 61 | 62 | while (*c != '\0') { 63 | int port, status, speed, devid; 64 | unsigned long socket; 65 | char lbusid[SYSFS_BUS_ID_SIZE]; 66 | 67 | ret = sscanf(c, "%d %d %d %x %lx %s\n", 68 | &port, &status, &speed, 69 | &devid, &socket, lbusid); 70 | 71 | if (ret < 5) { 72 | err("scanf %d", ret); 73 | BUG(); 74 | } 75 | 76 | dbg("port %d status %d speed %d devid %x", 77 | port, status, speed, devid); 78 | dbg("socket %lx lbusid %s", socket, lbusid); 79 | 80 | 81 | /* if a device is connected, look at it */ 82 | { 83 | struct usbip_imported_device *idev = &vhci_driver->idev[port]; 84 | 85 | idev->port = port; 86 | idev->status = status; 87 | 88 | idev->devid = devid; 89 | 90 | idev->busnum = (devid >> 16); 91 | idev->devnum = (devid & 0x0000ffff); 92 | 93 | idev->cdev_list = dlist_new(sizeof(struct class_device)); 94 | if (!idev->cdev_list) { 95 | err("init new device"); 96 | return -1; 97 | } 98 | 99 | if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) { 100 | idev = imported_device_init(idev, lbusid); 101 | if (!idev) { 102 | err("init new device"); 103 | return -1; 104 | } 105 | } 106 | } 107 | 108 | 109 | /* go to the next line */ 110 | c = strchr(c, '\n') + 1; 111 | } 112 | 113 | dbg("exit"); 114 | 115 | return 0; 116 | } 117 | 118 | 119 | static int check_usbip_device(struct sysfs_class_device *cdev) 120 | { 121 | char clspath[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */ 122 | char devpath[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */ 123 | 124 | int ret; 125 | 126 | snprintf(clspath, sizeof(clspath), "%s/device", cdev->path); 127 | 128 | ret = sysfs_get_link(clspath, devpath, SYSFS_PATH_MAX); 129 | if (!ret) { 130 | if (!strncmp(devpath, vhci_driver->hc_device->path, 131 | strlen(vhci_driver->hc_device->path))) { 132 | /* found usbip device */ 133 | struct class_device *cdev; 134 | 135 | cdev = calloc(1, sizeof(*cdev)); 136 | if (!cdev) { 137 | err("calloc cdev"); 138 | return -1; 139 | } 140 | dlist_unshift(vhci_driver->cdev_list, (void*) cdev); 141 | strncpy(cdev->clspath, clspath, sizeof(cdev->clspath)); 142 | strncpy(cdev->devpath, devpath, sizeof(cdev->clspath)); 143 | dbg(" found %s %s", clspath, devpath); 144 | } 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | 151 | static int search_class_for_usbip_device(char *cname) 152 | { 153 | struct sysfs_class *class; 154 | struct dlist *cdev_list; 155 | struct sysfs_class_device *cdev; 156 | int ret = 0; 157 | 158 | class = sysfs_open_class(cname); 159 | if (!class) { 160 | err("open class"); 161 | return -1; 162 | } 163 | 164 | dbg("class %s", class->name); 165 | 166 | cdev_list = sysfs_get_class_devices(class); 167 | if (!cdev_list) 168 | /* nothing */ 169 | goto out; 170 | 171 | dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) { 172 | dbg(" cdev %s", cdev->name); 173 | ret = check_usbip_device(cdev); 174 | if (ret < 0) 175 | goto out; 176 | } 177 | 178 | out: 179 | sysfs_close_class(class); 180 | 181 | return ret; 182 | } 183 | 184 | 185 | static int refresh_class_device_list(void) 186 | { 187 | int ret; 188 | struct dlist *cname_list; 189 | char *cname; 190 | 191 | /* search under /sys/class */ 192 | cname_list = sysfs_open_directory_list("/sys/class"); 193 | if (!cname_list) { 194 | err("open class directory"); 195 | return -1; 196 | } 197 | 198 | dlist_for_each_data(cname_list, cname, char) { 199 | ret = search_class_for_usbip_device(cname); 200 | if (ret < 0) { 201 | sysfs_close_list(cname_list); 202 | return -1; 203 | } 204 | } 205 | 206 | sysfs_close_list(cname_list); 207 | 208 | /* seach under /sys/block */ 209 | ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME); 210 | if (ret < 0) 211 | return -1; 212 | 213 | return 0; 214 | } 215 | 216 | 217 | static int refresh_imported_device_list(void) 218 | { 219 | struct sysfs_attribute *attr_status; 220 | 221 | 222 | attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status"); 223 | if (!attr_status) { 224 | err("get attr %s of %s", "status", vhci_driver->hc_device->name); 225 | return -1; 226 | } 227 | 228 | dbg("name %s, path %s, len %d, method %d\n", attr_status->name, 229 | attr_status->path, attr_status->len, attr_status->method); 230 | 231 | dbg("%s", attr_status->value); 232 | 233 | return parse_status(attr_status->value); 234 | } 235 | 236 | static int get_nports(void) 237 | { 238 | int nports = 0; 239 | struct sysfs_attribute *attr_status; 240 | 241 | attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status"); 242 | if (!attr_status) { 243 | err("get attr %s of %s", "status", vhci_driver->hc_device->name); 244 | return -1; 245 | } 246 | 247 | dbg("name %s, path %s, len %d, method %d\n", attr_status->name, 248 | attr_status->path, attr_status->len, attr_status->method); 249 | 250 | dbg("%s", attr_status->value); 251 | 252 | { 253 | char *c; 254 | 255 | /* skip a header line */ 256 | c = strchr(attr_status->value, '\n') + 1; 257 | 258 | while (*c != '\0') { 259 | /* go to the next line */ 260 | c = strchr(c, '\n') + 1; 261 | nports += 1; 262 | } 263 | } 264 | 265 | return nports; 266 | } 267 | 268 | static int get_hc_busid(char *sysfs_mntpath, char *hc_busid) 269 | { 270 | struct sysfs_driver *sdriver; 271 | char sdriver_path[SYSFS_PATH_MAX]; 272 | 273 | struct sysfs_device *hc_dev; 274 | struct dlist *hc_devs; 275 | 276 | int found = 0; 277 | 278 | snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/platform/%s/%s", 279 | sysfs_mntpath, SYSFS_BUS_NAME, SYSFS_DRIVERS_NAME, 280 | vhci_driver_name); 281 | 282 | sdriver = sysfs_open_driver_path(sdriver_path); 283 | if (!sdriver) { 284 | info("%s is not found", sdriver_path); 285 | info("load usbip-core.ko and vhci-hcd.ko !"); 286 | return -1; 287 | } 288 | 289 | hc_devs = sysfs_get_driver_devices(sdriver); 290 | if (!hc_devs) { 291 | err("get hc list"); 292 | goto err; 293 | } 294 | 295 | /* assume only one vhci_hcd */ 296 | dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) { 297 | strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE); 298 | found = 1; 299 | } 300 | 301 | err: 302 | sysfs_close_driver(sdriver); 303 | 304 | if (found) 305 | return 0; 306 | 307 | err("not found usbip hc"); 308 | return -1; 309 | } 310 | 311 | 312 | /* ---------------------------------------------------------------------- */ 313 | 314 | int usbip_vhci_driver_open(void) 315 | { 316 | int ret; 317 | char hc_busid[SYSFS_BUS_ID_SIZE]; 318 | 319 | vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver)); 320 | if (!vhci_driver) { 321 | err("alloc vhci_driver"); 322 | return -1; 323 | } 324 | 325 | ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX); 326 | if (ret < 0) { 327 | err("sysfs must be mounted"); 328 | goto err; 329 | } 330 | 331 | ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid); 332 | if (ret < 0) 333 | goto err; 334 | 335 | /* will be freed in usbip_driver_close() */ 336 | vhci_driver->hc_device = sysfs_open_device("platform", hc_busid); 337 | if (!vhci_driver->hc_device) { 338 | err("get sysfs vhci_driver"); 339 | goto err; 340 | } 341 | 342 | vhci_driver->nports = get_nports(); 343 | 344 | info("%d ports available\n", vhci_driver->nports); 345 | 346 | vhci_driver->cdev_list = dlist_new(sizeof(struct class_device)); 347 | if (!vhci_driver->cdev_list) 348 | goto err; 349 | 350 | if (refresh_class_device_list()) 351 | goto err; 352 | 353 | if (refresh_imported_device_list()) 354 | goto err; 355 | 356 | 357 | return 0; 358 | 359 | 360 | err: 361 | if (vhci_driver->cdev_list) 362 | dlist_destroy(vhci_driver->cdev_list); 363 | if (vhci_driver->hc_device) 364 | sysfs_close_device(vhci_driver->hc_device); 365 | if (vhci_driver) 366 | free(vhci_driver); 367 | 368 | vhci_driver = NULL; 369 | return -1; 370 | } 371 | 372 | 373 | void usbip_vhci_driver_close() 374 | { 375 | int i; 376 | 377 | if (!vhci_driver) 378 | return; 379 | 380 | if (vhci_driver->cdev_list) 381 | dlist_destroy(vhci_driver->cdev_list); 382 | 383 | for (i = 0; i < vhci_driver->nports; i++) { 384 | if (vhci_driver->idev[i].cdev_list) 385 | dlist_destroy(vhci_driver->idev[i].cdev_list); 386 | } 387 | 388 | if (vhci_driver->hc_device) 389 | sysfs_close_device(vhci_driver->hc_device); 390 | free(vhci_driver); 391 | 392 | vhci_driver = NULL; 393 | } 394 | 395 | 396 | int usbip_vhci_refresh_device_list(void) 397 | { 398 | int i; 399 | 400 | if (vhci_driver->cdev_list) 401 | dlist_destroy(vhci_driver->cdev_list); 402 | 403 | 404 | for (i = 0; i < vhci_driver->nports; i++) { 405 | if (vhci_driver->idev[i].cdev_list) 406 | dlist_destroy(vhci_driver->idev[i].cdev_list); 407 | } 408 | 409 | vhci_driver->cdev_list = dlist_new(sizeof(struct class_device)); 410 | if (!vhci_driver->cdev_list) 411 | goto err; 412 | 413 | if (refresh_class_device_list()) 414 | goto err; 415 | 416 | if (refresh_imported_device_list()) 417 | goto err; 418 | 419 | return 0; 420 | err: 421 | if (vhci_driver->cdev_list) 422 | dlist_destroy(vhci_driver->cdev_list); 423 | 424 | for (i = 0; i < vhci_driver->nports; i++) { 425 | if (vhci_driver->idev[i].cdev_list) 426 | dlist_destroy(vhci_driver->idev[i].cdev_list); 427 | } 428 | 429 | err("refresh device list"); 430 | return -1; 431 | } 432 | 433 | 434 | int usbip_vhci_get_free_port(void) 435 | { 436 | int i; 437 | 438 | for (i = 0; i < vhci_driver->nports; i++) { 439 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) 440 | return i; 441 | } 442 | 443 | return -1; 444 | } 445 | 446 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, 447 | uint32_t speed) { 448 | struct sysfs_attribute *attr_attach; 449 | char buff[200]; /* what size should be ? */ 450 | int ret; 451 | 452 | attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach"); 453 | if (!attr_attach) { 454 | err("get attach"); 455 | return -1; 456 | } 457 | 458 | snprintf(buff, sizeof(buff), "%u %u %u %u", 459 | port, sockfd, devid, speed); 460 | dbg("writing: %s", buff); 461 | 462 | ret = sysfs_write_attribute(attr_attach, buff, strlen(buff)); 463 | if (ret < 0) { 464 | err("write to attach failed"); 465 | return -1; 466 | } 467 | 468 | info("port %d attached", port); 469 | 470 | return 0; 471 | } 472 | 473 | static unsigned long get_devid(uint8_t busnum, uint8_t devnum) 474 | { 475 | return (busnum << 16) | devnum; 476 | } 477 | 478 | /* will be removed */ 479 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, 480 | uint8_t devnum, uint32_t speed) 481 | { 482 | int devid = get_devid(busnum, devnum); 483 | 484 | return usbip_vhci_attach_device2(port, sockfd, devid, speed); 485 | } 486 | 487 | int usbip_vhci_detach_device(uint8_t port) 488 | { 489 | struct sysfs_attribute *attr_detach; 490 | char buff[200]; /* what size should be ? */ 491 | int ret; 492 | 493 | attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach"); 494 | if (!attr_detach) { 495 | err("get detach"); 496 | return -1; 497 | } 498 | 499 | snprintf(buff, sizeof(buff), "%u", port); 500 | dbg("writing to detach"); 501 | dbg("writing: %s", buff); 502 | 503 | ret = sysfs_write_attribute(attr_detach, buff, strlen(buff)); 504 | if (ret < 0) { 505 | err("write to detach failed"); 506 | return -1; 507 | } 508 | 509 | info("port %d detached", port); 510 | 511 | return 0; 512 | } 513 | -------------------------------------------------------------------------------- /userspace/libsrc/vhci_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef _VHCI_DRIVER_H 6 | #define _VHCI_DRIVER_H 7 | 8 | #include "usbip.h" 9 | 10 | 11 | 12 | #define MAXNPORT 128 13 | 14 | struct class_device { 15 | char clspath[SYSFS_PATH_MAX]; 16 | char devpath[SYSFS_PATH_MAX]; 17 | }; 18 | 19 | struct usbip_imported_device { 20 | uint8_t port; 21 | uint32_t status; 22 | 23 | uint32_t devid; 24 | 25 | uint8_t busnum; 26 | uint8_t devnum; 27 | 28 | 29 | struct dlist *cdev_list; /* list of class device */ 30 | struct usb_device udev; 31 | }; 32 | 33 | struct usbip_vhci_driver { 34 | char sysfs_mntpath[SYSFS_PATH_MAX]; 35 | struct sysfs_device *hc_device; /* /sys/devices/platform/vhci_hcd */ 36 | 37 | struct dlist *cdev_list; /* list of class device */ 38 | 39 | int nports; 40 | struct usbip_imported_device idev[MAXNPORT]; 41 | }; 42 | 43 | 44 | extern struct usbip_vhci_driver *vhci_driver; 45 | 46 | int usbip_vhci_driver_open(void); 47 | void usbip_vhci_driver_close(void); 48 | 49 | int usbip_vhci_refresh_device_list(void); 50 | 51 | 52 | int usbip_vhci_get_free_port(void); 53 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, 54 | uint32_t speed); 55 | 56 | /* will be removed */ 57 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, 58 | uint8_t devnum, uint32_t speed); 59 | 60 | int usbip_vhci_detach_device(uint8_t port); 61 | #endif 62 | -------------------------------------------------------------------------------- /userspace/src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS := -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' 2 | AM_CFLAGS := @EXTRA_CFLAGS@ @PACKAGE_CFLAGS@ 3 | LDADD := $(top_srcdir)/libsrc/libusbip.la @PACKAGE_LIBS@ 4 | 5 | sbin_PROGRAMS := usbip usbipd usbip_bind_driver 6 | 7 | usbip_SOURCES = usbip.c usbip_network.c usbip_network.h usbip_linux.c usbip_platform.h 8 | usbipd_SOURCES := usbipd.c usbip_network.c usbip_network.h 9 | usbip_bind_driver_SOURCES := bind-driver.c utils.c utils.h \ 10 | usbip_network.h usbip_network.c 11 | -------------------------------------------------------------------------------- /userspace/src/bind-driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 4 | */ 5 | 6 | #include "utils.h" 7 | 8 | #define _GNU_SOURCE 9 | #include 10 | #include 11 | 12 | 13 | 14 | static const struct option longopts[] = { 15 | {"usbip", required_argument, NULL, 'u'}, 16 | {"other", required_argument, NULL, 'o'}, 17 | {"list", no_argument, NULL, 'l'}, 18 | {"list2", no_argument, NULL, 'L'}, 19 | {"help", no_argument, NULL, 'h'}, 20 | #if 0 21 | {"allusbip", no_argument, NULL, 'a'}, 22 | {"export-to", required_argument, NULL, 'e'}, 23 | {"unexport", required_argument, NULL, 'x'}, 24 | {"busid", required_argument, NULL, 'b'}, 25 | #endif 26 | 27 | {NULL, 0, NULL, 0} 28 | }; 29 | 30 | static const char match_busid_path[] = "/sys/bus/usb/drivers/usbip/match_busid"; 31 | 32 | 33 | static void show_help(void) 34 | { 35 | printf("Usage: usbip_bind_driver [OPTION]\n"); 36 | printf("Change driver binding for USB/IP.\n"); 37 | printf(" --usbip busid make a device exportable\n"); 38 | printf(" --other busid use a device by a local driver\n"); 39 | printf(" --list print usb devices and their drivers\n"); 40 | printf(" --list2 print usb devices and their drivers in parseable mode\n"); 41 | #if 0 42 | printf(" --allusbip make all devices exportable\n"); 43 | printf(" --export-to host export the device to 'host'\n"); 44 | printf(" --unexport host unexport a device previously exported to 'host'\n"); 45 | printf(" --busid busid the busid used for --export-to\n"); 46 | #endif 47 | } 48 | 49 | static int modify_match_busid(char *busid, int add) 50 | { 51 | int fd; 52 | int ret; 53 | char buff[BUS_ID_SIZE + 4]; 54 | 55 | /* BUS_IS_SIZE includes NULL termination? */ 56 | if (strnlen(busid, BUS_ID_SIZE) > BUS_ID_SIZE - 1) { 57 | g_warning("too long busid"); 58 | return -1; 59 | } 60 | 61 | fd = open(match_busid_path, O_WRONLY); 62 | if (fd < 0) 63 | return -1; 64 | 65 | if (add) 66 | snprintf(buff, BUS_ID_SIZE + 4, "add %s", busid); 67 | else 68 | snprintf(buff, BUS_ID_SIZE + 4, "del %s", busid); 69 | 70 | g_debug("write \"%s\" to %s", buff, match_busid_path); 71 | 72 | ret = write(fd, buff, sizeof(buff)); 73 | if (ret < 0) { 74 | close(fd); 75 | return -1; 76 | } 77 | 78 | close(fd); 79 | 80 | return 0; 81 | } 82 | 83 | static const char unbind_path_format[] = "/sys/bus/usb/devices/%s/driver/unbind"; 84 | 85 | /* buggy driver may cause dead lock */ 86 | static int unbind_interface_busid(char *busid) 87 | { 88 | char unbind_path[PATH_MAX]; 89 | int fd; 90 | int ret; 91 | 92 | snprintf(unbind_path, sizeof(unbind_path), unbind_path_format, busid); 93 | 94 | fd = open(unbind_path, O_WRONLY); 95 | if (fd < 0) { 96 | g_warning("opening unbind_path failed: %d", fd); 97 | return -1; 98 | } 99 | 100 | ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE)); 101 | if (ret < 0) { 102 | g_warning("write to unbind_path failed: %d", ret); 103 | close(fd); 104 | return -1; 105 | } 106 | 107 | close(fd); 108 | 109 | return 0; 110 | } 111 | 112 | static int unbind_interface(char *busid, int configvalue, int interface) 113 | { 114 | char inf_busid[BUS_ID_SIZE]; 115 | g_debug("unbinding interface"); 116 | 117 | snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface); 118 | 119 | return unbind_interface_busid(inf_busid); 120 | } 121 | 122 | 123 | static const char bind_path_format[] = "/sys/bus/usb/drivers/%s/bind"; 124 | 125 | static int bind_interface_busid(char *busid, char *driver) 126 | { 127 | char bind_path[PATH_MAX]; 128 | int fd; 129 | int ret; 130 | 131 | snprintf(bind_path, sizeof(bind_path), bind_path_format, driver); 132 | 133 | fd = open(bind_path, O_WRONLY); 134 | if (fd < 0) 135 | return -1; 136 | 137 | ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE)); 138 | if (ret < 0) { 139 | close(fd); 140 | return -1; 141 | } 142 | 143 | close(fd); 144 | 145 | return 0; 146 | } 147 | 148 | static int bind_interface(char *busid, int configvalue, int interface, char *driver) 149 | { 150 | char inf_busid[BUS_ID_SIZE]; 151 | 152 | snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface); 153 | 154 | return bind_interface_busid(inf_busid, driver); 155 | } 156 | 157 | static int unbind(char *busid) 158 | { 159 | int configvalue = 0; 160 | int ninterface = 0; 161 | int devclass = 0; 162 | int i; 163 | int failed = 0; 164 | 165 | configvalue = read_bConfigurationValue(busid); 166 | ninterface = read_bNumInterfaces(busid); 167 | devclass = read_bDeviceClass(busid); 168 | 169 | if (configvalue < 0 || ninterface < 0 || devclass < 0) { 170 | g_warning("read config and ninf value, removed?"); 171 | return -1; 172 | } 173 | 174 | if (devclass == 0x09) { 175 | g_message("skip unbinding of hub"); 176 | return -1; 177 | } 178 | 179 | for (i = 0; i < ninterface; i++) { 180 | char driver[PATH_MAX]; 181 | int ret; 182 | 183 | bzero(&driver, sizeof(driver)); 184 | 185 | getdriver(busid, configvalue, i, driver, PATH_MAX-1); 186 | 187 | g_debug(" %s:%d.%d -> %s ", busid, configvalue, i, driver); 188 | 189 | if (!strncmp("none", driver, PATH_MAX)) 190 | continue; /* unbound interface */ 191 | 192 | #if 0 193 | if (!strncmp("usbip", driver, PATH_MAX)) 194 | continue; /* already bound to usbip */ 195 | #endif 196 | 197 | /* unbinding */ 198 | ret = unbind_interface(busid, configvalue, i); 199 | if (ret < 0) { 200 | g_warning("unbind driver at %s:%d.%d failed", 201 | busid, configvalue, i); 202 | failed = 1; 203 | } 204 | } 205 | 206 | if (failed) 207 | return -1; 208 | else 209 | return 0; 210 | } 211 | 212 | /* call at unbound state */ 213 | static int bind_to_usbip(char *busid) 214 | { 215 | int configvalue = 0; 216 | int ninterface = 0; 217 | int i; 218 | int failed = 0; 219 | 220 | configvalue = read_bConfigurationValue(busid); 221 | ninterface = read_bNumInterfaces(busid); 222 | 223 | if (configvalue < 0 || ninterface < 0) { 224 | g_warning("read config and ninf value, removed?"); 225 | return -1; 226 | } 227 | 228 | for (i = 0; i < ninterface; i++) { 229 | int ret; 230 | 231 | ret = bind_interface(busid, configvalue, i, "usbip"); 232 | if (ret < 0) { 233 | g_warning("bind usbip at %s:%d.%d, failed", 234 | busid, configvalue, i); 235 | failed = 1; 236 | /* need to contine binding at other interfaces */ 237 | } 238 | } 239 | 240 | if (failed) 241 | return -1; 242 | else 243 | return 0; 244 | } 245 | 246 | 247 | static int use_device_by_usbip(char *busid) 248 | { 249 | int ret; 250 | 251 | ret = unbind(busid); 252 | if (ret < 0) { 253 | g_warning("unbind drivers of %s, failed", busid); 254 | return -1; 255 | } 256 | 257 | ret = modify_match_busid(busid, 1); 258 | if (ret < 0) { 259 | g_warning("add %s to match_busid, failed", busid); 260 | return -1; 261 | } 262 | 263 | ret = bind_to_usbip(busid); 264 | if (ret < 0) { 265 | g_warning("bind usbip to %s, failed", busid); 266 | modify_match_busid(busid, 0); 267 | return -1; 268 | } 269 | 270 | g_message("bind %s to usbip, complete!", busid); 271 | 272 | return 0; 273 | } 274 | 275 | 276 | 277 | static int use_device_by_other(char *busid) 278 | { 279 | int ret; 280 | int config; 281 | 282 | /* read and write the same config value to kick probing */ 283 | config = read_bConfigurationValue(busid); 284 | if (config < 0) { 285 | g_warning("read bConfigurationValue of %s, failed", busid); 286 | return -1; 287 | } 288 | 289 | ret = modify_match_busid(busid, 0); 290 | if (ret < 0) { 291 | g_warning("del %s to match_busid, failed", busid); 292 | return -1; 293 | } 294 | 295 | ret = write_bConfigurationValue(busid, config); 296 | if (ret < 0) { 297 | g_warning("read bConfigurationValue of %s, failed", busid); 298 | return -1; 299 | } 300 | 301 | g_message("bind %s to other drivers than usbip, complete!", busid); 302 | 303 | return 0; 304 | } 305 | 306 | 307 | #include 308 | #include 309 | 310 | #include 311 | #include 312 | #include 313 | 314 | 315 | 316 | static int is_usb_device(char *busid) 317 | { 318 | int ret; 319 | 320 | regex_t regex; 321 | regmatch_t pmatch[1]; 322 | 323 | ret = regcomp(®ex, "^[0-9]+-[0-9]+(\\.[0-9]+)*$", REG_NOSUB|REG_EXTENDED); 324 | if (ret < 0) 325 | g_error("regcomp: %s\n", strerror(errno)); 326 | 327 | ret = regexec(®ex, busid, 0, pmatch, 0); 328 | if (ret) 329 | return 0; /* not matched */ 330 | 331 | return 1; 332 | } 333 | 334 | 335 | #include 336 | static int show_devices(void) 337 | { 338 | DIR *dir; 339 | 340 | dir = opendir("/sys/bus/usb/devices/"); 341 | if (!dir) 342 | g_error("opendir: %s", strerror(errno)); 343 | 344 | printf("List USB devices\n"); 345 | for (;;) { 346 | struct dirent *dirent; 347 | char *busid; 348 | 349 | dirent = readdir(dir); 350 | if (!dirent) 351 | break; 352 | 353 | busid = dirent->d_name; 354 | 355 | if (is_usb_device(busid)) { 356 | char name[100] = {'\0'}; 357 | char driver[100] = {'\0'}; 358 | int conf, ninf = 0; 359 | int i; 360 | 361 | conf = read_bConfigurationValue(busid); 362 | ninf = read_bNumInterfaces(busid); 363 | 364 | getdevicename(busid, name, sizeof(name)); 365 | 366 | printf(" - busid %s (%s)\n", busid, name); 367 | 368 | for (i = 0; i < ninf; i++) { 369 | getdriver(busid, conf, i, driver, sizeof(driver)); 370 | printf(" %s:%d.%d -> %s\n", busid, conf, i, driver); 371 | } 372 | printf("\n"); 373 | } 374 | } 375 | 376 | closedir(dir); 377 | 378 | return 0; 379 | } 380 | 381 | static int show_devices2(void) 382 | { 383 | DIR *dir; 384 | 385 | dir = opendir("/sys/bus/usb/devices/"); 386 | if (!dir) 387 | g_error("opendir: %s", strerror(errno)); 388 | 389 | for (;;) { 390 | struct dirent *dirent; 391 | char *busid; 392 | 393 | dirent = readdir(dir); 394 | if (!dirent) 395 | break; 396 | 397 | busid = dirent->d_name; 398 | 399 | if (is_usb_device(busid)) { 400 | char name[100] = {'\0'}; 401 | char driver[100] = {'\0'}; 402 | int conf, ninf = 0; 403 | int i; 404 | 405 | conf = read_bConfigurationValue(busid); 406 | ninf = read_bNumInterfaces(busid); 407 | 408 | getdevicename(busid, name, sizeof(name)); 409 | 410 | printf("busid=%s#usbid=%s#", busid, name); 411 | 412 | for (i = 0; i < ninf; i++) { 413 | getdriver(busid, conf, i, driver, sizeof(driver)); 414 | printf("%s:%d.%d=%s#", busid, conf, i, driver); 415 | } 416 | printf("\n"); 417 | } 418 | } 419 | 420 | closedir(dir); 421 | 422 | return 0; 423 | } 424 | 425 | 426 | #if 0 427 | static int export_to(char *host, char *busid) { 428 | 429 | int ret; 430 | 431 | if( host == NULL ) { 432 | printf( "no host given\n\n"); 433 | show_help(); 434 | return -1; 435 | } 436 | if( busid == NULL ) { 437 | /* XXX print device list and ask for busnumber, if none is 438 | * given */ 439 | printf( "no busid given, use --busid switch\n\n"); 440 | show_help(); 441 | return -1; 442 | } 443 | 444 | 445 | ret = use_device_by_usbip(busid); 446 | if( ret != 0 ) { 447 | printf( "could not bind driver to usbip\n"); 448 | return -1; 449 | } 450 | 451 | printf( "DEBUG: exporting device '%s' to '%s'\n", busid, host ); 452 | ret = export_busid_to_host(host, busid); /* usbip_export.[ch] */ 453 | if( ret != 0 ) { 454 | printf( "could not export device to host\n" ); 455 | printf( " host: %s, device: %s\n", host, busid ); 456 | use_device_by_other(busid); 457 | return -1; 458 | } 459 | 460 | return 0; 461 | } 462 | 463 | static int unexport_from(char *host, char *busid) { 464 | 465 | int ret; 466 | 467 | if (!host || !busid) 468 | g_error("no host or no busid\n"); 469 | 470 | g_message("unexport_from: host: '%s', busid: '%s'", host, busid); 471 | 472 | ret = unexport_busid_from_host(host, busid); /* usbip_export.[ch] */ 473 | if( ret != 0 ) { 474 | err( "could not unexport device from host\n" ); 475 | err( " host: %s, device: %s\n", host, busid ); 476 | } 477 | 478 | ret = use_device_by_other(busid); 479 | if (ret < 0) 480 | g_error("could not unbind device from usbip\n"); 481 | 482 | return 0; 483 | } 484 | 485 | 486 | static int allusbip(void) 487 | { 488 | DIR *dir; 489 | 490 | dir = opendir("/sys/bus/usb/devices/"); 491 | if (!dir) 492 | g_error("opendir: %s", strerror(errno)); 493 | 494 | for (;;) { 495 | struct dirent *dirent; 496 | char *busid; 497 | 498 | dirent = readdir(dir); 499 | if (!dirent) 500 | break; 501 | 502 | busid = dirent->d_name; 503 | 504 | if (!is_usb_device(busid)) 505 | continue; 506 | 507 | { 508 | char name[PATH_MAX]; 509 | int conf, ninf = 0; 510 | int i; 511 | int be_local = 0; 512 | 513 | conf = read_bConfigurationValue(busid); 514 | ninf = read_bNumInterfaces(busid); 515 | 516 | getdevicename(busid, name, sizeof(name)); 517 | 518 | for (i = 0; i < ninf; i++) { 519 | char driver[PATH_MAX]; 520 | 521 | getdriver(busid, conf, i, driver, sizeof(driver)); 522 | #if 0 523 | if (strncmp(driver, "usbhid", 6) == 0 || strncmp(driver, "usb-storage", 11) == 0) { 524 | be_local = 1; 525 | break; 526 | } 527 | #endif 528 | } 529 | 530 | if (be_local == 0) 531 | use_device_by_usbip(busid); 532 | } 533 | } 534 | 535 | closedir(dir); 536 | 537 | return 0; 538 | } 539 | #endif 540 | 541 | int main(int argc, char **argv) 542 | { 543 | char *busid = NULL; 544 | char *remote_host __attribute__((unused)) = NULL; 545 | 546 | enum { 547 | cmd_unknown = 0, 548 | cmd_use_by_usbip, 549 | cmd_use_by_other, 550 | cmd_list, 551 | cmd_list2, 552 | cmd_allusbip, 553 | cmd_export_to, 554 | cmd_unexport, 555 | cmd_help, 556 | } cmd = cmd_unknown; 557 | 558 | if (geteuid() != 0) 559 | g_warning("running non-root?"); 560 | 561 | for (;;) { 562 | int c; 563 | int index = 0; 564 | 565 | c = getopt_long(argc, argv, "u:o:hlLae:x:b:", longopts, &index); 566 | if (c == -1) 567 | break; 568 | 569 | switch (c) { 570 | case 'u': 571 | cmd = cmd_use_by_usbip; 572 | busid = optarg; 573 | break; 574 | case 'o' : 575 | cmd = cmd_use_by_other; 576 | busid = optarg; 577 | break; 578 | case 'l' : 579 | cmd = cmd_list; 580 | break; 581 | case 'L' : 582 | cmd = cmd_list2; 583 | break; 584 | case 'a' : 585 | cmd = cmd_allusbip; 586 | break; 587 | case 'b': 588 | busid = optarg; 589 | break; 590 | case 'e': 591 | cmd = cmd_export_to; 592 | remote_host = optarg; 593 | break; 594 | case 'x': 595 | cmd = cmd_unexport; 596 | remote_host = optarg; 597 | break; 598 | case 'h': /* fallthrough */ 599 | case '?': 600 | cmd = cmd_help; 601 | break; 602 | default: 603 | g_error("getopt"); 604 | } 605 | 606 | //if (cmd) 607 | // break; 608 | } 609 | 610 | switch (cmd) { 611 | case cmd_use_by_usbip: 612 | use_device_by_usbip(busid); 613 | break; 614 | case cmd_use_by_other: 615 | use_device_by_other(busid); 616 | break; 617 | case cmd_list: 618 | show_devices(); 619 | break; 620 | case cmd_list2: 621 | show_devices2(); 622 | break; 623 | #if 0 624 | case cmd_allusbip: 625 | allusbip(); 626 | break; 627 | case cmd_export_to: 628 | export_to(remote_host, busid); 629 | break; 630 | case cmd_unexport: 631 | unexport_from(remote_host, busid); 632 | break; 633 | #endif 634 | case cmd_help: /* fallthrough */ 635 | case cmd_unknown: 636 | show_help(); 637 | break; 638 | default: 639 | g_error("NOT REACHED"); 640 | } 641 | 642 | return 0; 643 | } 644 | -------------------------------------------------------------------------------- /userspace/src/usbip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 4 | */ 5 | 6 | #include "usbip.h" 7 | #include "usbip_network.h" 8 | #include "usbip_osspecific.h" 9 | #include 10 | 11 | static const char version[] = PACKAGE_STRING; 12 | 13 | 14 | int show_exported_devices(char *host); 15 | 16 | 17 | const char help_message[] = "\ 18 | Usage: usbip [options] \n\ 19 | -a, --attach [host] [bus_id] \n\ 20 | Attach a remote USB device. \n\ 21 | \n" 22 | #ifdef __linux__ 23 | " -x, --attachall [host] \n\ 24 | Attach all remote USB devices on the specific host. \n\ 25 | \n" 26 | #endif 27 | " -d, --detach [ports] \n\ 28 | Detach an imported USB device. \n\ 29 | \n\ 30 | -l, --list [hosts] \n\ 31 | List exported USB devices. \n\ 32 | \n\ 33 | -p, --port \n\ 34 | List virtual USB port status. \n\ 35 | \n\ 36 | -D, --debug \n\ 37 | Print debugging information. \n\ 38 | \n\ 39 | -v, --version \n\ 40 | Show version. \n\ 41 | \n\ 42 | -h, --help \n\ 43 | Print this help. \n"; 44 | 45 | static void show_help(void) 46 | { 47 | printf("%s", help_message); 48 | } 49 | 50 | static const struct option longopts[] = { 51 | {"attach", no_argument, NULL, 'a'}, 52 | #ifdef __linux__ 53 | {"attachall", no_argument, NULL, 'x'}, 54 | #endif 55 | {"detach", no_argument, NULL, 'd'}, 56 | {"port", no_argument, NULL, 'p'}, 57 | {"list", no_argument, NULL, 'l'}, 58 | {"version", no_argument, NULL, 'v'}, 59 | {"help", no_argument, NULL, 'h'}, 60 | {"debug", no_argument, NULL, 'D'}, 61 | {"syslog", no_argument, NULL, 'S'}, 62 | {NULL, 0, NULL, 0} 63 | }; 64 | 65 | int main(int argc, char *argv[]) 66 | { 67 | int ret; 68 | 69 | enum { 70 | cmd_attach = 1, 71 | cmd_attachall, 72 | cmd_detach, 73 | cmd_port, 74 | cmd_list, 75 | cmd_help, 76 | cmd_version 77 | } cmd = 0; 78 | 79 | usbip_use_stderr = 1; 80 | 81 | #ifdef __linux__ 82 | if (geteuid() != 0) 83 | notice("running non-root?"); 84 | #endif 85 | 86 | if (init_socket()) 87 | return EXIT_FAILURE; 88 | 89 | ret = usbip_names_init(USBIDS_FILE); 90 | if (ret) 91 | notice("failed to open %s", USBIDS_FILE); 92 | 93 | for (;;) { 94 | int c; 95 | int index = 0; 96 | 97 | c = getopt_long(argc, argv, "adplvhDSx", longopts, &index); 98 | 99 | if (c == -1) 100 | break; 101 | 102 | switch(c) { 103 | case 'a': 104 | if (!cmd) 105 | cmd = cmd_attach; 106 | else 107 | cmd = cmd_help; 108 | break; 109 | case 'd': 110 | if (!cmd) 111 | cmd = cmd_detach; 112 | else 113 | cmd = cmd_help; 114 | break; 115 | case 'p': 116 | if (!cmd) 117 | cmd = cmd_port; 118 | else cmd = cmd_help; 119 | break; 120 | case 'l': 121 | if (!cmd) 122 | cmd = cmd_list; 123 | else 124 | cmd = cmd_help; 125 | break; 126 | case 'v': 127 | if (!cmd) 128 | cmd = cmd_version; 129 | else 130 | cmd = cmd_help; 131 | break; 132 | #ifdef __linux__ 133 | case 'x': 134 | if(!cmd) 135 | cmd = cmd_attachall; 136 | else 137 | cmd = cmd_help; 138 | break; 139 | #endif 140 | case 'h': 141 | cmd = cmd_help; 142 | break; 143 | case 'D': 144 | usbip_use_debug = 1; 145 | break; 146 | case 'S': 147 | usbip_use_syslog = 1; 148 | break; 149 | case '?': 150 | break; 151 | 152 | default: 153 | err("getopt"); 154 | } 155 | } 156 | 157 | ret = 0; 158 | switch(cmd) { 159 | case cmd_attach: 160 | if (optind == argc - 2) 161 | ret = attach_device(argv[optind], argv[optind+1]); 162 | else 163 | show_help(); 164 | break; 165 | case cmd_detach: 166 | while (optind < argc) 167 | ret = detach_port(argv[optind++]); 168 | break; 169 | case cmd_port: 170 | ret = show_port_status(); 171 | break; 172 | case cmd_list: 173 | while (optind < argc) 174 | ret = show_exported_devices(argv[optind++]); 175 | break; 176 | case cmd_attachall: 177 | while(optind < argc) 178 | ret = attach_devices_all(argv[optind++]); 179 | break; 180 | case cmd_version: 181 | printf("%s\n", version); 182 | break; 183 | case cmd_help: 184 | show_help(); 185 | break; 186 | default: 187 | show_help(); 188 | } 189 | 190 | 191 | usbip_names_free(); 192 | 193 | cleanup_socket(); 194 | 195 | exit((ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE); 196 | } 197 | 198 | static int query_exported_devices(int sockfd) 199 | { 200 | int ret; 201 | unsigned int i; 202 | int j; 203 | struct op_devlist_reply rep; 204 | uint16_t code = OP_REP_DEVLIST; 205 | 206 | memset(&rep, '\0', sizeof(rep)); 207 | 208 | ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); 209 | if (ret < 0) { 210 | err("send op_common"); 211 | return -1; 212 | } 213 | 214 | ret = usbip_recv_op_common(sockfd, &code); 215 | if (ret < 0) { 216 | err("recv op_common"); 217 | return -1; 218 | } 219 | 220 | ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); 221 | if (ret < 0) { 222 | err("recv op_devlist"); 223 | return -1; 224 | } 225 | 226 | PACK_OP_DEVLIST_REPLY(0, &rep); 227 | dbg("exportable %d devices", rep.ndev); 228 | for (i=0; i < rep.ndev; i++) { 229 | char product_name[100]; 230 | char class_name[100]; 231 | struct usb_device udev; 232 | 233 | memset(&udev, '\0', sizeof(udev)); 234 | 235 | ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); 236 | if (ret < 0) { 237 | err("recv usb_device[%d]", i); 238 | return -1; 239 | } 240 | pack_usb_device(0, &udev); 241 | 242 | usbip_names_get_product(product_name, sizeof(product_name), 243 | udev.idVendor, udev.idProduct); 244 | usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, 245 | udev.bDeviceSubClass, udev.bDeviceProtocol); 246 | 247 | info("%8s: %s", udev.busid, product_name); 248 | info("%8s: %s", " ", udev.path); 249 | info("%8s: %s", " ", class_name); 250 | 251 | for (j=0; j < udev.bNumInterfaces; j++) { 252 | struct usb_interface uinf; 253 | 254 | ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf)); 255 | if (ret < 0) { 256 | err("recv usb_interface[%d]", j); 257 | return -1; 258 | } 259 | 260 | pack_usb_interface(0, &uinf); 261 | usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass, 262 | uinf.bInterfaceSubClass, uinf.bInterfaceProtocol); 263 | 264 | info("%8s: %2d - %s", " ", j, class_name); 265 | } 266 | 267 | info(" "); 268 | } 269 | 270 | return rep.ndev; 271 | } 272 | 273 | int show_exported_devices(char *host) 274 | { 275 | int ret; 276 | int sockfd; 277 | 278 | sockfd = tcp_connect(host, USBIP_PORT_STRING); 279 | if (sockfd < 0) { 280 | err("- %s failed", host); 281 | return -1; 282 | } 283 | 284 | info("- %s", host); 285 | 286 | ret = query_exported_devices(sockfd); 287 | if (ret < 0) { 288 | err("query"); 289 | return -1; 290 | } 291 | 292 | closesocket(sockfd); 293 | return 0; 294 | } 295 | 296 | -------------------------------------------------------------------------------- /userspace/src/usbip.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {36CEE68D-D6CF-4413-978C-794488F44555} 15 | usbip 16 | 17 | 18 | 19 | Application 20 | true 21 | NotSet 22 | 23 | 24 | Application 25 | false 26 | true 27 | NotSet 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | $(ProjectDir)$(Configuration)\ 41 | 42 | 43 | $(ProjectDir)$(Configuration)\ 44 | 45 | 46 | 47 | Level3 48 | Disabled 49 | MultiThreadedDebug 50 | ..\libsrc; windows 51 | 52 | 53 | true 54 | setupapi.lib;ws2_32.lib;$(SolutionDir)$(Configuration)\usbip_common.lib 55 | 56 | 57 | 58 | 59 | Level3 60 | Full 61 | true 62 | true 63 | MultiThreaded 64 | true 65 | true 66 | ..\libsrc; windows 67 | 68 | 69 | true 70 | true 71 | true 72 | setupapi.lib;ws2_32.lib;$(SolutionDir)$(Configuration)\usbip_common.lib 73 | 74 | 75 | 76 | 77 | 78 | 79 | true 80 | true 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /userspace/src/usbip_linux.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: usbip_linux.c 173 2011-03-22 21:59:17Z maxvz $ 3 | * 4 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 5 | */ 6 | 7 | #include "usbip.h" 8 | #include "usbip_network.h" 9 | #include "usbip_osspecific.h" 10 | 11 | /* /sys/devices/platform/vhci_hcd/usb6/6-1/6-1:1.1 -> 1 */ 12 | static int get_interface_number(char *path) 13 | { 14 | char *c; 15 | 16 | c = strstr(path, vhci_driver->hc_device->bus_id); 17 | if (!c) 18 | return -1; /* hc exist? */ 19 | c++; 20 | /* -> usb6/6-1/6-1:1.1 */ 21 | 22 | c = strchr(c, '/'); 23 | if (!c) 24 | return -1; /* hc exist? */ 25 | c++; 26 | /* -> 6-1/6-1:1.1 */ 27 | 28 | c = strchr(c, '/'); 29 | if (!c) 30 | return -1; /* no interface path */ 31 | c++; 32 | /* -> 6-1:1.1 */ 33 | 34 | c = strchr(c, ':'); 35 | if (!c) 36 | return -1; /* no configuration? */ 37 | c++; 38 | /* -> 1.1 */ 39 | 40 | c = strchr(c, '.'); 41 | if (!c) 42 | return -1; /* no interface? */ 43 | c++; 44 | /* -> 1 */ 45 | 46 | 47 | return atoi(c); 48 | } 49 | 50 | 51 | static struct sysfs_device *open_usb_interface(struct usb_device *udev, int i) 52 | { 53 | struct sysfs_device *suinf; 54 | char busid[SYSFS_BUS_ID_SIZE]; 55 | 56 | snprintf(busid, SYSFS_BUS_ID_SIZE, "%s:%d.%d", 57 | udev->busid, udev->bConfigurationValue, i); 58 | 59 | suinf = sysfs_open_device("usb", busid); 60 | if (!suinf) 61 | err("sysfs_open_device %s", busid); 62 | 63 | return suinf; 64 | } 65 | 66 | 67 | #define MAX_BUFF 100 68 | static int record_connection(char *host, char *port, char *busid, int rhport) 69 | { 70 | int fd; 71 | char path[PATH_MAX+1]; 72 | char buff[MAX_BUFF+1]; 73 | int ret; 74 | 75 | mkdir(VHCI_STATE_PATH, 0700); 76 | 77 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); 78 | 79 | fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); 80 | if (fd < 0) 81 | return -1; 82 | 83 | snprintf(buff, MAX_BUFF, "%s %s %s\n", 84 | host, port, busid); 85 | 86 | ret = write(fd, buff, strlen(buff)); 87 | if (ret != (ssize_t) strlen(buff)) { 88 | close(fd); 89 | return -1; 90 | } 91 | 92 | close(fd); 93 | 94 | return 0; 95 | } 96 | 97 | static int read_record(int rhport, char *host, char *port, char *busid) 98 | { 99 | FILE *file; 100 | char path[PATH_MAX+1]; 101 | 102 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); 103 | 104 | file = fopen(path, "r"); 105 | if (!file) { 106 | err("fopen"); 107 | return -1; 108 | } 109 | 110 | if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) { 111 | err("fscanf"); 112 | fclose(file); 113 | return -1; 114 | } 115 | 116 | fclose(file); 117 | 118 | return 0; 119 | } 120 | 121 | 122 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) 123 | { 124 | char product_name[100]; 125 | char host[NI_MAXHOST] = "unknown host"; 126 | char serv[NI_MAXSERV] = "unknown port"; 127 | char remote_busid[SYSFS_BUS_ID_SIZE]; 128 | int ret; 129 | int i; 130 | 131 | if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) { 132 | info("Port %02d: <%s>", idev->port, usbip_status_string(idev->status)); 133 | return 0; 134 | } 135 | 136 | ret = read_record(idev->port, host, serv, remote_busid); 137 | if (ret) { 138 | err("read_record"); 139 | return -1; 140 | } 141 | 142 | info("Port %02d: <%s> at %s", idev->port, 143 | usbip_status_string(idev->status), usbip_speed_string(idev->udev.speed)); 144 | 145 | usbip_names_get_product(product_name, sizeof(product_name), 146 | idev->udev.idVendor, idev->udev.idProduct); 147 | 148 | info(" %s", product_name); 149 | 150 | info("%10s -> usbip://%s:%s/%s (remote devid %08x (bus/dev %03d/%03d))", 151 | idev->udev.busid, host, serv, remote_busid, 152 | idev->devid, 153 | idev->busnum, idev->devnum); 154 | 155 | for (i=0; i < idev->udev.bNumInterfaces; i++) { 156 | /* show interface information */ 157 | struct sysfs_device *suinf; 158 | 159 | suinf = open_usb_interface(&idev->udev, i); 160 | if (!suinf) 161 | continue; 162 | 163 | info(" %6s used by %-17s", suinf->bus_id, suinf->driver_name); 164 | sysfs_close_device(suinf); 165 | 166 | /* show class device information */ 167 | struct class_device *cdev; 168 | 169 | dlist_for_each_data(idev->cdev_list, cdev, struct class_device) { 170 | int ifnum = get_interface_number(cdev->devpath); 171 | if (ifnum == i) { 172 | info(" %s", cdev->clspath); 173 | } 174 | } 175 | } 176 | 177 | return 0; 178 | } 179 | 180 | 181 | 182 | 183 | static int import_device(int sockfd, struct usb_device *udev) 184 | { 185 | int ret; 186 | int port; 187 | 188 | ret = usbip_vhci_driver_open(); 189 | if (ret < 0) { 190 | err("open vhci_driver"); 191 | return -1; 192 | } 193 | 194 | port = usbip_vhci_get_free_port(); 195 | if (port < 0) { 196 | err("no free port"); 197 | usbip_vhci_driver_close(); 198 | return -1; 199 | } 200 | 201 | ret = usbip_vhci_attach_device(port, sockfd, udev->busnum, 202 | udev->devnum, udev->speed); 203 | if (ret < 0) { 204 | err("import device"); 205 | usbip_vhci_driver_close(); 206 | return -1; 207 | } 208 | 209 | usbip_vhci_driver_close(); 210 | 211 | return port; 212 | } 213 | 214 | 215 | static int query_import_device(int sockfd, char *busid) 216 | { 217 | int ret; 218 | struct op_import_request request; 219 | struct op_import_reply reply; 220 | uint16_t code = OP_REP_IMPORT; 221 | 222 | bzero(&request, sizeof(request)); 223 | bzero(&reply, sizeof(reply)); 224 | 225 | 226 | /* send a request */ 227 | ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0); 228 | if (ret < 0) { 229 | err("send op_common"); 230 | return -1; 231 | } 232 | 233 | strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); 234 | 235 | PACK_OP_IMPORT_REQUEST(0, &request); 236 | 237 | ret = usbip_send(sockfd, (void *) &request, sizeof(request)); 238 | if (ret < 0) { 239 | err("send op_import_request"); 240 | return -1; 241 | } 242 | 243 | 244 | /* recieve a reply */ 245 | ret = usbip_recv_op_common(sockfd, &code); 246 | if (ret < 0) { 247 | err("recv op_common"); 248 | return -1; 249 | } 250 | 251 | ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply)); 252 | if (ret < 0) { 253 | err("recv op_import_reply"); 254 | return -1; 255 | } 256 | 257 | PACK_OP_IMPORT_REPLY(0, &reply); 258 | 259 | 260 | /* check the reply */ 261 | if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { 262 | err("recv different busid %s", reply.udev.busid); 263 | return -1; 264 | } 265 | 266 | 267 | /* import a device */ 268 | return import_device(sockfd, &reply.udev); 269 | } 270 | 271 | int attach_device(char *host, char *busid) 272 | { 273 | int sockfd; 274 | int ret; 275 | int rhport; 276 | 277 | sockfd = tcp_connect(host, USBIP_PORT_STRING); 278 | if (sockfd < 0) { 279 | err("tcp connect"); 280 | return -1; 281 | } 282 | 283 | rhport = query_import_device(sockfd, busid); 284 | if (rhport < 0) { 285 | err("query"); 286 | return -1; 287 | } 288 | 289 | close(sockfd); 290 | 291 | ret = record_connection(host, USBIP_PORT_STRING, 292 | busid, rhport); 293 | if (ret < 0) { 294 | err("record connection"); 295 | return -1; 296 | } 297 | 298 | return 0; 299 | } 300 | 301 | int detach_port(char *port) 302 | { 303 | int ret; 304 | uint8_t portnum; 305 | unsigned int i; 306 | 307 | for (i=0; i < strlen(port); i++) 308 | if (!isdigit(port[i])) { 309 | err("invalid port %s", port); 310 | return -1; 311 | } 312 | 313 | /* check max port */ 314 | 315 | portnum = atoi(port); 316 | 317 | ret = usbip_vhci_driver_open(); 318 | if (ret < 0) { 319 | err("open vhci_driver"); 320 | return -1; 321 | } 322 | 323 | ret = usbip_vhci_detach_device(portnum); 324 | if (ret < 0) 325 | return -1; 326 | 327 | usbip_vhci_driver_close(); 328 | 329 | return ret; 330 | } 331 | 332 | static int attach_exported_devices(char *host, int sockfd) 333 | { 334 | int ret; 335 | struct op_devlist_reply rep; 336 | uint16_t code = OP_REP_DEVLIST; 337 | unsigned int i; 338 | int j; 339 | 340 | bzero(&rep, sizeof(rep)); 341 | 342 | ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); 343 | if(ret < 0) { 344 | err("send op_common"); 345 | return -1; 346 | } 347 | 348 | ret = usbip_recv_op_common(sockfd, &code); 349 | if(ret < 0) { 350 | err("recv op_common"); 351 | return -1; 352 | } 353 | 354 | ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); 355 | if(ret < 0) { 356 | err("recv op_devlist"); 357 | return -1; 358 | } 359 | 360 | PACK_OP_DEVLIST_REPLY(0, &rep); 361 | dbg("exportable %d devices", rep.ndev); 362 | 363 | for(i=0; i < rep.ndev; i++) { 364 | char product_name[100]; 365 | char class_name[100]; 366 | struct usb_device udev; 367 | 368 | bzero(&udev, sizeof(udev)); 369 | 370 | ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); 371 | if(ret < 0) { 372 | err("recv usb_device[%d]", i); 373 | return -1; 374 | } 375 | pack_usb_device(0, &udev); 376 | 377 | usbip_names_get_product(product_name, sizeof(product_name), 378 | udev.idVendor, udev.idProduct); 379 | usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, 380 | udev.bDeviceSubClass, udev.bDeviceProtocol); 381 | 382 | dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name); 383 | 384 | for (j=0; j < udev.bNumInterfaces; j++) { 385 | struct usb_interface uinf; 386 | 387 | ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf)); 388 | if (ret < 0) { 389 | err("recv usb_interface[%d]", j); 390 | return -1; 391 | } 392 | 393 | pack_usb_interface(0, &uinf); 394 | usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass, 395 | uinf.bInterfaceSubClass, uinf.bInterfaceProtocol); 396 | 397 | dbg("interface %2d - %s", j, class_name); 398 | } 399 | 400 | attach_device(host, udev.busid); 401 | } 402 | 403 | return rep.ndev; 404 | } 405 | 406 | int attach_devices_all(char *host) 407 | { 408 | int ret; 409 | int sockfd; 410 | 411 | sockfd = tcp_connect(host, USBIP_PORT_STRING); 412 | if(sockfd < 0) { 413 | err("- %s failed", host); 414 | return -1; 415 | } 416 | 417 | info("- %s", host); 418 | 419 | ret = attach_exported_devices(host, sockfd); 420 | if(ret < 0) { 421 | err("query"); 422 | return -1; 423 | } 424 | 425 | close(sockfd); 426 | return 0; 427 | } 428 | 429 | int show_port_status(void) 430 | { 431 | int ret; 432 | struct usbip_imported_device *idev; 433 | int i; 434 | 435 | ret = usbip_vhci_driver_open(); 436 | if (ret < 0) 437 | return ret; 438 | 439 | for (i = 0; i < vhci_driver->nports; i++) { 440 | idev = &vhci_driver->idev[i]; 441 | 442 | if (usbip_vhci_imported_device_dump(idev) < 0) 443 | ret = -1; 444 | } 445 | 446 | usbip_vhci_driver_close(); 447 | 448 | return ret; 449 | } 450 | 451 | int init_socket() 452 | { 453 | return 0; 454 | } 455 | 456 | int cleanup_socket() 457 | { 458 | return 0; 459 | } 460 | -------------------------------------------------------------------------------- /userspace/src/usbip_network.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 4 | */ 5 | 6 | #include "usbip.h" 7 | #include "usbip_network.h" 8 | 9 | void pack_uint32_t(int pack, uint32_t *num) 10 | { 11 | uint32_t i; 12 | 13 | if (pack) 14 | i = htonl(*num); 15 | else 16 | i = ntohl(*num); 17 | 18 | *num = i; 19 | } 20 | 21 | void pack_uint16_t(int pack, uint16_t *num) 22 | { 23 | uint16_t i; 24 | 25 | if (pack) 26 | i = htons(*num); 27 | else 28 | i = ntohs(*num); 29 | 30 | *num = i; 31 | } 32 | 33 | void pack_usb_device(int pack, struct usb_device *udev) 34 | { 35 | pack_uint32_t(pack, &udev->busnum); 36 | pack_uint32_t(pack, &udev->devnum); 37 | pack_uint32_t(pack, &udev->speed ); 38 | 39 | pack_uint16_t(pack, &udev->idVendor ); 40 | pack_uint16_t(pack, &udev->idProduct); 41 | pack_uint16_t(pack, &udev->bcdDevice); 42 | } 43 | 44 | void pack_usb_interface(int pack, struct usb_interface *udev) 45 | { 46 | UNUSED(pack); 47 | UNUSED(udev); 48 | /* uint8_t members need nothing */ 49 | } 50 | 51 | 52 | static ssize_t usbip_xmit(int sockfd, void *buff, size_t bufflen, int sending) 53 | { 54 | ssize_t total = 0; 55 | 56 | if (!bufflen) 57 | return 0; 58 | 59 | do { 60 | ssize_t nbytes; 61 | 62 | if (sending) 63 | nbytes = send(sockfd, buff, bufflen, 0); 64 | else 65 | nbytes = recv(sockfd, buff, bufflen, 0); 66 | 67 | if (nbytes <= 0) { 68 | LPVOID lpMsgBuf; 69 | 70 | // Get error information. 71 | int err = WSAGetLastError(); 72 | 73 | if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL)) { 74 | fprintf(stderr, "[usbip_xmit] recv() returned %d - error %d: %s\n", nbytes, err, lpMsgBuf); 75 | LocalFree(lpMsgBuf); 76 | } else { 77 | fprintf(stderr, "[usbip_xmit] recv() returned %d - error %d\n", nbytes, err); 78 | } 79 | 80 | return -1; 81 | } 82 | 83 | buff = (void *) ((intptr_t) buff + nbytes); 84 | bufflen -= nbytes; 85 | total += nbytes; 86 | 87 | } while (bufflen > 0); 88 | 89 | 90 | return total; 91 | } 92 | 93 | ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen) 94 | { 95 | return usbip_xmit(sockfd, buff, bufflen, 0); 96 | } 97 | 98 | ssize_t usbip_send(int sockfd, void *buff, size_t bufflen) 99 | { 100 | return usbip_xmit(sockfd, buff, bufflen, 1); 101 | } 102 | 103 | int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status) 104 | { 105 | int ret; 106 | struct op_common op_common; 107 | 108 | memset(&op_common, 0, sizeof(op_common)); 109 | 110 | op_common.version = USBIP_VERSION; 111 | op_common.code = code; 112 | op_common.status = status; 113 | 114 | PACK_OP_COMMON(1, &op_common); 115 | 116 | ret = usbip_send(sockfd, (void *) &op_common, sizeof(op_common)); 117 | if (ret < 0) { 118 | err("send op_common"); 119 | return -1; 120 | } 121 | 122 | return 0; 123 | } 124 | 125 | int usbip_recv_op_common(int sockfd, uint16_t *code) 126 | { 127 | int ret; 128 | struct op_common op_common; 129 | 130 | memset(&op_common, '\0', sizeof(op_common)); 131 | 132 | ret = usbip_recv(sockfd, (void *) &op_common, sizeof(op_common)); 133 | if (ret < 0) { 134 | err("recv op_common, %d", ret); 135 | goto err; 136 | } 137 | 138 | PACK_OP_COMMON(0, &op_common); 139 | 140 | if (op_common.version != USBIP_VERSION) { 141 | err("version mismatch, %d %d", op_common.version, USBIP_VERSION); 142 | goto err; 143 | } 144 | 145 | switch(*code) { 146 | case OP_UNSPEC: 147 | break; 148 | default: 149 | if (op_common.code != *code) { 150 | info("unexpected pdu %d for %d", op_common.code, *code); 151 | goto err; 152 | } 153 | } 154 | 155 | if (op_common.status != ST_OK) { 156 | info("request failed at peer, %d", op_common.status); 157 | goto err; 158 | } 159 | 160 | *code = op_common.code; 161 | 162 | return 0; 163 | err: 164 | return -1; 165 | } 166 | 167 | 168 | int usbip_set_reuseaddr(int sockfd) 169 | { 170 | const int val = 1; 171 | int ret; 172 | 173 | ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, sizeof(val)); 174 | if (ret < 0) 175 | err("setsockopt SO_REUSEADDR"); 176 | 177 | return ret; 178 | } 179 | 180 | int usbip_set_nodelay(int sockfd) 181 | { 182 | const int val = 1; 183 | int ret; 184 | 185 | ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); 186 | if (ret < 0) 187 | err("setsockopt TCP_NODELAY"); 188 | 189 | return ret; 190 | } 191 | 192 | int usbip_set_keepalive(int sockfd) 193 | { 194 | const int val = 1; 195 | int ret; 196 | 197 | ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&val, sizeof(val)); 198 | if (ret < 0) 199 | err("setsockopt SO_KEEPALIVE"); 200 | 201 | return ret; 202 | } 203 | 204 | /* IPv6 Ready */ 205 | /* 206 | * moved here from vhci_attach.c 207 | */ 208 | int tcp_connect(char *hostname, char *service) 209 | { 210 | struct addrinfo hints, *res, *res0; 211 | int sockfd; 212 | int err; 213 | 214 | 215 | memset(&hints, 0, sizeof(hints)); 216 | hints.ai_socktype = SOCK_STREAM; 217 | 218 | /* get all possible addresses */ 219 | err = getaddrinfo(hostname, service, &hints, &res0); 220 | if (err) { 221 | err("%s %s: %s", hostname, service, gai_strerror(err)); 222 | return -1; 223 | } 224 | 225 | /* try all the addresses */ 226 | for (res = res0; res; res = res->ai_next) { 227 | char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 228 | 229 | err = getnameinfo(res->ai_addr, res->ai_addrlen, 230 | hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); 231 | if (err) { 232 | err("%s %s: %s", hostname, service, gai_strerror(err)); 233 | continue; 234 | } 235 | 236 | dbg("trying %s port %s\n", hbuf, sbuf); 237 | 238 | sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 239 | if (sockfd < 0) { 240 | err("socket"); 241 | continue; 242 | } 243 | 244 | /* should set TCP_NODELAY for usbip */ 245 | usbip_set_nodelay(sockfd); 246 | /* TODO: write code for heatbeat */ 247 | usbip_set_keepalive(sockfd); 248 | 249 | err = connect(sockfd, res->ai_addr, res->ai_addrlen); 250 | if (err < 0) { 251 | closesocket(sockfd); 252 | continue; 253 | } 254 | 255 | /* connected */ 256 | dbg("connected to %s:%s", hbuf, sbuf); 257 | freeaddrinfo(res0); 258 | return sockfd; 259 | } 260 | 261 | 262 | dbg("%s:%s, %s", hostname, service, "no destination to connect to"); 263 | freeaddrinfo(res0); 264 | 265 | return -1; 266 | } 267 | -------------------------------------------------------------------------------- /userspace/src/usbip_network.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef _USBIP_NETWORK_H 6 | #define _USBIP_NETWORK_H 7 | 8 | #include "usbip.h" 9 | 10 | #ifdef __GNUC__ 11 | #define PACKED __attribute__((__packed__)) 12 | #else 13 | #pragma pack(push,1) 14 | #define PACKED /* */ 15 | #endif 16 | 17 | /* -------------------------------------------------- */ 18 | /* Define Protocol Format */ 19 | /* -------------------------------------------------- */ 20 | 21 | 22 | /* ---------------------------------------------------------------------- */ 23 | /* Common header for all the kinds of PDUs. */ 24 | struct op_common { 25 | uint16_t version; 26 | 27 | #define OP_REQUEST (0x80 << 8) 28 | #define OP_REPLY (0x00 << 8) 29 | uint16_t code; 30 | 31 | /* add more error code */ 32 | #define ST_OK 0x00 33 | #define ST_NA 0x01 34 | uint32_t status; /* op_code status (for reply) */ 35 | 36 | } PACKED; 37 | 38 | #define PACK_OP_COMMON(pack, op_common) do {\ 39 | pack_uint16_t(pack, &(op_common)->version);\ 40 | pack_uint16_t(pack, &(op_common)->code );\ 41 | pack_uint32_t(pack, &(op_common)->status );\ 42 | } while (0) 43 | 44 | 45 | /* ---------------------------------------------------------------------- */ 46 | /* Dummy Code */ 47 | #define OP_UNSPEC 0x00 48 | #define OP_REQ_UNSPEC OP_UNSPEC 49 | #define OP_REP_UNSPEC OP_UNSPEC 50 | 51 | /* ---------------------------------------------------------------------- */ 52 | /* Retrieve USB device information. (still not used) */ 53 | #define OP_DEVINFO 0x02 54 | #define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO) 55 | #define OP_REP_DEVINFO (OP_REPLY | OP_DEVINFO) 56 | 57 | struct op_devinfo_request { 58 | char busid[SYSFS_BUS_ID_SIZE]; 59 | } PACKED; 60 | 61 | struct op_devinfo_reply { 62 | struct usb_device udev; 63 | struct usb_interface uinf[]; 64 | } PACKED; 65 | 66 | 67 | /* ---------------------------------------------------------------------- */ 68 | /* Import a remote USB device. */ 69 | #define OP_IMPORT 0x03 70 | #define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT) 71 | #define OP_REP_IMPORT (OP_REPLY | OP_IMPORT) 72 | 73 | struct op_import_request { 74 | char busid[SYSFS_BUS_ID_SIZE]; 75 | } PACKED; 76 | 77 | struct op_import_reply { 78 | struct usb_device udev; 79 | // struct usb_interface uinf[]; 80 | } PACKED; 81 | 82 | #define PACK_OP_IMPORT_REQUEST(pack, request) do {\ 83 | } while (0) 84 | 85 | #define PACK_OP_IMPORT_REPLY(pack, reply) do {\ 86 | pack_usb_device(pack, &(reply)->udev);\ 87 | } while (0) 88 | 89 | 90 | 91 | /* ---------------------------------------------------------------------- */ 92 | /* Export a USB device to a remote host. */ 93 | #define OP_EXPORT 0x06 94 | #define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT) 95 | #define OP_REP_EXPORT (OP_REPLY | OP_EXPORT) 96 | 97 | struct op_export_request { 98 | struct usb_device udev; 99 | } PACKED; 100 | 101 | struct op_export_reply { 102 | int returncode; 103 | } PACKED; 104 | 105 | 106 | #define PACK_OP_EXPORT_REQUEST(pack, request) do {\ 107 | pack_usb_device(pack, &(request)->udev);\ 108 | } while (0) 109 | 110 | #define PACK_OP_EXPORT_REPLY(pack, reply) do {\ 111 | } while (0) 112 | 113 | /* ---------------------------------------------------------------------- */ 114 | /* un-Export a USB device from a remote host. */ 115 | #define OP_UNEXPORT 0x07 116 | #define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT) 117 | #define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT) 118 | 119 | struct op_unexport_request { 120 | struct usb_device udev; 121 | } PACKED; 122 | 123 | struct op_unexport_reply { 124 | int returncode; 125 | } PACKED; 126 | 127 | #define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\ 128 | pack_usb_device(pack, &(request)->udev);\ 129 | } while (0) 130 | 131 | #define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\ 132 | } while (0) 133 | 134 | 135 | 136 | /* ---------------------------------------------------------------------- */ 137 | /* Negotiate IPSec encryption key. (still not used) */ 138 | #define OP_CRYPKEY 0x04 139 | #define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY) 140 | #define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY) 141 | 142 | struct op_crypkey_request { 143 | /* 128bit key */ 144 | uint32_t key[4]; 145 | } PACKED; 146 | 147 | struct op_crypkey_reply { 148 | uint32_t _reserved; 149 | } PACKED; 150 | 151 | 152 | /* ---------------------------------------------------------------------- */ 153 | /* Retrieve the list of exported USB devices. */ 154 | #define OP_DEVLIST 0x05 155 | #define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST) 156 | #define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST) 157 | 158 | struct op_devlist_request { 159 | /* Struct or union must have at leat one member in MSC */ 160 | uint32_t _reserved; 161 | } PACKED; 162 | 163 | struct op_devlist_reply { 164 | uint32_t ndev; 165 | /* followed by reply_extra[] */ 166 | } PACKED; 167 | 168 | struct op_devlist_reply_extra { 169 | struct usb_device udev; 170 | struct usb_interface uinf[]; 171 | } PACKED; 172 | 173 | #define PACK_OP_DEVLIST_REQUEST(pack, request) do {\ 174 | } while (0) 175 | 176 | #define PACK_OP_DEVLIST_REPLY(pack, reply) do {\ 177 | pack_uint32_t(pack, &(reply)->ndev);\ 178 | } while (0) 179 | 180 | 181 | /* -------------------------------------------------- */ 182 | /* Declare Prototype Function */ 183 | /* -------------------------------------------------- */ 184 | 185 | void pack_uint32_t(int pack, uint32_t *num); 186 | void pack_uint16_t(int pack, uint16_t *num); 187 | void pack_usb_device(int pack, struct usb_device *udev); 188 | void pack_usb_interface(int pack, struct usb_interface *uinf); 189 | 190 | ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen); 191 | ssize_t usbip_send(int sockfd, void *buff, size_t bufflen); 192 | int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status); 193 | int usbip_recv_op_common(int sockfd, uint16_t *code); 194 | int usbip_set_reuseaddr(int sockfd); 195 | int usbip_set_nodelay(int sockfd); 196 | int usbip_set_keepalive(int sockfd); 197 | 198 | int tcp_connect(char *hostname, char *service); 199 | 200 | #define USBIP_PORT 3240 201 | #define USBIP_PORT_STRING "3240" 202 | 203 | #ifdef __GNUC__ 204 | #else 205 | #pragma pack(pop) 206 | #endif 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /userspace/src/usbip_osspecific.h: -------------------------------------------------------------------------------- 1 | #ifndef _USBIP_OS_H 2 | #define _USBIP_OS_H 3 | 4 | int attach_devices_all(char *host); 5 | int show_port_status(void); 6 | int detach_port(char *port); 7 | int attach_device(char *host, char *busid); 8 | int init_socket(); 9 | int cleanup_socket(); 10 | 11 | #endif -------------------------------------------------------------------------------- /userspace/src/usbipd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 4 | */ 5 | 6 | #ifdef HAVE_CONFIG_H 7 | #include "../config.h" 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef HAVE_LIBWRAP 21 | #include 22 | #endif 23 | 24 | #define _GNU_SOURCE 25 | #include 26 | #include 27 | 28 | #include "usbip.h" 29 | #include "usbip_network.h" 30 | 31 | #include 32 | 33 | static const char version[] = PACKAGE_STRING; 34 | 35 | 36 | static int send_reply_devlist(int sockfd) 37 | { 38 | int ret; 39 | struct usbip_exported_device *edev; 40 | struct op_devlist_reply reply; 41 | int i; 42 | 43 | reply.ndev = 0; 44 | 45 | /* how many devices are exported ? */ 46 | dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { 47 | reply.ndev += 1; 48 | } 49 | 50 | dbg("%d devices are exported", reply.ndev); 51 | 52 | ret = usbip_send_op_common(sockfd, OP_REP_DEVLIST, ST_OK); 53 | if (ret < 0) { 54 | err("send op_common"); 55 | return ret; 56 | } 57 | 58 | PACK_OP_DEVLIST_REPLY(1, &reply); 59 | 60 | ret = usbip_send(sockfd, (void *) &reply, sizeof(reply)); 61 | if (ret < 0) { 62 | err("send op_devlist_reply"); 63 | return ret; 64 | } 65 | 66 | dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { 67 | struct usb_device pdu_udev; 68 | 69 | dump_usb_device(&edev->udev); 70 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); 71 | pack_usb_device(1, &pdu_udev); 72 | 73 | ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev)); 74 | if (ret < 0) { 75 | err("send pdu_udev"); 76 | return ret; 77 | } 78 | 79 | for (i=0; i < edev->udev.bNumInterfaces; i++) { 80 | struct usb_interface pdu_uinf; 81 | 82 | dump_usb_interface(&edev->uinf[i]); 83 | memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf)); 84 | pack_usb_interface(1, &pdu_uinf); 85 | 86 | ret = usbip_send(sockfd, (void *) &pdu_uinf, sizeof(pdu_uinf)); 87 | if (ret < 0) { 88 | err("send pdu_uinf"); 89 | return ret; 90 | } 91 | } 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | 98 | static int recv_request_devlist(int sockfd) 99 | { 100 | int ret; 101 | struct op_devlist_request req; 102 | 103 | bzero(&req, sizeof(req)); 104 | 105 | ret = usbip_recv(sockfd, (void *) &req, sizeof(req)); 106 | if (ret < 0) { 107 | err("recv devlist request"); 108 | return -1; 109 | } 110 | 111 | ret = send_reply_devlist(sockfd); 112 | if (ret < 0) { 113 | err("send devlist reply"); 114 | return -1; 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | 121 | static int recv_request_import(int sockfd) 122 | { 123 | int ret; 124 | struct op_import_request req; 125 | struct op_common reply; 126 | struct usbip_exported_device *edev; 127 | int found = 0; 128 | int error = 0; 129 | 130 | bzero(&req, sizeof(req)); 131 | bzero(&reply, sizeof(reply)); 132 | 133 | ret = usbip_recv(sockfd, (void *) &req, sizeof(req)); 134 | if (ret < 0) { 135 | err("recv import request"); 136 | return -1; 137 | } 138 | 139 | PACK_OP_IMPORT_REQUEST(0, &req); 140 | 141 | dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { 142 | if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { 143 | dbg("found requested device %s", req.busid); 144 | found = 1; 145 | break; 146 | } 147 | } 148 | 149 | if (found) { 150 | /* should set TCP_NODELAY for usbip */ 151 | usbip_set_nodelay(sockfd); 152 | 153 | /* export_device needs a TCP/IP socket descriptor */ 154 | ret = usbip_stub_export_device(edev, sockfd); 155 | if (ret < 0) 156 | error = 1; 157 | } else { 158 | info("not found requested device %s", req.busid); 159 | error = 1; 160 | } 161 | 162 | 163 | ret = usbip_send_op_common(sockfd, OP_REP_IMPORT, (!error ? ST_OK : ST_NA)); 164 | if (ret < 0) { 165 | err("send import reply"); 166 | return -1; 167 | } 168 | 169 | if (!error) { 170 | struct usb_device pdu_udev; 171 | 172 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); 173 | pack_usb_device(1, &pdu_udev); 174 | 175 | ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev)); 176 | if (ret < 0) { 177 | err("send devinfo"); 178 | return -1; 179 | } 180 | } 181 | 182 | return 0; 183 | } 184 | 185 | 186 | 187 | static int recv_pdu(int sockfd) 188 | { 189 | int ret; 190 | uint16_t code = OP_UNSPEC; 191 | 192 | 193 | ret = usbip_recv_op_common(sockfd, &code); 194 | if (ret < 0) { 195 | err("recv op_common, %d", ret); 196 | return ret; 197 | } 198 | 199 | 200 | ret = usbip_stub_refresh_device_list(); 201 | if (ret < 0) 202 | return -1; 203 | 204 | switch(code) { 205 | case OP_REQ_DEVLIST: 206 | ret = recv_request_devlist(sockfd); 207 | break; 208 | 209 | case OP_REQ_IMPORT: 210 | ret = recv_request_import(sockfd); 211 | break; 212 | 213 | case OP_REQ_DEVINFO: 214 | case OP_REQ_CRYPKEY: 215 | 216 | default: 217 | err("unknown op_code, %d", code); 218 | ret = -1; 219 | } 220 | 221 | 222 | return ret; 223 | } 224 | 225 | 226 | 227 | 228 | static void log_addrinfo(struct addrinfo *ai) 229 | { 230 | int ret; 231 | char hbuf[NI_MAXHOST]; 232 | char sbuf[NI_MAXSERV]; 233 | 234 | ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), 235 | sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); 236 | if (ret) 237 | err("getnameinfo, %s", gai_strerror(ret)); 238 | 239 | info("listen at [%s]:%s", hbuf, sbuf); 240 | } 241 | 242 | static struct addrinfo *my_getaddrinfo(char *host, int ai_family) 243 | { 244 | int ret; 245 | struct addrinfo hints, *ai_head; 246 | 247 | bzero(&hints, sizeof(hints)); 248 | 249 | hints.ai_family = ai_family; 250 | hints.ai_socktype = SOCK_STREAM; 251 | hints.ai_flags = AI_PASSIVE; 252 | 253 | ret = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head); 254 | if (ret) { 255 | err("%s: %s", USBIP_PORT_STRING, gai_strerror(ret)); 256 | return NULL; 257 | } 258 | 259 | return ai_head; 260 | } 261 | 262 | #define MAXSOCK 20 263 | static int listen_all_addrinfo(struct addrinfo *ai_head, int lsock[]) 264 | { 265 | struct addrinfo *ai; 266 | int n = 0; /* number of sockets */ 267 | 268 | for (ai = ai_head; ai && n < MAXSOCK; ai = ai->ai_next) { 269 | int ret; 270 | 271 | lsock[n] = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 272 | if (lsock[n] < 0) 273 | continue; 274 | 275 | usbip_set_reuseaddr(lsock[n]); 276 | usbip_set_nodelay(lsock[n]); 277 | 278 | if (lsock[n] >= FD_SETSIZE) { 279 | close(lsock[n]); 280 | lsock[n] = -1; 281 | continue; 282 | } 283 | 284 | ret = bind(lsock[n], ai->ai_addr, ai->ai_addrlen); 285 | if (ret < 0) { 286 | close(lsock[n]); 287 | lsock[n] = -1; 288 | continue; 289 | } 290 | 291 | ret = listen(lsock[n], SOMAXCONN); 292 | if (ret < 0) { 293 | close(lsock[n]); 294 | lsock[n] = -1; 295 | continue; 296 | } 297 | 298 | log_addrinfo(ai); 299 | 300 | /* next if succeed */ 301 | n++; 302 | } 303 | 304 | if (n == 0) { 305 | err("no socket to listen to"); 306 | return -1; 307 | } 308 | 309 | dbg("listen %d address%s", n, (n==1)?"":"es"); 310 | 311 | return n; 312 | } 313 | 314 | #ifdef HAVE_LIBWRAP 315 | static int tcpd_auth(int csock) 316 | { 317 | int ret; 318 | struct request_info request; 319 | 320 | request_init(&request, RQ_DAEMON, "usbipd", RQ_FILE, csock, 0); 321 | 322 | fromhost(&request); 323 | 324 | ret = hosts_access(&request); 325 | if (!ret) 326 | return -1; 327 | 328 | return 0; 329 | } 330 | #endif 331 | 332 | static int my_accept(int lsock) 333 | { 334 | int csock; 335 | struct sockaddr_storage ss; 336 | socklen_t len = sizeof(ss); 337 | char host[NI_MAXHOST], port[NI_MAXSERV]; 338 | int ret; 339 | 340 | bzero(&ss, sizeof(ss)); 341 | 342 | csock = accept(lsock, (struct sockaddr *) &ss, &len); 343 | if (csock < 0) { 344 | err("accept"); 345 | return -1; 346 | } 347 | 348 | ret = getnameinfo((struct sockaddr *) &ss, len, 349 | host, sizeof(host), port, sizeof(port), 350 | (NI_NUMERICHOST | NI_NUMERICSERV)); 351 | if (ret) 352 | err("getnameinfo, %s", gai_strerror(ret)); 353 | 354 | #ifdef HAVE_LIBWRAP 355 | ret = tcpd_auth(csock); 356 | if (ret < 0) { 357 | info("deny access from %s", host); 358 | close(csock); 359 | return -1; 360 | } 361 | #endif 362 | 363 | info("connected from %s:%s", host, port); 364 | 365 | return csock; 366 | } 367 | 368 | 369 | GMainLoop *main_loop; 370 | 371 | static void signal_handler(int i) 372 | { 373 | dbg("signal catched, code %d", i); 374 | 375 | if (main_loop) 376 | g_main_loop_quit(main_loop); 377 | } 378 | 379 | static void set_signal(void) 380 | { 381 | struct sigaction act; 382 | 383 | bzero(&act, sizeof(act)); 384 | act.sa_handler = signal_handler; 385 | sigemptyset(&act.sa_mask); 386 | sigaction(SIGTERM, &act, NULL); 387 | sigaction(SIGINT, &act, NULL); 388 | } 389 | 390 | 391 | gboolean process_comming_request(GIOChannel *gio, GIOCondition condition, 392 | gpointer data __attribute__((unused))) 393 | { 394 | int ret; 395 | 396 | if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) 397 | g_error("unknown condition"); 398 | 399 | 400 | if (condition & G_IO_IN) { 401 | int lsock; 402 | int csock; 403 | 404 | lsock = g_io_channel_unix_get_fd(gio); 405 | 406 | csock = my_accept(lsock); 407 | if (csock < 0) 408 | return TRUE; 409 | 410 | ret = recv_pdu(csock); 411 | if (ret < 0) 412 | err("process recieved pdu"); 413 | 414 | close(csock); 415 | } 416 | 417 | return TRUE; 418 | } 419 | 420 | 421 | static void do_standalone_mode(gboolean daemonize) 422 | { 423 | int ret; 424 | int lsock[MAXSOCK]; 425 | struct addrinfo *ai_head; 426 | int n; 427 | int i; 428 | 429 | ret = usbip_names_init(USBIDS_FILE); 430 | if (ret) 431 | err("open usb.ids"); 432 | 433 | ret = usbip_stub_driver_open(); 434 | if (ret < 0) 435 | g_error("driver open failed"); 436 | 437 | if (daemonize) { 438 | if (daemon(0,0) < 0) 439 | g_error("daemonizing failed: %s", g_strerror(errno)); 440 | 441 | usbip_use_syslog = 1; 442 | } 443 | 444 | set_signal(); 445 | 446 | ai_head = my_getaddrinfo(NULL, PF_UNSPEC); 447 | if (!ai_head) 448 | return; 449 | 450 | n = listen_all_addrinfo(ai_head, lsock); 451 | if (n <= 0) 452 | g_error("no socket to listen to"); 453 | 454 | for (i = 0; i < n; i++) { 455 | GIOChannel *gio; 456 | 457 | gio = g_io_channel_unix_new(lsock[i]); 458 | g_io_add_watch(gio, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), 459 | process_comming_request, NULL); 460 | } 461 | 462 | 463 | info("usbipd start (%s)", version); 464 | 465 | 466 | main_loop = g_main_loop_new(FALSE, FALSE); 467 | g_main_loop_run(main_loop); 468 | 469 | info("shutdown"); 470 | 471 | freeaddrinfo(ai_head); 472 | usbip_names_free(); 473 | usbip_stub_driver_close(); 474 | 475 | return; 476 | } 477 | 478 | 479 | static const char help_message[] = "\ 480 | Usage: usbipd [options] \n\ 481 | -D, --daemon \n\ 482 | Run as a daemon process. \n\ 483 | \n\ 484 | -d, --debug \n\ 485 | Print debugging information. \n\ 486 | \n\ 487 | -v, --version \n\ 488 | Show version. \n\ 489 | \n\ 490 | -h, --help \n\ 491 | Print this help. \n"; 492 | 493 | static void show_help(void) 494 | { 495 | printf("%s", help_message); 496 | } 497 | 498 | static const struct option longopts[] = { 499 | {"daemon", no_argument, NULL, 'D'}, 500 | {"debug", no_argument, NULL, 'd'}, 501 | {"version", no_argument, NULL, 'v'}, 502 | {"help", no_argument, NULL, 'h'}, 503 | {NULL, 0, NULL, 0} 504 | }; 505 | 506 | int main(int argc, char *argv[]) 507 | { 508 | gboolean daemonize = FALSE; 509 | 510 | enum { 511 | cmd_standalone_mode = 1, 512 | cmd_help, 513 | cmd_version 514 | } cmd = cmd_standalone_mode; 515 | 516 | 517 | usbip_use_stderr = 1; 518 | usbip_use_syslog = 0; 519 | 520 | if (geteuid() != 0) 521 | g_warning("running non-root?"); 522 | 523 | for (;;) { 524 | int c; 525 | int index = 0; 526 | 527 | c = getopt_long(argc, argv, "vhdD", longopts, &index); 528 | 529 | if (c == -1) 530 | break; 531 | 532 | switch (c) { 533 | case 'd': 534 | usbip_use_debug = 1; 535 | continue; 536 | case 'v': 537 | cmd = cmd_version; 538 | break; 539 | case 'h': 540 | cmd = cmd_help; 541 | break; 542 | case 'D': 543 | daemonize = TRUE; 544 | break; 545 | case '?': 546 | show_help(); 547 | exit(EXIT_FAILURE); 548 | default: 549 | err("getopt"); 550 | } 551 | } 552 | 553 | switch (cmd) { 554 | case cmd_standalone_mode: 555 | do_standalone_mode(daemonize); 556 | break; 557 | case cmd_version: 558 | printf("%s\n", version); 559 | break; 560 | case cmd_help: 561 | show_help(); 562 | break; 563 | default: 564 | info("unknown cmd"); 565 | show_help(); 566 | } 567 | 568 | return 0; 569 | } 570 | -------------------------------------------------------------------------------- /userspace/src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 4 | */ 5 | 6 | #include "utils.h" 7 | 8 | int read_integer(char *path) 9 | { 10 | char buff[100]; 11 | int fd; 12 | int ret = 0; 13 | 14 | bzero(buff, sizeof(buff)); 15 | 16 | fd = open(path, O_RDONLY); 17 | if (fd < 0) 18 | return -1; 19 | 20 | ret = read(fd, buff, sizeof(buff)); 21 | if (ret < 0) { 22 | close(fd); 23 | return -1; 24 | } 25 | 26 | sscanf(buff, "%d", &ret); 27 | 28 | close(fd); 29 | 30 | return ret; 31 | } 32 | 33 | int read_string(char *path, char *string, size_t len) 34 | { 35 | int fd; 36 | int ret = 0; 37 | char *p; 38 | 39 | bzero(string, len); 40 | 41 | fd = open(path, O_RDONLY); 42 | if (fd < 0) { 43 | string = NULL; 44 | return -1; 45 | } 46 | 47 | ret = read(fd, string, len-1); 48 | if (ret < 0) { 49 | string = NULL; 50 | close(fd); 51 | return -1; 52 | } 53 | 54 | p = strchr(string, '\n'); 55 | *p = '\0'; 56 | 57 | close(fd); 58 | 59 | return 0; 60 | } 61 | 62 | int write_integer(char *path, int value) 63 | { 64 | int fd; 65 | int ret; 66 | char buff[100]; 67 | 68 | snprintf(buff, sizeof(buff), "%d", value); 69 | 70 | fd = open(path, O_WRONLY); 71 | if (fd < 0) 72 | return -1; 73 | 74 | ret = write(fd, buff, strlen(buff)); 75 | if (ret < 0) { 76 | close(fd); 77 | return -1; 78 | } 79 | 80 | close(fd); 81 | 82 | return 0; 83 | } 84 | 85 | int read_bConfigurationValue(char *busid) 86 | { 87 | char path[PATH_MAX]; 88 | 89 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bConfigurationValue", busid); 90 | 91 | return read_integer(path); 92 | } 93 | 94 | int write_bConfigurationValue(char *busid, int config) 95 | { 96 | char path[PATH_MAX]; 97 | 98 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bConfigurationValue", busid); 99 | 100 | return write_integer(path, config); 101 | } 102 | 103 | int read_bNumInterfaces(char *busid) 104 | { 105 | char path[PATH_MAX]; 106 | 107 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bNumInterfaces", busid); 108 | 109 | return read_integer(path); 110 | } 111 | 112 | int read_bDeviceClass(char *busid) 113 | { 114 | char path[PATH_MAX]; 115 | 116 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bDeviceClass", busid); 117 | 118 | return read_integer(path); 119 | } 120 | 121 | int getdriver(char *busid, int conf, int infnum, char *driver, size_t len) 122 | { 123 | char path[PATH_MAX]; 124 | char linkto[PATH_MAX]; 125 | int ret; 126 | 127 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s:%d.%d/driver", busid, conf, infnum); 128 | 129 | /* readlink does not add NULL */ 130 | bzero(linkto, sizeof(linkto)); 131 | ret = readlink(path, linkto, sizeof(linkto)-1); 132 | if (ret < 0) { 133 | strncpy(driver, "none", len); 134 | return -1; 135 | } else { 136 | strncpy(driver, basename(linkto), len); 137 | return 0; 138 | } 139 | } 140 | 141 | int getdevicename(char *busid, char *name, size_t len) 142 | { 143 | char path[PATH_MAX]; 144 | char idProduct[10], idVendor[10]; 145 | 146 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/idVendor", busid); 147 | read_string(path, idVendor, sizeof(idVendor)); 148 | 149 | snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/idProduct", busid); 150 | read_string(path, idProduct, sizeof(idProduct)); 151 | 152 | if (!idVendor[0] || !idProduct[0]) 153 | return -1; 154 | 155 | snprintf(name, len, "%s:%s", idVendor, idProduct); 156 | 157 | return 0; 158 | } 159 | 160 | #define MAXLINE 100 161 | 162 | /* if this cannot read a whole line, return -1 */ 163 | int readline(int sockfd, char *buff, int bufflen) 164 | { 165 | int ret; 166 | char c; 167 | int index = 0; 168 | 169 | 170 | while (index < bufflen) { 171 | ret = read(sockfd, &c, sizeof(c)); 172 | if (ret < 0 && errno == EINTR) 173 | continue; 174 | if (ret <= 0) { 175 | return -1; 176 | } 177 | 178 | buff[index] = c; 179 | 180 | if ( index > 0 && buff[index-1] == '\r' && buff[index] == '\n') { 181 | /* end of line */ 182 | buff[index-1] = '\0'; /* get rid of delimitor */ 183 | return index; 184 | } else 185 | index++; 186 | } 187 | 188 | return -1; 189 | } 190 | 191 | #if 0 192 | int writeline(int sockfd, char *str, int strlen) 193 | { 194 | int ret; 195 | int index = 0; 196 | int len; 197 | char buff[MAXLINE]; 198 | 199 | if (strlen + 3 > MAXLINE) 200 | return -1; 201 | 202 | strncpy(buff, str, strlen); 203 | buff[strlen+1] = '\r'; 204 | buff[strlen+2] = '\n'; 205 | buff[strlen+3] = '\0'; 206 | 207 | len = strlen + 3; 208 | 209 | while (len > 0) { 210 | ret = write(sockfd, buff+index, len); 211 | if (ret <= 0) { 212 | return -1; 213 | } 214 | 215 | len -= ret; 216 | index += ret; 217 | } 218 | 219 | return index; 220 | } 221 | #endif 222 | 223 | int writeline(int sockfd, char *str, int strlen) 224 | { 225 | int ret; 226 | int index = 0; 227 | int len; 228 | char buff[MAXLINE]; 229 | 230 | len = strnlen(str, strlen); 231 | 232 | if (strlen + 2 > MAXLINE) 233 | return -1; 234 | 235 | memcpy(buff, str, strlen); 236 | buff[strlen] = '\r'; 237 | buff[strlen+1] = '\n'; /* strlen+1 <= MAXLINE-1 */ 238 | 239 | len = strlen + 2; 240 | 241 | while (len > 0) { 242 | ret = write(sockfd, buff+index, len); 243 | if (ret < 0 && errno == EINTR) 244 | continue; 245 | if (ret <= 0) { 246 | return -1; 247 | } 248 | 249 | len -= ret; 250 | index += ret; 251 | } 252 | 253 | return index; 254 | } 255 | 256 | -------------------------------------------------------------------------------- /userspace/src/utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifdef HAVE_CONFIG_H 3 | #include "../config.h" 4 | #endif 5 | 6 | #define _GNU_SOURCE 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | 25 | /* Be sync to kernel header */ 26 | #define BUS_ID_SIZE 20 27 | 28 | int read_string(char *path, char *, size_t len); 29 | int read_integer(char *path); 30 | int getdevicename(char *busid, char *name, size_t len); 31 | int getdriver(char *busid, int conf, int infnum, char *driver, size_t len); 32 | int read_bNumInterfaces(char *busid); 33 | int read_bConfigurationValue(char *busid); 34 | int write_integer(char *path, int value); 35 | int write_bConfigurationValue(char *busid, int config); 36 | int read_bDeviceClass(char *busid); 37 | int readline(int sockfd, char *str, int strlen); 38 | int writeline(int sockfd, char *buff, int bufflen); 39 | -------------------------------------------------------------------------------- /userspace/src/windows/getopt.c: -------------------------------------------------------------------------------- 1 | /* 2 | Newsgroups: mod.std.unix 3 | Subject: public domain AT&T getopt source 4 | Date: 3 Nov 85 19:34:15 GMT 5 | 6 | Here's something you've all been waiting for: the AT&T public domain 7 | source for getopt(3). It is the code which was given out at the 1985 8 | UNIFORUM conference in Dallas. I obtained it by electronic mail 9 | directly from AT&T. The people there assure me that it is indeed 10 | in the public domain. 11 | */ 12 | 13 | /*LINTLIBRARY*/ 14 | 15 | extern unsigned int strlen(); 16 | extern int strcmp(); 17 | extern char *strchr(); 18 | extern int write(); 19 | 20 | #define NULL 0 21 | #define EOF (-1) 22 | #define ERR(s, c) if(opterr){\ 23 | char errbuf[2];\ 24 | errbuf[0] = c; errbuf[1] = '\n';\ 25 | (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ 26 | (void) write(2, s, (unsigned)strlen(s));\ 27 | (void) write(2, errbuf, 2);} 28 | 29 | 30 | int opterr = 1; 31 | int optind = 1; 32 | int optopt; 33 | char *optarg; 34 | 35 | int 36 | getopt(argc, argv, opts) 37 | int argc; 38 | char **argv, *opts; 39 | { 40 | static int sp = 1; 41 | register int c; 42 | register char *cp; 43 | 44 | if(sp == 1) 45 | if(optind >= argc || 46 | argv[optind][0] != '-' || argv[optind][1] == '\0') 47 | return(EOF); 48 | else if(strcmp(argv[optind], "--") == NULL) { 49 | optind++; 50 | return(EOF); 51 | } 52 | optopt = c = argv[optind][sp]; 53 | if(c == ':' || (cp=strchr(opts, c)) == NULL) { 54 | ERR(": illegal option -- ", c); 55 | if(argv[optind][++sp] == '\0') { 56 | optind++; 57 | sp = 1; 58 | } 59 | return('?'); 60 | } 61 | if(*++cp == ':') { 62 | if(argv[optind][sp+1] != '\0') 63 | optarg = &argv[optind++][sp+1]; 64 | else if(++optind >= argc) { 65 | ERR(": option requires an argument -- ", c); 66 | sp = 1; 67 | return('?'); 68 | } else 69 | optarg = argv[optind++]; 70 | sp = 1; 71 | } else { 72 | if(argv[optind][++sp] == '\0') { 73 | sp = 1; 74 | optind++; 75 | } 76 | optarg = NULL; 77 | } 78 | return(c); 79 | } 80 | -------------------------------------------------------------------------------- /userspace/src/windows/getopt.h: -------------------------------------------------------------------------------- 1 | /* libext+gcc: getopt.h - $Id: getopt.h,v 1.1 2003/03/13 23:18:17 neis Exp $*/ 2 | 3 | /*- 4 | * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 | * All rights reserved. 6 | * 7 | * This code is derived from software contributed to The NetBSD Foundation 8 | * by Dieter Baron and Thomas Klausner. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 3. All advertising materials mentioning features or use of this software 19 | * must display the following acknowledgement: 20 | * This product includes software developed by the NetBSD 21 | * Foundation, Inc. and its contributors. 22 | * 4. Neither the name of The NetBSD Foundation nor the names of its 23 | * contributors may be used to endorse or promote products derived 24 | * from this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | #ifndef _GETOPT_H_ 40 | #define _GETOPT_H_ 41 | 42 | //#include 43 | 44 | /* 45 | * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions 46 | */ 47 | #define no_argument 0 48 | #define required_argument 1 49 | #define optional_argument 2 50 | 51 | struct option { 52 | /* name of long option */ 53 | const char *name; 54 | /* 55 | * one of no_argument, required_argument, and optional_argument: 56 | * whether option takes an argument 57 | */ 58 | int has_arg; 59 | /* if not NULL, set *flag to val when option found */ 60 | int *flag; 61 | /* if flag not NULL, value to set *flag to; else return value */ 62 | int val; 63 | }; 64 | 65 | int getopt_long(int, char * const *, const char *, 66 | const struct option *, int *); 67 | int getopt_long_only(int, char * const *, const char *, 68 | const struct option *, int *); 69 | #ifndef _GETOPT_DEFINED_ 70 | #define _GETOPT_DEFINED_ 71 | int getopt(int, char * const *, const char *); 72 | int getsubopt(char **, char * const *, char **); 73 | 74 | extern char *optarg; /* getopt(3) external variables */ 75 | extern int opterr; 76 | extern int optind; 77 | extern int optopt; 78 | extern int optreset; 79 | extern char *suboptarg; /* getsubopt(3) external variable */ 80 | #endif 81 | 82 | #endif /* !_GETOPT_H_ */ 83 | -------------------------------------------------------------------------------- /userspace/src/windows/usbip_vbus_ui.h: -------------------------------------------------------------------------------- 1 | #ifndef _USBIP_VBUS_UI_H 2 | #define _USBIP_VBUS_UI_H 3 | /* char * usbip_vbus_dev_node_name(char *buf, int buf_len); */ 4 | HANDLE usbip_vbus_open(void); 5 | int usbip_vbus_get_free_port(HANDLE fd); 6 | int usbip_vbus_get_ports_status(HANDLE fd, char *buf, int len); 7 | int usbip_vbus_attach_device(HANDLE fd, int port, 8 | struct usb_device *udev, struct usb_interface * uinf0); 9 | int usbip_vbus_detach_device(HANDLE fd, int port); 10 | void usbip_vbus_forward(SOCKET sockfd, HANDLE devfd); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /userspace/src/windows/usbip_windows_kernel_api.h: -------------------------------------------------------------------------------- 1 | // 2 | // Define an Interface Guid for bus enumerator class. 3 | // This GUID is used to register (IoRegisterDeviceInterface) 4 | // an instance of an interface so that enumerator application 5 | // can send an ioctl to the bus driver. 6 | // 7 | 8 | DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_USBIP, 9 | 0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 10 | 11 | 12 | // 13 | // Define a Setup Class GUID for USBIP Class. This is same 14 | // as the TOASTSER CLASS guid in the INF files. 15 | // 16 | 17 | DEFINE_GUID (GUID_DEVCLASS_USBIP, 18 | 0xB85B7C50, 0x6A01, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 19 | //{B85B7C50-6A01-11d2-B841-00C04FAD5171} 20 | 21 | // 22 | // Define a WMI GUID to get busenum info. 23 | // 24 | 25 | DEFINE_GUID (USBIP_BUS_WMI_STD_DATA_GUID, 26 | 0x0006A660, 0x8F12, 0x11d2, 0xB8, 0x54, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 27 | //{0006A660-8F12-11d2-B854-00C04FAD5171} 28 | 29 | // 30 | // Define a WMI GUID to get USBIP device info. 31 | // 32 | 33 | DEFINE_GUID (USBIP_WMI_STD_DATA_GUID, 34 | 0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); 35 | 36 | // 37 | // Define a WMI GUID to represent device arrival notification WMIEvent class. 38 | // 39 | 40 | DEFINE_GUID (USBIP_NOTIFY_DEVICE_ARRIVAL_EVENT, 41 | 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c); 42 | // {01CDAFF1-C901-45b4-B359-B5542725E29C} 43 | 44 | 45 | // 46 | // GUID definition are required to be outside of header inclusion pragma to avoid 47 | // error during precompiled headers. 48 | // 49 | 50 | #ifndef __PUBLIC_H 51 | #define __PUBLIC_H 52 | 53 | #define USBVBUS_IOCTL(_index_) \ 54 | CTL_CODE (FILE_DEVICE_BUS_EXTENDER, _index_, METHOD_BUFFERED, FILE_READ_DATA) 55 | 56 | #define IOCTL_USBVBUS_PLUGIN_HARDWARE USBVBUS_IOCTL (0x0) 57 | #define IOCTL_USBVBUS_UNPLUG_HARDWARE USBVBUS_IOCTL (0x1) 58 | #define IOCTL_USBVBUS_EJECT_HARDWARE USBVBUS_IOCTL (0x2) 59 | #define IOCTL_USBVBUS_GET_PORTS_STATUS USBVBUS_IOCTL (0x3) 60 | 61 | #define COMPATIBLE_IDS_SAMPLE L"USB\\Class_00&SubClass_00&Prot_00\0USB\\Class_00&SubClass_00\0USB\\Class_00\0" 62 | 63 | #define BUSENUM_COMPATIBLE_IDS_LENGTH sizeof(COMPATIBLE_IDS_SAMPLE) 64 | 65 | typedef struct _ioctl_usbvbus_plugin 66 | { 67 | unsigned int devid; 68 | /* 4 bytes */ 69 | unsigned short vendor; 70 | unsigned short product; 71 | /* 8 bytes */ 72 | unsigned short version; 73 | unsigned char speed; 74 | unsigned char inum; 75 | /* 12 bytes */ 76 | unsigned char int0_class; 77 | unsigned char int0_subclass; 78 | unsigned char int0_protocol; 79 | signed char addr; /* then it can not be bigger then 127 */ 80 | /* 16 bytes */ 81 | } ioctl_usbvbus_plugin; 82 | 83 | typedef struct _ioctl_usbvbus_get_ports_status 84 | { 85 | union { 86 | signed char max_used_port; /* then it can not be bigger than 127 */ 87 | unsigned char port_status[128]; 88 | /* 128 bytes */ 89 | }; 90 | } ioctl_usbvbus_get_ports_status; 91 | 92 | typedef struct _ioctl_usbvbus_unplug 93 | { 94 | signed char addr; 95 | char unused[3]; 96 | 97 | } ioctl_usbvbus_unplug; 98 | 99 | typedef struct _BUSENUM_EJECT_HARDWARE 100 | { 101 | // 102 | // sizeof (struct _EJECT_HARDWARE) 103 | // 104 | 105 | ULONG Size; 106 | 107 | // 108 | // Serial number of the device to be ejected 109 | // 110 | 111 | ULONG SerialNo; 112 | 113 | ULONG Reserved[2]; 114 | 115 | } BUSENUM_EJECT_HARDWARE, *PBUSENUM_EJECT_HARDWARE; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /userspace/usb.ids: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spurious/usbip-windows-mirror/1e5e567eec456da0c73c37d6f3d6b11cfae2e388/userspace/usb.ids -------------------------------------------------------------------------------- /userspace/usbip.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{104306E1-1D27-4B28-88FF-F4B3934A1CD5}" 5 | ProjectSection(SolutionItems) = preProject 6 | Todo.txt = Todo.txt 7 | EndProjectSection 8 | EndProject 9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbip", "src\usbip.vcxproj", "{36CEE68D-D6CF-4413-978C-794488F44555}" 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbip_common", "libsrc\usbip_common.vcxproj", "{2C173853-88C0-4334-85BF-0B46CFD5A007}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Release|Win32 = Release|Win32 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {36CEE68D-D6CF-4413-978C-794488F44555}.Debug|Win32.ActiveCfg = Debug|Win32 20 | {36CEE68D-D6CF-4413-978C-794488F44555}.Debug|Win32.Build.0 = Debug|Win32 21 | {36CEE68D-D6CF-4413-978C-794488F44555}.Release|Win32.ActiveCfg = Release|Win32 22 | {36CEE68D-D6CF-4413-978C-794488F44555}.Release|Win32.Build.0 = Release|Win32 23 | {2C173853-88C0-4334-85BF-0B46CFD5A007}.Debug|Win32.ActiveCfg = Debug|Win32 24 | {2C173853-88C0-4334-85BF-0B46CFD5A007}.Debug|Win32.Build.0 = Debug|Win32 25 | {2C173853-88C0-4334-85BF-0B46CFD5A007}.Release|Win32.ActiveCfg = Release|Win32 26 | {2C173853-88C0-4334-85BF-0B46CFD5A007}.Release|Win32.Build.0 = Release|Win32 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | --------------------------------------------------------------------------------