Statistics
| Branch: | Revision:

root / hw / usb.c @ 32993698

History | View | Annotate | Download (6.8 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 bb36d470 bellard
#define SETUP_STATE_IDLE 0
67 bb36d470 bellard
#define SETUP_STATE_DATA 1
68 bb36d470 bellard
#define SETUP_STATE_ACK  2
69 bb36d470 bellard
70 89b9b79f aliguori
static int do_token_setup(USBDevice *s, USBPacket *p)
71 89b9b79f aliguori
{
72 89b9b79f aliguori
    int request, value, index;
73 89b9b79f aliguori
    int ret = 0;
74 89b9b79f aliguori
75 89b9b79f aliguori
    if (p->len != 8)
76 89b9b79f aliguori
        return USB_RET_STALL;
77 89b9b79f aliguori
 
78 89b9b79f aliguori
    memcpy(s->setup_buf, p->data, 8);
79 89b9b79f aliguori
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
80 89b9b79f aliguori
    s->setup_index = 0;
81 89b9b79f aliguori
82 89b9b79f aliguori
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
83 89b9b79f aliguori
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
84 89b9b79f aliguori
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
85 89b9b79f aliguori
 
86 89b9b79f aliguori
    if (s->setup_buf[0] & USB_DIR_IN) {
87 806b6024 Gerd Hoffmann
        ret = s->info->handle_control(s, request, value, index, 
88 806b6024 Gerd Hoffmann
                                      s->setup_len, s->data_buf);
89 89b9b79f aliguori
        if (ret < 0)
90 89b9b79f aliguori
            return ret;
91 89b9b79f aliguori
92 89b9b79f aliguori
        if (ret < s->setup_len)
93 89b9b79f aliguori
            s->setup_len = ret;
94 89b9b79f aliguori
        s->setup_state = SETUP_STATE_DATA;
95 89b9b79f aliguori
    } else {
96 89b9b79f aliguori
        if (s->setup_len == 0)
97 89b9b79f aliguori
            s->setup_state = SETUP_STATE_ACK;
98 89b9b79f aliguori
        else
99 89b9b79f aliguori
            s->setup_state = SETUP_STATE_DATA;
100 89b9b79f aliguori
    }
101 89b9b79f aliguori
102 89b9b79f aliguori
    return ret;
103 89b9b79f aliguori
}
104 89b9b79f aliguori
105 89b9b79f aliguori
static int do_token_in(USBDevice *s, USBPacket *p)
106 bb36d470 bellard
{
107 89b9b79f aliguori
    int request, value, index;
108 89b9b79f aliguori
    int ret = 0;
109 89b9b79f aliguori
110 89b9b79f aliguori
    if (p->devep != 0)
111 806b6024 Gerd Hoffmann
        return s->info->handle_data(s, p);
112 89b9b79f aliguori
113 89b9b79f aliguori
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
114 89b9b79f aliguori
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
115 89b9b79f aliguori
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
116 89b9b79f aliguori
 
117 89b9b79f aliguori
    switch(s->setup_state) {
118 89b9b79f aliguori
    case SETUP_STATE_ACK:
119 89b9b79f aliguori
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
120 89b9b79f aliguori
            s->setup_state = SETUP_STATE_IDLE;
121 806b6024 Gerd Hoffmann
            ret = s->info->handle_control(s, request, value, index,
122 806b6024 Gerd Hoffmann
                                          s->setup_len, s->data_buf);
123 89b9b79f aliguori
            if (ret > 0)
124 89b9b79f aliguori
                return 0;
125 89b9b79f aliguori
            return ret;
126 89b9b79f aliguori
        }
127 89b9b79f aliguori
128 89b9b79f aliguori
        /* return 0 byte */
129 89b9b79f aliguori
        return 0;
130 89b9b79f aliguori
131 89b9b79f aliguori
    case SETUP_STATE_DATA:
132 89b9b79f aliguori
        if (s->setup_buf[0] & USB_DIR_IN) {
133 89b9b79f aliguori
            int len = s->setup_len - s->setup_index;
134 89b9b79f aliguori
            if (len > p->len)
135 89b9b79f aliguori
                len = p->len;
136 89b9b79f aliguori
            memcpy(p->data, s->data_buf + s->setup_index, len);
137 89b9b79f aliguori
            s->setup_index += len;
138 89b9b79f aliguori
            if (s->setup_index >= s->setup_len)
139 89b9b79f aliguori
                s->setup_state = SETUP_STATE_ACK;
140 89b9b79f aliguori
            return len;
141 89b9b79f aliguori
        }
142 89b9b79f aliguori
143 89b9b79f aliguori
        s->setup_state = SETUP_STATE_IDLE;
144 89b9b79f aliguori
        return USB_RET_STALL;
145 89b9b79f aliguori
146 89b9b79f aliguori
    default:
147 89b9b79f aliguori
        return USB_RET_STALL;
148 89b9b79f aliguori
    }
149 89b9b79f aliguori
}
150 89b9b79f aliguori
151 89b9b79f aliguori
static int do_token_out(USBDevice *s, USBPacket *p)
152 89b9b79f aliguori
{
153 89b9b79f aliguori
    if (p->devep != 0)
154 806b6024 Gerd Hoffmann
        return s->info->handle_data(s, p);
155 89b9b79f aliguori
156 89b9b79f aliguori
    switch(s->setup_state) {
157 89b9b79f aliguori
    case SETUP_STATE_ACK:
158 89b9b79f aliguori
        if (s->setup_buf[0] & USB_DIR_IN) {
159 89b9b79f aliguori
            s->setup_state = SETUP_STATE_IDLE;
160 89b9b79f aliguori
            /* transfer OK */
161 89b9b79f aliguori
        } else {
162 89b9b79f aliguori
            /* ignore additional output */
163 89b9b79f aliguori
        }
164 89b9b79f aliguori
        return 0;
165 89b9b79f aliguori
166 89b9b79f aliguori
    case SETUP_STATE_DATA:
167 89b9b79f aliguori
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
168 89b9b79f aliguori
            int len = s->setup_len - s->setup_index;
169 89b9b79f aliguori
            if (len > p->len)
170 89b9b79f aliguori
                len = p->len;
171 89b9b79f aliguori
            memcpy(s->data_buf + s->setup_index, p->data, len);
172 89b9b79f aliguori
            s->setup_index += len;
173 89b9b79f aliguori
            if (s->setup_index >= s->setup_len)
174 89b9b79f aliguori
                s->setup_state = SETUP_STATE_ACK;
175 89b9b79f aliguori
            return len;
176 89b9b79f aliguori
        }
177 89b9b79f aliguori
178 89b9b79f aliguori
        s->setup_state = SETUP_STATE_IDLE;
179 89b9b79f aliguori
        return USB_RET_STALL;
180 89b9b79f aliguori
181 89b9b79f aliguori
    default:
182 89b9b79f aliguori
        return USB_RET_STALL;
183 89b9b79f aliguori
    }
184 89b9b79f aliguori
}
185 bb36d470 bellard
186 89b9b79f aliguori
/*
187 89b9b79f aliguori
 * Generic packet handler.
188 89b9b79f aliguori
 * Called by the HC (host controller).
189 89b9b79f aliguori
 *
190 89b9b79f aliguori
 * Returns length of the transaction or one of the USB_RET_XXX codes.
191 89b9b79f aliguori
 */
192 89b9b79f aliguori
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
193 89b9b79f aliguori
{
194 4d611c9a pbrook
    switch(p->pid) {
195 bb36d470 bellard
    case USB_MSG_ATTACH:
196 bb36d470 bellard
        s->state = USB_STATE_ATTACHED;
197 b6f77fbe Gerd Hoffmann
        if (s->info->handle_attach) {
198 b6f77fbe Gerd Hoffmann
            s->info->handle_attach(s);
199 b6f77fbe Gerd Hoffmann
        }
200 89b9b79f aliguori
        return 0;
201 89b9b79f aliguori
202 bb36d470 bellard
    case USB_MSG_DETACH:
203 bb36d470 bellard
        s->state = USB_STATE_NOTATTACHED;
204 89b9b79f aliguori
        return 0;
205 89b9b79f aliguori
206 bb36d470 bellard
    case USB_MSG_RESET:
207 bb36d470 bellard
        s->remote_wakeup = 0;
208 bb36d470 bellard
        s->addr = 0;
209 bb36d470 bellard
        s->state = USB_STATE_DEFAULT;
210 b6f77fbe Gerd Hoffmann
        if (s->info->handle_reset) {
211 b6f77fbe Gerd Hoffmann
            s->info->handle_reset(s);
212 b6f77fbe Gerd Hoffmann
        }
213 89b9b79f aliguori
        return 0;
214 89b9b79f aliguori
    }
215 89b9b79f aliguori
216 89b9b79f aliguori
    /* Rest of the PIDs must match our address */
217 89b9b79f aliguori
    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
218 89b9b79f aliguori
        return USB_RET_NODEV;
219 89b9b79f aliguori
220 89b9b79f aliguori
    switch (p->pid) {
221 bb36d470 bellard
    case USB_TOKEN_SETUP:
222 89b9b79f aliguori
        return do_token_setup(s, p);
223 89b9b79f aliguori
224 bb36d470 bellard
    case USB_TOKEN_IN:
225 89b9b79f aliguori
        return do_token_in(s, p);
226 89b9b79f aliguori
227 bb36d470 bellard
    case USB_TOKEN_OUT:
228 89b9b79f aliguori
        return do_token_out(s, p);
229 89b9b79f aliguori
 
230 bb36d470 bellard
    default:
231 89b9b79f aliguori
        return USB_RET_STALL;
232 bb36d470 bellard
    }
233 bb36d470 bellard
}
234 bb36d470 bellard
235 bb36d470 bellard
/* XXX: fix overflow */
236 bb36d470 bellard
int set_usb_string(uint8_t *buf, const char *str)
237 bb36d470 bellard
{
238 bb36d470 bellard
    int len, i;
239 bb36d470 bellard
    uint8_t *q;
240 bb36d470 bellard
241 bb36d470 bellard
    q = buf;
242 bb36d470 bellard
    len = strlen(str);
243 ce5c37c2 pbrook
    *q++ = 2 * len + 2;
244 bb36d470 bellard
    *q++ = 3;
245 bb36d470 bellard
    for(i = 0; i < len; i++) {
246 bb36d470 bellard
        *q++ = str[i];
247 bb36d470 bellard
        *q++ = 0;
248 bb36d470 bellard
    }
249 bb36d470 bellard
    return q - buf;
250 bb36d470 bellard
}
251 4d611c9a pbrook
252 4d611c9a pbrook
/* Send an internal message to a USB device.  */
253 4d611c9a pbrook
void usb_send_msg(USBDevice *dev, int msg)
254 4d611c9a pbrook
{
255 4d611c9a pbrook
    USBPacket p;
256 4d611c9a pbrook
    memset(&p, 0, sizeof(p));
257 4d611c9a pbrook
    p.pid = msg;
258 806b6024 Gerd Hoffmann
    dev->info->handle_packet(dev, &p);
259 4d611c9a pbrook
260 89b9b79f aliguori
    /* This _must_ be synchronous */
261 89b9b79f aliguori
}