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