/* * usbip_status shows the status of usbip-host as long as this driver is bound * to the target device.
*/ static ssize_t usbip_status_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct stub_device *sdev = dev_get_drvdata(dev); int status;
if (!sdev) {
dev_err(dev, "sdev is null\n"); return -ENODEV;
}
spin_lock_irq(&sdev->ud.lock);
status = sdev->ud.status;
spin_unlock_irq(&sdev->ud.lock);
/* * usbip_sockfd gets a socket descriptor of an established TCP connection that * is used to transfer usbip requests by kernel threads. -1 is a magic number * by which usbip connection is finished.
*/ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct stub_device *sdev = dev_get_drvdata(dev); int sockfd = 0; struct socket *socket; int rv; struct task_struct *tcp_rx = NULL; struct task_struct *tcp_tx = NULL;
if (!sdev) {
dev_err(dev, "sdev is null\n"); return -ENODEV;
}
/* * When removing an exported device, kernel panic sometimes occurred * and then EIP was sk_wait_data of stub_rx thread. Is this because * sk_wait_data returned though stub_rx thread was already finished by * step 1?
*/ if (ud->tcp_socket) {
dev_dbg(&sdev->udev->dev, "shutdown sockfd %d\n", ud->sockfd);
kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
}
/* * 2. close the socket * * tcp_socket is freed after threads are killed so that usbip_xmit does * not touch NULL socket.
*/ if (ud->tcp_socket) {
sockfd_put(ud->tcp_socket);
ud->tcp_socket = NULL;
ud->sockfd = -1;
}
/* 3. free used data */
stub_device_cleanup_urbs(sdev);
/** * stub_device_alloc - allocate a new stub_device struct * @udev: usb_device of a new device * * Allocates and initializes a new stub_device struct.
*/ staticstruct stub_device *stub_device_alloc(struct usb_device *udev)
{ struct stub_device *sdev; int busnum = udev->bus->busnum; int devnum = udev->devnum;
dev_dbg(&udev->dev, "allocating stub device");
/* yes, it's a new device */
sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL); if (!sdev) return NULL;
sdev->udev = usb_get_dev(udev);
/* * devid is defined with devnum when this driver is first allocated. * devnum may change later if a device is reset. However, devid never * changes during a usbip connection.
*/
sdev->devid = (busnum << 16) | devnum;
sdev->ud.side = USBIP_STUB;
sdev->ud.status = SDEV_ST_AVAILABLE;
spin_lock_init(&sdev->ud.lock);
mutex_init(&sdev->ud.sysfs_lock);
sdev->ud.tcp_socket = NULL;
sdev->ud.sockfd = -1;
/* Not sure if this is our device. Allocate here to avoid * calling alloc while holding busid_table lock.
*/
sdev = stub_device_alloc(udev); if (!sdev) return -ENOMEM;
/* check we should claim or not by busid_table */
busid_priv = get_busid_priv(udev_busid); if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
(busid_priv->status == STUB_BUSID_OTHER)) {
dev_info(&udev->dev, "%s is not in match_busid table... skip!\n",
udev_busid);
/* * Return value should be ENODEV or ENOXIO to continue trying * other matched drivers by the driver core. * See driver_probe_device() in driver/base/dd.c
*/
rc = -ENODEV; if (!busid_priv) goto sdev_free;
goto call_put_busid_priv;
}
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n",
udev_busid);
rc = -ENODEV; goto call_put_busid_priv;
}
if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
dev_dbg(&udev->dev, "%s is attached on vhci_hcd... skip!\n",
udev_busid);
rc = -ENODEV; goto call_put_busid_priv;
}
dev_info(&udev->dev, "usbip-host: register new device (bus %u dev %u)\n",
udev->bus->busnum, udev->devnum);
busid_priv->shutdown_busid = 0;
/* set private data to usb_device */
dev_set_drvdata(&udev->dev, sdev);
/* release the busid_lock */
put_busid_priv(busid_priv);
/* * Claim this hub port. * It doesn't matter what value we pass as owner * (struct dev_state) as long as it is unique.
*/
rc = usb_hub_claim_port(udev->parent, udev->portnum,
(struct usb_dev_state *) udev); if (rc) {
dev_dbg(&udev->dev, "unable to claim port\n"); goto err_port;
}
return 0;
err_port:
dev_set_drvdata(&udev->dev, NULL);
/* we already have busid_priv, just lock busid_lock */
spin_lock(&busid_priv->busid_lock);
busid_priv->sdev = NULL;
busid_priv->status = save_status;
spin_unlock(&busid_priv->busid_lock); /* lock is released - go to free */ goto sdev_free;
call_put_busid_priv: /* release the busid_lock */
put_busid_priv(busid_priv);
/* wait for the stop of the event handler */
usbip_stop_eh(&busid_priv->sdev->ud);
}
/* * called in usb_disconnect() or usb_deregister() * but only if actconfig(active configuration) exists
*/ staticvoid stub_disconnect(struct usb_device *udev)
{ struct stub_device *sdev; constchar *udev_busid = dev_name(&udev->dev); struct bus_id_priv *busid_priv; int rc;
dev_dbg(&udev->dev, "Enter disconnect\n");
busid_priv = get_busid_priv(udev_busid); if (!busid_priv) {
BUG(); return;
}
sdev = dev_get_drvdata(&udev->dev);
/* get stub_device */ if (!sdev) {
dev_err(&udev->dev, "could not get device"); /* release busid_lock */
put_busid_priv(busid_priv); return;
}
dev_set_drvdata(&udev->dev, NULL);
/* release busid_lock before call to remove device files */
put_busid_priv(busid_priv);
/* * NOTE: rx/tx threads are invoked for each usb_device.
*/
/* release port */
rc = usb_hub_release_port(udev->parent, udev->portnum,
(struct usb_dev_state *) udev); /* * NOTE: If a HUB disconnect triggered disconnect of the down stream * device usb_hub_release_port will return -ENODEV so we can safely ignore * that error here.
*/ if (rc && (rc != -ENODEV)) {
dev_dbg(&udev->dev, "unable to release port (%i)\n", rc); return;
}
/* If usb reset is called from event handler */ if (usbip_in_eh(current)) return;
/* we already have busid_priv, just lock busid_lock */
spin_lock(&busid_priv->busid_lock); if (!busid_priv->shutdown_busid)
busid_priv->shutdown_busid = 1; /* release busid_lock */
spin_unlock(&busid_priv->busid_lock);
/* shutdown the current connection */
shutdown_busid(busid_priv);
usb_put_dev(sdev->udev);
/* we already have busid_priv, just lock busid_lock */
spin_lock(&busid_priv->busid_lock); /* free sdev */
busid_priv->sdev = NULL;
stub_device_free(sdev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.