📄 usb-serial.c
字号:
/* * FTDI FT232BM Device emulation * * Copyright (c) 2006 CodeSourcery. * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org> * Written by Paul Brook, reused for FTDI by Samuel Thibault * * This code is licenced under the LGPL. */#include "qemu-common.h"#include "usb.h"#include "qemu-char.h"//#define DEBUG_Serial#ifdef DEBUG_Serial#define DPRINTF(fmt, args...) \do { printf("usb-serial: " fmt , ##args); } while (0)#else#define DPRINTF(fmt, args...) do {} while(0)#endif#define RECV_BUF 384#define SEND_BUF 128 // Not used for now/* Commands */#define FTDI_RESET 0#define FTDI_SET_MDM_CTRL 1#define FTDI_SET_FLOW_CTRL 2#define FTDI_SET_BAUD 3#define FTDI_SET_DATA 4#define FTDI_GET_MDM_ST 5#define FTDI_SET_EVENT_CHR 6#define FTDI_SET_ERROR_CHR 7#define FTDI_SET_LATENCY 9#define FTDI_GET_LATENCY 10#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)/* RESET */#define FTDI_RESET_SIO 0#define FTDI_RESET_RX 1#define FTDI_RESET_TX 2/* SET_MDM_CTRL */#define FTDI_MDM_CTRL 3#define FTDI_DTR 1#define FTDI_RTS 2/* SET_FLOW_CTRL */#define FTDI_RTS_CTS_HS 1#define FTDI_DTR_DSR_HS 2#define FTDI_XON_XOFF_HS 4/* SET_DATA */#define FTDI_PARITY (0x7 << 8)#define FTDI_ODD (0x1 << 8)#define FTDI_EVEN (0x2 << 8)#define FTDI_MARK (0x3 << 8)#define FTDI_SPACE (0x4 << 8)#define FTDI_STOP (0x3 << 11)#define FTDI_STOP1 (0x0 << 11)#define FTDI_STOP15 (0x1 << 11)#define FTDI_STOP2 (0x2 << 11)/* GET_MDM_ST *//* TODO: should be sent every 40ms */#define FTDI_CTS (1<<4) // CTS line status#define FTDI_DSR (1<<5) // DSR line status#define FTDI_RI (1<<6) // RI line status#define FTDI_RLSD (1<<7) // Receive Line Signal Detect/* Status */#define FTDI_DR (1<<0) // Data Ready#define FTDI_OE (1<<1) // Overrun Err#define FTDI_PE (1<<2) // Parity Err#define FTDI_FE (1<<3) // Framing Err#define FTDI_BI (1<<4) // Break Interrupt#define FTDI_THRE (1<<5) // Transmitter Holding Register#define FTDI_TEMT (1<<6) // Transmitter Empty#define FTDI_FIFO (1<<7) // Error in FIFOtypedef struct { USBDevice dev; uint16_t vendorid; uint16_t productid; uint8_t recv_buf[RECV_BUF]; uint8_t recv_ptr; uint8_t recv_used; uint8_t send_buf[SEND_BUF]; uint8_t event_chr; uint8_t error_chr; uint8_t event_trigger; uint8_t lines; QEMUSerialSetParams params; int latency; /* ms */ CharDriverState *cs;} USBSerialState;static const uint8_t qemu_serial_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ 0x00, 0x02, /* u16 bcdUSB; v2.0 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ /* Vendor and product id are arbitrary. */ 0x03, 0x04, /* u16 idVendor; */ 0x00, 0xFF, /* u16 idProduct; */ 0x00, 0x04, /* u16 bcdDevice */ 0x01, /* u8 iManufacturer; */ 0x02, /* u8 iProduct; */ 0x03, /* u8 iSerialNumber; */ 0x01 /* u8 bNumConfigurations; */};static const uint8_t qemu_serial_config_descriptor[] = { /* one configuration */ 0x09, /* u8 bLength; */ 0x02, /* u8 bDescriptorType; Configuration */ 0x20, 0x00, /* u16 wTotalLength; */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ 0x80, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 100/2, /* u8 MaxPower; */ /* one interface */ 0x09, /* u8 if_bLength; */ 0x04, /* u8 if_bDescriptorType; Interface */ 0x00, /* u8 if_bInterfaceNumber; */ 0x00, /* u8 if_bAlternateSetting; */ 0x02, /* u8 if_bNumEndpoints; */ 0xff, /* u8 if_bInterfaceClass; Vendor Specific */ 0xff, /* u8 if_bInterfaceSubClass; Vendor Specific */ 0xff, /* u8 if_bInterfaceProtocol; Vendor Specific */ 0x02, /* u8 if_iInterface; */ /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ /* Bulk-Out endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00 /* u8 ep_bInterval; */};static void usb_serial_reset(USBSerialState *s){ /* TODO: Set flow control to none */ s->event_chr = 0x0d; s->event_trigger = 0; s->recv_ptr = 0; s->recv_used = 0; /* TODO: purge in char driver */ s->lines &= ~(FTDI_DTR|FTDI_RTS);}static void usb_serial_handle_reset(USBDevice *dev){ USBSerialState *s = (USBSerialState *)dev; DPRINTF("Reset\n"); usb_serial_reset(s); /* TODO: Reset char device, send BREAK? */}static int usb_serial_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data){ USBSerialState *s = (USBSerialState *)dev; int ret = 0; //DPRINTF("got control %x, value %x\n",request, value); switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (0 << USB_DEVICE_SELF_POWERED) | (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); data[1] = 0x00; ret = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 0; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 1; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: dev->addr = value; ret = 0; break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case USB_DT_DEVICE: memcpy(data, qemu_serial_dev_descriptor, sizeof(qemu_serial_dev_descriptor)); data[8] = s->vendorid & 0xff; data[9] = ((s->vendorid) >> 8) & 0xff; data[10] = s->productid & 0xff; data[11] = ((s->productid) >> 8) & 0xff; ret = sizeof(qemu_serial_dev_descriptor); break; case USB_DT_CONFIG: memcpy(data, qemu_serial_config_descriptor, sizeof(qemu_serial_config_descriptor)); ret = sizeof(qemu_serial_config_descriptor); break; case USB_DT_STRING: switch(value & 0xff) { case 0: /* language ids */ data[0] = 4; data[1] = 3; data[2] = 0x09; data[3] = 0x04; ret = 4; break; case 1: /* vendor description */ ret = set_usb_string(data, "QEMU " QEMU_VERSION); break; case 2: /* product description */ ret = set_usb_string(data, "QEMU USB SERIAL"); break; case 3: /* serial number */ ret = set_usb_string(data, "1"); break; default: goto fail; } break; default: goto fail; } break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -