blob: 98d1ca3c9136898d869e2f813818e59ff07c2084 [file] [log] [blame]
balroga7954212008-01-14 03:41:02 +00001/*
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 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +10008 * This code is licensed under the LGPL.
balroga7954212008-01-14 03:41:02 +00009 */
10
Peter Maydelle532b2e2016-01-26 18:17:12 +000011#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010012#include "qapi/error.h"
balroga7954212008-01-14 03:41:02 +000013#include "qemu-common.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020014#include "qemu/cutils.h"
Markus Armbrusterd49b6832015-03-17 18:29:20 +010015#include "qemu/error-report.h"
Gerd Hoffmannf1ae32a2012-03-07 14:55:18 +010016#include "hw/usb.h"
Michael S. Tsirkin463581a2018-05-03 22:50:48 +030017#include "desc.h"
Marc-André Lureau7566c6e2017-01-26 17:33:39 +040018#include "chardev/char-serial.h"
Marc-André Lureau4d43a602017-01-26 18:26:44 +040019#include "chardev/char-fe.h"
balroga7954212008-01-14 03:41:02 +000020
21//#define DEBUG_Serial
22
23#ifdef DEBUG_Serial
Blue Swirl001faf32009-05-13 17:53:17 +000024#define DPRINTF(fmt, ...) \
25do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
balroga7954212008-01-14 03:41:02 +000026#else
Blue Swirl001faf32009-05-13 17:53:17 +000027#define DPRINTF(fmt, ...) do {} while(0)
balroga7954212008-01-14 03:41:02 +000028#endif
29
30#define RECV_BUF 384
balroga7954212008-01-14 03:41:02 +000031
32/* Commands */
33#define FTDI_RESET 0
34#define FTDI_SET_MDM_CTRL 1
35#define FTDI_SET_FLOW_CTRL 2
36#define FTDI_SET_BAUD 3
37#define FTDI_SET_DATA 4
38#define FTDI_GET_MDM_ST 5
39#define FTDI_SET_EVENT_CHR 6
40#define FTDI_SET_ERROR_CHR 7
41#define FTDI_SET_LATENCY 9
42#define FTDI_GET_LATENCY 10
43
44#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
45#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
46
47/* RESET */
48
49#define FTDI_RESET_SIO 0
50#define FTDI_RESET_RX 1
51#define FTDI_RESET_TX 2
52
53/* SET_MDM_CTRL */
54
balroga7954212008-01-14 03:41:02 +000055#define FTDI_DTR 1
aurel32abb8a132008-08-13 04:23:17 +000056#define FTDI_SET_DTR (FTDI_DTR << 8)
balroga7954212008-01-14 03:41:02 +000057#define FTDI_RTS 2
aurel32abb8a132008-08-13 04:23:17 +000058#define FTDI_SET_RTS (FTDI_RTS << 8)
balroga7954212008-01-14 03:41:02 +000059
60/* SET_FLOW_CTRL */
61
62#define FTDI_RTS_CTS_HS 1
63#define FTDI_DTR_DSR_HS 2
64#define FTDI_XON_XOFF_HS 4
65
66/* SET_DATA */
67
68#define FTDI_PARITY (0x7 << 8)
69#define FTDI_ODD (0x1 << 8)
70#define FTDI_EVEN (0x2 << 8)
71#define FTDI_MARK (0x3 << 8)
72#define FTDI_SPACE (0x4 << 8)
73
74#define FTDI_STOP (0x3 << 11)
75#define FTDI_STOP1 (0x0 << 11)
76#define FTDI_STOP15 (0x1 << 11)
77#define FTDI_STOP2 (0x2 << 11)
78
79/* GET_MDM_ST */
80/* TODO: should be sent every 40ms */
81#define FTDI_CTS (1<<4) // CTS line status
82#define FTDI_DSR (1<<5) // DSR line status
83#define FTDI_RI (1<<6) // RI line status
84#define FTDI_RLSD (1<<7) // Receive Line Signal Detect
85
86/* Status */
87
88#define FTDI_DR (1<<0) // Data Ready
89#define FTDI_OE (1<<1) // Overrun Err
90#define FTDI_PE (1<<2) // Parity Err
91#define FTDI_FE (1<<3) // Framing Err
92#define FTDI_BI (1<<4) // Break Interrupt
93#define FTDI_THRE (1<<5) // Transmitter Holding Register
94#define FTDI_TEMT (1<<6) // Transmitter Empty
95#define FTDI_FIFO (1<<7) // Error in FIFO
96
97typedef struct {
98 USBDevice dev;
balroga7954212008-01-14 03:41:02 +000099 uint8_t recv_buf[RECV_BUF];
aurel328109b9b2008-09-17 22:04:21 +0000100 uint16_t recv_ptr;
101 uint16_t recv_used;
balroga7954212008-01-14 03:41:02 +0000102 uint8_t event_chr;
103 uint8_t error_chr;
104 uint8_t event_trigger;
balroga7954212008-01-14 03:41:02 +0000105 QEMUSerialSetParams params;
106 int latency; /* ms */
Marc-André Lureaubecdfa02016-10-22 12:52:51 +0300107 CharBackend cs;
balroga7954212008-01-14 03:41:02 +0000108} USBSerialState;
109
Gongleicdf0d762015-05-06 20:55:36 +0800110#define TYPE_USB_SERIAL "usb-serial-dev"
111#define USB_SERIAL_DEV(obj) OBJECT_CHECK(USBSerialState, (obj), TYPE_USB_SERIAL)
112
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100113enum {
114 STR_MANUFACTURER = 1,
115 STR_PRODUCT_SERIAL,
116 STR_PRODUCT_BRAILLE,
117 STR_SERIALNUMBER,
balroga7954212008-01-14 03:41:02 +0000118};
119
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100120static const USBDescStrings desc_strings = {
Crístian Viana93bfef42012-05-30 00:35:51 -0300121 [STR_MANUFACTURER] = "QEMU",
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100122 [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
Samuel Thibault2964cd92012-08-23 09:59:27 +0200123 [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100124 [STR_SERIALNUMBER] = "1",
125};
balroga7954212008-01-14 03:41:02 +0000126
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100127static const USBDescIface desc_iface0 = {
128 .bInterfaceNumber = 0,
129 .bNumEndpoints = 2,
130 .bInterfaceClass = 0xff,
131 .bInterfaceSubClass = 0xff,
132 .bInterfaceProtocol = 0xff,
133 .eps = (USBDescEndpoint[]) {
134 {
135 .bEndpointAddress = USB_DIR_IN | 0x01,
136 .bmAttributes = USB_ENDPOINT_XFER_BULK,
137 .wMaxPacketSize = 64,
138 },{
139 .bEndpointAddress = USB_DIR_OUT | 0x02,
140 .bmAttributes = USB_ENDPOINT_XFER_BULK,
141 .wMaxPacketSize = 64,
142 },
143 }
144};
balroga7954212008-01-14 03:41:02 +0000145
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100146static const USBDescDevice desc_device = {
147 .bcdUSB = 0x0200,
148 .bMaxPacketSize0 = 8,
149 .bNumConfigurations = 1,
150 .confs = (USBDescConfig[]) {
151 {
152 .bNumInterfaces = 1,
153 .bConfigurationValue = 1,
Pantelis Koukousoulasbd939762013-12-16 09:42:49 +0200154 .bmAttributes = USB_CFG_ATT_ONE,
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100155 .bMaxPower = 50,
Brad Hardsadd75082011-04-03 15:33:19 +1000156 .nif = 1,
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100157 .ifs = &desc_iface0,
158 },
159 },
160};
balroga7954212008-01-14 03:41:02 +0000161
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100162static const USBDesc desc_serial = {
163 .id = {
164 .idVendor = 0x0403,
165 .idProduct = 0x6001,
166 .bcdDevice = 0x0400,
167 .iManufacturer = STR_MANUFACTURER,
168 .iProduct = STR_PRODUCT_SERIAL,
169 .iSerialNumber = STR_SERIALNUMBER,
170 },
171 .full = &desc_device,
172 .str = desc_strings,
173};
balroga7954212008-01-14 03:41:02 +0000174
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100175static const USBDesc desc_braille = {
176 .id = {
177 .idVendor = 0x0403,
178 .idProduct = 0xfe72,
179 .bcdDevice = 0x0400,
180 .iManufacturer = STR_MANUFACTURER,
181 .iProduct = STR_PRODUCT_BRAILLE,
182 .iSerialNumber = STR_SERIALNUMBER,
183 },
184 .full = &desc_device,
185 .str = desc_strings,
balroga7954212008-01-14 03:41:02 +0000186};
187
188static void usb_serial_reset(USBSerialState *s)
189{
190 /* TODO: Set flow control to none */
191 s->event_chr = 0x0d;
192 s->event_trigger = 0;
193 s->recv_ptr = 0;
194 s->recv_used = 0;
195 /* TODO: purge in char driver */
balroga7954212008-01-14 03:41:02 +0000196}
197
198static void usb_serial_handle_reset(USBDevice *dev)
199{
200 USBSerialState *s = (USBSerialState *)dev;
201
202 DPRINTF("Reset\n");
203
204 usb_serial_reset(s);
205 /* TODO: Reset char device, send BREAK? */
206}
207
aurel32abb8a132008-08-13 04:23:17 +0000208static uint8_t usb_get_modem_lines(USBSerialState *s)
209{
210 int flags;
211 uint8_t ret;
212
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300213 if (qemu_chr_fe_ioctl(&s->cs,
Marc-André Lureaubecdfa02016-10-22 12:52:51 +0300214 CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
aurel32abb8a132008-08-13 04:23:17 +0000215 return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
Marc-André Lureaubecdfa02016-10-22 12:52:51 +0300216 }
aurel32abb8a132008-08-13 04:23:17 +0000217
218 ret = 0;
219 if (flags & CHR_TIOCM_CTS)
220 ret |= FTDI_CTS;
221 if (flags & CHR_TIOCM_DSR)
222 ret |= FTDI_DSR;
223 if (flags & CHR_TIOCM_RI)
224 ret |= FTDI_RI;
225 if (flags & CHR_TIOCM_CAR)
226 ret |= FTDI_RLSD;
227
228 return ret;
229}
230
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100231static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
Hans de Goede007fd622011-02-02 16:33:13 +0100232 int request, int value, int index, int length, uint8_t *data)
balroga7954212008-01-14 03:41:02 +0000233{
234 USBSerialState *s = (USBSerialState *)dev;
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100235 int ret;
balroga7954212008-01-14 03:41:02 +0000236
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100237 DPRINTF("got control %x, value %x\n",request, value);
Hans de Goede007fd622011-02-02 16:33:13 +0100238 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100239 if (ret >= 0) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100240 return;
Gerd Hoffmannf29783f2010-11-17 11:05:32 +0100241 }
242
balroga7954212008-01-14 03:41:02 +0000243 switch (request) {
balroga7954212008-01-14 03:41:02 +0000244 case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
balroga7954212008-01-14 03:41:02 +0000245 break;
246
247 /* Class specific requests. */
248 case DeviceOutVendor | FTDI_RESET:
249 switch (value) {
250 case FTDI_RESET_SIO:
251 usb_serial_reset(s);
252 break;
253 case FTDI_RESET_RX:
254 s->recv_ptr = 0;
255 s->recv_used = 0;
256 /* TODO: purge from char device */
257 break;
258 case FTDI_RESET_TX:
259 /* TODO: purge from char device */
260 break;
261 }
262 break;
263 case DeviceOutVendor | FTDI_SET_MDM_CTRL:
aurel32abb8a132008-08-13 04:23:17 +0000264 {
265 static int flags;
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300266 qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
aurel32abb8a132008-08-13 04:23:17 +0000267 if (value & FTDI_SET_RTS) {
268 if (value & FTDI_RTS)
269 flags |= CHR_TIOCM_RTS;
270 else
271 flags &= ~CHR_TIOCM_RTS;
272 }
273 if (value & FTDI_SET_DTR) {
274 if (value & FTDI_DTR)
275 flags |= CHR_TIOCM_DTR;
276 else
277 flags &= ~CHR_TIOCM_DTR;
278 }
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300279 qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
balroga7954212008-01-14 03:41:02 +0000280 break;
aurel32abb8a132008-08-13 04:23:17 +0000281 }
balroga7954212008-01-14 03:41:02 +0000282 case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
283 /* TODO: ioctl */
284 break;
285 case DeviceOutVendor | FTDI_SET_BAUD: {
286 static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
287 int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
288 | ((index & 1) << 2)];
289 int divisor = value & 0x3fff;
290
291 /* chip special cases */
292 if (divisor == 1 && subdivisor8 == 0)
293 subdivisor8 = 4;
294 if (divisor == 0 && subdivisor8 == 0)
295 divisor = 1;
296
297 s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300298 qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
balroga7954212008-01-14 03:41:02 +0000299 break;
300 }
301 case DeviceOutVendor | FTDI_SET_DATA:
302 switch (value & FTDI_PARITY) {
303 case 0:
304 s->params.parity = 'N';
305 break;
306 case FTDI_ODD:
307 s->params.parity = 'O';
308 break;
309 case FTDI_EVEN:
310 s->params.parity = 'E';
311 break;
312 default:
313 DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
314 goto fail;
315 }
316 switch (value & FTDI_STOP) {
317 case FTDI_STOP1:
318 s->params.stop_bits = 1;
319 break;
320 case FTDI_STOP2:
321 s->params.stop_bits = 2;
322 break;
323 default:
324 DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
325 goto fail;
326 }
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300327 qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
balroga7954212008-01-14 03:41:02 +0000328 /* TODO: TX ON/OFF */
329 break;
330 case DeviceInVendor | FTDI_GET_MDM_ST:
aurel32abb8a132008-08-13 04:23:17 +0000331 data[0] = usb_get_modem_lines(s) | 1;
332 data[1] = 0;
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100333 p->actual_length = 2;
balroga7954212008-01-14 03:41:02 +0000334 break;
335 case DeviceOutVendor | FTDI_SET_EVENT_CHR:
336 /* TODO: handle it */
337 s->event_chr = value;
338 break;
339 case DeviceOutVendor | FTDI_SET_ERROR_CHR:
340 /* TODO: handle it */
341 s->error_chr = value;
342 break;
343 case DeviceOutVendor | FTDI_SET_LATENCY:
344 s->latency = value;
345 break;
346 case DeviceInVendor | FTDI_GET_LATENCY:
347 data[0] = s->latency;
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100348 p->actual_length = 1;
balroga7954212008-01-14 03:41:02 +0000349 break;
350 default:
351 fail:
352 DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100353 p->status = USB_RET_STALL;
balroga7954212008-01-14 03:41:02 +0000354 break;
355 }
balroga7954212008-01-14 03:41:02 +0000356}
357
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100358static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
balroga7954212008-01-14 03:41:02 +0000359{
360 USBSerialState *s = (USBSerialState *)dev;
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100361 uint8_t devep = p->ep->nr;
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200362 struct iovec *iov;
363 uint8_t header[2];
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100364 int i, first_len, len;
balroga7954212008-01-14 03:41:02 +0000365
366 switch (p->pid) {
367 case USB_TOKEN_OUT:
368 if (devep != 2)
369 goto fail;
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200370 for (i = 0; i < p->iov.niov; i++) {
371 iov = p->iov.iov + i;
Daniel P. Berrange6ab3fc32016-09-06 14:56:04 +0100372 /* XXX this blocks entire thread. Rewrite to use
373 * qemu_chr_fe_write and background I/O callbacks */
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300374 qemu_chr_fe_write_all(&s->cs, iov->iov_base, iov->iov_len);
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200375 }
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100376 p->actual_length = p->iov.size;
balroga7954212008-01-14 03:41:02 +0000377 break;
378
379 case USB_TOKEN_IN:
380 if (devep != 1)
381 goto fail;
382 first_len = RECV_BUF - s->recv_ptr;
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200383 len = p->iov.size;
balroga7954212008-01-14 03:41:02 +0000384 if (len <= 2) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100385 p->status = USB_RET_NAK;
balroga7954212008-01-14 03:41:02 +0000386 break;
387 }
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200388 header[0] = usb_get_modem_lines(s) | 1;
aurel32abb8a132008-08-13 04:23:17 +0000389 /* We do not have the uart details */
Jason Wessel7e57f042009-05-18 10:00:26 -0500390 /* handle serial break */
391 if (s->event_trigger && s->event_trigger & FTDI_BI) {
392 s->event_trigger &= ~FTDI_BI;
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200393 header[1] = FTDI_BI;
394 usb_packet_copy(p, header, 2);
Jason Wessel7e57f042009-05-18 10:00:26 -0500395 break;
396 } else {
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200397 header[1] = 0;
Jason Wessel7e57f042009-05-18 10:00:26 -0500398 }
balroga7954212008-01-14 03:41:02 +0000399 len -= 2;
400 if (len > s->recv_used)
401 len = s->recv_used;
402 if (!len) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100403 p->status = USB_RET_NAK;
balroga7954212008-01-14 03:41:02 +0000404 break;
405 }
406 if (first_len > len)
407 first_len = len;
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200408 usb_packet_copy(p, header, 2);
409 usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
balroga7954212008-01-14 03:41:02 +0000410 if (len > first_len)
Gerd Hoffmann9440b7e2011-07-13 10:53:23 +0200411 usb_packet_copy(p, s->recv_buf, len - first_len);
balroga7954212008-01-14 03:41:02 +0000412 s->recv_used -= len;
413 s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
balroga7954212008-01-14 03:41:02 +0000414 break;
415
416 default:
417 DPRINTF("Bad token\n");
418 fail:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100419 p->status = USB_RET_STALL;
balroga7954212008-01-14 03:41:02 +0000420 break;
421 }
balroga7954212008-01-14 03:41:02 +0000422}
423
blueswir18fcd3692008-08-17 20:26:25 +0000424static int usb_serial_can_read(void *opaque)
balroga7954212008-01-14 03:41:02 +0000425{
426 USBSerialState *s = opaque;
Gerd Hoffmannda124e62012-10-17 09:54:25 +0200427
428 if (!s->dev.attached) {
429 return 0;
430 }
balroga7954212008-01-14 03:41:02 +0000431 return RECV_BUF - s->recv_used;
432}
433
blueswir18fcd3692008-08-17 20:26:25 +0000434static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
balroga7954212008-01-14 03:41:02 +0000435{
436 USBSerialState *s = opaque;
David S. Ahern4ab41832010-02-03 09:00:54 -0700437 int first_size, start;
438
439 /* room in the buffer? */
440 if (size > (RECV_BUF - s->recv_used))
441 size = RECV_BUF - s->recv_used;
442
443 start = s->recv_ptr + s->recv_used;
444 if (start < RECV_BUF) {
445 /* copy data to end of buffer */
446 first_size = RECV_BUF - start;
447 if (first_size > size)
448 first_size = size;
449
450 memcpy(s->recv_buf + start, buf, first_size);
451
452 /* wrap around to front if needed */
453 if (size > first_size)
454 memcpy(s->recv_buf, buf + first_size, size - first_size);
455 } else {
456 start -= RECV_BUF;
457 memcpy(s->recv_buf + start, buf, size);
458 }
balroga7954212008-01-14 03:41:02 +0000459 s->recv_used += size;
460}
461
blueswir18fcd3692008-08-17 20:26:25 +0000462static void usb_serial_event(void *opaque, int event)
balroga7954212008-01-14 03:41:02 +0000463{
464 USBSerialState *s = opaque;
465
466 switch (event) {
467 case CHR_EVENT_BREAK:
Jason Wessel7e57f042009-05-18 10:00:26 -0500468 s->event_trigger |= FTDI_BI;
balroga7954212008-01-14 03:41:02 +0000469 break;
Amit Shahb6b8df52009-10-07 18:31:16 +0530470 case CHR_EVENT_OPENED:
Gerd Hoffmannda124e62012-10-17 09:54:25 +0200471 if (!s->dev.attached) {
Gonglei7334d652014-09-19 15:25:21 +0800472 usb_device_attach(&s->dev, &error_abort);
Gerd Hoffmannda124e62012-10-17 09:54:25 +0200473 }
474 break;
475 case CHR_EVENT_CLOSED:
476 if (s->dev.attached) {
477 usb_device_detach(&s->dev);
478 }
balroga7954212008-01-14 03:41:02 +0000479 break;
480 }
481}
482
Gonglei38fff2c2014-09-19 14:48:34 +0800483static void usb_serial_realize(USBDevice *dev, Error **errp)
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200484{
Gongleicdf0d762015-05-06 20:55:36 +0800485 USBSerialState *s = USB_SERIAL_DEV(dev);
Gonglei7334d652014-09-19 15:25:21 +0800486 Error *local_err = NULL;
Gerd Hoffmanna980a062010-11-26 20:20:41 +0100487
Gerd Hoffmann9d55d1a2012-04-20 12:33:30 +0200488 usb_desc_create_serial(dev);
Gerd Hoffmanna980a062010-11-26 20:20:41 +0100489 usb_desc_init(dev);
Gerd Hoffmannda124e62012-10-17 09:54:25 +0200490 dev->auto_attach = 0;
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100491
Anton Nefedov30650702017-07-06 15:08:52 +0300492 if (!qemu_chr_fe_backend_connected(&s->cs)) {
Gonglei38fff2c2014-09-19 14:48:34 +0800493 error_setg(errp, "Property chardev is required");
494 return;
Markus Armbruster81bf96d2010-05-28 17:03:22 +0200495 }
496
Gonglei7334d652014-09-19 15:25:21 +0800497 usb_check_attach(dev, &local_err);
498 if (local_err) {
499 error_propagate(errp, local_err);
500 return;
501 }
502
Marc-André Lureau5345fdb2016-10-22 12:52:55 +0300503 qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
Anton Nefedov81517ba2017-07-06 15:08:49 +0300504 usb_serial_event, NULL, s, NULL, true);
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100505 usb_serial_handle_reset(dev);
Gerd Hoffmannda124e62012-10-17 09:54:25 +0200506
Anton Nefedov30650702017-07-06 15:08:52 +0300507 if (qemu_chr_fe_backend_open(&s->cs) && !dev->attached) {
Gonglei7334d652014-09-19 15:25:21 +0800508 usb_device_attach(dev, &error_abort);
Gerd Hoffmannda124e62012-10-17 09:54:25 +0200509 }
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200510}
511
Jan Kiszka37417152012-02-27 15:18:47 +0100512static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100513{
514 USBDevice *dev;
Marc-André Lureau0ec7b3e2016-12-07 16:20:22 +0300515 Chardev *cdrv;
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100516
Marc-André Lureaub4948be2016-10-22 12:52:46 +0300517 cdrv = qemu_chr_new("braille", "braille");
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100518 if (!cdrv)
519 return NULL;
520
Jan Kiszka37417152012-02-27 15:18:47 +0100521 dev = usb_create(bus, "usb-braille");
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100522 qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100523 return dev;
balroga7954212008-01-14 03:41:02 +0000524}
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200525
Gerd Hoffmann98e51ec2011-07-20 10:06:18 +0200526static const VMStateDescription vmstate_usb_serial = {
527 .name = "usb-serial",
528 .unmigratable = 1,
529};
530
Anthony Liguori39bffca2011-12-07 21:34:16 -0600531static Property serial_properties[] = {
532 DEFINE_PROP_CHR("chardev", USBSerialState, cs),
533 DEFINE_PROP_END_OF_LIST(),
534};
535
Gongleicdf0d762015-05-06 20:55:36 +0800536static void usb_serial_dev_class_init(ObjectClass *klass, void *data)
537{
538 DeviceClass *dc = DEVICE_CLASS(klass);
539 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
540
541 uc->realize = usb_serial_realize;
542 uc->handle_reset = usb_serial_handle_reset;
543 uc->handle_control = usb_serial_handle_control;
544 uc->handle_data = usb_serial_handle_data;
545 dc->vmsd = &vmstate_usb_serial;
546 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
547}
548
549static const TypeInfo usb_serial_dev_type_info = {
550 .name = TYPE_USB_SERIAL,
551 .parent = TYPE_USB_DEVICE,
552 .instance_size = sizeof(USBSerialState),
553 .abstract = true,
554 .class_init = usb_serial_dev_class_init,
555};
556
Anthony Liguori62aed762011-12-15 14:53:10 -0600557static void usb_serial_class_initfn(ObjectClass *klass, void *data)
558{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600559 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori62aed762011-12-15 14:53:10 -0600560 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
561
Anthony Liguori62aed762011-12-15 14:53:10 -0600562 uc->product_desc = "QEMU USB Serial";
563 uc->usb_desc = &desc_serial;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600564 dc->props = serial_properties;
Anthony Liguori62aed762011-12-15 14:53:10 -0600565}
566
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100567static const TypeInfo serial_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600568 .name = "usb-serial",
Gongleicdf0d762015-05-06 20:55:36 +0800569 .parent = TYPE_USB_SERIAL,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600570 .class_init = usb_serial_class_initfn,
571};
572
573static Property braille_properties[] = {
574 DEFINE_PROP_CHR("chardev", USBSerialState, cs),
575 DEFINE_PROP_END_OF_LIST(),
Gerd Hoffmann2b0efdc2009-10-26 15:56:47 +0100576};
577
Anthony Liguori62aed762011-12-15 14:53:10 -0600578static void usb_braille_class_initfn(ObjectClass *klass, void *data)
579{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600580 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori62aed762011-12-15 14:53:10 -0600581 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
582
Anthony Liguori62aed762011-12-15 14:53:10 -0600583 uc->product_desc = "QEMU USB Braille";
584 uc->usb_desc = &desc_braille;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600585 dc->props = braille_properties;
Anthony Liguori62aed762011-12-15 14:53:10 -0600586}
587
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100588static const TypeInfo braille_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600589 .name = "usb-braille",
Gongleicdf0d762015-05-06 20:55:36 +0800590 .parent = TYPE_USB_SERIAL,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600591 .class_init = usb_braille_class_initfn,
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200592};
593
Andreas Färber83f7d432012-02-09 15:20:55 +0100594static void usb_serial_register_types(void)
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200595{
Gongleicdf0d762015-05-06 20:55:36 +0800596 type_register_static(&usb_serial_dev_type_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600597 type_register_static(&serial_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600598 type_register_static(&braille_info);
Anthony Liguoriba024302011-12-08 14:56:53 -0600599 usb_legacy_register("usb-braille", "braille", usb_braille_init);
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200600}
Andreas Färber83f7d432012-02-09 15:20:55 +0100601
602type_init(usb_serial_register_types)