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