hw/isa/Kconfig: Add missing dependency VIA VT82C686 -> APM
[qemu/ar7.git] / hw / usb / u2f.c
blob56001249a449a480eed7cf9c21108c1aea432cd7
1 /*
2 * U2F USB device.
4 * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5 * Written by César Belley <cesar.belley@lse.epita.fr>
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
26 #include "qemu/osdep.h"
27 #include "qemu/module.h"
28 #include "qapi/error.h"
29 #include "hw/usb.h"
30 #include "hw/usb/hid.h"
31 #include "migration/vmstate.h"
32 #include "desc.h"
34 #include "u2f.h"
36 /* U2F key Vendor / Product */
37 #define U2F_KEY_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
38 #define U2F_KEY_PRODUCT_NUM 0x0005
40 enum {
41 STR_MANUFACTURER = 1,
42 STR_PRODUCT,
43 STR_SERIALNUMBER,
44 STR_CONFIG,
45 STR_INTERFACE
48 static const USBDescStrings desc_strings = {
49 [STR_MANUFACTURER] = "QEMU",
50 [STR_PRODUCT] = "U2F USB key",
51 [STR_SERIALNUMBER] = "0",
52 [STR_CONFIG] = "U2F key config",
53 [STR_INTERFACE] = "U2F key interface"
56 static const USBDescIface desc_iface_u2f_key = {
57 .bInterfaceNumber = 0,
58 .bNumEndpoints = 2,
59 .bInterfaceClass = USB_CLASS_HID,
60 .bInterfaceSubClass = 0x0,
61 .bInterfaceProtocol = 0x0,
62 .ndesc = 1,
63 .descs = (USBDescOther[]) {
65 /* HID descriptor */
66 .data = (uint8_t[]) {
67 0x09, /* u8 bLength */
68 USB_DT_HID, /* u8 bDescriptorType */
69 0x10, 0x01, /* u16 HID_class */
70 0x00, /* u8 country_code */
71 0x01, /* u8 num_descriptors */
72 USB_DT_REPORT, /* u8 type: Report */
73 0x22, 0, /* u16 len */
77 .eps = (USBDescEndpoint[]) {
79 .bEndpointAddress = USB_DIR_IN | 0x01,
80 .bmAttributes = USB_ENDPOINT_XFER_INT,
81 .wMaxPacketSize = U2FHID_PACKET_SIZE,
82 .bInterval = 0x05,
83 }, {
84 .bEndpointAddress = USB_DIR_OUT | 0x01,
85 .bmAttributes = USB_ENDPOINT_XFER_INT,
86 .wMaxPacketSize = U2FHID_PACKET_SIZE,
87 .bInterval = 0x05,
93 static const USBDescDevice desc_device_u2f_key = {
94 .bcdUSB = 0x0100,
95 .bMaxPacketSize0 = U2FHID_PACKET_SIZE,
96 .bNumConfigurations = 1,
97 .confs = (USBDescConfig[]) {
99 .bNumInterfaces = 1,
100 .bConfigurationValue = 1,
101 .iConfiguration = STR_CONFIG,
102 .bmAttributes = USB_CFG_ATT_ONE,
103 .bMaxPower = 15,
104 .nif = 1,
105 .ifs = &desc_iface_u2f_key,
110 static const USBDesc desc_u2f_key = {
111 .id = {
112 .idVendor = U2F_KEY_VENDOR_NUM,
113 .idProduct = U2F_KEY_PRODUCT_NUM,
114 .bcdDevice = 0,
115 .iManufacturer = STR_MANUFACTURER,
116 .iProduct = STR_PRODUCT,
117 .iSerialNumber = STR_SERIALNUMBER,
119 .full = &desc_device_u2f_key,
120 .str = desc_strings,
123 static const uint8_t u2f_key_hid_report_desc[] = {
124 0x06, 0xd0, 0xf1, /* Usage Page (FIDO) */
125 0x09, 0x01, /* Usage (FIDO) */
126 0xa1, 0x01, /* Collection (HID Application) */
127 0x09, 0x20, /* Usage (FIDO data in) */
128 0x15, 0x00, /* Logical Minimum (0) */
129 0x26, 0xFF, 0x00, /* Logical Maximum (0xff) */
130 0x75, 0x08, /* Report Size (8) */
131 0x95, 0x40, /* Report Count (0x40) */
132 0x81, 0x02, /* Input (Data, Variable, Absolute) */
133 0x09, 0x21, /* Usage (FIDO data out) */
134 0x15, 0x00, /* Logical Minimum (0) */
135 0x26, 0xFF, 0x00, /* Logical Maximum (0xFF) */
136 0x75, 0x08, /* Report Size (8) */
137 0x95, 0x40, /* Report Count (0x40) */
138 0x91, 0x02, /* Output (Data, Variable, Absolute) */
139 0xC0 /* End Collection */
142 static void u2f_key_reset(U2FKeyState *key)
144 key->pending_in_start = 0;
145 key->pending_in_end = 0;
146 key->pending_in_num = 0;
149 static void u2f_key_handle_reset(USBDevice *dev)
151 U2FKeyState *key = U2F_KEY(dev);
153 u2f_key_reset(key);
156 static void u2f_key_handle_control(USBDevice *dev, USBPacket *p,
157 int request, int value, int index, int length, uint8_t *data)
159 U2FKeyState *key = U2F_KEY(dev);
160 int ret;
162 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
163 if (ret >= 0) {
164 return;
167 switch (request) {
168 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
169 switch (value >> 8) {
170 case 0x22:
171 memcpy(data, u2f_key_hid_report_desc,
172 sizeof(u2f_key_hid_report_desc));
173 p->actual_length = sizeof(u2f_key_hid_report_desc);
174 break;
175 default:
176 goto fail;
178 break;
179 case HID_GET_IDLE:
180 data[0] = key->idle;
181 p->actual_length = 1;
182 break;
183 case HID_SET_IDLE:
184 key->idle = (uint8_t)(value >> 8);
185 break;
186 default:
187 fail:
188 p->status = USB_RET_STALL;
189 break;
194 static void u2f_key_recv_from_guest(U2FKeyState *key, USBPacket *p)
196 U2FKeyClass *kc = U2F_KEY_GET_CLASS(key);
197 uint8_t packet[U2FHID_PACKET_SIZE];
199 if (kc->recv_from_guest == NULL || p->iov.size != U2FHID_PACKET_SIZE) {
200 return;
203 usb_packet_copy(p, packet, p->iov.size);
204 kc->recv_from_guest(key, packet);
207 static void u2f_pending_in_add(U2FKeyState *key,
208 const uint8_t packet[U2FHID_PACKET_SIZE])
210 uint8_t index;
212 if (key->pending_in_num >= U2FHID_PENDING_IN_NUM) {
213 return;
216 index = key->pending_in_end;
217 key->pending_in_end = (index + 1) % U2FHID_PENDING_IN_NUM;
218 ++key->pending_in_num;
220 memcpy(key->pending_in[index], packet, U2FHID_PACKET_SIZE);
223 static uint8_t *u2f_pending_in_get(U2FKeyState *key)
225 uint8_t index;
227 if (key->pending_in_num == 0) {
228 return NULL;
231 index = key->pending_in_start;
232 key->pending_in_start = (index + 1) % U2FHID_PENDING_IN_NUM;
233 --key->pending_in_num;
235 return key->pending_in[index];
238 static void u2f_key_handle_data(USBDevice *dev, USBPacket *p)
240 U2FKeyState *key = U2F_KEY(dev);
241 uint8_t *packet_in;
243 /* Endpoint number check */
244 if (p->ep->nr != 1) {
245 p->status = USB_RET_STALL;
246 return;
249 switch (p->pid) {
250 case USB_TOKEN_OUT:
251 u2f_key_recv_from_guest(key, p);
252 break;
253 case USB_TOKEN_IN:
254 packet_in = u2f_pending_in_get(key);
255 if (packet_in == NULL) {
256 p->status = USB_RET_NAK;
257 return;
259 usb_packet_copy(p, packet_in, U2FHID_PACKET_SIZE);
260 break;
261 default:
262 p->status = USB_RET_STALL;
263 break;
267 void u2f_send_to_guest(U2FKeyState *key,
268 const uint8_t packet[U2FHID_PACKET_SIZE])
270 u2f_pending_in_add(key, packet);
271 usb_wakeup(key->ep, 0);
274 static void u2f_key_unrealize(USBDevice *dev)
276 U2FKeyState *key = U2F_KEY(dev);
277 U2FKeyClass *kc = U2F_KEY_GET_CLASS(key);
279 if (kc->unrealize != NULL) {
280 kc->unrealize(key);
284 static void u2f_key_realize(USBDevice *dev, Error **errp)
286 U2FKeyState *key = U2F_KEY(dev);
287 U2FKeyClass *kc = U2F_KEY_GET_CLASS(key);
288 Error *local_err = NULL;
290 usb_desc_create_serial(dev);
291 usb_desc_init(dev);
292 u2f_key_reset(key);
294 if (kc->realize != NULL) {
295 kc->realize(key, &local_err);
296 if (local_err != NULL) {
297 error_propagate(errp, local_err);
298 return;
301 key->ep = usb_ep_get(dev, USB_TOKEN_IN, 1);
304 const VMStateDescription vmstate_u2f_key = {
305 .name = "u2f-key",
306 .version_id = 1,
307 .minimum_version_id = 1,
308 .fields = (VMStateField[]) {
309 VMSTATE_USB_DEVICE(dev, U2FKeyState),
310 VMSTATE_UINT8(idle, U2FKeyState),
311 VMSTATE_UINT8_2DARRAY(pending_in, U2FKeyState,
312 U2FHID_PENDING_IN_NUM, U2FHID_PACKET_SIZE),
313 VMSTATE_UINT8(pending_in_start, U2FKeyState),
314 VMSTATE_UINT8(pending_in_end, U2FKeyState),
315 VMSTATE_UINT8(pending_in_num, U2FKeyState),
316 VMSTATE_END_OF_LIST()
320 static void u2f_key_class_init(ObjectClass *klass, void *data)
322 DeviceClass *dc = DEVICE_CLASS(klass);
323 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
325 uc->product_desc = "QEMU U2F USB key";
326 uc->usb_desc = &desc_u2f_key;
327 uc->handle_reset = u2f_key_handle_reset;
328 uc->handle_control = u2f_key_handle_control;
329 uc->handle_data = u2f_key_handle_data;
330 uc->handle_attach = usb_desc_attach;
331 uc->realize = u2f_key_realize;
332 uc->unrealize = u2f_key_unrealize;
333 dc->desc = "QEMU U2F key";
334 dc->vmsd = &vmstate_u2f_key;
337 static const TypeInfo u2f_key_info = {
338 .name = TYPE_U2F_KEY,
339 .parent = TYPE_USB_DEVICE,
340 .instance_size = sizeof(U2FKeyState),
341 .abstract = true,
342 .class_size = sizeof(U2FKeyClass),
343 .class_init = u2f_key_class_init,
346 static void u2f_key_register_types(void)
348 type_register_static(&u2f_key_info);
351 type_init(u2f_key_register_types)