Statistics
| Branch: | Revision:

root / hw / usb.c @ 9b32d5a5

History | View | Annotate | Download (6.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 bb36d470 bellard
    port->attach(port, dev);
32 bb36d470 bellard
}
33 bb36d470 bellard
34 bb36d470 bellard
/**********************/
35 89b9b79f aliguori
36 bb36d470 bellard
/* generic USB device helpers (you are not forced to use them when
37 bb36d470 bellard
   writing your USB device driver, but they help handling the
38 5fafdf24 ths
   protocol)
39 bb36d470 bellard
*/
40 bb36d470 bellard
41 bb36d470 bellard
#define SETUP_STATE_IDLE 0
42 bb36d470 bellard
#define SETUP_STATE_DATA 1
43 bb36d470 bellard
#define SETUP_STATE_ACK  2
44 bb36d470 bellard
45 89b9b79f aliguori
static int do_token_setup(USBDevice *s, USBPacket *p)
46 89b9b79f aliguori
{
47 89b9b79f aliguori
    int request, value, index;
48 89b9b79f aliguori
    int ret = 0;
49 89b9b79f aliguori
50 89b9b79f aliguori
    if (p->len != 8)
51 89b9b79f aliguori
        return USB_RET_STALL;
52 89b9b79f aliguori
 
53 89b9b79f aliguori
    memcpy(s->setup_buf, p->data, 8);
54 89b9b79f aliguori
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
55 89b9b79f aliguori
    s->setup_index = 0;
56 89b9b79f aliguori
57 89b9b79f aliguori
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
58 89b9b79f aliguori
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
59 89b9b79f aliguori
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
60 89b9b79f aliguori
 
61 89b9b79f aliguori
    if (s->setup_buf[0] & USB_DIR_IN) {
62 89b9b79f aliguori
        ret = s->handle_control(s, request, value, index, 
63 89b9b79f aliguori
                                s->setup_len, s->data_buf);
64 89b9b79f aliguori
        if (ret < 0)
65 89b9b79f aliguori
            return ret;
66 89b9b79f aliguori
67 89b9b79f aliguori
        if (ret < s->setup_len)
68 89b9b79f aliguori
            s->setup_len = ret;
69 89b9b79f aliguori
        s->setup_state = SETUP_STATE_DATA;
70 89b9b79f aliguori
    } else {
71 89b9b79f aliguori
        if (s->setup_len == 0)
72 89b9b79f aliguori
            s->setup_state = SETUP_STATE_ACK;
73 89b9b79f aliguori
        else
74 89b9b79f aliguori
            s->setup_state = SETUP_STATE_DATA;
75 89b9b79f aliguori
    }
76 89b9b79f aliguori
77 89b9b79f aliguori
    return ret;
78 89b9b79f aliguori
}
79 89b9b79f aliguori
80 89b9b79f aliguori
static int do_token_in(USBDevice *s, USBPacket *p)
81 bb36d470 bellard
{
82 89b9b79f aliguori
    int request, value, index;
83 89b9b79f aliguori
    int ret = 0;
84 89b9b79f aliguori
85 89b9b79f aliguori
    if (p->devep != 0)
86 89b9b79f aliguori
        return s->handle_data(s, p);
87 89b9b79f aliguori
88 89b9b79f aliguori
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
89 89b9b79f aliguori
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
90 89b9b79f aliguori
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
91 89b9b79f aliguori
 
92 89b9b79f aliguori
    switch(s->setup_state) {
93 89b9b79f aliguori
    case SETUP_STATE_ACK:
94 89b9b79f aliguori
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
95 89b9b79f aliguori
            s->setup_state = SETUP_STATE_IDLE;
96 89b9b79f aliguori
            ret = s->handle_control(s, request, value, index,
97 89b9b79f aliguori
                                    s->setup_len, s->data_buf);
98 89b9b79f aliguori
            if (ret > 0)
99 89b9b79f aliguori
                return 0;
100 89b9b79f aliguori
            return ret;
101 89b9b79f aliguori
        }
102 89b9b79f aliguori
103 89b9b79f aliguori
        /* return 0 byte */
104 89b9b79f aliguori
        return 0;
105 89b9b79f aliguori
106 89b9b79f aliguori
    case SETUP_STATE_DATA:
107 89b9b79f aliguori
        if (s->setup_buf[0] & USB_DIR_IN) {
108 89b9b79f aliguori
            int len = s->setup_len - s->setup_index;
109 89b9b79f aliguori
            if (len > p->len)
110 89b9b79f aliguori
                len = p->len;
111 89b9b79f aliguori
            memcpy(p->data, s->data_buf + s->setup_index, len);
112 89b9b79f aliguori
            s->setup_index += len;
113 89b9b79f aliguori
            if (s->setup_index >= s->setup_len)
114 89b9b79f aliguori
                s->setup_state = SETUP_STATE_ACK;
115 89b9b79f aliguori
            return len;
116 89b9b79f aliguori
        }
117 89b9b79f aliguori
118 89b9b79f aliguori
        s->setup_state = SETUP_STATE_IDLE;
119 89b9b79f aliguori
        return USB_RET_STALL;
120 89b9b79f aliguori
121 89b9b79f aliguori
    default:
122 89b9b79f aliguori
        return USB_RET_STALL;
123 89b9b79f aliguori
    }
124 89b9b79f aliguori
}
125 89b9b79f aliguori
126 89b9b79f aliguori
static int do_token_out(USBDevice *s, USBPacket *p)
127 89b9b79f aliguori
{
128 89b9b79f aliguori
    if (p->devep != 0)
129 89b9b79f aliguori
        return s->handle_data(s, p);
130 89b9b79f aliguori
131 89b9b79f aliguori
    switch(s->setup_state) {
132 89b9b79f aliguori
    case SETUP_STATE_ACK:
133 89b9b79f aliguori
        if (s->setup_buf[0] & USB_DIR_IN) {
134 89b9b79f aliguori
            s->setup_state = SETUP_STATE_IDLE;
135 89b9b79f aliguori
            /* transfer OK */
136 89b9b79f aliguori
        } else {
137 89b9b79f aliguori
            /* ignore additional output */
138 89b9b79f aliguori
        }
139 89b9b79f aliguori
        return 0;
140 89b9b79f aliguori
141 89b9b79f aliguori
    case SETUP_STATE_DATA:
142 89b9b79f aliguori
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
143 89b9b79f aliguori
            int len = s->setup_len - s->setup_index;
144 89b9b79f aliguori
            if (len > p->len)
145 89b9b79f aliguori
                len = p->len;
146 89b9b79f aliguori
            memcpy(s->data_buf + s->setup_index, p->data, len);
147 89b9b79f aliguori
            s->setup_index += len;
148 89b9b79f aliguori
            if (s->setup_index >= s->setup_len)
149 89b9b79f aliguori
                s->setup_state = SETUP_STATE_ACK;
150 89b9b79f aliguori
            return len;
151 89b9b79f aliguori
        }
152 89b9b79f aliguori
153 89b9b79f aliguori
        s->setup_state = SETUP_STATE_IDLE;
154 89b9b79f aliguori
        return USB_RET_STALL;
155 89b9b79f aliguori
156 89b9b79f aliguori
    default:
157 89b9b79f aliguori
        return USB_RET_STALL;
158 89b9b79f aliguori
    }
159 89b9b79f aliguori
}
160 bb36d470 bellard
161 89b9b79f aliguori
/*
162 89b9b79f aliguori
 * Generic packet handler.
163 89b9b79f aliguori
 * Called by the HC (host controller).
164 89b9b79f aliguori
 *
165 89b9b79f aliguori
 * Returns length of the transaction or one of the USB_RET_XXX codes.
166 89b9b79f aliguori
 */
167 89b9b79f aliguori
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
168 89b9b79f aliguori
{
169 4d611c9a pbrook
    switch(p->pid) {
170 bb36d470 bellard
    case USB_MSG_ATTACH:
171 bb36d470 bellard
        s->state = USB_STATE_ATTACHED;
172 89b9b79f aliguori
        return 0;
173 89b9b79f aliguori
174 bb36d470 bellard
    case USB_MSG_DETACH:
175 bb36d470 bellard
        s->state = USB_STATE_NOTATTACHED;
176 89b9b79f aliguori
        return 0;
177 89b9b79f aliguori
178 bb36d470 bellard
    case USB_MSG_RESET:
179 bb36d470 bellard
        s->remote_wakeup = 0;
180 bb36d470 bellard
        s->addr = 0;
181 bb36d470 bellard
        s->state = USB_STATE_DEFAULT;
182 059809e4 bellard
        s->handle_reset(s);
183 89b9b79f aliguori
        return 0;
184 89b9b79f aliguori
    }
185 89b9b79f aliguori
186 89b9b79f aliguori
    /* Rest of the PIDs must match our address */
187 89b9b79f aliguori
    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
188 89b9b79f aliguori
        return USB_RET_NODEV;
189 89b9b79f aliguori
190 89b9b79f aliguori
    switch (p->pid) {
191 bb36d470 bellard
    case USB_TOKEN_SETUP:
192 89b9b79f aliguori
        return do_token_setup(s, p);
193 89b9b79f aliguori
194 bb36d470 bellard
    case USB_TOKEN_IN:
195 89b9b79f aliguori
        return do_token_in(s, p);
196 89b9b79f aliguori
197 bb36d470 bellard
    case USB_TOKEN_OUT:
198 89b9b79f aliguori
        return do_token_out(s, p);
199 89b9b79f aliguori
 
200 bb36d470 bellard
    default:
201 89b9b79f aliguori
        return USB_RET_STALL;
202 bb36d470 bellard
    }
203 bb36d470 bellard
}
204 bb36d470 bellard
205 bb36d470 bellard
/* XXX: fix overflow */
206 bb36d470 bellard
int set_usb_string(uint8_t *buf, const char *str)
207 bb36d470 bellard
{
208 bb36d470 bellard
    int len, i;
209 bb36d470 bellard
    uint8_t *q;
210 bb36d470 bellard
211 bb36d470 bellard
    q = buf;
212 bb36d470 bellard
    len = strlen(str);
213 ce5c37c2 pbrook
    *q++ = 2 * len + 2;
214 bb36d470 bellard
    *q++ = 3;
215 bb36d470 bellard
    for(i = 0; i < len; i++) {
216 bb36d470 bellard
        *q++ = str[i];
217 bb36d470 bellard
        *q++ = 0;
218 bb36d470 bellard
    }
219 bb36d470 bellard
    return q - buf;
220 bb36d470 bellard
}
221 4d611c9a pbrook
222 4d611c9a pbrook
/* Send an internal message to a USB device.  */
223 4d611c9a pbrook
void usb_send_msg(USBDevice *dev, int msg)
224 4d611c9a pbrook
{
225 4d611c9a pbrook
    USBPacket p;
226 4d611c9a pbrook
    memset(&p, 0, sizeof(p));
227 4d611c9a pbrook
    p.pid = msg;
228 4d611c9a pbrook
    dev->handle_packet(dev, &p);
229 4d611c9a pbrook
230 89b9b79f aliguori
    /* This _must_ be synchronous */
231 89b9b79f aliguori
}