struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len) { struct usb_request *req; req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req) { req->length = usb_endpoint_dir_out(ep->desc) ? usb_ep_align(ep, len) : len; req->buf = kmalloc(req->length, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request(ep, req); req = NULL; } } return req; }
static int _rtl_usb_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); int err; u8 epidx; struct usb_interface *usb_intf = rtlusb->intf; u8 epnums = usb_intf->cur_altsetting->desc.bNumEndpoints; rtlusb->out_ep_nums = rtlusb->in_ep_nums = 0; rtlusb->epnums = epnums; for (epidx = 0; epidx < epnums; epidx++) { struct usb_endpoint_descriptor *pep_desc; pep_desc = &usb_intf->cur_altsetting->endpoint[epidx].desc; if (usb_endpoint_dir_in(pep_desc)) rtlusb->in_ep_nums++; else if (usb_endpoint_dir_out(pep_desc)) rtlusb->out_ep_nums++; RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "USB EP(0x%02x), MaxPacketSize=%d, Interval=%d\n", pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize, pep_desc->bInterval); } if (rtlusb->in_ep_nums < rtlpriv->cfg->usb_interface_cfg->in_ep_num) { pr_err("Too few input end points found\n"); return -EINVAL; } if (rtlusb->out_ep_nums == 0) { pr_err("No output end points found\n"); return -EINVAL; } /* usb endpoint mapping */ err = rtlpriv->cfg->usb_interface_cfg->usb_endpoint_mapping(hw); rtlusb->usb_mq_to_hwq = rtlpriv->cfg->usb_interface_cfg->usb_mq_to_hwq; _rtl_usb_init_tx(hw); _rtl_usb_init_rx(hw); return err; }
/** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the urb describing the request * @mem_flags: the type of memory to allocate, see kmalloc() for a list * of valid options for this. * * This submits a transfer request, and transfers control of the URB * describing that request to the USB subsystem. Request completion will * be indicated later, asynchronously, by calling the completion handler. * The three types of completion are success, error, and unlink * (a software-induced fault, also called "request cancellation"). * * URBs may be submitted in interrupt context. * * The caller must have correctly initialized the URB before submitting * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are * available to ensure that most fields are correctly initialized, for * the particular kind of transfer, although they will not initialize * any transfer flags. * * Successful submissions return 0; otherwise this routine returns a * negative error number. If the submission is successful, the complete() * callback from the URB will be called exactly once, when the USB core and * Host Controller Driver (HCD) are finished with the URB. When the completion * function is called, control of the URB is returned to the device * driver which issued the request. The completion handler may then * immediately free or reuse that URB. * * With few exceptions, USB device drivers should never access URB fields * provided by usbcore or the HCD until its complete() is called. * The exceptions relate to periodic transfer scheduling. For both * interrupt and isochronous urbs, as part of successful URB submission * urb->interval is modified to reflect the actual transfer period used * (normally some power of two units). And for isochronous urbs, * urb->start_frame is modified to reflect when the URB's transfers were * scheduled to start. Not all isochronous transfer scheduling policies * will work, but most host controller drivers should easily handle ISO * queues going from now until 10-200 msec into the future. * * For control endpoints, the synchronous usb_control_msg() call is * often used (in non-interrupt context) instead of this call. * That is often used through convenience wrappers, for the requests * that are standardized in the USB 2.0 specification. For bulk * endpoints, a synchronous usb_bulk_msg() call is available. * * Request Queuing: * * URBs may be submitted to endpoints before previous ones complete, to * minimize the impact of interrupt latencies and system overhead on data * throughput. With that queuing policy, an endpoint's queue would never * be empty. This is required for continuous isochronous data streams, * and may also be required for some kinds of interrupt transfers. Such * queuing also maximizes bandwidth utilization by letting USB controllers * start work on later requests before driver software has finished the * completion processing for earlier (successful) requests. * * As of Linux 2.6, all USB endpoint transfer queues support depths greater * than one. This was previously a HCD-specific behavior, except for ISO * transfers. Non-isochronous endpoint queues are inactive during cleanup * after faults (transfer errors or cancellation). * * Reserved Bandwidth Transfers: * * Periodic transfers (interrupt or isochronous) are performed repeatedly, * using the interval specified in the urb. Submitting the first urb to * the endpoint reserves the bandwidth necessary to make those transfers. * If the USB subsystem can't allocate sufficient bandwidth to perform * the periodic request, submitting such a periodic request should fail. * * Device drivers must explicitly request that repetition, by ensuring that * some URB is always on the endpoint's queue (except possibly for short * periods during completion callacks). When there is no longer an urb * queued, the endpoint's bandwidth reservation is canceled. This means * drivers can use their completion handlers to ensure they keep bandwidth * they need, by reinitializing and resubmitting the just-completed urb * until the driver longer needs that periodic bandwidth. * * Memory Flags: * * The general rules for how to decide which mem_flags to use * are the same as for kmalloc. There are four * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and * GFP_ATOMIC. * * GFP_NOFS is not ever used, as it has not been implemented yet. * * GFP_ATOMIC is used when * (a) you are inside a completion handler, an interrupt, bottom half, * tasklet or timer, or * (b) you are holding a spinlock or rwlock (does not apply to * semaphores), or * (c) current->state != TASK_RUNNING, this is the case only after * you've changed it. * * GFP_NOIO is used in the block io path and error handling of storage * devices. * * All other situations use GFP_KERNEL. * * Some more specific rules for mem_flags can be inferred, such as * (1) start_xmit, timeout, and receive methods of network drivers must * use GFP_ATOMIC (they are called with a spinlock held); * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also * called with a spinlock held); * (3) If you use a kernel thread with a network driver you must use * GFP_NOIO, unless (b) or (c) apply; * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c) * apply or your are in a storage driver's block io path; * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and * (6) changing firmware on a running storage or net device uses * GFP_NOIO, unless b) or c) apply * */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; dev = urb->dev; if ((!dev) || (dev->state < USB_STATE_DEFAULT)) return -ENODEV; /* For now, get the endpoint from the pipe. Eventually drivers * will be required to set urb->ep directly and we will eliminate * urb->pipe. */ ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) [usb_pipeendpoint(urb->pipe)]; if (!ep) return -ENOENT; urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ xfertype = usb_endpoint_type(&ep->desc); if (xfertype == USB_ENDPOINT_XFER_CONTROL) { struct usb_ctrlrequest *setup = (struct usb_ctrlrequest *) urb->setup_packet; if (!setup) return -ENOEXEC; is_out = !(setup->bRequestType & USB_DIR_IN) || !setup->wLength; } else { is_out = usb_endpoint_dir_out(&ep->desc); } /* Cache the direction for later use */ urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | (is_out ? URB_DIR_OUT : URB_DIR_IN); if (xfertype != USB_ENDPOINT_XFER_CONTROL && dev->state < USB_STATE_CONFIGURED) return -ENODEV; max = le16_to_cpu(ep->desc.wMaxPacketSize); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __func__, max); return -EMSGSIZE; } /* periodic transfers limit size per frame/uframe, * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */ if (dev->speed == USB_SPEED_HIGH) { int mult = 1 + ((max >> 11) & 0x03); max &= 0x07ff; max *= mult; }
/** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the urb describing the request * @mem_flags: the type of memory to allocate, see kmalloc() for a list * of valid options for this. * * This submits a transfer request, and transfers control of the URB * describing that request to the USB subsystem. Request completion will * be indicated later, asynchronously, by calling the completion handler. * The three types of completion are success, error, and unlink * (a software-induced fault, also called "request cancellation"). * * URBs may be submitted in interrupt context. * * The caller must have correctly initialized the URB before submitting * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are * available to ensure that most fields are correctly initialized, for * the particular kind of transfer, although they will not initialize * any transfer flags. * * Successful submissions return 0; otherwise this routine returns a * negative error number. If the submission is successful, the complete() * callback from the URB will be called exactly once, when the USB core and * Host Controller Driver (HCD) are finished with the URB. When the completion * function is called, control of the URB is returned to the device * driver which issued the request. The completion handler may then * immediately free or reuse that URB. * * With few exceptions, USB device drivers should never access URB fields * provided by usbcore or the HCD until its complete() is called. * The exceptions relate to periodic transfer scheduling. For both * interrupt and isochronous urbs, as part of successful URB submission * urb->interval is modified to reflect the actual transfer period used * (normally some power of two units). And for isochronous urbs, * urb->start_frame is modified to reflect when the URB's transfers were * scheduled to start. Not all isochronous transfer scheduling policies * will work, but most host controller drivers should easily handle ISO * queues going from now until 10-200 msec into the future. * * For control endpoints, the synchronous usb_control_msg() call is * often used (in non-interrupt context) instead of this call. * That is often used through convenience wrappers, for the requests * that are standardized in the USB 2.0 specification. For bulk * endpoints, a synchronous usb_bulk_msg() call is available. * * Request Queuing: * * URBs may be submitted to endpoints before previous ones complete, to * minimize the impact of interrupt latencies and system overhead on data * throughput. With that queuing policy, an endpoint's queue would never * be empty. This is required for continuous isochronous data streams, * and may also be required for some kinds of interrupt transfers. Such * queuing also maximizes bandwidth utilization by letting USB controllers * start work on later requests before driver software has finished the * completion processing for earlier (successful) requests. * * As of Linux 2.6, all USB endpoint transfer queues support depths greater * than one. This was previously a HCD-specific behavior, except for ISO * transfers. Non-isochronous endpoint queues are inactive during cleanup * after faults (transfer errors or cancellation). * * Reserved Bandwidth Transfers: * * Periodic transfers (interrupt or isochronous) are performed repeatedly, * using the interval specified in the urb. Submitting the first urb to * the endpoint reserves the bandwidth necessary to make those transfers. * If the USB subsystem can't allocate sufficient bandwidth to perform * the periodic request, submitting such a periodic request should fail. * * For devices under xHCI, the bandwidth is reserved at configuration time, or * when the alt setting is selected. If there is not enough bus bandwidth, the * configuration/alt setting request will fail. Therefore, submissions to * periodic endpoints on devices under xHCI should never fail due to bandwidth * constraints. * * Device drivers must explicitly request that repetition, by ensuring that * some URB is always on the endpoint's queue (except possibly for short * periods during completion callacks). When there is no longer an urb * queued, the endpoint's bandwidth reservation is canceled. This means * drivers can use their completion handlers to ensure they keep bandwidth * they need, by reinitializing and resubmitting the just-completed urb * until the driver longer needs that periodic bandwidth. * * Memory Flags: * * The general rules for how to decide which mem_flags to use * are the same as for kmalloc. There are four * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and * GFP_ATOMIC. * * GFP_NOFS is not ever used, as it has not been implemented yet. * * GFP_ATOMIC is used when * (a) you are inside a completion handler, an interrupt, bottom half, * tasklet or timer, or * (b) you are holding a spinlock or rwlock (does not apply to * semaphores), or * (c) current->state != TASK_RUNNING, this is the case only after * you've changed it. * * GFP_NOIO is used in the block io path and error handling of storage * devices. * * All other situations use GFP_KERNEL. * * Some more specific rules for mem_flags can be inferred, such as * (1) start_xmit, timeout, and receive methods of network drivers must * use GFP_ATOMIC (they are called with a spinlock held); * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also * called with a spinlock held); * (3) If you use a kernel thread with a network driver you must use * GFP_NOIO, unless (b) or (c) apply; * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c) * apply or your are in a storage driver's block io path; * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and * (6) changing firmware on a running storage or net device uses * GFP_NOIO, unless b) or c) apply * */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; dev = urb->dev; if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) return -ENODEV; /* For now, get the endpoint from the pipe. Eventually drivers * will be required to set urb->ep directly and we will eliminate * urb->pipe. */ ep = usb_pipe_endpoint(dev, urb->pipe); if (!ep) return -ENOENT; urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ xfertype = usb_endpoint_type(&ep->desc); if (xfertype == USB_ENDPOINT_XFER_CONTROL) { struct usb_ctrlrequest *setup = (struct usb_ctrlrequest *) urb->setup_packet; if (!setup) return -ENOEXEC; is_out = !(setup->bRequestType & USB_DIR_IN) || !setup->wLength; } else { is_out = usb_endpoint_dir_out(&ep->desc); } /* Clear the internal flags and cache the direction for later use */ urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE | URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL | URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL | URB_DMA_SG_COMBINED); urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN); if (xfertype != USB_ENDPOINT_XFER_CONTROL && dev->state < USB_STATE_CONFIGURED) return -ENODEV; max = usb_endpoint_maxp(&ep->desc); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __func__, max); return -EMSGSIZE; } /* periodic transfers limit size per frame/uframe, * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* SuperSpeed isoc endpoints have up to 16 bursts of up to * 3 packets each */ if (dev->speed == USB_SPEED_SUPER) { int burst = 1 + ep->ss_ep_comp.bMaxBurst; int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes); max *= burst; max *= mult; } /* "high bandwidth" mode, 1-3 packets/uframe? */ if (dev->speed == USB_SPEED_HIGH) { int mult = 1 + ((max >> 11) & 0x03); max &= 0x07ff; max *= mult; }
static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) { return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd); }
/* This function probes an mwifiex device and registers it. It allocates * the card structure, initiates the device registration and initialization * procedure by adding a logical interface. */ static int mwifiex_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_interface *iface_desc = intf->cur_altsetting; struct usb_endpoint_descriptor *epd; int ret, i; struct usb_card_rec *card; u16 id_vendor, id_product, bcd_device, bcd_usb; card = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); if (!card) return -ENOMEM; id_vendor = le16_to_cpu(udev->descriptor.idVendor); id_product = le16_to_cpu(udev->descriptor.idProduct); bcd_device = le16_to_cpu(udev->descriptor.bcdDevice); bcd_usb = le16_to_cpu(udev->descriptor.bcdUSB); pr_debug("info: VID/PID = %X/%X, Boot2 version = %X\n", id_vendor, id_product, bcd_device); /* PID_1 is used for firmware downloading only */ switch (id_product) { case USB8797_PID_1: case USB8897_PID_1: card->usb_boot_state = USB8XXX_FW_DNLD; break; case USB8797_PID_2: case USB8897_PID_2: card->usb_boot_state = USB8XXX_FW_READY; break; default: pr_warning("unknown id_product %#x\n", id_product); card->usb_boot_state = USB8XXX_FW_DNLD; break; } card->udev = udev; card->intf = intf; pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { epd = &iface_desc->endpoint[i].desc; if (usb_endpoint_dir_in(epd) && usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && usb_endpoint_xfer_bulk(epd)) { pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", le16_to_cpu(epd->wMaxPacketSize), epd->bEndpointAddress); card->rx_cmd_ep = usb_endpoint_num(epd); atomic_set(&card->rx_cmd_urb_pending, 0); } if (usb_endpoint_dir_in(epd) && usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA && usb_endpoint_xfer_bulk(epd)) { pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", le16_to_cpu(epd->wMaxPacketSize), epd->bEndpointAddress); card->rx_data_ep = usb_endpoint_num(epd); atomic_set(&card->rx_data_urb_pending, 0); } if (usb_endpoint_dir_out(epd) && usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA && usb_endpoint_xfer_bulk(epd)) { pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", le16_to_cpu(epd->wMaxPacketSize), epd->bEndpointAddress); card->tx_data_ep = usb_endpoint_num(epd); atomic_set(&card->tx_data_urb_pending, 0); } if (usb_endpoint_dir_out(epd) && usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && usb_endpoint_xfer_bulk(epd)) { pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", le16_to_cpu(epd->wMaxPacketSize), epd->bEndpointAddress); card->tx_cmd_ep = usb_endpoint_num(epd); atomic_set(&card->tx_cmd_urb_pending, 0); card->bulk_out_maxpktsize = le16_to_cpu(epd->wMaxPacketSize); } } usb_set_intfdata(intf, card); ret = mwifiex_add_card(card, &add_remove_card_sem, &usb_ops, MWIFIEX_USB); if (ret) { pr_err("%s: mwifiex_add_card failed: %d\n", __func__, ret); usb_reset_device(udev); kfree(card); return ret; } usb_get_dev(udev); return 0; }
/*=========================================================================== METHOD: GobiNetDriverBind (Public Method) DESCRIPTION: Setup in and out pipes PARAMETERS pDev [ I ] - Pointer to usbnet device pIntf [ I ] - Pointer to interface RETURN VALUE: int - 0 for success Negative errno for error ===========================================================================*/ static int GobiNetDriverBind( struct usbnet * pDev, struct usb_interface * pIntf ) { int numEndpoints; int endpointIndex; struct usb_host_endpoint * pEndpoint = NULL; struct usb_host_endpoint * pIn = NULL; struct usb_host_endpoint * pOut = NULL; // Verify one altsetting if (pIntf->num_altsetting != 1) { DBG( "invalid num_altsetting %u\n", pIntf->num_altsetting ); return -ENODEV; } /* We only accept certain interfaces */ if (pIntf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC ) { DBG( "Ignoring non vendor class interface #%d\n", pIntf->cur_altsetting->desc.bInterfaceNumber ); return -ENODEV; } else if (pDev->driver_info->data && !test_bit(pIntf->cur_altsetting->desc.bInterfaceNumber, &pDev->driver_info->data)) { DBG( "invalid interface %d\n", pIntf->cur_altsetting->desc.bInterfaceNumber ); return -ENODEV; } // Collect In and Out endpoints numEndpoints = pIntf->cur_altsetting->desc.bNumEndpoints; for (endpointIndex = 0; endpointIndex < numEndpoints; endpointIndex++) { pEndpoint = pIntf->cur_altsetting->endpoint + endpointIndex; if (pEndpoint == NULL) { DBG( "invalid endpoint %u\n", endpointIndex ); return -ENODEV; } if (usb_endpoint_dir_in( &pEndpoint->desc ) == true && usb_endpoint_xfer_int( &pEndpoint->desc ) == false) { pIn = pEndpoint; } else if (usb_endpoint_dir_out( &pEndpoint->desc ) == true) { pOut = pEndpoint; } } if (pIn == NULL || pOut == NULL) { DBG( "invalid endpoints\n" ); return -ENODEV; } if (usb_set_interface( pDev->udev, pIntf->cur_altsetting->desc.bInterfaceNumber, 0 ) != 0) { DBG( "unable to set interface\n" ); return -ENODEV; } pDev->in = usb_rcvbulkpipe( pDev->udev, pIn->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ); pDev->out = usb_sndbulkpipe( pDev->udev, pOut->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ); DBG( "in %x, out %x\n", pIn->desc.bEndpointAddress, pOut->desc.bEndpointAddress ); // In later versions of the kernel, usbnet helps with this #if (LINUX_VERSION_CODE <= KERNEL_VERSION( 2,6,23 )) pIntf->dev.platform_data = (void *)pDev; #endif /* make MAC addr easily distinguishable from an IP header */ if (possibly_iphdr(pDev->net->dev_addr)) { pDev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ pDev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ } return 0; }
static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) { struct usb_device *dev = interface_to_usbdev(intf); struct uvd *uvd = NULL; int ix, i, nas; int actInterface=-1, inactInterface=-1, maxPS=0; unsigned char video_ep = 0; DEBUG(1, "konicawc_probe(%p)", intf); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; dev_info(&intf->dev, "Konica Webcam (rev. 0x%04x)\n", le16_to_cpu(dev->descriptor.bcdDevice)); RESTRICT_TO_RANGE(speed, 0, MAX_SPEED); /* Validate found interface: must have one ISO endpoint */ nas = intf->num_altsetting; if (nas != 8) { err("Incorrect number of alternate settings (%d) for this camera!", nas); return -ENODEV; } /* Validate all alternate settings */ for (ix=0; ix < nas; ix++) { const struct usb_host_interface *interface; const struct usb_endpoint_descriptor *endpoint; interface = &intf->altsetting[ix]; i = interface->desc.bAlternateSetting; if (interface->desc.bNumEndpoints != 2) { err("Interface %d. has %u. endpoints!", interface->desc.bInterfaceNumber, (unsigned)(interface->desc.bNumEndpoints)); return -ENODEV; } endpoint = &interface->endpoint[1].desc; DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x", endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize)); if (video_ep == 0) video_ep = endpoint->bEndpointAddress; else if (video_ep != endpoint->bEndpointAddress) { err("Alternate settings have different endpoint addresses!"); return -ENODEV; } if (!usb_endpoint_xfer_isoc(endpoint)) { err("Interface %d. has non-ISO endpoint!", interface->desc.bInterfaceNumber); return -ENODEV; } if (usb_endpoint_dir_out(endpoint)) { err("Interface %d. has ISO OUT endpoint!", interface->desc.bInterfaceNumber); return -ENODEV; } if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { if (inactInterface < 0) inactInterface = i; else { err("More than one inactive alt. setting!"); return -ENODEV; } } else { if (i == spd_to_iface[speed]) { /* This one is the requested one */ actInterface = i; } } if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS) maxPS = le16_to_cpu(endpoint->wMaxPacketSize); } if(actInterface == -1) { err("Cant find required endpoint"); return -ENODEV; } DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS); uvd = usbvideo_AllocateDevice(cams); if (uvd != NULL) { struct konicawc *cam = (struct konicawc *)(uvd->user_data); /* Here uvd is a fully allocated uvd object */ for(i = 0; i < USBVIDEO_NUMSBUF; i++) { cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); if(cam->sts_urb[i] == NULL) { while(i--) { usb_free_urb(cam->sts_urb[i]); } err("can't allocate urbs"); return -ENOMEM; } } cam->speed = speed; RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240); cam->width = camera_sizes[size].width; cam->height = camera_sizes[size].height; cam->size = size; uvd->flags = 0; uvd->debug = debug; uvd->dev = dev; uvd->iface = intf->altsetting->desc.bInterfaceNumber; uvd->ifaceAltInactive = inactInterface; uvd->ifaceAltActive = actInterface; uvd->video_endp = video_ep; uvd->iso_packet_len = maxPS; uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P; uvd->defaultPalette = VIDEO_PALETTE_YUV420P; uvd->canvas = VIDEOSIZE(320, 240); uvd->videosize = VIDEOSIZE(cam->width, cam->height); /* Initialize konicawc specific data */ konicawc_configure_video(uvd); i = usbvideo_RegisterVideoDevice(uvd); uvd->max_frame_size = (320 * 240 * 3)/2; if (i != 0) { err("usbvideo_RegisterVideoDevice() failed."); uvd = NULL; } konicawc_register_input(cam, dev); } if (uvd) { usb_set_intfdata (intf, uvd); return 0; } return -EIO; }
static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) { return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); }
/* * ultracam_probe() * * This procedure queries device descriptor and accepts the interface * if it looks like our camera. * * History: * 12-Nov-2000 Reworked to comply with new probe() signature. * 23-Jan-2001 Added compatibility with 2.2.x kernels. */ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) { struct usb_device *dev = interface_to_usbdev(intf); struct uvd *uvd = NULL; int ix, i, nas; int actInterface=-1, inactInterface=-1, maxPS=0; unsigned char video_ep = 0; if (debug >= 1) dev_info(&intf->dev, "ultracam_probe\n"); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) return -ENODEV; dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n", le16_to_cpu(dev->descriptor.bcdDevice)); /* Validate found interface: must have one ISO endpoint */ nas = intf->num_altsetting; if (debug > 0) dev_info(&intf->dev, "Number of alternate settings=%d.\n", nas); if (nas < 8) { err("Too few alternate settings for this camera!"); return -ENODEV; } /* Validate all alternate settings */ for (ix=0; ix < nas; ix++) { const struct usb_host_interface *interface; const struct usb_endpoint_descriptor *endpoint; interface = &intf->altsetting[ix]; i = interface->desc.bAlternateSetting; if (interface->desc.bNumEndpoints != 1) { err("Interface %d. has %u. endpoints!", interface->desc.bInterfaceNumber, (unsigned)(interface->desc.bNumEndpoints)); return -ENODEV; } endpoint = &interface->endpoint[0].desc; if (video_ep == 0) video_ep = endpoint->bEndpointAddress; else if (video_ep != endpoint->bEndpointAddress) { err("Alternate settings have different endpoint addresses!"); return -ENODEV; } if (!usb_endpoint_xfer_isoc(endpoint)) { err("Interface %d. has non-ISO endpoint!", interface->desc.bInterfaceNumber); return -ENODEV; } if (usb_endpoint_dir_out(endpoint)) { err("Interface %d. has ISO OUT endpoint!", interface->desc.bInterfaceNumber); return -ENODEV; } if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { if (inactInterface < 0) inactInterface = i; else { err("More than one inactive alt. setting!"); return -ENODEV; } } else { if (actInterface < 0) { actInterface = i; maxPS = le16_to_cpu(endpoint->wMaxPacketSize); if (debug > 0) dev_info(&intf->dev, "Active setting=%d. " "maxPS=%d.\n", i, maxPS); } else { /* Got another active alt. setting */ if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { /* This one is better! */ actInterface = i; maxPS = le16_to_cpu(endpoint->wMaxPacketSize); if (debug > 0) { dev_info(&intf->dev, "Even better ctive " "setting=%d. " "maxPS=%d.\n", i, maxPS); } } } } } if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { err("Failed to recognize the camera!"); return -ENODEV; } uvd = usbvideo_AllocateDevice(cams); if (uvd != NULL) { /* Here uvd is a fully allocated uvd object */ uvd->flags = flags; uvd->debug = debug; uvd->dev = dev; uvd->iface = intf->altsetting->desc.bInterfaceNumber; uvd->ifaceAltInactive = inactInterface; uvd->ifaceAltActive = actInterface; uvd->video_endp = video_ep; uvd->iso_packet_len = maxPS; uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; uvd->defaultPalette = VIDEO_PALETTE_RGB24; uvd->canvas = VIDEOSIZE(640, 480); uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ /* Initialize ibmcam-specific data */ assert(ULTRACAM_T(uvd) != NULL); ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ ULTRACAM_T(uvd)->initialized = 0; ultracam_configure_video(uvd); i = usbvideo_RegisterVideoDevice(uvd); if (i != 0) { err("usbvideo_RegisterVideoDevice() failed."); uvd = NULL; } } if (uvd) { usb_set_intfdata (intf, uvd); return 0; } return -EIO; }
/*=========================================================================== METHOD: GobiNetDriverBind (Public Method) DESCRIPTION: Setup in and out pipes PARAMETERS pDev [ I ] - Pointer to usbnet device pIntf [ I ] - Pointer to interface RETURN VALUE: int - 0 for success Negative errno for error ===========================================================================*/ static int GobiNetDriverBind( struct usbnet * pDev, struct usb_interface * pIntf ) { int numEndpoints; int endpointIndex; struct usb_host_endpoint * pEndpoint = NULL; struct usb_host_endpoint * pIn = NULL; struct usb_host_endpoint * pOut = NULL; DBG( "UnBind GobiNet driver \n" ); // Verify one altsetting if (pIntf->num_altsetting != 1) { DBG( "invalid num_altsetting %u\n", pIntf->num_altsetting ); return -ENODEV; } /* We only accept certain interfaces */ if( InterfaceIsWhitelisted( (signed char)pIntf->cur_altsetting->desc.bInterfaceNumber, (const signed char *)pDev->driver_info->data) == false ) { DBG( "invalid interface %d\n", pIntf->cur_altsetting->desc.bInterfaceNumber ); return -ENODEV; } // Collect In and Out endpoints numEndpoints = pIntf->cur_altsetting->desc.bNumEndpoints; for (endpointIndex = 0; endpointIndex < numEndpoints; endpointIndex++) { pEndpoint = pIntf->cur_altsetting->endpoint + endpointIndex; if (pEndpoint == NULL) { DBG( "invalid endpoint %u\n", endpointIndex ); return -ENODEV; } if (usb_endpoint_dir_in( &pEndpoint->desc ) == true && usb_endpoint_xfer_int( &pEndpoint->desc ) == false) { pIn = pEndpoint; } else if (usb_endpoint_dir_out( &pEndpoint->desc ) == true) { pOut = pEndpoint; } } if (pIn == NULL || pOut == NULL) { DBG( "invalid endpoints\n" ); return -ENODEV; } if (usb_set_interface( pDev->udev, pIntf->cur_altsetting->desc.bInterfaceNumber, 0 ) != 0) { DBG( "unable to set interface\n" ); return -ENODEV; } pDev->in = usb_rcvbulkpipe( pDev->udev, pIn->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ); pDev->out = usb_sndbulkpipe( pDev->udev, pOut->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ); DBG( "in %x, out %x\n", pIn->desc.bEndpointAddress, pOut->desc.bEndpointAddress ); // In later versions of the kernel, usbnet helps with this #if (LINUX_VERSION_CODE <= KERNEL_VERSION( 2,6,23 )) pIntf->dev.platform_data = (void *)pDev; #endif return 0; }
static int carl9170_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_endpoint_descriptor *ep; struct ar9170 *ar; struct usb_device *udev; int i, err; err = usb_reset_device(interface_to_usbdev(intf)); if (err) return err; ar = carl9170_alloc(sizeof(*ar)); if (IS_ERR(ar)) return PTR_ERR(ar); udev = interface_to_usbdev(intf); usb_get_dev(udev); ar->udev = udev; ar->intf = intf; ar->features = id->driver_info; /* We need to remember the type of endpoint 4 because it differs * between high- and full-speed configuration. The high-speed * configuration specifies it as interrupt and the full-speed * configuration as bulk endpoint. This information is required * later when sending urbs to that endpoint. */ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; ++i) { ep = &intf->cur_altsetting->endpoint[i].desc; if (usb_endpoint_num(ep) == AR9170_USB_EP_CMD && usb_endpoint_dir_out(ep) && usb_endpoint_type(ep) == USB_ENDPOINT_XFER_BULK) ar->usb_ep_cmd_is_bulk = true; } usb_set_intfdata(intf, ar); SET_IEEE80211_DEV(ar->hw, &intf->dev); init_usb_anchor(&ar->rx_anch); init_usb_anchor(&ar->rx_pool); init_usb_anchor(&ar->rx_work); init_usb_anchor(&ar->tx_wait); init_usb_anchor(&ar->tx_anch); init_usb_anchor(&ar->tx_cmd); init_usb_anchor(&ar->tx_err); init_completion(&ar->cmd_wait); init_completion(&ar->fw_boot_wait); init_completion(&ar->fw_load_wait); tasklet_init(&ar->usb_tasklet, carl9170_usb_tasklet, (unsigned long)ar); atomic_set(&ar->tx_cmd_urbs, 0); atomic_set(&ar->tx_anch_urbs, 0); atomic_set(&ar->rx_work_urbs, 0); atomic_set(&ar->rx_anch_urbs, 0); atomic_set(&ar->rx_pool_urbs, 0); usb_get_dev(ar->udev); carl9170_set_state(ar, CARL9170_STOPPED); return request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME, &ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2); }
/* FIXME VP 27.12.2010: Really long method */ static int g13_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device* device = interface_to_usbdev(intf); struct usb_host_interface* cur_altsetting = intf->cur_altsetting; struct usb_interface_descriptor desc = cur_altsetting->desc; int usb_register_dev_result; int i; struct usb_host_endpoint endpoint; struct usb_endpoint_descriptor endpoint_descriptor; __u8 bEndpointAddress; __u8 bmAttributes; __u8 bInterval; struct urb* urb; unsigned int in_pipe; __le16 wMaxPacketSize; unsigned char* in_transfer_buffer; unsigned int in_transfer_buffer_length; int input_register_device_result; g13_input_device = input_allocate_device(); if (g13_input_device == NULL) { printk("G13: input_allocate_device failed.\n"); return -1; } g13_input_device->name = "G13"; g13_input_device->evbit[0] = BIT_MASK(EV_KEY); REGISTER_BUTTON(1); REGISTER_BUTTON(2); REGISTER_BUTTON(3); REGISTER_BUTTON(4); REGISTER_BUTTON(5); REGISTER_BUTTON(6); REGISTER_BUTTON(7); REGISTER_BUTTON(8); REGISTER_BUTTON(9); REGISTER_BUTTON(10); REGISTER_BUTTON(11); REGISTER_BUTTON(12); REGISTER_BUTTON(13); REGISTER_BUTTON(14); REGISTER_BUTTON(15); REGISTER_BUTTON(16); REGISTER_BUTTON(17); REGISTER_BUTTON(18); REGISTER_BUTTON(19); REGISTER_BUTTON(20); REGISTER_BUTTON(21); REGISTER_BUTTON(22); input_register_device_result = input_register_device(g13_input_device); if (input_register_device_result) { printk("G13: input_register_device failed: %d\n", input_register_device_result); return input_register_device_result; } for (i = 0; i < desc.bNumEndpoints; i++) { endpoint = cur_altsetting->endpoint[i]; endpoint_descriptor = endpoint.desc; bEndpointAddress = endpoint_descriptor.bEndpointAddress; bmAttributes = endpoint_descriptor.bmAttributes; if (usb_endpoint_dir_in(&endpoint_descriptor)) { /* We know that bmAttributes == USB_ENDPOINT_XFER_INT */ if (usb_endpoint_xfer_int(&endpoint_descriptor)) { bInterval = endpoint_descriptor.bInterval; wMaxPacketSize = endpoint_descriptor.wMaxPacketSize; in_pipe = usb_rcvintpipe(device, bEndpointAddress); in_transfer_buffer = kzalloc((sizeof (unsigned char)) * wMaxPacketSize, GFP_ATOMIC); in_transfer_buffer_length = wMaxPacketSize; urb = usb_alloc_urb(0, GFP_ATOMIC); usb_fill_int_urb(urb, device, in_pipe, in_transfer_buffer, in_transfer_buffer_length, &g13_urb_complete, NULL, bInterval); usb_submit_urb(urb, GFP_ATOMIC); } } else if (usb_endpoint_dir_out(&endpoint_descriptor)) { /* We know that bmAttributes == USB_ENDPOINT_XFER_INT */ if (usb_endpoint_xfer_int(&endpoint_descriptor)) { bInterval = endpoint_descriptor.bInterval; /* TODO VP 27.12.2010: Implement output */ } } else { printk("G13: Bug found! Endpoint not IN nor OUT.\n"); } } usb_register_dev_result = usb_register_dev(intf, &g13_class); if (usb_register_dev_result ) { printk("G13: usb_register_dev failed: %d\n", usb_register_dev_result); return usb_register_dev_result; } printk("G13: Device registration successful.\n"); return 0; }
static int qcnmea_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usb_dev = interface_to_usbdev(intf); struct usb_host_interface *cur_intf = intf->cur_altsetting; int epnum, minor; struct usb_endpoint_descriptor *epread, *epwrite, *eptmp; struct qcnmea *nmea; int i, num_rx_buf = QCNMEA_NR; if(cur_intf->desc.bInterfaceNumber != 1) { /*not the right interface*/ return -ENODEV; } printk(KERN_ALERT "this is qct nmea interface!\n"); epnum = cur_intf->desc.bNumEndpoints; if(epnum != 2) {/*endpoint number error*/ printk(KERN_ALERT "epnum[%d] is wrong!\n", epnum); return -EINVAL; } while(epnum > 0) { eptmp = &cur_intf->endpoint[epnum - 1].desc; if(!eptmp) return -EINVAL; if(usb_endpoint_dir_in(eptmp)) epread = eptmp; else if(usb_endpoint_dir_out(eptmp)) epwrite = eptmp; epnum--; } if(!epwrite || !epread) { printk(KERN_ALERT "epwrite[%d], epread[%d]\n", epwrite, epread); return -EINVAL; } for(minor = 0; (minor < QC_NMEA_MINORS) && qcnmea_tab[minor]; minor++) ; if(minor == QC_NMEA_MINORS) { printk(KERN_ALERT "minor is wrong!\n"); return -ENODEV; } nmea = kzalloc(sizeof(struct qcnmea), GFP_KERNEL); if(!nmea) { printk(KERN_ALERT "in alloc_fail1\n"); goto alloc_fail1; } nmea->usb_dev = usb_dev; nmea->read_size = le16_to_cpu(epread->wMaxPacketSize); nmea->write_size = le16_to_cpu(epwrite->wMaxPacketSize); nmea->intf = intf; spin_lock_init(&nmea->throttle_lock); spin_lock_init(&nmea->write_lock); spin_lock_init(&nmea->read_lock); INIT_WORK(&nmea->write_work, qcnmea_write_work, nmea); nmea->write_ready = 1; nmea->read_pipe = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); if(qcnmea_write_buf_alloc(nmea) < 0) { printk(KERN_ALERT "in alloc_fail4\n"); goto alloc_fail4; } nmea->write_urb = usb_alloc_urb(0, GFP_KERNEL); if(!nmea->write_urb) { printk(KERN_ALERT "in alloc_fail5\n"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct qcnmea_ru *rcv = &(nmea->ru[i]); if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { //dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)"); printk(KERN_ALERT "in alloc_fail7\n"); goto alloc_fail7; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; rcv->instance = nmea; } for (i = 0; i < num_rx_buf; i++) { struct qcnmea_rb *buf = &(nmea->rb[i]); if (!(buf->base = usb_buffer_alloc(nmea->usb_dev, nmea->read_size, GFP_KERNEL, &buf->dma))) { //dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)"); printk(KERN_ALERT "in alloc_fail7,1\n"); goto alloc_fail7; } } tasklet_init(&nmea->rx_tasklet, qcnmea_rx_tasklet, nmea); usb_set_intfdata(intf, nmea); //if(device_create_file(&intf->dev, &dev_attr_bmCapabilities)) // goto alloc_fail7; usb_fill_bulk_urb(nmea->write_urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), nmea->write_buf, nmea->write_size, qcnmea_write_bulk, nmea); nmea->write_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; nmea->line.dwDTERate = cpu_to_le32(9600); nmea->line.bDataBits = 8; qcnmea_set_line(nmea, &nmea->line); qcnmea_set_control(nmea, nmea->seria_out); usb_get_intf(intf); tty_register_device(qcnmea_tty_driver, minor, &intf->dev); nmea->minor = minor; qcnmea_tab[minor] = nmea; printk(KERN_ALERT "qct nmea probe ok!, read_size :%d, write_size :%d\n",nmea->read_size, nmea->write_size); return 0; alloc_fail7: for (i = 0; i < num_rx_buf; i++) usb_buffer_free(usb_dev, nmea->read_size, nmea->rb[i].base, nmea->rb[i].dma); for (i = 0; i < num_rx_buf; i++) usb_free_urb(nmea->ru[i].urb); alloc_fail6: usb_free_urb(nmea->write_urb); alloc_fail5: qcnmea_write_buf_free(nmea); alloc_fail4: alloc_fail3: alloc_fail2: kfree(nmea); alloc_fail1:
/*=========================================================================== METHOD: GobiProbe (Free Method) DESCRIPTION: Attach to correct interfaces PARAMETERS: pSerial [ I ] - Serial structure pID [ I ] - VID PID table RETURN VALUE: int - negative error code on failure zero on success ===========================================================================*/ static int GobiProbe( struct usb_serial * pSerial, const struct usb_device_id * pID ) { // Assume failure int nRetval = -ENODEV; int nNumInterfaces; int nInterfaceNum; DBG( "\n" ); // Test parameters if ( (pSerial == NULL) || (pSerial->dev == NULL) || (pSerial->dev->actconfig == NULL) || (pSerial->interface == NULL) || (pSerial->interface->cur_altsetting == NULL) || (pSerial->type == NULL) ) { DBG( "invalid parameter\n" ); return -EINVAL; } nNumInterfaces = pSerial->dev->actconfig->desc.bNumInterfaces; DBG( "Num Interfaces = %d\n", nNumInterfaces ); nInterfaceNum = pSerial->interface->cur_altsetting->desc.bInterfaceNumber; DBG( "This Interface = %d\n", nInterfaceNum ); if (nNumInterfaces == 1) { // QDL mode? if (nInterfaceNum == 1 || nInterfaceNum == 0) { DBG( "QDL port found\n" ); nRetval = usb_set_interface( pSerial->dev, nInterfaceNum, 0 ); if (nRetval < 0) { DBG( "Could not set interface, error %d\n", nRetval ); } } else { DBG( "Incorrect QDL interface number\n" ); } } else { // Composite mode if (nInterfaceNum == 2) { DBG( "Modem port found\n" ); nRetval = usb_set_interface( pSerial->dev, nInterfaceNum, 0 ); if (nRetval < 0) { DBG( "Could not set interface, error %d\n", nRetval ); } } else if (nInterfaceNum == 3) { DBG( "GPS port found\n" ); nRetval = usb_set_interface( pSerial->dev, nInterfaceNum, 0 ); if (nRetval < 0) { DBG( "Could not set interface, error %d\n", nRetval ); } // Check for recursion if (pSerial->type->close != GobiClose) { // Store usb_serial_generic_close in gpClose gpClose = pSerial->type->close; pSerial->type->close = GobiClose; } } else { // Not a port we want to support at this time DBG( "Unsupported interface number\n" ); } } if (nRetval == 0) { // Clearing endpoint halt is a magic handshake that brings // the device out of low power (airplane) mode // NOTE: FCC verification should be done before this, if required struct usb_host_endpoint * pEndpoint; int endpointIndex; int numEndpoints = pSerial->interface->cur_altsetting ->desc.bInterfaceNumber; for (endpointIndex = 0; endpointIndex < numEndpoints; endpointIndex++) { pEndpoint = pSerial->interface->cur_altsetting->endpoint + endpointIndex; if (pEndpoint != NULL && usb_endpoint_dir_out( &pEndpoint->desc ) == true) { int pipe = usb_sndbulkpipe( pSerial->dev, pEndpoint->desc.bEndpointAddress ); nRetval = usb_clear_halt( pSerial->dev, pipe ); // Should only be one break; } } } return nRetval; }