?? linux_usbfs.c
字號(hào):
if (*config == -1) *config = 0; return 0;}static int op_set_configuration(struct libusb_device_handle *handle, int config){ struct linux_device_priv *priv = __device_priv(handle->dev); int fd = __device_handle_priv(handle)->fd; int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config); if (r) { if (errno == EINVAL) return LIBUSB_ERROR_NOT_FOUND; else if (errno == EBUSY) return LIBUSB_ERROR_BUSY; else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } if (!sysfs_has_descriptors) { /* update our cached active config descriptor */ if (config == -1) { if (priv->config_descriptor) { free(priv->config_descriptor); priv->config_descriptor = NULL; } } else { r = cache_active_config(handle->dev, fd, config); if (r < 0) usbi_warn(HANDLE_CTX(handle), "failed to update cached config descriptor, error %d", r); } } return 0;}static int op_claim_interface(struct libusb_device_handle *handle, int iface){ int fd = __device_handle_priv(handle)->fd; int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface); if (r) { if (errno == ENOENT) return LIBUSB_ERROR_NOT_FOUND; else if (errno == EBUSY) return LIBUSB_ERROR_BUSY; else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "claim interface failed, error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0;}static int op_release_interface(struct libusb_device_handle *handle, int iface){ int fd = __device_handle_priv(handle)->fd; int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface); if (r) { if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "release interface failed, error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0;}static int op_set_interface(struct libusb_device_handle *handle, int iface, int altsetting){ int fd = __device_handle_priv(handle)->fd; struct usbfs_setinterface setintf; int r; setintf.interface = iface; setintf.altsetting = altsetting; r = ioctl(fd, IOCTL_USBFS_SETINTF, &setintf); if (r) { if (errno == EINVAL) return LIBUSB_ERROR_NOT_FOUND; else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "setintf failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0;}static int op_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint){ int fd = __device_handle_priv(handle)->fd; unsigned int _endpoint = endpoint; int r = ioctl(fd, IOCTL_USBFS_CLEAR_HALT, &_endpoint); if (r) { if (errno == ENOENT) return LIBUSB_ERROR_NOT_FOUND; else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "clear_halt failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0;}static int op_reset_device(struct libusb_device_handle *handle){ int fd = __device_handle_priv(handle)->fd; int r = ioctl(fd, IOCTL_USBFS_RESET, NULL); if (r) { if (errno == ENODEV) return LIBUSB_ERROR_NOT_FOUND; usbi_err(HANDLE_CTX(handle), "reset failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0;}static int op_kernel_driver_active(struct libusb_device_handle *handle, int interface){ int fd = __device_handle_priv(handle)->fd; struct usbfs_getdriver getdrv; int r; getdrv.interface = interface; r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv); if (r) { if (errno == ENODATA) return 0; else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "get driver failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 1;}static int op_detach_kernel_driver(struct libusb_device_handle *handle, int interface){ int fd = __device_handle_priv(handle)->fd; struct usbfs_ioctl command; int r; command.ifno = interface; command.ioctl_code = IOCTL_USBFS_DISCONNECT; command.data = NULL; r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); if (r) { if (errno == ENODATA) return LIBUSB_ERROR_NOT_FOUND; else if (errno == EINVAL) return LIBUSB_ERROR_INVALID_PARAM; else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(HANDLE_CTX(handle), "detach failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0;}static void op_destroy_device(struct libusb_device *dev){ struct linux_device_priv *priv = __device_priv(dev); if (!sysfs_has_descriptors) { if (priv->dev_descriptor) free(priv->dev_descriptor); if (priv->config_descriptor) free(priv->config_descriptor); } if (priv->sysfs_dir) free(priv->sysfs_dir);}static void free_iso_urbs(struct linux_transfer_priv *tpriv){ int i; for (i = 0; i < tpriv->num_urbs; i++) { struct usbfs_urb *urb = tpriv->iso_urbs[i]; if (!urb) break; free(urb); } free(tpriv->iso_urbs);}static int submit_bulk_transfer(struct usbi_transfer *itransfer, unsigned char urb_type){ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); struct usbfs_urb *urbs; int r; int i; size_t alloc_size; /* usbfs places a 16kb limit on bulk URBs. we divide up larger requests * into smaller units to meet such restriction, then fire off all the * units at once. it would be simpler if we just fired one unit at a time, * but there is a big performance gain through doing it this way. */ int num_urbs = transfer->length / MAX_BULK_BUFFER_LENGTH; int last_urb_partial = 0; if ((transfer->length % MAX_BULK_BUFFER_LENGTH) > 0) { last_urb_partial = 1; num_urbs++; } usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, transfer->length); alloc_size = num_urbs * sizeof(struct usbfs_urb); urbs = malloc(alloc_size); if (!urbs) return LIBUSB_ERROR_NO_MEM; memset(urbs, 0, alloc_size); tpriv->urbs = urbs; tpriv->num_urbs = num_urbs; tpriv->awaiting_discard = 0; tpriv->awaiting_reap = 0; tpriv->reap_action = NORMAL; for (i = 0; i < num_urbs; i++) { struct usbfs_urb *urb = &urbs[i]; urb->usercontext = itransfer; urb->type = urb_type; urb->endpoint = transfer->endpoint; urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH); if (i == num_urbs - 1 && last_urb_partial) urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH; else urb->buffer_length = MAX_BULK_BUFFER_LENGTH; r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); if (r < 0) { int j; if (errno == ENODEV) { r = LIBUSB_ERROR_NO_DEVICE; } else { usbi_err(TRANSFER_CTX(transfer), "submiturb failed error %d errno=%d", r, errno); r = LIBUSB_ERROR_IO; } /* if the first URB submission fails, we can simply free up and * return failure immediately. */ if (i == 0) { usbi_dbg("first URB failed, easy peasy"); free(urbs); return r; } /* if it's not the first URB that failed, the situation is a bit * tricky. we must discard all previous URBs. there are * complications: * - discarding is asynchronous - discarded urbs will be reaped * later. the user must not have freed the transfer when the * discarded URBs are reaped, otherwise libusb will be using * freed memory. * - the earlier URBs may have completed successfully and we do * not want to throw away any data. * so, in this case we discard all the previous URBs BUT we report * that the transfer was submitted successfully. then later when * the final discard completes we can report error to the user. */ tpriv->reap_action = SUBMIT_FAILED; for (j = 0; j < i; j++) { int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &urbs[j]); if (tmp == 0) tpriv->awaiting_discard++; else if (errno == EINVAL) tpriv->awaiting_reap++; else usbi_warn(TRANSFER_CTX(transfer), "unrecognised discard return %d", tmp); } usbi_dbg("reporting successful submission but waiting for %d " "discards and %d reaps before reporting error", tpriv->awaiting_discard, tpriv->awaiting_reap); return 0; } } return 0;}static int submit_iso_transfer(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); struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); struct usbfs_urb **urbs; size_t alloc_size; int num_packets = transfer->num_iso_packets; int i; int this_urb_len = 0; int num_urbs = 1; int packet_offset = 0; unsigned int packet_len; unsigned char *urb_buffer = transfer->buffer; /* usbfs places a 32kb limit on iso URBs. we divide up larger requests * into smaller units to meet such restriction, then fire off all the * units at once. it would be simpler if we just fired one unit at a time, * but there is a big performance gain through doing it this way. */ /* calculate how many URBs we need */ for (i = 0; i < num_packets; i++) { int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len; packet_len = transfer->iso_packet_desc[i].length; if (packet_len > space_remaining) { num_urbs++; this_urb_len = packet_len; } else { this_urb_len += packet_len; } } usbi_dbg("need %d 32k URBs for transfer", num_urbs); alloc_size = num_urbs * sizeof(*urbs); urbs = malloc(alloc_size); if (!urbs) return LIBUSB_ERROR_NO_MEM; memset(urbs, 0, alloc_size); tpriv->iso_urbs = urbs; tpriv->num_urbs = num_urbs; tpriv->awaiting_discard = 0; tpriv->awaiting_reap = 0; tpriv->reap_action = NORMAL; tpriv->iso_packet_offset = 0; /* allocate + initialize each URB with the correct number of packets */ for (i = 0; i < num_urbs; i++) { struct usbfs_urb *urb; int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH; int urb_packet_offset = 0; unsigned char *urb_buffer_orig = urb_buffer; int j; int k; /* swallow up all the packets we can fit into this URB */ while (packet_offset < transfer->num_iso_packets) { packet_len = transfer->iso_packet_desc[packet_offset].length; if (packet_len <= space_remaining_in_urb) { /* throw it in */ urb_packet_offset++; packet_offset++; space_remaining_in_urb -= packet_len; urb_buffer += packet_len; } else { /* it can't fit, save it for the next URB */ break; } } alloc_size = sizeof(*urb) + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc)); urb = malloc(alloc_size); if (!urb) { free_iso_urbs(tpriv); return LIBUSB_ERROR_NO_MEM; } memset(urb, 0, alloc_size); urbs[i] = urb; /* populate packet lengths */ for (j = 0, k = packet_offset - urb_packet_offset; k < packet_offset; k++, j++) { packet_len = transfer->iso_packet_desc[k].length; urb->iso_frame_desc[j].length = packet_len; } urb->usercontext = itransfer; urb->type = USBFS_URB_TYPE_ISO; /* FIXME: interface for non-ASAP data? */ urb->flags = USBFS_URB_ISO_ASAP; urb->endpoint = transfer->endpoint; urb->number_of_packets = urb_packet_offset; urb->buffer = urb_buffer_orig; } /* submit URBs */ for (i = 0; i < num_urbs; i++) { int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]); if (r < 0) { int j; if (errno == ENODEV) { r = LIBUSB_ERROR_NO_DEVICE; } else { usbi_err(TRANSFER_CTX(transfer), "submiturb failed error %d errno=%d", r, errno); r = LIBUSB_ERROR_IO; } /* if the first URB submission fails, we can simply free up and * return failure immediately. */ if (i == 0) { usbi_dbg("first URB failed, easy peasy"); free_iso_urbs(tpriv); return r; } /* if it's not the first URB that failed, the situation is a bit * tricky. we must discard all previous URBs. there are * complications: * - discarding is asynchronous - discarded urbs will be reaped * later. the user must not have freed the transfer when the * discarded URBs are reaped, otherwise libusb will be using * freed memory. * - the earlier URBs may have completed successfully and we do * not want to throw away any data. * so, in this case we discard all the previous URBs BUT we report * that the transfer was submitted successfully. then later when * the final discard completes we can report error to the user. */ tpriv->reap_action = SUBMIT_FAILED; for (j = 0; j < i; j++) { int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urbs[j]); if (tmp == 0) tpriv->awaiting_discard++; else if (errno == EINVAL) tpriv->awaiting_reap++; else usbi_warn(TRANSFER_CTX(transfer), "unrecognised discard return %d", tmp); } usbi_dbg("reporting successful submission but waiting for %d " "discards and %d reaps before reporting error", tpriv->awaiting_discard, tpriv->awaiting_reap); return 0; } } return 0;}static int submit_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); struct usbfs_urb *urb; int r; if (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH) return LIBUSB_ERROR_INVALID_PARAM; urb = malloc(sizeof(struct usbfs_urb)); if (!urb) return LIBUSB_ERROR_NO_MEM; memset(urb, 0, sizeof(struct usbfs_urb)); tpriv->urbs = urb; tpriv->reap_action = NORMAL; urb->usercontext = itransfer; urb->type = USBFS_URB_TYPE_CONTROL; urb->endpoint = transfer->endpoint; urb->buffer = transfer->buffer; urb->buffer_length = transfer->length; r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); if (r < 0) { free(urb); if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -