📄 usb-serial.c
字号:
ret = 1; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ret = 0; break; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; break; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ret = 0; break; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ret = 0; break; /* Class specific requests. */ case DeviceOutVendor | FTDI_RESET: switch (value) { case FTDI_RESET_SIO: usb_serial_reset(s); break; case FTDI_RESET_RX: s->recv_ptr = 0; s->recv_used = 0; /* TODO: purge from char device */ break; case FTDI_RESET_TX: /* TODO: purge from char device */ break; } break; case DeviceOutVendor | FTDI_SET_MDM_CTRL: s->lines = value & FTDI_MDM_CTRL; break; case DeviceOutVendor | FTDI_SET_FLOW_CTRL: /* TODO: ioctl */ break; case DeviceOutVendor | FTDI_SET_BAUD: { static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 }; int subdivisor8 = subdivisors8[((value & 0xc000) >> 14) | ((index & 1) << 2)]; int divisor = value & 0x3fff; /* chip special cases */ if (divisor == 1 && subdivisor8 == 0) subdivisor8 = 4; if (divisor == 0 && subdivisor8 == 0) divisor = 1; s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8); qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); break; } case DeviceOutVendor | FTDI_SET_DATA: switch (value & FTDI_PARITY) { case 0: s->params.parity = 'N'; break; case FTDI_ODD: s->params.parity = 'O'; break; case FTDI_EVEN: s->params.parity = 'E'; break; default: DPRINTF("unsupported parity %d\n", value & FTDI_PARITY); goto fail; } switch (value & FTDI_STOP) { case FTDI_STOP1: s->params.stop_bits = 1; break; case FTDI_STOP2: s->params.stop_bits = 2; break; default: DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP); goto fail; } qemu_chr_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); /* TODO: TX ON/OFF */ break; case DeviceInVendor | FTDI_GET_MDM_ST: /* TODO: return modem status */ data[0] = 0; ret = 1; break; case DeviceOutVendor | FTDI_SET_EVENT_CHR: /* TODO: handle it */ s->event_chr = value; break; case DeviceOutVendor | FTDI_SET_ERROR_CHR: /* TODO: handle it */ s->error_chr = value; break; case DeviceOutVendor | FTDI_SET_LATENCY: s->latency = value; break; case DeviceInVendor | FTDI_GET_LATENCY: data[0] = s->latency; ret = 1; break; default: fail: DPRINTF("got unsupported/bogus control %x, value %x\n", request, value); ret = USB_RET_STALL; break; } return ret;}static int usb_serial_handle_data(USBDevice *dev, USBPacket *p){ USBSerialState *s = (USBSerialState *)dev; int ret = 0; uint8_t devep = p->devep; uint8_t *data = p->data; int len = p->len; int first_len; switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) goto fail; qemu_chr_write(s->cs, data, len); break; case USB_TOKEN_IN: if (devep != 1) goto fail; first_len = RECV_BUF - s->recv_ptr; if (len <= 2) { ret = USB_RET_NAK; break; } /* TODO: Report serial line status */ *data++ = 0; *data++ = 0; len -= 2; if (len > s->recv_used) len = s->recv_used; if (!len) { ret = USB_RET_NAK; break; } if (first_len > len) first_len = len; memcpy(data, s->recv_buf + s->recv_ptr, first_len); if (len > first_len) memcpy(data + first_len, s->recv_buf, len - first_len); s->recv_used -= len; s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; ret = len + 2; break; default: DPRINTF("Bad token\n"); fail: ret = USB_RET_STALL; break; } return ret;}static void usb_serial_handle_destroy(USBDevice *dev){ USBSerialState *s = (USBSerialState *)dev; qemu_chr_close(s->cs); qemu_free(s);}int usb_serial_can_read(void *opaque){ USBSerialState *s = opaque; return RECV_BUF - s->recv_used;}void usb_serial_read(void *opaque, const uint8_t *buf, int size){ USBSerialState *s = opaque; int first_size = RECV_BUF - s->recv_ptr; if (first_size > size) first_size = size; memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size); if (size > first_size) memcpy(s->recv_buf, buf + first_size, size - first_size); s->recv_used += size;}void usb_serial_event(void *opaque, int event){ USBSerialState *s = opaque; switch (event) { case CHR_EVENT_BREAK: /* TODO: Send Break to USB */ break; case CHR_EVENT_FOCUS: break; case CHR_EVENT_RESET: usb_serial_reset(s); /* TODO: Reset USB port */ break; }}USBDevice *usb_serial_init(const char *filename){ USBSerialState *s; CharDriverState *cdrv; unsigned short vendorid = 0x0403, productid = 0x6001; while (*filename && *filename != ':') { const char *p; char *e; if (strstart(filename, "vendorid=", &p)) { vendorid = strtol(p, &e, 16); if (e == p || (*e && *e != ',' && *e != ':')) { printf("bogus vendor ID %s\n", p); return NULL; } filename = e; } else if (strstart(filename, "productid=", &p)) { productid = strtol(p, &e, 16); if (e == p || (*e && *e != ',' && *e != ':')) { printf("bogus product ID %s\n", p); return NULL; } filename = e; } else { printf("unrecognized serial USB option %s\n", filename); return NULL; } while(*filename == ',') filename++; } if (!*filename) { printf("character device specification needed\n"); return NULL; } filename++; s = qemu_mallocz(sizeof(USBSerialState)); if (!s) return NULL; cdrv = qemu_chr_open(filename); if (!cdrv) goto fail; s->cs = cdrv; qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s); s->dev.speed = USB_SPEED_FULL; s->dev.handle_packet = usb_generic_handle_packet; s->dev.handle_reset = usb_serial_handle_reset; s->dev.handle_control = usb_serial_handle_control; s->dev.handle_data = usb_serial_handle_data; s->dev.handle_destroy = usb_serial_handle_destroy; s->vendorid = vendorid; s->productid = productid; snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)", filename); usb_serial_handle_reset((USBDevice *)s); return (USBDevice *)s; fail: qemu_free(s); return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -