Release 4.11 drivers/usb/usbip/vhci_sysfs.c
/*
* Copyright (C) 2003-2008 Takahiro Hirofuchi
* Copyright (C) 2015-2016 Nobuo Iwata
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <linux/kthread.h>
#include <linux/file.h>
#include <linux/net.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "usbip_common.h"
#include "vhci.h"
/* TODO: refine locking ?*/
/* 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;
char *s = out;
int i = 0;
unsigned long flags;
if (!pdev || !out) {
usbip_dbg_vhci_sysfs("show status error\n");
return 0;
}
vhci = hcd_to_vhci(platform_get_drvdata(pdev));
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];
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");
}
out += sprintf(out, "\n");
spin_unlock(&vdev->ud.lock);
}
spin_unlock_irqrestore(&vhci->lock, flags);
return out - s;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Takahiro Hirofuchi | 167 | 65.75% | 1 | 16.67% |
Nobuo Iwata | 70 | 27.56% | 1 | 16.67% |
Andrew Goodbody | 10 | 3.94% | 1 | 16.67% |
Kay Sievers | 4 | 1.57% | 1 | 16.67% |
Matt Mooney | 2 | 0.79% | 1 | 16.67% |
Stoyan Gaydarov | 1 | 0.39% | 1 | 16.67% |
Total | 254 | 100.00% | 6 | 100.00% |
static ssize_t status_show_not_ready(int pdev_nr, char *out)
{
char *s = out;
int i = 0;
for (i = 0; i < VHCI_HC_PORTS; i++) {
out += sprintf(out, "%04u %03u ",
(pdev_nr * VHCI_HC_PORTS) + i,
VDEV_ST_NOTASSIGNED);
out += sprintf(out, "000 00000000 0000000000000000 0-0");
out += sprintf(out, "\n");
}
return out - s;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 56 | 69.14% | 1 | 33.33% |
Takahiro Hirofuchi | 22 | 27.16% | 1 | 33.33% |
Andrew Goodbody | 3 | 3.70% | 1 | 33.33% |
Total | 81 | 100.00% | 3 | 100.00% |
static int status_name_to_id(const char *name)
{
char *c;
long val;
int ret;
c = strchr(name, '.');
if (c == NULL)
return 0;
ret = kstrtol(c+1, 10, &val);
if (ret < 0)
return ret;
return val;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 57 | 87.69% | 1 | 50.00% |
Takahiro Hirofuchi | 8 | 12.31% | 1 | 50.00% |
Total | 65 | 100.00% | 2 | 100.00% |
static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *out)
{
char *s = out;
int pdev_nr;
out += sprintf(out,
"port sta spd dev socket local_busid\n");
pdev_nr = status_name_to_id(attr->attr.name);
if (pdev_nr < 0)
out += status_show_not_ready(pdev_nr, out);
else
out += status_show_vhci(pdev_nr, out);
return out - s;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 79 | 100.00% | 1 | 100.00% |
Total | 79 | 100.00% | 1 | 100.00% |
static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
char *out)
{
char *s = out;
out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
return out - s;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 44 | 100.00% | 1 | 100.00% |
Total | 44 | 100.00% | 1 | 100.00% |
static DEVICE_ATTR_RO(nports);
/* Sysfs entry to shutdown a virtual connection */
static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport)
{
struct vhci_device *vdev = &vhci->vdev[rhport];
unsigned long flags;
usbip_dbg_vhci_sysfs("enter\n");
/* lock */
spin_lock_irqsave(&vhci->lock, flags);
spin_lock(&vdev->ud.lock);
if (vdev->ud.status == VDEV_ST_NULL) {
pr_err("not connected %d\n", vdev->ud.status);
/* unlock */
spin_unlock(&vdev->ud.lock);
spin_unlock_irqrestore(&vhci->lock, flags);
return -EINVAL;
}
/* unlock */
spin_unlock(&vdev->ud.lock);
spin_unlock_irqrestore(&vhci->lock, flags);
usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 139 | 100.00% | 1 | 100.00% |
Total | 139 | 100.00% | 1 | 100.00% |
static int valid_port(__u32 pdev_nr, __u32 rhport)
{
if (pdev_nr >= vhci_num_controllers) {
pr_err("pdev %u\n", pdev_nr);
return 0;
}
if (rhport >= VHCI_HC_PORTS) {
pr_err("rhport %u\n", rhport);
return 0;
}
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 51 | 100.00% | 1 | 100.00% |
Total | 51 | 100.00% | 1 | 100.00% |
static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
__u32 port = 0, pdev_nr = 0, rhport = 0;
struct usb_hcd *hcd;
int ret;
if (kstrtoint(buf, 10, &port) < 0)
return -EINVAL;
pdev_nr = port_to_pdev_nr(port);
rhport = port_to_rhport(port);
if (!valid_port(pdev_nr, rhport))
return -EINVAL;
hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
if (hcd == NULL) {
dev_err(dev, "port is not ready %u\n", port);
return -EAGAIN;
}
ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport);
if (ret < 0)
return -EINVAL;
usbip_dbg_vhci_sysfs("Leave\n");
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 96 | 62.34% | 1 | 20.00% |
Takahiro Hirofuchi | 47 | 30.52% | 1 | 20.00% |
John de la Garza | 7 | 4.55% | 1 | 20.00% |
Matt Mooney | 3 | 1.95% | 1 | 20.00% |
Brian G. Merrell | 1 | 0.65% | 1 | 20.00% |
Total | 154 | 100.00% | 5 | 100.00% |
static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed)
{
if (!valid_port(pdev_nr, rhport)) {
return 0;
}
switch (speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
case USB_SPEED_WIRELESS:
break;
default:
pr_err("Failed attach request for unsupported USB speed: %s\n",
usb_speed_string(speed));
return 0;
}
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Takahiro Hirofuchi | 50 | 74.63% | 1 | 20.00% |
Nobuo Iwata | 11 | 16.42% | 1 | 20.00% |
Shuah Khan | 4 | 5.97% | 1 | 20.00% |
Matt Mooney | 1 | 1.49% | 1 | 20.00% |
Greg Kroah-Hartman | 1 | 1.49% | 1 | 20.00% |
Total | 67 | 100.00% | 5 | 100.00% |
/* Sysfs entry to establish a virtual connection */
/*
* To start a new USB/IP attachment, a userland program needs to setup a TCP
* connection and then write its socket descriptor with remote device
* information into this sysfs file.
*
* A remote device is virtually attached to the root-hub port of @rhport with
* @speed. @devid is embedded into a request to specify the remote device in a
* server host.
*
* write() returns 0 on success, else negative errno.
*/
static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct socket *socket;
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_device *vdev;
int err;
unsigned long flags;
/*
* @rhport: port number of vhci_hcd
* @sockfd: socket descriptor of an established TCP connection
* @devid: unique device identifier in a remote host
* @speed: usb device speed in a remote host
*/
if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4)
return -EINVAL;
pdev_nr = port_to_pdev_nr(port);
rhport = port_to_rhport(port);
usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n",
port, pdev_nr, rhport);
usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n",
sockfd, devid, speed);
/* check received parameters */
if (!valid_args(pdev_nr, rhport, speed))
return -EINVAL;
hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
if (hcd == NULL) {
dev_err(dev, "port %d is not ready\n", port);
return -EAGAIN;
}
vhci = hcd_to_vhci(hcd);
vdev = &vhci->vdev[rhport];
/* Extract socket from fd. */
socket = sockfd_lookup(sockfd, &err);
if (!socket)
return -EINVAL;
/* now need lock until setting vdev status as used */
/* begin a lock */
spin_lock_irqsave(&vhci->lock, flags);
spin_lock(&vdev->ud.lock);
if (vdev->ud.status != VDEV_ST_NULL) {
/* end of the lock */
spin_unlock(&vdev->ud.lock);
spin_unlock_irqrestore(&vhci->lock, flags);
sockfd_put(socket);
dev_err(dev, "port %d already used\n", rhport);
return -EINVAL;
}
dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n",
pdev_nr, rhport, sockfd);
dev_info(dev, "devid(%u) speed(%u) speed_str(%s)\n",
devid, speed, usb_speed_string(speed));
vdev->devid = devid;
vdev->speed = speed;
vdev->ud.tcp_socket = socket;
vdev->ud.status = VDEV_ST_NOTASSIGNED;
spin_unlock(&vdev->ud.lock);
spin_unlock_irqrestore(&vhci->lock, flags);
/* end the lock */
vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
rh_port_connect(vdev, speed);
return count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Takahiro Hirofuchi | 225 | 52.94% | 1 | 7.69% |
Nobuo Iwata | 115 | 27.06% | 1 | 7.69% |
Max Vozeler | 27 | 6.35% | 1 | 7.69% |
Andrew Goodbody | 13 | 3.06% | 1 | 7.69% |
Arnd Bergmann | 9 | 2.12% | 1 | 7.69% |
John de la Garza | 8 | 1.88% | 1 | 7.69% |
Al Viro | 8 | 1.88% | 1 | 7.69% |
Shuah Khan | 6 | 1.41% | 2 | 15.38% |
Matt Mooney | 6 | 1.41% | 1 | 7.69% |
Bernard Blackham | 5 | 1.18% | 1 | 7.69% |
Oleg Nesterov | 2 | 0.47% | 1 | 7.69% |
Brian G. Merrell | 1 | 0.24% | 1 | 7.69% |
Total | 425 | 100.00% | 13 | 100.00% |
static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
#define MAX_STATUS_NAME 16
struct status_attr {
struct device_attribute attr;
char name[MAX_STATUS_NAME+1];
};
static struct status_attr *status_attrs;
static void set_status_attr(int id)
{
struct status_attr *status;
status = status_attrs + id;
if (id == 0)
strcpy(status->name, "status");
else
snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id);
status->attr.attr.name = status->name;
status->attr.attr.mode = S_IRUGO;
status->attr.show = status_show;
sysfs_attr_init(&status->attr.attr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 72 | 79.12% | 1 | 33.33% |
Shuah Khan | 10 | 10.99% | 1 | 33.33% |
Takahiro Hirofuchi | 9 | 9.89% | 1 | 33.33% |
Total | 91 | 100.00% | 3 | 100.00% |
static int init_status_attrs(void)
{
int id;
status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr),
GFP_KERNEL);
if (status_attrs == NULL)
return -ENOMEM;
for (id = 0; id < vhci_num_controllers; id++)
set_status_attr(id);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 56 | 98.25% | 1 | 50.00% |
Takahiro Hirofuchi | 1 | 1.75% | 1 | 50.00% |
Total | 57 | 100.00% | 2 | 100.00% |
static void finish_status_attrs(void)
{
kfree(status_attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 13 | 100.00% | 1 | 100.00% |
Total | 13 | 100.00% | 1 | 100.00% |
struct attribute_group vhci_attr_group = {
.attrs = NULL,
};
int vhci_init_attr_group(void)
{
struct attribute **attrs;
int ret, i;
attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *),
GFP_KERNEL);
if (attrs == NULL)
return -ENOMEM;
ret = init_status_attrs();
if (ret) {
kfree(attrs);
return ret;
}
*attrs = &dev_attr_nports.attr;
*(attrs + 1) = &dev_attr_detach.attr;
*(attrs + 2) = &dev_attr_attach.attr;
*(attrs + 3) = &dev_attr_usbip_debug.attr;
for (i = 0; i < vhci_num_controllers; i++)
*(attrs + i + 4) = &((status_attrs + i)->attr.attr);
vhci_attr_group.attrs = attrs;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 155 | 100.00% | 1 | 100.00% |
Total | 155 | 100.00% | 1 | 100.00% |
void vhci_finish_attr_group(void)
{
finish_status_attrs();
kfree(vhci_attr_group.attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nobuo Iwata | 1072 | 59.99% | 1 | 5.00% |
Takahiro Hirofuchi | 574 | 32.12% | 1 | 5.00% |
Max Vozeler | 29 | 1.62% | 1 | 5.00% |
Andrew Goodbody | 26 | 1.45% | 1 | 5.00% |
Shuah Khan | 20 | 1.12% | 4 | 20.00% |
Matt Mooney | 16 | 0.90% | 3 | 15.00% |
John de la Garza | 15 | 0.84% | 1 | 5.00% |
Arnd Bergmann | 9 | 0.50% | 1 | 5.00% |
Al Viro | 8 | 0.45% | 1 | 5.00% |
Bernard Blackham | 8 | 0.45% | 1 | 5.00% |
Kay Sievers | 4 | 0.22% | 1 | 5.00% |
Oleg Nesterov | 2 | 0.11% | 1 | 5.00% |
Brian G. Merrell | 2 | 0.11% | 1 | 5.00% |
Greg Kroah-Hartman | 1 | 0.06% | 1 | 5.00% |
Stoyan Gaydarov | 1 | 0.06% | 1 | 5.00% |
Total | 1787 | 100.00% | 20 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.