📄 usb.c
字号:
#elsestatic void wrap_urb_complete_worker(worker_param_t dummy)#endif{ struct irp *irp; struct urb *urb; struct usbd_bulk_or_intr_transfer *bulk_int_tx; struct usbd_vendor_or_class_request *vc_req; union nt_urb *nt_urb; struct wrap_urb *wrap_urb; struct nt_list *ent; unsigned long flags; USBENTER(""); while (1) { nt_spin_lock_irqsave(&wrap_urb_complete_list_lock, flags); ent = RemoveHeadList(&wrap_urb_complete_list); nt_spin_unlock_irqrestore(&wrap_urb_complete_list_lock, flags); if (!ent) break; wrap_urb = container_of(ent, struct wrap_urb, complete_list); urb = wrap_urb->urb;#ifdef USB_DEBUG if (wrap_urb->state != URB_COMPLETED && wrap_urb->state != URB_INT_UNLINKED) WARNING("urb %p in wrong state: %d", urb, wrap_urb->state);#endif irp = wrap_urb->irp; DUMP_IRP(irp); nt_urb = IRP_URB(irp); USBTRACE("urb: %p, nt_urb: %p, status: %d", urb, nt_urb, urb->status); switch (urb->status) { case 0: /* succesfully transferred */ irp->io_status.info = urb->actual_length; if (nt_urb->header.function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { bulk_int_tx = &nt_urb->bulk_int_transfer; bulk_int_tx->transfer_buffer_length = urb->actual_length; DUMP_URB_BUFFER(urb, USB_DIR_IN); if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && usb_pipein(urb->pipe)) memcpy(bulk_int_tx->transfer_buffer, urb->transfer_buffer, urb->actual_length); } else { // vendor or class request vc_req = &nt_urb->vendor_class_request; vc_req->transfer_buffer_length = urb->actual_length; DUMP_URB_BUFFER(urb, USB_DIR_IN); if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && usb_pipein(urb->pipe)) memcpy(vc_req->transfer_buffer, urb->transfer_buffer, urb->actual_length); } NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; irp->io_status.status = STATUS_SUCCESS; break; case -ENOENT: case -ECONNRESET: /* urb canceled */ irp->io_status.info = 0; TRACE1("urb %p canceled", urb); NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; irp->io_status.status = STATUS_CANCELLED; break; default: TRACE1("irp: %p, urb: %p, status: %d/%d", irp, urb, urb->status, wrap_urb->state); irp->io_status.info = 0; NT_URB_STATUS(nt_urb) = wrap_urb_status(urb->status); irp->io_status.status = nt_urb_irp_status(NT_URB_STATUS(nt_urb)); break; } wrap_free_urb(urb); IoCompleteRequest(irp, IO_NO_INCREMENT); } USBEXIT(return);}static USBD_STATUS wrap_bulk_or_intr_trans(struct irp *irp){ usbd_pipe_handle pipe_handle; struct urb *urb; unsigned int pipe; struct usbd_bulk_or_intr_transfer *bulk_int_tx; USBD_STATUS status; struct usb_device *udev; union nt_urb *nt_urb; nt_urb = IRP_URB(irp); udev = IRP_WRAP_DEVICE(irp)->usb.udev; bulk_int_tx = &nt_urb->bulk_int_transfer; pipe_handle = bulk_int_tx->pipe_handle; USBTRACE("flags: %X, length: %u, buffer: %p, handle: %p", bulk_int_tx->transfer_flags, bulk_int_tx->transfer_buffer_length, bulk_int_tx->transfer_buffer, pipe_handle); if (USBD_IS_BULK_PIPE(pipe_handle)) { if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) pipe = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress); else pipe = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress); } else { if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) pipe = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress); else pipe = usb_sndintpipe(udev, pipe_handle->bEndpointAddress); } DUMP_IRP(irp); urb = wrap_alloc_urb(irp, pipe, bulk_int_tx->transfer_buffer, bulk_int_tx->transfer_buffer_length); if (!urb) { ERROR("couldn't allocate urb"); return USBD_STATUS_NO_MEMORY; } if (usb_pipein(pipe) && (!(bulk_int_tx->transfer_flags & USBD_SHORT_TRANSFER_OK))) { USBTRACE("short not ok"); urb->transfer_flags |= URB_SHORT_NOT_OK; } if (usb_pipebulk(pipe)) { usb_fill_bulk_urb(urb, udev, pipe, urb->transfer_buffer, bulk_int_tx->transfer_buffer_length, wrap_urb_complete, urb->context); USBTRACE("submitting bulk urb %p on pipe 0x%x (ep 0x%x)", urb, urb->pipe, pipe_handle->bEndpointAddress); } else { usb_fill_int_urb(urb, udev, pipe, urb->transfer_buffer, bulk_int_tx->transfer_buffer_length, wrap_urb_complete, urb->context, pipe_handle->bInterval); USBTRACE("submitting interrupt urb %p on pipe 0x%x (ep 0x%x), " "intvl: %d", urb, urb->pipe, pipe_handle->bEndpointAddress, pipe_handle->bInterval); } status = wrap_submit_urb(irp); USBTRACE("status: %08X", status); USBEXIT(return status);}static USBD_STATUS wrap_vendor_or_class_req(struct irp *irp){ u8 req_type; unsigned int pipe; struct usbd_vendor_or_class_request *vc_req; struct usb_device *udev; union nt_urb *nt_urb; USBD_STATUS status; struct urb *urb; struct usb_ctrlrequest *dr; nt_urb = IRP_URB(irp); udev = IRP_WRAP_DEVICE(irp)->usb.udev; vc_req = &nt_urb->vendor_class_request; USBTRACE("bits: %x, req: %x, val: %08x, index: %08x, flags: %x," "buf: %p, len: %d", vc_req->reserved_bits, vc_req->request, vc_req->value, vc_req->index, vc_req->transfer_flags, vc_req->transfer_buffer, vc_req->transfer_buffer_length); USBTRACE("%x", nt_urb->header.function); switch (nt_urb->header.function) { case URB_FUNCTION_VENDOR_DEVICE: req_type = USB_TYPE_VENDOR | USB_RECIP_DEVICE; break; case URB_FUNCTION_VENDOR_INTERFACE: req_type = USB_TYPE_VENDOR | USB_RECIP_INTERFACE; break; case URB_FUNCTION_VENDOR_ENDPOINT: req_type = USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; break; case URB_FUNCTION_VENDOR_OTHER: req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; break; case URB_FUNCTION_CLASS_DEVICE: req_type = USB_TYPE_CLASS | USB_RECIP_DEVICE; break; case URB_FUNCTION_CLASS_INTERFACE: req_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; break; case URB_FUNCTION_CLASS_ENDPOINT: req_type = USB_TYPE_CLASS | USB_RECIP_ENDPOINT; break; case URB_FUNCTION_CLASS_OTHER: req_type = USB_TYPE_CLASS | USB_RECIP_OTHER; break; default: ERROR("unknown request type: %x", nt_urb->header.function); req_type = 0; break; } req_type |= vc_req->reserved_bits; USBTRACE("req type: %08x", req_type); if (vc_req->transfer_flags & USBD_TRANSFER_DIRECTION_IN) { pipe = usb_rcvctrlpipe(udev, 0); req_type |= USB_DIR_IN; USBTRACE("pipe: %x, dir in", pipe); } else { pipe = usb_sndctrlpipe(udev, 0); req_type |= USB_DIR_OUT; USBTRACE("pipe: %x, dir out", pipe); } urb = wrap_alloc_urb(irp, pipe, vc_req->transfer_buffer, vc_req->transfer_buffer_length); if (!urb) { ERROR("couldn't allocate urb"); return USBD_STATUS_NO_MEMORY; } if (usb_pipein(pipe) && (!(vc_req->transfer_flags & USBD_SHORT_TRANSFER_OK))) { USBTRACE("short not ok"); urb->transfer_flags |= URB_SHORT_NOT_OK; } dr = kmalloc(sizeof(*dr), GFP_ATOMIC); if (!dr) { ERROR("couldn't allocate memory"); wrap_free_urb(urb); return USBD_STATUS_NO_MEMORY; } memset(dr, 0, sizeof(*dr)); dr->bRequestType = req_type; dr->bRequest = vc_req->request; dr->wValue = cpu_to_le16(vc_req->value); dr->wIndex = cpu_to_le16((u16)vc_req->index); dr->wLength = cpu_to_le16((u16)urb->transfer_buffer_length); usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, urb->transfer_buffer, urb->transfer_buffer_length, wrap_urb_complete, urb->context); status = wrap_submit_urb(irp); USBTRACE("status: %08X", status); USBEXIT(return status);}static USBD_STATUS wrap_reset_pipe(struct usb_device *udev, struct irp *irp){ int ret; union nt_urb *nt_urb; usbd_pipe_handle pipe_handle; unsigned int pipe1, pipe2; nt_urb = IRP_URB(irp); pipe_handle = nt_urb->pipe_req.pipe_handle; /* TODO: not clear if both directions should be cleared? */ if (USBD_IS_BULK_PIPE(pipe_handle)) { pipe1 = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress); pipe2 = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress); } else if (USBD_IS_INT_PIPE(pipe_handle)) { pipe1 = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress); pipe2 = pipe1; } else { WARNING("invalid pipe %d", pipe_handle->bEndpointAddress); return USBD_STATUS_INVALID_PIPE_HANDLE; } USBTRACE("ep: %d, pipe: 0x%x", pipe_handle->bEndpointAddress, pipe1); ret = usb_clear_halt(udev, pipe1); if (ret) USBTRACE("resetting pipe %d failed: %d", pipe1, ret); if (pipe2 != pipe1) { ret = usb_clear_halt(udev, pipe2); if (ret) USBTRACE("resetting pipe %d failed: %d", pipe2, ret); }// return wrap_urb_status(ret); return USBD_STATUS_SUCCESS;}static USBD_STATUS wrap_abort_pipe(struct usb_device *udev, struct irp *irp){ union nt_urb *nt_urb; usbd_pipe_handle pipe_handle; struct wrap_urb *wrap_urb; struct wrap_device *wd; KIRQL irql; wd = IRP_WRAP_DEVICE(irp); nt_urb = IRP_URB(irp); pipe_handle = nt_urb->pipe_req.pipe_handle; USBENTER("%p, %x", irp, pipe_handle->bEndpointAddress); IoAcquireCancelSpinLock(&irql); nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { USBTRACE("%p, %p, %d, %x, %x", wrap_urb, wrap_urb->urb, wrap_urb->state, wrap_urb->urb->pipe, usb_pipeendpoint(wrap_urb->urb->pipe)); /* for WG111T driver, urbs for endpoint 0 should also * be canceled */ if ((usb_pipeendpoint(wrap_urb->urb->pipe) == pipe_handle->bEndpointAddress) || (usb_pipeendpoint(wrap_urb->urb->pipe) == 0)) { if (wrap_cancel_urb(wrap_urb) == 0) USBTRACE("canceled wrap_urb: %p", wrap_urb); } } IoReleaseCancelSpinLock(irql); NT_URB_STATUS(nt_urb) = USBD_STATUS_CANCELED; USBEXIT(return USBD_STATUS_SUCCESS);}static void set_intf_pipe_info(struct wrap_device *wd, struct usb_interface *usb_intf, struct usbd_interface_information *intf){ int i; struct usb_endpoint_descriptor *ep; struct usbd_pipe_information *pipe;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) for (i = 0; i < CUR_ALT_SETTING(usb_intf)->desc.bNumEndpoints; i++) { ep = &(CUR_ALT_SETTING(usb_intf)->endpoint[i]).desc;#else for (i = 0; i < CUR_ALT_SETTING(usb_intf).bNumEndpoints; i++) { ep = &((CUR_ALT_SETTING(usb_intf)).endpoint[i]);#endif if (i >= intf->bNumEndpoints) { ERROR("intf %p has only %d endpoints, " "ignoring endpoints above %d", intf, intf->bNumEndpoints, i); break; } pipe = &intf->pipes[i]; if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET) USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize, pipe->max_tx_size); USBTRACE("driver wants max_tx_size to %d", pipe->max_tx_size); pipe->wMaxPacketSize = ep->wMaxPacketSize; pipe->bEndpointAddress = ep->bEndpointAddress; pipe->type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (pipe->type == UsbdPipeTypeInterrupt) { /* for low speed devices, Linux sets bInterval * as frames per second, whereas Windows * interprets it as milliseconds */ if (wd->usb.udev->speed == USB_SPEED_LOW) pipe->bInterval = 1 << (ep->bInterval - 1); else pipe->bInterval = ep->bInterval; } pipe->handle = ep; USBTRACE("%d: ep 0x%x, type %d, pkt_sz %d, intv %d (%d)," "type: %d, handle %p", i, ep->bEndpointAddress, ep->bmAttributes, ep->wMaxPacketSize, ep->bInterval, pipe->bInterval, pipe->type, pipe->handle); }}static USBD_STATUS wrap_select_configuration(struct wrap_device *wd, union nt_urb *nt_urb, struct irp *irp){ int i, ret; struct usbd_select_configuration *sel_conf; struct usb_device *udev; struct usbd_interface_information *intf; struct usb_config_descriptor *config; struct usb_interface *usb_intf; udev = wd->usb.udev; sel_conf = &nt_urb->select_conf; config = sel_conf->config; USBTRACE("%p", config); if (config == NULL) { kill_all_urbs(wd, 1);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ret = usb_reset_configuration(udev);#else ret = 0;#endif return wrap_urb_status(ret); } USBTRACE("conf: %d, type: %d, length: %d, numif: %d, attr: %08x", config->bConfigurationValue, config->bDescriptorType, config->wTotalLength, config->bNumInterfaces, config->bmAttributes); ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_CONFIGURATION, 0, config->bConfigurationValue, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (ret < 0) { ERROR("ret: %d", ret); return wrap_urb_status(ret); } sel_conf->handle = udev->actconfig; intf = &sel_conf->intf; for (i = 0; i < config->bNumInterfaces && intf->bLength > 0; i++, intf = (((void *)intf) + intf->bLength)) { USBTRACE("intf: %d, alt setting: %d", intf->bInterfaceNumber, intf->bAlternateSetting); ret = usb_set_interface(udev, intf->bInterfaceNumber, intf->bAlternateSetting); if (ret < 0) { ERROR("failed with %d", ret); return wrap_urb_status(ret); } usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); if (!usb_intf) { ERROR("couldn't obtain ifnum"); return USBD_STATUS_REQUEST_FAILED; } USBTRACE("intf: %p, num ep: %d", intf, intf->bNumEndpoints); set_intf_pipe_info(wd, usb_intf, intf); } return USBD_STATUS_SUCCESS;}static USBD_STATUS wrap_select_interface(struct wrap_device *wd, union nt_urb *nt_urb, struct irp *irp){ int ret; struct usbd_select_interface *sel_intf; struct usb_device *udev; struct usbd_interface_information *intf; struct usb_interface *usb_intf; udev = wd->usb.udev; sel_intf = &nt_urb->select_intf; intf = &sel_intf->intf; ret = usb_set_interface(udev, intf->bInterfaceNumber, intf->bAlternateSetting); if (ret < 0) { ERROR("failed with %d", ret); return wrap_urb_status(ret); } usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); if (!usb_intf) { ERROR("couldn't get interface information"); return USBD_STATUS_REQUEST_FAILED; } USBTRACE("intf: %p, num ep: %d", usb_intf, intf->bNumEndpoints); set_intf_pipe_info(wd, usb_intf, intf); return USBD_STATUS_SUCCESS;}static int wrap_usb_get_string(struct usb_device *udev, unsigned short langid, unsigned char index, void *buf, int size){ int i, ret; /* if langid is 0, return array of langauges supported in * buf */ for (i = 0; i < 3; i++) { ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + index, langid, buf, size, USB_CTRL_GET_TIMEOUT); if (ret > 0 || ret == -EPIPE) break; } return ret;}static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd, union nt_urb *nt_urb, struct irp *irp){ struct usbd_control_descriptor_request *control_desc; int ret = 0; struct usb_device *udev; udev = wd->usb.udev; control_desc = &nt_urb->control_desc; USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p," "transfer_buffer_length = %d", control_desc->desc_type, control_desc->index, control_desc->transfer_buffer, control_desc->transfer_buffer_length);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -