static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { struct eth_dev *dev = netdev_priv(net); int length = skb->len; int retval; struct usb_request *req = NULL; unsigned long flags; struct usb_ep *in; u16 cdc_filter; spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { in = dev->port_usb->in_ep; cdc_filter = dev->port_usb->cdc_filter; } else { in = NULL; cdc_filter = 0; } spin_unlock_irqrestore(&dev->lock, flags); if (!in) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } /* apply outgoing CDC or RNDIS filters */ if (!is_promisc(cdc_filter)) { u8 *dest = skb->data; if (is_multicast_ether_addr(dest)) { u16 type; /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host * SET_ETHERNET_MULTICAST_FILTERS requests */ if (is_broadcast_ether_addr(dest)) type = USB_CDC_PACKET_TYPE_BROADCAST; else type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } } /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ } spin_lock_irqsave(&dev->req_lock, flags); /* * this freelist can be empty if an interrupt triggered disconnect() * and reconfigured the gadget (shutting down this queue) after the * network stack decided to xmit but before we got the spinlock. */ if (list_empty(&dev->tx_reqs)) { spin_unlock_irqrestore(&dev->req_lock, flags); return NETDEV_TX_BUSY; } req = container_of(dev->tx_reqs.next, struct usb_request, list); list_del(&req->list); /* temporarily stop TX queue when the freelist empties */ if (list_empty(&dev->tx_reqs)) netif_stop_queue(net); spin_unlock_irqrestore(&dev->req_lock, flags); /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. * or there's not enough space for extra headers we need */ if (dev->wrap) { unsigned long flags; spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); spin_unlock_irqrestore(&dev->lock, flags); if (!skb) goto drop; length = skb->len; } req->buf = skb->data; req->context = skb; req->complete = tx_complete; /* use zlp framing on tx for strict CDC-Ether conformance, * though any robust network rx path ignores extra padding. * and some hardware doesn't like to write zlps. */ req->zero = 1; if (!dev->zlp && (length % in->maxpacket) == 0) length++; req->length = length; /* throttle highspeed IRQ rate back slightly */ if (gadget_is_dualspeed(dev->gadget)) req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) : 0; retval = usb_ep_queue(in, req, GFP_ATOMIC); switch (retval) { default: DBG(dev, "tx queue err %d\n", retval); break; case 0: net->trans_start = jiffies; atomic_inc(&dev->tx_qlen); } if (retval) { dev_kfree_skb_any(skb); drop: dev->net->stats.tx_dropped++; spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) netif_start_queue(net); list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } return NETDEV_TX_OK; }
static int dtf_allocate_endpoints(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct dtf_dev *dev = func_to_dtf(f); struct usb_request *req; struct usb_ep *ep; _dbgmsg( "IN\n" ); /* allocate endpoints: PipeGroup1 intrrupt */ _dbgmsg_gadget( "usb_ep_autoconfig\n" ); ep = usb_ep_autoconfig(cdev->gadget, &vPg1_epintr_desc); if( !ep ) { _dbgmsg( "usb_ep_autoconfig for PG1 ep_intr failed\n" ); return -ENODEV; } _dbgmsg("usb_ep_autoconfig for PG1 ep_intr got %s\n", ep->name); ep->driver_data = dev; dev->pg.ep_intr = ep; /* allocate endpoints: PipeGroup1 bulk(in) */ _dbgmsg_gadget( "usb_ep_autoconfig\n" ); ep = usb_ep_autoconfig(cdev->gadget, &vPg1_epin_desc); if( !ep ) { _dbgmsg( "usb_ep_autoconfig for PG1 ep_in failed\n" ); return -ENODEV; } _dbgmsg("usb_ep_autoconfig for PG1 ep_in got %s\n", ep->name); ep->driver_data = dev; dev->pg.ep_in = ep; /* allocate endpoints: PipeGroup1 bulk(out) */ _dbgmsg_gadget( "usb_ep_autoconfig\n" ); ep = usb_ep_autoconfig(cdev->gadget, &vPg1_epout_desc); if( !ep ) { _dbgmsg( "usb_ep_autoconfig for PG1 ep_out failed\n" ); return -ENODEV; } _dbgmsg("usb_ep_autoconfig for PG1 ep_out got %s\n", ep->name); ep->driver_data = dev; dev->pg.ep_out = ep; /* support high speed hardware */ if (gadget_is_dualspeed(cdev->gadget)) { vPg1_epintr_desc_hs.bEndpointAddress = vPg1_epintr_desc.bEndpointAddress; vPg1_epin_desc_hs.bEndpointAddress = vPg1_epin_desc.bEndpointAddress; vPg1_epout_desc_hs.bEndpointAddress = vPg1_epout_desc.bEndpointAddress; } _dbgmsg("%s speed %s: PG1[INTR/%s, IN/%s, OUT/%s]\n", gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", f->name, dev->pg.ep_intr->name, dev->pg.ep_in->name, dev->pg.ep_out->name); /* allocate request for endpoints */ req = dtf_request_new( dev->pg.ep_intr, 16 ); if(!req) { _dbgmsg( "create request error\n" ); return -ENODEV; } req->complete = dtf_complete_intr; dev->pg.mReq_intr = req; req = dtf_request_new( dev->pg.ep_in, 512 ); if(!req) { _dbgmsg( "create request error\n" ); return -ENODEV; } req->complete = dtf_complete_in; dev->pg.mReq_in = req; req = dtf_request_new( dev->pg.ep_out, 512 ); if(!req) { _dbgmsg( "create request error\n" ); return -ENODEV; } req->complete = dtf_complete_out; dev->pg.mReq_out = req; _dbgmsg( "OUT\n" ); return 0; }
static int thor_func_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_gadget *gadget = c->cdev->gadget; struct f_thor *f_thor = func_to_thor(f); struct thor_dev *dev; struct usb_ep *ep; int status; thor_func = f_thor; dev = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*dev)); if (!dev) return -ENOMEM; memset(dev, 0, sizeof(*dev)); dev->gadget = gadget; f_thor->dev = dev; debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n", __func__, c, f); debug("f_thor: 0x%p thor: 0x%p\n", f_thor, dev); /* EP0 */ /* preallocate control response and buffer */ dev->req = usb_ep_alloc_request(gadget->ep0, 0); if (!dev->req) { status = -ENOMEM; goto fail; } dev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, THOR_PACKET_SIZE); if (!dev->req->buf) { status = -ENOMEM; goto fail; } dev->req->complete = thor_setup_complete; /* DYNAMIC interface numbers assignments */ status = usb_interface_id(c, f); if (status < 0) goto fail; thor_downloader_intf_int.bInterfaceNumber = status; thor_downloader_cdc_union.bMasterInterface0 = status; status = usb_interface_id(c, f); if (status < 0) goto fail; thor_downloader_intf_data.bInterfaceNumber = status; thor_downloader_cdc_union.bSlaveInterface0 = status; /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(gadget, &fs_in_desc); if (!ep) { status = -ENODEV; goto fail; } if (gadget_is_dualspeed(gadget)) { hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress; } dev->in_ep = ep; /* Store IN EP for enabling @ setup */ ep->driver_data = dev; ep = usb_ep_autoconfig(gadget, &fs_out_desc); if (!ep) { status = -ENODEV; goto fail; } if (gadget_is_dualspeed(gadget)) hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress; dev->out_ep = ep; /* Store OUT EP for enabling @ setup */ ep->driver_data = dev; ep = usb_ep_autoconfig(gadget, &fs_int_desc); if (!ep) { status = -ENODEV; goto fail; } dev->int_ep = ep; ep->driver_data = dev; if (gadget_is_dualspeed(gadget)) { hs_int_desc.bEndpointAddress = fs_int_desc.bEndpointAddress; f->hs_descriptors = (struct usb_descriptor_header **) &hs_thor_downloader_function; if (!f->hs_descriptors) goto fail; } debug("%s: out_ep:%p out_req:%p\n", __func__, dev->out_ep, dev->out_req); return 0; fail: free(dev); return status; }
static int fastboot_bind(struct usb_gadget *gadget) { struct fastboot_dev *dev = &l_fbdev; u8 cdc = 1, zlp = 1; struct usb_ep *in_ep, *out_ep; int gcnum; u8 tmp[7]; debug("%s controller :%s recognized\n", __func__, gadget->name); gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) device_desc.bcdDevice = cpu_to_le16(0x0300 + gcnum); else { /* * can't assume CDC works. don't want to default to * anything less functional on CDC-capable hardware, * so we fail in this case. */ error("controller '%s' not recognized", gadget->name); return -ENODEV; } if (bcdDevice) device_desc.bcdDevice = cpu_to_le16(bcdDevice); if (iManufacturer) strlcpy(manufacturer, iManufacturer, sizeof manufacturer); if (iProduct) strlcpy(product_desc, iProduct, sizeof product_desc); iSerialNumber = get_product_sn(); device_desc.iSerialNumber = STRING_SERIALNUMBER, strlcpy(serial_number, iSerialNumber, sizeof serial_number); /* all we really need is bulk IN/OUT */ usb_ep_autoconfig_reset(gadget); in_ep = usb_ep_autoconfig(gadget, &fs_source_desc); if (!in_ep) { autoconf_fail: error("can't autoconfigure on %s\n", gadget->name); return -ENODEV; } in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc); if (!out_ep) goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered(gadget); if (gadget_is_dualspeed(gadget)) { /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; /* and that all endpoints are dual-speed */ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; } dev->network_started = 0; dev->in_ep = in_ep; dev->out_ep = out_ep; /* preallocate control message data and buffer */ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!dev->req) goto fail; dev->req->buf = control_req; dev->req->complete = fastboot_setup_complete; /* ... and maybe likewise for status transfer */ /* finish hookup to lower layer ... */ dev->gadget = gadget; set_gadget_data(gadget, dev); gadget->ep0->driver_data = dev; debug("bind controller with the driver\n"); /* * two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" */ return 0; fail: error("%s failed", __func__); fastboot_unbind(gadget); return -ENOMEM; }
/* * The setup() callback implements all the ep0 functionality that's not * handled lower down. CDC has a number of less-common features: * * - two interfaces: control, and ethernet data * - Ethernet data interface has two altsettings: default, and active * - class-specific descriptors for the control interface * - class-specific control requests */ static int fastboot_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct fastboot_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); u16 wLength = le16_to_cpu(ctrl->wLength); /* * descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. */ debug("%s\n", __func__); req->complete = fastboot_setup_complete; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; switch (wValue >> 8) { case USB_DT_DEVICE: value = min(wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; case USB_DT_DEVICE_QUALIFIER: if (!gadget_is_dualspeed(gadget)) break; value = min(wLength, (u16) sizeof dev_qualifier); memcpy(req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ case USB_DT_CONFIG: value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, gadget_is_otg(gadget)); if (value >= 0) value = min(wLength, (u16) value); break; case USB_DT_STRING: value = usb_gadget_get_string(&stringtab, wValue & 0xff, req->buf); if (value >= 0) value = min(wLength, (u16) value); break; } break; case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) break; value = fastboot_set_config(dev, wValue, GFP_ATOMIC); l_fbdev.network_started = 1; break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *) req->buf = dev->config; value = min(wLength, (u16) 1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE || !dev->config || wIndex > 1) break; /* * FIXME this is wrong, as is the assumption that * all non-PXA hardware talks real CDC ... */ debug("set_interface ignored!\n"); done_set_intf: break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE) || !dev->config || wIndex > 1) break; /* for CDC, iff carrier is on, data interface is active. */ if (wIndex != 1) *(u8 *) req->buf = 0; else { /* *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; */ /* carrier always ok ... */ *(u8 *) req->buf = 1; } value = min(wLength, (u16) 1); break; default: debug("unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); } /* respond with data transfer before status phase? */ if (value >= 0) { debug("respond with data transfer before status phase\n"); req->length = value; req->zero = value < wLength && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { debug("ep_queue --> %d\n", value); req->status = 0; fastboot_setup_complete(gadget->ep0, req); } } /* host either stalls (value < 0) or reports success */ return value; }
/* maxpacket and other transfer characteristics vary by speed. */ static inline struct usb_endpoint_descriptor *ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, struct usb_endpoint_descriptor *fs) { if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return hs; return fs; }
static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_gser *gser = func_to_gser(f); int status; struct usb_ep *ep; #ifdef CONFIG_PANTECH_ANDROID_USB ushort vid; #endif /* allocate instance-specific interface IDs */ #ifdef CONFIG_PANTECH_ANDROID_USB vid = getVendorID(); if(vid == 0x05C6){ //printk("^^^^ It's Qualcomm gser\n"); status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; }else{ //printk("^^^^ It's SKY gser\n"); status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; //data_id : cdc interface number gser_acm_cdc_interface_desc.bInterfaceNumber = status; //acm interface status = usb_interface_id(c, f); if (status < 0) goto fail; gser_acm_data_interface_desc.bInterfaceNumber = status; } #else status = usb_interface_id(c, f); if (status < 0) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; #endif status = -ENODEV; /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc); if (!ep) goto fail; gser->port.in = ep; ep->driver_data = cdev; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); if (!ep) goto fail; gser->port.out = ep; ep->driver_data = cdev; /* claim */ #ifdef CONFIG_MODEM_SUPPORT ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); if (!ep) goto fail; gser->notify = ep; ep->driver_data = cdev; /* claim */ /* allocate notification */ gser->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, GFP_KERNEL); if (!gser->notify_req) goto fail; gser->notify_req->complete = gser_notify_complete; gser->notify_req->context = gser; #endif /* copy descriptors, and track endpoint copies */ #ifdef CONFIG_PANTECH_ANDROID_USB vid = getVendorID(); if( vid == 0x05C6){ f->descriptors = usb_copy_descriptors(gser_fs_function); }else{ f->descriptors = usb_copy_descriptors(pantech_gser_fs_function); } #else f->descriptors = usb_copy_descriptors(gser_fs_function); #endif if (!f->descriptors) goto fail; /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ if (gadget_is_dualspeed(c->cdev->gadget)) { gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; #ifdef CONFIG_MODEM_SUPPORT gser_hs_notify_desc.bEndpointAddress = gser_fs_notify_desc.bEndpointAddress; #endif /* copy descriptors, and track endpoint copies */ #ifdef CONFIG_PANTECH_ANDROID_USB if( vid == 0x05C6){ f->hs_descriptors = usb_copy_descriptors(gser_hs_function); }else{ f->hs_descriptors = usb_copy_descriptors(pantech_gser_hs_function); } #else f->hs_descriptors = usb_copy_descriptors(gser_hs_function); #endif if (!f->hs_descriptors) goto fail; } if (gadget_is_superspeed(c->cdev->gadget)) { gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; /* copy descriptors, and track endpoint copies */ f->ss_descriptors = usb_copy_descriptors(gser_ss_function); if (!f->ss_descriptors) goto fail; } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", gser->port_num, gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", gser->port.in->name, gser->port.out->name); return 0; fail: if (f->descriptors) usb_free_descriptors(f->descriptors); #ifdef CONFIG_MODEM_SUPPORT if (gser->notify_req) gs_free_req(gser->notify, gser->notify_req); /* we might as well release our claims on endpoints */ if (gser->notify) gser->notify->driver_data = NULL; #endif /* we might as well release our claims on endpoints */ if (gser->port.out) gser->port.out->driver_data = NULL; if (gser->port.in) gser->port.in->driver_data = NULL; ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; }
int __init uvc_bind_config(struct usb_configuration *c, const struct uvc_descriptor_header * const *control, const struct uvc_descriptor_header * const *fs_streaming, const struct uvc_descriptor_header * const *hs_streaming) { struct uvc_device *uvc; int ret = 0; /* TODO Check if the USB device controller supports the required * features. */ if (!gadget_is_dualspeed(c->cdev->gadget)) return -EINVAL; uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); if (uvc == NULL) return -ENOMEM; uvc->state = UVC_STATE_DISCONNECTED; /* Validate the descriptors. */ if (control == NULL || control[0] == NULL || control[0]->bDescriptorSubType != UVC_DT_HEADER) goto error; if (fs_streaming == NULL || fs_streaming[0] == NULL || fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER) goto error; if (hs_streaming == NULL || hs_streaming[0] == NULL || hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER) goto error; uvc->desc.control = control; uvc->desc.fs_streaming = fs_streaming; uvc->desc.hs_streaming = hs_streaming; /* Allocate string descriptor numbers. */ if ((ret = usb_string_id(c->cdev)) < 0) goto error; uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; uvc_iad.iFunction = ret; if ((ret = usb_string_id(c->cdev)) < 0) goto error; uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; uvc_control_intf.iInterface = ret; if ((ret = usb_string_id(c->cdev)) < 0) goto error; uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; uvc_streaming_intf_alt0.iInterface = ret; uvc_streaming_intf_alt1.iInterface = ret; /* Register the function. */ uvc->func.name = "uvc"; uvc->func.strings = uvc_function_strings; uvc->func.bind = uvc_function_bind; uvc->func.unbind = uvc_function_unbind; uvc->func.get_alt = uvc_function_get_alt; uvc->func.set_alt = uvc_function_set_alt; uvc->func.disable = uvc_function_disable; uvc->func.setup = uvc_function_setup; ret = usb_add_function(c, &uvc->func); if (ret) kfree(uvc); return 0; error: kfree(uvc); return ret; }