/* Change the control interface altsetting and update the .driver_info * pointer if the matching entry after changing class codes points to * a different struct */ static int cdc_mbim_set_ctrlalt(struct usbnet *dev, struct usb_interface *intf, u8 alt) { struct usb_driver *driver = to_usb_driver(intf->dev.driver); const struct usb_device_id *id; struct driver_info *info; int ret; ret = usb_set_interface(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber, alt); if (ret) return ret; id = usb_match_id(intf, driver->id_table); if (!id) return -ENODEV; info = (struct driver_info *)id->driver_info; if (info != dev->driver_info) { dev_dbg(&intf->dev, "driver_info updated to '%s'\n", info->description); dev->driver_info = info; } return 0; }
static ssize_t supports_autosuspend_show(struct device *dev, struct device_attribute *attr, char *buf) { int s; device_lock(dev); /* Devices will be autosuspended even when an interface isn't claimed */ s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); device_unlock(dev); return sprintf(buf, "%u\n", s); }
static int usb_generic_resume(struct device *dev) { struct usb_interface *intf; struct usb_driver *driver; struct usb_device *udev; int status; if (dev->power.power_state.event == PM_EVENT_ON) return 0; /* mark things as "on" immediately, no matter what errors crop up */ dev->power.power_state.event = PM_EVENT_ON; /*唤醒usb设备*/ /* devices resume through their hubs */ if (dev->driver == &usb_generic_driver) { udev = to_usb_device(dev); if (udev->state == USB_STATE_NOTATTACHED) return 0; return usb_resume_device (to_usb_device(dev)); } if ((dev->driver == NULL) || (dev->driver_data == &usb_generic_driver_data)) { dev->power.power_state.event = PM_EVENT_FREEZE; return 0; } intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); udev = interface_to_usbdev(intf); if (udev->state == USB_STATE_NOTATTACHED) return 0; /* if driver was suspended, it has a resume method; * however, sysfs can wrongly mark things as suspended * (on the "no suspend method" FIXME path above) */ //唤醒usb设备接口的驱动 if (driver->resume) { status = driver->resume(intf); if (status) { dev_err(dev, "%s error %d\n", "resume", status); mark_quiesced(intf); } } else dev_warn(dev, "no resume for driver %s?\n", driver->name); return 0; }
static int usb_generic_suspend(struct device *dev, pm_message_t message) { struct usb_interface *intf; struct usb_driver *driver; int status; /* USB devices enter SUSPEND state through their hubs, but can be * marked for FREEZE as soon as their children are already idled. * But those semantics are useless, so we equate the two (sigh). */ /*挂起usb设备*/ if (dev->driver == &usb_generic_driver) { if (dev->power.power_state.event == message.event) return 0; /* we need to rule out bogus requests through sysfs */ status = device_for_each_child(dev, NULL, verify_suspended); if (status) return status; /*挂起设备的操作*/ return usb_suspend_device (to_usb_device(dev)); } if ((dev->driver == NULL) || (dev->driver_data == &usb_generic_driver_data)) return 0; intf = to_usb_interface(dev); driver = to_usb_driver(dev->driver); /* with no hardware, USB interfaces only use FREEZE and ON states */ if (!is_active(intf)) return 0; //挂起usb设备接口驱动 if (driver->suspend && driver->resume) { status = driver->suspend(intf, message); if (status) dev_err(dev, "%s error %d\n", "suspend", status); else mark_quiesced(intf); } else { // FIXME else if there's no suspend method, disconnect... dev_warn(dev, "no suspend for driver %s?\n", driver->name); mark_quiesced(intf); status = 0; } return status; }
static ssize_t show_supports_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_interface *intf; struct usb_device *udev; int ret; intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); usb_lock_device(udev); /* Devices will be autosuspended even when an interface isn't claimed */ if (!intf->dev.driver || to_usb_driver(intf->dev.driver)->supports_autosuspend) ret = sprintf(buf, "%u\n", 1); else ret = sprintf(buf, "%u\n", 0); usb_unlock_device(udev); return ret; }
int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) { struct usbnet *dev; struct net_device *net; struct usb_host_interface *interface; struct driver_info *info; struct usb_device *xdev; int status; const char *name; struct usb_driver *driver = to_usb_driver(udev->dev.driver); /* usbnet already took usb runtime pm, so have to enable the feature * for usb interface, otherwise usb_autopm_get_interface may return * failure if USB_SUSPEND(RUNTIME_PM) is enabled. */ if (!driver->supports_autosuspend) { driver->supports_autosuspend = 1; pm_runtime_enable(&udev->dev); } name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; if (!info) { dev_dbg (&udev->dev, "blacklisted by %s\n", name); return -ENODEV; } xdev = interface_to_usbdev (udev); interface = udev->cur_altsetting; usb_get_dev (xdev); status = -ENOMEM; // set up our own records net = alloc_etherdev(sizeof(*dev)); if (!net) { dbg ("can't kmalloc dev"); goto out; } /* netdev_printk() needs this so do it as early as possible */ SET_NETDEV_DEV(net, &udev->dev); dev = netdev_priv(net); dev->udev = xdev; dev->intf = udev; dev->driver_info = info; dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK); skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); skb_queue_head_init(&dev->rxq_pause); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; INIT_WORK (&dev->kevent, kevent); init_usb_anchor(&dev->deferred); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); mutex_init (&dev->phy_mutex); dev->net = net; strcpy (net->name, "usb%d"); memcpy (net->dev_addr, node_id, sizeof node_id); /* rx and tx sides can use different message sizes; * bind() should set rx_urb_size in that case. */ dev->hard_mtu = net->mtu + net->hard_header_len; #if 0 // dma_supported() is deeply broken on almost all architectures // possible with some EHCI controllers if (dma_supported (&udev->dev, DMA_BIT_MASK(64))) net->features |= NETIF_F_HIGHDMA; #endif net->netdev_ops = &usbnet_netdev_ops; net->watchdog_timeo = TX_TIMEOUT_JIFFIES; net->ethtool_ops = &usbnet_ethtool_ops; // allow device-specific bind/init procedures // NOTE net->name still not usable ... if (info->bind) { status = info->bind (dev, udev); if (status < 0) goto out1; // heuristic: "usb%d" for links we know are two-host, // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. if ((dev->driver_info->flags & FLAG_ETHER) != 0 && (net->dev_addr [0] & 0x02) == 0) strcpy (net->name, "eth%d"); /* WLAN devices should always be named "wlan%d" */ if ((dev->driver_info->flags & FLAG_WLAN) != 0) strcpy(net->name, "wlan%d"); /* WWAN devices should always be named "wwan%d" */ if ((dev->driver_info->flags & FLAG_WWAN) != 0) strcpy(net->name, "wwan%d"); /* maybe the remote can't receive an Ethernet MTU */ if (net->mtu > (dev->hard_mtu - net->hard_header_len)) net->mtu = dev->hard_mtu - net->hard_header_len; } else if (!info->in || !info->out) status = usbnet_get_endpoints (dev, udev); else { dev->in = usb_rcvbulkpipe (xdev, info->in); dev->out = usb_sndbulkpipe (xdev, info->out); if (!(info->flags & FLAG_NO_SETINT)) status = usb_set_interface (xdev, interface->desc.bInterfaceNumber, interface->desc.bAlternateSetting); else status = 0; } if (status >= 0 && dev->status) status = init_status (dev, udev); if (status < 0) goto out3; if (!dev->rx_urb_size) dev->rx_urb_size = dev->hard_mtu; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); if ((dev->driver_info->flags & FLAG_WLAN) != 0) SET_NETDEV_DEVTYPE(net, &wlan_type); if ((dev->driver_info->flags & FLAG_WWAN) != 0) SET_NETDEV_DEVTYPE(net, &wwan_type); status = register_netdev (net); if (status) goto out3; netif_info(dev, probe, dev->net, "register '%s' at usb-%s-%s, %s, %pM\n", udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, net->dev_addr); // ok, it's ready to go. usb_set_intfdata (udev, dev); netif_device_attach (net); if (dev->driver_info->flags & FLAG_LINK_INTR) netif_carrier_off(net); return 0; out3: if (info->unbind) info->unbind (dev, udev); out1: free_netdev(net); out: usb_put_dev(xdev); return status; }
static inline struct usb_driver *get_usb_driver(struct usb_interface *intf) { return to_usb_driver(intf->dev.driver); }
/* * udev, which is used for the firmware downloading, requires we cannot * block during module_init(). module_init() calls USB probe() which * is this routine. Due to that we delay actual operation using workqueue * and return always success here. */ static void dvb_usbv2_init_work(struct work_struct *work) { int ret; struct dvb_usb_device *d = container_of(work, struct dvb_usb_device, probe_work); d->work_pid = current->pid; dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid); if (d->props->size_of_priv) { d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); if (!d->priv) { dev_err(&d->udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; goto err_usb_driver_release_interface; } } if (d->props->identify_state) { const char *name = NULL; ret = d->props->identify_state(d, &name); if (ret == 0) { ; } else if (ret == COLD) { dev_info(&d->udev->dev, "%s: found a '%s' in cold state\n", KBUILD_MODNAME, d->name); if (!name) name = d->props->firmware; ret = dvb_usbv2_download_firmware(d, name); if (ret == 0) { /* device is warm, continue initialization */ ; } else if (ret == RECONNECTS_USB) { /* * USB core will call disconnect() and then * probe() as device reconnects itself from the * USB bus. disconnect() will release all driver * resources and probe() is called for 'new' * device. As 'new' device is warm we should * never go here again. */ return; } else { /* * Unexpected error. We must unregister driver * manually from the device, because device is * already register by returning from probe() * with success. usb_driver_release_interface() * finally calls disconnect() in order to free * resources. */ goto err_usb_driver_release_interface; } } else { goto err_usb_driver_release_interface; } } dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name); ret = dvb_usbv2_init(d); if (ret < 0) goto err_usb_driver_release_interface; dev_info(&d->udev->dev, "%s: '%s' successfully initialized and connected\n", KBUILD_MODNAME, d->name); return; err_usb_driver_release_interface: dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, d->name, ret); usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), d->intf); dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return; }
int cdc_ncm_bind(struct if_usb_devdata *pipe_data, struct usb_interface *intf, struct usb_link_device *usb_ld) { struct cdc_ncm_ctx *ctx; struct usb_driver *usbdrv = to_usb_driver(intf->dev.driver); struct usb_device *usbdev = interface_to_usbdev(intf); unsigned char *buf = intf->cur_altsetting->extra; int buflen = intf->cur_altsetting->extralen; const struct usb_cdc_union_desc *union_desc; int temp; u8 iface_no; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) return -ENODEV; hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; ctx->bh.data = (unsigned long)pipe_data; ctx->bh.func = cdc_ncm_txpath_bh; atomic_set(&ctx->stop, 0); spin_lock_init(&ctx->mtx); /* store ctx pointer in device data field */ pipe_data->sedata = (void *)ctx; ctx->intf = intf; /* parse through descriptors associated with control interface */ while ((buflen > 0) && (buf[0] > 2) && (buf[0] <= buflen)) { if (buf[1] == USB_DT_CS_INTERFACE) { switch (buf[2]) { case USB_CDC_UNION_TYPE: if (buf[0] < sizeof(*union_desc)) break; union_desc = (const struct usb_cdc_union_desc *)buf; ctx->control = usb_ifnum_to_if(usbdev, union_desc->bMasterInterface0); ctx->data = usb_ifnum_to_if(usbdev, union_desc->bSlaveInterface0); break; case USB_CDC_ETHERNET_TYPE: if (buf[0] < sizeof(*(ctx->ether_desc))) break; ctx->ether_desc = (const struct usb_cdc_ether_desc *)buf; break; case USB_CDC_NCM_TYPE: if (buf[0] < sizeof(*(ctx->func_desc))) break; ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf; break; default: break; } } temp = buf[0]; buf += temp; buflen -= temp; } /* check if we got everything */ if ((ctx->control == NULL) || (ctx->data == NULL) || (ctx->ether_desc == NULL) || (ctx->control != intf)) goto error; pipe_data->usbdev = usb_get_dev(usbdev); pipe_data->usb_ld = usb_ld; pipe_data->disconnected = 0; pipe_data->state = STATE_RESUMED; /* claim interfaces, if any */ temp = usb_driver_claim_interface(usbdrv, ctx->data, pipe_data); if (temp) goto error; iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; /* reset data interface */ temp = usb_set_interface(usbdev, iface_no, 0); if (temp) goto error2; /* initialize data interface */ if (cdc_ncm_setup(pipe_data)) goto error2; /* configure data interface */ temp = usb_set_interface(usbdev, iface_no, 1); if (temp) goto error2; cdc_ncm_find_endpoints(ctx, ctx->data); cdc_ncm_find_endpoints(ctx, ctx->control); if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) || (ctx->status_ep == NULL)) goto error2; usb_set_intfdata(ctx->data, pipe_data); usb_set_intfdata(ctx->control, pipe_data); usb_set_intfdata(ctx->intf, pipe_data); pipe_data->rx_pipe = usb_rcvbulkpipe(usbdev, ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); pipe_data->tx_pipe = usb_sndbulkpipe(usbdev, ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); pipe_data->status = ctx->status_ep; pipe_data->rx_buf_size = ctx->rx_max; mif_debug("EP status: %x, tx:%x, rx:%x\n", ctx->status_ep->desc.bEndpointAddress, ctx->in_ep->desc.bEndpointAddress, ctx->out_ep->desc.bEndpointAddress); temp = cdc_ncm_setup_ethernet_address(pipe_data); if (temp) goto error2; /* * We should get an event when network connection is "connected" or * "disconnected". Set network connection in "disconnected" state * (carrier is OFF) during attach, so the IP network stack does not * start IPv6 negotiation and more. */ netif_carrier_off(pipe_data->iod->ndev); ctx->tx_speed = ctx->rx_speed = 0; if (pipe_data->iod->ndev->mtu != (ctx->max_datagram_size - ETH_HLEN)) pipe_data->iod->ndev->mtu = ctx->max_datagram_size - ETH_HLEN; return 0; error2: usb_set_intfdata(ctx->control, NULL); usb_set_intfdata(ctx->data, NULL); usb_driver_release_interface(usbdrv, ctx->data); error: cdc_ncm_free((struct cdc_ncm_ctx *)pipe_data->sedata); pipe_data->sedata = NULL; mif_err("bind() failure\n"); return -ENODEV; }