static void cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf) { struct usb_host_endpoint *e; u8 ep; for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) { e = intf->cur_altsetting->endpoint + ep; switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_INT: if (usb_endpoint_dir_in(&e->desc)) { if (ctx->status_ep == NULL) ctx->status_ep = e; } break; case USB_ENDPOINT_XFER_BULK: if (usb_endpoint_dir_in(&e->desc)) { if (ctx->in_ep == NULL) ctx->in_ep = e; } else { if (ctx->out_ep == NULL) ctx->out_ep = e; } break; default: break; } } }
int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) { int tmp; struct usb_host_interface *alt = NULL; struct usb_host_endpoint *in = NULL, *out = NULL; struct usb_host_endpoint *status = NULL; for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; in = out = status = NULL; alt = intf->altsetting + tmp; for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { struct usb_host_endpoint *e; int intr = 0; e = alt->endpoint + ep; switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_INT: if (!usb_endpoint_dir_in(&e->desc)) continue; intr = 1; case USB_ENDPOINT_XFER_BULK: break; default: continue; } if (usb_endpoint_dir_in(&e->desc)) { if (!intr && !in) in = e; else if (intr && !status) status = e; } else { if (!out) out = e; } } if (in && out) break; } if (!alt || !in || !out) return -EINVAL; if (alt->desc.bAlternateSetting != 0 || !(dev->driver_info->flags & FLAG_NO_SETINT)) { tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) return tmp; } dev->in = usb_rcvbulkpipe (dev->udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out = usb_sndbulkpipe (dev->udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->status = status; return 0; }
/* * * usb_ep_ops * */ static int usbhsg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; int ret = -EIO; unsigned long flags; usbhs_lock(priv, flags); /* * if it already have pipe, * nothing to do */ if (uep->pipe) { usbhs_pipe_clear(uep->pipe); usbhs_pipe_sequence_data0(uep->pipe); ret = 0; goto usbhsg_ep_enable_end; } pipe = usbhs_pipe_malloc(priv, usb_endpoint_type(desc), usb_endpoint_dir_in(desc)); if (pipe) { uep->pipe = pipe; pipe->mod_private = uep; /* set epnum / maxp */ usbhs_pipe_config_update(pipe, 0, usb_endpoint_num(desc), usb_endpoint_maxp(desc)); /* * usbhs_fifo_dma_push/pop_handler try to * use dmaengine if possible. * It will use pio handler if impossible. */ if (usb_endpoint_dir_in(desc)) { pipe->handler = &usbhs_fifo_dma_push_handler; } else { pipe->handler = &usbhs_fifo_dma_pop_handler; usbhs_xxxsts_clear(priv, BRDYSTS, usbhs_pipe_number(pipe)); } ret = 0; } usbhsg_ep_enable_end: usbhs_unlock(priv, flags); return ret; }
static inline u32 xhci_get_endpoint_type(struct usb_device *udev, struct usb_host_endpoint *ep) { int in; u32 type; in = usb_endpoint_dir_in(&ep->desc); if (usb_endpoint_xfer_control(&ep->desc)) { type = EP_TYPE(CTRL_EP); } else if (usb_endpoint_xfer_bulk(&ep->desc)) { if (in) type = EP_TYPE(BULK_IN_EP); else type = EP_TYPE(BULK_OUT_EP); } else if (usb_endpoint_xfer_isoc(&ep->desc)) { if (in) type = EP_TYPE(ISOC_IN_EP); else type = EP_TYPE(ISOC_OUT_EP); } else if (usb_endpoint_xfer_int(&ep->desc)) { if (in) type = EP_TYPE(INT_IN_EP); else type = EP_TYPE(INT_OUT_EP); } else { BUG(); } return type; }
static int ecos_usbserial_probe(struct usb_serial *serial, const struct usb_device_id *id) { struct usb_interface *interface = serial->interface; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int num_bulk_in = 0; int num_bulk_out = 0; int i; iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_xfer_bulk(endpoint)) { if (usb_endpoint_dir_in(endpoint)) { /* we found a bulk in endpoint */ dbg("found bulk in on endpoint %d", i); ++num_bulk_in; } else { /* we found a bulk out endpoint */ dbg("found bulk out on endpoint %d", i); ++num_bulk_out; } } } if (!num_bulk_in || !num_bulk_out) { info("Ignoring interface, insufficient endpoints"); return -ENODEV; } return 0; }
/* this function must be called with interrupt disabled */ static u16 get_empty_pipenum(struct r8a66597 *r8a66597, struct usb_endpoint_descriptor *ep) { u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min; memset(array, 0, sizeof(array)); switch (usb_endpoint_type(ep)) { case USB_ENDPOINT_XFER_BULK: if (usb_endpoint_dir_in(ep)) array[i++] = 4; else { array[i++] = 3; array[i++] = 5; } break; case USB_ENDPOINT_XFER_INT: if (usb_endpoint_dir_in(ep)) { array[i++] = 6; array[i++] = 7; array[i++] = 8; } else array[i++] = 9; break; case USB_ENDPOINT_XFER_ISOC: if (usb_endpoint_dir_in(ep)) array[i++] = 2; else array[i++] = 1; break; default: printk(KERN_ERR "r8a66597: Illegal type\n"); return 0; } i = 1; min = array[0]; while (array[i] != 0) { if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]]) min = array[i]; i++; } return min; }
/** * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and * HCDs. Find the index for an endpoint given its descriptor. Use the return * value to right shift 1 for the bitmask. * * Index = (epnum * 2) + direction - 1, * where direction = 0 for OUT, 1 for IN. * For control endpoints, the IN index is used (OUT index is unused), so * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2) */ unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc) { unsigned int index; if (usb_endpoint_xfer_control(desc)) index = (unsigned int) (usb_endpoint_num(desc)*2); else index = (unsigned int) (usb_endpoint_num(desc)*2) + (usb_endpoint_dir_in(desc) ? 1 : 0) - 1; return index; }
/* Get the pipe settings */ static int get_pipes(struct us_data *us) { struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting; int i; struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct usb_endpoint_descriptor *ep_int = NULL; //--------------------------- pr_info("13 get pipes\n"); /* * Find the first endpoint of each type we need. * We are expecting a minimum of 2 endpoints - in and out (bulk). * An optional interrupt-in is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; if (usb_endpoint_xfer_bulk(ep)) { if (usb_endpoint_dir_in(ep)) { if (!ep_in) ep_in = ep; } else { if (!ep_out) ep_out = ep; } } else if (usb_endpoint_is_int_in(ep)) { if (!ep_int) ep_int = ep; } } if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) { US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); return -EIO; } /* Calculate and store the pipe values */ us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0); us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0); us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, usb_endpoint_num(ep_out)); us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, usb_endpoint_num(ep_in)); if (ep_int) { us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, usb_endpoint_num(ep_int)); us->ep_bInterval = ep_int->bInterval; } return 0; }
static bool match_endpoint(struct usb_endpoint_descriptor *epd, struct usb_endpoint_descriptor **bulk_in, struct usb_endpoint_descriptor **bulk_out, struct usb_endpoint_descriptor **int_in, struct usb_endpoint_descriptor **int_out) { switch (usb_endpoint_type(epd)) { case USB_ENDPOINT_XFER_BULK: if (usb_endpoint_dir_in(epd)) { if (bulk_in && !*bulk_in) { *bulk_in = epd; break; } } else { if (bulk_out && !*bulk_out) { *bulk_out = epd; break; } } return false; case USB_ENDPOINT_XFER_INT: if (usb_endpoint_dir_in(epd)) { if (int_in && !*int_in) { *int_in = epd; break; } } else { if (int_out && !*int_out) { *int_out = epd; break; } } return false; default: return false; } return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) && (!int_in || *int_in) && (!int_out || *int_out); }
static void cdc_ncm_find_endpoints(struct usbnet *dev, struct usb_interface *intf) { struct usb_host_endpoint *e, *in = NULL, *out = NULL; u8 ep; for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) { e = intf->cur_altsetting->endpoint + ep; switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_INT: if (usb_endpoint_dir_in(&e->desc)) { if (!dev->status) dev->status = e; } break; case USB_ENDPOINT_XFER_BULK: if (usb_endpoint_dir_in(&e->desc)) { if (!in) in = e; } else { if (!out) out = e; } break; default: break; } } if (in && !dev->in) dev->in = usb_rcvbulkpipe(dev->udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); if (out && !dev->out) dev->out = usb_sndbulkpipe(dev->udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); }
static int get_pipes(struct rts51x_chip *chip) { struct rts51x_usb *rts51x = chip->usb; struct usb_host_interface *altsetting = rts51x->pusb_intf->cur_altsetting; int i; struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct usb_endpoint_descriptor *ep_int = NULL; for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; if (usb_endpoint_xfer_bulk(ep)) { if (usb_endpoint_dir_in(ep)) { if (!ep_in) ep_in = ep; } else { if (!ep_out) ep_out = ep; } } else if (usb_endpoint_is_int_in(ep)) { if (!ep_int) ep_int = ep; } } if (!ep_in || !ep_out) { RTS51X_DEBUGP("Endpoint sanity check failed!" "Rejecting dev.\n"); return -EIO; } rts51x->send_ctrl_pipe = usb_sndctrlpipe(rts51x->pusb_dev, 0); rts51x->recv_ctrl_pipe = usb_rcvctrlpipe(rts51x->pusb_dev, 0); rts51x->send_bulk_pipe = usb_sndbulkpipe(rts51x->pusb_dev, usb_endpoint_num(ep_out)); rts51x->recv_bulk_pipe = usb_rcvbulkpipe(rts51x->pusb_dev, usb_endpoint_num(ep_in)); if (ep_int) { rts51x->recv_intr_pipe = usb_rcvintpipe(rts51x->pusb_dev, usb_endpoint_num (ep_int)); rts51x->ep_bInterval = ep_int->bInterval; } return 0; }
static int fotg210_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct fotg210_ep *ep; ep = container_of(_ep, struct fotg210_ep, ep); ep->desc = desc; ep->epnum = usb_endpoint_num(desc); ep->type = usb_endpoint_type(desc); ep->dir_in = usb_endpoint_dir_in(desc); ep->ep.maxpacket = usb_endpoint_maxp(desc); return fotg210_config_ep(ep, desc); }
/* handle a synchronous IN bulk/intr/iso transfer */ static ssize_t ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) { struct ep_data *data = fd->private_data; void *kbuf; ssize_t value; if ((value = get_ready_ep (fd->f_flags, data)) < 0) return value; /* halt any endpoint by doing a "wrong direction" i/o call */ if (!usb_endpoint_dir_in(&data->desc)) { if (usb_endpoint_xfer_isoc(&data->desc)) { mutex_unlock(&data->lock); return -EINVAL; } DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); if (likely (data->ep != NULL)) usb_ep_set_halt (data->ep); spin_unlock_irq (&data->dev->lock); mutex_unlock(&data->lock); return -EBADMSG; } /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ value = -ENOMEM; kbuf = kmalloc (len, GFP_KERNEL); if (!kbuf) goto free1; if (copy_from_user (kbuf, buf, len)) { value = -EFAULT; goto free1; } value = ep_io (data, kbuf, len); VDEBUG (data->dev, "%s write %zu IN, status %d\n", data->name, len, (int) value); free1: mutex_unlock(&data->lock); kfree (kbuf); return value; }
/* handle a synchronous OUT bulk/intr/iso transfer */ static ssize_t ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) { struct ep_data *data = fd->private_data; void *kbuf; ssize_t value; if ((value = get_ready_ep (fd->f_flags, data)) < 0) return value; /* halt any endpoint by doing a "wrong direction" i/o call */ if (usb_endpoint_dir_in(&data->desc)) { if (usb_endpoint_xfer_isoc(&data->desc)) { mutex_unlock(&data->lock); return -EINVAL; } DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); if (likely (data->ep != NULL)) usb_ep_set_halt (data->ep); spin_unlock_irq (&data->dev->lock); mutex_unlock(&data->lock); return -EBADMSG; } /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */ value = -ENOMEM; kbuf = kmalloc (len, GFP_KERNEL); if (unlikely (!kbuf)) goto free1; value = ep_io (data, kbuf, len); VDEBUG (data->dev, "%s read %zu OUT, status %d\n", data->name, len, (int) value); if (value >= 0 && copy_to_user (buf, kbuf, value)) value = -EFAULT; free1: mutex_unlock(&data->lock); kfree (kbuf); return value; }
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_ep_ops * */ static int usbhsg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; spinlock_t *lock; unsigned long flags; int ret = -EIO; /* * if it already have pipe, * nothing to do */ if (uep->pipe) return 0; /******************** spin lock ********************/ lock = usbhsg_trylock(gpriv, &flags); pipe = usbhs_pipe_malloc(priv, desc); if (pipe) { uep->pipe = pipe; pipe->mod_private = uep; INIT_LIST_HEAD(&uep->list); if (usb_endpoint_dir_in(desc)) uep->handler = &usbhsg_handler_send_packet; else uep->handler = &usbhsg_handler_recv_packet; ret = 0; } usbhsg_unlock(lock, &flags); /******************** spin unlock ******************/ return ret; }
/* * * usb_ep_ops * */ static int usbhsg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; int ret = -EIO; /* * if it already have pipe, * nothing to do */ if (uep->pipe) { usbhs_pipe_clear(uep->pipe); usbhs_pipe_clear_sequence(uep->pipe); return 0; } pipe = usbhs_pipe_malloc(priv, desc); if (pipe) { uep->pipe = pipe; pipe->mod_private = uep; /* * usbhs_fifo_dma_push/pop_handler try to * use dmaengine if possible. * It will use pio handler if impossible. */ if (usb_endpoint_dir_in(desc)) uep->handler = &usbhs_fifo_dma_push_handler; else uep->handler = &usbhs_fifo_dma_pop_handler; ret = 0; } return ret; }
/* 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 acm_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; struct usb_interface *data_interface; struct usb_endpoint_descriptor *epctrl; struct usb_endpoint_descriptor *epread; struct usb_endpoint_descriptor *epwrite; struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; int minor; int ctrlsize,readsize; u8 *buf; u8 ac_management_function = 0; u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num; unsigned long quirks; int num_rx_buf; int i; /* normal quirks */ quirks = (unsigned long)id->driver_info; num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; /* handle quirks deadly to normal probing*/ if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); goto skip_normal_probe; } /* normal probing*/ if (!buffer) { err("Weird descriptor references\n"); return -EINVAL; } if (!buflen) { if (intf->cur_altsetting->endpoint && intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { err("Zero length descriptor references\n"); return -EINVAL; } } while (buflen > 0) { if (buffer [1] != USB_DT_CS_INTERFACE) { err("skipping garbage\n"); goto next_desc; } switch (buffer [2]) { case USB_CDC_UNION_TYPE: /* we've found it */ if (union_header) { err("More than one union descriptor, skipping ..."); goto next_desc; } union_header = (struct usb_cdc_union_desc *) buffer; break; case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ cfd = (struct usb_cdc_country_functional_desc *)buffer; break; case USB_CDC_HEADER_TYPE: /* maybe check version */ break; /* for now we ignore it */ case USB_CDC_ACM_TYPE: ac_management_function = buffer[3]; break; case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; if ((call_management_function & 3) != 3) err("This device cannot do calls on its own. It is no modem."); break; default: /* there are LOTS more CDC descriptors that * could legitimately be found here. */ dev_dbg(&intf->dev, "Ignoring descriptor: " "type %02x, length %d\n", buffer[2], buffer[0]); break; } next_desc: buflen -= buffer[0]; buffer += buffer[0]; } if (!union_header) { if (call_interface_num > 0) { dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { dev_dbg(&intf->dev,"No union descriptor, giving up\n"); return -ENODEV; } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { dev_dbg(&intf->dev,"no interfaces\n"); return -ENODEV; } } if (data_interface_num != call_interface_num) dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n"); skip_normal_probe: /*workaround for switched interfaces */ if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); t = control_interface; control_interface = data_interface; data_interface = t; } else { return -EINVAL; } } /* Accept probe requests only for the control interface */ if (intf != control_interface) return -ENODEV; if (usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev,"The data interface isn't available\n"); return -EBUSY; } if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; epread = &data_interface->cur_altsetting->endpoint[0].desc; epwrite = &data_interface->cur_altsetting->endpoint[1].desc; /* workaround for switched endpoints */ if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); t = epread; epread = epwrite; epwrite = t; } dbg("interfaces are valid"); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); if (minor == ACM_TTY_MINORS) { err("no more free acm devices"); return -ENODEV; } if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; acm->control = control_interface; acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; acm->ctrl_caps = ac_management_function; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; acm->urb_task.func = acm_rx_tasklet; acm->urb_task.data = (unsigned long) acm; INIT_WORK(&acm->work, acm_softint); INIT_WORK(&acm->waker, acm_waker); spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->write_ready = 1; acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n"); goto alloc_fail2; } acm->ctrl_buffer = buf; if (acm_write_buffers_alloc(acm) < 0) { dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); goto alloc_fail4; } acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct acm_ru *rcv = &(acm->ru[i]); if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); goto alloc_fail7; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; rcv->instance = acm; } for (i = 0; i < num_rx_buf; i++) { struct acm_rb *buf = &(acm->rb[i]); if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); goto alloc_fail7; } } for(i = 0; i < ACM_NW; i++) { struct acm_wb *snd = &(acm->wb[i]); if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); goto alloc_fail7; } usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->instance = acm; } usb_set_intfdata (intf, acm); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); if (i < 0) goto alloc_fail8; if (cfd) { /* export the country data */ acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); goto skip_countries; } i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { kfree(acm->country_codes); goto skip_countries; } } skip_countries: usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); acm_set_control(acm, acm->ctrlout); acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_get_intf(control_interface); tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; return 0; alloc_fail8: for (i = 0; i < ACM_NW; i++) usb_free_urb(acm->wb[i].urb); alloc_fail7: acm_read_buffers_free(acm); for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ctrlurb); alloc_fail5: acm_write_buffers_free(acm); alloc_fail4: usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); alloc_fail2: kfree(acm); alloc_fail: return -ENOMEM; }
static int pixcir_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_host_interface *interface = intf->cur_altsetting; struct usb_device *dev = interface_to_usbdev(intf); struct input_dev *input_dev1; int n = 0, insize = TOUCH_PACKAGE_LEN; int err; const char *path; int len; char input_buf[10]; struct pixcir_mt_usb *psmt = kzalloc(sizeof(struct pixcir_mt_usb), GFP_KERNEL); kref_init(&psmt->kref); mutex_init(&psmt->io_mutex); printk("%s\n", __FUNCTION__); psmt->type = &type; psmt->udev = dev; if (dev->manufacturer) strlcpy(psmt->name, dev->manufacturer, sizeof(psmt->name)); if (dev->product) { if (dev->manufacturer) strlcat(psmt->name, " ", sizeof(psmt->name)); strlcat(psmt->name, dev->product, sizeof(psmt->name)); } if (!strlen(psmt->name)) snprintf(psmt->name, sizeof(psmt->name), "USB Touchscreen %04x:%04x", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); if (!psmt->type->process_pkt) { printk("process_pkt is null\n"); psmt->type->process_pkt = usbtouch_process_pkt; } usb_set_intfdata(intf, psmt); err = usb_register_dev(intf,&pixcir_class_driver); if(err){ printk("Not able to get minor for this device."); } dev_info(&intf->dev,"now attach to USB-%d",intf->minor); input_dev1 = input_allocate_device(); input_dev1->name = "pixcir_usb_ts"; usb_to_input_id(dev, &input_dev1->id); psmt->input_dev = input_dev1; if(!psmt|| !input_dev1) { printk("Memory is not enough\n"); goto fail1; } input_dev1->dev.parent = &intf->dev; input_set_drvdata(input_dev1, psmt); set_bit(EV_SYN, input_dev1->evbit); set_bit(EV_KEY, input_dev1->evbit); set_bit(EV_ABS, input_dev1->evbit); set_bit(BTN_TOUCH, input_dev1->keybit); input_set_abs_params(input_dev1, ABS_X, psmt->type->min_xc, psmt->type->max_xc, 0, 0); input_set_abs_params(input_dev1, ABS_Y, psmt->type->min_yc, psmt->type->max_yc, 0, 0); input_set_abs_params(input_dev1, ABS_MT_POSITION_X, psmt->type->min_xc, psmt->type->max_xc, 0, 0); input_set_abs_params(input_dev1, ABS_MT_POSITION_Y, psmt->type->min_yc, psmt->type->max_yc, 0, 0); input_set_abs_params(input_dev1, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(input_dev1, ABS_MT_WIDTH_MAJOR, 0, 25, 0, 0); psmt->data = usb_alloc_coherent(dev, insize, GFP_KERNEL, &psmt->data_dma); if(!psmt->data) { printk("psmt->data allocating fail"); goto fail; } for (n = 0; n < interface->desc.bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint; int pipe; int interval; endpoint = &interface->endpoint[n].desc; /*find a int endpoint*/ if (!usb_endpoint_xfer_int(endpoint)) continue; interval = endpoint->bInterval; if (usb_endpoint_dir_in(endpoint)) { if (psmt->urb) continue; if (!(psmt->urb = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); usb_fill_int_urb(psmt->urb, dev, pipe, psmt->data, insize, pixcir_mt_irq, psmt, interval); psmt->urb->transfer_dma = psmt->data_dma; psmt->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } } if (usb_submit_urb(psmt->urb, GFP_ATOMIC)) { printk("usb submit urb error\n"); return -EIO; } err = input_register_device(psmt->input_dev); if(err) { printk("pixcir_probe: Could not register input device(touchscreen)!\n"); return -EIO; } path = kobject_get_path(&psmt->input_dev->dev.kobj, GFP_KERNEL); len=strlen(path); if(len>10){ if(path[len-2]=='t'){ memset(input_buf,'\0',9); strncpy(input_buf,&path[len-6],6); }else if(path[len-3]=='t'){ memset(input_buf,'\0',9); strncpy(input_buf,&path[len-7],7); }else{ goto fail; } }else{ goto fail; } usb_make_path(dev, psmt->phys0, sizeof(psmt->phys0)); strlcat(psmt->phys0,input_buf, sizeof(psmt->phys0)); return 0; fail: usb_free_urb(psmt->urb); psmt->urb = NULL; usb_free_coherent(dev, insize, psmt->data, psmt->data_dma); fail1: input_free_device(input_dev1); kfree(psmt); return 1; }
/*=========================================================================== METHOD: GatherEndpoints (Public Method) DESCRIPTION: Enumerate endpoints PARAMETERS pIntf [ I ] - Pointer to usb interface RETURN VALUE: sEndpoints structure NULL for failure ===========================================================================*/ sEndpoints * GatherEndpoints( struct usb_interface * pIntf ) { int numEndpoints; int endpointIndex; sEndpoints * pOut; struct usb_host_endpoint * pEndpoint = NULL; pOut = kzalloc( sizeof( sEndpoints ), GFP_ATOMIC ); if (pOut == NULL) { DBG( "unable to allocate memory\n" ); return NULL; } pOut->mIntfNum = pIntf->cur_altsetting->desc.bInterfaceNumber; // Scan 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 ); kfree( pOut ); return NULL; } if (usb_endpoint_dir_in( &pEndpoint->desc ) == true && usb_endpoint_xfer_int( &pEndpoint->desc ) == true) { pOut->mIntInEndp = pEndpoint->desc.bEndpointAddress; } else if (usb_endpoint_dir_in( &pEndpoint->desc ) == true && usb_endpoint_xfer_int( &pEndpoint->desc ) == false) { pOut->mBlkInEndp = pEndpoint->desc.bEndpointAddress; } else if (usb_endpoint_dir_in( &pEndpoint->desc ) == false && usb_endpoint_xfer_int( &pEndpoint->desc ) == false) { pOut->mBlkOutEndp = pEndpoint->desc.bEndpointAddress; } } if (pOut->mIntInEndp == 0 || pOut->mBlkInEndp == 0 || pOut->mBlkOutEndp == 0) { DBG( "One or more endpoints missing\n" ); kfree( pOut ); return NULL; } DBG( "intf %u\n", pOut->mIntfNum ); DBG( " int in 0x%02x\n", pOut->mIntInEndp ); DBG( " blk in 0x%02x\n", pOut->mBlkInEndp ); DBG( " blk out 0x%02x\n", pOut->mBlkOutEndp ); return pOut; }
static int get_endpoints(struct usbtest_dev *dev, struct usb_interface *intf) { int tmp; struct usb_host_interface *alt; struct usb_host_endpoint *in, *out; struct usb_host_endpoint *iso_in, *iso_out; struct usb_device *udev; for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; in = out = NULL; iso_in = iso_out = NULL; alt = intf->altsetting + tmp; /* take the first altsetting with in-bulk + out-bulk; * ignore other endpoints and altsettings. */ for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { struct usb_host_endpoint *e; e = alt->endpoint + ep; switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_BULK: break; case USB_ENDPOINT_XFER_ISOC: if (dev->info->iso) goto try_iso; /* FALLTHROUGH */ default: continue; } if (usb_endpoint_dir_in(&e->desc)) { if (!in) in = e; } else { if (!out) out = e; } continue; try_iso: if (usb_endpoint_dir_in(&e->desc)) { if (!iso_in) iso_in = e; } else { if (!iso_out) iso_out = e; } } if ((in && out) || iso_in || iso_out) goto found; } return -EINVAL; found: udev = testdev_to_usbdev(dev); if (alt->desc.bAlternateSetting != 0) { tmp = usb_set_interface(udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) return tmp; } if (in) { dev->in_pipe = usb_rcvbulkpipe(udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out_pipe = usb_sndbulkpipe(udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } if (iso_in) { dev->iso_in = &iso_in->desc; dev->in_iso_pipe = usb_rcvisocpipe(udev, iso_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } if (iso_out) { dev->iso_out = &iso_out->desc; dev->out_iso_pipe = usb_sndisocpipe(udev, iso_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); } return 0; }
/* handles CDC Ethernet and many other network "bulk data" interfaces */ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) { int tmp; struct usb_host_interface *alt = NULL; struct usb_host_endpoint *in = NULL, *out = NULL; struct usb_host_endpoint *status = NULL; for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; in = out = status = NULL; alt = intf->altsetting + tmp; /* take the first altsetting with in-bulk + out-bulk; * remember any status endpoint, just in case; * ignore other endpoints and altsettings. */ for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { struct usb_host_endpoint *e; int intr = 0; e = alt->endpoint + ep; switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_INT: if (!usb_endpoint_dir_in(&e->desc)) continue; intr = 1; /* FALLTHROUGH */ case USB_ENDPOINT_XFER_BULK: break; default: continue; } if (usb_endpoint_dir_in(&e->desc)) { if (!intr && !in) in = e; else if (intr && !status) status = e; } else { if (!out) out = e; } } if (in && out) break; } if (!alt || !in || !out) return -EINVAL; if (alt->desc.bAlternateSetting != 0 || !(dev->driver_info->flags & FLAG_NO_SETINT)) { tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) return tmp; } dev->in = usb_rcvbulkpipe (dev->udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->out = usb_sndbulkpipe (dev->udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->status = status; #ifdef LG_FW_HSIC_EMS_DEBUG /* secheol.pyo - endpoint logging */ printk("[%s] usbnet bulk_in_Addr = %d, bulk_out_Addr = %d, bulk_in_endpoint = %d , bulk_out_endpoint = %d \n", __func__, in->desc.bEndpointAddress, out->desc.bEndpointAddress, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); #endif /* secheol.pyo - endpoint logging */ 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; 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 acm_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; struct usb_interface *data_interface; struct usb_endpoint_descriptor *epctrl = NULL; struct usb_endpoint_descriptor *epread = NULL; struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; int minor; int ctrlsize, readsize; u8 *buf; u8 ac_management_function = 0; u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num = -1; unsigned long quirks; int num_rx_buf; int i; int combined_interfaces = 0; /* normal quirks */ quirks = (unsigned long)id->driver_info; num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; /* handle quirks deadly to normal probing*/ if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); /* we would crash */ if (!data_interface || !control_interface) return -ENODEV; goto skip_normal_probe; } /* normal probing*/ if (!buffer) { dev_err(&intf->dev, "Weird descriptor references\n"); return -EINVAL; } if (!buflen) { if (intf->cur_altsetting->endpoint && intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { dev_dbg(&intf->dev, "Seeking extra descriptors on endpoint\n"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { dev_err(&intf->dev, "Zero length descriptor references\n"); return -EINVAL; } } while (buflen > 0) { if (buffer[1] != USB_DT_CS_INTERFACE) { dev_err(&intf->dev, "skipping garbage\n"); goto next_desc; } switch (buffer[2]) { case USB_CDC_UNION_TYPE: /* we've found it */ if (union_header) { dev_err(&intf->dev, "More than one " "union descriptor, skipping ...\n"); goto next_desc; } union_header = (struct usb_cdc_union_desc *)buffer; break; case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ cfd = (struct usb_cdc_country_functional_desc *)buffer; break; case USB_CDC_HEADER_TYPE: /* maybe check version */ break; /* for now we ignore it */ case USB_CDC_ACM_TYPE: ac_management_function = buffer[3]; break; case USB_CDC_CALL_MANAGEMENT_TYPE: call_management_function = buffer[3]; call_interface_num = buffer[4]; if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); break; default: /* there are LOTS more CDC descriptors that * could legitimately be found here. */ dev_dbg(&intf->dev, "Ignoring descriptor: " "type %02x, length %d\n", buffer[2], buffer[0]); break; } next_desc: buflen -= buffer[0]; buffer += buffer[0]; } if (!union_header) { if (call_interface_num > 0) { dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); /* quirks for Droids MuIn LCD */ if (quirks & NO_DATA_INTERFACE) data_interface = usb_ifnum_to_if(usb_dev, 0); else data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { if (intf->cur_altsetting->desc.bNumEndpoints != 3) { dev_dbg(&intf->dev,"No union descriptor, giving up\n"); return -ENODEV; } else { dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); combined_interfaces = 1; control_interface = data_interface = intf; goto look_for_collapsed_interface; } } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { dev_dbg(&intf->dev, "no interfaces\n"); return -ENODEV; } } if (data_interface_num != call_interface_num) dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); if (control_interface == data_interface) { /* some broken devices designed for windows work this way */ dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); combined_interfaces = 1; /* a popular other OS doesn't use it */ quirks |= NO_CAP_LINE; if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); return -EINVAL; } look_for_collapsed_interface: for (i = 0; i < 3; i++) { struct usb_endpoint_descriptor *ep; ep = &data_interface->cur_altsetting->endpoint[i].desc; if (usb_endpoint_is_int_in(ep)) epctrl = ep; else if (usb_endpoint_is_bulk_out(ep)) epwrite = ep; else if (usb_endpoint_is_bulk_in(ep)) epread = ep; else return -EINVAL; } if (!epctrl || !epread || !epwrite) return -ENODEV; else goto made_compressed_probe; } skip_normal_probe: /*workaround for switched interfaces */ if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; dev_dbg(&intf->dev, "Your device has switched interfaces.\n"); t = control_interface; control_interface = data_interface; data_interface = t; } else { return -EINVAL; } } /* Accept probe requests only for the control interface */ if (!combined_interfaces && intf != control_interface) return -ENODEV; if (!combined_interfaces && usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev, "The data interface isn't available\n"); return -EBUSY; } if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 || control_interface->cur_altsetting->desc.bNumEndpoints == 0) return -EINVAL; epctrl = &control_interface->cur_altsetting->endpoint[0].desc; epread = &data_interface->cur_altsetting->endpoint[0].desc; epwrite = &data_interface->cur_altsetting->endpoint[1].desc; /* workaround for switched endpoints */ if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev, "The data interface has switched endpoints\n"); t = epread; epread = epwrite; epwrite = t; } made_compressed_probe: dev_dbg(&intf->dev, "interfaces are valid\n"); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); if (minor == ACM_TTY_MINORS) { dev_err(&intf->dev, "no more free acm devices\n"); return -ENODEV; } acm = kzalloc(sizeof(struct acm), GFP_KERNEL); if (acm == NULL) { dev_err(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize) * (quirks == SINGLE_RX_URB ? 1 : 2); acm->combined_interfaces = combined_interfaces; acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; acm->control = control_interface; acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; acm->ctrl_caps = ac_management_function; if (quirks & NO_CAP_LINE) acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; INIT_WORK(&acm->work, acm_softint); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); acm->is_int_ep = usb_endpoint_xfer_int(epread); if (acm->is_int_ep) acm->bInterval = epread->bInterval; tty_port_init(&acm->port); acm->port.ops = &acm_port_ops; buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); goto alloc_fail2; } acm->ctrl_buffer = buf; if (acm_write_buffers_alloc(acm) < 0) { dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); goto alloc_fail4; } acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); goto alloc_fail5; } for (i = 0; i < num_rx_buf; i++) { struct acm_rb *rb = &(acm->read_buffers[i]); struct urb *urb; rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, &rb->dma); if (!rb->base) { dev_err(&intf->dev, "out of memory " "(read bufs usb_alloc_coherent)\n"); goto alloc_fail6; } rb->index = i; rb->instance = acm; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { dev_err(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); goto alloc_fail6; } urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = rb->dma; if (acm->is_int_ep) { usb_fill_int_urb(urb, acm->dev, acm->rx_endpoint, rb->base, acm->readsize, acm_read_bulk_callback, rb, acm->bInterval); } else { usb_fill_bulk_urb(urb, acm->dev, acm->rx_endpoint, rb->base, acm->readsize, acm_read_bulk_callback, rb); } acm->read_urbs[i] = urb; __set_bit(i, &acm->read_urbs_free); } for (i = 0; i < ACM_NW; i++) { struct acm_wb *snd = &(acm->wb[i]); snd->urb = usb_alloc_urb(0, GFP_KERNEL); if (snd->urb == NULL) { dev_err(&intf->dev, "out of memory (write urbs usb_alloc_urb)\n"); goto alloc_fail7; } if (usb_endpoint_xfer_int(epwrite)) usb_fill_int_urb(snd->urb, usb_dev, usb_sndintpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); else usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->instance = acm; } usb_set_intfdata(intf, acm); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); if (i < 0) goto alloc_fail7; if (cfd) { /* export the country data */ acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); acm->country_codes = NULL; acm->country_code_size = 0; goto skip_countries; } i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); acm->country_codes = NULL; acm->country_code_size = 0; goto skip_countries; } } skip_countries: usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, /* works around buggy devices */ epctrl->bInterval ? epctrl->bInterval : 0xff); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); acm_set_control(acm, acm->ctrlout); acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_set_intfdata(data_interface, acm); usb_get_intf(control_interface); tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; return 0; alloc_fail7: for (i = 0; i < ACM_NW; i++) usb_free_urb(acm->wb[i].urb); alloc_fail6: for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->read_urbs[i]); acm_read_buffers_free(acm); usb_free_urb(acm->ctrlurb); alloc_fail5: acm_write_buffers_free(acm); alloc_fail4: usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); alloc_fail2: kfree(acm); alloc_fail: return -ENOMEM; }
static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) { return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd); }
/*=========================================================================== 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; }
/* 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; }
static int goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct goku_udc *dev; struct goku_ep *ep; u32 mode; u16 max; unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; dev = ep->dev; if (ep == &dev->ep[0]) return -EINVAL; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; if (ep->num != usb_endpoint_num(desc)) return -EINVAL; switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: break; default: return -EINVAL; } if ((readl(ep->reg_status) & EPxSTATUS_EP_MASK) != EPxSTATUS_EP_INVALID) return -EBUSY; /* enabling the no-toggle interrupt mode would need an api hook */ mode = 0; max = get_unaligned_le16(&desc->wMaxPacketSize); switch (max) { case 64: mode++; case 32: mode++; case 16: mode++; case 8: mode <<= 3; break; default: return -EINVAL; } mode |= 2 << 1; /* bulk, or intr-with-toggle */ /* ep1/ep2 dma direction is chosen early; it works in the other * direction, with pio. be cautious with out-dma. */ ep->is_in = usb_endpoint_dir_in(desc); if (ep->is_in) { mode |= 1; ep->dma = (use_dma != 0) && (ep->num == UDC_MSTRD_ENDPOINT); } else { ep->dma = (use_dma == 2) && (ep->num == UDC_MSTWR_ENDPOINT); if (ep->dma) DBG(dev, "%s out-dma hides short packets\n", ep->ep.name); } spin_lock_irqsave(&ep->dev->lock, flags); /* ep1 and ep2 can do double buffering and/or dma */ if (ep->num < 3) { struct goku_udc_regs __iomem *regs = ep->dev->regs; u32 tmp; /* double buffer except (for now) with pio in */ tmp = ((ep->dma || !ep->is_in) ? 0x10 /* double buffered */ : 0x11 /* single buffer */ ) << ep->num; tmp |= readl(®s->EPxSingle); writel(tmp, ®s->EPxSingle); tmp = (ep->dma ? 0x10/*dma*/ : 0x11/*pio*/) << ep->num; tmp |= readl(®s->EPxBCS); writel(tmp, ®s->EPxBCS); } writel(mode, ep->reg_mode); command(ep->dev->regs, COMMAND_RESET, ep->num); ep->ep.maxpacket = max; ep->stopped = 0; ep->ep.desc = desc; spin_unlock_irqrestore(&ep->dev->lock, flags); DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name, ep->is_in ? "IN" : "OUT", ep->dma ? "dma" : "pio", max); return 0; }
static int brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usb = interface_to_usbdev(intf); struct brcmf_usbdev_info *devinfo; struct usb_interface_descriptor *desc; struct usb_endpoint_descriptor *endpoint; int ret = 0; u32 num_of_eps; u8 endpoint_num, ep; brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct); devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC); if (devinfo == NULL) return -ENOMEM; devinfo->usbdev = usb; devinfo->dev = &usb->dev; /* Take an init lock, to protect for disconnect while still loading. * Necessary because of the asynchronous firmware load construction */ mutex_init(&devinfo->dev_init_lock); mutex_lock(&devinfo->dev_init_lock); usb_set_intfdata(intf, devinfo); /* Check that the device supports only one configuration */ if (usb->descriptor.bNumConfigurations != 1) { brcmf_err("Number of configurations: %d not supported\n", usb->descriptor.bNumConfigurations); ret = -ENODEV; goto fail; } if ((usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) && (usb->descriptor.bDeviceClass != USB_CLASS_MISC) && (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS_CONTROLLER)) { brcmf_err("Device class: 0x%x not supported\n", usb->descriptor.bDeviceClass); ret = -ENODEV; goto fail; } desc = &intf->altsetting[0].desc; if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || (desc->bInterfaceSubClass != 2) || (desc->bInterfaceProtocol != 0xff)) { brcmf_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n", desc->bInterfaceNumber, desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol); ret = -ENODEV; goto fail; } num_of_eps = desc->bNumEndpoints; for (ep = 0; ep < num_of_eps; ep++) { endpoint = &intf->altsetting[0].endpoint[ep].desc; endpoint_num = usb_endpoint_num(endpoint); if (!usb_endpoint_xfer_bulk(endpoint)) continue; if (usb_endpoint_dir_in(endpoint)) { if (!devinfo->rx_pipe) devinfo->rx_pipe = usb_rcvbulkpipe(usb, endpoint_num); } else { if (!devinfo->tx_pipe) devinfo->tx_pipe = usb_sndbulkpipe(usb, endpoint_num); } } if (devinfo->rx_pipe == 0) { brcmf_err("No RX (in) Bulk EP found\n"); ret = -ENODEV; goto fail; } if (devinfo->tx_pipe == 0) { brcmf_err("No TX (out) Bulk EP found\n"); ret = -ENODEV; goto fail; } devinfo->ifnum = desc->bInterfaceNumber; if (usb->speed == USB_SPEED_SUPER) brcmf_dbg(USB, "Broadcom super speed USB WLAN interface detected\n"); else if (usb->speed == USB_SPEED_HIGH) brcmf_dbg(USB, "Broadcom high speed USB WLAN interface detected\n"); else brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n"); ret = brcmf_usb_probe_cb(devinfo); if (ret) goto fail; /* Success */ return 0; fail: mutex_unlock(&devinfo->dev_init_lock); kfree(devinfo); usb_set_intfdata(intf, NULL); return ret; }