xref: /illumos-kvm-cmd/hw/usb.c (revision 68396ea9)
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 
usb_attach(USBPort * port,USBDevice * dev)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 
usb_wakeup(USBDevice * dev)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 
do_token_setup(USBDevice * s,USBPacket * p)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 
do_token_in(USBDevice * s,USBPacket * p)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 
do_token_out(USBDevice * s,USBPacket * p)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  */
usb_generic_handle_packet(USBDevice * s,USBPacket * p)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 */
set_usb_string(uint8_t * buf,const char * str)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.  */
usb_send_msg(USBDevice * dev,int msg)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 }
262