2 * FTDI FT232BM Device emulation
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
8 * This code is licenced under the LGPL.
11 #include "qemu-common.h"
13 #include "qemu-char.h"
15 //#define DEBUG_Serial
18 #define DPRINTF(fmt, args...) \
19 do { printf("usb-serial: " fmt , ##args); } while (0)
21 #define DPRINTF(fmt, args...) do {} while(0)
25 #define SEND_BUF 128 // Not used for now
29 #define FTDI_SET_MDM_CTRL 1
30 #define FTDI_SET_FLOW_CTRL 2
31 #define FTDI_SET_BAUD 3
32 #define FTDI_SET_DATA 4
33 #define FTDI_GET_MDM_ST 5
34 #define FTDI_SET_EVENT_CHR 6
35 #define FTDI_SET_ERROR_CHR 7
36 #define FTDI_SET_LATENCY 9
37 #define FTDI_GET_LATENCY 10
39 #define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
40 #define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
44 #define FTDI_RESET_SIO 0
45 #define FTDI_RESET_RX 1
46 #define FTDI_RESET_TX 2
51 #define FTDI_SET_DTR (FTDI_DTR << 8)
53 #define FTDI_SET_RTS (FTDI_RTS << 8)
57 #define FTDI_RTS_CTS_HS 1
58 #define FTDI_DTR_DSR_HS 2
59 #define FTDI_XON_XOFF_HS 4
63 #define FTDI_PARITY (0x7 << 8)
64 #define FTDI_ODD (0x1 << 8)
65 #define FTDI_EVEN (0x2 << 8)
66 #define FTDI_MARK (0x3 << 8)
67 #define FTDI_SPACE (0x4 << 8)
69 #define FTDI_STOP (0x3 << 11)
70 #define FTDI_STOP1 (0x0 << 11)
71 #define FTDI_STOP15 (0x1 << 11)
72 #define FTDI_STOP2 (0x2 << 11)
75 /* TODO: should be sent every 40ms */
76 #define FTDI_CTS (1<<4) // CTS line status
77 #define FTDI_DSR (1<<5) // DSR line status
78 #define FTDI_RI (1<<6) // RI line status
79 #define FTDI_RLSD (1<<7) // Receive Line Signal Detect
83 #define FTDI_DR (1<<0) // Data Ready
84 #define FTDI_OE (1<<1) // Overrun Err
85 #define FTDI_PE (1<<2) // Parity Err
86 #define FTDI_FE (1<<3) // Framing Err
87 #define FTDI_BI (1<<4) // Break Interrupt
88 #define FTDI_THRE (1<<5) // Transmitter Holding Register
89 #define FTDI_TEMT (1<<6) // Transmitter Empty
90 #define FTDI_FIFO (1<<7) // Error in FIFO
96 uint8_t recv_buf
[RECV_BUF
];
99 uint8_t send_buf
[SEND_BUF
];
102 uint8_t event_trigger
;
103 QEMUSerialSetParams params
;
104 int latency
; /* ms */
108 static const uint8_t qemu_serial_dev_descriptor
[] = {
109 0x12, /* u8 bLength; */
110 0x01, /* u8 bDescriptorType; Device */
111 0x00, 0x02, /* u16 bcdUSB; v2.0 */
113 0x00, /* u8 bDeviceClass; */
114 0x00, /* u8 bDeviceSubClass; */
115 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
116 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
118 /* Vendor and product id are arbitrary. */
119 0x03, 0x04, /* u16 idVendor; */
120 0x00, 0xFF, /* u16 idProduct; */
121 0x00, 0x04, /* u16 bcdDevice */
123 0x01, /* u8 iManufacturer; */
124 0x02, /* u8 iProduct; */
125 0x03, /* u8 iSerialNumber; */
126 0x01 /* u8 bNumConfigurations; */
129 static const uint8_t qemu_serial_config_descriptor
[] = {
131 /* one configuration */
132 0x09, /* u8 bLength; */
133 0x02, /* u8 bDescriptorType; Configuration */
134 0x20, 0x00, /* u16 wTotalLength; */
135 0x01, /* u8 bNumInterfaces; (1) */
136 0x01, /* u8 bConfigurationValue; */
137 0x00, /* u8 iConfiguration; */
138 0x80, /* u8 bmAttributes;
143 100/2, /* u8 MaxPower; */
146 0x09, /* u8 if_bLength; */
147 0x04, /* u8 if_bDescriptorType; Interface */
148 0x00, /* u8 if_bInterfaceNumber; */
149 0x00, /* u8 if_bAlternateSetting; */
150 0x02, /* u8 if_bNumEndpoints; */
151 0xff, /* u8 if_bInterfaceClass; Vendor Specific */
152 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */
153 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */
154 0x02, /* u8 if_iInterface; */
156 /* Bulk-In endpoint */
157 0x07, /* u8 ep_bLength; */
158 0x05, /* u8 ep_bDescriptorType; Endpoint */
159 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
160 0x02, /* u8 ep_bmAttributes; Bulk */
161 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
162 0x00, /* u8 ep_bInterval; */
164 /* Bulk-Out endpoint */
165 0x07, /* u8 ep_bLength; */
166 0x05, /* u8 ep_bDescriptorType; Endpoint */
167 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */
168 0x02, /* u8 ep_bmAttributes; Bulk */
169 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
170 0x00 /* u8 ep_bInterval; */
173 static void usb_serial_reset(USBSerialState
*s
)
175 /* TODO: Set flow control to none */
177 s
->event_trigger
= 0;
180 /* TODO: purge in char driver */
183 static void usb_serial_handle_reset(USBDevice
*dev
)
185 USBSerialState
*s
= (USBSerialState
*)dev
;
190 /* TODO: Reset char device, send BREAK? */
193 static uint8_t usb_get_modem_lines(USBSerialState
*s
)
198 if (qemu_chr_ioctl(s
->cs
, CHR_IOCTL_SERIAL_GET_TIOCM
, &flags
) == -ENOTSUP
)
199 return FTDI_CTS
|FTDI_DSR
|FTDI_RLSD
;
202 if (flags
& CHR_TIOCM_CTS
)
204 if (flags
& CHR_TIOCM_DSR
)
206 if (flags
& CHR_TIOCM_RI
)
208 if (flags
& CHR_TIOCM_CAR
)
214 static int usb_serial_handle_control(USBDevice
*dev
, int request
, int value
,
215 int index
, int length
, uint8_t *data
)
217 USBSerialState
*s
= (USBSerialState
*)dev
;
220 //DPRINTF("got control %x, value %x\n",request, value);
222 case DeviceRequest
| USB_REQ_GET_STATUS
:
223 data
[0] = (0 << USB_DEVICE_SELF_POWERED
) |
224 (dev
->remote_wakeup
<< USB_DEVICE_REMOTE_WAKEUP
);
228 case DeviceOutRequest
| USB_REQ_CLEAR_FEATURE
:
229 if (value
== USB_DEVICE_REMOTE_WAKEUP
) {
230 dev
->remote_wakeup
= 0;
236 case DeviceOutRequest
| USB_REQ_SET_FEATURE
:
237 if (value
== USB_DEVICE_REMOTE_WAKEUP
) {
238 dev
->remote_wakeup
= 1;
244 case DeviceOutRequest
| USB_REQ_SET_ADDRESS
:
248 case DeviceRequest
| USB_REQ_GET_DESCRIPTOR
:
251 memcpy(data
, qemu_serial_dev_descriptor
,
252 sizeof(qemu_serial_dev_descriptor
));
253 data
[8] = s
->vendorid
& 0xff;
254 data
[9] = ((s
->vendorid
) >> 8) & 0xff;
255 data
[10] = s
->productid
& 0xff;
256 data
[11] = ((s
->productid
) >> 8) & 0xff;
257 ret
= sizeof(qemu_serial_dev_descriptor
);
260 memcpy(data
, qemu_serial_config_descriptor
,
261 sizeof(qemu_serial_config_descriptor
));
262 ret
= sizeof(qemu_serial_config_descriptor
);
265 switch(value
& 0xff) {
275 /* vendor description */
276 ret
= set_usb_string(data
, "QEMU " QEMU_VERSION
);
279 /* product description */
280 ret
= set_usb_string(data
, "QEMU USB SERIAL");
284 ret
= set_usb_string(data
, "1");
294 case DeviceRequest
| USB_REQ_GET_CONFIGURATION
:
298 case DeviceOutRequest
| USB_REQ_SET_CONFIGURATION
:
301 case DeviceRequest
| USB_REQ_GET_INTERFACE
:
305 case InterfaceOutRequest
| USB_REQ_SET_INTERFACE
:
308 case EndpointOutRequest
| USB_REQ_CLEAR_FEATURE
:
312 /* Class specific requests. */
313 case DeviceOutVendor
| FTDI_RESET
:
321 /* TODO: purge from char device */
324 /* TODO: purge from char device */
328 case DeviceOutVendor
| FTDI_SET_MDM_CTRL
:
331 qemu_chr_ioctl(s
->cs
,CHR_IOCTL_SERIAL_GET_TIOCM
, &flags
);
332 if (value
& FTDI_SET_RTS
) {
333 if (value
& FTDI_RTS
)
334 flags
|= CHR_TIOCM_RTS
;
336 flags
&= ~CHR_TIOCM_RTS
;
338 if (value
& FTDI_SET_DTR
) {
339 if (value
& FTDI_DTR
)
340 flags
|= CHR_TIOCM_DTR
;
342 flags
&= ~CHR_TIOCM_DTR
;
344 qemu_chr_ioctl(s
->cs
,CHR_IOCTL_SERIAL_SET_TIOCM
, &flags
);
347 case DeviceOutVendor
| FTDI_SET_FLOW_CTRL
:
350 case DeviceOutVendor
| FTDI_SET_BAUD
: {
351 static const int subdivisors8
[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
352 int subdivisor8
= subdivisors8
[((value
& 0xc000) >> 14)
353 | ((index
& 1) << 2)];
354 int divisor
= value
& 0x3fff;
356 /* chip special cases */
357 if (divisor
== 1 && subdivisor8
== 0)
359 if (divisor
== 0 && subdivisor8
== 0)
362 s
->params
.speed
= (48000000 / 2) / (8 * divisor
+ subdivisor8
);
363 qemu_chr_ioctl(s
->cs
, CHR_IOCTL_SERIAL_SET_PARAMS
, &s
->params
);
366 case DeviceOutVendor
| FTDI_SET_DATA
:
367 switch (value
& FTDI_PARITY
) {
369 s
->params
.parity
= 'N';
372 s
->params
.parity
= 'O';
375 s
->params
.parity
= 'E';
378 DPRINTF("unsupported parity %d\n", value
& FTDI_PARITY
);
381 switch (value
& FTDI_STOP
) {
383 s
->params
.stop_bits
= 1;
386 s
->params
.stop_bits
= 2;
389 DPRINTF("unsupported stop bits %d\n", value
& FTDI_STOP
);
392 qemu_chr_ioctl(s
->cs
, CHR_IOCTL_SERIAL_SET_PARAMS
, &s
->params
);
393 /* TODO: TX ON/OFF */
395 case DeviceInVendor
| FTDI_GET_MDM_ST
:
396 data
[0] = usb_get_modem_lines(s
) | 1;
400 case DeviceOutVendor
| FTDI_SET_EVENT_CHR
:
401 /* TODO: handle it */
402 s
->event_chr
= value
;
404 case DeviceOutVendor
| FTDI_SET_ERROR_CHR
:
405 /* TODO: handle it */
406 s
->error_chr
= value
;
408 case DeviceOutVendor
| FTDI_SET_LATENCY
:
411 case DeviceInVendor
| FTDI_GET_LATENCY
:
412 data
[0] = s
->latency
;
417 DPRINTF("got unsupported/bogus control %x, value %x\n", request
, value
);
424 static int usb_serial_handle_data(USBDevice
*dev
, USBPacket
*p
)
426 USBSerialState
*s
= (USBSerialState
*)dev
;
428 uint8_t devep
= p
->devep
;
429 uint8_t *data
= p
->data
;
437 qemu_chr_write(s
->cs
, data
, len
);
443 first_len
= RECV_BUF
- s
->recv_ptr
;
448 *data
++ = usb_get_modem_lines(s
) | 1;
449 /* We do not have the uart details */
452 if (len
> s
->recv_used
)
460 memcpy(data
, s
->recv_buf
+ s
->recv_ptr
, first_len
);
462 memcpy(data
+ first_len
, s
->recv_buf
, len
- first_len
);
464 s
->recv_ptr
= (s
->recv_ptr
+ len
) % RECV_BUF
;
469 DPRINTF("Bad token\n");
478 static void usb_serial_handle_destroy(USBDevice
*dev
)
480 USBSerialState
*s
= (USBSerialState
*)dev
;
482 qemu_chr_close(s
->cs
);
486 static int usb_serial_can_read(void *opaque
)
488 USBSerialState
*s
= opaque
;
489 return RECV_BUF
- s
->recv_used
;
492 static void usb_serial_read(void *opaque
, const uint8_t *buf
, int size
)
494 USBSerialState
*s
= opaque
;
495 int first_size
= RECV_BUF
- s
->recv_ptr
;
496 if (first_size
> size
)
498 memcpy(s
->recv_buf
+ s
->recv_ptr
+ s
->recv_used
, buf
, first_size
);
499 if (size
> first_size
)
500 memcpy(s
->recv_buf
, buf
+ first_size
, size
- first_size
);
501 s
->recv_used
+= size
;
504 static void usb_serial_event(void *opaque
, int event
)
506 USBSerialState
*s
= opaque
;
509 case CHR_EVENT_BREAK
:
510 /* TODO: Send Break to USB */
512 case CHR_EVENT_FOCUS
:
514 case CHR_EVENT_RESET
:
516 /* TODO: Reset USB port */
521 USBDevice
*usb_serial_init(const char *filename
)
524 CharDriverState
*cdrv
;
525 unsigned short vendorid
= 0x0403, productid
= 0x6001;
527 while (*filename
&& *filename
!= ':') {
530 if (strstart(filename
, "vendorid=", &p
)) {
531 vendorid
= strtol(p
, &e
, 16);
532 if (e
== p
|| (*e
&& *e
!= ',' && *e
!= ':')) {
533 printf("bogus vendor ID %s\n", p
);
537 } else if (strstart(filename
, "productid=", &p
)) {
538 productid
= strtol(p
, &e
, 16);
539 if (e
== p
|| (*e
&& *e
!= ',' && *e
!= ':')) {
540 printf("bogus product ID %s\n", p
);
545 printf("unrecognized serial USB option %s\n", filename
);
548 while(*filename
== ',')
552 printf("character device specification needed\n");
556 s
= qemu_mallocz(sizeof(USBSerialState
));
560 cdrv
= qemu_chr_open(filename
);
564 qemu_chr_add_handlers(cdrv
, usb_serial_can_read
, usb_serial_read
, usb_serial_event
, s
);
566 s
->dev
.speed
= USB_SPEED_FULL
;
567 s
->dev
.handle_packet
= usb_generic_handle_packet
;
569 s
->dev
.handle_reset
= usb_serial_handle_reset
;
570 s
->dev
.handle_control
= usb_serial_handle_control
;
571 s
->dev
.handle_data
= usb_serial_handle_data
;
572 s
->dev
.handle_destroy
= usb_serial_handle_destroy
;
574 s
->vendorid
= vendorid
;
575 s
->productid
= productid
;
577 snprintf(s
->dev
.devname
, sizeof(s
->dev
.devname
), "QEMU USB Serial(%.16s)",
580 usb_serial_handle_reset((USBDevice
*)s
);
581 return (USBDevice
*)s
;