]> git.ipfire.org Git - thirdparty/qemu.git/blob - usb-linux.c
initial USB support
[thirdparty/qemu.git] / usb-linux.c
1 /*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "vl.h"
25
26 #if defined(__linux__)
27 #include <dirent.h>
28 #include <sys/ioctl.h>
29 #include <linux/usbdevice_fs.h>
30 #include <linux/version.h>
31
32 /* We redefine it to avoid version problems */
33 struct usb_ctrltransfer {
34 uint8_t bRequestType;
35 uint8_t bRequest;
36 uint16_t wValue;
37 uint16_t wIndex;
38 uint16_t wLength;
39 uint32_t timeout;
40 void *data;
41 };
42
43 //#define DEBUG
44
45 #define MAX_DEVICES 8
46
47 #define USBDEVFS_PATH "/proc/bus/usb"
48
49 typedef struct USBHostDevice {
50 USBDevice dev;
51 int fd;
52 } USBHostDevice;
53
54 typedef struct USBHostHubState {
55 USBDevice *hub_dev;
56 USBPort *hub_ports[MAX_DEVICES];
57 USBDevice *hub_devices[MAX_DEVICES];
58 } USBHostHubState;
59
60 static void usb_host_handle_reset(USBDevice *dev)
61 {
62 #if 0
63 USBHostDevice *s = (USBHostDevice *)dev;
64 /* USBDEVFS_RESET, but not the first time as it has already be
65 done by the host OS */
66 ioctl(s->fd, USBDEVFS_RESET);
67 #endif
68 }
69
70 static int usb_host_handle_control(USBDevice *dev,
71 int request,
72 int value,
73 int index,
74 int length,
75 uint8_t *data)
76 {
77 USBHostDevice *s = (USBHostDevice *)dev;
78 struct usb_ctrltransfer ct;
79 int ret;
80
81 if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
82 /* specific SET_ADDRESS support */
83 dev->addr = value;
84 return 0;
85 } else {
86 ct.bRequestType = request >> 8;
87 ct.bRequest = request;
88 ct.wValue = value;
89 ct.wIndex = index;
90 ct.wLength = length;
91 ct.timeout = 50;
92 ct.data = data;
93 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
94 if (ret < 0) {
95 switch(errno) {
96 case ETIMEDOUT:
97 return USB_RET_NAK;
98 default:
99 return USB_RET_STALL;
100 }
101 } else {
102 return ret;
103 }
104 }
105 }
106
107 static int usb_host_handle_data(USBDevice *dev, int pid,
108 uint8_t devep,
109 uint8_t *data, int len)
110 {
111 USBHostDevice *s = (USBHostDevice *)dev;
112 struct usbdevfs_bulktransfer bt;
113 int ret;
114
115 /* XXX: optimize and handle all data types by looking at the
116 config descriptor */
117 if (pid == USB_TOKEN_IN)
118 devep |= 0x80;
119 bt.ep = devep;
120 bt.len = len;
121 bt.timeout = 50;
122 bt.data = data;
123 ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
124 if (ret < 0) {
125 switch(errno) {
126 case ETIMEDOUT:
127 return USB_RET_NAK;
128 case EPIPE:
129 default:
130 #ifdef DEBUG
131 printf("handle_data: errno=%d\n", errno);
132 #endif
133 return USB_RET_STALL;
134 }
135 } else {
136 return ret;
137 }
138 }
139
140 static int usb_host_handle_packet(USBDevice *dev, int pid,
141 uint8_t devaddr, uint8_t devep,
142 uint8_t *data, int len)
143 {
144 return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
145 }
146
147 /* XXX: exclude high speed devices or implement EHCI */
148 static void scan_host_device(USBHostHubState *s, const char *filename)
149 {
150 int fd, interface, ret, i;
151 USBHostDevice *dev;
152 struct usbdevfs_connectinfo ci;
153 uint8_t descr[1024];
154 int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
155
156 #ifdef DEBUG
157 printf("scanning %s\n", filename);
158 #endif
159 fd = open(filename, O_RDWR);
160 if (fd < 0) {
161 perror(filename);
162 return;
163 }
164
165 /* read the config description */
166 descr_len = read(fd, descr, sizeof(descr));
167 if (descr_len <= 0) {
168 perror("read descr");
169 goto fail;
170 }
171
172 i = 0;
173 dev_descr_len = descr[0];
174 if (dev_descr_len > descr_len)
175 goto fail;
176 i += dev_descr_len;
177 config_descr_len = descr[i];
178 if (i + config_descr_len > descr_len)
179 goto fail;
180 nb_interfaces = descr[i + 4];
181 if (nb_interfaces != 1) {
182 /* NOTE: currently we grab only one interface */
183 goto fail;
184 }
185 /* XXX: only grab if all interfaces are free */
186 interface = 0;
187 ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
188 if (ret < 0) {
189 if (errno == EBUSY) {
190 #ifdef DEBUG
191 printf("%s already grabbed\n", filename);
192 #endif
193 } else {
194 perror("USBDEVFS_CLAIMINTERFACE");
195 }
196 fail:
197 close(fd);
198 return;
199 }
200
201 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
202 if (ret < 0) {
203 perror("USBDEVFS_CONNECTINFO");
204 goto fail;
205 }
206
207 #ifdef DEBUG
208 printf("%s grabbed\n", filename);
209 #endif
210
211 /* find a free slot */
212 for(i = 0; i < MAX_DEVICES; i++) {
213 if (!s->hub_devices[i])
214 break;
215 }
216 if (i == MAX_DEVICES) {
217 #ifdef DEBUG
218 printf("too many host devices\n");
219 goto fail;
220 #endif
221 }
222
223 dev = qemu_mallocz(sizeof(USBHostDevice));
224 if (!dev)
225 goto fail;
226 dev->fd = fd;
227 if (ci.slow)
228 dev->dev.speed = USB_SPEED_LOW;
229 else
230 dev->dev.speed = USB_SPEED_HIGH;
231 dev->dev.handle_packet = usb_host_handle_packet;
232
233 dev->dev.handle_reset = usb_host_handle_reset;
234 dev->dev.handle_control = usb_host_handle_control;
235 dev->dev.handle_data = usb_host_handle_data;
236
237 s->hub_devices[i] = (USBDevice *)dev;
238
239 /* activate device on hub */
240 usb_attach(s->hub_ports[i], s->hub_devices[i]);
241 }
242
243 static void scan_host_devices(USBHostHubState *s, const char *bus_path)
244 {
245 DIR *d;
246 struct dirent *de;
247 char buf[1024];
248
249 d = opendir(bus_path);
250 if (!d)
251 return;
252 for(;;) {
253 de = readdir(d);
254 if (!de)
255 break;
256 if (de->d_name[0] != '.') {
257 snprintf(buf, sizeof(buf), "%s/%s", bus_path, de->d_name);
258 scan_host_device(s, buf);
259 }
260 }
261 closedir(d);
262 }
263
264 static void scan_host_buses(USBHostHubState *s)
265 {
266 DIR *d;
267 struct dirent *de;
268 char buf[1024];
269
270 d = opendir(USBDEVFS_PATH);
271 if (!d)
272 return;
273 for(;;) {
274 de = readdir(d);
275 if (!de)
276 break;
277 if (isdigit(de->d_name[0])) {
278 snprintf(buf, sizeof(buf), "%s/%s", USBDEVFS_PATH, de->d_name);
279 scan_host_devices(s, buf);
280 }
281 }
282 closedir(d);
283 }
284
285 /* virtual hub containing the USB devices of the host */
286 USBDevice *usb_host_hub_init(void)
287 {
288 USBHostHubState *s;
289 s = qemu_mallocz(sizeof(USBHostHubState));
290 if (!s)
291 return NULL;
292 s->hub_dev = usb_hub_init(s->hub_ports, MAX_DEVICES);
293 if (!s->hub_dev) {
294 free(s);
295 return NULL;
296 }
297 scan_host_buses(s);
298 return s->hub_dev;
299 }
300
301 #else
302
303 /* XXX: modify configure to compile the right host driver */
304 USBDevice *usb_host_hub_init(void)
305 {
306 return NULL;
307 }
308
309 #endif