Statistics
| Branch: | Revision:

root / hw / usb.c @ 231f5f43

History | View | Annotate | Download (6.8 kB)

1
/*
2
 * QEMU USB emulation
3
 *
4
 * Copyright (c) 2005 Fabrice Bellard
5
 *
6
 * 2008 Generic packet handler rewrite by Max Krasnyansky
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
#include "qemu-common.h"
27
#include "usb.h"
28

    
29
void usb_attach(USBPort *port, USBDevice *dev)
30
{
31
    if (dev != NULL) {
32
        /* attach */
33
        if (port->dev) {
34
            usb_attach(port, NULL);
35
        }
36
        dev->port = port;
37
        port->dev = dev;
38
        port->ops->attach(port);
39
        usb_send_msg(dev, USB_MSG_ATTACH);
40
    } else {
41
        /* detach */
42
        dev = port->dev;
43
        port->ops->detach(port);
44
        if (dev) {
45
            usb_send_msg(dev, USB_MSG_DETACH);
46
            dev->port = NULL;
47
            port->dev = NULL;
48
        }
49
    }
50
}
51

    
52
void usb_wakeup(USBDevice *dev)
53
{
54
    if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
55
        dev->port->ops->wakeup(dev);
56
    }
57
}
58

    
59
/**********************/
60

    
61
/* generic USB device helpers (you are not forced to use them when
62
   writing your USB device driver, but they help handling the
63
   protocol)
64
*/
65

    
66
#define SETUP_STATE_IDLE 0
67
#define SETUP_STATE_DATA 1
68
#define SETUP_STATE_ACK  2
69

    
70
static int do_token_setup(USBDevice *s, USBPacket *p)
71
{
72
    int request, value, index;
73
    int ret = 0;
74

    
75
    if (p->len != 8)
76
        return USB_RET_STALL;
77
 
78
    memcpy(s->setup_buf, p->data, 8);
79
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
80
    s->setup_index = 0;
81

    
82
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
83
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
84
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
85
 
86
    if (s->setup_buf[0] & USB_DIR_IN) {
87
        ret = s->info->handle_control(s, request, value, index, 
88
                                      s->setup_len, s->data_buf);
89
        if (ret < 0)
90
            return ret;
91

    
92
        if (ret < s->setup_len)
93
            s->setup_len = ret;
94
        s->setup_state = SETUP_STATE_DATA;
95
    } else {
96
        if (s->setup_len == 0)
97
            s->setup_state = SETUP_STATE_ACK;
98
        else
99
            s->setup_state = SETUP_STATE_DATA;
100
    }
101

    
102
    return ret;
103
}
104

    
105
static int do_token_in(USBDevice *s, USBPacket *p)
106
{
107
    int request, value, index;
108
    int ret = 0;
109

    
110
    if (p->devep != 0)
111
        return s->info->handle_data(s, p);
112

    
113
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
114
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
115
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
116
 
117
    switch(s->setup_state) {
118
    case SETUP_STATE_ACK:
119
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
120
            s->setup_state = SETUP_STATE_IDLE;
121
            ret = s->info->handle_control(s, request, value, index,
122
                                          s->setup_len, s->data_buf);
123
            if (ret > 0)
124
                return 0;
125
            return ret;
126
        }
127

    
128
        /* return 0 byte */
129
        return 0;
130

    
131
    case SETUP_STATE_DATA:
132
        if (s->setup_buf[0] & USB_DIR_IN) {
133
            int len = s->setup_len - s->setup_index;
134
            if (len > p->len)
135
                len = p->len;
136
            memcpy(p->data, s->data_buf + s->setup_index, len);
137
            s->setup_index += len;
138
            if (s->setup_index >= s->setup_len)
139
                s->setup_state = SETUP_STATE_ACK;
140
            return len;
141
        }
142

    
143
        s->setup_state = SETUP_STATE_IDLE;
144
        return USB_RET_STALL;
145

    
146
    default:
147
        return USB_RET_STALL;
148
    }
149
}
150

    
151
static int do_token_out(USBDevice *s, USBPacket *p)
152
{
153
    if (p->devep != 0)
154
        return s->info->handle_data(s, p);
155

    
156
    switch(s->setup_state) {
157
    case SETUP_STATE_ACK:
158
        if (s->setup_buf[0] & USB_DIR_IN) {
159
            s->setup_state = SETUP_STATE_IDLE;
160
            /* transfer OK */
161
        } else {
162
            /* ignore additional output */
163
        }
164
        return 0;
165

    
166
    case SETUP_STATE_DATA:
167
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
168
            int len = s->setup_len - s->setup_index;
169
            if (len > p->len)
170
                len = p->len;
171
            memcpy(s->data_buf + s->setup_index, p->data, len);
172
            s->setup_index += len;
173
            if (s->setup_index >= s->setup_len)
174
                s->setup_state = SETUP_STATE_ACK;
175
            return len;
176
        }
177

    
178
        s->setup_state = SETUP_STATE_IDLE;
179
        return USB_RET_STALL;
180

    
181
    default:
182
        return USB_RET_STALL;
183
    }
184
}
185

    
186
/*
187
 * Generic packet handler.
188
 * Called by the HC (host controller).
189
 *
190
 * Returns length of the transaction or one of the USB_RET_XXX codes.
191
 */
192
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
193
{
194
    switch(p->pid) {
195
    case USB_MSG_ATTACH:
196
        s->state = USB_STATE_ATTACHED;
197
        if (s->info->handle_attach) {
198
            s->info->handle_attach(s);
199
        }
200
        return 0;
201

    
202
    case USB_MSG_DETACH:
203
        s->state = USB_STATE_NOTATTACHED;
204
        return 0;
205

    
206
    case USB_MSG_RESET:
207
        s->remote_wakeup = 0;
208
        s->addr = 0;
209
        s->state = USB_STATE_DEFAULT;
210
        if (s->info->handle_reset) {
211
            s->info->handle_reset(s);
212
        }
213
        return 0;
214
    }
215

    
216
    /* Rest of the PIDs must match our address */
217
    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
218
        return USB_RET_NODEV;
219

    
220
    switch (p->pid) {
221
    case USB_TOKEN_SETUP:
222
        return do_token_setup(s, p);
223

    
224
    case USB_TOKEN_IN:
225
        return do_token_in(s, p);
226

    
227
    case USB_TOKEN_OUT:
228
        return do_token_out(s, p);
229
 
230
    default:
231
        return USB_RET_STALL;
232
    }
233
}
234

    
235
/* XXX: fix overflow */
236
int set_usb_string(uint8_t *buf, const char *str)
237
{
238
    int len, i;
239
    uint8_t *q;
240

    
241
    q = buf;
242
    len = strlen(str);
243
    *q++ = 2 * len + 2;
244
    *q++ = 3;
245
    for(i = 0; i < len; i++) {
246
        *q++ = str[i];
247
        *q++ = 0;
248
    }
249
    return q - buf;
250
}
251

    
252
/* Send an internal message to a USB device.  */
253
void usb_send_msg(USBDevice *dev, int msg)
254
{
255
    USBPacket p;
256
    memset(&p, 0, sizeof(p));
257
    p.pid = msg;
258
    dev->info->handle_packet(dev, &p);
259

    
260
    /* This _must_ be synchronous */
261
}