diff options
Diffstat (limited to 'tools')
40 files changed, 5636 insertions, 11 deletions
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile index 5386fd7c43ae..74bbefdeaf4c 100644 --- a/tools/testing/selftests/ipc/Makefile +++ b/tools/testing/selftests/ipc/Makefile | |||
| @@ -1,18 +1,18 @@ | |||
| 1 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 1 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
| 2 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) | 2 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) |
| 3 | ifeq ($(ARCH),i386) | 3 | ifeq ($(ARCH),i386) |
| 4 | ARCH := X86 | 4 | ARCH := x86 |
| 5 | CFLAGS := -DCONFIG_X86_32 -D__i386__ | 5 | CFLAGS := -DCONFIG_X86_32 -D__i386__ |
| 6 | endif | 6 | endif |
| 7 | ifeq ($(ARCH),x86_64) | 7 | ifeq ($(ARCH),x86_64) |
| 8 | ARCH := X86 | 8 | ARCH := x86 |
| 9 | CFLAGS := -DCONFIG_X86_64 -D__x86_64__ | 9 | CFLAGS := -DCONFIG_X86_64 -D__x86_64__ |
| 10 | endif | 10 | endif |
| 11 | 11 | ||
| 12 | CFLAGS += -I../../../../usr/include/ | 12 | CFLAGS += -I../../../../usr/include/ |
| 13 | 13 | ||
| 14 | all: | 14 | all: |
| 15 | ifeq ($(ARCH),X86) | 15 | ifeq ($(ARCH),x86) |
| 16 | gcc $(CFLAGS) msgque.c -o msgque_test | 16 | gcc $(CFLAGS) msgque.c -o msgque_test |
| 17 | else | 17 | else |
| 18 | echo "Not an x86 target, can't build msgque selftest" | 18 | echo "Not an x86 target, can't build msgque selftest" |
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile index d7d6bbeeff2f..8aabd82db9e4 100644 --- a/tools/testing/selftests/kcmp/Makefile +++ b/tools/testing/selftests/kcmp/Makefile | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 1 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
| 2 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) | 2 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) |
| 3 | ifeq ($(ARCH),i386) | 3 | ifeq ($(ARCH),i386) |
| 4 | ARCH := X86 | 4 | ARCH := x86 |
| 5 | CFLAGS := -DCONFIG_X86_32 -D__i386__ | 5 | CFLAGS := -DCONFIG_X86_32 -D__i386__ |
| 6 | endif | 6 | endif |
| 7 | ifeq ($(ARCH),x86_64) | 7 | ifeq ($(ARCH),x86_64) |
| 8 | ARCH := X86 | 8 | ARCH := x86 |
| 9 | CFLAGS := -DCONFIG_X86_64 -D__x86_64__ | 9 | CFLAGS := -DCONFIG_X86_64 -D__x86_64__ |
| 10 | endif | 10 | endif |
| 11 | 11 | ||
| @@ -15,7 +15,7 @@ CFLAGS += -I../../../../usr/include/ | |||
| 15 | CFLAGS += -I../../../../arch/x86/include/ | 15 | CFLAGS += -I../../../../arch/x86/include/ |
| 16 | 16 | ||
| 17 | all: | 17 | all: |
| 18 | ifeq ($(ARCH),X86) | 18 | ifeq ($(ARCH),x86) |
| 19 | gcc $(CFLAGS) kcmp_test.c -o kcmp_test | 19 | gcc $(CFLAGS) kcmp_test.c -o kcmp_test |
| 20 | else | 20 | else |
| 21 | echo "Not an x86 target, can't build kcmp selftest" | 21 | echo "Not an x86 target, can't build kcmp selftest" |
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile index 6816c491c5ff..ad4ab01cd28f 100644 --- a/tools/testing/selftests/memfd/Makefile +++ b/tools/testing/selftests/memfd/Makefile | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 1 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
| 2 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) | 2 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) |
| 3 | ifeq ($(ARCH),i386) | 3 | ifeq ($(ARCH),i386) |
| 4 | ARCH := X86 | 4 | ARCH := x86 |
| 5 | endif | 5 | endif |
| 6 | ifeq ($(ARCH),x86_64) | 6 | ifeq ($(ARCH),x86_64) |
| 7 | ARCH := X86 | 7 | ARCH := x86 |
| 8 | endif | 8 | endif |
| 9 | 9 | ||
| 10 | CFLAGS += -D_FILE_OFFSET_BITS=64 | 10 | CFLAGS += -D_FILE_OFFSET_BITS=64 |
| @@ -14,20 +14,20 @@ CFLAGS += -I../../../../include/uapi/ | |||
| 14 | CFLAGS += -I../../../../include/ | 14 | CFLAGS += -I../../../../include/ |
| 15 | 15 | ||
| 16 | all: | 16 | all: |
| 17 | ifeq ($(ARCH),X86) | 17 | ifeq ($(ARCH),x86) |
| 18 | gcc $(CFLAGS) memfd_test.c -o memfd_test | 18 | gcc $(CFLAGS) memfd_test.c -o memfd_test |
| 19 | else | 19 | else |
| 20 | echo "Not an x86 target, can't build memfd selftest" | 20 | echo "Not an x86 target, can't build memfd selftest" |
| 21 | endif | 21 | endif |
| 22 | 22 | ||
| 23 | run_tests: all | 23 | run_tests: all |
| 24 | ifeq ($(ARCH),X86) | 24 | ifeq ($(ARCH),x86) |
| 25 | gcc $(CFLAGS) memfd_test.c -o memfd_test | 25 | gcc $(CFLAGS) memfd_test.c -o memfd_test |
| 26 | endif | 26 | endif |
| 27 | @./memfd_test || echo "memfd_test: [FAIL]" | 27 | @./memfd_test || echo "memfd_test: [FAIL]" |
| 28 | 28 | ||
| 29 | build_fuse: | 29 | build_fuse: |
| 30 | ifeq ($(ARCH),X86) | 30 | ifeq ($(ARCH),x86) |
| 31 | gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt | 31 | gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt |
| 32 | gcc $(CFLAGS) fuse_test.c -o fuse_test | 32 | gcc $(CFLAGS) fuse_test.c -o fuse_test |
| 33 | else | 33 | else |
diff --git a/tools/usb/usbip/.gitignore b/tools/usb/usbip/.gitignore new file mode 100644 index 000000000000..9aad9e30a8ba --- /dev/null +++ b/tools/usb/usbip/.gitignore | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | Makefile | ||
| 2 | Makefile.in | ||
| 3 | aclocal.m4 | ||
| 4 | autom4te.cache/ | ||
| 5 | config.guess | ||
| 6 | config.h | ||
| 7 | config.h.in | ||
| 8 | config.log | ||
| 9 | config.status | ||
| 10 | config.sub | ||
| 11 | configure | ||
| 12 | depcomp | ||
| 13 | install-sh | ||
| 14 | libsrc/Makefile | ||
| 15 | libsrc/Makefile.in | ||
| 16 | libtool | ||
| 17 | ltmain.sh | ||
| 18 | missing | ||
| 19 | src/Makefile | ||
| 20 | src/Makefile.in | ||
| 21 | stamp-h1 | ||
| 22 | libsrc/libusbip.la | ||
| 23 | libsrc/libusbip_la-names.lo | ||
| 24 | libsrc/libusbip_la-usbip_common.lo | ||
| 25 | libsrc/libusbip_la-usbip_host_driver.lo | ||
| 26 | libsrc/libusbip_la-vhci_driver.lo | ||
| 27 | src/usbip | ||
| 28 | src/usbipd | ||
diff --git a/tools/usb/usbip/AUTHORS b/tools/usb/usbip/AUTHORS new file mode 100644 index 000000000000..a27ea8d03aec --- /dev/null +++ b/tools/usb/usbip/AUTHORS | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | Takahiro Hirofuchi | ||
| 2 | Robert Leibl | ||
| 3 | matt mooney <mfm@muteddisk.com> | ||
diff --git a/tools/usb/usbip/COPYING b/tools/usb/usbip/COPYING new file mode 100644 index 000000000000..c5611e48a8e1 --- /dev/null +++ b/tools/usb/usbip/COPYING | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | GNU GENERAL PUBLIC LICENSE | ||
| 2 | Version 2, June 1991 | ||
| 3 | |||
| 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||
| 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 6 | Everyone is permitted to copy and distribute verbatim copies | ||
| 7 | of this license document, but changing it is not allowed. | ||
| 8 | |||
| 9 | Preamble | ||
| 10 | |||
| 11 | The licenses for most software are designed to take away your | ||
| 12 | freedom to share and change it. By contrast, the GNU General Public | ||
| 13 | License is intended to guarantee your freedom to share and change free | ||
| 14 | software--to make sure the software is free for all its users. This | ||
| 15 | General Public License applies to most of the Free Software | ||
| 16 | Foundation's software and to any other program whose authors commit to | ||
| 17 | using it. (Some other Free Software Foundation software is covered by | ||
| 18 | the GNU Library General Public License instead.) You can apply it to | ||
| 19 | your programs, too. | ||
| 20 | |||
| 21 | When we speak of free software, we are referring to freedom, not | ||
| 22 | price. Our General Public Licenses are designed to make sure that you | ||
| 23 | have the freedom to distribute copies of free software (and charge for | ||
| 24 | this service if you wish), that you receive source code or can get it | ||
| 25 | if you want it, that you can change the software or use pieces of it | ||
| 26 | in new free programs; and that you know you can do these things. | ||
| 27 | |||
| 28 | To protect your rights, we need to make restrictions that forbid | ||
| 29 | anyone to deny you these rights or to ask you to surrender the rights. | ||
| 30 | These restrictions translate to certain responsibilities for you if you | ||
| 31 | distribute copies of the software, or if you modify it. | ||
| 32 | |||
| 33 | For example, if you distribute copies of such a program, whether | ||
| 34 | gratis or for a fee, you must give the recipients all the rights that | ||
| 35 | you have. You must make sure that they, too, receive or can get the | ||
| 36 | source code. And you must show them these terms so they know their | ||
| 37 | rights. | ||
| 38 | |||
| 39 | We protect your rights with two steps: (1) copyright the software, and | ||
| 40 | (2) offer you this license which gives you legal permission to copy, | ||
| 41 | distribute and/or modify the software. | ||
| 42 | |||
| 43 | Also, for each author's protection and ours, we want to make certain | ||
| 44 | that everyone understands that there is no warranty for this free | ||
| 45 | software. If the software is modified by someone else and passed on, we | ||
| 46 | want its recipients to know that what they have is not the original, so | ||
| 47 | that any problems introduced by others will not reflect on the original | ||
| 48 | authors' reputations. | ||
| 49 | |||
| 50 | Finally, any free program is threatened constantly by software | ||
| 51 | patents. We wish to avoid the danger that redistributors of a free | ||
| 52 | program will individually obtain patent licenses, in effect making the | ||
| 53 | program proprietary. To prevent this, we have made it clear that any | ||
| 54 | patent must be licensed for everyone's free use or not licensed at all. | ||
| 55 | |||
| 56 | The precise terms and conditions for copying, distribution and | ||
| 57 | modification follow. | ||
| 58 | |||
| 59 | GNU GENERAL PUBLIC LICENSE | ||
| 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||
| 61 | |||
| 62 | 0. This License applies to any program or other work which contains | ||
| 63 | a notice placed by the copyright holder saying it may be distributed | ||
| 64 | under the terms of this General Public License. The "Program", below, | ||
| 65 | refers to any such program or work, and a "work based on the Program" | ||
| 66 | means either the Program or any derivative work under copyright law: | ||
| 67 | that is to say, a work containing the Program or a portion of it, | ||
| 68 | either verbatim or with modifications and/or translated into another | ||
| 69 | language. (Hereinafter, translation is included without limitation in | ||
| 70 | the term "modification".) Each licensee is addressed as "you". | ||
| 71 | |||
| 72 | Activities other than copying, distribution and modification are not | ||
| 73 | covered by this License; they are outside its scope. The act of | ||
| 74 | running the Program is not restricted, and the output from the Program | ||
| 75 | is covered only if its contents constitute a work based on the | ||
| 76 | Program (independent of having been made by running the Program). | ||
| 77 | Whether that is true depends on what the Program does. | ||
| 78 | |||
| 79 | 1. You may copy and distribute verbatim copies of the Program's | ||
| 80 | source code as you receive it, in any medium, provided that you | ||
| 81 | conspicuously and appropriately publish on each copy an appropriate | ||
| 82 | copyright notice and disclaimer of warranty; keep intact all the | ||
| 83 | notices that refer to this License and to the absence of any warranty; | ||
| 84 | and give any other recipients of the Program a copy of this License | ||
| 85 | along with the Program. | ||
| 86 | |||
| 87 | You may charge a fee for the physical act of transferring a copy, and | ||
| 88 | you may at your option offer warranty protection in exchange for a fee. | ||
| 89 | |||
| 90 | 2. You may modify your copy or copies of the Program or any portion | ||
| 91 | of it, thus forming a work based on the Program, and copy and | ||
| 92 | distribute such modifications or work under the terms of Section 1 | ||
| 93 | above, provided that you also meet all of these conditions: | ||
| 94 | |||
| 95 | a) You must cause the modified files to carry prominent notices | ||
| 96 | stating that you changed the files and the date of any change. | ||
| 97 | |||
| 98 | b) You must cause any work that you distribute or publish, that in | ||
| 99 | whole or in part contains or is derived from the Program or any | ||
| 100 | part thereof, to be licensed as a whole at no charge to all third | ||
| 101 | parties under the terms of this License. | ||
| 102 | |||
| 103 | c) If the modified program normally reads commands interactively | ||
| 104 | when run, you must cause it, when started running for such | ||
| 105 | interactive use in the most ordinary way, to print or display an | ||
| 106 | announcement including an appropriate copyright notice and a | ||
| 107 | notice that there is no warranty (or else, saying that you provide | ||
| 108 | a warranty) and that users may redistribute the program under | ||
| 109 | these conditions, and telling the user how to view a copy of this | ||
| 110 | License. (Exception: if the Program itself is interactive but | ||
| 111 | does not normally print such an announcement, your work based on | ||
| 112 | the Program is not required to print an announcement.) | ||
| 113 | |||
| 114 | These requirements apply to the modified work as a whole. If | ||
| 115 | identifiable sections of that work are not derived from the Program, | ||
| 116 | and can be reasonably considered independent and separate works in | ||
| 117 | themselves, then this License, and its terms, do not apply to those | ||
| 118 | sections when you distribute them as separate works. But when you | ||
| 119 | distribute the same sections as part of a whole which is a work based | ||
| 120 | on the Program, the distribution of the whole must be on the terms of | ||
| 121 | this License, whose permissions for other licensees extend to the | ||
| 122 | entire whole, and thus to each and every part regardless of who wrote it. | ||
| 123 | |||
| 124 | Thus, it is not the intent of this section to claim rights or contest | ||
| 125 | your rights to work written entirely by you; rather, the intent is to | ||
| 126 | exercise the right to control the distribution of derivative or | ||
| 127 | collective works based on the Program. | ||
| 128 | |||
| 129 | In addition, mere aggregation of another work not based on the Program | ||
| 130 | with the Program (or with a work based on the Program) on a volume of | ||
| 131 | a storage or distribution medium does not bring the other work under | ||
| 132 | the scope of this License. | ||
| 133 | |||
| 134 | 3. You may copy and distribute the Program (or a work based on it, | ||
| 135 | under Section 2) in object code or executable form under the terms of | ||
| 136 | Sections 1 and 2 above provided that you also do one of the following: | ||
| 137 | |||
| 138 | a) Accompany it with the complete corresponding machine-readable | ||
| 139 | source code, which must be distributed under the terms of Sections | ||
| 140 | 1 and 2 above on a medium customarily used for software interchange; or, | ||
| 141 | |||
| 142 | b) Accompany it with a written offer, valid for at least three | ||
| 143 | years, to give any third party, for a charge no more than your | ||
| 144 | cost of physically performing source distribution, a complete | ||
| 145 | machine-readable copy of the corresponding source code, to be | ||
| 146 | distributed under the terms of Sections 1 and 2 above on a medium | ||
| 147 | customarily used for software interchange; or, | ||
| 148 | |||
| 149 | c) Accompany it with the information you received as to the offer | ||
| 150 | to distribute corresponding source code. (This alternative is | ||
| 151 | allowed only for noncommercial distribution and only if you | ||
| 152 | received the program in object code or executable form with such | ||
| 153 | an offer, in accord with Subsection b above.) | ||
| 154 | |||
| 155 | The source code for a work means the preferred form of the work for | ||
| 156 | making modifications to it. For an executable work, complete source | ||
| 157 | code means all the source code for all modules it contains, plus any | ||
| 158 | associated interface definition files, plus the scripts used to | ||
| 159 | control compilation and installation of the executable. However, as a | ||
| 160 | special exception, the source code distributed need not include | ||
| 161 | anything that is normally distributed (in either source or binary | ||
| 162 | form) with the major components (compiler, kernel, and so on) of the | ||
| 163 | operating system on which the executable runs, unless that component | ||
| 164 | itself accompanies the executable. | ||
| 165 | |||
| 166 | If distribution of executable or object code is made by offering | ||
| 167 | access to copy from a designated place, then offering equivalent | ||
| 168 | access to copy the source code from the same place counts as | ||
| 169 | distribution of the source code, even though third parties are not | ||
| 170 | compelled to copy the source along with the object code. | ||
| 171 | |||
| 172 | 4. You may not copy, modify, sublicense, or distribute the Program | ||
| 173 | except as expressly provided under this License. Any attempt | ||
| 174 | otherwise to copy, modify, sublicense or distribute the Program is | ||
| 175 | void, and will automatically terminate your rights under this License. | ||
| 176 | However, parties who have received copies, or rights, from you under | ||
| 177 | this License will not have their licenses terminated so long as such | ||
| 178 | parties remain in full compliance. | ||
| 179 | |||
| 180 | 5. You are not required to accept this License, since you have not | ||
| 181 | signed it. However, nothing else grants you permission to modify or | ||
| 182 | distribute the Program or its derivative works. These actions are | ||
| 183 | prohibited by law if you do not accept this License. Therefore, by | ||
| 184 | modifying or distributing the Program (or any work based on the | ||
| 185 | Program), you indicate your acceptance of this License to do so, and | ||
| 186 | all its terms and conditions for copying, distributing or modifying | ||
| 187 | the Program or works based on it. | ||
| 188 | |||
| 189 | 6. Each time you redistribute the Program (or any work based on the | ||
| 190 | Program), the recipient automatically receives a license from the | ||
| 191 | original licensor to copy, distribute or modify the Program subject to | ||
| 192 | these terms and conditions. You may not impose any further | ||
| 193 | restrictions on the recipients' exercise of the rights granted herein. | ||
| 194 | You are not responsible for enforcing compliance by third parties to | ||
| 195 | this License. | ||
| 196 | |||
| 197 | 7. If, as a consequence of a court judgment or allegation of patent | ||
| 198 | infringement or for any other reason (not limited to patent issues), | ||
| 199 | conditions are imposed on you (whether by court order, agreement or | ||
| 200 | otherwise) that contradict the conditions of this License, they do not | ||
| 201 | excuse you from the conditions of this License. If you cannot | ||
| 202 | distribute so as to satisfy simultaneously your obligations under this | ||
| 203 | License and any other pertinent obligations, then as a consequence you | ||
| 204 | may not distribute the Program at all. For example, if a patent | ||
| 205 | license would not permit royalty-free redistribution of the Program by | ||
| 206 | all those who receive copies directly or indirectly through you, then | ||
| 207 | the only way you could satisfy both it and this License would be to | ||
| 208 | refrain entirely from distribution of the Program. | ||
| 209 | |||
| 210 | If any portion of this section is held invalid or unenforceable under | ||
| 211 | any particular circumstance, the balance of the section is intended to | ||
| 212 | apply and the section as a whole is intended to apply in other | ||
| 213 | circumstances. | ||
| 214 | |||
| 215 | It is not the purpose of this section to induce you to infringe any | ||
| 216 | patents or other property right claims or to contest validity of any | ||
| 217 | such claims; this section has the sole purpose of protecting the | ||
| 218 | integrity of the free software distribution system, which is | ||
| 219 | implemented by public license practices. Many people have made | ||
| 220 | generous contributions to the wide range of software distributed | ||
| 221 | through that system in reliance on consistent application of that | ||
| 222 | system; it is up to the author/donor to decide if he or she is willing | ||
| 223 | to distribute software through any other system and a licensee cannot | ||
| 224 | impose that choice. | ||
| 225 | |||
| 226 | This section is intended to make thoroughly clear what is believed to | ||
| 227 | be a consequence of the rest of this License. | ||
| 228 | |||
| 229 | 8. If the distribution and/or use of the Program is restricted in | ||
| 230 | certain countries either by patents or by copyrighted interfaces, the | ||
| 231 | original copyright holder who places the Program under this License | ||
| 232 | may add an explicit geographical distribution limitation excluding | ||
| 233 | those countries, so that distribution is permitted only in or among | ||
| 234 | countries not thus excluded. In such case, this License incorporates | ||
| 235 | the limitation as if written in the body of this License. | ||
| 236 | |||
| 237 | 9. The Free Software Foundation may publish revised and/or new versions | ||
| 238 | of the General Public License from time to time. Such new versions will | ||
| 239 | be similar in spirit to the present version, but may differ in detail to | ||
| 240 | address new problems or concerns. | ||
| 241 | |||
| 242 | Each version is given a distinguishing version number. If the Program | ||
| 243 | specifies a version number of this License which applies to it and "any | ||
| 244 | later version", you have the option of following the terms and conditions | ||
| 245 | either of that version or of any later version published by the Free | ||
| 246 | Software Foundation. If the Program does not specify a version number of | ||
| 247 | this License, you may choose any version ever published by the Free Software | ||
| 248 | Foundation. | ||
| 249 | |||
| 250 | 10. If you wish to incorporate parts of the Program into other free | ||
| 251 | programs whose distribution conditions are different, write to the author | ||
| 252 | to ask for permission. For software which is copyrighted by the Free | ||
| 253 | Software Foundation, write to the Free Software Foundation; we sometimes | ||
| 254 | make exceptions for this. Our decision will be guided by the two goals | ||
| 255 | of preserving the free status of all derivatives of our free software and | ||
| 256 | of promoting the sharing and reuse of software generally. | ||
| 257 | |||
| 258 | NO WARRANTY | ||
| 259 | |||
| 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||
| 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | ||
| 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||
| 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||
| 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
| 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | ||
| 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | ||
| 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||
| 268 | REPAIR OR CORRECTION. | ||
| 269 | |||
| 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||
| 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||
| 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||
| 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||
| 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||
| 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||
| 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||
| 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||
| 278 | POSSIBILITY OF SUCH DAMAGES. | ||
| 279 | |||
| 280 | END OF TERMS AND CONDITIONS | ||
| 281 | |||
| 282 | How to Apply These Terms to Your New Programs | ||
| 283 | |||
| 284 | If you develop a new program, and you want it to be of the greatest | ||
| 285 | possible use to the public, the best way to achieve this is to make it | ||
| 286 | free software which everyone can redistribute and change under these terms. | ||
| 287 | |||
| 288 | To do so, attach the following notices to the program. It is safest | ||
| 289 | to attach them to the start of each source file to most effectively | ||
| 290 | convey the exclusion of warranty; and each file should have at least | ||
| 291 | the "copyright" line and a pointer to where the full notice is found. | ||
| 292 | |||
| 293 | <one line to give the program's name and a brief idea of what it does.> | ||
| 294 | Copyright (C) <year> <name of author> | ||
| 295 | |||
| 296 | This program is free software; you can redistribute it and/or modify | ||
| 297 | it under the terms of the GNU General Public License as published by | ||
| 298 | the Free Software Foundation; either version 2 of the License, or | ||
| 299 | (at your option) any later version. | ||
| 300 | |||
| 301 | This program is distributed in the hope that it will be useful, | ||
| 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 304 | GNU General Public License for more details. | ||
| 305 | |||
| 306 | You should have received a copy of the GNU General Public License | ||
| 307 | along with this program; if not, write to the Free Software | ||
| 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 309 | |||
| 310 | |||
| 311 | Also add information on how to contact you by electronic and paper mail. | ||
| 312 | |||
| 313 | If the program is interactive, make it output a short notice like this | ||
| 314 | when it starts in an interactive mode: | ||
| 315 | |||
| 316 | Gnomovision version 69, Copyright (C) year name of author | ||
| 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||
| 318 | This is free software, and you are welcome to redistribute it | ||
| 319 | under certain conditions; type `show c' for details. | ||
| 320 | |||
| 321 | The hypothetical commands `show w' and `show c' should show the appropriate | ||
| 322 | parts of the General Public License. Of course, the commands you use may | ||
| 323 | be called something other than `show w' and `show c'; they could even be | ||
| 324 | mouse-clicks or menu items--whatever suits your program. | ||
| 325 | |||
| 326 | You should also get your employer (if you work as a programmer) or your | ||
| 327 | school, if any, to sign a "copyright disclaimer" for the program, if | ||
| 328 | necessary. Here is a sample; alter the names: | ||
| 329 | |||
| 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||
| 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||
| 332 | |||
| 333 | <signature of Ty Coon>, 1 April 1989 | ||
| 334 | Ty Coon, President of Vice | ||
| 335 | |||
| 336 | This General Public License does not permit incorporating your program into | ||
| 337 | proprietary programs. If your program is a subroutine library, you may | ||
| 338 | consider it more useful to permit linking proprietary applications with the | ||
| 339 | library. If this is what you want to do, use the GNU Library General | ||
| 340 | Public License instead of this License. | ||
diff --git a/tools/usb/usbip/INSTALL b/tools/usb/usbip/INSTALL new file mode 100644 index 000000000000..d3c5b40a9409 --- /dev/null +++ b/tools/usb/usbip/INSTALL | |||
| @@ -0,0 +1,237 @@ | |||
| 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 | |||
diff --git a/tools/usb/usbip/Makefile.am b/tools/usb/usbip/Makefile.am new file mode 100644 index 000000000000..66f8bf038c9f --- /dev/null +++ b/tools/usb/usbip/Makefile.am | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | SUBDIRS := libsrc src | ||
| 2 | includedir = @includedir@/usbip | ||
| 3 | include_HEADERS := $(addprefix libsrc/, \ | ||
| 4 | usbip_common.h vhci_driver.h usbip_host_driver.h) | ||
| 5 | |||
| 6 | dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) | ||
diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README new file mode 100644 index 000000000000..831f49fea3ce --- /dev/null +++ b/tools/usb/usbip/README | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | # | ||
| 2 | # README for usbip-utils | ||
| 3 | # | ||
| 4 | # Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 5 | # 2005-2008 Takahiro Hirofuchi | ||
| 6 | |||
| 7 | |||
| 8 | [Requirements] | ||
| 9 | - USB/IP device drivers | ||
| 10 | Found in the staging directory of the Linux kernel. | ||
| 11 | |||
| 12 | - libudev >= 2.0 | ||
| 13 | libudev library | ||
| 14 | |||
| 15 | - libwrap0-dev | ||
| 16 | tcp wrapper library | ||
| 17 | |||
| 18 | - gcc >= 4.0 | ||
| 19 | |||
| 20 | - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config | ||
| 21 | |||
| 22 | [Optional] | ||
| 23 | - hwdata | ||
| 24 | Contains USB device identification data. | ||
| 25 | |||
| 26 | |||
| 27 | [Install] | ||
| 28 | 0. Generate configuration scripts. | ||
| 29 | $ ./autogen.sh | ||
| 30 | |||
| 31 | 1. Compile & install the userspace utilities. | ||
| 32 | $ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>] | ||
| 33 | $ make install | ||
| 34 | |||
| 35 | 2. Compile & install USB/IP drivers. | ||
| 36 | |||
| 37 | |||
| 38 | [Usage] | ||
| 39 | server:# (Physically attach your USB device.) | ||
| 40 | |||
| 41 | server:# insmod usbip-core.ko | ||
| 42 | server:# insmod usbip-host.ko | ||
| 43 | |||
| 44 | server:# usbipd -D | ||
| 45 | - Start usbip daemon. | ||
| 46 | |||
| 47 | server:# usbip list -l | ||
| 48 | - List driver assignments for USB devices. | ||
| 49 | |||
| 50 | server:# usbip bind --busid 1-2 | ||
| 51 | - Bind usbip-host.ko to the device with busid 1-2. | ||
| 52 | - The USB device 1-2 is now exportable to other hosts! | ||
| 53 | - Use `usbip unbind --busid 1-2' to stop exporting the device. | ||
| 54 | |||
| 55 | client:# insmod usbip-core.ko | ||
| 56 | client:# insmod vhci-hcd.ko | ||
| 57 | |||
| 58 | client:# usbip list --remote <host> | ||
| 59 | - List exported USB devices on the <host>. | ||
| 60 | |||
| 61 | client:# usbip attach --remote <host> --busid 1-2 | ||
| 62 | - Connect the remote USB device. | ||
| 63 | |||
| 64 | client:# usbip port | ||
| 65 | - Show virtual port status. | ||
| 66 | |||
| 67 | client:# usbip detach --port <port> | ||
| 68 | - Detach the USB device. | ||
| 69 | |||
| 70 | |||
| 71 | [Example] | ||
| 72 | --------------------------- | ||
| 73 | SERVER SIDE | ||
| 74 | --------------------------- | ||
| 75 | Physically attach your USB devices to this host. | ||
| 76 | |||
| 77 | trois:# insmod path/to/usbip-core.ko | ||
| 78 | trois:# insmod path/to/usbip-host.ko | ||
| 79 | trois:# usbipd -D | ||
| 80 | |||
| 81 | In another terminal, let's look up what USB devices are physically | ||
| 82 | attached to this host. | ||
| 83 | |||
| 84 | trois:# usbip list -l | ||
| 85 | Local USB devices | ||
| 86 | ================= | ||
| 87 | - busid 1-1 (05a9:a511) | ||
| 88 | 1-1:1.0 -> ov511 | ||
| 89 | |||
| 90 | - busid 3-2 (0711:0902) | ||
| 91 | 3-2:1.0 -> none | ||
| 92 | |||
| 93 | - busid 3-3.1 (08bb:2702) | ||
| 94 | 3-3.1:1.0 -> snd-usb-audio | ||
| 95 | 3-3.1:1.1 -> snd-usb-audio | ||
| 96 | |||
| 97 | - busid 3-3.2 (04bb:0206) | ||
| 98 | 3-3.2:1.0 -> usb-storage | ||
| 99 | |||
| 100 | - busid 3-3 (0409:0058) | ||
| 101 | 3-3:1.0 -> hub | ||
| 102 | |||
| 103 | - busid 4-1 (046d:08b2) | ||
| 104 | 4-1:1.0 -> none | ||
| 105 | 4-1:1.1 -> none | ||
| 106 | 4-1:1.2 -> none | ||
| 107 | |||
| 108 | - busid 5-2 (058f:9254) | ||
| 109 | 5-2:1.0 -> hub | ||
| 110 | |||
| 111 | A USB storage device of busid 3-3.2 is now bound to the usb-storage | ||
| 112 | driver. To export this device, we first mark the device as | ||
| 113 | "exportable"; the device is bound to the usbip-host driver. Please | ||
| 114 | remember you can not export a USB hub. | ||
| 115 | |||
| 116 | Mark the device of busid 3-3.2 as exportable: | ||
| 117 | |||
| 118 | trois:# usbip --debug bind --busid 3-3.2 | ||
| 119 | ... | ||
| 120 | usbip debug: usbip_bind.c:162:[unbind_other] 3-3.2:1.0 -> usb-storage | ||
| 121 | ... | ||
| 122 | bind device on busid 3-3.2: complete | ||
| 123 | |||
| 124 | trois:# usbip list -l | ||
| 125 | Local USB devices | ||
| 126 | ================= | ||
| 127 | ... | ||
| 128 | |||
| 129 | - busid 3-3.2 (04bb:0206) | ||
| 130 | 3-3.2:1.0 -> usbip-host | ||
| 131 | ... | ||
| 132 | |||
| 133 | --------------------------- | ||
| 134 | CLIENT SIDE | ||
| 135 | --------------------------- | ||
| 136 | First, let's list available remote devices that are marked as | ||
| 137 | exportable on the host. | ||
| 138 | |||
| 139 | deux:# insmod path/to/usbip-core.ko | ||
| 140 | deux:# insmod path/to/vhci-hcd.ko | ||
| 141 | |||
| 142 | deux:# usbip list --remote 10.0.0.3 | ||
| 143 | Exportable USB devices | ||
| 144 | ====================== | ||
| 145 | - 10.0.0.3 | ||
| 146 | 1-1: Prolific Technology, Inc. : unknown product (067b:3507) | ||
| 147 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1 | ||
| 148 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) | ||
| 149 | : 0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50) | ||
| 150 | |||
| 151 | 1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203) | ||
| 152 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1 | ||
| 153 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) | ||
| 154 | : 0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01) | ||
| 155 | |||
| 156 | 1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511) | ||
| 157 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3 | ||
| 158 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) | ||
| 159 | : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00) | ||
| 160 | |||
| 161 | 3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2) | ||
| 162 | : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1 | ||
| 163 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) | ||
| 164 | : 0 - Data / unknown subclass / unknown protocol (0a/ff/00) | ||
| 165 | : 1 - Audio / Control Device / unknown protocol (01/01/00) | ||
| 166 | : 2 - Audio / Streaming / unknown protocol (01/02/00) | ||
| 167 | |||
| 168 | Attach a remote USB device: | ||
| 169 | |||
| 170 | deux:# usbip attach --remote 10.0.0.3 --busid 1-1 | ||
| 171 | port 0 attached | ||
| 172 | |||
| 173 | Show the devices attached to this client: | ||
| 174 | |||
| 175 | deux:# usbip port | ||
| 176 | Port 00: <Port in Use> at Full Speed(12Mbps) | ||
| 177 | Prolific Technology, Inc. : unknown product (067b:3507) | ||
| 178 | 6-1 -> usbip://10.0.0.3:3240/1-1 (remote bus/dev 001/004) | ||
| 179 | 6-1:1.0 used by usb-storage | ||
| 180 | /sys/class/scsi_device/0:0:0:0/device | ||
| 181 | /sys/class/scsi_host/host0/device | ||
| 182 | /sys/block/sda/device | ||
| 183 | |||
| 184 | Detach the imported device: | ||
| 185 | |||
| 186 | deux:# usbip detach --port 0 | ||
| 187 | port 0 detached | ||
| 188 | |||
| 189 | |||
| 190 | [Checklist] | ||
| 191 | - See 'Debug Tips' on the project wiki. | ||
| 192 | - http://usbip.wiki.sourceforge.net/how-to-debug-usbip | ||
| 193 | - usbip-host.ko must be bound to the target device. | ||
| 194 | - See /proc/bus/usb/devices and find "Driver=..." lines of the device. | ||
| 195 | - Shutdown firewall. | ||
| 196 | - usbip now uses TCP port 3240. | ||
| 197 | - Disable SELinux. | ||
| 198 | - Check the kernel and daemon messages. | ||
| 199 | |||
| 200 | |||
| 201 | [Contact] | ||
| 202 | Mailing List: linux-usb@vger.kernel.org | ||
diff --git a/tools/usb/usbip/autogen.sh b/tools/usb/usbip/autogen.sh new file mode 100755 index 000000000000..e1112d3fcbf6 --- /dev/null +++ b/tools/usb/usbip/autogen.sh | |||
| @@ -0,0 +1,9 @@ | |||
| 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 | ||
diff --git a/tools/usb/usbip/cleanup.sh b/tools/usb/usbip/cleanup.sh new file mode 100755 index 000000000000..955c3ccb729a --- /dev/null +++ b/tools/usb/usbip/cleanup.sh | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | if [ -r Makefile ]; then | ||
| 4 | make distclean | ||
| 5 | fi | ||
| 6 | |||
| 7 | FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \ | ||
| 8 | config.status config.sub configure cscope.out depcomp install-sh \ | ||
| 9 | libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile \ | ||
| 10 | Makefile.in missing src/Makefile src/Makefile.in" | ||
| 11 | |||
| 12 | rm -vRf $FILES | ||
diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac new file mode 100644 index 000000000000..607d05c5ccfd --- /dev/null +++ b/tools/usb/usbip/configure.ac | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | dnl Process this file with autoconf to produce a configure script. | ||
| 2 | |||
| 3 | AC_PREREQ(2.59) | ||
| 4 | AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org]) | ||
| 5 | AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal 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=gnu99"]) | ||
| 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 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([memset mkdir regcomp socket strchr strerror strstr dnl | ||
| 45 | strtoul]) | ||
| 46 | |||
| 47 | AC_CHECK_HEADER([libudev.h], | ||
| 48 | [AC_CHECK_LIB([udev], [udev_new], | ||
| 49 | [LIBS="$LIBS -ludev"], | ||
| 50 | [AC_MSG_ERROR([Missing udev library!])])], | ||
| 51 | [AC_MSG_ERROR([Missing /usr/include/libudev.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 | [if test "$withval" = "yes"; then | ||
| 60 | AC_MSG_RESULT([yes]) | ||
| 61 | AC_MSG_CHECKING([for hosts_access in -lwrap]) | ||
| 62 | saved_LIBS="$LIBS" | ||
| 63 | LIBS="-lwrap $saved_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 | dnl [ACTION-IF-NOT-GIVEN] | ||
| 75 | [AC_MSG_RESULT([(default)]) | ||
| 76 | AC_MSG_CHECKING([for hosts_access in -lwrap]) | ||
| 77 | saved_LIBS="$LIBS" | ||
| 78 | LIBS="-lwrap $saved_LIBS" | ||
| 79 | AC_TRY_LINK( | ||
| 80 | [int hosts_access(); int allow_severity, deny_severity;], | ||
| 81 | [hosts_access()], | ||
| 82 | [AC_MSG_RESULT([yes]); | ||
| 83 | AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])], | ||
| 84 | [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])]) | ||
| 85 | |||
| 86 | # Sets directory containing usb.ids. | ||
| 87 | AC_ARG_WITH([usbids-dir], | ||
| 88 | [AS_HELP_STRING([--with-usbids-dir=DIR], | ||
| 89 | [where usb.ids is found (default /usr/share/hwdata/)])], | ||
| 90 | [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"]) | ||
| 91 | AC_SUBST([USBIDS_DIR]) | ||
| 92 | |||
| 93 | # use _FORTIFY_SOURCE | ||
| 94 | AC_MSG_CHECKING([whether to use fortify]) | ||
| 95 | AC_ARG_WITH([fortify], | ||
| 96 | [AS_HELP_STRING([--with-fortify], | ||
| 97 | [use _FORTIFY_SROUCE option when compiling)])], | ||
| 98 | dnl [ACTION-IF-GIVEN] | ||
| 99 | [if test "$withval" = "yes"; then | ||
| 100 | AC_MSG_RESULT([yes]) | ||
| 101 | CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O" | ||
| 102 | else | ||
| 103 | AC_MSG_RESULT([no]) | ||
| 104 | CFLAGS="$CFLAGS -U_FORTIFY_SOURCE" | ||
| 105 | fi | ||
| 106 | ], | ||
| 107 | dnl [ACTION-IF-NOT-GIVEN] | ||
| 108 | [AC_MSG_RESULT([default])]) | ||
| 109 | |||
| 110 | AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile]) | ||
| 111 | AC_OUTPUT | ||
diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8 new file mode 100644 index 000000000000..a6097be25d28 --- /dev/null +++ b/tools/usb/usbip/doc/usbip.8 | |||
| @@ -0,0 +1,95 @@ | |||
| 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] <\fIcommand\fR> <\fIargs\fR> | ||
| 7 | |||
| 8 | .SH DESCRIPTION | ||
| 9 | On a USB/IP server, devices can be listed, bound, and unbound using | ||
| 10 | this program. On a USB/IP client, devices exported by USB/IP servers | ||
| 11 | can be listed, attached and detached. | ||
| 12 | |||
| 13 | .SH OPTIONS | ||
| 14 | .HP | ||
| 15 | \fB\-\-debug\fR | ||
| 16 | .IP | ||
| 17 | Print debugging information. | ||
| 18 | .PP | ||
| 19 | |||
| 20 | .HP | ||
| 21 | \fB\-\-log\fR | ||
| 22 | .IP | ||
| 23 | Log to syslog. | ||
| 24 | .PP | ||
| 25 | |||
| 26 | .HP | ||
| 27 | \fB\-\-tcp-port PORT\fR | ||
| 28 | .IP | ||
| 29 | Connect to PORT on remote host (used for attach and list --remote). | ||
| 30 | .PP | ||
| 31 | |||
| 32 | .SH COMMANDS | ||
| 33 | .HP | ||
| 34 | \fBversion\fR | ||
| 35 | .IP | ||
| 36 | Show version and exit. | ||
| 37 | .PP | ||
| 38 | |||
| 39 | .HP | ||
| 40 | \fBhelp\fR [\fIcommand\fR] | ||
| 41 | .IP | ||
| 42 | Print the program help message, or help on a specific command, and | ||
| 43 | then exit. | ||
| 44 | .PP | ||
| 45 | |||
| 46 | .HP | ||
| 47 | \fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR> | ||
| 48 | .IP | ||
| 49 | Attach a remote USB device. | ||
| 50 | .PP | ||
| 51 | |||
| 52 | .HP | ||
| 53 | \fBdetach\fR \-\-port=<\fIport\fR> | ||
| 54 | .IP | ||
| 55 | Detach an imported USB device. | ||
| 56 | .PP | ||
| 57 | |||
| 58 | .HP | ||
| 59 | \fBbind\fR \-\-busid=<\fIbusid\fR> | ||
| 60 | .IP | ||
| 61 | Make a device exportable. | ||
| 62 | .PP | ||
| 63 | |||
| 64 | .HP | ||
| 65 | \fBunbind\fR \-\-busid=<\fIbusid\fR> | ||
| 66 | .IP | ||
| 67 | Stop exporting a device so it can be used by a local driver. | ||
| 68 | .PP | ||
| 69 | |||
| 70 | .HP | ||
| 71 | \fBlist\fR \-\-remote=<\fIhost\fR> | ||
| 72 | .IP | ||
| 73 | List USB devices exported by a remote host. | ||
| 74 | .PP | ||
| 75 | |||
| 76 | .HP | ||
| 77 | \fBlist\fR \-\-local | ||
| 78 | .IP | ||
| 79 | List local USB devices. | ||
| 80 | .PP | ||
| 81 | |||
| 82 | |||
| 83 | .SH EXAMPLES | ||
| 84 | |||
| 85 | client:# usbip list --remote=server | ||
| 86 | - List exportable usb devices on the server. | ||
| 87 | |||
| 88 | client:# usbip attach --remote=server --busid=1-2 | ||
| 89 | - Connect the remote USB device. | ||
| 90 | |||
| 91 | client:# usbip detach --port=0 | ||
| 92 | - Detach the usb device. | ||
| 93 | |||
| 94 | .SH "SEE ALSO" | ||
| 95 | \fBusbipd\fP\fB(8)\fB\fP | ||
diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8 new file mode 100644 index 000000000000..ac4635db3f03 --- /dev/null +++ b/tools/usb/usbip/doc/usbipd.8 | |||
| @@ -0,0 +1,91 @@ | |||
| 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 | ||
| 14 | before usbipd makes them available to other hosts. | ||
| 15 | |||
| 16 | The daemon accepts connections from USB/IP clients | ||
| 17 | on TCP port 3240 by default. | ||
| 18 | |||
| 19 | .SH OPTIONS | ||
| 20 | .HP | ||
| 21 | \fB\-4\fR, \fB\-\-ipv4\fR | ||
| 22 | .IP | ||
| 23 | Bind to IPv4. Default is both. | ||
| 24 | .PP | ||
| 25 | |||
| 26 | .HP | ||
| 27 | \fB\-6\fR, \fB\-\-ipv6\fR | ||
| 28 | .IP | ||
| 29 | Bind to IPv6. Default is both. | ||
| 30 | .PP | ||
| 31 | |||
| 32 | .HP | ||
| 33 | \fB\-D\fR, \fB\-\-daemon\fR | ||
| 34 | .IP | ||
| 35 | Run as a daemon process. | ||
| 36 | .PP | ||
| 37 | |||
| 38 | .HP | ||
| 39 | \fB\-d\fR, \fB\-\-debug\fR | ||
| 40 | .IP | ||
| 41 | Print debugging information. | ||
| 42 | .PP | ||
| 43 | |||
| 44 | .HP | ||
| 45 | \fB\-PFILE\fR, \fB\-\-pid FILE\fR | ||
| 46 | .IP | ||
| 47 | Write process id to FILE. | ||
| 48 | .br | ||
| 49 | If no FILE specified, use /var/run/usbipd.pid | ||
| 50 | .PP | ||
| 51 | |||
| 52 | \fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR | ||
| 53 | .IP | ||
| 54 | Listen on TCP/IP port PORT. | ||
| 55 | .PP | ||
| 56 | |||
| 57 | \fB\-h\fR, \fB\-\-help\fR | ||
| 58 | .IP | ||
| 59 | Print the program help message and exit. | ||
| 60 | .PP | ||
| 61 | |||
| 62 | .HP | ||
| 63 | \fB\-v\fR, \fB\-\-version\fR | ||
| 64 | .IP | ||
| 65 | Show version. | ||
| 66 | .PP | ||
| 67 | |||
| 68 | .SH LIMITATIONS | ||
| 69 | |||
| 70 | .B usbipd | ||
| 71 | offers no authentication or authorization for USB/IP. Any | ||
| 72 | USB/IP client can connect and use exported devices. | ||
| 73 | |||
| 74 | .SH EXAMPLES | ||
| 75 | |||
| 76 | server:# modprobe usbip | ||
| 77 | |||
| 78 | server:# usbipd -D | ||
| 79 | - Start usbip daemon. | ||
| 80 | |||
| 81 | server:# usbip list --local | ||
| 82 | - List driver assignments for usb devices. | ||
| 83 | |||
| 84 | server:# usbip bind --busid=1-2 | ||
| 85 | - Bind usbip-host.ko to the device of busid 1-2. | ||
| 86 | - A usb device 1-2 is now exportable to other hosts! | ||
| 87 | - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally. | ||
| 88 | |||
| 89 | .SH "SEE ALSO" | ||
| 90 | \fBusbip\fP\fB(8)\fB\fP | ||
| 91 | |||
diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am new file mode 100644 index 000000000000..7c8f8a4d54e4 --- /dev/null +++ b/tools/usb/usbip/libsrc/Makefile.am | |||
| @@ -0,0 +1,8 @@ | |||
| 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 usbip_host_driver.c usbip_host_driver.h \ | ||
| 7 | usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \ | ||
| 8 | sysfs_utils.c sysfs_utils.h | ||
diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h new file mode 100644 index 000000000000..8d0c936e184f --- /dev/null +++ b/tools/usb/usbip/libsrc/list.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | #ifndef _LIST_H | ||
| 2 | #define _LIST_H | ||
| 3 | |||
| 4 | /* Stripped down implementation of linked list taken | ||
| 5 | * from the Linux Kernel. | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * Simple doubly linked list implementation. | ||
| 10 | * | ||
| 11 | * Some of the internal functions ("__xxx") are useful when | ||
| 12 | * manipulating whole lists rather than single entries, as | ||
| 13 | * sometimes we already know the next/prev entries and we can | ||
| 14 | * generate better code by using them directly rather than | ||
| 15 | * using the generic single-entry routines. | ||
| 16 | */ | ||
| 17 | |||
| 18 | struct list_head { | ||
| 19 | struct list_head *next, *prev; | ||
| 20 | }; | ||
| 21 | |||
| 22 | #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||
| 23 | |||
| 24 | #define LIST_HEAD(name) \ | ||
| 25 | struct list_head name = LIST_HEAD_INIT(name) | ||
| 26 | |||
| 27 | static inline void INIT_LIST_HEAD(struct list_head *list) | ||
| 28 | { | ||
| 29 | list->next = list; | ||
| 30 | list->prev = list; | ||
| 31 | } | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Insert a new entry between two known consecutive entries. | ||
| 35 | * | ||
| 36 | * This is only for internal list manipulation where we know | ||
| 37 | * the prev/next entries already! | ||
| 38 | */ | ||
| 39 | static inline void __list_add(struct list_head *new, | ||
| 40 | struct list_head *prev, | ||
| 41 | struct list_head *next) | ||
| 42 | { | ||
| 43 | next->prev = new; | ||
| 44 | new->next = next; | ||
| 45 | new->prev = prev; | ||
| 46 | prev->next = new; | ||
| 47 | } | ||
| 48 | |||
| 49 | /** | ||
| 50 | * list_add - add a new entry | ||
| 51 | * @new: new entry to be added | ||
| 52 | * @head: list head to add it after | ||
| 53 | * | ||
| 54 | * Insert a new entry after the specified head. | ||
| 55 | * This is good for implementing stacks. | ||
| 56 | */ | ||
| 57 | static inline void list_add(struct list_head *new, struct list_head *head) | ||
| 58 | { | ||
| 59 | __list_add(new, head, head->next); | ||
| 60 | } | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Delete a list entry by making the prev/next entries | ||
| 64 | * point to each other. | ||
| 65 | * | ||
| 66 | * This is only for internal list manipulation where we know | ||
| 67 | * the prev/next entries already! | ||
| 68 | */ | ||
| 69 | static inline void __list_del(struct list_head * prev, struct list_head * next) | ||
| 70 | { | ||
| 71 | next->prev = prev; | ||
| 72 | prev->next = next; | ||
| 73 | } | ||
| 74 | |||
| 75 | #define POISON_POINTER_DELTA 0 | ||
| 76 | #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) | ||
| 77 | #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) | ||
| 78 | |||
| 79 | /** | ||
| 80 | * list_del - deletes entry from list. | ||
| 81 | * @entry: the element to delete from the list. | ||
| 82 | * Note: list_empty() on entry does not return true after this, the entry is | ||
| 83 | * in an undefined state. | ||
| 84 | */ | ||
| 85 | static inline void __list_del_entry(struct list_head *entry) | ||
| 86 | { | ||
| 87 | __list_del(entry->prev, entry->next); | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline void list_del(struct list_head *entry) | ||
| 91 | { | ||
| 92 | __list_del(entry->prev, entry->next); | ||
| 93 | entry->next = LIST_POISON1; | ||
| 94 | entry->prev = LIST_POISON2; | ||
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * list_entry - get the struct for this entry | ||
| 99 | * @ptr: the &struct list_head pointer. | ||
| 100 | * @type: the type of the struct this is embedded in. | ||
| 101 | * @member: the name of the list_struct within the struct. | ||
| 102 | */ | ||
| 103 | #define list_entry(ptr, type, member) \ | ||
| 104 | container_of(ptr, type, member) | ||
| 105 | /** | ||
| 106 | * list_for_each - iterate over a list | ||
| 107 | * @pos: the &struct list_head to use as a loop cursor. | ||
| 108 | * @head: the head for your list. | ||
| 109 | */ | ||
| 110 | #define list_for_each(pos, head) \ | ||
| 111 | for (pos = (head)->next; pos != (head); pos = pos->next) | ||
| 112 | |||
| 113 | /** | ||
| 114 | * list_for_each_safe - iterate over a list safe against removal of list entry | ||
| 115 | * @pos: the &struct list_head to use as a loop cursor. | ||
| 116 | * @n: another &struct list_head to use as temporary storage | ||
| 117 | * @head: the head for your list. | ||
| 118 | */ | ||
| 119 | #define list_for_each_safe(pos, n, head) \ | ||
| 120 | for (pos = (head)->next, n = pos->next; pos != (head); \ | ||
| 121 | pos = n, n = pos->next) | ||
| 122 | |||
| 123 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | ||
| 124 | |||
| 125 | /** | ||
| 126 | * container_of - cast a member of a structure out to the containing structure | ||
| 127 | * @ptr: the pointer to the member. | ||
| 128 | * @type: the type of the container struct this is embedded in. | ||
| 129 | * @member: the name of the member within the struct. | ||
| 130 | * | ||
| 131 | */ | ||
| 132 | #define container_of(ptr, type, member) ({ \ | ||
| 133 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
| 134 | (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
| 135 | |||
| 136 | #endif | ||
diff --git a/tools/usb/usbip/libsrc/names.c b/tools/usb/usbip/libsrc/names.c new file mode 100644 index 000000000000..81ff8522405c --- /dev/null +++ b/tools/usb/usbip/libsrc/names.c | |||
| @@ -0,0 +1,504 @@ | |||
| 1 | /* | ||
| 2 | * names.c -- USB name database manipulation routines | ||
| 3 | * | ||
| 4 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | * | ||
| 20 | * | ||
| 21 | * | ||
| 22 | * | ||
| 23 | * | ||
| 24 | * Copyright (C) 2005 Takahiro Hirofuchi | ||
| 25 | * - names_deinit() is added. | ||
| 26 | * | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <sys/types.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | #include <fcntl.h> | ||
| 32 | #include <dirent.h> | ||
| 33 | #include <string.h> | ||
| 34 | #include <errno.h> | ||
| 35 | #include <stdlib.h> | ||
| 36 | #include <unistd.h> | ||
| 37 | #include <stdio.h> | ||
| 38 | #include <ctype.h> | ||
| 39 | |||
| 40 | #include "names.h" | ||
| 41 | #include "usbip_common.h" | ||
| 42 | |||
| 43 | struct vendor { | ||
| 44 | struct vendor *next; | ||
| 45 | u_int16_t vendorid; | ||
| 46 | char name[1]; | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct product { | ||
| 50 | struct product *next; | ||
| 51 | u_int16_t vendorid, productid; | ||
| 52 | char name[1]; | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct class { | ||
| 56 | struct class *next; | ||
| 57 | u_int8_t classid; | ||
| 58 | char name[1]; | ||
| 59 | }; | ||
| 60 | |||
| 61 | struct subclass { | ||
| 62 | struct subclass *next; | ||
| 63 | u_int8_t classid, subclassid; | ||
| 64 | char name[1]; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct protocol { | ||
| 68 | struct protocol *next; | ||
| 69 | u_int8_t classid, subclassid, protocolid; | ||
| 70 | char name[1]; | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct genericstrtable { | ||
| 74 | struct genericstrtable *next; | ||
| 75 | unsigned int num; | ||
| 76 | char name[1]; | ||
| 77 | }; | ||
| 78 | |||
| 79 | |||
| 80 | #define HASH1 0x10 | ||
| 81 | #define HASH2 0x02 | ||
| 82 | #define HASHSZ 16 | ||
| 83 | |||
| 84 | static unsigned int hashnum(unsigned int num) | ||
| 85 | { | ||
| 86 | unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; | ||
| 87 | |||
| 88 | for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) | ||
| 89 | if (num & mask1) | ||
| 90 | num ^= mask2; | ||
| 91 | return num & (HASHSZ-1); | ||
| 92 | } | ||
| 93 | |||
| 94 | |||
| 95 | static struct vendor *vendors[HASHSZ] = { NULL, }; | ||
| 96 | static struct product *products[HASHSZ] = { NULL, }; | ||
| 97 | static struct class *classes[HASHSZ] = { NULL, }; | ||
| 98 | static struct subclass *subclasses[HASHSZ] = { NULL, }; | ||
| 99 | static struct protocol *protocols[HASHSZ] = { NULL, }; | ||
| 100 | |||
| 101 | const char *names_vendor(u_int16_t vendorid) | ||
| 102 | { | ||
| 103 | struct vendor *v; | ||
| 104 | |||
| 105 | v = vendors[hashnum(vendorid)]; | ||
| 106 | for (; v; v = v->next) | ||
| 107 | if (v->vendorid == vendorid) | ||
| 108 | return v->name; | ||
| 109 | return NULL; | ||
| 110 | } | ||
| 111 | |||
| 112 | const char *names_product(u_int16_t vendorid, u_int16_t productid) | ||
| 113 | { | ||
| 114 | struct product *p; | ||
| 115 | |||
| 116 | p = products[hashnum((vendorid << 16) | productid)]; | ||
| 117 | for (; p; p = p->next) | ||
| 118 | if (p->vendorid == vendorid && p->productid == productid) | ||
| 119 | return p->name; | ||
| 120 | return NULL; | ||
| 121 | } | ||
| 122 | |||
| 123 | const char *names_class(u_int8_t classid) | ||
| 124 | { | ||
| 125 | struct class *c; | ||
| 126 | |||
| 127 | c = classes[hashnum(classid)]; | ||
| 128 | for (; c; c = c->next) | ||
| 129 | if (c->classid == classid) | ||
| 130 | return c->name; | ||
| 131 | return NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | const char *names_subclass(u_int8_t classid, u_int8_t subclassid) | ||
| 135 | { | ||
| 136 | struct subclass *s; | ||
| 137 | |||
| 138 | s = subclasses[hashnum((classid << 8) | subclassid)]; | ||
| 139 | for (; s; s = s->next) | ||
| 140 | if (s->classid == classid && s->subclassid == subclassid) | ||
| 141 | return s->name; | ||
| 142 | return NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | const char *names_protocol(u_int8_t classid, u_int8_t subclassid, | ||
| 146 | u_int8_t protocolid) | ||
| 147 | { | ||
| 148 | struct protocol *p; | ||
| 149 | |||
| 150 | p = protocols[hashnum((classid << 16) | (subclassid << 8) | ||
| 151 | | protocolid)]; | ||
| 152 | for (; p; p = p->next) | ||
| 153 | if (p->classid == classid && p->subclassid == subclassid && | ||
| 154 | p->protocolid == protocolid) | ||
| 155 | return p->name; | ||
| 156 | return NULL; | ||
| 157 | } | ||
| 158 | |||
| 159 | /* add a cleanup function by takahiro */ | ||
| 160 | struct pool { | ||
| 161 | struct pool *next; | ||
| 162 | void *mem; | ||
| 163 | }; | ||
| 164 | |||
| 165 | static struct pool *pool_head; | ||
| 166 | |||
| 167 | static void *my_malloc(size_t size) | ||
| 168 | { | ||
| 169 | struct pool *p; | ||
| 170 | |||
| 171 | p = calloc(1, sizeof(struct pool)); | ||
| 172 | if (!p) | ||
| 173 | return NULL; | ||
| 174 | |||
| 175 | p->mem = calloc(1, size); | ||
| 176 | if (!p->mem) { | ||
| 177 | free(p); | ||
| 178 | return NULL; | ||
| 179 | } | ||
| 180 | |||
| 181 | p->next = pool_head; | ||
| 182 | pool_head = p; | ||
| 183 | |||
| 184 | return p->mem; | ||
| 185 | } | ||
| 186 | |||
| 187 | void names_free(void) | ||
| 188 | { | ||
| 189 | struct pool *pool; | ||
| 190 | |||
| 191 | if (!pool_head) | ||
| 192 | return; | ||
| 193 | |||
| 194 | for (pool = pool_head; pool != NULL; ) { | ||
| 195 | struct pool *tmp; | ||
| 196 | |||
| 197 | if (pool->mem) | ||
| 198 | free(pool->mem); | ||
| 199 | |||
| 200 | tmp = pool; | ||
| 201 | pool = pool->next; | ||
| 202 | free(tmp); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | static int new_vendor(const char *name, u_int16_t vendorid) | ||
| 207 | { | ||
| 208 | struct vendor *v; | ||
| 209 | unsigned int h = hashnum(vendorid); | ||
| 210 | |||
| 211 | v = vendors[h]; | ||
| 212 | for (; v; v = v->next) | ||
| 213 | if (v->vendorid == vendorid) | ||
| 214 | return -1; | ||
| 215 | v = my_malloc(sizeof(struct vendor) + strlen(name)); | ||
| 216 | if (!v) | ||
| 217 | return -1; | ||
| 218 | strcpy(v->name, name); | ||
| 219 | v->vendorid = vendorid; | ||
| 220 | v->next = vendors[h]; | ||
| 221 | vendors[h] = v; | ||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int new_product(const char *name, u_int16_t vendorid, | ||
| 226 | u_int16_t productid) | ||
| 227 | { | ||
| 228 | struct product *p; | ||
| 229 | unsigned int h = hashnum((vendorid << 16) | productid); | ||
| 230 | |||
| 231 | p = products[h]; | ||
| 232 | for (; p; p = p->next) | ||
| 233 | if (p->vendorid == vendorid && p->productid == productid) | ||
| 234 | return -1; | ||
| 235 | p = my_malloc(sizeof(struct product) + strlen(name)); | ||
| 236 | if (!p) | ||
| 237 | return -1; | ||
| 238 | strcpy(p->name, name); | ||
| 239 | p->vendorid = vendorid; | ||
| 240 | p->productid = productid; | ||
| 241 | p->next = products[h]; | ||
| 242 | products[h] = p; | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static int new_class(const char *name, u_int8_t classid) | ||
| 247 | { | ||
| 248 | struct class *c; | ||
| 249 | unsigned int h = hashnum(classid); | ||
| 250 | |||
| 251 | c = classes[h]; | ||
| 252 | for (; c; c = c->next) | ||
| 253 | if (c->classid == classid) | ||
| 254 | return -1; | ||
| 255 | c = my_malloc(sizeof(struct class) + strlen(name)); | ||
| 256 | if (!c) | ||
| 257 | return -1; | ||
| 258 | strcpy(c->name, name); | ||
| 259 | c->classid = classid; | ||
| 260 | c->next = classes[h]; | ||
| 261 | classes[h] = c; | ||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) | ||
| 266 | { | ||
| 267 | struct subclass *s; | ||
| 268 | unsigned int h = hashnum((classid << 8) | subclassid); | ||
| 269 | |||
| 270 | s = subclasses[h]; | ||
| 271 | for (; s; s = s->next) | ||
| 272 | if (s->classid == classid && s->subclassid == subclassid) | ||
| 273 | return -1; | ||
| 274 | s = my_malloc(sizeof(struct subclass) + strlen(name)); | ||
| 275 | if (!s) | ||
| 276 | return -1; | ||
| 277 | strcpy(s->name, name); | ||
| 278 | s->classid = classid; | ||
| 279 | s->subclassid = subclassid; | ||
| 280 | s->next = subclasses[h]; | ||
| 281 | subclasses[h] = s; | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, | ||
| 286 | u_int8_t protocolid) | ||
| 287 | { | ||
| 288 | struct protocol *p; | ||
| 289 | unsigned int h = hashnum((classid << 16) | (subclassid << 8) | ||
| 290 | | protocolid); | ||
| 291 | |||
| 292 | p = protocols[h]; | ||
| 293 | for (; p; p = p->next) | ||
| 294 | if (p->classid == classid && p->subclassid == subclassid | ||
| 295 | && p->protocolid == protocolid) | ||
| 296 | return -1; | ||
| 297 | p = my_malloc(sizeof(struct protocol) + strlen(name)); | ||
| 298 | if (!p) | ||
| 299 | return -1; | ||
| 300 | strcpy(p->name, name); | ||
| 301 | p->classid = classid; | ||
| 302 | p->subclassid = subclassid; | ||
| 303 | p->protocolid = protocolid; | ||
| 304 | p->next = protocols[h]; | ||
| 305 | protocols[h] = p; | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | |||
| 309 | static void parse(FILE *f) | ||
| 310 | { | ||
| 311 | char buf[512], *cp; | ||
| 312 | unsigned int linectr = 0; | ||
| 313 | int lastvendor = -1; | ||
| 314 | int lastclass = -1; | ||
| 315 | int lastsubclass = -1; | ||
| 316 | int lasthut = -1; | ||
| 317 | int lastlang = -1; | ||
| 318 | unsigned int u; | ||
| 319 | |||
| 320 | while (fgets(buf, sizeof(buf), f)) { | ||
| 321 | linectr++; | ||
| 322 | /* remove line ends */ | ||
| 323 | cp = strchr(buf, '\r'); | ||
| 324 | if (cp) | ||
| 325 | *cp = 0; | ||
| 326 | cp = strchr(buf, '\n'); | ||
| 327 | if (cp) | ||
| 328 | *cp = 0; | ||
| 329 | if (buf[0] == '#' || !buf[0]) | ||
| 330 | continue; | ||
| 331 | cp = buf; | ||
| 332 | if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && | ||
| 333 | buf[3] == 'S' && buf[4] == 'D' && | ||
| 334 | buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ | ||
| 335 | buf[7] == ' ') { | ||
| 336 | continue; | ||
| 337 | } | ||
| 338 | if (buf[0] == 'P' && buf[1] == 'H' && | ||
| 339 | buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { | ||
| 340 | continue; | ||
| 341 | } | ||
| 342 | if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && | ||
| 343 | buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { | ||
| 344 | continue; | ||
| 345 | } | ||
| 346 | if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { | ||
| 347 | lasthut = lastclass = lastvendor = lastsubclass = -1; | ||
| 348 | /* | ||
| 349 | * set 1 as pseudo-id to indicate that the parser is | ||
| 350 | * in a `L' section. | ||
| 351 | */ | ||
| 352 | lastlang = 1; | ||
| 353 | continue; | ||
| 354 | } | ||
| 355 | if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { | ||
| 356 | /* class spec */ | ||
| 357 | cp = buf+2; | ||
| 358 | while (isspace(*cp)) | ||
| 359 | cp++; | ||
| 360 | if (!isxdigit(*cp)) { | ||
| 361 | err("Invalid class spec at line %u", linectr); | ||
| 362 | continue; | ||
| 363 | } | ||
| 364 | u = strtoul(cp, &cp, 16); | ||
| 365 | while (isspace(*cp)) | ||
| 366 | cp++; | ||
| 367 | if (!*cp) { | ||
| 368 | err("Invalid class spec at line %u", linectr); | ||
| 369 | continue; | ||
| 370 | } | ||
| 371 | if (new_class(cp, u)) | ||
| 372 | err("Duplicate class spec at line %u class %04x %s", | ||
| 373 | linectr, u, cp); | ||
| 374 | dbg("line %5u class %02x %s", linectr, u, cp); | ||
| 375 | lasthut = lastlang = lastvendor = lastsubclass = -1; | ||
| 376 | lastclass = u; | ||
| 377 | continue; | ||
| 378 | } | ||
| 379 | if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { | ||
| 380 | /* audio terminal type spec */ | ||
| 381 | continue; | ||
| 382 | } | ||
| 383 | if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' | ||
| 384 | && isspace(buf[3])) { | ||
| 385 | /* HID Descriptor bCountryCode */ | ||
| 386 | continue; | ||
| 387 | } | ||
| 388 | if (isxdigit(*cp)) { | ||
| 389 | /* vendor */ | ||
| 390 | u = strtoul(cp, &cp, 16); | ||
| 391 | while (isspace(*cp)) | ||
| 392 | cp++; | ||
| 393 | if (!*cp) { | ||
| 394 | err("Invalid vendor spec at line %u", linectr); | ||
| 395 | continue; | ||
| 396 | } | ||
| 397 | if (new_vendor(cp, u)) | ||
| 398 | err("Duplicate vendor spec at line %u vendor %04x %s", | ||
| 399 | linectr, u, cp); | ||
| 400 | dbg("line %5u vendor %04x %s", linectr, u, cp); | ||
| 401 | lastvendor = u; | ||
| 402 | lasthut = lastlang = lastclass = lastsubclass = -1; | ||
| 403 | continue; | ||
| 404 | } | ||
| 405 | if (buf[0] == '\t' && isxdigit(buf[1])) { | ||
| 406 | /* product or subclass spec */ | ||
| 407 | u = strtoul(buf+1, &cp, 16); | ||
| 408 | while (isspace(*cp)) | ||
| 409 | cp++; | ||
| 410 | if (!*cp) { | ||
| 411 | err("Invalid product/subclass spec at line %u", | ||
| 412 | linectr); | ||
| 413 | continue; | ||
| 414 | } | ||
| 415 | if (lastvendor != -1) { | ||
| 416 | if (new_product(cp, lastvendor, u)) | ||
| 417 | err("Duplicate product spec at line %u product %04x:%04x %s", | ||
| 418 | linectr, lastvendor, u, cp); | ||
| 419 | dbg("line %5u product %04x:%04x %s", linectr, | ||
| 420 | lastvendor, u, cp); | ||
| 421 | continue; | ||
| 422 | } | ||
| 423 | if (lastclass != -1) { | ||
| 424 | if (new_subclass(cp, lastclass, u)) | ||
| 425 | err("Duplicate subclass spec at line %u class %02x:%02x %s", | ||
| 426 | linectr, lastclass, u, cp); | ||
| 427 | dbg("line %5u subclass %02x:%02x %s", linectr, | ||
| 428 | lastclass, u, cp); | ||
| 429 | lastsubclass = u; | ||
| 430 | continue; | ||
| 431 | } | ||
| 432 | if (lasthut != -1) { | ||
| 433 | /* do not store hut */ | ||
| 434 | continue; | ||
| 435 | } | ||
| 436 | if (lastlang != -1) { | ||
| 437 | /* do not store langid */ | ||
| 438 | continue; | ||
| 439 | } | ||
| 440 | err("Product/Subclass spec without prior Vendor/Class spec at line %u", | ||
| 441 | linectr); | ||
| 442 | continue; | ||
| 443 | } | ||
| 444 | if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { | ||
| 445 | /* protocol spec */ | ||
| 446 | u = strtoul(buf+2, &cp, 16); | ||
| 447 | while (isspace(*cp)) | ||
| 448 | cp++; | ||
| 449 | if (!*cp) { | ||
| 450 | err("Invalid protocol spec at line %u", | ||
| 451 | linectr); | ||
| 452 | continue; | ||
| 453 | } | ||
| 454 | if (lastclass != -1 && lastsubclass != -1) { | ||
| 455 | if (new_protocol(cp, lastclass, lastsubclass, | ||
| 456 | u)) | ||
| 457 | err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", | ||
| 458 | linectr, lastclass, lastsubclass, | ||
| 459 | u, cp); | ||
| 460 | dbg("line %5u protocol %02x:%02x:%02x %s", | ||
| 461 | linectr, lastclass, lastsubclass, u, cp); | ||
| 462 | continue; | ||
| 463 | } | ||
| 464 | err("Protocol spec without prior Class and Subclass spec at line %u", | ||
| 465 | linectr); | ||
| 466 | continue; | ||
| 467 | } | ||
| 468 | if (buf[0] == 'H' && buf[1] == 'I' && | ||
| 469 | buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { | ||
| 470 | continue; | ||
| 471 | } | ||
| 472 | if (buf[0] == 'H' && buf[1] == 'U' && | ||
| 473 | buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { | ||
| 474 | lastlang = lastclass = lastvendor = lastsubclass = -1; | ||
| 475 | /* | ||
| 476 | * set 1 as pseudo-id to indicate that the parser is | ||
| 477 | * in a `HUT' section. | ||
| 478 | */ | ||
| 479 | lasthut = 1; | ||
| 480 | continue; | ||
| 481 | } | ||
| 482 | if (buf[0] == 'R' && buf[1] == ' ') | ||
| 483 | continue; | ||
| 484 | |||
| 485 | if (buf[0] == 'V' && buf[1] == 'T') | ||
| 486 | continue; | ||
| 487 | |||
| 488 | err("Unknown line at line %u", linectr); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | |||
| 493 | int names_init(char *n) | ||
| 494 | { | ||
| 495 | FILE *f; | ||
| 496 | |||
| 497 | f = fopen(n, "r"); | ||
| 498 | if (!f) | ||
| 499 | return errno; | ||
| 500 | |||
| 501 | parse(f); | ||
| 502 | fclose(f); | ||
| 503 | return 0; | ||
| 504 | } | ||
diff --git a/tools/usb/usbip/libsrc/names.h b/tools/usb/usbip/libsrc/names.h new file mode 100644 index 000000000000..680926512de2 --- /dev/null +++ b/tools/usb/usbip/libsrc/names.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * names.h -- USB name database manipulation routines | ||
| 3 | * | ||
| 4 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | * | ||
| 20 | * | ||
| 21 | * | ||
| 22 | * Copyright (C) 2005 Takahiro Hirofuchi | ||
| 23 | * - names_free() is added. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #ifndef _NAMES_H | ||
| 27 | #define _NAMES_H | ||
| 28 | |||
| 29 | #include <sys/types.h> | ||
| 30 | |||
| 31 | /* used by usbip_common.c */ | ||
| 32 | extern const char *names_vendor(u_int16_t vendorid); | ||
| 33 | extern const char *names_product(u_int16_t vendorid, u_int16_t productid); | ||
| 34 | extern const char *names_class(u_int8_t classid); | ||
| 35 | extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid); | ||
| 36 | extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, | ||
| 37 | u_int8_t protocolid); | ||
| 38 | extern int names_init(char *n); | ||
| 39 | extern void names_free(void); | ||
| 40 | |||
| 41 | #endif /* _NAMES_H */ | ||
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.c b/tools/usb/usbip/libsrc/sysfs_utils.c new file mode 100644 index 000000000000..36ac88ece0b8 --- /dev/null +++ b/tools/usb/usbip/libsrc/sysfs_utils.c | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include <fcntl.h> | ||
| 4 | #include <errno.h> | ||
| 5 | |||
| 6 | #include "sysfs_utils.h" | ||
| 7 | #include "usbip_common.h" | ||
| 8 | |||
| 9 | int write_sysfs_attribute(const char *attr_path, const char *new_value, | ||
| 10 | size_t len) | ||
| 11 | { | ||
| 12 | int fd; | ||
| 13 | int length; | ||
| 14 | |||
| 15 | fd = open(attr_path, O_WRONLY); | ||
| 16 | if (fd < 0) { | ||
| 17 | dbg("error opening attribute %s", attr_path); | ||
| 18 | return -1; | ||
| 19 | } | ||
| 20 | |||
| 21 | length = write(fd, new_value, len); | ||
| 22 | if (length < 0) { | ||
| 23 | dbg("error writing to attribute %s", attr_path); | ||
| 24 | close(fd); | ||
| 25 | return -1; | ||
| 26 | } | ||
| 27 | |||
| 28 | close(fd); | ||
| 29 | |||
| 30 | return 0; | ||
| 31 | } | ||
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.h b/tools/usb/usbip/libsrc/sysfs_utils.h new file mode 100644 index 000000000000..32ac1d105d18 --- /dev/null +++ b/tools/usb/usbip/libsrc/sysfs_utils.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | |||
| 2 | #ifndef __SYSFS_UTILS_H | ||
| 3 | #define __SYSFS_UTILS_H | ||
| 4 | |||
| 5 | int write_sysfs_attribute(const char *attr_path, const char *new_value, | ||
| 6 | size_t len); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c new file mode 100644 index 000000000000..ac73710473de --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_common.c | |||
| @@ -0,0 +1,285 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <libudev.h> | ||
| 6 | #include "usbip_common.h" | ||
| 7 | #include "names.h" | ||
| 8 | |||
| 9 | #undef PROGNAME | ||
| 10 | #define PROGNAME "libusbip" | ||
| 11 | |||
| 12 | int usbip_use_syslog; | ||
| 13 | int usbip_use_stderr; | ||
| 14 | int usbip_use_debug; | ||
| 15 | |||
| 16 | extern struct udev *udev_context; | ||
| 17 | |||
| 18 | struct speed_string { | ||
| 19 | int num; | ||
| 20 | char *speed; | ||
| 21 | char *desc; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static const struct speed_string speed_strings[] = { | ||
| 25 | { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"}, | ||
| 26 | { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, | ||
| 27 | { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, | ||
| 28 | { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, | ||
| 29 | { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, | ||
| 30 | { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, | ||
| 31 | { 0, NULL, NULL } | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct portst_string { | ||
| 35 | int num; | ||
| 36 | char *desc; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static struct portst_string portst_strings[] = { | ||
| 40 | { SDEV_ST_AVAILABLE, "Device Available" }, | ||
| 41 | { SDEV_ST_USED, "Device in Use" }, | ||
| 42 | { SDEV_ST_ERROR, "Device Error"}, | ||
| 43 | { VDEV_ST_NULL, "Port Available"}, | ||
| 44 | { VDEV_ST_NOTASSIGNED, "Port Initializing"}, | ||
| 45 | { VDEV_ST_USED, "Port in Use"}, | ||
| 46 | { VDEV_ST_ERROR, "Port Error"}, | ||
| 47 | { 0, NULL} | ||
| 48 | }; | ||
| 49 | |||
| 50 | const char *usbip_status_string(int32_t status) | ||
| 51 | { | ||
| 52 | for (int i = 0; portst_strings[i].desc != NULL; i++) | ||
| 53 | if (portst_strings[i].num == status) | ||
| 54 | return portst_strings[i].desc; | ||
| 55 | |||
| 56 | return "Unknown Status"; | ||
| 57 | } | ||
| 58 | |||
| 59 | const char *usbip_speed_string(int num) | ||
| 60 | { | ||
| 61 | for (int i = 0; speed_strings[i].speed != NULL; i++) | ||
| 62 | if (speed_strings[i].num == num) | ||
| 63 | return speed_strings[i].desc; | ||
| 64 | |||
| 65 | return "Unknown Speed"; | ||
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | #define DBG_UDEV_INTEGER(name)\ | ||
| 70 | dbg("%-20s = %x", to_string(name), (int) udev->name) | ||
| 71 | |||
| 72 | #define DBG_UINF_INTEGER(name)\ | ||
| 73 | dbg("%-20s = %x", to_string(name), (int) uinf->name) | ||
| 74 | |||
| 75 | void dump_usb_interface(struct usbip_usb_interface *uinf) | ||
| 76 | { | ||
| 77 | char buff[100]; | ||
| 78 | |||
| 79 | usbip_names_get_class(buff, sizeof(buff), | ||
| 80 | uinf->bInterfaceClass, | ||
| 81 | uinf->bInterfaceSubClass, | ||
| 82 | uinf->bInterfaceProtocol); | ||
| 83 | dbg("%-20s = %s", "Interface(C/SC/P)", buff); | ||
| 84 | } | ||
| 85 | |||
| 86 | void dump_usb_device(struct usbip_usb_device *udev) | ||
| 87 | { | ||
| 88 | char buff[100]; | ||
| 89 | |||
| 90 | dbg("%-20s = %s", "path", udev->path); | ||
| 91 | dbg("%-20s = %s", "busid", udev->busid); | ||
| 92 | |||
| 93 | usbip_names_get_class(buff, sizeof(buff), | ||
| 94 | udev->bDeviceClass, | ||
| 95 | udev->bDeviceSubClass, | ||
| 96 | udev->bDeviceProtocol); | ||
| 97 | dbg("%-20s = %s", "Device(C/SC/P)", buff); | ||
| 98 | |||
| 99 | DBG_UDEV_INTEGER(bcdDevice); | ||
| 100 | |||
| 101 | usbip_names_get_product(buff, sizeof(buff), | ||
| 102 | udev->idVendor, | ||
| 103 | udev->idProduct); | ||
| 104 | dbg("%-20s = %s", "Vendor/Product", buff); | ||
| 105 | |||
| 106 | DBG_UDEV_INTEGER(bNumConfigurations); | ||
| 107 | DBG_UDEV_INTEGER(bNumInterfaces); | ||
| 108 | |||
| 109 | dbg("%-20s = %s", "speed", | ||
| 110 | usbip_speed_string(udev->speed)); | ||
| 111 | |||
| 112 | DBG_UDEV_INTEGER(busnum); | ||
| 113 | DBG_UDEV_INTEGER(devnum); | ||
| 114 | } | ||
| 115 | |||
| 116 | |||
| 117 | int read_attr_value(struct udev_device *dev, const char *name, | ||
| 118 | const char *format) | ||
| 119 | { | ||
| 120 | const char *attr; | ||
| 121 | int num = 0; | ||
| 122 | int ret; | ||
| 123 | |||
| 124 | attr = udev_device_get_sysattr_value(dev, name); | ||
| 125 | if (!attr) { | ||
| 126 | err("udev_device_get_sysattr_value failed"); | ||
| 127 | goto err; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* The client chooses the device configuration | ||
| 131 | * when attaching it so right after being bound | ||
| 132 | * to usbip-host on the server the device will | ||
| 133 | * have no configuration. | ||
| 134 | * Therefore, attributes such as bConfigurationValue | ||
| 135 | * and bNumInterfaces will not exist and sscanf will | ||
| 136 | * fail. Check for these cases and don't treat them | ||
| 137 | * as errors. | ||
| 138 | */ | ||
| 139 | |||
| 140 | ret = sscanf(attr, format, &num); | ||
| 141 | if (ret < 1) { | ||
| 142 | if (strcmp(name, "bConfigurationValue") && | ||
| 143 | strcmp(name, "bNumInterfaces")) { | ||
| 144 | err("sscanf failed for attribute %s", name); | ||
| 145 | goto err; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | err: | ||
| 150 | |||
| 151 | return num; | ||
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | int read_attr_speed(struct udev_device *dev) | ||
| 156 | { | ||
| 157 | const char *speed; | ||
| 158 | |||
| 159 | speed = udev_device_get_sysattr_value(dev, "speed"); | ||
| 160 | if (!speed) { | ||
| 161 | err("udev_device_get_sysattr_value failed"); | ||
| 162 | goto err; | ||
| 163 | } | ||
| 164 | |||
| 165 | for (int i = 0; speed_strings[i].speed != NULL; i++) { | ||
| 166 | if (!strcmp(speed, speed_strings[i].speed)) | ||
| 167 | return speed_strings[i].num; | ||
| 168 | } | ||
| 169 | |||
| 170 | err: | ||
| 171 | |||
| 172 | return USB_SPEED_UNKNOWN; | ||
| 173 | } | ||
| 174 | |||
| 175 | #define READ_ATTR(object, type, dev, name, format) \ | ||
| 176 | do { \ | ||
| 177 | (object)->name = (type) read_attr_value(dev, to_string(name), \ | ||
| 178 | format); \ | ||
| 179 | } while (0) | ||
| 180 | |||
| 181 | |||
| 182 | int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev) | ||
| 183 | { | ||
| 184 | uint32_t busnum, devnum; | ||
| 185 | const char *path, *name; | ||
| 186 | |||
| 187 | READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); | ||
| 188 | READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); | ||
| 189 | READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n"); | ||
| 190 | |||
| 191 | READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n"); | ||
| 192 | READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n"); | ||
| 193 | READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n"); | ||
| 194 | |||
| 195 | READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n"); | ||
| 196 | READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n"); | ||
| 197 | READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n"); | ||
| 198 | |||
| 199 | READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); | ||
| 200 | udev->speed = read_attr_speed(sdev); | ||
| 201 | |||
| 202 | path = udev_device_get_syspath(sdev); | ||
| 203 | name = udev_device_get_sysname(sdev); | ||
| 204 | |||
| 205 | strncpy(udev->path, path, SYSFS_PATH_MAX); | ||
| 206 | strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE); | ||
| 207 | |||
| 208 | sscanf(name, "%u-%u", &busnum, &devnum); | ||
| 209 | udev->busnum = busnum; | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | int read_usb_interface(struct usbip_usb_device *udev, int i, | ||
| 215 | struct usbip_usb_interface *uinf) | ||
| 216 | { | ||
| 217 | char busid[SYSFS_BUS_ID_SIZE]; | ||
| 218 | struct udev_device *sif; | ||
| 219 | |||
| 220 | sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); | ||
| 221 | |||
| 222 | sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); | ||
| 223 | if (!sif) { | ||
| 224 | err("udev_device_new_from_subsystem_sysname %s failed", 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 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | int usbip_names_init(char *f) | ||
| 236 | { | ||
| 237 | return names_init(f); | ||
| 238 | } | ||
| 239 | |||
| 240 | void usbip_names_free(void) | ||
| 241 | { | ||
| 242 | names_free(); | ||
| 243 | } | ||
| 244 | |||
| 245 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, | ||
| 246 | uint16_t product) | ||
| 247 | { | ||
| 248 | const char *prod, *vend; | ||
| 249 | |||
| 250 | prod = names_product(vendor, product); | ||
| 251 | if (!prod) | ||
| 252 | prod = "unknown product"; | ||
| 253 | |||
| 254 | |||
| 255 | vend = names_vendor(vendor); | ||
| 256 | if (!vend) | ||
| 257 | vend = "unknown vendor"; | ||
| 258 | |||
| 259 | snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product); | ||
| 260 | } | ||
| 261 | |||
| 262 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, | ||
| 263 | uint8_t subclass, uint8_t protocol) | ||
| 264 | { | ||
| 265 | const char *c, *s, *p; | ||
| 266 | |||
| 267 | if (class == 0 && subclass == 0 && protocol == 0) { | ||
| 268 | snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol); | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | |||
| 272 | p = names_protocol(class, subclass, protocol); | ||
| 273 | if (!p) | ||
| 274 | p = "unknown protocol"; | ||
| 275 | |||
| 276 | s = names_subclass(class, subclass); | ||
| 277 | if (!s) | ||
| 278 | s = "unknown subclass"; | ||
| 279 | |||
| 280 | c = names_class(class); | ||
| 281 | if (!c) | ||
| 282 | c = "unknown class"; | ||
| 283 | |||
| 284 | snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol); | ||
| 285 | } | ||
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h new file mode 100644 index 000000000000..15fe792e1e96 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_common.h | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef __USBIP_COMMON_H | ||
| 6 | #define __USBIP_COMMON_H | ||
| 7 | |||
| 8 | #include <libudev.h> | ||
| 9 | |||
| 10 | #include <stdint.h> | ||
| 11 | #include <stdio.h> | ||
| 12 | #include <stdlib.h> | ||
| 13 | #include <string.h> | ||
| 14 | |||
| 15 | #include <syslog.h> | ||
| 16 | #include <unistd.h> | ||
| 17 | #include <linux/usb/ch9.h> | ||
| 18 | #include <linux/usbip.h> | ||
| 19 | |||
| 20 | #ifndef USBIDS_FILE | ||
| 21 | #define USBIDS_FILE "/usr/share/hwdata/usb.ids" | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #ifndef VHCI_STATE_PATH | ||
| 25 | #define VHCI_STATE_PATH "/var/run/vhci_hcd" | ||
| 26 | #endif | ||
| 27 | |||
| 28 | /* kernel module names */ | ||
| 29 | #define USBIP_CORE_MOD_NAME "usbip-core" | ||
| 30 | #define USBIP_HOST_DRV_NAME "usbip-host" | ||
| 31 | #define USBIP_VHCI_DRV_NAME "vhci_hcd" | ||
| 32 | |||
| 33 | /* sysfs constants */ | ||
| 34 | #define SYSFS_MNT_PATH "/sys" | ||
| 35 | #define SYSFS_BUS_NAME "bus" | ||
| 36 | #define SYSFS_BUS_TYPE "usb" | ||
| 37 | #define SYSFS_DRIVERS_NAME "drivers" | ||
| 38 | |||
| 39 | #define SYSFS_PATH_MAX 256 | ||
| 40 | #define SYSFS_BUS_ID_SIZE 32 | ||
| 41 | |||
| 42 | extern int usbip_use_syslog; | ||
| 43 | extern int usbip_use_stderr; | ||
| 44 | extern int usbip_use_debug ; | ||
| 45 | |||
| 46 | #define PROGNAME "usbip" | ||
| 47 | |||
| 48 | #define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME | ||
| 49 | #define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \ | ||
| 50 | __FILE__, __LINE__, __func__ | ||
| 51 | |||
| 52 | #define err(fmt, args...) \ | ||
| 53 | do { \ | ||
| 54 | if (usbip_use_syslog) { \ | ||
| 55 | syslog(LOG_ERR, pr_fmt(fmt), "error", ##args); \ | ||
| 56 | } \ | ||
| 57 | if (usbip_use_stderr) { \ | ||
| 58 | fprintf(stderr, pr_fmt(fmt), "error", ##args); \ | ||
| 59 | } \ | ||
| 60 | } while (0) | ||
| 61 | |||
| 62 | #define info(fmt, args...) \ | ||
| 63 | do { \ | ||
| 64 | if (usbip_use_syslog) { \ | ||
| 65 | syslog(LOG_INFO, pr_fmt(fmt), "info", ##args); \ | ||
| 66 | } \ | ||
| 67 | if (usbip_use_stderr) { \ | ||
| 68 | fprintf(stderr, pr_fmt(fmt), "info", ##args); \ | ||
| 69 | } \ | ||
| 70 | } while (0) | ||
| 71 | |||
| 72 | #define dbg(fmt, args...) \ | ||
| 73 | do { \ | ||
| 74 | if (usbip_use_debug) { \ | ||
| 75 | if (usbip_use_syslog) { \ | ||
| 76 | syslog(LOG_DEBUG, dbg_fmt(fmt), ##args); \ | ||
| 77 | } \ | ||
| 78 | if (usbip_use_stderr) { \ | ||
| 79 | fprintf(stderr, dbg_fmt(fmt), ##args); \ | ||
| 80 | } \ | ||
| 81 | } \ | ||
| 82 | } while (0) | ||
| 83 | |||
| 84 | #define BUG() \ | ||
| 85 | do { \ | ||
| 86 | err("sorry, it's a bug!"); \ | ||
| 87 | abort(); \ | ||
| 88 | } while (0) | ||
| 89 | |||
| 90 | struct usbip_usb_interface { | ||
| 91 | uint8_t bInterfaceClass; | ||
| 92 | uint8_t bInterfaceSubClass; | ||
| 93 | uint8_t bInterfaceProtocol; | ||
| 94 | uint8_t padding; /* alignment */ | ||
| 95 | } __attribute__((packed)); | ||
| 96 | |||
| 97 | struct usbip_usb_device { | ||
| 98 | char path[SYSFS_PATH_MAX]; | ||
| 99 | char busid[SYSFS_BUS_ID_SIZE]; | ||
| 100 | |||
| 101 | uint32_t busnum; | ||
| 102 | uint32_t devnum; | ||
| 103 | uint32_t speed; | ||
| 104 | |||
| 105 | uint16_t idVendor; | ||
| 106 | uint16_t idProduct; | ||
| 107 | uint16_t bcdDevice; | ||
| 108 | |||
| 109 | uint8_t bDeviceClass; | ||
| 110 | uint8_t bDeviceSubClass; | ||
| 111 | uint8_t bDeviceProtocol; | ||
| 112 | uint8_t bConfigurationValue; | ||
| 113 | uint8_t bNumConfigurations; | ||
| 114 | uint8_t bNumInterfaces; | ||
| 115 | } __attribute__((packed)); | ||
| 116 | |||
| 117 | #define to_string(s) #s | ||
| 118 | |||
| 119 | void dump_usb_interface(struct usbip_usb_interface *); | ||
| 120 | void dump_usb_device(struct usbip_usb_device *); | ||
| 121 | int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev); | ||
| 122 | int read_attr_value(struct udev_device *dev, const char *name, | ||
| 123 | const char *format); | ||
| 124 | int read_usb_interface(struct usbip_usb_device *udev, int i, | ||
| 125 | struct usbip_usb_interface *uinf); | ||
| 126 | |||
| 127 | const char *usbip_speed_string(int num); | ||
| 128 | const char *usbip_status_string(int32_t status); | ||
| 129 | |||
| 130 | int usbip_names_init(char *); | ||
| 131 | void usbip_names_free(void); | ||
| 132 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, | ||
| 133 | uint16_t product); | ||
| 134 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, | ||
| 135 | uint8_t subclass, uint8_t protocol); | ||
| 136 | |||
| 137 | #endif /* __USBIP_COMMON_H */ | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c new file mode 100644 index 000000000000..bef08d5c44e8 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_host_driver.c | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <sys/types.h> | ||
| 20 | #include <sys/stat.h> | ||
| 21 | #include <fcntl.h> | ||
| 22 | |||
| 23 | #include <errno.h> | ||
| 24 | #include <unistd.h> | ||
| 25 | |||
| 26 | #include <libudev.h> | ||
| 27 | |||
| 28 | #include "usbip_common.h" | ||
| 29 | #include "usbip_host_driver.h" | ||
| 30 | #include "list.h" | ||
| 31 | #include "sysfs_utils.h" | ||
| 32 | |||
| 33 | #undef PROGNAME | ||
| 34 | #define PROGNAME "libusbip" | ||
| 35 | |||
| 36 | struct usbip_host_driver *host_driver; | ||
| 37 | struct udev *udev_context; | ||
| 38 | |||
| 39 | static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | ||
| 40 | { | ||
| 41 | char status_attr_path[SYSFS_PATH_MAX]; | ||
| 42 | int fd; | ||
| 43 | int length; | ||
| 44 | char status; | ||
| 45 | int value = 0; | ||
| 46 | |||
| 47 | snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", | ||
| 48 | udev->path); | ||
| 49 | |||
| 50 | fd = open(status_attr_path, O_RDONLY); | ||
| 51 | if (fd < 0) { | ||
| 52 | err("error opening attribute %s", status_attr_path); | ||
| 53 | return -1; | ||
| 54 | } | ||
| 55 | |||
| 56 | length = read(fd, &status, 1); | ||
| 57 | if (length < 0) { | ||
| 58 | err("error reading attribute %s", status_attr_path); | ||
| 59 | close(fd); | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | |||
| 63 | value = atoi(&status); | ||
| 64 | |||
| 65 | return value; | ||
| 66 | } | ||
| 67 | |||
| 68 | static | ||
| 69 | struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath) | ||
| 70 | { | ||
| 71 | struct usbip_exported_device *edev = NULL; | ||
| 72 | struct usbip_exported_device *edev_old; | ||
| 73 | size_t size; | ||
| 74 | int i; | ||
| 75 | |||
| 76 | edev = calloc(1, sizeof(struct usbip_exported_device)); | ||
| 77 | |||
| 78 | edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath); | ||
| 79 | if (!edev->sudev) { | ||
| 80 | err("udev_device_new_from_syspath: %s", sdevpath); | ||
| 81 | goto err; | ||
| 82 | } | ||
| 83 | |||
| 84 | read_usb_device(edev->sudev, &edev->udev); | ||
| 85 | |||
| 86 | edev->status = read_attr_usbip_status(&edev->udev); | ||
| 87 | if (edev->status < 0) | ||
| 88 | goto err; | ||
| 89 | |||
| 90 | /* reallocate buffer to include usb interface data */ | ||
| 91 | size = sizeof(struct usbip_exported_device) + | ||
| 92 | edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); | ||
| 93 | |||
| 94 | edev_old = edev; | ||
| 95 | edev = realloc(edev, size); | ||
| 96 | if (!edev) { | ||
| 97 | edev = edev_old; | ||
| 98 | dbg("realloc failed"); | ||
| 99 | goto err; | ||
| 100 | } | ||
| 101 | |||
| 102 | for (i = 0; i < edev->udev.bNumInterfaces; i++) | ||
| 103 | read_usb_interface(&edev->udev, i, &edev->uinf[i]); | ||
| 104 | |||
| 105 | return edev; | ||
| 106 | err: | ||
| 107 | if (edev->sudev) | ||
| 108 | udev_device_unref(edev->sudev); | ||
| 109 | if (edev) | ||
| 110 | free(edev); | ||
| 111 | |||
| 112 | return NULL; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int refresh_exported_devices(void) | ||
| 116 | { | ||
| 117 | struct usbip_exported_device *edev; | ||
| 118 | struct udev_enumerate *enumerate; | ||
| 119 | struct udev_list_entry *devices, *dev_list_entry; | ||
| 120 | struct udev_device *dev; | ||
| 121 | const char *path; | ||
| 122 | const char *driver; | ||
| 123 | |||
| 124 | enumerate = udev_enumerate_new(udev_context); | ||
| 125 | udev_enumerate_add_match_subsystem(enumerate, "usb"); | ||
| 126 | udev_enumerate_scan_devices(enumerate); | ||
| 127 | |||
| 128 | devices = udev_enumerate_get_list_entry(enumerate); | ||
| 129 | |||
| 130 | udev_list_entry_foreach(dev_list_entry, devices) { | ||
| 131 | path = udev_list_entry_get_name(dev_list_entry); | ||
| 132 | dev = udev_device_new_from_syspath(udev_context, path); | ||
| 133 | if (dev == NULL) | ||
| 134 | continue; | ||
| 135 | |||
| 136 | /* Check whether device uses usbip-host driver. */ | ||
| 137 | driver = udev_device_get_driver(dev); | ||
| 138 | if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) { | ||
| 139 | edev = usbip_exported_device_new(path); | ||
| 140 | if (!edev) { | ||
| 141 | dbg("usbip_exported_device_new failed"); | ||
| 142 | continue; | ||
| 143 | } | ||
| 144 | |||
| 145 | list_add(&edev->node, &host_driver->edev_list); | ||
| 146 | host_driver->ndevs++; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static void usbip_exported_device_destroy(void) | ||
| 154 | { | ||
| 155 | struct list_head *i, *tmp; | ||
| 156 | struct usbip_exported_device *edev; | ||
| 157 | |||
| 158 | list_for_each_safe(i, tmp, &host_driver->edev_list) { | ||
| 159 | edev = list_entry(i, struct usbip_exported_device, node); | ||
| 160 | list_del(i); | ||
| 161 | free(edev); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | int usbip_host_driver_open(void) | ||
| 166 | { | ||
| 167 | int rc; | ||
| 168 | |||
| 169 | udev_context = udev_new(); | ||
| 170 | if (!udev_context) { | ||
| 171 | err("udev_new failed"); | ||
| 172 | return -1; | ||
| 173 | } | ||
| 174 | |||
| 175 | host_driver = calloc(1, sizeof(*host_driver)); | ||
| 176 | |||
| 177 | host_driver->ndevs = 0; | ||
| 178 | INIT_LIST_HEAD(&host_driver->edev_list); | ||
| 179 | |||
| 180 | rc = refresh_exported_devices(); | ||
| 181 | if (rc < 0) | ||
| 182 | goto err_free_host_driver; | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | |||
| 186 | err_free_host_driver: | ||
| 187 | free(host_driver); | ||
| 188 | host_driver = NULL; | ||
| 189 | |||
| 190 | udev_unref(udev_context); | ||
| 191 | |||
| 192 | return -1; | ||
| 193 | } | ||
| 194 | |||
| 195 | void usbip_host_driver_close(void) | ||
| 196 | { | ||
| 197 | if (!host_driver) | ||
| 198 | return; | ||
| 199 | |||
| 200 | usbip_exported_device_destroy(); | ||
| 201 | |||
| 202 | free(host_driver); | ||
| 203 | host_driver = NULL; | ||
| 204 | |||
| 205 | udev_unref(udev_context); | ||
| 206 | } | ||
| 207 | |||
| 208 | int usbip_host_refresh_device_list(void) | ||
| 209 | { | ||
| 210 | int rc; | ||
| 211 | |||
| 212 | usbip_exported_device_destroy(); | ||
| 213 | |||
| 214 | host_driver->ndevs = 0; | ||
| 215 | INIT_LIST_HEAD(&host_driver->edev_list); | ||
| 216 | |||
| 217 | rc = refresh_exported_devices(); | ||
| 218 | if (rc < 0) | ||
| 219 | return -1; | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) | ||
| 225 | { | ||
| 226 | char attr_name[] = "usbip_sockfd"; | ||
| 227 | char sockfd_attr_path[SYSFS_PATH_MAX]; | ||
| 228 | char sockfd_buff[30]; | ||
| 229 | int ret; | ||
| 230 | |||
| 231 | if (edev->status != SDEV_ST_AVAILABLE) { | ||
| 232 | dbg("device not available: %s", edev->udev.busid); | ||
| 233 | switch (edev->status) { | ||
| 234 | case SDEV_ST_ERROR: | ||
| 235 | dbg("status SDEV_ST_ERROR"); | ||
| 236 | break; | ||
| 237 | case SDEV_ST_USED: | ||
| 238 | dbg("status SDEV_ST_USED"); | ||
| 239 | break; | ||
| 240 | default: | ||
| 241 | dbg("status unknown: 0x%x", edev->status); | ||
| 242 | } | ||
| 243 | return -1; | ||
| 244 | } | ||
| 245 | |||
| 246 | /* only the first interface is true */ | ||
| 247 | snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", | ||
| 248 | edev->udev.path, attr_name); | ||
| 249 | |||
| 250 | snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); | ||
| 251 | |||
| 252 | ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, | ||
| 253 | strlen(sockfd_buff)); | ||
| 254 | if (ret < 0) { | ||
| 255 | err("write_sysfs_attribute failed: sockfd %s to %s", | ||
| 256 | sockfd_buff, sockfd_attr_path); | ||
| 257 | return ret; | ||
| 258 | } | ||
| 259 | |||
| 260 | info("connect: %s", edev->udev.busid); | ||
| 261 | |||
| 262 | return ret; | ||
| 263 | } | ||
| 264 | |||
| 265 | struct usbip_exported_device *usbip_host_get_device(int num) | ||
| 266 | { | ||
| 267 | struct list_head *i; | ||
| 268 | struct usbip_exported_device *edev; | ||
| 269 | int cnt = 0; | ||
| 270 | |||
| 271 | list_for_each(i, &host_driver->edev_list) { | ||
| 272 | edev = list_entry(i, struct usbip_exported_device, node); | ||
| 273 | if (num == cnt) | ||
| 274 | return edev; | ||
| 275 | else | ||
| 276 | cnt++; | ||
| 277 | } | ||
| 278 | |||
| 279 | return NULL; | ||
| 280 | } | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h new file mode 100644 index 000000000000..2a31f855c616 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_host_driver.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __USBIP_HOST_DRIVER_H | ||
| 20 | #define __USBIP_HOST_DRIVER_H | ||
| 21 | |||
| 22 | #include <stdint.h> | ||
| 23 | #include "usbip_common.h" | ||
| 24 | #include "list.h" | ||
| 25 | |||
| 26 | struct usbip_host_driver { | ||
| 27 | int ndevs; | ||
| 28 | /* list of exported device */ | ||
| 29 | struct list_head edev_list; | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct usbip_exported_device { | ||
| 33 | struct udev_device *sudev; | ||
| 34 | int32_t status; | ||
| 35 | struct usbip_usb_device udev; | ||
| 36 | struct list_head node; | ||
| 37 | struct usbip_usb_interface uinf[]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | extern struct usbip_host_driver *host_driver; | ||
| 41 | |||
| 42 | int usbip_host_driver_open(void); | ||
| 43 | void usbip_host_driver_close(void); | ||
| 44 | |||
| 45 | int usbip_host_refresh_device_list(void); | ||
| 46 | int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd); | ||
| 47 | struct usbip_exported_device *usbip_host_get_device(int num); | ||
| 48 | |||
| 49 | #endif /* __USBIP_HOST_DRIVER_H */ | ||
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c new file mode 100644 index 000000000000..ad9204773533 --- /dev/null +++ b/tools/usb/usbip/libsrc/vhci_driver.c | |||
| @@ -0,0 +1,411 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include "usbip_common.h" | ||
| 6 | #include "vhci_driver.h" | ||
| 7 | #include <limits.h> | ||
| 8 | #include <netdb.h> | ||
| 9 | #include <libudev.h> | ||
| 10 | #include "sysfs_utils.h" | ||
| 11 | |||
| 12 | #undef PROGNAME | ||
| 13 | #define PROGNAME "libusbip" | ||
| 14 | |||
| 15 | struct usbip_vhci_driver *vhci_driver; | ||
| 16 | struct udev *udev_context; | ||
| 17 | |||
| 18 | static struct usbip_imported_device * | ||
| 19 | imported_device_init(struct usbip_imported_device *idev, char *busid) | ||
| 20 | { | ||
| 21 | struct udev_device *sudev; | ||
| 22 | |||
| 23 | sudev = udev_device_new_from_subsystem_sysname(udev_context, | ||
| 24 | "usb", busid); | ||
| 25 | if (!sudev) { | ||
| 26 | dbg("udev_device_new_from_subsystem_sysname failed: %s", busid); | ||
| 27 | goto err; | ||
| 28 | } | ||
| 29 | read_usb_device(sudev, &idev->udev); | ||
| 30 | udev_device_unref(sudev); | ||
| 31 | |||
| 32 | return idev; | ||
| 33 | |||
| 34 | err: | ||
| 35 | return NULL; | ||
| 36 | } | ||
| 37 | |||
| 38 | |||
| 39 | |||
| 40 | static int parse_status(const char *value) | ||
| 41 | { | ||
| 42 | int ret = 0; | ||
| 43 | char *c; | ||
| 44 | |||
| 45 | |||
| 46 | for (int i = 0; i < vhci_driver->nports; i++) | ||
| 47 | memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i])); | ||
| 48 | |||
| 49 | |||
| 50 | /* skip a header line */ | ||
| 51 | c = strchr(value, '\n'); | ||
| 52 | if (!c) | ||
| 53 | return -1; | ||
| 54 | c++; | ||
| 55 | |||
| 56 | while (*c != '\0') { | ||
| 57 | int port, status, speed, devid; | ||
| 58 | unsigned long socket; | ||
| 59 | char lbusid[SYSFS_BUS_ID_SIZE]; | ||
| 60 | |||
| 61 | ret = sscanf(c, "%d %d %d %x %lx %31s\n", | ||
| 62 | &port, &status, &speed, | ||
| 63 | &devid, &socket, lbusid); | ||
| 64 | |||
| 65 | if (ret < 5) { | ||
| 66 | dbg("sscanf failed: %d", ret); | ||
| 67 | BUG(); | ||
| 68 | } | ||
| 69 | |||
| 70 | dbg("port %d status %d speed %d devid %x", | ||
| 71 | port, status, speed, devid); | ||
| 72 | dbg("socket %lx lbusid %s", socket, lbusid); | ||
| 73 | |||
| 74 | |||
| 75 | /* if a device is connected, look at it */ | ||
| 76 | { | ||
| 77 | struct usbip_imported_device *idev = &vhci_driver->idev[port]; | ||
| 78 | |||
| 79 | idev->port = port; | ||
| 80 | idev->status = status; | ||
| 81 | |||
| 82 | idev->devid = devid; | ||
| 83 | |||
| 84 | idev->busnum = (devid >> 16); | ||
| 85 | idev->devnum = (devid & 0x0000ffff); | ||
| 86 | |||
| 87 | if (idev->status != VDEV_ST_NULL | ||
| 88 | && idev->status != VDEV_ST_NOTASSIGNED) { | ||
| 89 | idev = imported_device_init(idev, lbusid); | ||
| 90 | if (!idev) { | ||
| 91 | dbg("imported_device_init failed"); | ||
| 92 | return -1; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | /* go to the next line */ | ||
| 99 | c = strchr(c, '\n'); | ||
| 100 | if (!c) | ||
| 101 | break; | ||
| 102 | c++; | ||
| 103 | } | ||
| 104 | |||
| 105 | dbg("exit"); | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int refresh_imported_device_list(void) | ||
| 111 | { | ||
| 112 | const char *attr_status; | ||
| 113 | |||
| 114 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, | ||
| 115 | "status"); | ||
| 116 | if (!attr_status) { | ||
| 117 | err("udev_device_get_sysattr_value failed"); | ||
| 118 | return -1; | ||
| 119 | } | ||
| 120 | |||
| 121 | return parse_status(attr_status); | ||
| 122 | } | ||
| 123 | |||
| 124 | static int get_nports(void) | ||
| 125 | { | ||
| 126 | char *c; | ||
| 127 | int nports = 0; | ||
| 128 | const char *attr_status; | ||
| 129 | |||
| 130 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, | ||
| 131 | "status"); | ||
| 132 | if (!attr_status) { | ||
| 133 | err("udev_device_get_sysattr_value failed"); | ||
| 134 | return -1; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* skip a header line */ | ||
| 138 | c = strchr(attr_status, '\n'); | ||
| 139 | if (!c) | ||
| 140 | return 0; | ||
| 141 | c++; | ||
| 142 | |||
| 143 | while (*c != '\0') { | ||
| 144 | /* go to the next line */ | ||
| 145 | c = strchr(c, '\n'); | ||
| 146 | if (!c) | ||
| 147 | return nports; | ||
| 148 | c++; | ||
| 149 | nports += 1; | ||
| 150 | } | ||
| 151 | |||
| 152 | return nports; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Read the given port's record. | ||
| 157 | * | ||
| 158 | * To avoid buffer overflow we will read the entire line and | ||
| 159 | * validate each part's size. The initial buffer is padded by 4 to | ||
| 160 | * accommodate the 2 spaces, 1 newline and an additional character | ||
| 161 | * which is needed to properly validate the 3rd part without it being | ||
| 162 | * truncated to an acceptable length. | ||
| 163 | */ | ||
| 164 | static int read_record(int rhport, char *host, unsigned long host_len, | ||
| 165 | char *port, unsigned long port_len, char *busid) | ||
| 166 | { | ||
| 167 | int part; | ||
| 168 | FILE *file; | ||
| 169 | char path[PATH_MAX+1]; | ||
| 170 | char *buffer, *start, *end; | ||
| 171 | char delim[] = {' ', ' ', '\n'}; | ||
| 172 | int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE}; | ||
| 173 | size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4; | ||
| 174 | |||
| 175 | buffer = malloc(buffer_len); | ||
| 176 | if (!buffer) | ||
| 177 | return -1; | ||
| 178 | |||
| 179 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); | ||
| 180 | |||
| 181 | file = fopen(path, "r"); | ||
| 182 | if (!file) { | ||
| 183 | err("fopen"); | ||
| 184 | free(buffer); | ||
| 185 | return -1; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (fgets(buffer, buffer_len, file) == NULL) { | ||
| 189 | err("fgets"); | ||
| 190 | free(buffer); | ||
| 191 | fclose(file); | ||
| 192 | return -1; | ||
| 193 | } | ||
| 194 | fclose(file); | ||
| 195 | |||
| 196 | /* validate the length of each of the 3 parts */ | ||
| 197 | start = buffer; | ||
| 198 | for (part = 0; part < 3; part++) { | ||
| 199 | end = strchr(start, delim[part]); | ||
| 200 | if (end == NULL || (end - start) > max_len[part]) { | ||
| 201 | free(buffer); | ||
| 202 | return -1; | ||
| 203 | } | ||
| 204 | start = end + 1; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) { | ||
| 208 | err("sscanf"); | ||
| 209 | free(buffer); | ||
| 210 | return -1; | ||
| 211 | } | ||
| 212 | |||
| 213 | free(buffer); | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* ---------------------------------------------------------------------- */ | ||
| 219 | |||
| 220 | int usbip_vhci_driver_open(void) | ||
| 221 | { | ||
| 222 | udev_context = udev_new(); | ||
| 223 | if (!udev_context) { | ||
| 224 | err("udev_new failed"); | ||
| 225 | return -1; | ||
| 226 | } | ||
| 227 | |||
| 228 | vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); | ||
| 229 | |||
| 230 | /* will be freed in usbip_driver_close() */ | ||
| 231 | vhci_driver->hc_device = | ||
| 232 | udev_device_new_from_subsystem_sysname(udev_context, | ||
| 233 | USBIP_VHCI_BUS_TYPE, | ||
| 234 | USBIP_VHCI_DRV_NAME); | ||
| 235 | if (!vhci_driver->hc_device) { | ||
| 236 | err("udev_device_new_from_subsystem_sysname failed"); | ||
| 237 | goto err; | ||
| 238 | } | ||
| 239 | |||
| 240 | vhci_driver->nports = get_nports(); | ||
| 241 | |||
| 242 | dbg("available ports: %d", vhci_driver->nports); | ||
| 243 | |||
| 244 | if (refresh_imported_device_list()) | ||
| 245 | goto err; | ||
| 246 | |||
| 247 | return 0; | ||
| 248 | |||
| 249 | err: | ||
| 250 | udev_device_unref(vhci_driver->hc_device); | ||
| 251 | |||
| 252 | if (vhci_driver) | ||
| 253 | free(vhci_driver); | ||
| 254 | |||
| 255 | vhci_driver = NULL; | ||
| 256 | |||
| 257 | udev_unref(udev_context); | ||
| 258 | |||
| 259 | return -1; | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | void usbip_vhci_driver_close(void) | ||
| 264 | { | ||
| 265 | if (!vhci_driver) | ||
| 266 | return; | ||
| 267 | |||
| 268 | udev_device_unref(vhci_driver->hc_device); | ||
| 269 | |||
| 270 | free(vhci_driver); | ||
| 271 | |||
| 272 | vhci_driver = NULL; | ||
| 273 | |||
| 274 | udev_unref(udev_context); | ||
| 275 | } | ||
| 276 | |||
| 277 | |||
| 278 | int usbip_vhci_refresh_device_list(void) | ||
| 279 | { | ||
| 280 | |||
| 281 | if (refresh_imported_device_list()) | ||
| 282 | goto err; | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | err: | ||
| 286 | dbg("failed to refresh device list"); | ||
| 287 | return -1; | ||
| 288 | } | ||
| 289 | |||
| 290 | |||
| 291 | int usbip_vhci_get_free_port(void) | ||
| 292 | { | ||
| 293 | for (int i = 0; i < vhci_driver->nports; i++) { | ||
| 294 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) | ||
| 295 | return i; | ||
| 296 | } | ||
| 297 | |||
| 298 | return -1; | ||
| 299 | } | ||
| 300 | |||
| 301 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, | ||
| 302 | uint32_t speed) { | ||
| 303 | char buff[200]; /* what size should be ? */ | ||
| 304 | char attach_attr_path[SYSFS_PATH_MAX]; | ||
| 305 | char attr_attach[] = "attach"; | ||
| 306 | const char *path; | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | snprintf(buff, sizeof(buff), "%u %d %u %u", | ||
| 310 | port, sockfd, devid, speed); | ||
| 311 | dbg("writing: %s", buff); | ||
| 312 | |||
| 313 | path = udev_device_get_syspath(vhci_driver->hc_device); | ||
| 314 | snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s", | ||
| 315 | path, attr_attach); | ||
| 316 | dbg("attach attribute path: %s", attach_attr_path); | ||
| 317 | |||
| 318 | ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff)); | ||
| 319 | if (ret < 0) { | ||
| 320 | dbg("write_sysfs_attribute failed"); | ||
| 321 | return -1; | ||
| 322 | } | ||
| 323 | |||
| 324 | dbg("attached port: %d", port); | ||
| 325 | |||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static unsigned long get_devid(uint8_t busnum, uint8_t devnum) | ||
| 330 | { | ||
| 331 | return (busnum << 16) | devnum; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* will be removed */ | ||
| 335 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, | ||
| 336 | uint8_t devnum, uint32_t speed) | ||
| 337 | { | ||
| 338 | int devid = get_devid(busnum, devnum); | ||
| 339 | |||
| 340 | return usbip_vhci_attach_device2(port, sockfd, devid, speed); | ||
| 341 | } | ||
| 342 | |||
| 343 | int usbip_vhci_detach_device(uint8_t port) | ||
| 344 | { | ||
| 345 | char detach_attr_path[SYSFS_PATH_MAX]; | ||
| 346 | char attr_detach[] = "detach"; | ||
| 347 | char buff[200]; /* what size should be ? */ | ||
| 348 | const char *path; | ||
| 349 | int ret; | ||
| 350 | |||
| 351 | snprintf(buff, sizeof(buff), "%u", port); | ||
| 352 | dbg("writing: %s", buff); | ||
| 353 | |||
| 354 | path = udev_device_get_syspath(vhci_driver->hc_device); | ||
| 355 | snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s", | ||
| 356 | path, attr_detach); | ||
| 357 | dbg("detach attribute path: %s", detach_attr_path); | ||
| 358 | |||
| 359 | ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff)); | ||
| 360 | if (ret < 0) { | ||
| 361 | dbg("write_sysfs_attribute failed"); | ||
| 362 | return -1; | ||
| 363 | } | ||
| 364 | |||
| 365 | dbg("detached port: %d", port); | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) | ||
| 371 | { | ||
| 372 | char product_name[100]; | ||
| 373 | char host[NI_MAXHOST] = "unknown host"; | ||
| 374 | char serv[NI_MAXSERV] = "unknown port"; | ||
| 375 | char remote_busid[SYSFS_BUS_ID_SIZE]; | ||
| 376 | int ret; | ||
| 377 | int read_record_error = 0; | ||
| 378 | |||
| 379 | if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) | ||
| 380 | return 0; | ||
| 381 | |||
| 382 | ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv), | ||
| 383 | remote_busid); | ||
| 384 | if (ret) { | ||
| 385 | err("read_record"); | ||
| 386 | read_record_error = 1; | ||
| 387 | } | ||
| 388 | |||
| 389 | printf("Port %02d: <%s> at %s\n", idev->port, | ||
| 390 | usbip_status_string(idev->status), | ||
| 391 | usbip_speed_string(idev->udev.speed)); | ||
| 392 | |||
| 393 | usbip_names_get_product(product_name, sizeof(product_name), | ||
| 394 | idev->udev.idVendor, idev->udev.idProduct); | ||
| 395 | |||
| 396 | printf(" %s\n", product_name); | ||
| 397 | |||
| 398 | if (!read_record_error) { | ||
| 399 | printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid, | ||
| 400 | host, serv, remote_busid); | ||
| 401 | printf("%10s -> remote bus/dev %03d/%03d\n", " ", | ||
| 402 | idev->busnum, idev->devnum); | ||
| 403 | } else { | ||
| 404 | printf("%10s -> unknown host, remote port and remote busid\n", | ||
| 405 | idev->udev.busid); | ||
| 406 | printf("%10s -> remote bus/dev %03d/%03d\n", " ", | ||
| 407 | idev->busnum, idev->devnum); | ||
| 408 | } | ||
| 409 | |||
| 410 | return 0; | ||
| 411 | } | ||
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h new file mode 100644 index 000000000000..fa2316cf2cac --- /dev/null +++ b/tools/usb/usbip/libsrc/vhci_driver.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef __VHCI_DRIVER_H | ||
| 6 | #define __VHCI_DRIVER_H | ||
| 7 | |||
| 8 | #include <libudev.h> | ||
| 9 | #include <stdint.h> | ||
| 10 | |||
| 11 | #include "usbip_common.h" | ||
| 12 | |||
| 13 | #define USBIP_VHCI_BUS_TYPE "platform" | ||
| 14 | #define MAXNPORT 128 | ||
| 15 | |||
| 16 | struct usbip_imported_device { | ||
| 17 | uint8_t port; | ||
| 18 | uint32_t status; | ||
| 19 | |||
| 20 | uint32_t devid; | ||
| 21 | |||
| 22 | uint8_t busnum; | ||
| 23 | uint8_t devnum; | ||
| 24 | |||
| 25 | /* usbip_class_device list */ | ||
| 26 | struct usbip_usb_device udev; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct usbip_vhci_driver { | ||
| 30 | |||
| 31 | /* /sys/devices/platform/vhci_hcd */ | ||
| 32 | struct udev_device *hc_device; | ||
| 33 | |||
| 34 | int nports; | ||
| 35 | struct usbip_imported_device idev[MAXNPORT]; | ||
| 36 | }; | ||
| 37 | |||
| 38 | |||
| 39 | extern struct usbip_vhci_driver *vhci_driver; | ||
| 40 | |||
| 41 | int usbip_vhci_driver_open(void); | ||
| 42 | void usbip_vhci_driver_close(void); | ||
| 43 | |||
| 44 | int usbip_vhci_refresh_device_list(void); | ||
| 45 | |||
| 46 | |||
| 47 | int usbip_vhci_get_free_port(void); | ||
| 48 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, | ||
| 49 | uint32_t speed); | ||
| 50 | |||
| 51 | /* will be removed */ | ||
| 52 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, | ||
| 53 | uint8_t devnum, uint32_t speed); | ||
| 54 | |||
| 55 | int usbip_vhci_detach_device(uint8_t port); | ||
| 56 | |||
| 57 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev); | ||
| 58 | |||
| 59 | #endif /* __VHCI_DRIVER_H */ | ||
diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am new file mode 100644 index 000000000000..e81a4ebadeff --- /dev/null +++ b/tools/usb/usbip/src/Makefile.am | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' | ||
| 2 | AM_CFLAGS = @EXTRA_CFLAGS@ | ||
| 3 | LDADD = $(top_builddir)/libsrc/libusbip.la | ||
| 4 | |||
| 5 | sbin_PROGRAMS := usbip usbipd | ||
| 6 | |||
| 7 | usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \ | ||
| 8 | usbip_attach.c usbip_detach.c usbip_list.c \ | ||
| 9 | usbip_bind.c usbip_unbind.c usbip_port.c | ||
| 10 | |||
| 11 | usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c | ||
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c new file mode 100644 index 000000000000..d7599d943529 --- /dev/null +++ b/tools/usb/usbip/src/usbip.c | |||
| @@ -0,0 +1,201 @@ | |||
| 1 | /* | ||
| 2 | * command structure borrowed from udev | ||
| 3 | * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 6 | * 2005-2007 Takahiro Hirofuchi | ||
| 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, see <http://www.gnu.org/licenses/>. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <stdio.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | |||
| 25 | #include <getopt.h> | ||
| 26 | #include <syslog.h> | ||
| 27 | |||
| 28 | #include "usbip_common.h" | ||
| 29 | #include "usbip_network.h" | ||
| 30 | #include "usbip.h" | ||
| 31 | |||
| 32 | static int usbip_help(int argc, char *argv[]); | ||
| 33 | static int usbip_version(int argc, char *argv[]); | ||
| 34 | |||
| 35 | static const char usbip_version_string[] = PACKAGE_STRING; | ||
| 36 | |||
| 37 | static const char usbip_usage_string[] = | ||
| 38 | "usbip [--debug] [--log] [--tcp-port PORT] [version]\n" | ||
| 39 | " [help] <command> <args>\n"; | ||
| 40 | |||
| 41 | static void usbip_usage(void) | ||
| 42 | { | ||
| 43 | printf("usage: %s", usbip_usage_string); | ||
| 44 | } | ||
| 45 | |||
| 46 | struct command { | ||
| 47 | const char *name; | ||
| 48 | int (*fn)(int argc, char *argv[]); | ||
| 49 | const char *help; | ||
| 50 | void (*usage)(void); | ||
| 51 | }; | ||
| 52 | |||
| 53 | static const struct command cmds[] = { | ||
| 54 | { | ||
| 55 | .name = "help", | ||
| 56 | .fn = usbip_help, | ||
| 57 | .help = NULL, | ||
| 58 | .usage = NULL | ||
| 59 | }, | ||
| 60 | { | ||
| 61 | .name = "version", | ||
| 62 | .fn = usbip_version, | ||
| 63 | .help = NULL, | ||
| 64 | .usage = NULL | ||
| 65 | }, | ||
| 66 | { | ||
| 67 | .name = "attach", | ||
| 68 | .fn = usbip_attach, | ||
| 69 | .help = "Attach a remote USB device", | ||
| 70 | .usage = usbip_attach_usage | ||
| 71 | }, | ||
| 72 | { | ||
| 73 | .name = "detach", | ||
| 74 | .fn = usbip_detach, | ||
| 75 | .help = "Detach a remote USB device", | ||
| 76 | .usage = usbip_detach_usage | ||
| 77 | }, | ||
| 78 | { | ||
| 79 | .name = "list", | ||
| 80 | .fn = usbip_list, | ||
| 81 | .help = "List exportable or local USB devices", | ||
| 82 | .usage = usbip_list_usage | ||
| 83 | }, | ||
| 84 | { | ||
| 85 | .name = "bind", | ||
| 86 | .fn = usbip_bind, | ||
| 87 | .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko", | ||
| 88 | .usage = usbip_bind_usage | ||
| 89 | }, | ||
| 90 | { | ||
| 91 | .name = "unbind", | ||
| 92 | .fn = usbip_unbind, | ||
| 93 | .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko", | ||
| 94 | .usage = usbip_unbind_usage | ||
| 95 | }, | ||
| 96 | { | ||
| 97 | .name = "port", | ||
| 98 | .fn = usbip_port_show, | ||
| 99 | .help = "Show imported USB devices", | ||
| 100 | .usage = NULL | ||
| 101 | }, | ||
| 102 | { NULL, NULL, NULL, NULL } | ||
| 103 | }; | ||
| 104 | |||
| 105 | static int usbip_help(int argc, char *argv[]) | ||
| 106 | { | ||
| 107 | const struct command *cmd; | ||
| 108 | int i; | ||
| 109 | int ret = 0; | ||
| 110 | |||
| 111 | if (argc > 1 && argv++) { | ||
| 112 | for (i = 0; cmds[i].name != NULL; i++) | ||
| 113 | if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) { | ||
| 114 | cmds[i].usage(); | ||
| 115 | goto done; | ||
| 116 | } | ||
| 117 | ret = -1; | ||
| 118 | } | ||
| 119 | |||
| 120 | usbip_usage(); | ||
| 121 | printf("\n"); | ||
| 122 | for (cmd = cmds; cmd->name != NULL; cmd++) | ||
| 123 | if (cmd->help != NULL) | ||
| 124 | printf(" %-10s %s\n", cmd->name, cmd->help); | ||
| 125 | printf("\n"); | ||
| 126 | done: | ||
| 127 | return ret; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int usbip_version(int argc, char *argv[]) | ||
| 131 | { | ||
| 132 | (void) argc; | ||
| 133 | (void) argv; | ||
| 134 | |||
| 135 | printf(PROGNAME " (%s)\n", usbip_version_string); | ||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int run_command(const struct command *cmd, int argc, char *argv[]) | ||
| 140 | { | ||
| 141 | dbg("running command: `%s'", cmd->name); | ||
| 142 | return cmd->fn(argc, argv); | ||
| 143 | } | ||
| 144 | |||
| 145 | int main(int argc, char *argv[]) | ||
| 146 | { | ||
| 147 | static const struct option opts[] = { | ||
| 148 | { "debug", no_argument, NULL, 'd' }, | ||
| 149 | { "log", no_argument, NULL, 'l' }, | ||
| 150 | { "tcp-port", required_argument, NULL, 't' }, | ||
| 151 | { NULL, 0, NULL, 0 } | ||
| 152 | }; | ||
| 153 | |||
| 154 | char *cmd; | ||
| 155 | int opt; | ||
| 156 | int i, rc = -1; | ||
| 157 | |||
| 158 | usbip_use_stderr = 1; | ||
| 159 | opterr = 0; | ||
| 160 | for (;;) { | ||
| 161 | opt = getopt_long(argc, argv, "+dlt:", opts, NULL); | ||
| 162 | |||
| 163 | if (opt == -1) | ||
| 164 | break; | ||
| 165 | |||
| 166 | switch (opt) { | ||
| 167 | case 'd': | ||
| 168 | usbip_use_debug = 1; | ||
| 169 | break; | ||
| 170 | case 'l': | ||
| 171 | usbip_use_syslog = 1; | ||
| 172 | openlog("", LOG_PID, LOG_USER); | ||
| 173 | break; | ||
| 174 | case 't': | ||
| 175 | usbip_setup_port_number(optarg); | ||
| 176 | break; | ||
| 177 | case '?': | ||
| 178 | printf("usbip: invalid option\n"); | ||
| 179 | default: | ||
| 180 | usbip_usage(); | ||
| 181 | goto out; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | cmd = argv[optind]; | ||
| 186 | if (cmd) { | ||
| 187 | for (i = 0; cmds[i].name != NULL; i++) | ||
| 188 | if (!strcmp(cmds[i].name, cmd)) { | ||
| 189 | argc -= optind; | ||
| 190 | argv += optind; | ||
| 191 | optind = 0; | ||
| 192 | rc = run_command(&cmds[i], argc, argv); | ||
| 193 | goto out; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | /* invalid command */ | ||
| 198 | usbip_help(0, NULL); | ||
| 199 | out: | ||
| 200 | return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE); | ||
| 201 | } | ||
diff --git a/tools/usb/usbip/src/usbip.h b/tools/usb/usbip/src/usbip.h new file mode 100644 index 000000000000..84fe66a9d8ad --- /dev/null +++ b/tools/usb/usbip/src/usbip.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __USBIP_H | ||
| 20 | #define __USBIP_H | ||
| 21 | |||
| 22 | #ifdef HAVE_CONFIG_H | ||
| 23 | #include "../config.h" | ||
| 24 | #endif | ||
| 25 | |||
| 26 | /* usbip commands */ | ||
| 27 | int usbip_attach(int argc, char *argv[]); | ||
| 28 | int usbip_detach(int argc, char *argv[]); | ||
| 29 | int usbip_list(int argc, char *argv[]); | ||
| 30 | int usbip_bind(int argc, char *argv[]); | ||
| 31 | int usbip_unbind(int argc, char *argv[]); | ||
| 32 | int usbip_port_show(int argc, char *argv[]); | ||
| 33 | |||
| 34 | void usbip_attach_usage(void); | ||
| 35 | void usbip_detach_usage(void); | ||
| 36 | void usbip_list_usage(void); | ||
| 37 | void usbip_bind_usage(void); | ||
| 38 | void usbip_unbind_usage(void); | ||
| 39 | |||
| 40 | #endif /* __USBIP_H */ | ||
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c new file mode 100644 index 000000000000..d58a14dfc094 --- /dev/null +++ b/tools/usb/usbip/src/usbip_attach.c | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <sys/stat.h> | ||
| 20 | |||
| 21 | #include <limits.h> | ||
| 22 | #include <stdint.h> | ||
| 23 | #include <stdio.h> | ||
| 24 | #include <string.h> | ||
| 25 | |||
| 26 | #include <fcntl.h> | ||
| 27 | #include <getopt.h> | ||
| 28 | #include <unistd.h> | ||
| 29 | #include <errno.h> | ||
| 30 | |||
| 31 | #include "vhci_driver.h" | ||
| 32 | #include "usbip_common.h" | ||
| 33 | #include "usbip_network.h" | ||
| 34 | #include "usbip.h" | ||
| 35 | |||
| 36 | static const char usbip_attach_usage_string[] = | ||
| 37 | "usbip attach <args>\n" | ||
| 38 | " -r, --remote=<host> The machine with exported USB devices\n" | ||
| 39 | " -b, --busid=<busid> Busid of the device on <host>\n"; | ||
| 40 | |||
| 41 | void usbip_attach_usage(void) | ||
| 42 | { | ||
| 43 | printf("usage: %s", usbip_attach_usage_string); | ||
| 44 | } | ||
| 45 | |||
| 46 | #define MAX_BUFF 100 | ||
| 47 | static int record_connection(char *host, char *port, char *busid, int rhport) | ||
| 48 | { | ||
| 49 | int fd; | ||
| 50 | char path[PATH_MAX+1]; | ||
| 51 | char buff[MAX_BUFF+1]; | ||
| 52 | int ret; | ||
| 53 | |||
| 54 | ret = mkdir(VHCI_STATE_PATH, 0700); | ||
| 55 | if (ret < 0) { | ||
| 56 | /* if VHCI_STATE_PATH exists, then it better be a directory */ | ||
| 57 | if (errno == EEXIST) { | ||
| 58 | struct stat s; | ||
| 59 | |||
| 60 | ret = stat(VHCI_STATE_PATH, &s); | ||
| 61 | if (ret < 0) | ||
| 62 | return -1; | ||
| 63 | if (!(s.st_mode & S_IFDIR)) | ||
| 64 | return -1; | ||
| 65 | } else | ||
| 66 | return -1; | ||
| 67 | } | ||
| 68 | |||
| 69 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); | ||
| 70 | |||
| 71 | fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); | ||
| 72 | if (fd < 0) | ||
| 73 | return -1; | ||
| 74 | |||
| 75 | snprintf(buff, MAX_BUFF, "%s %s %s\n", | ||
| 76 | host, port, busid); | ||
| 77 | |||
| 78 | ret = write(fd, buff, strlen(buff)); | ||
| 79 | if (ret != (ssize_t) strlen(buff)) { | ||
| 80 | close(fd); | ||
| 81 | return -1; | ||
| 82 | } | ||
| 83 | |||
| 84 | close(fd); | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | static int import_device(int sockfd, struct usbip_usb_device *udev) | ||
| 90 | { | ||
| 91 | int rc; | ||
| 92 | int port; | ||
| 93 | |||
| 94 | rc = usbip_vhci_driver_open(); | ||
| 95 | if (rc < 0) { | ||
| 96 | err("open vhci_driver"); | ||
| 97 | return -1; | ||
| 98 | } | ||
| 99 | |||
| 100 | port = usbip_vhci_get_free_port(); | ||
| 101 | if (port < 0) { | ||
| 102 | err("no free port"); | ||
| 103 | usbip_vhci_driver_close(); | ||
| 104 | return -1; | ||
| 105 | } | ||
| 106 | |||
| 107 | rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, | ||
| 108 | udev->devnum, udev->speed); | ||
| 109 | if (rc < 0) { | ||
| 110 | err("import device"); | ||
| 111 | usbip_vhci_driver_close(); | ||
| 112 | return -1; | ||
| 113 | } | ||
| 114 | |||
| 115 | usbip_vhci_driver_close(); | ||
| 116 | |||
| 117 | return port; | ||
| 118 | } | ||
| 119 | |||
| 120 | static int query_import_device(int sockfd, char *busid) | ||
| 121 | { | ||
| 122 | int rc; | ||
| 123 | struct op_import_request request; | ||
| 124 | struct op_import_reply reply; | ||
| 125 | uint16_t code = OP_REP_IMPORT; | ||
| 126 | |||
| 127 | memset(&request, 0, sizeof(request)); | ||
| 128 | memset(&reply, 0, sizeof(reply)); | ||
| 129 | |||
| 130 | /* send a request */ | ||
| 131 | rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); | ||
| 132 | if (rc < 0) { | ||
| 133 | err("send op_common"); | ||
| 134 | return -1; | ||
| 135 | } | ||
| 136 | |||
| 137 | strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); | ||
| 138 | |||
| 139 | PACK_OP_IMPORT_REQUEST(0, &request); | ||
| 140 | |||
| 141 | rc = usbip_net_send(sockfd, (void *) &request, sizeof(request)); | ||
| 142 | if (rc < 0) { | ||
| 143 | err("send op_import_request"); | ||
| 144 | return -1; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* receive a reply */ | ||
| 148 | rc = usbip_net_recv_op_common(sockfd, &code); | ||
| 149 | if (rc < 0) { | ||
| 150 | err("recv op_common"); | ||
| 151 | return -1; | ||
| 152 | } | ||
| 153 | |||
| 154 | rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply)); | ||
| 155 | if (rc < 0) { | ||
| 156 | err("recv op_import_reply"); | ||
| 157 | return -1; | ||
| 158 | } | ||
| 159 | |||
| 160 | PACK_OP_IMPORT_REPLY(0, &reply); | ||
| 161 | |||
| 162 | /* check the reply */ | ||
| 163 | if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { | ||
| 164 | err("recv different busid %s", reply.udev.busid); | ||
| 165 | return -1; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* import a device */ | ||
| 169 | return import_device(sockfd, &reply.udev); | ||
| 170 | } | ||
| 171 | |||
| 172 | static int attach_device(char *host, char *busid) | ||
| 173 | { | ||
| 174 | int sockfd; | ||
| 175 | int rc; | ||
| 176 | int rhport; | ||
| 177 | |||
| 178 | sockfd = usbip_net_tcp_connect(host, usbip_port_string); | ||
| 179 | if (sockfd < 0) { | ||
| 180 | err("tcp connect"); | ||
| 181 | return -1; | ||
| 182 | } | ||
| 183 | |||
| 184 | rhport = query_import_device(sockfd, busid); | ||
| 185 | if (rhport < 0) { | ||
| 186 | err("query"); | ||
| 187 | return -1; | ||
| 188 | } | ||
| 189 | |||
| 190 | close(sockfd); | ||
| 191 | |||
| 192 | rc = record_connection(host, usbip_port_string, busid, rhport); | ||
| 193 | if (rc < 0) { | ||
| 194 | err("record connection"); | ||
| 195 | return -1; | ||
| 196 | } | ||
| 197 | |||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | int usbip_attach(int argc, char *argv[]) | ||
| 202 | { | ||
| 203 | static const struct option opts[] = { | ||
| 204 | { "remote", required_argument, NULL, 'r' }, | ||
| 205 | { "busid", required_argument, NULL, 'b' }, | ||
| 206 | { NULL, 0, NULL, 0 } | ||
| 207 | }; | ||
| 208 | char *host = NULL; | ||
| 209 | char *busid = NULL; | ||
| 210 | int opt; | ||
| 211 | int ret = -1; | ||
| 212 | |||
| 213 | for (;;) { | ||
| 214 | opt = getopt_long(argc, argv, "r:b:", opts, NULL); | ||
| 215 | |||
| 216 | if (opt == -1) | ||
| 217 | break; | ||
| 218 | |||
| 219 | switch (opt) { | ||
| 220 | case 'r': | ||
| 221 | host = optarg; | ||
| 222 | break; | ||
| 223 | case 'b': | ||
| 224 | busid = optarg; | ||
| 225 | break; | ||
| 226 | default: | ||
| 227 | goto err_out; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | if (!host || !busid) | ||
| 232 | goto err_out; | ||
| 233 | |||
| 234 | ret = attach_device(host, busid); | ||
| 235 | goto out; | ||
| 236 | |||
| 237 | err_out: | ||
| 238 | usbip_attach_usage(); | ||
| 239 | out: | ||
| 240 | return ret; | ||
| 241 | } | ||
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c new file mode 100644 index 000000000000..fa46141ae68b --- /dev/null +++ b/tools/usb/usbip/src/usbip_bind.c | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <libudev.h> | ||
| 20 | |||
| 21 | #include <errno.h> | ||
| 22 | #include <stdio.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <string.h> | ||
| 25 | |||
| 26 | #include <getopt.h> | ||
| 27 | |||
| 28 | #include "usbip_common.h" | ||
| 29 | #include "utils.h" | ||
| 30 | #include "usbip.h" | ||
| 31 | #include "sysfs_utils.h" | ||
| 32 | |||
| 33 | enum unbind_status { | ||
| 34 | UNBIND_ST_OK, | ||
| 35 | UNBIND_ST_USBIP_HOST, | ||
| 36 | UNBIND_ST_FAILED | ||
| 37 | }; | ||
| 38 | |||
| 39 | static const char usbip_bind_usage_string[] = | ||
| 40 | "usbip bind <args>\n" | ||
| 41 | " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device " | ||
| 42 | "on <busid>\n"; | ||
| 43 | |||
| 44 | void usbip_bind_usage(void) | ||
| 45 | { | ||
| 46 | printf("usage: %s", usbip_bind_usage_string); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* call at unbound state */ | ||
| 50 | static int bind_usbip(char *busid) | ||
| 51 | { | ||
| 52 | char attr_name[] = "bind"; | ||
| 53 | char bind_attr_path[SYSFS_PATH_MAX]; | ||
| 54 | int rc = -1; | ||
| 55 | |||
| 56 | snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s", | ||
| 57 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, | ||
| 58 | SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); | ||
| 59 | |||
| 60 | rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid)); | ||
| 61 | if (rc < 0) { | ||
| 62 | err("error binding device %s to driver: %s", busid, | ||
| 63 | strerror(errno)); | ||
| 64 | return -1; | ||
| 65 | } | ||
| 66 | |||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* buggy driver may cause dead lock */ | ||
| 71 | static int unbind_other(char *busid) | ||
| 72 | { | ||
| 73 | enum unbind_status status = UNBIND_ST_OK; | ||
| 74 | |||
| 75 | char attr_name[] = "unbind"; | ||
| 76 | char unbind_attr_path[SYSFS_PATH_MAX]; | ||
| 77 | int rc = -1; | ||
| 78 | |||
| 79 | struct udev *udev; | ||
| 80 | struct udev_device *dev; | ||
| 81 | const char *driver; | ||
| 82 | const char *bDevClass; | ||
| 83 | |||
| 84 | /* Create libudev context. */ | ||
| 85 | udev = udev_new(); | ||
| 86 | |||
| 87 | /* Get the device. */ | ||
| 88 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); | ||
| 89 | if (!dev) { | ||
| 90 | dbg("unable to find device with bus ID %s", busid); | ||
| 91 | goto err_close_busid_dev; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* Check what kind of device it is. */ | ||
| 95 | bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass"); | ||
| 96 | if (!bDevClass) { | ||
| 97 | dbg("unable to get bDevClass device attribute"); | ||
| 98 | goto err_close_busid_dev; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (!strncmp(bDevClass, "09", strlen(bDevClass))) { | ||
| 102 | dbg("skip unbinding of hub"); | ||
| 103 | goto err_close_busid_dev; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* Get the device driver. */ | ||
| 107 | driver = udev_device_get_driver(dev); | ||
| 108 | if (!driver) { | ||
| 109 | /* No driver bound to this device. */ | ||
| 110 | goto out; | ||
| 111 | } | ||
| 112 | |||
| 113 | if (!strncmp(USBIP_HOST_DRV_NAME, driver, | ||
| 114 | strlen(USBIP_HOST_DRV_NAME))) { | ||
| 115 | /* Already bound to usbip-host. */ | ||
| 116 | status = UNBIND_ST_USBIP_HOST; | ||
| 117 | goto out; | ||
| 118 | } | ||
| 119 | |||
| 120 | /* Unbind device from driver. */ | ||
| 121 | snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", | ||
| 122 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, | ||
| 123 | SYSFS_DRIVERS_NAME, driver, attr_name); | ||
| 124 | |||
| 125 | rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); | ||
| 126 | if (rc < 0) { | ||
| 127 | err("error unbinding device %s from driver", busid); | ||
| 128 | goto err_close_busid_dev; | ||
| 129 | } | ||
| 130 | |||
| 131 | goto out; | ||
| 132 | |||
| 133 | err_close_busid_dev: | ||
| 134 | status = UNBIND_ST_FAILED; | ||
| 135 | out: | ||
| 136 | udev_device_unref(dev); | ||
| 137 | udev_unref(udev); | ||
| 138 | |||
| 139 | return status; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int bind_device(char *busid) | ||
| 143 | { | ||
| 144 | int rc; | ||
| 145 | struct udev *udev; | ||
| 146 | struct udev_device *dev; | ||
| 147 | |||
| 148 | /* Check whether the device with this bus ID exists. */ | ||
| 149 | udev = udev_new(); | ||
| 150 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); | ||
| 151 | if (!dev) { | ||
| 152 | err("device with the specified bus ID does not exist"); | ||
| 153 | return -1; | ||
| 154 | } | ||
| 155 | udev_unref(udev); | ||
| 156 | |||
| 157 | rc = unbind_other(busid); | ||
| 158 | if (rc == UNBIND_ST_FAILED) { | ||
| 159 | err("could not unbind driver from device on busid %s", busid); | ||
| 160 | return -1; | ||
| 161 | } else if (rc == UNBIND_ST_USBIP_HOST) { | ||
| 162 | err("device on busid %s is already bound to %s", busid, | ||
| 163 | USBIP_HOST_DRV_NAME); | ||
| 164 | return -1; | ||
| 165 | } | ||
| 166 | |||
| 167 | rc = modify_match_busid(busid, 1); | ||
| 168 | if (rc < 0) { | ||
| 169 | err("unable to bind device on %s", busid); | ||
| 170 | return -1; | ||
| 171 | } | ||
| 172 | |||
| 173 | rc = bind_usbip(busid); | ||
| 174 | if (rc < 0) { | ||
| 175 | err("could not bind device to %s", USBIP_HOST_DRV_NAME); | ||
| 176 | modify_match_busid(busid, 0); | ||
| 177 | return -1; | ||
| 178 | } | ||
| 179 | |||
| 180 | info("bind device on busid %s: complete", busid); | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | int usbip_bind(int argc, char *argv[]) | ||
| 186 | { | ||
| 187 | static const struct option opts[] = { | ||
| 188 | { "busid", required_argument, NULL, 'b' }, | ||
| 189 | { NULL, 0, NULL, 0 } | ||
| 190 | }; | ||
| 191 | |||
| 192 | int opt; | ||
| 193 | int ret = -1; | ||
| 194 | |||
| 195 | for (;;) { | ||
| 196 | opt = getopt_long(argc, argv, "b:", opts, NULL); | ||
| 197 | |||
| 198 | if (opt == -1) | ||
| 199 | break; | ||
| 200 | |||
| 201 | switch (opt) { | ||
| 202 | case 'b': | ||
| 203 | ret = bind_device(optarg); | ||
| 204 | goto out; | ||
| 205 | default: | ||
| 206 | goto err_out; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | err_out: | ||
| 211 | usbip_bind_usage(); | ||
| 212 | out: | ||
| 213 | return ret; | ||
| 214 | } | ||
diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c new file mode 100644 index 000000000000..05c6d15856eb --- /dev/null +++ b/tools/usb/usbip/src/usbip_detach.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <ctype.h> | ||
| 20 | #include <limits.h> | ||
| 21 | #include <stdint.h> | ||
| 22 | #include <stdio.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <string.h> | ||
| 25 | |||
| 26 | #include <getopt.h> | ||
| 27 | #include <unistd.h> | ||
| 28 | |||
| 29 | #include "vhci_driver.h" | ||
| 30 | #include "usbip_common.h" | ||
| 31 | #include "usbip_network.h" | ||
| 32 | #include "usbip.h" | ||
| 33 | |||
| 34 | static const char usbip_detach_usage_string[] = | ||
| 35 | "usbip detach <args>\n" | ||
| 36 | " -p, --port=<port> " USBIP_VHCI_DRV_NAME | ||
| 37 | " port the device is on\n"; | ||
| 38 | |||
| 39 | void usbip_detach_usage(void) | ||
| 40 | { | ||
| 41 | printf("usage: %s", usbip_detach_usage_string); | ||
| 42 | } | ||
| 43 | |||
| 44 | static int detach_port(char *port) | ||
| 45 | { | ||
| 46 | int ret; | ||
| 47 | uint8_t portnum; | ||
| 48 | char path[PATH_MAX+1]; | ||
| 49 | |||
| 50 | for (unsigned int i = 0; i < strlen(port); i++) | ||
| 51 | if (!isdigit(port[i])) { | ||
| 52 | err("invalid port %s", port); | ||
| 53 | return -1; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* check max port */ | ||
| 57 | |||
| 58 | portnum = atoi(port); | ||
| 59 | |||
| 60 | /* remove the port state file */ | ||
| 61 | |||
| 62 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); | ||
| 63 | |||
| 64 | remove(path); | ||
| 65 | rmdir(VHCI_STATE_PATH); | ||
| 66 | |||
| 67 | ret = usbip_vhci_driver_open(); | ||
| 68 | if (ret < 0) { | ||
| 69 | err("open vhci_driver"); | ||
| 70 | return -1; | ||
| 71 | } | ||
| 72 | |||
| 73 | ret = usbip_vhci_detach_device(portnum); | ||
| 74 | if (ret < 0) | ||
| 75 | return -1; | ||
| 76 | |||
| 77 | usbip_vhci_driver_close(); | ||
| 78 | |||
| 79 | return ret; | ||
| 80 | } | ||
| 81 | |||
| 82 | int usbip_detach(int argc, char *argv[]) | ||
| 83 | { | ||
| 84 | static const struct option opts[] = { | ||
| 85 | { "port", required_argument, NULL, 'p' }, | ||
| 86 | { NULL, 0, NULL, 0 } | ||
| 87 | }; | ||
| 88 | int opt; | ||
| 89 | int ret = -1; | ||
| 90 | |||
| 91 | for (;;) { | ||
| 92 | opt = getopt_long(argc, argv, "p:", opts, NULL); | ||
| 93 | |||
| 94 | if (opt == -1) | ||
| 95 | break; | ||
| 96 | |||
| 97 | switch (opt) { | ||
| 98 | case 'p': | ||
| 99 | ret = detach_port(optarg); | ||
| 100 | goto out; | ||
| 101 | default: | ||
| 102 | goto err_out; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | err_out: | ||
| 107 | usbip_detach_usage(); | ||
| 108 | out: | ||
| 109 | return ret; | ||
| 110 | } | ||
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c new file mode 100644 index 000000000000..d5ce34a410e7 --- /dev/null +++ b/tools/usb/usbip/src/usbip_list.c | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <sys/types.h> | ||
| 20 | #include <libudev.h> | ||
| 21 | |||
| 22 | #include <errno.h> | ||
| 23 | #include <stdbool.h> | ||
| 24 | #include <stdint.h> | ||
| 25 | #include <stdio.h> | ||
| 26 | #include <stdlib.h> | ||
| 27 | #include <string.h> | ||
| 28 | |||
| 29 | #include <getopt.h> | ||
| 30 | #include <netdb.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | |||
| 33 | #include "usbip_common.h" | ||
| 34 | #include "usbip_network.h" | ||
| 35 | #include "usbip.h" | ||
| 36 | |||
| 37 | static const char usbip_list_usage_string[] = | ||
| 38 | "usbip list [-p|--parsable] <args>\n" | ||
| 39 | " -p, --parsable Parsable list format\n" | ||
| 40 | " -r, --remote=<host> List the exportable USB devices on <host>\n" | ||
| 41 | " -l, --local List the local USB devices\n"; | ||
| 42 | |||
| 43 | void usbip_list_usage(void) | ||
| 44 | { | ||
| 45 | printf("usage: %s", usbip_list_usage_string); | ||
| 46 | } | ||
| 47 | |||
| 48 | static int get_exported_devices(char *host, int sockfd) | ||
| 49 | { | ||
| 50 | char product_name[100]; | ||
| 51 | char class_name[100]; | ||
| 52 | struct op_devlist_reply reply; | ||
| 53 | uint16_t code = OP_REP_DEVLIST; | ||
| 54 | struct usbip_usb_device udev; | ||
| 55 | struct usbip_usb_interface uintf; | ||
| 56 | unsigned int i; | ||
| 57 | int rc, j; | ||
| 58 | |||
| 59 | rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); | ||
| 60 | if (rc < 0) { | ||
| 61 | dbg("usbip_net_send_op_common failed"); | ||
| 62 | return -1; | ||
| 63 | } | ||
| 64 | |||
| 65 | rc = usbip_net_recv_op_common(sockfd, &code); | ||
| 66 | if (rc < 0) { | ||
| 67 | dbg("usbip_net_recv_op_common failed"); | ||
| 68 | return -1; | ||
| 69 | } | ||
| 70 | |||
| 71 | memset(&reply, 0, sizeof(reply)); | ||
| 72 | rc = usbip_net_recv(sockfd, &reply, sizeof(reply)); | ||
| 73 | if (rc < 0) { | ||
| 74 | dbg("usbip_net_recv_op_devlist failed"); | ||
| 75 | return -1; | ||
| 76 | } | ||
| 77 | PACK_OP_DEVLIST_REPLY(0, &reply); | ||
| 78 | dbg("exportable devices: %d\n", reply.ndev); | ||
| 79 | |||
| 80 | if (reply.ndev == 0) { | ||
| 81 | info("no exportable devices found on %s", host); | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | printf("Exportable USB devices\n"); | ||
| 86 | printf("======================\n"); | ||
| 87 | printf(" - %s\n", host); | ||
| 88 | |||
| 89 | for (i = 0; i < reply.ndev; i++) { | ||
| 90 | memset(&udev, 0, sizeof(udev)); | ||
| 91 | rc = usbip_net_recv(sockfd, &udev, sizeof(udev)); | ||
| 92 | if (rc < 0) { | ||
| 93 | dbg("usbip_net_recv failed: usbip_usb_device[%d]", i); | ||
| 94 | return -1; | ||
| 95 | } | ||
| 96 | usbip_net_pack_usb_device(0, &udev); | ||
| 97 | |||
| 98 | usbip_names_get_product(product_name, sizeof(product_name), | ||
| 99 | udev.idVendor, udev.idProduct); | ||
| 100 | usbip_names_get_class(class_name, sizeof(class_name), | ||
| 101 | udev.bDeviceClass, udev.bDeviceSubClass, | ||
| 102 | udev.bDeviceProtocol); | ||
| 103 | printf("%11s: %s\n", udev.busid, product_name); | ||
| 104 | printf("%11s: %s\n", "", udev.path); | ||
| 105 | printf("%11s: %s\n", "", class_name); | ||
| 106 | |||
| 107 | for (j = 0; j < udev.bNumInterfaces; j++) { | ||
| 108 | rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); | ||
| 109 | if (rc < 0) { | ||
| 110 | err("usbip_net_recv failed: usbip_usb_intf[%d]", | ||
| 111 | j); | ||
| 112 | |||
| 113 | return -1; | ||
| 114 | } | ||
| 115 | usbip_net_pack_usb_interface(0, &uintf); | ||
| 116 | |||
| 117 | usbip_names_get_class(class_name, sizeof(class_name), | ||
| 118 | uintf.bInterfaceClass, | ||
| 119 | uintf.bInterfaceSubClass, | ||
| 120 | uintf.bInterfaceProtocol); | ||
| 121 | printf("%11s: %2d - %s\n", "", j, class_name); | ||
| 122 | } | ||
| 123 | |||
| 124 | printf("\n"); | ||
| 125 | } | ||
| 126 | |||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int list_exported_devices(char *host) | ||
| 131 | { | ||
| 132 | int rc; | ||
| 133 | int sockfd; | ||
| 134 | |||
| 135 | sockfd = usbip_net_tcp_connect(host, usbip_port_string); | ||
| 136 | if (sockfd < 0) { | ||
| 137 | err("could not connect to %s:%s: %s", host, | ||
| 138 | usbip_port_string, gai_strerror(sockfd)); | ||
| 139 | return -1; | ||
| 140 | } | ||
| 141 | dbg("connected to %s:%s", host, usbip_port_string); | ||
| 142 | |||
| 143 | rc = get_exported_devices(host, sockfd); | ||
| 144 | if (rc < 0) { | ||
| 145 | err("failed to get device list from %s", host); | ||
| 146 | return -1; | ||
| 147 | } | ||
| 148 | |||
| 149 | close(sockfd); | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | static void print_device(const char *busid, const char *vendor, | ||
| 155 | const char *product, bool parsable) | ||
| 156 | { | ||
| 157 | if (parsable) | ||
| 158 | printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); | ||
| 159 | else | ||
| 160 | printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); | ||
| 161 | } | ||
| 162 | |||
| 163 | static void print_product_name(char *product_name, bool parsable) | ||
| 164 | { | ||
| 165 | if (!parsable) | ||
| 166 | printf(" %s\n", product_name); | ||
| 167 | } | ||
| 168 | |||
| 169 | static int list_devices(bool parsable) | ||
| 170 | { | ||
| 171 | struct udev *udev; | ||
| 172 | struct udev_enumerate *enumerate; | ||
| 173 | struct udev_list_entry *devices, *dev_list_entry; | ||
| 174 | struct udev_device *dev; | ||
| 175 | const char *path; | ||
| 176 | const char *idVendor; | ||
| 177 | const char *idProduct; | ||
| 178 | const char *bConfValue; | ||
| 179 | const char *bNumIntfs; | ||
| 180 | const char *busid; | ||
| 181 | char product_name[128]; | ||
| 182 | int ret = -1; | ||
| 183 | |||
| 184 | /* Create libudev context. */ | ||
| 185 | udev = udev_new(); | ||
| 186 | |||
| 187 | /* Create libudev device enumeration. */ | ||
| 188 | enumerate = udev_enumerate_new(udev); | ||
| 189 | |||
| 190 | /* Take only USB devices that are not hubs and do not have | ||
| 191 | * the bInterfaceNumber attribute, i.e. are not interfaces. | ||
| 192 | */ | ||
| 193 | udev_enumerate_add_match_subsystem(enumerate, "usb"); | ||
| 194 | udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09"); | ||
| 195 | udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL); | ||
| 196 | udev_enumerate_scan_devices(enumerate); | ||
| 197 | |||
| 198 | devices = udev_enumerate_get_list_entry(enumerate); | ||
| 199 | |||
| 200 | /* Show information about each device. */ | ||
| 201 | udev_list_entry_foreach(dev_list_entry, devices) { | ||
| 202 | path = udev_list_entry_get_name(dev_list_entry); | ||
| 203 | dev = udev_device_new_from_syspath(udev, path); | ||
| 204 | |||
| 205 | /* Get device information. */ | ||
| 206 | idVendor = udev_device_get_sysattr_value(dev, "idVendor"); | ||
| 207 | idProduct = udev_device_get_sysattr_value(dev, "idProduct"); | ||
| 208 | bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue"); | ||
| 209 | bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces"); | ||
| 210 | busid = udev_device_get_sysname(dev); | ||
| 211 | if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { | ||
| 212 | err("problem getting device attributes: %s", | ||
| 213 | strerror(errno)); | ||
| 214 | goto err_out; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* Get product name. */ | ||
| 218 | usbip_names_get_product(product_name, sizeof(product_name), | ||
| 219 | strtol(idVendor, NULL, 16), | ||
| 220 | strtol(idProduct, NULL, 16)); | ||
| 221 | |||
| 222 | /* Print information. */ | ||
| 223 | print_device(busid, idVendor, idProduct, parsable); | ||
| 224 | print_product_name(product_name, parsable); | ||
| 225 | |||
| 226 | printf("\n"); | ||
| 227 | |||
| 228 | udev_device_unref(dev); | ||
| 229 | } | ||
| 230 | |||
| 231 | ret = 0; | ||
| 232 | |||
| 233 | err_out: | ||
| 234 | udev_enumerate_unref(enumerate); | ||
| 235 | udev_unref(udev); | ||
| 236 | |||
| 237 | return ret; | ||
| 238 | } | ||
| 239 | |||
| 240 | int usbip_list(int argc, char *argv[]) | ||
| 241 | { | ||
| 242 | static const struct option opts[] = { | ||
| 243 | { "parsable", no_argument, NULL, 'p' }, | ||
| 244 | { "remote", required_argument, NULL, 'r' }, | ||
| 245 | { "local", no_argument, NULL, 'l' }, | ||
| 246 | { NULL, 0, NULL, 0 } | ||
| 247 | }; | ||
| 248 | |||
| 249 | bool parsable = false; | ||
| 250 | int opt; | ||
| 251 | int ret = -1; | ||
| 252 | |||
| 253 | if (usbip_names_init(USBIDS_FILE)) | ||
| 254 | err("failed to open %s", USBIDS_FILE); | ||
| 255 | |||
| 256 | for (;;) { | ||
| 257 | opt = getopt_long(argc, argv, "pr:l", opts, NULL); | ||
| 258 | |||
| 259 | if (opt == -1) | ||
| 260 | break; | ||
| 261 | |||
| 262 | switch (opt) { | ||
| 263 | case 'p': | ||
| 264 | parsable = true; | ||
| 265 | break; | ||
| 266 | case 'r': | ||
| 267 | ret = list_exported_devices(optarg); | ||
| 268 | goto out; | ||
| 269 | case 'l': | ||
| 270 | ret = list_devices(parsable); | ||
| 271 | goto out; | ||
| 272 | default: | ||
| 273 | goto err_out; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | err_out: | ||
| 278 | usbip_list_usage(); | ||
| 279 | out: | ||
| 280 | usbip_names_free(); | ||
| 281 | |||
| 282 | return ret; | ||
| 283 | } | ||
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c new file mode 100644 index 000000000000..b4c37e76a6e0 --- /dev/null +++ b/tools/usb/usbip/src/usbip_network.c | |||
| @@ -0,0 +1,303 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <sys/socket.h> | ||
| 20 | |||
| 21 | #include <string.h> | ||
| 22 | |||
| 23 | #include <arpa/inet.h> | ||
| 24 | #include <netdb.h> | ||
| 25 | #include <netinet/tcp.h> | ||
| 26 | #include <unistd.h> | ||
| 27 | |||
| 28 | #ifdef HAVE_LIBWRAP | ||
| 29 | #include <tcpd.h> | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #include "usbip_common.h" | ||
| 33 | #include "usbip_network.h" | ||
| 34 | |||
| 35 | int usbip_port = 3240; | ||
| 36 | char *usbip_port_string = "3240"; | ||
| 37 | |||
| 38 | void usbip_setup_port_number(char *arg) | ||
| 39 | { | ||
| 40 | dbg("parsing port arg '%s'", arg); | ||
| 41 | char *end; | ||
| 42 | unsigned long int port = strtoul(arg, &end, 10); | ||
| 43 | |||
| 44 | if (end == arg) { | ||
| 45 | err("port: could not parse '%s' as a decimal integer", arg); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | if (*end != '\0') { | ||
| 50 | err("port: garbage at end of '%s'", arg); | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | if (port > UINT16_MAX) { | ||
| 55 | err("port: %s too high (max=%d)", | ||
| 56 | arg, UINT16_MAX); | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | |||
| 60 | usbip_port = port; | ||
| 61 | usbip_port_string = arg; | ||
| 62 | info("using port %d (\"%s\")", usbip_port, usbip_port_string); | ||
| 63 | } | ||
| 64 | |||
| 65 | void usbip_net_pack_uint32_t(int pack, uint32_t *num) | ||
| 66 | { | ||
| 67 | uint32_t i; | ||
| 68 | |||
| 69 | if (pack) | ||
| 70 | i = htonl(*num); | ||
| 71 | else | ||
| 72 | i = ntohl(*num); | ||
| 73 | |||
| 74 | *num = i; | ||
| 75 | } | ||
| 76 | |||
| 77 | void usbip_net_pack_uint16_t(int pack, uint16_t *num) | ||
| 78 | { | ||
| 79 | uint16_t i; | ||
| 80 | |||
| 81 | if (pack) | ||
| 82 | i = htons(*num); | ||
| 83 | else | ||
| 84 | i = ntohs(*num); | ||
| 85 | |||
| 86 | *num = i; | ||
| 87 | } | ||
| 88 | |||
| 89 | void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) | ||
| 90 | { | ||
| 91 | usbip_net_pack_uint32_t(pack, &udev->busnum); | ||
| 92 | usbip_net_pack_uint32_t(pack, &udev->devnum); | ||
| 93 | usbip_net_pack_uint32_t(pack, &udev->speed); | ||
| 94 | |||
| 95 | usbip_net_pack_uint16_t(pack, &udev->idVendor); | ||
| 96 | usbip_net_pack_uint16_t(pack, &udev->idProduct); | ||
| 97 | usbip_net_pack_uint16_t(pack, &udev->bcdDevice); | ||
| 98 | } | ||
| 99 | |||
| 100 | void usbip_net_pack_usb_interface(int pack __attribute__((unused)), | ||
| 101 | struct usbip_usb_interface *udev | ||
| 102 | __attribute__((unused))) | ||
| 103 | { | ||
| 104 | /* uint8_t members need nothing */ | ||
| 105 | } | ||
| 106 | |||
| 107 | static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen, | ||
| 108 | int sending) | ||
| 109 | { | ||
| 110 | ssize_t nbytes; | ||
| 111 | ssize_t total = 0; | ||
| 112 | |||
| 113 | if (!bufflen) | ||
| 114 | return 0; | ||
| 115 | |||
| 116 | do { | ||
| 117 | if (sending) | ||
| 118 | nbytes = send(sockfd, buff, bufflen, 0); | ||
| 119 | else | ||
| 120 | nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL); | ||
| 121 | |||
| 122 | if (nbytes <= 0) | ||
| 123 | return -1; | ||
| 124 | |||
| 125 | buff = (void *)((intptr_t) buff + nbytes); | ||
| 126 | bufflen -= nbytes; | ||
| 127 | total += nbytes; | ||
| 128 | |||
| 129 | } while (bufflen > 0); | ||
| 130 | |||
| 131 | return total; | ||
| 132 | } | ||
| 133 | |||
| 134 | ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen) | ||
| 135 | { | ||
| 136 | return usbip_net_xmit(sockfd, buff, bufflen, 0); | ||
| 137 | } | ||
| 138 | |||
| 139 | ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) | ||
| 140 | { | ||
| 141 | return usbip_net_xmit(sockfd, buff, bufflen, 1); | ||
| 142 | } | ||
| 143 | |||
| 144 | int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) | ||
| 145 | { | ||
| 146 | struct op_common op_common; | ||
| 147 | int rc; | ||
| 148 | |||
| 149 | memset(&op_common, 0, sizeof(op_common)); | ||
| 150 | |||
| 151 | op_common.version = USBIP_VERSION; | ||
| 152 | op_common.code = code; | ||
| 153 | op_common.status = status; | ||
| 154 | |||
| 155 | PACK_OP_COMMON(1, &op_common); | ||
| 156 | |||
| 157 | rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); | ||
| 158 | if (rc < 0) { | ||
| 159 | dbg("usbip_net_send failed: %d", rc); | ||
| 160 | return -1; | ||
| 161 | } | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | int usbip_net_recv_op_common(int sockfd, uint16_t *code) | ||
| 167 | { | ||
| 168 | struct op_common op_common; | ||
| 169 | int rc; | ||
| 170 | |||
| 171 | memset(&op_common, 0, sizeof(op_common)); | ||
| 172 | |||
| 173 | rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common)); | ||
| 174 | if (rc < 0) { | ||
| 175 | dbg("usbip_net_recv failed: %d", rc); | ||
| 176 | goto err; | ||
| 177 | } | ||
| 178 | |||
| 179 | PACK_OP_COMMON(0, &op_common); | ||
| 180 | |||
| 181 | if (op_common.version != USBIP_VERSION) { | ||
| 182 | dbg("version mismatch: %d %d", op_common.version, | ||
| 183 | USBIP_VERSION); | ||
| 184 | goto err; | ||
| 185 | } | ||
| 186 | |||
| 187 | switch (*code) { | ||
| 188 | case OP_UNSPEC: | ||
| 189 | break; | ||
| 190 | default: | ||
| 191 | if (op_common.code != *code) { | ||
| 192 | dbg("unexpected pdu %#0x for %#0x", op_common.code, | ||
| 193 | *code); | ||
| 194 | goto err; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | if (op_common.status != ST_OK) { | ||
| 199 | dbg("request failed at peer: %d", op_common.status); | ||
| 200 | goto err; | ||
| 201 | } | ||
| 202 | |||
| 203 | *code = op_common.code; | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | err: | ||
| 207 | return -1; | ||
| 208 | } | ||
| 209 | |||
| 210 | int usbip_net_set_reuseaddr(int sockfd) | ||
| 211 | { | ||
| 212 | const int val = 1; | ||
| 213 | int ret; | ||
| 214 | |||
| 215 | ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); | ||
| 216 | if (ret < 0) | ||
| 217 | dbg("setsockopt: SO_REUSEADDR"); | ||
| 218 | |||
| 219 | return ret; | ||
| 220 | } | ||
| 221 | |||
| 222 | int usbip_net_set_nodelay(int sockfd) | ||
| 223 | { | ||
| 224 | const int val = 1; | ||
| 225 | int ret; | ||
| 226 | |||
| 227 | ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); | ||
| 228 | if (ret < 0) | ||
| 229 | dbg("setsockopt: TCP_NODELAY"); | ||
| 230 | |||
| 231 | return ret; | ||
| 232 | } | ||
| 233 | |||
| 234 | int usbip_net_set_keepalive(int sockfd) | ||
| 235 | { | ||
| 236 | const int val = 1; | ||
| 237 | int ret; | ||
| 238 | |||
| 239 | ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); | ||
| 240 | if (ret < 0) | ||
| 241 | dbg("setsockopt: SO_KEEPALIVE"); | ||
| 242 | |||
| 243 | return ret; | ||
| 244 | } | ||
| 245 | |||
| 246 | int usbip_net_set_v6only(int sockfd) | ||
| 247 | { | ||
| 248 | const int val = 1; | ||
| 249 | int ret; | ||
| 250 | |||
| 251 | ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); | ||
| 252 | if (ret < 0) | ||
| 253 | dbg("setsockopt: IPV6_V6ONLY"); | ||
| 254 | |||
| 255 | return ret; | ||
| 256 | } | ||
| 257 | |||
| 258 | /* | ||
| 259 | * IPv6 Ready | ||
| 260 | */ | ||
| 261 | int usbip_net_tcp_connect(char *hostname, char *service) | ||
| 262 | { | ||
| 263 | struct addrinfo hints, *res, *rp; | ||
| 264 | int sockfd; | ||
| 265 | int ret; | ||
| 266 | |||
| 267 | memset(&hints, 0, sizeof(hints)); | ||
| 268 | hints.ai_family = AF_UNSPEC; | ||
| 269 | hints.ai_socktype = SOCK_STREAM; | ||
| 270 | |||
| 271 | /* get all possible addresses */ | ||
| 272 | ret = getaddrinfo(hostname, service, &hints, &res); | ||
| 273 | if (ret < 0) { | ||
| 274 | dbg("getaddrinfo: %s service %s: %s", hostname, service, | ||
| 275 | gai_strerror(ret)); | ||
| 276 | return ret; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* try the addresses */ | ||
| 280 | for (rp = res; rp; rp = rp->ai_next) { | ||
| 281 | sockfd = socket(rp->ai_family, rp->ai_socktype, | ||
| 282 | rp->ai_protocol); | ||
| 283 | if (sockfd < 0) | ||
| 284 | continue; | ||
| 285 | |||
| 286 | /* should set TCP_NODELAY for usbip */ | ||
| 287 | usbip_net_set_nodelay(sockfd); | ||
| 288 | /* TODO: write code for heartbeat */ | ||
| 289 | usbip_net_set_keepalive(sockfd); | ||
| 290 | |||
| 291 | if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) | ||
| 292 | break; | ||
| 293 | |||
| 294 | close(sockfd); | ||
| 295 | } | ||
| 296 | |||
| 297 | freeaddrinfo(res); | ||
| 298 | |||
| 299 | if (!rp) | ||
| 300 | return EAI_SYSTEM; | ||
| 301 | |||
| 302 | return sockfd; | ||
| 303 | } | ||
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h new file mode 100644 index 000000000000..c1e875cf1078 --- /dev/null +++ b/tools/usb/usbip/src/usbip_network.h | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef __USBIP_NETWORK_H | ||
| 6 | #define __USBIP_NETWORK_H | ||
| 7 | |||
| 8 | #ifdef HAVE_CONFIG_H | ||
| 9 | #include "../config.h" | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #include <sys/types.h> | ||
| 13 | |||
| 14 | #include <stdint.h> | ||
| 15 | |||
| 16 | extern int usbip_port; | ||
| 17 | extern char *usbip_port_string; | ||
| 18 | void usbip_setup_port_number(char *arg); | ||
| 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 | usbip_net_pack_uint16_t(pack, &(op_common)->version);\ | ||
| 38 | usbip_net_pack_uint16_t(pack, &(op_common)->code);\ | ||
| 39 | usbip_net_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 | struct op_devinfo_request { | ||
| 55 | char busid[SYSFS_BUS_ID_SIZE]; | ||
| 56 | } __attribute__((packed)); | ||
| 57 | |||
| 58 | struct op_devinfo_reply { | ||
| 59 | struct usbip_usb_device udev; | ||
| 60 | struct usbip_usb_interface uinf[]; | ||
| 61 | } __attribute__((packed)); | ||
| 62 | |||
| 63 | /* ---------------------------------------------------------------------- */ | ||
| 64 | /* Import a remote USB device. */ | ||
| 65 | #define OP_IMPORT 0x03 | ||
| 66 | #define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT) | ||
| 67 | #define OP_REP_IMPORT (OP_REPLY | OP_IMPORT) | ||
| 68 | |||
| 69 | struct op_import_request { | ||
| 70 | char busid[SYSFS_BUS_ID_SIZE]; | ||
| 71 | } __attribute__((packed)); | ||
| 72 | |||
| 73 | struct op_import_reply { | ||
| 74 | struct usbip_usb_device udev; | ||
| 75 | // struct usbip_usb_interface uinf[]; | ||
| 76 | } __attribute__((packed)); | ||
| 77 | |||
| 78 | #define PACK_OP_IMPORT_REQUEST(pack, request) do {\ | ||
| 79 | } while (0) | ||
| 80 | |||
| 81 | #define PACK_OP_IMPORT_REPLY(pack, reply) do {\ | ||
| 82 | usbip_net_pack_usb_device(pack, &(reply)->udev);\ | ||
| 83 | } while (0) | ||
| 84 | |||
| 85 | /* ---------------------------------------------------------------------- */ | ||
| 86 | /* Export a USB device to a remote host. */ | ||
| 87 | #define OP_EXPORT 0x06 | ||
| 88 | #define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT) | ||
| 89 | #define OP_REP_EXPORT (OP_REPLY | OP_EXPORT) | ||
| 90 | |||
| 91 | struct op_export_request { | ||
| 92 | struct usbip_usb_device udev; | ||
| 93 | } __attribute__((packed)); | ||
| 94 | |||
| 95 | struct op_export_reply { | ||
| 96 | int returncode; | ||
| 97 | } __attribute__((packed)); | ||
| 98 | |||
| 99 | |||
| 100 | #define PACK_OP_EXPORT_REQUEST(pack, request) do {\ | ||
| 101 | usbip_net_pack_usb_device(pack, &(request)->udev);\ | ||
| 102 | } while (0) | ||
| 103 | |||
| 104 | #define PACK_OP_EXPORT_REPLY(pack, reply) do {\ | ||
| 105 | } while (0) | ||
| 106 | |||
| 107 | /* ---------------------------------------------------------------------- */ | ||
| 108 | /* un-Export a USB device from a remote host. */ | ||
| 109 | #define OP_UNEXPORT 0x07 | ||
| 110 | #define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT) | ||
| 111 | #define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT) | ||
| 112 | |||
| 113 | struct op_unexport_request { | ||
| 114 | struct usbip_usb_device udev; | ||
| 115 | } __attribute__((packed)); | ||
| 116 | |||
| 117 | struct op_unexport_reply { | ||
| 118 | int returncode; | ||
| 119 | } __attribute__((packed)); | ||
| 120 | |||
| 121 | #define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\ | ||
| 122 | usbip_net_pack_usb_device(pack, &(request)->udev);\ | ||
| 123 | } while (0) | ||
| 124 | |||
| 125 | #define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\ | ||
| 126 | } while (0) | ||
| 127 | |||
| 128 | /* ---------------------------------------------------------------------- */ | ||
| 129 | /* Negotiate IPSec encryption key. (still not used) */ | ||
| 130 | #define OP_CRYPKEY 0x04 | ||
| 131 | #define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY) | ||
| 132 | #define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY) | ||
| 133 | |||
| 134 | struct op_crypkey_request { | ||
| 135 | /* 128bit key */ | ||
| 136 | uint32_t key[4]; | ||
| 137 | } __attribute__((packed)); | ||
| 138 | |||
| 139 | struct op_crypkey_reply { | ||
| 140 | uint32_t __reserved; | ||
| 141 | } __attribute__((packed)); | ||
| 142 | |||
| 143 | |||
| 144 | /* ---------------------------------------------------------------------- */ | ||
| 145 | /* Retrieve the list of exported USB devices. */ | ||
| 146 | #define OP_DEVLIST 0x05 | ||
| 147 | #define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST) | ||
| 148 | #define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST) | ||
| 149 | |||
| 150 | struct op_devlist_request { | ||
| 151 | } __attribute__((packed)); | ||
| 152 | |||
| 153 | struct op_devlist_reply { | ||
| 154 | uint32_t ndev; | ||
| 155 | /* followed by reply_extra[] */ | ||
| 156 | } __attribute__((packed)); | ||
| 157 | |||
| 158 | struct op_devlist_reply_extra { | ||
| 159 | struct usbip_usb_device udev; | ||
| 160 | struct usbip_usb_interface uinf[]; | ||
| 161 | } __attribute__((packed)); | ||
| 162 | |||
| 163 | #define PACK_OP_DEVLIST_REQUEST(pack, request) do {\ | ||
| 164 | } while (0) | ||
| 165 | |||
| 166 | #define PACK_OP_DEVLIST_REPLY(pack, reply) do {\ | ||
| 167 | usbip_net_pack_uint32_t(pack, &(reply)->ndev);\ | ||
| 168 | } while (0) | ||
| 169 | |||
| 170 | void usbip_net_pack_uint32_t(int pack, uint32_t *num); | ||
| 171 | void usbip_net_pack_uint16_t(int pack, uint16_t *num); | ||
| 172 | void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev); | ||
| 173 | void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf); | ||
| 174 | |||
| 175 | ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen); | ||
| 176 | ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen); | ||
| 177 | int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status); | ||
| 178 | int usbip_net_recv_op_common(int sockfd, uint16_t *code); | ||
| 179 | int usbip_net_set_reuseaddr(int sockfd); | ||
| 180 | int usbip_net_set_nodelay(int sockfd); | ||
| 181 | int usbip_net_set_keepalive(int sockfd); | ||
| 182 | int usbip_net_set_v6only(int sockfd); | ||
| 183 | int usbip_net_tcp_connect(char *hostname, char *port); | ||
| 184 | |||
| 185 | #endif /* __USBIP_NETWORK_H */ | ||
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c new file mode 100644 index 000000000000..a2e884fd9226 --- /dev/null +++ b/tools/usb/usbip/src/usbip_port.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include "vhci_driver.h" | ||
| 17 | #include "usbip_common.h" | ||
| 18 | |||
| 19 | static int list_imported_devices(void) | ||
| 20 | { | ||
| 21 | int i; | ||
| 22 | struct usbip_imported_device *idev; | ||
| 23 | int ret; | ||
| 24 | |||
| 25 | ret = usbip_vhci_driver_open(); | ||
| 26 | if (ret < 0) { | ||
| 27 | err("open vhci_driver"); | ||
| 28 | return -1; | ||
| 29 | } | ||
| 30 | |||
| 31 | printf("Imported USB devices\n"); | ||
| 32 | printf("====================\n"); | ||
| 33 | |||
| 34 | for (i = 0; i < vhci_driver->nports; i++) { | ||
| 35 | idev = &vhci_driver->idev[i]; | ||
| 36 | |||
| 37 | if (usbip_vhci_imported_device_dump(idev) < 0) | ||
| 38 | ret = -1; | ||
| 39 | } | ||
| 40 | |||
| 41 | usbip_vhci_driver_close(); | ||
| 42 | |||
| 43 | return ret; | ||
| 44 | |||
| 45 | } | ||
| 46 | |||
| 47 | int usbip_port_show(__attribute__((unused)) int argc, | ||
| 48 | __attribute__((unused)) char *argv[]) | ||
| 49 | { | ||
| 50 | int ret; | ||
| 51 | |||
| 52 | ret = list_imported_devices(); | ||
| 53 | if (ret < 0) | ||
| 54 | err("list imported devices"); | ||
| 55 | |||
| 56 | return ret; | ||
| 57 | } | ||
diff --git a/tools/usb/usbip/src/usbip_unbind.c b/tools/usb/usbip/src/usbip_unbind.c new file mode 100644 index 000000000000..a4a496c9cbaf --- /dev/null +++ b/tools/usb/usbip/src/usbip_unbind.c | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <libudev.h> | ||
| 20 | |||
| 21 | #include <errno.h> | ||
| 22 | #include <stdio.h> | ||
| 23 | #include <string.h> | ||
| 24 | |||
| 25 | #include <getopt.h> | ||
| 26 | |||
| 27 | #include "usbip_common.h" | ||
| 28 | #include "utils.h" | ||
| 29 | #include "usbip.h" | ||
| 30 | #include "sysfs_utils.h" | ||
| 31 | |||
| 32 | static const char usbip_unbind_usage_string[] = | ||
| 33 | "usbip unbind <args>\n" | ||
| 34 | " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from " | ||
| 35 | "device on <busid>\n"; | ||
| 36 | |||
| 37 | void usbip_unbind_usage(void) | ||
| 38 | { | ||
| 39 | printf("usage: %s", usbip_unbind_usage_string); | ||
| 40 | } | ||
| 41 | |||
| 42 | static int unbind_device(char *busid) | ||
| 43 | { | ||
| 44 | char bus_type[] = "usb"; | ||
| 45 | int rc, ret = -1; | ||
| 46 | |||
| 47 | char unbind_attr_name[] = "unbind"; | ||
| 48 | char unbind_attr_path[SYSFS_PATH_MAX]; | ||
| 49 | char rebind_attr_name[] = "rebind"; | ||
| 50 | char rebind_attr_path[SYSFS_PATH_MAX]; | ||
| 51 | |||
| 52 | struct udev *udev; | ||
| 53 | struct udev_device *dev; | ||
| 54 | const char *driver; | ||
| 55 | |||
| 56 | /* Create libudev context. */ | ||
| 57 | udev = udev_new(); | ||
| 58 | |||
| 59 | /* Check whether the device with this bus ID exists. */ | ||
| 60 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); | ||
| 61 | if (!dev) { | ||
| 62 | err("device with the specified bus ID does not exist"); | ||
| 63 | goto err_close_udev; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* Check whether the device is using usbip-host driver. */ | ||
| 67 | driver = udev_device_get_driver(dev); | ||
| 68 | if (!driver || strcmp(driver, "usbip-host")) { | ||
| 69 | err("device is not bound to usbip-host driver"); | ||
| 70 | goto err_close_udev; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* Unbind device from driver. */ | ||
| 74 | snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", | ||
| 75 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, | ||
| 76 | USBIP_HOST_DRV_NAME, unbind_attr_name); | ||
| 77 | |||
| 78 | rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); | ||
| 79 | if (rc < 0) { | ||
| 80 | err("error unbinding device %s from driver", busid); | ||
| 81 | goto err_close_udev; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* Notify driver of unbind. */ | ||
| 85 | rc = modify_match_busid(busid, 0); | ||
| 86 | if (rc < 0) { | ||
| 87 | err("unable to unbind device on %s", busid); | ||
| 88 | goto err_close_udev; | ||
| 89 | } | ||
| 90 | |||
| 91 | /* Trigger new probing. */ | ||
| 92 | snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", | ||
| 93 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, | ||
| 94 | USBIP_HOST_DRV_NAME, rebind_attr_name); | ||
| 95 | |||
| 96 | rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid)); | ||
| 97 | if (rc < 0) { | ||
| 98 | err("error rebinding"); | ||
| 99 | goto err_close_udev; | ||
| 100 | } | ||
| 101 | |||
| 102 | ret = 0; | ||
| 103 | info("unbind device on busid %s: complete", busid); | ||
| 104 | |||
| 105 | err_close_udev: | ||
| 106 | udev_device_unref(dev); | ||
| 107 | udev_unref(udev); | ||
| 108 | |||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | int usbip_unbind(int argc, char *argv[]) | ||
| 113 | { | ||
| 114 | static const struct option opts[] = { | ||
| 115 | { "busid", required_argument, NULL, 'b' }, | ||
| 116 | { NULL, 0, NULL, 0 } | ||
| 117 | }; | ||
| 118 | |||
| 119 | int opt; | ||
| 120 | int ret = -1; | ||
| 121 | |||
| 122 | for (;;) { | ||
| 123 | opt = getopt_long(argc, argv, "b:", opts, NULL); | ||
| 124 | |||
| 125 | if (opt == -1) | ||
| 126 | break; | ||
| 127 | |||
| 128 | switch (opt) { | ||
| 129 | case 'b': | ||
| 130 | ret = unbind_device(optarg); | ||
| 131 | goto out; | ||
| 132 | default: | ||
| 133 | goto err_out; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | err_out: | ||
| 138 | usbip_unbind_usage(); | ||
| 139 | out: | ||
| 140 | return ret; | ||
| 141 | } | ||
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c new file mode 100644 index 000000000000..2f87f2d348ba --- /dev/null +++ b/tools/usb/usbip/src/usbipd.c | |||
| @@ -0,0 +1,679 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifdef HAVE_CONFIG_H | ||
| 20 | #include "../config.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #define _GNU_SOURCE | ||
| 24 | #include <errno.h> | ||
| 25 | #include <unistd.h> | ||
| 26 | #include <netdb.h> | ||
| 27 | #include <string.h> | ||
| 28 | #include <stdlib.h> | ||
| 29 | #include <sys/types.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | #include <arpa/inet.h> | ||
| 32 | #include <sys/socket.h> | ||
| 33 | #include <netinet/in.h> | ||
| 34 | |||
| 35 | #ifdef HAVE_LIBWRAP | ||
| 36 | #include <tcpd.h> | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #include <getopt.h> | ||
| 40 | #include <signal.h> | ||
| 41 | #include <poll.h> | ||
| 42 | |||
| 43 | #include "usbip_host_driver.h" | ||
| 44 | #include "usbip_common.h" | ||
| 45 | #include "usbip_network.h" | ||
| 46 | #include "list.h" | ||
| 47 | |||
| 48 | #undef PROGNAME | ||
| 49 | #define PROGNAME "usbipd" | ||
| 50 | #define MAXSOCKFD 20 | ||
| 51 | |||
| 52 | #define MAIN_LOOP_TIMEOUT 10 | ||
| 53 | |||
| 54 | #define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid" | ||
| 55 | |||
| 56 | static const char usbip_version_string[] = PACKAGE_STRING; | ||
| 57 | |||
| 58 | static const char usbipd_help_string[] = | ||
| 59 | "usage: usbipd [options]\n" | ||
| 60 | "\n" | ||
| 61 | " -4, --ipv4\n" | ||
| 62 | " Bind to IPv4. Default is both.\n" | ||
| 63 | "\n" | ||
| 64 | " -6, --ipv6\n" | ||
| 65 | " Bind to IPv6. Default is both.\n" | ||
| 66 | "\n" | ||
| 67 | " -D, --daemon\n" | ||
| 68 | " Run as a daemon process.\n" | ||
| 69 | "\n" | ||
| 70 | " -d, --debug\n" | ||
| 71 | " Print debugging information.\n" | ||
| 72 | "\n" | ||
| 73 | " -PFILE, --pid FILE\n" | ||
| 74 | " Write process id to FILE.\n" | ||
| 75 | " If no FILE specified, use " DEFAULT_PID_FILE "\n" | ||
| 76 | "\n" | ||
| 77 | " -tPORT, --tcp-port PORT\n" | ||
| 78 | " Listen on TCP/IP port PORT.\n" | ||
| 79 | "\n" | ||
| 80 | " -h, --help\n" | ||
| 81 | " Print this help.\n" | ||
| 82 | "\n" | ||
| 83 | " -v, --version\n" | ||
| 84 | " Show version.\n"; | ||
| 85 | |||
| 86 | static void usbipd_help(void) | ||
| 87 | { | ||
| 88 | printf("%s\n", usbipd_help_string); | ||
| 89 | } | ||
| 90 | |||
| 91 | static int recv_request_import(int sockfd) | ||
| 92 | { | ||
| 93 | struct op_import_request req; | ||
| 94 | struct op_common reply; | ||
| 95 | struct usbip_exported_device *edev; | ||
| 96 | struct usbip_usb_device pdu_udev; | ||
| 97 | struct list_head *i; | ||
| 98 | int found = 0; | ||
| 99 | int error = 0; | ||
| 100 | int rc; | ||
| 101 | |||
| 102 | memset(&req, 0, sizeof(req)); | ||
| 103 | memset(&reply, 0, sizeof(reply)); | ||
| 104 | |||
| 105 | rc = usbip_net_recv(sockfd, &req, sizeof(req)); | ||
| 106 | if (rc < 0) { | ||
| 107 | dbg("usbip_net_recv failed: import request"); | ||
| 108 | return -1; | ||
| 109 | } | ||
| 110 | PACK_OP_IMPORT_REQUEST(0, &req); | ||
| 111 | |||
| 112 | list_for_each(i, &host_driver->edev_list) { | ||
| 113 | edev = list_entry(i, struct usbip_exported_device, node); | ||
| 114 | if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { | ||
| 115 | info("found requested device: %s", req.busid); | ||
| 116 | found = 1; | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | if (found) { | ||
| 122 | /* should set TCP_NODELAY for usbip */ | ||
| 123 | usbip_net_set_nodelay(sockfd); | ||
| 124 | |||
| 125 | /* export device needs a TCP/IP socket descriptor */ | ||
| 126 | rc = usbip_host_export_device(edev, sockfd); | ||
| 127 | if (rc < 0) | ||
| 128 | error = 1; | ||
| 129 | } else { | ||
| 130 | info("requested device not found: %s", req.busid); | ||
| 131 | error = 1; | ||
| 132 | } | ||
| 133 | |||
| 134 | rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, | ||
| 135 | (!error ? ST_OK : ST_NA)); | ||
| 136 | if (rc < 0) { | ||
| 137 | dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT); | ||
| 138 | return -1; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (error) { | ||
| 142 | dbg("import request busid %s: failed", req.busid); | ||
| 143 | return -1; | ||
| 144 | } | ||
| 145 | |||
| 146 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); | ||
| 147 | usbip_net_pack_usb_device(1, &pdu_udev); | ||
| 148 | |||
| 149 | rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev)); | ||
| 150 | if (rc < 0) { | ||
| 151 | dbg("usbip_net_send failed: devinfo"); | ||
| 152 | return -1; | ||
| 153 | } | ||
| 154 | |||
| 155 | dbg("import request busid %s: complete", req.busid); | ||
| 156 | |||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int send_reply_devlist(int connfd) | ||
| 161 | { | ||
| 162 | struct usbip_exported_device *edev; | ||
| 163 | struct usbip_usb_device pdu_udev; | ||
| 164 | struct usbip_usb_interface pdu_uinf; | ||
| 165 | struct op_devlist_reply reply; | ||
| 166 | struct list_head *j; | ||
| 167 | int rc, i; | ||
| 168 | |||
| 169 | reply.ndev = 0; | ||
| 170 | /* number of exported devices */ | ||
| 171 | list_for_each(j, &host_driver->edev_list) { | ||
| 172 | reply.ndev += 1; | ||
| 173 | } | ||
| 174 | info("exportable devices: %d", reply.ndev); | ||
| 175 | |||
| 176 | rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK); | ||
| 177 | if (rc < 0) { | ||
| 178 | dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST); | ||
| 179 | return -1; | ||
| 180 | } | ||
| 181 | PACK_OP_DEVLIST_REPLY(1, &reply); | ||
| 182 | |||
| 183 | rc = usbip_net_send(connfd, &reply, sizeof(reply)); | ||
| 184 | if (rc < 0) { | ||
| 185 | dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST); | ||
| 186 | return -1; | ||
| 187 | } | ||
| 188 | |||
| 189 | list_for_each(j, &host_driver->edev_list) { | ||
| 190 | edev = list_entry(j, struct usbip_exported_device, node); | ||
| 191 | dump_usb_device(&edev->udev); | ||
| 192 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); | ||
| 193 | usbip_net_pack_usb_device(1, &pdu_udev); | ||
| 194 | |||
| 195 | rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev)); | ||
| 196 | if (rc < 0) { | ||
| 197 | dbg("usbip_net_send failed: pdu_udev"); | ||
| 198 | return -1; | ||
| 199 | } | ||
| 200 | |||
| 201 | for (i = 0; i < edev->udev.bNumInterfaces; i++) { | ||
| 202 | dump_usb_interface(&edev->uinf[i]); | ||
| 203 | memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf)); | ||
| 204 | usbip_net_pack_usb_interface(1, &pdu_uinf); | ||
| 205 | |||
| 206 | rc = usbip_net_send(connfd, &pdu_uinf, | ||
| 207 | sizeof(pdu_uinf)); | ||
| 208 | if (rc < 0) { | ||
| 209 | err("usbip_net_send failed: pdu_uinf"); | ||
| 210 | return -1; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int recv_request_devlist(int connfd) | ||
| 219 | { | ||
| 220 | struct op_devlist_request req; | ||
| 221 | int rc; | ||
| 222 | |||
| 223 | memset(&req, 0, sizeof(req)); | ||
| 224 | |||
| 225 | rc = usbip_net_recv(connfd, &req, sizeof(req)); | ||
| 226 | if (rc < 0) { | ||
| 227 | dbg("usbip_net_recv failed: devlist request"); | ||
| 228 | return -1; | ||
| 229 | } | ||
| 230 | |||
| 231 | rc = send_reply_devlist(connfd); | ||
| 232 | if (rc < 0) { | ||
| 233 | dbg("send_reply_devlist failed"); | ||
| 234 | return -1; | ||
| 235 | } | ||
| 236 | |||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | static int recv_pdu(int connfd) | ||
| 241 | { | ||
| 242 | uint16_t code = OP_UNSPEC; | ||
| 243 | int ret; | ||
| 244 | |||
| 245 | ret = usbip_net_recv_op_common(connfd, &code); | ||
| 246 | if (ret < 0) { | ||
| 247 | dbg("could not receive opcode: %#0x", code); | ||
| 248 | return -1; | ||
| 249 | } | ||
| 250 | |||
| 251 | ret = usbip_host_refresh_device_list(); | ||
| 252 | if (ret < 0) { | ||
| 253 | dbg("could not refresh device list: %d", ret); | ||
| 254 | return -1; | ||
| 255 | } | ||
| 256 | |||
| 257 | info("received request: %#0x(%d)", code, connfd); | ||
| 258 | switch (code) { | ||
| 259 | case OP_REQ_DEVLIST: | ||
| 260 | ret = recv_request_devlist(connfd); | ||
| 261 | break; | ||
| 262 | case OP_REQ_IMPORT: | ||
| 263 | ret = recv_request_import(connfd); | ||
| 264 | break; | ||
| 265 | case OP_REQ_DEVINFO: | ||
| 266 | case OP_REQ_CRYPKEY: | ||
| 267 | default: | ||
| 268 | err("received an unknown opcode: %#0x", code); | ||
| 269 | ret = -1; | ||
| 270 | } | ||
| 271 | |||
| 272 | if (ret == 0) | ||
| 273 | info("request %#0x(%d): complete", code, connfd); | ||
| 274 | else | ||
| 275 | info("request %#0x(%d): failed", code, connfd); | ||
| 276 | |||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | #ifdef HAVE_LIBWRAP | ||
| 281 | static int tcpd_auth(int connfd) | ||
| 282 | { | ||
| 283 | struct request_info request; | ||
| 284 | int rc; | ||
| 285 | |||
| 286 | request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0); | ||
| 287 | fromhost(&request); | ||
| 288 | rc = hosts_access(&request); | ||
| 289 | if (rc == 0) | ||
| 290 | return -1; | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | #endif | ||
| 295 | |||
| 296 | static int do_accept(int listenfd) | ||
| 297 | { | ||
| 298 | int connfd; | ||
| 299 | struct sockaddr_storage ss; | ||
| 300 | socklen_t len = sizeof(ss); | ||
| 301 | char host[NI_MAXHOST], port[NI_MAXSERV]; | ||
| 302 | int rc; | ||
| 303 | |||
| 304 | memset(&ss, 0, sizeof(ss)); | ||
| 305 | |||
| 306 | connfd = accept(listenfd, (struct sockaddr *)&ss, &len); | ||
| 307 | if (connfd < 0) { | ||
| 308 | err("failed to accept connection"); | ||
| 309 | return -1; | ||
| 310 | } | ||
| 311 | |||
| 312 | rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host), | ||
| 313 | port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); | ||
| 314 | if (rc) | ||
| 315 | err("getnameinfo: %s", gai_strerror(rc)); | ||
| 316 | |||
| 317 | #ifdef HAVE_LIBWRAP | ||
| 318 | rc = tcpd_auth(connfd); | ||
| 319 | if (rc < 0) { | ||
| 320 | info("denied access from %s", host); | ||
| 321 | close(connfd); | ||
| 322 | return -1; | ||
| 323 | } | ||
| 324 | #endif | ||
| 325 | info("connection from %s:%s", host, port); | ||
| 326 | |||
| 327 | return connfd; | ||
| 328 | } | ||
| 329 | |||
| 330 | int process_request(int listenfd) | ||
| 331 | { | ||
| 332 | pid_t childpid; | ||
| 333 | int connfd; | ||
| 334 | |||
| 335 | connfd = do_accept(listenfd); | ||
| 336 | if (connfd < 0) | ||
| 337 | return -1; | ||
| 338 | childpid = fork(); | ||
| 339 | if (childpid == 0) { | ||
| 340 | close(listenfd); | ||
| 341 | recv_pdu(connfd); | ||
| 342 | exit(0); | ||
| 343 | } | ||
| 344 | close(connfd); | ||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | |||
| 348 | static void addrinfo_to_text(struct addrinfo *ai, char buf[], | ||
| 349 | const size_t buf_size) | ||
| 350 | { | ||
| 351 | char hbuf[NI_MAXHOST]; | ||
| 352 | char sbuf[NI_MAXSERV]; | ||
| 353 | int rc; | ||
| 354 | |||
| 355 | buf[0] = '\0'; | ||
| 356 | |||
| 357 | rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), | ||
| 358 | sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); | ||
| 359 | if (rc) | ||
| 360 | err("getnameinfo: %s", gai_strerror(rc)); | ||
| 361 | |||
| 362 | snprintf(buf, buf_size, "%s:%s", hbuf, sbuf); | ||
| 363 | } | ||
| 364 | |||
| 365 | static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], | ||
| 366 | int maxsockfd) | ||
| 367 | { | ||
| 368 | struct addrinfo *ai; | ||
| 369 | int ret, nsockfd = 0; | ||
| 370 | const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2; | ||
| 371 | char ai_buf[ai_buf_size]; | ||
| 372 | |||
| 373 | for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) { | ||
| 374 | int sock; | ||
| 375 | |||
| 376 | addrinfo_to_text(ai, ai_buf, ai_buf_size); | ||
| 377 | dbg("opening %s", ai_buf); | ||
| 378 | sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | ||
| 379 | if (sock < 0) { | ||
| 380 | err("socket: %s: %d (%s)", | ||
| 381 | ai_buf, errno, strerror(errno)); | ||
| 382 | continue; | ||
| 383 | } | ||
| 384 | |||
| 385 | usbip_net_set_reuseaddr(sock); | ||
| 386 | usbip_net_set_nodelay(sock); | ||
| 387 | /* We use seperate sockets for IPv4 and IPv6 | ||
| 388 | * (see do_standalone_mode()) */ | ||
| 389 | usbip_net_set_v6only(sock); | ||
| 390 | |||
| 391 | if (sock >= FD_SETSIZE) { | ||
| 392 | err("FD_SETSIZE: %s: sock=%d, max=%d", | ||
| 393 | ai_buf, sock, FD_SETSIZE); | ||
| 394 | close(sock); | ||
| 395 | continue; | ||
| 396 | } | ||
| 397 | |||
| 398 | ret = bind(sock, ai->ai_addr, ai->ai_addrlen); | ||
| 399 | if (ret < 0) { | ||
| 400 | err("bind: %s: %d (%s)", | ||
| 401 | ai_buf, errno, strerror(errno)); | ||
| 402 | close(sock); | ||
| 403 | continue; | ||
| 404 | } | ||
| 405 | |||
| 406 | ret = listen(sock, SOMAXCONN); | ||
| 407 | if (ret < 0) { | ||
| 408 | err("listen: %s: %d (%s)", | ||
| 409 | ai_buf, errno, strerror(errno)); | ||
| 410 | close(sock); | ||
| 411 | continue; | ||
| 412 | } | ||
| 413 | |||
| 414 | info("listening on %s", ai_buf); | ||
| 415 | sockfdlist[nsockfd++] = sock; | ||
| 416 | } | ||
| 417 | |||
| 418 | return nsockfd; | ||
| 419 | } | ||
| 420 | |||
| 421 | static struct addrinfo *do_getaddrinfo(char *host, int ai_family) | ||
| 422 | { | ||
| 423 | struct addrinfo hints, *ai_head; | ||
| 424 | int rc; | ||
| 425 | |||
| 426 | memset(&hints, 0, sizeof(hints)); | ||
| 427 | hints.ai_family = ai_family; | ||
| 428 | hints.ai_socktype = SOCK_STREAM; | ||
| 429 | hints.ai_flags = AI_PASSIVE; | ||
| 430 | |||
| 431 | rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head); | ||
| 432 | if (rc) { | ||
| 433 | err("failed to get a network address %s: %s", usbip_port_string, | ||
| 434 | gai_strerror(rc)); | ||
| 435 | return NULL; | ||
| 436 | } | ||
| 437 | |||
| 438 | return ai_head; | ||
| 439 | } | ||
| 440 | |||
| 441 | static void signal_handler(int i) | ||
| 442 | { | ||
| 443 | dbg("received '%s' signal", strsignal(i)); | ||
| 444 | } | ||
| 445 | |||
| 446 | static void set_signal(void) | ||
| 447 | { | ||
| 448 | struct sigaction act; | ||
| 449 | |||
| 450 | memset(&act, 0, sizeof(act)); | ||
| 451 | act.sa_handler = signal_handler; | ||
| 452 | sigemptyset(&act.sa_mask); | ||
| 453 | sigaction(SIGTERM, &act, NULL); | ||
| 454 | sigaction(SIGINT, &act, NULL); | ||
| 455 | act.sa_handler = SIG_IGN; | ||
| 456 | sigaction(SIGCLD, &act, NULL); | ||
| 457 | } | ||
| 458 | |||
| 459 | static const char *pid_file; | ||
| 460 | |||
| 461 | static void write_pid_file(void) | ||
| 462 | { | ||
| 463 | if (pid_file) { | ||
| 464 | dbg("creating pid file %s", pid_file); | ||
| 465 | FILE *fp; | ||
| 466 | |||
| 467 | fp = fopen(pid_file, "w"); | ||
| 468 | if (!fp) { | ||
| 469 | err("pid_file: %s: %d (%s)", | ||
| 470 | pid_file, errno, strerror(errno)); | ||
| 471 | return; | ||
| 472 | } | ||
| 473 | fprintf(fp, "%d\n", getpid()); | ||
| 474 | fclose(fp); | ||
| 475 | } | ||
| 476 | } | ||
| 477 | |||
| 478 | static void remove_pid_file(void) | ||
| 479 | { | ||
| 480 | if (pid_file) { | ||
| 481 | dbg("removing pid file %s", pid_file); | ||
| 482 | unlink(pid_file); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | static int do_standalone_mode(int daemonize, int ipv4, int ipv6) | ||
| 487 | { | ||
| 488 | struct addrinfo *ai_head; | ||
| 489 | int sockfdlist[MAXSOCKFD]; | ||
| 490 | int nsockfd, family; | ||
| 491 | int i, terminate; | ||
| 492 | struct pollfd *fds; | ||
| 493 | struct timespec timeout; | ||
| 494 | sigset_t sigmask; | ||
| 495 | |||
| 496 | if (usbip_host_driver_open()) { | ||
| 497 | err("please load " USBIP_CORE_MOD_NAME ".ko and " | ||
| 498 | USBIP_HOST_DRV_NAME ".ko!"); | ||
| 499 | return -1; | ||
| 500 | } | ||
| 501 | |||
| 502 | if (daemonize) { | ||
| 503 | if (daemon(0, 0) < 0) { | ||
| 504 | err("daemonizing failed: %s", strerror(errno)); | ||
| 505 | usbip_host_driver_close(); | ||
| 506 | return -1; | ||
| 507 | } | ||
| 508 | umask(0); | ||
| 509 | usbip_use_syslog = 1; | ||
| 510 | } | ||
| 511 | set_signal(); | ||
| 512 | write_pid_file(); | ||
| 513 | |||
| 514 | info("starting " PROGNAME " (%s)", usbip_version_string); | ||
| 515 | |||
| 516 | /* | ||
| 517 | * To suppress warnings on systems with bindv6only disabled | ||
| 518 | * (default), we use seperate sockets for IPv6 and IPv4 and set | ||
| 519 | * IPV6_V6ONLY on the IPv6 sockets. | ||
| 520 | */ | ||
| 521 | if (ipv4 && ipv6) | ||
| 522 | family = AF_UNSPEC; | ||
| 523 | else if (ipv4) | ||
| 524 | family = AF_INET; | ||
| 525 | else | ||
| 526 | family = AF_INET6; | ||
| 527 | |||
| 528 | ai_head = do_getaddrinfo(NULL, family); | ||
| 529 | if (!ai_head) { | ||
| 530 | usbip_host_driver_close(); | ||
| 531 | return -1; | ||
| 532 | } | ||
| 533 | nsockfd = listen_all_addrinfo(ai_head, sockfdlist, | ||
| 534 | sizeof(sockfdlist) / sizeof(*sockfdlist)); | ||
| 535 | freeaddrinfo(ai_head); | ||
| 536 | if (nsockfd <= 0) { | ||
| 537 | err("failed to open a listening socket"); | ||
| 538 | usbip_host_driver_close(); | ||
| 539 | return -1; | ||
| 540 | } | ||
| 541 | |||
| 542 | dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); | ||
| 543 | |||
| 544 | fds = calloc(nsockfd, sizeof(struct pollfd)); | ||
| 545 | for (i = 0; i < nsockfd; i++) { | ||
| 546 | fds[i].fd = sockfdlist[i]; | ||
| 547 | fds[i].events = POLLIN; | ||
| 548 | } | ||
| 549 | timeout.tv_sec = MAIN_LOOP_TIMEOUT; | ||
| 550 | timeout.tv_nsec = 0; | ||
| 551 | |||
| 552 | sigfillset(&sigmask); | ||
| 553 | sigdelset(&sigmask, SIGTERM); | ||
| 554 | sigdelset(&sigmask, SIGINT); | ||
| 555 | |||
| 556 | terminate = 0; | ||
| 557 | while (!terminate) { | ||
| 558 | int r; | ||
| 559 | |||
| 560 | r = ppoll(fds, nsockfd, &timeout, &sigmask); | ||
| 561 | if (r < 0) { | ||
| 562 | dbg("%s", strerror(errno)); | ||
| 563 | terminate = 1; | ||
| 564 | } else if (r) { | ||
| 565 | for (i = 0; i < nsockfd; i++) { | ||
| 566 | if (fds[i].revents & POLLIN) { | ||
| 567 | dbg("read event on fd[%d]=%d", | ||
| 568 | i, sockfdlist[i]); | ||
| 569 | process_request(sockfdlist[i]); | ||
| 570 | } | ||
| 571 | } | ||
| 572 | } else { | ||
| 573 | dbg("heartbeat timeout on ppoll()"); | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | info("shutting down " PROGNAME); | ||
| 578 | free(fds); | ||
| 579 | usbip_host_driver_close(); | ||
| 580 | |||
| 581 | return 0; | ||
| 582 | } | ||
| 583 | |||
| 584 | int main(int argc, char *argv[]) | ||
| 585 | { | ||
| 586 | static const struct option longopts[] = { | ||
| 587 | { "ipv4", no_argument, NULL, '4' }, | ||
| 588 | { "ipv6", no_argument, NULL, '6' }, | ||
| 589 | { "daemon", no_argument, NULL, 'D' }, | ||
| 590 | { "daemon", no_argument, NULL, 'D' }, | ||
| 591 | { "debug", no_argument, NULL, 'd' }, | ||
| 592 | { "pid", optional_argument, NULL, 'P' }, | ||
| 593 | { "tcp-port", required_argument, NULL, 't' }, | ||
| 594 | { "help", no_argument, NULL, 'h' }, | ||
| 595 | { "version", no_argument, NULL, 'v' }, | ||
| 596 | { NULL, 0, NULL, 0 } | ||
| 597 | }; | ||
| 598 | |||
| 599 | enum { | ||
| 600 | cmd_standalone_mode = 1, | ||
| 601 | cmd_help, | ||
| 602 | cmd_version | ||
| 603 | } cmd; | ||
| 604 | |||
| 605 | int daemonize = 0; | ||
| 606 | int ipv4 = 0, ipv6 = 0; | ||
| 607 | int opt, rc = -1; | ||
| 608 | |||
| 609 | pid_file = NULL; | ||
| 610 | |||
| 611 | usbip_use_stderr = 1; | ||
| 612 | usbip_use_syslog = 0; | ||
| 613 | |||
| 614 | if (geteuid() != 0) | ||
| 615 | err("not running as root?"); | ||
| 616 | |||
| 617 | cmd = cmd_standalone_mode; | ||
| 618 | for (;;) { | ||
| 619 | opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL); | ||
| 620 | |||
| 621 | if (opt == -1) | ||
| 622 | break; | ||
| 623 | |||
| 624 | switch (opt) { | ||
| 625 | case '4': | ||
| 626 | ipv4 = 1; | ||
| 627 | break; | ||
| 628 | case '6': | ||
| 629 | ipv6 = 1; | ||
| 630 | break; | ||
| 631 | case 'D': | ||
| 632 | daemonize = 1; | ||
| 633 | break; | ||
| 634 | case 'd': | ||
| 635 | usbip_use_debug = 1; | ||
| 636 | break; | ||
| 637 | case 'h': | ||
| 638 | cmd = cmd_help; | ||
| 639 | break; | ||
| 640 | case 'P': | ||
| 641 | pid_file = optarg ? optarg : DEFAULT_PID_FILE; | ||
| 642 | break; | ||
| 643 | case 't': | ||
| 644 | usbip_setup_port_number(optarg); | ||
| 645 | break; | ||
| 646 | case 'v': | ||
| 647 | cmd = cmd_version; | ||
| 648 | break; | ||
| 649 | case '?': | ||
| 650 | usbipd_help(); | ||
| 651 | default: | ||
| 652 | goto err_out; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | if (!ipv4 && !ipv6) | ||
| 657 | ipv4 = ipv6 = 1; | ||
| 658 | |||
| 659 | switch (cmd) { | ||
| 660 | case cmd_standalone_mode: | ||
| 661 | rc = do_standalone_mode(daemonize, ipv4, ipv6); | ||
| 662 | remove_pid_file(); | ||
| 663 | break; | ||
| 664 | case cmd_version: | ||
| 665 | printf(PROGNAME " (%s)\n", usbip_version_string); | ||
| 666 | rc = 0; | ||
| 667 | break; | ||
| 668 | case cmd_help: | ||
| 669 | usbipd_help(); | ||
| 670 | rc = 0; | ||
| 671 | break; | ||
| 672 | default: | ||
| 673 | usbipd_help(); | ||
| 674 | goto err_out; | ||
| 675 | } | ||
| 676 | |||
| 677 | err_out: | ||
| 678 | return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE); | ||
| 679 | } | ||
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c new file mode 100644 index 000000000000..2b3d6d235015 --- /dev/null +++ b/tools/usb/usbip/src/utils.c | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <errno.h> | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <string.h> | ||
| 22 | |||
| 23 | #include "usbip_common.h" | ||
| 24 | #include "utils.h" | ||
| 25 | #include "sysfs_utils.h" | ||
| 26 | |||
| 27 | int modify_match_busid(char *busid, int add) | ||
| 28 | { | ||
| 29 | char attr_name[] = "match_busid"; | ||
| 30 | char command[SYSFS_BUS_ID_SIZE + 4]; | ||
| 31 | char match_busid_attr_path[SYSFS_PATH_MAX]; | ||
| 32 | int rc; | ||
| 33 | |||
| 34 | snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), | ||
| 35 | "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, | ||
| 36 | SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, | ||
| 37 | attr_name); | ||
| 38 | |||
| 39 | if (add) | ||
| 40 | snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); | ||
| 41 | else | ||
| 42 | snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); | ||
| 43 | |||
| 44 | rc = write_sysfs_attribute(match_busid_attr_path, command, | ||
| 45 | sizeof(command)); | ||
| 46 | if (rc < 0) { | ||
| 47 | dbg("failed to write match_busid: %s", strerror(errno)); | ||
| 48 | return -1; | ||
| 49 | } | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | } | ||
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h new file mode 100644 index 000000000000..5916fd3e02a6 --- /dev/null +++ b/tools/usb/usbip/src/utils.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
| 3 | * 2005-2007 Takahiro Hirofuchi | ||
| 4 | * | ||
| 5 | * This program is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation, either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __UTILS_H | ||
| 20 | #define __UTILS_H | ||
| 21 | |||
| 22 | int modify_match_busid(char *busid, int add); | ||
| 23 | |||
| 24 | #endif /* __UTILS_H */ | ||
| 25 | |||
