Statistics
| Branch: | Revision:

root / hw / usb.c @ 746d6de7

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 87ecb68b pbrook
#include "qemu-common.h"
25 87ecb68b pbrook
#include "usb.h"
26 bb36d470 bellard
27 bb36d470 bellard
void usb_attach(USBPort *port, USBDevice *dev)
28 bb36d470 bellard
{
29 bb36d470 bellard
    port->attach(port, dev);
30 bb36d470 bellard
}
31 bb36d470 bellard
32 bb36d470 bellard
/**********************/
33 bb36d470 bellard
/* generic USB device helpers (you are not forced to use them when
34 bb36d470 bellard
   writing your USB device driver, but they help handling the
35 5fafdf24 ths
   protocol)
36 bb36d470 bellard
*/
37 bb36d470 bellard
38 bb36d470 bellard
#define SETUP_STATE_IDLE 0
39 bb36d470 bellard
#define SETUP_STATE_DATA 1
40 bb36d470 bellard
#define SETUP_STATE_ACK  2
41 bb36d470 bellard
42 4d611c9a pbrook
int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
43 bb36d470 bellard
{
44 bb36d470 bellard
    int l, ret = 0;
45 4d611c9a pbrook
    int len = p->len;
46 4d611c9a pbrook
    uint8_t *data = p->data;
47 bb36d470 bellard
48 4d611c9a pbrook
    switch(p->pid) {
49 bb36d470 bellard
    case USB_MSG_ATTACH:
50 bb36d470 bellard
        s->state = USB_STATE_ATTACHED;
51 bb36d470 bellard
        break;
52 bb36d470 bellard
    case USB_MSG_DETACH:
53 bb36d470 bellard
        s->state = USB_STATE_NOTATTACHED;
54 bb36d470 bellard
        break;
55 bb36d470 bellard
    case USB_MSG_RESET:
56 bb36d470 bellard
        s->remote_wakeup = 0;
57 bb36d470 bellard
        s->addr = 0;
58 bb36d470 bellard
        s->state = USB_STATE_DEFAULT;
59 059809e4 bellard
        s->handle_reset(s);
60 bb36d470 bellard
        break;
61 bb36d470 bellard
    case USB_TOKEN_SETUP:
62 4d611c9a pbrook
        if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
63 bb36d470 bellard
            return USB_RET_NODEV;
64 bb36d470 bellard
        if (len != 8)
65 bb36d470 bellard
            goto fail;
66 bb36d470 bellard
        memcpy(s->setup_buf, data, 8);
67 bb36d470 bellard
        s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
68 bb36d470 bellard
        s->setup_index = 0;
69 bb36d470 bellard
        if (s->setup_buf[0] & USB_DIR_IN) {
70 5fafdf24 ths
            ret = s->handle_control(s,
71 bb36d470 bellard
                                    (s->setup_buf[0] << 8) | s->setup_buf[1],
72 bb36d470 bellard
                                    (s->setup_buf[3] << 8) | s->setup_buf[2],
73 bb36d470 bellard
                                    (s->setup_buf[5] << 8) | s->setup_buf[4],
74 bb36d470 bellard
                                    s->setup_len,
75 bb36d470 bellard
                                    s->data_buf);
76 bb36d470 bellard
            if (ret < 0)
77 bb36d470 bellard
                return ret;
78 bb36d470 bellard
            if (ret < s->setup_len)
79 bb36d470 bellard
                s->setup_len = ret;
80 bb36d470 bellard
            s->setup_state = SETUP_STATE_DATA;
81 bb36d470 bellard
        } else {
82 bb36d470 bellard
            if (s->setup_len == 0)
83 bb36d470 bellard
                s->setup_state = SETUP_STATE_ACK;
84 bb36d470 bellard
            else
85 bb36d470 bellard
                s->setup_state = SETUP_STATE_DATA;
86 bb36d470 bellard
        }
87 bb36d470 bellard
        break;
88 bb36d470 bellard
    case USB_TOKEN_IN:
89 4d611c9a pbrook
        if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
90 bb36d470 bellard
            return USB_RET_NODEV;
91 4d611c9a pbrook
        switch(p->devep) {
92 bb36d470 bellard
        case 0:
93 bb36d470 bellard
            switch(s->setup_state) {
94 bb36d470 bellard
            case SETUP_STATE_ACK:
95 bb36d470 bellard
                if (!(s->setup_buf[0] & USB_DIR_IN)) {
96 56bebe70 bellard
                    s->setup_state = SETUP_STATE_IDLE;
97 5fafdf24 ths
                    ret = s->handle_control(s,
98 bb36d470 bellard
                                      (s->setup_buf[0] << 8) | s->setup_buf[1],
99 bb36d470 bellard
                                      (s->setup_buf[3] << 8) | s->setup_buf[2],
100 bb36d470 bellard
                                      (s->setup_buf[5] << 8) | s->setup_buf[4],
101 bb36d470 bellard
                                      s->setup_len,
102 bb36d470 bellard
                                      s->data_buf);
103 bb36d470 bellard
                    if (ret > 0)
104 bb36d470 bellard
                        ret = 0;
105 bb36d470 bellard
                } else {
106 56bebe70 bellard
                    /* return 0 byte */
107 bb36d470 bellard
                }
108 bb36d470 bellard
                break;
109 bb36d470 bellard
            case SETUP_STATE_DATA:
110 bb36d470 bellard
                if (s->setup_buf[0] & USB_DIR_IN) {
111 bb36d470 bellard
                    l = s->setup_len - s->setup_index;
112 bb36d470 bellard
                    if (l > len)
113 bb36d470 bellard
                        l = len;
114 bb36d470 bellard
                    memcpy(data, s->data_buf + s->setup_index, l);
115 bb36d470 bellard
                    s->setup_index += l;
116 bb36d470 bellard
                    if (s->setup_index >= s->setup_len)
117 bb36d470 bellard
                        s->setup_state = SETUP_STATE_ACK;
118 bb36d470 bellard
                    ret = l;
119 bb36d470 bellard
                } else {
120 bb36d470 bellard
                    s->setup_state = SETUP_STATE_IDLE;
121 bb36d470 bellard
                    goto fail;
122 bb36d470 bellard
                }
123 bb36d470 bellard
                break;
124 bb36d470 bellard
            default:
125 bb36d470 bellard
                goto fail;
126 bb36d470 bellard
            }
127 bb36d470 bellard
            break;
128 bb36d470 bellard
        default:
129 4d611c9a pbrook
            ret = s->handle_data(s, p);
130 bb36d470 bellard
            break;
131 bb36d470 bellard
        }
132 bb36d470 bellard
        break;
133 bb36d470 bellard
    case USB_TOKEN_OUT:
134 4d611c9a pbrook
        if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
135 bb36d470 bellard
            return USB_RET_NODEV;
136 4d611c9a pbrook
        switch(p->devep) {
137 bb36d470 bellard
        case 0:
138 bb36d470 bellard
            switch(s->setup_state) {
139 bb36d470 bellard
            case SETUP_STATE_ACK:
140 bb36d470 bellard
                if (s->setup_buf[0] & USB_DIR_IN) {
141 56bebe70 bellard
                    s->setup_state = SETUP_STATE_IDLE;
142 bb36d470 bellard
                    /* transfer OK */
143 bb36d470 bellard
                } else {
144 aa1f17c1 ths
                    /* ignore additional output */
145 bb36d470 bellard
                }
146 bb36d470 bellard
                break;
147 bb36d470 bellard
            case SETUP_STATE_DATA:
148 bb36d470 bellard
                if (!(s->setup_buf[0] & USB_DIR_IN)) {
149 bb36d470 bellard
                    l = s->setup_len - s->setup_index;
150 bb36d470 bellard
                    if (l > len)
151 bb36d470 bellard
                        l = len;
152 bb36d470 bellard
                    memcpy(s->data_buf + s->setup_index, data, l);
153 bb36d470 bellard
                    s->setup_index += l;
154 bb36d470 bellard
                    if (s->setup_index >= s->setup_len)
155 bb36d470 bellard
                        s->setup_state = SETUP_STATE_ACK;
156 bb36d470 bellard
                    ret = l;
157 bb36d470 bellard
                } else {
158 bb36d470 bellard
                    s->setup_state = SETUP_STATE_IDLE;
159 bb36d470 bellard
                    goto fail;
160 bb36d470 bellard
                }
161 bb36d470 bellard
                break;
162 bb36d470 bellard
            default:
163 bb36d470 bellard
                goto fail;
164 bb36d470 bellard
            }
165 bb36d470 bellard
            break;
166 bb36d470 bellard
        default:
167 4d611c9a pbrook
            ret = s->handle_data(s, p);
168 bb36d470 bellard
            break;
169 bb36d470 bellard
        }
170 bb36d470 bellard
        break;
171 bb36d470 bellard
    default:
172 bb36d470 bellard
    fail:
173 bb36d470 bellard
        ret = USB_RET_STALL;
174 bb36d470 bellard
        break;
175 bb36d470 bellard
    }
176 bb36d470 bellard
    return ret;
177 bb36d470 bellard
}
178 bb36d470 bellard
179 bb36d470 bellard
/* XXX: fix overflow */
180 bb36d470 bellard
int set_usb_string(uint8_t *buf, const char *str)
181 bb36d470 bellard
{
182 bb36d470 bellard
    int len, i;
183 bb36d470 bellard
    uint8_t *q;
184 bb36d470 bellard
185 bb36d470 bellard
    q = buf;
186 bb36d470 bellard
    len = strlen(str);
187 ce5c37c2 pbrook
    *q++ = 2 * len + 2;
188 bb36d470 bellard
    *q++ = 3;
189 bb36d470 bellard
    for(i = 0; i < len; i++) {
190 bb36d470 bellard
        *q++ = str[i];
191 bb36d470 bellard
        *q++ = 0;
192 bb36d470 bellard
    }
193 bb36d470 bellard
    return q - buf;
194 bb36d470 bellard
}
195 4d611c9a pbrook
196 4d611c9a pbrook
/* Send an internal message to a USB device.  */
197 4d611c9a pbrook
void usb_send_msg(USBDevice *dev, int msg)
198 4d611c9a pbrook
{
199 4d611c9a pbrook
    USBPacket p;
200 4d611c9a pbrook
    memset(&p, 0, sizeof(p));
201 4d611c9a pbrook
    p.pid = msg;
202 4d611c9a pbrook
    dev->handle_packet(dev, &p);
203 4d611c9a pbrook
}