xref: /openbmc/qemu/hw/usb/dev-serial.c (revision 59a3a1c0)
1 /*
2  * FTDI FT232BM Device emulation
3  *
4  * Copyright (c) 2006 CodeSourcery.
5  * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
6  * Written by Paul Brook, reused for FTDI by Samuel Thibault
7  *
8  * This code is licensed under the LGPL.
9  */
10 
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "qemu/cutils.h"
14 #include "qemu/error-report.h"
15 #include "qemu/module.h"
16 #include "hw/qdev-properties.h"
17 #include "hw/usb.h"
18 #include "migration/vmstate.h"
19 #include "desc.h"
20 #include "chardev/char-serial.h"
21 #include "chardev/char-fe.h"
22 
23 //#define DEBUG_Serial
24 
25 #ifdef DEBUG_Serial
26 #define DPRINTF(fmt, ...) \
27 do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
28 #else
29 #define DPRINTF(fmt, ...) do {} while(0)
30 #endif
31 
32 #define RECV_BUF 384
33 
34 /* Commands */
35 #define FTDI_RESET		0
36 #define FTDI_SET_MDM_CTRL	1
37 #define FTDI_SET_FLOW_CTRL	2
38 #define FTDI_SET_BAUD		3
39 #define FTDI_SET_DATA		4
40 #define FTDI_GET_MDM_ST		5
41 #define FTDI_SET_EVENT_CHR	6
42 #define FTDI_SET_ERROR_CHR	7
43 #define FTDI_SET_LATENCY	9
44 #define FTDI_GET_LATENCY	10
45 
46 #define DeviceOutVendor	((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
47 #define DeviceInVendor	((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
48 
49 /* RESET */
50 
51 #define FTDI_RESET_SIO	0
52 #define FTDI_RESET_RX	1
53 #define FTDI_RESET_TX	2
54 
55 /* SET_MDM_CTRL */
56 
57 #define FTDI_DTR	1
58 #define FTDI_SET_DTR	(FTDI_DTR << 8)
59 #define FTDI_RTS	2
60 #define FTDI_SET_RTS	(FTDI_RTS << 8)
61 
62 /* SET_FLOW_CTRL */
63 
64 #define FTDI_RTS_CTS_HS		1
65 #define FTDI_DTR_DSR_HS		2
66 #define FTDI_XON_XOFF_HS	4
67 
68 /* SET_DATA */
69 
70 #define FTDI_PARITY	(0x7 << 8)
71 #define FTDI_ODD	(0x1 << 8)
72 #define FTDI_EVEN	(0x2 << 8)
73 #define FTDI_MARK	(0x3 << 8)
74 #define FTDI_SPACE	(0x4 << 8)
75 
76 #define FTDI_STOP	(0x3 << 11)
77 #define FTDI_STOP1	(0x0 << 11)
78 #define FTDI_STOP15	(0x1 << 11)
79 #define FTDI_STOP2	(0x2 << 11)
80 
81 /* GET_MDM_ST */
82 /* TODO: should be sent every 40ms */
83 #define FTDI_CTS  (1<<4)        // CTS line status
84 #define FTDI_DSR  (1<<5)        // DSR line status
85 #define FTDI_RI   (1<<6)        // RI line status
86 #define FTDI_RLSD (1<<7)        // Receive Line Signal Detect
87 
88 /* Status */
89 
90 #define FTDI_DR   (1<<0)        // Data Ready
91 #define FTDI_OE   (1<<1)        // Overrun Err
92 #define FTDI_PE   (1<<2)        // Parity Err
93 #define FTDI_FE   (1<<3)        // Framing Err
94 #define FTDI_BI   (1<<4)        // Break Interrupt
95 #define FTDI_THRE (1<<5)        // Transmitter Holding Register
96 #define FTDI_TEMT (1<<6)        // Transmitter Empty
97 #define FTDI_FIFO (1<<7)        // Error in FIFO
98 
99 typedef struct {
100     USBDevice dev;
101     uint8_t recv_buf[RECV_BUF];
102     uint16_t recv_ptr;
103     uint16_t recv_used;
104     uint8_t event_chr;
105     uint8_t error_chr;
106     uint8_t event_trigger;
107     QEMUSerialSetParams params;
108     int latency;        /* ms */
109     CharBackend cs;
110 } USBSerialState;
111 
112 #define TYPE_USB_SERIAL "usb-serial-dev"
113 #define USB_SERIAL_DEV(obj) OBJECT_CHECK(USBSerialState, (obj), TYPE_USB_SERIAL)
114 
115 enum {
116     STR_MANUFACTURER = 1,
117     STR_PRODUCT_SERIAL,
118     STR_PRODUCT_BRAILLE,
119     STR_SERIALNUMBER,
120 };
121 
122 static const USBDescStrings desc_strings = {
123     [STR_MANUFACTURER]    = "QEMU",
124     [STR_PRODUCT_SERIAL]  = "QEMU USB SERIAL",
125     [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
126     [STR_SERIALNUMBER]    = "1",
127 };
128 
129 static const USBDescIface desc_iface0 = {
130     .bInterfaceNumber              = 0,
131     .bNumEndpoints                 = 2,
132     .bInterfaceClass               = 0xff,
133     .bInterfaceSubClass            = 0xff,
134     .bInterfaceProtocol            = 0xff,
135     .eps = (USBDescEndpoint[]) {
136         {
137             .bEndpointAddress      = USB_DIR_IN | 0x01,
138             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
139             .wMaxPacketSize        = 64,
140         },{
141             .bEndpointAddress      = USB_DIR_OUT | 0x02,
142             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
143             .wMaxPacketSize        = 64,
144         },
145     }
146 };
147 
148 static const USBDescDevice desc_device = {
149     .bcdUSB                        = 0x0200,
150     .bMaxPacketSize0               = 8,
151     .bNumConfigurations            = 1,
152     .confs = (USBDescConfig[]) {
153         {
154             .bNumInterfaces        = 1,
155             .bConfigurationValue   = 1,
156             .bmAttributes          = USB_CFG_ATT_ONE,
157             .bMaxPower             = 50,
158             .nif = 1,
159             .ifs = &desc_iface0,
160         },
161     },
162 };
163 
164 static const USBDesc desc_serial = {
165     .id = {
166         .idVendor          = 0x0403,
167         .idProduct         = 0x6001,
168         .bcdDevice         = 0x0400,
169         .iManufacturer     = STR_MANUFACTURER,
170         .iProduct          = STR_PRODUCT_SERIAL,
171         .iSerialNumber     = STR_SERIALNUMBER,
172     },
173     .full = &desc_device,
174     .str  = desc_strings,
175 };
176 
177 static const USBDesc desc_braille = {
178     .id = {
179         .idVendor          = 0x0403,
180         .idProduct         = 0xfe72,
181         .bcdDevice         = 0x0400,
182         .iManufacturer     = STR_MANUFACTURER,
183         .iProduct          = STR_PRODUCT_BRAILLE,
184         .iSerialNumber     = STR_SERIALNUMBER,
185     },
186     .full = &desc_device,
187     .str  = desc_strings,
188 };
189 
190 static void usb_serial_reset(USBSerialState *s)
191 {
192     /* TODO: Set flow control to none */
193     s->event_chr = 0x0d;
194     s->event_trigger = 0;
195     s->recv_ptr = 0;
196     s->recv_used = 0;
197     /* TODO: purge in char driver */
198 }
199 
200 static void usb_serial_handle_reset(USBDevice *dev)
201 {
202     USBSerialState *s = (USBSerialState *)dev;
203 
204     DPRINTF("Reset\n");
205 
206     usb_serial_reset(s);
207     /* TODO: Reset char device, send BREAK? */
208 }
209 
210 static uint8_t usb_get_modem_lines(USBSerialState *s)
211 {
212     int flags;
213     uint8_t ret;
214 
215     if (qemu_chr_fe_ioctl(&s->cs,
216                           CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
217         return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
218     }
219 
220     ret = 0;
221     if (flags & CHR_TIOCM_CTS)
222         ret |= FTDI_CTS;
223     if (flags & CHR_TIOCM_DSR)
224         ret |= FTDI_DSR;
225     if (flags & CHR_TIOCM_RI)
226         ret |= FTDI_RI;
227     if (flags & CHR_TIOCM_CAR)
228         ret |= FTDI_RLSD;
229 
230     return ret;
231 }
232 
233 static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
234                int request, int value, int index, int length, uint8_t *data)
235 {
236     USBSerialState *s = (USBSerialState *)dev;
237     int ret;
238 
239     DPRINTF("got control %x, value %x\n",request, value);
240     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
241     if (ret >= 0) {
242         return;
243     }
244 
245     switch (request) {
246     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
247         break;
248 
249         /* Class specific requests.  */
250     case DeviceOutVendor | FTDI_RESET:
251         switch (value) {
252         case FTDI_RESET_SIO:
253             usb_serial_reset(s);
254             break;
255         case FTDI_RESET_RX:
256             s->recv_ptr = 0;
257             s->recv_used = 0;
258             /* TODO: purge from char device */
259             break;
260         case FTDI_RESET_TX:
261             /* TODO: purge from char device */
262             break;
263         }
264         break;
265     case DeviceOutVendor | FTDI_SET_MDM_CTRL:
266     {
267         static int flags;
268         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
269         if (value & FTDI_SET_RTS) {
270             if (value & FTDI_RTS)
271                 flags |= CHR_TIOCM_RTS;
272             else
273                 flags &= ~CHR_TIOCM_RTS;
274         }
275         if (value & FTDI_SET_DTR) {
276             if (value & FTDI_DTR)
277                 flags |= CHR_TIOCM_DTR;
278             else
279                 flags &= ~CHR_TIOCM_DTR;
280         }
281         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
282         break;
283     }
284     case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
285         /* TODO: ioctl */
286         break;
287     case DeviceOutVendor | FTDI_SET_BAUD: {
288         static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
289         int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
290                                      | ((index & 1) << 2)];
291         int divisor = value & 0x3fff;
292 
293         /* chip special cases */
294         if (divisor == 1 && subdivisor8 == 0)
295             subdivisor8 = 4;
296         if (divisor == 0 && subdivisor8 == 0)
297             divisor = 1;
298 
299         s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
300         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
301         break;
302     }
303     case DeviceOutVendor | FTDI_SET_DATA:
304         switch (value & FTDI_PARITY) {
305             case 0:
306                 s->params.parity = 'N';
307                 break;
308             case FTDI_ODD:
309                 s->params.parity = 'O';
310                 break;
311             case FTDI_EVEN:
312                 s->params.parity = 'E';
313                 break;
314             default:
315                 DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
316                 goto fail;
317         }
318         switch (value & FTDI_STOP) {
319             case FTDI_STOP1:
320                 s->params.stop_bits = 1;
321                 break;
322             case FTDI_STOP2:
323                 s->params.stop_bits = 2;
324                 break;
325             default:
326                 DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
327                 goto fail;
328         }
329         qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
330         /* TODO: TX ON/OFF */
331         break;
332     case DeviceInVendor | FTDI_GET_MDM_ST:
333         data[0] = usb_get_modem_lines(s) | 1;
334         data[1] = 0;
335         p->actual_length = 2;
336         break;
337     case DeviceOutVendor | FTDI_SET_EVENT_CHR:
338         /* TODO: handle it */
339         s->event_chr = value;
340         break;
341     case DeviceOutVendor | FTDI_SET_ERROR_CHR:
342         /* TODO: handle it */
343         s->error_chr = value;
344         break;
345     case DeviceOutVendor | FTDI_SET_LATENCY:
346         s->latency = value;
347         break;
348     case DeviceInVendor | FTDI_GET_LATENCY:
349         data[0] = s->latency;
350         p->actual_length = 1;
351         break;
352     default:
353     fail:
354         DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
355         p->status = USB_RET_STALL;
356         break;
357     }
358 }
359 
360 static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
361 {
362     USBSerialState *s = (USBSerialState *)dev;
363     uint8_t devep = p->ep->nr;
364     struct iovec *iov;
365     uint8_t header[2];
366     int i, first_len, len;
367 
368     switch (p->pid) {
369     case USB_TOKEN_OUT:
370         if (devep != 2)
371             goto fail;
372         for (i = 0; i < p->iov.niov; i++) {
373             iov = p->iov.iov + i;
374             /* XXX this blocks entire thread. Rewrite to use
375              * qemu_chr_fe_write and background I/O callbacks */
376             qemu_chr_fe_write_all(&s->cs, iov->iov_base, iov->iov_len);
377         }
378         p->actual_length = p->iov.size;
379         break;
380 
381     case USB_TOKEN_IN:
382         if (devep != 1)
383             goto fail;
384         first_len = RECV_BUF - s->recv_ptr;
385         len = p->iov.size;
386         if (len <= 2) {
387             p->status = USB_RET_NAK;
388             break;
389         }
390         header[0] = usb_get_modem_lines(s) | 1;
391         /* We do not have the uart details */
392         /* handle serial break */
393         if (s->event_trigger && s->event_trigger & FTDI_BI) {
394             s->event_trigger &= ~FTDI_BI;
395             header[1] = FTDI_BI;
396             usb_packet_copy(p, header, 2);
397             break;
398         } else {
399             header[1] = 0;
400         }
401         len -= 2;
402         if (len > s->recv_used)
403             len = s->recv_used;
404         if (!len) {
405             p->status = USB_RET_NAK;
406             break;
407         }
408         if (first_len > len)
409             first_len = len;
410         usb_packet_copy(p, header, 2);
411         usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
412         if (len > first_len)
413             usb_packet_copy(p, s->recv_buf, len - first_len);
414         s->recv_used -= len;
415         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
416         break;
417 
418     default:
419         DPRINTF("Bad token\n");
420     fail:
421         p->status = USB_RET_STALL;
422         break;
423     }
424 }
425 
426 static int usb_serial_can_read(void *opaque)
427 {
428     USBSerialState *s = opaque;
429 
430     if (!s->dev.attached) {
431         return 0;
432     }
433     return RECV_BUF - s->recv_used;
434 }
435 
436 static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
437 {
438     USBSerialState *s = opaque;
439     int first_size, start;
440 
441     /* room in the buffer? */
442     if (size > (RECV_BUF - s->recv_used))
443         size = RECV_BUF - s->recv_used;
444 
445     start = s->recv_ptr + s->recv_used;
446     if (start < RECV_BUF) {
447         /* copy data to end of buffer */
448         first_size = RECV_BUF - start;
449         if (first_size > size)
450             first_size = size;
451 
452         memcpy(s->recv_buf + start, buf, first_size);
453 
454         /* wrap around to front if needed */
455         if (size > first_size)
456             memcpy(s->recv_buf, buf + first_size, size - first_size);
457     } else {
458         start -= RECV_BUF;
459         memcpy(s->recv_buf + start, buf, size);
460     }
461     s->recv_used += size;
462 }
463 
464 static void usb_serial_event(void *opaque, int event)
465 {
466     USBSerialState *s = opaque;
467 
468     switch (event) {
469         case CHR_EVENT_BREAK:
470             s->event_trigger |= FTDI_BI;
471             break;
472         case CHR_EVENT_OPENED:
473             if (!s->dev.attached) {
474                 usb_device_attach(&s->dev, &error_abort);
475             }
476             break;
477         case CHR_EVENT_CLOSED:
478             if (s->dev.attached) {
479                 usb_device_detach(&s->dev);
480             }
481             break;
482     }
483 }
484 
485 static void usb_serial_realize(USBDevice *dev, Error **errp)
486 {
487     USBSerialState *s = USB_SERIAL_DEV(dev);
488     Error *local_err = NULL;
489 
490     usb_desc_create_serial(dev);
491     usb_desc_init(dev);
492     dev->auto_attach = 0;
493 
494     if (!qemu_chr_fe_backend_connected(&s->cs)) {
495         error_setg(errp, "Property chardev is required");
496         return;
497     }
498 
499     usb_check_attach(dev, &local_err);
500     if (local_err) {
501         error_propagate(errp, local_err);
502         return;
503     }
504 
505     qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
506                              usb_serial_event, NULL, s, NULL, true);
507     usb_serial_handle_reset(dev);
508 
509     if (qemu_chr_fe_backend_open(&s->cs) && !dev->attached) {
510         usb_device_attach(dev, &error_abort);
511     }
512 }
513 
514 static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
515 {
516     USBDevice *dev;
517     Chardev *cdrv;
518 
519     cdrv = qemu_chr_new("braille", "braille", NULL);
520     if (!cdrv)
521         return NULL;
522 
523     dev = usb_create(bus, "usb-braille");
524     qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
525     return dev;
526 }
527 
528 static const VMStateDescription vmstate_usb_serial = {
529     .name = "usb-serial",
530     .unmigratable = 1,
531 };
532 
533 static Property serial_properties[] = {
534     DEFINE_PROP_CHR("chardev", USBSerialState, cs),
535     DEFINE_PROP_END_OF_LIST(),
536 };
537 
538 static void usb_serial_dev_class_init(ObjectClass *klass, void *data)
539 {
540     DeviceClass *dc = DEVICE_CLASS(klass);
541     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
542 
543     uc->realize        = usb_serial_realize;
544     uc->handle_reset   = usb_serial_handle_reset;
545     uc->handle_control = usb_serial_handle_control;
546     uc->handle_data    = usb_serial_handle_data;
547     dc->vmsd = &vmstate_usb_serial;
548     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
549 }
550 
551 static const TypeInfo usb_serial_dev_type_info = {
552     .name = TYPE_USB_SERIAL,
553     .parent = TYPE_USB_DEVICE,
554     .instance_size = sizeof(USBSerialState),
555     .abstract = true,
556     .class_init = usb_serial_dev_class_init,
557 };
558 
559 static void usb_serial_class_initfn(ObjectClass *klass, void *data)
560 {
561     DeviceClass *dc = DEVICE_CLASS(klass);
562     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
563 
564     uc->product_desc   = "QEMU USB Serial";
565     uc->usb_desc       = &desc_serial;
566     dc->props = serial_properties;
567 }
568 
569 static const TypeInfo serial_info = {
570     .name          = "usb-serial",
571     .parent        = TYPE_USB_SERIAL,
572     .class_init    = usb_serial_class_initfn,
573 };
574 
575 static Property braille_properties[] = {
576     DEFINE_PROP_CHR("chardev", USBSerialState, cs),
577     DEFINE_PROP_END_OF_LIST(),
578 };
579 
580 static void usb_braille_class_initfn(ObjectClass *klass, void *data)
581 {
582     DeviceClass *dc = DEVICE_CLASS(klass);
583     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
584 
585     uc->product_desc   = "QEMU USB Braille";
586     uc->usb_desc       = &desc_braille;
587     dc->props = braille_properties;
588 }
589 
590 static const TypeInfo braille_info = {
591     .name          = "usb-braille",
592     .parent        = TYPE_USB_SERIAL,
593     .class_init    = usb_braille_class_initfn,
594 };
595 
596 static void usb_serial_register_types(void)
597 {
598     type_register_static(&usb_serial_dev_type_info);
599     type_register_static(&serial_info);
600     type_register_static(&braille_info);
601     usb_legacy_register("usb-braille", "braille", usb_braille_init);
602 }
603 
604 type_init(usb_serial_register_types)
605