Statistics
| Branch: | Revision:

root / hw / usb.c @ bfa30a38

History | View | Annotate | Download (6.5 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 bb36d470 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 bb36d470 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 bb36d470 bellard
 * in the Software without restriction, including without limitation the rights
9 bb36d470 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 bb36d470 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 bb36d470 bellard
 * furnished to do so, subject to the following conditions:
12 bb36d470 bellard
 *
13 bb36d470 bellard
 * The above copyright notice and this permission notice shall be included in
14 bb36d470 bellard
 * all copies or substantial portions of the Software.
15 bb36d470 bellard
 *
16 bb36d470 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 bb36d470 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 bb36d470 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 bb36d470 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 bb36d470 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 bb36d470 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 bb36d470 bellard
 * THE SOFTWARE.
23 bb36d470 bellard
 */
24 bb36d470 bellard
#include "vl.h"
25 bb36d470 bellard
26 bb36d470 bellard
void usb_attach(USBPort *port, USBDevice *dev)
27 bb36d470 bellard
{
28 bb36d470 bellard
    port->attach(port, dev);
29 bb36d470 bellard
}
30 bb36d470 bellard
31 bb36d470 bellard
/**********************/
32 bb36d470 bellard
/* generic USB device helpers (you are not forced to use them when
33 bb36d470 bellard
   writing your USB device driver, but they help handling the
34 5fafdf24 ths
   protocol)
35 bb36d470 bellard
*/
36 bb36d470 bellard
37 bb36d470 bellard
#define SETUP_STATE_IDLE 0
38 bb36d470 bellard
#define SETUP_STATE_DATA 1
39 bb36d470 bellard
#define SETUP_STATE_ACK  2
40 bb36d470 bellard
41 4d611c9a pbrook
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
42 bb36d470 bellard
{
43 bb36d470 bellard
    int l, ret = 0;
44 4d611c9a pbrook
    int len = p->len;
45 4d611c9a pbrook
    uint8_t *data = p->data;
46 bb36d470 bellard
47 4d611c9a pbrook
    switch(p->pid) {
48 bb36d470 bellard
    case USB_MSG_ATTACH:
49 bb36d470 bellard
        s->state = USB_STATE_ATTACHED;
50 bb36d470 bellard
        break;
51 bb36d470 bellard
    case USB_MSG_DETACH:
52 bb36d470 bellard
        s->state = USB_STATE_NOTATTACHED;
53 bb36d470 bellard
        break;
54 bb36d470 bellard
    case USB_MSG_RESET:
55 bb36d470 bellard
        s->remote_wakeup = 0;
56 bb36d470 bellard
        s->addr = 0;
57 bb36d470 bellard
        s->state = USB_STATE_DEFAULT;
58 059809e4 bellard
        s->handle_reset(s);
59 bb36d470 bellard
        break;
60 bb36d470 bellard
    case USB_TOKEN_SETUP:
61 4d611c9a pbrook
        if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
62 bb36d470 bellard
            return USB_RET_NODEV;
63 bb36d470 bellard
        if (len != 8)
64 bb36d470 bellard
            goto fail;
65 bb36d470 bellard
        memcpy(s->setup_buf, data, 8);
66 bb36d470 bellard
        s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
67 bb36d470 bellard
        s->setup_index = 0;
68 bb36d470 bellard
        if (s->setup_buf[0] & USB_DIR_IN) {
69 5fafdf24 ths
            ret = s->handle_control(s,
70 bb36d470 bellard
                                    (s->setup_buf[0] << 8) | s->setup_buf[1],
71 bb36d470 bellard
                                    (s->setup_buf[3] << 8) | s->setup_buf[2],
72 bb36d470 bellard
                                    (s->setup_buf[5] << 8) | s->setup_buf[4],
73 bb36d470 bellard
                                    s->setup_len,
74 bb36d470 bellard
                                    s->data_buf);
75 bb36d470 bellard
            if (ret < 0)
76 bb36d470 bellard
                return ret;
77 bb36d470 bellard
            if (ret < s->setup_len)
78 bb36d470 bellard
                s->setup_len = ret;
79 bb36d470 bellard
            s->setup_state = SETUP_STATE_DATA;
80 bb36d470 bellard
        } else {
81 bb36d470 bellard
            if (s->setup_len == 0)
82 bb36d470 bellard
                s->setup_state = SETUP_STATE_ACK;
83 bb36d470 bellard
            else
84 bb36d470 bellard
                s->setup_state = SETUP_STATE_DATA;
85 bb36d470 bellard
        }
86 bb36d470 bellard
        break;
87 bb36d470 bellard
    case USB_TOKEN_IN:
88 4d611c9a pbrook
        if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
89 bb36d470 bellard
            return USB_RET_NODEV;
90 4d611c9a pbrook
        switch(p->devep) {
91 bb36d470 bellard
        case 0:
92 bb36d470 bellard
            switch(s->setup_state) {
93 bb36d470 bellard
            case SETUP_STATE_ACK:
94 bb36d470 bellard
                if (!(s->setup_buf[0] & USB_DIR_IN)) {
95 56bebe70 bellard
                    s->setup_state = SETUP_STATE_IDLE;
96 5fafdf24 ths
                    ret = s->handle_control(s,
97 bb36d470 bellard
                                      (s->setup_buf[0] << 8) | s->setup_buf[1],
98 bb36d470 bellard
                                      (s->setup_buf[3] << 8) | s->setup_buf[2],
99 bb36d470 bellard
                                      (s->setup_buf[5] << 8) | s->setup_buf[4],
100 bb36d470 bellard
                                      s->setup_len,
101 bb36d470 bellard
                                      s->data_buf);
102 bb36d470 bellard
                    if (ret > 0)
103 bb36d470 bellard
                        ret = 0;
104 bb36d470 bellard
                } else {
105 56bebe70 bellard
                    /* return 0 byte */
106 bb36d470 bellard
                }
107 bb36d470 bellard
                break;
108 bb36d470 bellard
            case SETUP_STATE_DATA:
109 bb36d470 bellard
                if (s->setup_buf[0] & USB_DIR_IN) {
110 bb36d470 bellard
                    l = s->setup_len - s->setup_index;
111 bb36d470 bellard
                    if (l > len)
112 bb36d470 bellard
                        l = len;
113 bb36d470 bellard
                    memcpy(data, s->data_buf + s->setup_index, l);
114 bb36d470 bellard
                    s->setup_index += l;
115 bb36d470 bellard
                    if (s->setup_index >= s->setup_len)
116 bb36d470 bellard
                        s->setup_state = SETUP_STATE_ACK;
117 bb36d470 bellard
                    ret = l;
118 bb36d470 bellard
                } else {
119 bb36d470 bellard
                    s->setup_state = SETUP_STATE_IDLE;
120 bb36d470 bellard
                    goto fail;
121 bb36d470 bellard
                }
122 bb36d470 bellard
                break;
123 bb36d470 bellard
            default:
124 bb36d470 bellard
                goto fail;
125 bb36d470 bellard
            }
126 bb36d470 bellard
            break;
127 bb36d470 bellard
        default:
128 4d611c9a pbrook
            ret = s->handle_data(s, p);
129 bb36d470 bellard
            break;
130 bb36d470 bellard
        }
131 bb36d470 bellard
        break;
132 bb36d470 bellard
    case USB_TOKEN_OUT:
133 4d611c9a pbrook
        if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
134 bb36d470 bellard
            return USB_RET_NODEV;
135 4d611c9a pbrook
        switch(p->devep) {
136 bb36d470 bellard
        case 0:
137 bb36d470 bellard
            switch(s->setup_state) {
138 bb36d470 bellard
            case SETUP_STATE_ACK:
139 bb36d470 bellard
                if (s->setup_buf[0] & USB_DIR_IN) {
140 56bebe70 bellard
                    s->setup_state = SETUP_STATE_IDLE;
141 bb36d470 bellard
                    /* transfer OK */
142 bb36d470 bellard
                } else {
143 aa1f17c1 ths
                    /* ignore additional output */
144 bb36d470 bellard
                }
145 bb36d470 bellard
                break;
146 bb36d470 bellard
            case SETUP_STATE_DATA:
147 bb36d470 bellard
                if (!(s->setup_buf[0] & USB_DIR_IN)) {
148 bb36d470 bellard
                    l = s->setup_len - s->setup_index;
149 bb36d470 bellard
                    if (l > len)
150 bb36d470 bellard
                        l = len;
151 bb36d470 bellard
                    memcpy(s->data_buf + s->setup_index, data, l);
152 bb36d470 bellard
                    s->setup_index += l;
153 bb36d470 bellard
                    if (s->setup_index >= s->setup_len)
154 bb36d470 bellard
                        s->setup_state = SETUP_STATE_ACK;
155 bb36d470 bellard
                    ret = l;
156 bb36d470 bellard
                } else {
157 bb36d470 bellard
                    s->setup_state = SETUP_STATE_IDLE;
158 bb36d470 bellard
                    goto fail;
159 bb36d470 bellard
                }
160 bb36d470 bellard
                break;
161 bb36d470 bellard
            default:
162 bb36d470 bellard
                goto fail;
163 bb36d470 bellard
            }
164 bb36d470 bellard
            break;
165 bb36d470 bellard
        default:
166 4d611c9a pbrook
            ret = s->handle_data(s, p);
167 bb36d470 bellard
            break;
168 bb36d470 bellard
        }
169 bb36d470 bellard
        break;
170 bb36d470 bellard
    default:
171 bb36d470 bellard
    fail:
172 bb36d470 bellard
        ret = USB_RET_STALL;
173 bb36d470 bellard
        break;
174 bb36d470 bellard
    }
175 bb36d470 bellard
    return ret;
176 bb36d470 bellard
}
177 bb36d470 bellard
178 bb36d470 bellard
/* XXX: fix overflow */
179 bb36d470 bellard
int set_usb_string(uint8_t *buf, const char *str)
180 bb36d470 bellard
{
181 bb36d470 bellard
    int len, i;
182 bb36d470 bellard
    uint8_t *q;
183 bb36d470 bellard
184 bb36d470 bellard
    q = buf;
185 bb36d470 bellard
    len = strlen(str);
186 ce5c37c2 pbrook
    *q++ = 2 * len + 2;
187 bb36d470 bellard
    *q++ = 3;
188 bb36d470 bellard
    for(i = 0; i < len; i++) {
189 bb36d470 bellard
        *q++ = str[i];
190 bb36d470 bellard
        *q++ = 0;
191 bb36d470 bellard
    }
192 bb36d470 bellard
    return q - buf;
193 bb36d470 bellard
}
194 4d611c9a pbrook
195 4d611c9a pbrook
/* Send an internal message to a USB device.  */
196 4d611c9a pbrook
void usb_send_msg(USBDevice *dev, int msg)
197 4d611c9a pbrook
{
198 4d611c9a pbrook
    USBPacket p;
199 4d611c9a pbrook
    memset(&p, 0, sizeof(p));
200 4d611c9a pbrook
    p.pid = msg;
201 4d611c9a pbrook
    dev->handle_packet(dev, &p);
202 4d611c9a pbrook
}