aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/usbip/vhci_sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/usbip/vhci_sysfs.c')
-rw-r--r--drivers/usb/usbip/vhci_sysfs.c138
1 files changed, 95 insertions, 43 deletions
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index b96e5b189269..5778b640ba9c 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -29,13 +29,51 @@
/* TODO: refine locking ?*/
+/*
+ * output example:
+ * hub port sta spd dev socket local_busid
+ * hs 0000 004 000 00000000 c5a7bb80 1-2.3
+ * ................................................
+ * ss 0008 004 000 00000000 d8cee980 2-3.4
+ * ................................................
+ *
+ * IP address can be retrieved from a socket pointer address by looking
+ * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
+ * port number and its peer IP address.
+ */
+static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev)
+{
+ if (hub == HUB_SPEED_HIGH)
+ *out += sprintf(*out, "hs %04u %03u ",
+ port, vdev->ud.status);
+ else /* hub == HUB_SPEED_SUPER */
+ *out += sprintf(*out, "ss %04u %03u ",
+ port, vdev->ud.status);
+
+ if (vdev->ud.status == VDEV_ST_USED) {
+ *out += sprintf(*out, "%03u %08x ",
+ vdev->speed, vdev->devid);
+ *out += sprintf(*out, "%16p %s",
+ vdev->ud.tcp_socket,
+ dev_name(&vdev->udev->dev));
+
+ } else {
+ *out += sprintf(*out, "000 00000000 ");
+ *out += sprintf(*out, "0000000000000000 0-0");
+ }
+
+ *out += sprintf(*out, "\n");
+}
+
/* Sysfs entry to show port status */
static ssize_t status_show_vhci(int pdev_nr, char *out)
{
- struct platform_device *pdev = *(vhci_pdevs + pdev_nr);
- struct vhci_hcd *vhci;
+ struct platform_device *pdev = vhcis[pdev_nr].pdev;
+ struct vhci *vhci;
+ struct usb_hcd *hcd;
+ struct vhci_hcd *vhci_hcd;
char *s = out;
- int i = 0;
+ int i;
unsigned long flags;
if (!pdev || !out) {
@@ -43,41 +81,27 @@ static ssize_t status_show_vhci(int pdev_nr, char *out)
return 0;
}
- vhci = hcd_to_vhci(platform_get_drvdata(pdev));
+ hcd = platform_get_drvdata(pdev);
+ vhci_hcd = hcd_to_vhci_hcd(hcd);
+ vhci = vhci_hcd->vhci;
spin_lock_irqsave(&vhci->lock, flags);
- /*
- * output example:
- * port sta spd dev socket local_busid
- * 0000 004 000 00000000 c5a7bb80 1-2.3
- * 0001 004 000 00000000 d8cee980 2-3.4
- *
- * IP address can be retrieved from a socket pointer address by looking
- * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
- * port number and its peer IP address.
- */
for (i = 0; i < VHCI_HC_PORTS; i++) {
- struct vhci_device *vdev = &vhci->vdev[i];
+ struct vhci_device *vdev = &vhci->vhci_hcd_hs->vdev[i];
spin_lock(&vdev->ud.lock);
- out += sprintf(out, "%04u %03u ",
- (pdev_nr * VHCI_HC_PORTS) + i,
- vdev->ud.status);
-
- if (vdev->ud.status == VDEV_ST_USED) {
- out += sprintf(out, "%03u %08x ",
- vdev->speed, vdev->devid);
- out += sprintf(out, "%16p %s",
- vdev->ud.tcp_socket,
- dev_name(&vdev->udev->dev));
-
- } else {
- out += sprintf(out, "000 00000000 ");
- out += sprintf(out, "0000000000000000 0-0");
- }
+ port_show_vhci(&out, HUB_SPEED_HIGH,
+ pdev_nr * VHCI_PORTS + i, vdev);
+ spin_unlock(&vdev->ud.lock);
+ }
- out += sprintf(out, "\n");
+ for (i = 0; i < VHCI_HC_PORTS; i++) {
+ struct vhci_device *vdev = &vhci->vhci_hcd_ss->vdev[i];
+
+ spin_lock(&vdev->ud.lock);
+ port_show_vhci(&out, HUB_SPEED_SUPER,
+ pdev_nr * VHCI_PORTS + VHCI_HC_PORTS + i, vdev);
spin_unlock(&vdev->ud.lock);
}
@@ -92,8 +116,16 @@ static ssize_t status_show_not_ready(int pdev_nr, char *out)
int i = 0;
for (i = 0; i < VHCI_HC_PORTS; i++) {
- out += sprintf(out, "%04u %03u ",
- (pdev_nr * VHCI_HC_PORTS) + i,
+ out += sprintf(out, "hs %04u %03u ",
+ (pdev_nr * VHCI_PORTS) + i,
+ VDEV_ST_NOTASSIGNED);
+ out += sprintf(out, "000 00000000 0000000000000000 0-0");
+ out += sprintf(out, "\n");
+ }
+
+ for (i = 0; i < VHCI_HC_PORTS; i++) {
+ out += sprintf(out, "ss %04u %03u ",
+ (pdev_nr * VHCI_PORTS) + VHCI_HC_PORTS + i,
VDEV_ST_NOTASSIGNED);
out += sprintf(out, "000 00000000 0000000000000000 0-0");
out += sprintf(out, "\n");
@@ -125,7 +157,7 @@ static ssize_t status_show(struct device *dev,
int pdev_nr;
out += sprintf(out,
- "port sta spd dev socket local_busid\n");
+ "hub port sta spd dev socket local_busid\n");
pdev_nr = status_name_to_id(attr->attr.name);
if (pdev_nr < 0)
@@ -141,15 +173,19 @@ static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
{
char *s = out;
- out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
+ /*
+ * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the * 2.
+ */
+ out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers);
return out - s;
}
static DEVICE_ATTR_RO(nports);
/* Sysfs entry to shutdown a virtual connection */
-static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport)
+static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
{
- struct vhci_device *vdev = &vhci->vdev[rhport];
+ struct vhci_device *vdev = &vhci_hcd->vdev[rhport];
+ struct vhci *vhci = vhci_hcd->vhci;
unsigned long flags;
usbip_dbg_vhci_sysfs("enter\n");
@@ -195,6 +231,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
{
__u32 port = 0, pdev_nr = 0, rhport = 0;
struct usb_hcd *hcd;
+ struct vhci_hcd *vhci_hcd;
int ret;
if (kstrtoint(buf, 10, &port) < 0)
@@ -206,13 +243,20 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
if (!valid_port(pdev_nr, rhport))
return -EINVAL;
- hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
+ hcd = platform_get_drvdata(vhcis[pdev_nr].pdev);
if (hcd == NULL) {
dev_err(dev, "port is not ready %u\n", port);
return -EAGAIN;
}
- ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport);
+ usbip_dbg_vhci_sysfs("rhport %d\n", rhport);
+
+ if ((port / VHCI_HC_PORTS) % 2)
+ vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_ss;
+ else
+ vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_hs;
+
+ ret = vhci_port_disconnect(vhci_hcd, rhport);
if (ret < 0)
return -EINVAL;
@@ -233,6 +277,7 @@ static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed)
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
case USB_SPEED_WIRELESS:
+ case USB_SPEED_SUPER:
break;
default:
pr_err("Failed attach request for unsupported USB speed: %s\n",
@@ -262,8 +307,9 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
int sockfd = 0;
__u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
struct usb_hcd *hcd;
- struct vhci_hcd *vhci;
+ struct vhci_hcd *vhci_hcd;
struct vhci_device *vdev;
+ struct vhci *vhci;
int err;
unsigned long flags;
@@ -287,13 +333,19 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
if (!valid_args(pdev_nr, rhport, speed))
return -EINVAL;
- hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
+ hcd = platform_get_drvdata(vhcis[pdev_nr].pdev);
if (hcd == NULL) {
dev_err(dev, "port %d is not ready\n", port);
return -EAGAIN;
}
- vhci = hcd_to_vhci(hcd);
- vdev = &vhci->vdev[rhport];
+
+ vhci_hcd = hcd_to_vhci_hcd(hcd);
+ vhci = vhci_hcd->vhci;
+
+ if (speed == USB_SPEED_SUPER)
+ vdev = &vhci->vhci_hcd_ss->vdev[rhport];
+ else
+ vdev = &vhci->vhci_hcd_hs->vdev[rhport];
/* Extract socket from fd. */
socket = sockfd_lookup(sockfd, &err);