static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) { MSDState *s = (MSDState *)dev; int ret = 0; struct usb_msd_cbw cbw; uint8_t devep = p->devep; uint8_t *data = p->data; int len = p->len; switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) goto fail; switch (s->mode) { case USB_MSDM_CBW: if (len != 31) { fprintf(stderr, "usb-msd: Bad CBW size"); goto fail; } memcpy(&cbw, data, 31); if (le32_to_cpu(cbw.sig) != 0x43425355) { fprintf(stderr, "usb-msd: Bad signature %08x\n", le32_to_cpu(cbw.sig)); goto fail; } DPRINTF("Command on LUN %d\n", cbw.lun); if (cbw.lun != 0) { fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); goto fail; } s->tag = le32_to_cpu(cbw.tag); s->data_len = le32_to_cpu(cbw.data_len); if (s->data_len == 0) { s->mode = USB_MSDM_CSW; } else if (cbw.flags & 0x80) { s->mode = USB_MSDM_DATAIN; } else { s->mode = USB_MSDM_DATAOUT; } DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); /* ??? Should check that USB and SCSI data transfer directions match. */ if (s->residue == 0) { if (s->mode == USB_MSDM_DATAIN) { scsi_read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { scsi_write_data(s->scsi_dev, s->tag); } } ret = len; break; case USB_MSDM_DATAOUT: DPRINTF("Data out %d/%d\n", len, s->data_len); if (len > s->data_len) goto fail; s->usb_buf = data; s->usb_len = len; if (s->scsi_len) { usb_msd_copy_data(s); } if (s->residue && s->usb_len) { s->data_len -= s->usb_len; if (s->data_len == 0) s->mode = USB_MSDM_CSW; s->usb_len = 0; } if (s->usb_len) { DPRINTF("Deferring packet %p\n", p); usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; } else { ret = len; } break; default: DPRINTF("Unexpected write (len %d)\n", len); goto fail; } break; case USB_TOKEN_IN: if (devep != 1) goto fail; switch (s->mode) { case USB_MSDM_DATAOUT: if (s->data_len != 0 || len < 13) goto fail; /* Waiting for SCSI write to complete. */ usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; break; case USB_MSDM_CSW: DPRINTF("Command status %d tag 0x%x, len %d\n", s->result, s->tag, len); if (len < 13) goto fail; s->usb_len = len; s->usb_buf = data; usb_msd_send_status(s); s->mode = USB_MSDM_CBW; ret = 13; break; case USB_MSDM_DATAIN: DPRINTF("Data in %d/%d\n", len, s->data_len); if (len > s->data_len) len = s->data_len; s->usb_buf = data; s->usb_len = len; if (s->scsi_len) { usb_msd_copy_data(s); } if (s->residue && s->usb_len) { s->data_len -= s->usb_len; memset(s->usb_buf, 0, s->usb_len); if (s->data_len == 0) s->mode = USB_MSDM_CSW; s->usb_len = 0; } if (s->usb_len) { DPRINTF("Deferring packet %p\n", p); usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; } else { ret = len; } break; default: DPRINTF("Unexpected read (len %d)\n", len); goto fail; } break; default: DPRINTF("Bad token\n"); fail: ret = USB_RET_STALL; break; } return ret; }
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p) { struct usbdevfs_urb *urb; AsyncURB *aurb; int ret; aurb = async_alloc(); if (!aurb) { dprintf("husb: async malloc failed\n"); return USB_RET_NAK; } aurb->hdev = s; aurb->packet = p; urb = &aurb->urb; if (p->pid == USB_TOKEN_IN) urb->endpoint = p->devep | 0x80; else urb->endpoint = p->devep; if (is_halted(s, p->devep)) { ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint); if (ret < 0) { dprintf("husb: failed to clear halt. ep 0x%x errno %d\n", urb->endpoint, errno); return USB_RET_NAK; } clear_halt(s, p->devep); } urb->buffer = p->data; urb->buffer_length = p->len; if (is_isoc(s, p->devep)) { /* Setup ISOC transfer */ urb->type = USBDEVFS_URB_TYPE_ISO; urb->flags = USBDEVFS_URB_ISO_ASAP; urb->number_of_packets = 1; urb->iso_frame_desc[0].length = p->len; } else { /* Setup bulk transfer */ urb->type = USBDEVFS_URB_TYPE_BULK; } urb->usercontext = s; ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); dprintf("husb: data submit. ep 0x%x len %u aurb %p\n", urb->endpoint, p->len, aurb); if (ret < 0) { dprintf("husb: submit failed. errno %d\n", errno); async_free(aurb); switch(errno) { case ETIMEDOUT: return USB_RET_NAK; case EPIPE: default: return USB_RET_STALL; } } usb_defer_packet(p, async_cancel, aurb); return USB_RET_ASYNC; }
static int usb_host_handle_control(USBHostDevice *s, USBPacket *p) { struct usbdevfs_urb *urb; AsyncURB *aurb; int ret, value, index; /* * Process certain standard device requests. * These are infrequent and are processed synchronously. */ value = le16_to_cpu(s->ctrl.req.wValue); index = le16_to_cpu(s->ctrl.req.wIndex); dprintf("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n", s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index, s->ctrl.len); if (s->ctrl.req.bRequestType == 0) { switch (s->ctrl.req.bRequest) { case USB_REQ_SET_ADDRESS: return usb_host_set_address(s, value); case USB_REQ_SET_CONFIGURATION: return usb_host_set_config(s, value & 0xff); } } if (s->ctrl.req.bRequestType == 1 && s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) return usb_host_set_interface(s, index, value); /* The rest are asynchronous */ aurb = async_alloc(); if (!aurb) { dprintf("husb: async malloc failed\n"); return USB_RET_NAK; } aurb->hdev = s; aurb->packet = p; /* * Setup ctrl transfer. * * s->ctrl is layed out such that data buffer immediately follows * 'req' struct which is exactly what usbdevfs expects. */ urb = &aurb->urb; urb->type = USBDEVFS_URB_TYPE_CONTROL; urb->endpoint = p->devep; urb->buffer = &s->ctrl.req; urb->buffer_length = 8 + s->ctrl.len; urb->usercontext = s; ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); dprintf("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb); if (ret < 0) { dprintf("husb: submit failed. errno %d\n", errno); async_free(aurb); switch(errno) { case ETIMEDOUT: return USB_RET_NAK; case EPIPE: default: return USB_RET_STALL; } } usb_defer_packet(p, async_cancel, aurb); return USB_RET_ASYNC; }
int usb_msd_device_c::handle_data(USBPacket *p) { struct usb_msd_cbw cbw; int ret = 0; Bit8u devep = p->devep; Bit8u *data = p->data; int len = p->len; switch (p->pid) { case USB_TOKEN_OUT: usb_dump_packet(data, len); if (devep != 2) goto fail; switch (s.mode) { case USB_MSDM_CBW: if (len != 31) { BX_ERROR(("bad CBW len")); goto fail; } memcpy(&cbw, data, 31); if (dtoh32(cbw.sig) != 0x43425355) { BX_ERROR(("bad signature %08x", dtoh32(cbw.sig))); goto fail; } BX_DEBUG(("command on LUN %d", cbw.lun)); s.tag = dtoh32(cbw.tag); s.data_len = dtoh32(cbw.data_len); if (s.data_len == 0) { s.mode = USB_MSDM_CSW; } else if (cbw.flags & 0x80) { s.mode = USB_MSDM_DATAIN; } else { s.mode = USB_MSDM_DATAOUT; } BX_DEBUG(("command tag 0x%x flags %08x len %d data %d", s.tag, cbw.flags, cbw.cmd_len, s.data_len)); s.residue = 0; s.scsi_dev->scsi_send_command(s.tag, cbw.cmd, cbw.lun); if (s.residue == 0) { if (s.mode == USB_MSDM_DATAIN) { s.scsi_dev->scsi_read_data(s.tag); } else if (s.mode == USB_MSDM_DATAOUT) { s.scsi_dev->scsi_write_data(s.tag); } } ret = len; break; case USB_MSDM_DATAOUT: BX_DEBUG(("data out %d/%d", len, s.data_len)); if (len > (int)s.data_len) goto fail; s.usb_buf = data; s.usb_len = len; if (s.scsi_len) { copy_data(); } if (s.residue && s.usb_len) { s.data_len -= s.usb_len; if (s.data_len == 0) s.mode = USB_MSDM_CSW; s.usb_len = 0; } if (s.usb_len) { BX_INFO(("deferring packet %p", p)); usb_defer_packet(p, this); s.packet = p; ret = USB_RET_ASYNC; } else { ret = len; } break; default: BX_ERROR(("USB MSD handle_data: unexpected mode at USB_TOKEN_OUT")); goto fail; } break; case USB_TOKEN_IN: if (devep != 1) goto fail; switch (s.mode) { case USB_MSDM_DATAOUT: if ((s.data_len > 0) && (len == 13)) { s.usb_len = len; s.usb_buf = data; send_status(); ret = 13; break; } if (s.data_len != 0 || len < 13) goto fail; usb_defer_packet(p, this); s.packet = p; ret = USB_RET_ASYNC; break; case USB_MSDM_CSW: BX_DEBUG(("command status %d tag 0x%x, len %d", s.result, s.tag, len)); if (len < 13) return ret; s.usb_len = len; s.usb_buf = data; send_status(); s.mode = USB_MSDM_CBW; ret = 13; break; case USB_MSDM_DATAIN: BX_DEBUG(("data in %d/%d", len, s.data_len)); if (len > (int)s.data_len) len = s.data_len; s.usb_buf = data; s.usb_len = len; if (s.scsi_len) { copy_data(); } if (s.residue && s.usb_len) { s.data_len -= s.usb_len; memset(s.usb_buf, 0, s.usb_len); if (s.data_len == 0) s.mode = USB_MSDM_CSW; s.usb_len = 0; } if (s.usb_len) { BX_INFO(("deferring packet %p", p)); usb_defer_packet(p, this); s.packet = p; ret = USB_RET_ASYNC; } else { ret = len; } break; default: BX_ERROR(("USB MSD handle_data: unexpected mode at USB_TOKEN_IN")); goto fail; } if (ret > 0) usb_dump_packet(data, ret); break; default: BX_ERROR(("USB MSD handle_data: bad token")); fail: d.stall = 1; ret = USB_RET_STALL; break; } return ret; }