initial USB support
[qemu] / 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