?? linux_usbfs.c
字號:
usbi_err(TRANSFER_CTX(transfer), "submiturb failed error %d errno=%d", r, errno); return LIBUSB_ERROR_IO; } return 0;}static int op_submit_transfer(struct usbi_transfer *itransfer){ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: return submit_control_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_BULK: return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK); case LIBUSB_TRANSFER_TYPE_INTERRUPT: return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT); case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return submit_iso_transfer(itransfer); default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; }}static int cancel_control_transfer(struct usbi_transfer *itransfer){ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); int r; tpriv->reap_action = CANCELLED; r = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->urbs); if(r) { if (errno == EINVAL) { usbi_dbg("URB not found --> assuming ready to be reaped"); return 0; } else { usbi_err(TRANSFER_CTX(transfer), "unrecognised DISCARD code %d", errno); return LIBUSB_ERROR_OTHER; } } return 0;}static void cancel_bulk_transfer(struct usbi_transfer *itransfer){ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); int i; tpriv->reap_action = CANCELLED; tpriv->awaiting_reap = 0; tpriv->awaiting_discard = 0; for (i = 0; i < tpriv->num_urbs; i++) { int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[i]); if (tmp == 0) tpriv->awaiting_discard++; else if (errno == EINVAL) tpriv->awaiting_reap++; else usbi_warn(TRANSFER_CTX(transfer), "unrecognised discard return %d", errno); }}static void cancel_iso_transfer(struct usbi_transfer *itransfer){ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); int i; tpriv->reap_action = CANCELLED; tpriv->awaiting_reap = 0; tpriv->awaiting_discard = 0; for (i = 0; i < tpriv->num_urbs; i++) { int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->iso_urbs[i]); if (tmp == 0) tpriv->awaiting_discard++; else if (errno == EINVAL) tpriv->awaiting_reap++; else usbi_warn(TRANSFER_CTX(transfer), "unrecognised discard return %d", errno); }}static int op_cancel_transfer(struct usbi_transfer *itransfer){ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: return cancel_control_transfer(itransfer); case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: cancel_bulk_transfer(itransfer); return 0; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: cancel_iso_transfer(itransfer); return 0; default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; }}static void op_clear_transfer_priv(struct usbi_transfer *itransfer){ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_CONTROL: case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: free(tpriv->urbs); break; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: free_iso_urbs(tpriv); break; default: usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); }}static int handle_bulk_completion(struct usbi_transfer *itransfer, struct usbfs_urb *urb){ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); int num_urbs = tpriv->num_urbs; int urb_idx = urb - tpriv->urbs; enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED; usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status, urb_idx + 1, num_urbs); if (urb->status == 0 || (urb->status == -EOVERFLOW && urb->actual_length > 0)) itransfer->transferred += urb->actual_length; if (tpriv->reap_action != NORMAL) { /* cancelled, submit_fail, or completed early */ if (urb->status == -ENOENT) { usbi_dbg("CANCEL: detected a cancelled URB"); if (tpriv->awaiting_discard == 0) usbi_err(ITRANSFER_CTX(itransfer), "CANCEL: cancelled URB but not awaiting discards?"); else tpriv->awaiting_discard--; } else if (urb->status == 0) { usbi_dbg("CANCEL: detected a completed URB"); /* FIXME we could solve this extreme corner case with a memmove * or something */ if (tpriv->reap_action == COMPLETED_EARLY) usbi_warn(ITRANSFER_CTX(itransfer), "SOME DATA LOST! " "(completed early but remaining urb completed)"); if (tpriv->awaiting_reap == 0) usbi_err(ITRANSFER_CTX(itransfer), "CANCEL: completed URB not awaiting reap?"); else tpriv->awaiting_reap--; } else if (urb->status == -EPIPE || urb->status == -EOVERFLOW) { if (tpriv->awaiting_reap == 0) usbi_err(ITRANSFER_CTX(itransfer), "CANCEL: completed URB not awaiting reap?"); else tpriv->awaiting_reap--; } else { usbi_warn(ITRANSFER_CTX(itransfer), "unhandled CANCEL urb status %d", urb->status); } if (tpriv->awaiting_reap == 0 && tpriv->awaiting_discard == 0) { usbi_dbg("CANCEL: last URB handled, reporting"); if (tpriv->reap_action == CANCELLED) { free(tpriv->urbs); usbi_handle_transfer_cancellation(itransfer); return 0; } else if (tpriv->reap_action == COMPLETED_EARLY) { goto out; } else { status = LIBUSB_TRANSFER_ERROR; goto out; } } return 0; } if (urb->status == -EPIPE) { usbi_dbg("detected endpoint stall"); status = LIBUSB_TRANSFER_STALL; goto out; } else if (urb->status == -EOVERFLOW) { /* overflow can only ever occur in the last urb */ usbi_dbg("overflow, actual_length=%d", urb->actual_length); status = LIBUSB_TRANSFER_OVERFLOW; goto out; } else if (urb->status != 0) { usbi_warn(ITRANSFER_CTX(itransfer), "unrecognised urb status %d", urb->status); } /* if we're the last urb or we got less data than requested then we're * done */ if (urb_idx == num_urbs - 1) { usbi_dbg("last URB in transfer --> complete!"); } else if (urb->actual_length < urb->buffer_length) { struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); int i; usbi_dbg("short transfer %d/%d --> complete!", urb->actual_length, urb->buffer_length); /* we have to cancel the remaining urbs and wait for their completion * before reporting results */ tpriv->reap_action = COMPLETED_EARLY; for (i = urb_idx + 1; i < tpriv->num_urbs; i++) { int r = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[i]); if (r == 0) tpriv->awaiting_discard++; else if (errno == EINVAL) tpriv->awaiting_reap++; else usbi_warn(ITRANSFER_CTX(itransfer), "unrecognised discard return %d", errno); } return 0; } else { return 0; }out: free(tpriv->urbs); usbi_handle_transfer_completion(itransfer, status); return 0;}static int handle_iso_completion(struct usbi_transfer *itransfer, struct usbfs_urb *urb){ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); int num_urbs = tpriv->num_urbs; int urb_idx = 0; int i; for (i = 0; i < num_urbs; i++) { if (urb == tpriv->iso_urbs[i]) { urb_idx = i + 1; break; } } if (urb_idx == 0) { usbi_err(TRANSFER_CTX(transfer), "could not locate urb!"); return LIBUSB_ERROR_NOT_FOUND; } usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status, urb_idx, num_urbs); if (urb->status == 0) { /* copy isochronous results back in */ for (i = 0; i < urb->number_of_packets; i++) { struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i]; struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[tpriv->iso_packet_offset++]; lib_desc->status = urb_desc->status; lib_desc->actual_length = urb_desc->actual_length; } } if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */ if (urb->status == -ENOENT) { usbi_dbg("CANCEL: detected a cancelled URB"); if (tpriv->awaiting_discard == 0) usbi_err(TRANSFER_CTX(transfer), "CANCEL: cancelled URB but not awaiting discards?"); else tpriv->awaiting_discard--; } else if (urb->status == 0) { usbi_dbg("CANCEL: detected a completed URB"); if (tpriv->awaiting_reap == 0) usbi_err(TRANSFER_CTX(transfer), "CANCEL: completed URB not awaiting reap?"); else tpriv->awaiting_reap--; } else { usbi_warn(TRANSFER_CTX(transfer), "unhandled CANCEL urb status %d", urb->status); } if (tpriv->awaiting_reap == 0 && tpriv->awaiting_discard == 0) { usbi_dbg("CANCEL: last URB handled, reporting"); free_iso_urbs(tpriv); if (tpriv->reap_action == CANCELLED) usbi_handle_transfer_cancellation(itransfer); else usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_ERROR); } return 0; } if (urb->status != 0) usbi_warn(TRANSFER_CTX(transfer), "unrecognised urb status %d", urb->status); /* if we're the last urb or we got less data than requested then we're * done */ if (urb_idx == num_urbs) { usbi_dbg("last URB in transfer --> complete!"); free_iso_urbs(tpriv); usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED); } return 0;}static int handle_control_completion(struct usbi_transfer *itransfer, struct usbfs_urb *urb){ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); int status; usbi_dbg("handling completion status %d", urb->status); if (urb->status == 0) itransfer->transferred += urb->actual_length; if (tpriv->reap_action == CANCELLED) { if (urb->status != 0 && urb->status != -ENOENT) usbi_warn(ITRANSFER_CTX(itransfer), "cancel: unrecognised urb status %d", urb->status); free(tpriv->urbs); usbi_handle_transfer_cancellation(itransfer); return 0; } if (urb->status == -EPIPE) { usbi_dbg("unsupported control request"); status = LIBUSB_TRANSFER_STALL; goto out; } else if (urb->status != 0) { usbi_warn(ITRANSFER_CTX(itransfer), "unrecognised urb status %d", urb->status); status = LIBUSB_TRANSFER_ERROR; goto out; } itransfer->transferred = urb->actual_length; status = LIBUSB_TRANSFER_COMPLETED;out: free(tpriv->urbs); usbi_handle_transfer_completion(itransfer, status); return 0;}static int reap_for_handle(struct libusb_device_handle *handle){ struct linux_device_handle_priv *hpriv = __device_handle_priv(handle); int r; struct usbfs_urb *urb; struct usbi_transfer *itransfer; struct libusb_transfer *transfer; r = ioctl(hpriv->fd, IOCTL_USBFS_REAPURBNDELAY, &urb); if (r == -1 && errno == EAGAIN) return 1; if (r < 0) { if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d", r, errno); return LIBUSB_ERROR_IO; } itransfer = urb->usercontext; transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status, urb->actual_length); switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return handle_iso_completion(itransfer, urb); case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: return handle_bulk_completion(itransfer, urb); case LIBUSB_TRANSFER_TYPE_CONTROL: return handle_control_completion(itransfer, urb); default: usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x", transfer->type); return LIBUSB_ERROR_OTHER; }}static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready){ int r; int i = 0; pthread_mutex_lock(&ctx->open_devs_lock); for (i = 0; i < nfds && num_ready > 0; i++) { struct pollfd *pollfd = &fds[i]; struct libusb_device_handle *handle; struct linux_device_handle_priv *hpriv = NULL; if (!pollfd->revents) continue; num_ready--; list_for_each_entry(handle, &ctx->open_devs, list) { hpriv = __device_handle_priv(handle); if (hpriv->fd == pollfd->fd) break; } if (pollfd->revents & POLLERR) { usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); usbi_handle_disconnect(handle); continue; } r = reap_for_handle(handle); if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE) continue; else if (r < 0) goto out; } r = 0;out: pthread_mutex_unlock(&ctx->open_devs_lock); return r;}const struct usbi_os_backend linux_usbfs_backend = { .name = "Linux usbfs", .init = op_init, .exit = NULL, .get_device_list = op_get_device_list, .get_device_descriptor = op_get_device_descriptor, .get_active_config_descriptor = op_get_active_config_descriptor, .get_config_descriptor = op_get_config_descriptor, .open = op_open, .close = op_close, .get_configuration = op_get_configuration, .set_configuration = op_set_configuration, .claim_interface = op_claim_interface, .release_interface = op_release_interface, .set_interface_altsetting = op_set_interface, .clear_halt = op_clear_halt, .reset_device = op_reset_device, .kernel_driver_active = op_kernel_driver_active, .detach_kernel_driver = op_detach_kernel_driver, .destroy_device = op_destroy_device, .submit_transfer = op_submit_transfer, .cancel_transfer = op_cancel_transfer, .clear_transfer_priv = op_clear_transfer_priv, .handle_events = op_handle_events, .device_priv_size = sizeof(struct linux_device_priv), .device_handle_priv_size = sizeof(struct linux_device_handle_priv), .transfer_priv_size = sizeof(struct linux_transfer_priv), .add_iso_packet_size = 0,};
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -