Statistics
| Branch: | Revision:

root / hw / usb.c @ 1a1ea6f0

History | View | Annotate | Download (6.1 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
    port->attach(port, dev);
32
}
33

    
34
/**********************/
35

    
36
/* generic USB device helpers (you are not forced to use them when
37
   writing your USB device driver, but they help handling the
38
   protocol)
39
*/
40

    
41
#define SETUP_STATE_IDLE 0
42
#define SETUP_STATE_DATA 1
43
#define SETUP_STATE_ACK  2
44

    
45
static int do_token_setup(USBDevice *s, USBPacket *p)
46
{
47
    int request, value, index;
48
    int ret = 0;
49

    
50
    if (p->len != 8)
51
        return USB_RET_STALL;
52
 
53
    memcpy(s->setup_buf, p->data, 8);
54
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
55
    s->setup_index = 0;
56

    
57
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
58
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
59
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
60
 
61
    if (s->setup_buf[0] & USB_DIR_IN) {
62
        ret = s->info->handle_control(s, request, value, index, 
63
                                      s->setup_len, s->data_buf);
64
        if (ret < 0)
65
            return ret;
66

    
67
        if (ret < s->setup_len)
68
            s->setup_len = ret;
69
        s->setup_state = SETUP_STATE_DATA;
70
    } else {
71
        if (s->setup_len == 0)
72
            s->setup_state = SETUP_STATE_ACK;
73
        else
74
            s->setup_state = SETUP_STATE_DATA;
75
    }
76

    
77
    return ret;
78
}
79

    
80
static int do_token_in(USBDevice *s, USBPacket *p)
81
{
82
    int request, value, index;
83
    int ret = 0;
84

    
85
    if (p->devep != 0)
86
        return s->info->handle_data(s, p);
87

    
88
    request = (s->setup_buf[0] << 8) | s->setup_buf[1];
89
    value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
90
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];
91
 
92
    switch(s->setup_state) {
93
    case SETUP_STATE_ACK:
94
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
95
            s->setup_state = SETUP_STATE_IDLE;
96
            ret = s->info->handle_control(s, request, value, index,
97
                                          s->setup_len, s->data_buf);
98
            if (ret > 0)
99
                return 0;
100
            return ret;
101
        }
102

    
103
        /* return 0 byte */
104
        return 0;
105

    
106
    case SETUP_STATE_DATA:
107
        if (s->setup_buf[0] & USB_DIR_IN) {
108
            int len = s->setup_len - s->setup_index;
109
            if (len > p->len)
110
                len = p->len;
111
            memcpy(p->data, s->data_buf + s->setup_index, len);
112
            s->setup_index += len;
113
            if (s->setup_index >= s->setup_len)
114
                s->setup_state = SETUP_STATE_ACK;
115
            return len;
116
        }
117

    
118
        s->setup_state = SETUP_STATE_IDLE;
119
        return USB_RET_STALL;
120

    
121
    default:
122
        return USB_RET_STALL;
123
    }
124
}
125

    
126
static int do_token_out(USBDevice *s, USBPacket *p)
127
{
128
    if (p->devep != 0)
129
        return s->info->handle_data(s, p);
130

    
131
    switch(s->setup_state) {
132
    case SETUP_STATE_ACK:
133
        if (s->setup_buf[0] & USB_DIR_IN) {
134
            s->setup_state = SETUP_STATE_IDLE;
135
            /* transfer OK */
136
        } else {
137
            /* ignore additional output */
138
        }
139
        return 0;
140

    
141
    case SETUP_STATE_DATA:
142
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
143
            int len = s->setup_len - s->setup_index;
144
            if (len > p->len)
145
                len = p->len;
146
            memcpy(s->data_buf + s->setup_index, p->data, len);
147
            s->setup_index += len;
148
            if (s->setup_index >= s->setup_len)
149
                s->setup_state = SETUP_STATE_ACK;
150
            return len;
151
        }
152

    
153
        s->setup_state = SETUP_STATE_IDLE;
154
        return USB_RET_STALL;
155

    
156
    default:
157
        return USB_RET_STALL;
158
    }
159
}
160

    
161
/*
162
 * Generic packet handler.
163
 * Called by the HC (host controller).
164
 *
165
 * Returns length of the transaction or one of the USB_RET_XXX codes.
166
 */
167
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
168
{
169
    switch(p->pid) {
170
    case USB_MSG_ATTACH:
171
        s->state = USB_STATE_ATTACHED;
172
        return 0;
173

    
174
    case USB_MSG_DETACH:
175
        s->state = USB_STATE_NOTATTACHED;
176
        return 0;
177

    
178
    case USB_MSG_RESET:
179
        s->remote_wakeup = 0;
180
        s->addr = 0;
181
        s->state = USB_STATE_DEFAULT;
182
        s->info->handle_reset(s);
183
        return 0;
184
    }
185

    
186
    /* Rest of the PIDs must match our address */
187
    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
188
        return USB_RET_NODEV;
189

    
190
    switch (p->pid) {
191
    case USB_TOKEN_SETUP:
192
        return do_token_setup(s, p);
193

    
194
    case USB_TOKEN_IN:
195
        return do_token_in(s, p);
196

    
197
    case USB_TOKEN_OUT:
198
        return do_token_out(s, p);
199
 
200
    default:
201
        return USB_RET_STALL;
202
    }
203
}
204

    
205
/* XXX: fix overflow */
206
int set_usb_string(uint8_t *buf, const char *str)
207
{
208
    int len, i;
209
    uint8_t *q;
210

    
211
    q = buf;
212
    len = strlen(str);
213
    *q++ = 2 * len + 2;
214
    *q++ = 3;
215
    for(i = 0; i < len; i++) {
216
        *q++ = str[i];
217
        *q++ = 0;
218
    }
219
    return q - buf;
220
}
221

    
222
/* Send an internal message to a USB device.  */
223
void usb_send_msg(USBDevice *dev, int msg)
224
{
225
    USBPacket p;
226
    memset(&p, 0, sizeof(p));
227
    p.pid = msg;
228
    dev->info->handle_packet(dev, &p);
229

    
230
    /* This _must_ be synchronous */
231
}