Statistics
| Branch: | Revision:

root / hw / usb.c @ 50b7963e

History | View | Annotate | Download (8.1 kB)

1 bb36d470 bellard
/*
2 bb36d470 bellard
 * QEMU USB emulation
3 bb36d470 bellard
 *
4 bb36d470 bellard
 * Copyright (c) 2005 Fabrice Bellard
5 5fafdf24 ths
 *
6 89b9b79f aliguori
 * 2008 Generic packet handler rewrite by Max Krasnyansky
7 89b9b79f aliguori
 *
8 bb36d470 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 bb36d470 bellard
 * of this software and associated documentation files (the "Software"), to deal
10 bb36d470 bellard
 * in the Software without restriction, including without limitation the rights
11 bb36d470 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 bb36d470 bellard
 * copies of the Software, and to permit persons to whom the Software is
13 bb36d470 bellard
 * furnished to do so, subject to the following conditions:
14 bb36d470 bellard
 *
15 bb36d470 bellard
 * The above copyright notice and this permission notice shall be included in
16 bb36d470 bellard
 * all copies or substantial portions of the Software.
17 bb36d470 bellard
 *
18 bb36d470 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 bb36d470 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 bb36d470 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 bb36d470 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 bb36d470 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 bb36d470 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 bb36d470 bellard
 * THE SOFTWARE.
25 bb36d470 bellard
 */
26 87ecb68b pbrook
#include "qemu-common.h"
27 87ecb68b pbrook
#include "usb.h"
28 bb36d470 bellard
29 bb36d470 bellard
void usb_attach(USBPort *port, USBDevice *dev)
30 bb36d470 bellard
{
31 618c169b Gerd Hoffmann
    if (dev != NULL) {
32 618c169b Gerd Hoffmann
        /* attach */
33 618c169b Gerd Hoffmann
        if (port->dev) {
34 618c169b Gerd Hoffmann
            usb_attach(port, NULL);
35 618c169b Gerd Hoffmann
        }
36 618c169b Gerd Hoffmann
        dev->port = port;
37 618c169b Gerd Hoffmann
        port->dev = dev;
38 618c169b Gerd Hoffmann
        port->ops->attach(port);
39 618c169b Gerd Hoffmann
        usb_send_msg(dev, USB_MSG_ATTACH);
40 618c169b Gerd Hoffmann
    } else {
41 618c169b Gerd Hoffmann
        /* detach */
42 618c169b Gerd Hoffmann
        dev = port->dev;
43 618c169b Gerd Hoffmann
        port->ops->detach(port);
44 618c169b Gerd Hoffmann
        if (dev) {
45 618c169b Gerd Hoffmann
            usb_send_msg(dev, USB_MSG_DETACH);
46 618c169b Gerd Hoffmann
            dev->port = NULL;
47 618c169b Gerd Hoffmann
            port->dev = NULL;
48 618c169b Gerd Hoffmann
        }
49 618c169b Gerd Hoffmann
    }
50 bb36d470 bellard
}
51 bb36d470 bellard
52 01eacab6 Gerd Hoffmann
void usb_wakeup(USBDevice *dev)
53 01eacab6 Gerd Hoffmann
{
54 01eacab6 Gerd Hoffmann
    if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
55 01eacab6 Gerd Hoffmann
        dev->port->ops->wakeup(dev);
56 01eacab6 Gerd Hoffmann
    }
57 01eacab6 Gerd Hoffmann
}
58 01eacab6 Gerd Hoffmann
59 bb36d470 bellard
/**********************/
60 89b9b79f aliguori
61 bb36d470 bellard
/* generic USB device helpers (you are not forced to use them when
62 bb36d470 bellard
   writing your USB device driver, but they help handling the
63 5fafdf24 ths
   protocol)
64 bb36d470 bellard
*/
65 bb36d470 bellard
66 50b7963e Hans de Goede
#define SETUP_STATE_IDLE  0
67 50b7963e Hans de Goede
#define SETUP_STATE_SETUP 1
68 50b7963e Hans de Goede
#define SETUP_STATE_DATA  2
69 50b7963e Hans de Goede
#define SETUP_STATE_ACK   3
70 bb36d470 bellard
71 89b9b79f aliguori
static int do_token_setup(USBDevice *s, USBPacket *p)
72 89b9b79f aliguori
{
73 89b9b79f aliguori
    int request, value, index;
74 89b9b79f aliguori
    int ret = 0;
75 89b9b79f aliguori
76 89b9b79f aliguori
    if (p->len != 8)
77 89b9b79f aliguori
        return USB_RET_STALL;
78 89b9b79f aliguori
 
79 89b9b79f aliguori
    memcpy(s->setup_buf, p->data, 8);
80 89b9b79f aliguori
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
81 89b9b79f aliguori
    s->setup_index = 0;
82 89b9b79f aliguori
83 89b9b79f aliguori
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
84 89b9b79f aliguori
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
85 89b9b79f aliguori
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
86 007fd62f Hans de Goede
87 89b9b79f aliguori
    if (s->setup_buf[0] & USB_DIR_IN) {
88 007fd62f Hans de Goede
        ret = s->info->handle_control(s, p, request, value, index,
89 806b6024 Gerd Hoffmann
                                      s->setup_len, s->data_buf);
90 50b7963e Hans de Goede
        if (ret == USB_RET_ASYNC) {
91 50b7963e Hans de Goede
             s->setup_state = SETUP_STATE_SETUP;
92 50b7963e Hans de Goede
             return USB_RET_ASYNC;
93 50b7963e Hans de Goede
        }
94 89b9b79f aliguori
        if (ret < 0)
95 89b9b79f aliguori
            return ret;
96 89b9b79f aliguori
97 89b9b79f aliguori
        if (ret < s->setup_len)
98 89b9b79f aliguori
            s->setup_len = ret;
99 89b9b79f aliguori
        s->setup_state = SETUP_STATE_DATA;
100 89b9b79f aliguori
    } else {
101 19f33223 Hans de Goede
        if (s->setup_len > sizeof(s->data_buf)) {
102 19f33223 Hans de Goede
            fprintf(stderr,
103 19f33223 Hans de Goede
                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
104 19f33223 Hans de Goede
                s->setup_len, sizeof(s->data_buf));
105 19f33223 Hans de Goede
            return USB_RET_STALL;
106 19f33223 Hans de Goede
        }
107 89b9b79f aliguori
        if (s->setup_len == 0)
108 89b9b79f aliguori
            s->setup_state = SETUP_STATE_ACK;
109 89b9b79f aliguori
        else
110 89b9b79f aliguori
            s->setup_state = SETUP_STATE_DATA;
111 89b9b79f aliguori
    }
112 89b9b79f aliguori
113 89b9b79f aliguori
    return ret;
114 89b9b79f aliguori
}
115 89b9b79f aliguori
116 89b9b79f aliguori
static int do_token_in(USBDevice *s, USBPacket *p)
117 bb36d470 bellard
{
118 89b9b79f aliguori
    int request, value, index;
119 89b9b79f aliguori
    int ret = 0;
120 89b9b79f aliguori
121 89b9b79f aliguori
    if (p->devep != 0)
122 806b6024 Gerd Hoffmann
        return s->info->handle_data(s, p);
123 89b9b79f aliguori
124 89b9b79f aliguori
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
125 89b9b79f aliguori
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
126 89b9b79f aliguori
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
127 89b9b79f aliguori
 
128 89b9b79f aliguori
    switch(s->setup_state) {
129 89b9b79f aliguori
    case SETUP_STATE_ACK:
130 89b9b79f aliguori
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
131 007fd62f Hans de Goede
            ret = s->info->handle_control(s, p, request, value, index,
132 806b6024 Gerd Hoffmann
                                          s->setup_len, s->data_buf);
133 007fd62f Hans de Goede
            if (ret == USB_RET_ASYNC) {
134 007fd62f Hans de Goede
                return USB_RET_ASYNC;
135 007fd62f Hans de Goede
            }
136 007fd62f Hans de Goede
            s->setup_state = SETUP_STATE_IDLE;
137 89b9b79f aliguori
            if (ret > 0)
138 89b9b79f aliguori
                return 0;
139 89b9b79f aliguori
            return ret;
140 89b9b79f aliguori
        }
141 89b9b79f aliguori
142 89b9b79f aliguori
        /* return 0 byte */
143 89b9b79f aliguori
        return 0;
144 89b9b79f aliguori
145 89b9b79f aliguori
    case SETUP_STATE_DATA:
146 89b9b79f aliguori
        if (s->setup_buf[0] & USB_DIR_IN) {
147 89b9b79f aliguori
            int len = s->setup_len - s->setup_index;
148 89b9b79f aliguori
            if (len > p->len)
149 89b9b79f aliguori
                len = p->len;
150 89b9b79f aliguori
            memcpy(p->data, s->data_buf + s->setup_index, len);
151 89b9b79f aliguori
            s->setup_index += len;
152 89b9b79f aliguori
            if (s->setup_index >= s->setup_len)
153 89b9b79f aliguori
                s->setup_state = SETUP_STATE_ACK;
154 89b9b79f aliguori
            return len;
155 89b9b79f aliguori
        }
156 89b9b79f aliguori
157 89b9b79f aliguori
        s->setup_state = SETUP_STATE_IDLE;
158 89b9b79f aliguori
        return USB_RET_STALL;
159 89b9b79f aliguori
160 89b9b79f aliguori
    default:
161 89b9b79f aliguori
        return USB_RET_STALL;
162 89b9b79f aliguori
    }
163 89b9b79f aliguori
}
164 89b9b79f aliguori
165 89b9b79f aliguori
static int do_token_out(USBDevice *s, USBPacket *p)
166 89b9b79f aliguori
{
167 89b9b79f aliguori
    if (p->devep != 0)
168 806b6024 Gerd Hoffmann
        return s->info->handle_data(s, p);
169 89b9b79f aliguori
170 89b9b79f aliguori
    switch(s->setup_state) {
171 89b9b79f aliguori
    case SETUP_STATE_ACK:
172 89b9b79f aliguori
        if (s->setup_buf[0] & USB_DIR_IN) {
173 89b9b79f aliguori
            s->setup_state = SETUP_STATE_IDLE;
174 89b9b79f aliguori
            /* transfer OK */
175 89b9b79f aliguori
        } else {
176 89b9b79f aliguori
            /* ignore additional output */
177 89b9b79f aliguori
        }
178 89b9b79f aliguori
        return 0;
179 89b9b79f aliguori
180 89b9b79f aliguori
    case SETUP_STATE_DATA:
181 89b9b79f aliguori
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
182 89b9b79f aliguori
            int len = s->setup_len - s->setup_index;
183 89b9b79f aliguori
            if (len > p->len)
184 89b9b79f aliguori
                len = p->len;
185 89b9b79f aliguori
            memcpy(s->data_buf + s->setup_index, p->data, len);
186 89b9b79f aliguori
            s->setup_index += len;
187 89b9b79f aliguori
            if (s->setup_index >= s->setup_len)
188 89b9b79f aliguori
                s->setup_state = SETUP_STATE_ACK;
189 89b9b79f aliguori
            return len;
190 89b9b79f aliguori
        }
191 89b9b79f aliguori
192 89b9b79f aliguori
        s->setup_state = SETUP_STATE_IDLE;
193 89b9b79f aliguori
        return USB_RET_STALL;
194 89b9b79f aliguori
195 89b9b79f aliguori
    default:
196 89b9b79f aliguori
        return USB_RET_STALL;
197 89b9b79f aliguori
    }
198 89b9b79f aliguori
}
199 bb36d470 bellard
200 89b9b79f aliguori
/*
201 89b9b79f aliguori
 * Generic packet handler.
202 89b9b79f aliguori
 * Called by the HC (host controller).
203 89b9b79f aliguori
 *
204 89b9b79f aliguori
 * Returns length of the transaction or one of the USB_RET_XXX codes.
205 89b9b79f aliguori
 */
206 89b9b79f aliguori
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
207 89b9b79f aliguori
{
208 4d611c9a pbrook
    switch(p->pid) {
209 bb36d470 bellard
    case USB_MSG_ATTACH:
210 bb36d470 bellard
        s->state = USB_STATE_ATTACHED;
211 b6f77fbe Gerd Hoffmann
        if (s->info->handle_attach) {
212 b6f77fbe Gerd Hoffmann
            s->info->handle_attach(s);
213 b6f77fbe Gerd Hoffmann
        }
214 89b9b79f aliguori
        return 0;
215 89b9b79f aliguori
216 bb36d470 bellard
    case USB_MSG_DETACH:
217 bb36d470 bellard
        s->state = USB_STATE_NOTATTACHED;
218 89b9b79f aliguori
        return 0;
219 89b9b79f aliguori
220 bb36d470 bellard
    case USB_MSG_RESET:
221 bb36d470 bellard
        s->remote_wakeup = 0;
222 bb36d470 bellard
        s->addr = 0;
223 bb36d470 bellard
        s->state = USB_STATE_DEFAULT;
224 b6f77fbe Gerd Hoffmann
        if (s->info->handle_reset) {
225 b6f77fbe Gerd Hoffmann
            s->info->handle_reset(s);
226 b6f77fbe Gerd Hoffmann
        }
227 89b9b79f aliguori
        return 0;
228 89b9b79f aliguori
    }
229 89b9b79f aliguori
230 89b9b79f aliguori
    /* Rest of the PIDs must match our address */
231 89b9b79f aliguori
    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
232 89b9b79f aliguori
        return USB_RET_NODEV;
233 89b9b79f aliguori
234 89b9b79f aliguori
    switch (p->pid) {
235 bb36d470 bellard
    case USB_TOKEN_SETUP:
236 89b9b79f aliguori
        return do_token_setup(s, p);
237 89b9b79f aliguori
238 bb36d470 bellard
    case USB_TOKEN_IN:
239 89b9b79f aliguori
        return do_token_in(s, p);
240 89b9b79f aliguori
241 bb36d470 bellard
    case USB_TOKEN_OUT:
242 89b9b79f aliguori
        return do_token_out(s, p);
243 89b9b79f aliguori
 
244 bb36d470 bellard
    default:
245 89b9b79f aliguori
        return USB_RET_STALL;
246 bb36d470 bellard
    }
247 bb36d470 bellard
}
248 bb36d470 bellard
249 50b7963e Hans de Goede
/* ctrl complete function for devices which use usb_generic_handle_packet and
250 50b7963e Hans de Goede
   may return USB_RET_ASYNC from their handle_control callback. Device code
251 50b7963e Hans de Goede
   which does this *must* call this function instead of the normal
252 50b7963e Hans de Goede
   usb_packet_complete to complete their async control packets. */
253 50b7963e Hans de Goede
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
254 50b7963e Hans de Goede
{
255 50b7963e Hans de Goede
    if (p->len < 0) {
256 50b7963e Hans de Goede
        s->setup_state = SETUP_STATE_IDLE;
257 50b7963e Hans de Goede
    }
258 50b7963e Hans de Goede
259 50b7963e Hans de Goede
    switch (s->setup_state) {
260 50b7963e Hans de Goede
    case SETUP_STATE_SETUP:
261 50b7963e Hans de Goede
        if (p->len < s->setup_len) {
262 50b7963e Hans de Goede
            s->setup_len = p->len;
263 50b7963e Hans de Goede
        }
264 50b7963e Hans de Goede
        s->setup_state = SETUP_STATE_DATA;
265 50b7963e Hans de Goede
        p->len = 8;
266 50b7963e Hans de Goede
        break;
267 50b7963e Hans de Goede
268 50b7963e Hans de Goede
    case SETUP_STATE_ACK:
269 50b7963e Hans de Goede
        s->setup_state = SETUP_STATE_IDLE;
270 50b7963e Hans de Goede
        p->len = 0;
271 50b7963e Hans de Goede
        break;
272 50b7963e Hans de Goede
273 50b7963e Hans de Goede
    default:
274 50b7963e Hans de Goede
        break;
275 50b7963e Hans de Goede
    }
276 50b7963e Hans de Goede
    usb_packet_complete(s, p);
277 50b7963e Hans de Goede
}
278 50b7963e Hans de Goede
279 bb36d470 bellard
/* XXX: fix overflow */
280 bb36d470 bellard
int set_usb_string(uint8_t *buf, const char *str)
281 bb36d470 bellard
{
282 bb36d470 bellard
    int len, i;
283 bb36d470 bellard
    uint8_t *q;
284 bb36d470 bellard
285 bb36d470 bellard
    q = buf;
286 bb36d470 bellard
    len = strlen(str);
287 ce5c37c2 pbrook
    *q++ = 2 * len + 2;
288 bb36d470 bellard
    *q++ = 3;
289 bb36d470 bellard
    for(i = 0; i < len; i++) {
290 bb36d470 bellard
        *q++ = str[i];
291 bb36d470 bellard
        *q++ = 0;
292 bb36d470 bellard
    }
293 bb36d470 bellard
    return q - buf;
294 bb36d470 bellard
}
295 4d611c9a pbrook
296 4d611c9a pbrook
/* Send an internal message to a USB device.  */
297 4d611c9a pbrook
void usb_send_msg(USBDevice *dev, int msg)
298 4d611c9a pbrook
{
299 4d611c9a pbrook
    USBPacket p;
300 4d611c9a pbrook
    memset(&p, 0, sizeof(p));
301 4d611c9a pbrook
    p.pid = msg;
302 806b6024 Gerd Hoffmann
    dev->info->handle_packet(dev, &p);
303 4d611c9a pbrook
304 89b9b79f aliguori
    /* This _must_ be synchronous */
305 89b9b79f aliguori
}