Blame view
drivers/usb/usbip/vhci_sysfs.c
6.18 KB
04679b348 Staging: USB/IP: ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* * Copyright (C) 2003-2008 Takahiro Hirofuchi * * 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. */ |
7aaacb43e staging: usbip: f... |
19 |
#include <linux/kthread.h> |
3d0a2a22c staging: usbip: D... |
20 |
#include <linux/file.h> |
7aaacb43e staging: usbip: f... |
21 |
#include <linux/net.h> |
04679b348 Staging: USB/IP: ... |
22 23 |
#include "usbip_common.h" #include "vhci.h" |
04679b348 Staging: USB/IP: ... |
24 25 26 |
/* TODO: refine locking ?*/ /* Sysfs entry to show port status */ |
b1f56acac staging: usbip: u... |
27 |
static ssize_t status_show(struct device *dev, struct device_attribute *attr, |
04679b348 Staging: USB/IP: ... |
28 29 30 31 |
char *out) { char *s = out; int i = 0; |
2961f24f7 Staging: BUG to B... |
32 |
BUG_ON(!the_controller || !out); |
04679b348 Staging: USB/IP: ... |
33 34 35 36 37 38 39 40 41 42 43 44 45 |
spin_lock(&the_controller->lock); /* * output example: * prt sta spd dev socket local_busid * 000 004 000 000 c5a7bb80 1-2.3 * 001 004 000 000 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. */ |
6bb3ee695 staging: usbip: f... |
46 47 48 |
out += sprintf(out, "prt sta spd bus dev socket local_busid "); |
04679b348 Staging: USB/IP: ... |
49 50 51 52 53 |
for (i = 0; i < VHCI_NPORTS; i++) { struct vhci_device *vdev = port_to_vdev(i); spin_lock(&vdev->ud.lock); |
04679b348 Staging: USB/IP: ... |
54 55 56 57 |
out += sprintf(out, "%03u %03u ", i, vdev->ud.status); if (vdev->ud.status == VDEV_ST_USED) { out += sprintf(out, "%03u %08x ", |
bd608f6ce staging: usbip: v... |
58 |
vdev->speed, vdev->devid); |
04679b348 Staging: USB/IP: ... |
59 |
out += sprintf(out, "%16p ", vdev->ud.tcp_socket); |
e91339720 staging: struct d... |
60 |
out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); |
04679b348 Staging: USB/IP: ... |
61 |
|
bd608f6ce staging: usbip: v... |
62 |
} else { |
04679b348 Staging: USB/IP: ... |
63 |
out += sprintf(out, "000 000 000 0000000000000000 0-0"); |
bd608f6ce staging: usbip: v... |
64 |
} |
04679b348 Staging: USB/IP: ... |
65 66 67 |
out += sprintf(out, " "); |
04679b348 Staging: USB/IP: ... |
68 69 70 71 72 73 74 |
spin_unlock(&vdev->ud.lock); } spin_unlock(&the_controller->lock); return out - s; } |
b1f56acac staging: usbip: u... |
75 |
static DEVICE_ATTR_RO(status); |
04679b348 Staging: USB/IP: ... |
76 77 78 79 80 |
/* Sysfs entry to shutdown a virtual connection */ static int vhci_port_disconnect(__u32 rhport) { struct vhci_device *vdev; |
b8868e45c Staging: USB-IP c... |
81 82 |
usbip_dbg_vhci_sysfs("enter "); |
04679b348 Staging: USB/IP: ... |
83 84 85 86 87 88 89 90 |
/* lock */ spin_lock(&the_controller->lock); vdev = port_to_vdev(rhport); spin_lock(&vdev->ud.lock); if (vdev->ud.status == VDEV_ST_NULL) { |
1a4b6f662 staging: usbip: r... |
91 92 |
pr_err("not connected %d ", vdev->ud.status); |
04679b348 Staging: USB/IP: ... |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
/* unlock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); return -EINVAL; } /* unlock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); return 0; } static ssize_t store_detach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int err; __u32 rhport = 0; |
88fa1ebfa staging: usbip: v... |
115 116 |
if (sscanf(buf, "%u", &rhport) != 1) return -EINVAL; |
04679b348 Staging: USB/IP: ... |
117 118 119 |
/* check rhport */ if (rhport >= VHCI_NPORTS) { |
1a4b6f662 staging: usbip: r... |
120 121 |
dev_err(dev, "invalid port %u ", rhport); |
04679b348 Staging: USB/IP: ... |
122 123 124 125 126 127 |
return -EINVAL; } err = vhci_port_disconnect(rhport); if (err < 0) return -EINVAL; |
b8868e45c Staging: USB-IP c... |
128 129 |
usbip_dbg_vhci_sysfs("Leave "); |
bd608f6ce staging: usbip: v... |
130 |
|
04679b348 Staging: USB/IP: ... |
131 132 133 134 135 136 137 138 |
return count; } static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); /* Sysfs entry to establish a virtual connection */ static int valid_args(__u32 rhport, enum usb_device_speed speed) { /* check rhport */ |
988e75208 usbip: remove che... |
139 |
if (rhport >= VHCI_NPORTS) { |
1a4b6f662 staging: usbip: r... |
140 141 |
pr_err("port %u ", rhport); |
04679b348 Staging: USB/IP: ... |
142 143 144 145 146 147 148 149 |
return -EINVAL; } /* check speed */ switch (speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: |
551cdbbeb USB: rename USB_S... |
150 |
case USB_SPEED_WIRELESS: |
04679b348 Staging: USB/IP: ... |
151 152 |
break; default: |
8360fb0d9 staging/usbip: Fi... |
153 154 155 |
pr_err("Failed attach request for unsupported USB speed: %s ", usb_speed_string(speed)); |
04679b348 Staging: USB/IP: ... |
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
return -EINVAL; } return 0; } /* * 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 vhci_device *vdev; struct socket *socket; int sockfd = 0; __u32 rhport = 0, devid = 0, speed = 0; |
964ea96eb usbip: don't open... |
180 |
int err; |
04679b348 Staging: USB/IP: ... |
181 182 183 184 185 186 187 |
/* * @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 */ |
de4734bc6 staging/usbip: fi... |
188 |
if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) |
88fa1ebfa staging: usbip: v... |
189 |
return -EINVAL; |
04679b348 Staging: USB/IP: ... |
190 |
|
b8868e45c Staging: USB-IP c... |
191 192 |
usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u) ", |
bd608f6ce staging: usbip: v... |
193 |
rhport, sockfd, devid, speed); |
04679b348 Staging: USB/IP: ... |
194 195 196 197 |
/* check received parameters */ if (valid_args(rhport, speed) < 0) return -EINVAL; |
3d0a2a22c staging: usbip: D... |
198 |
/* Extract socket from fd. */ |
964ea96eb usbip: don't open... |
199 |
socket = sockfd_lookup(sockfd, &err); |
04679b348 Staging: USB/IP: ... |
200 |
if (!socket) |
a6d81814a usbip: remove ext... |
201 |
return -EINVAL; |
04679b348 Staging: USB/IP: ... |
202 203 204 205 206 |
/* now need lock until setting vdev status as used */ /* begin a lock */ spin_lock(&the_controller->lock); |
04679b348 Staging: USB/IP: ... |
207 |
vdev = port_to_vdev(rhport); |
04679b348 Staging: USB/IP: ... |
208 209 210 211 212 213 |
spin_lock(&vdev->ud.lock); if (vdev->ud.status != VDEV_ST_NULL) { /* end of the lock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); |
964ea96eb usbip: don't open... |
214 |
sockfd_put(socket); |
3d0a2a22c staging: usbip: D... |
215 |
|
1a4b6f662 staging: usbip: r... |
216 217 |
dev_err(dev, "port %d already used ", rhport); |
04679b348 Staging: USB/IP: ... |
218 219 |
return -EINVAL; } |
a6646ea68 staging/usbip: Ch... |
220 221 222 223 |
dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s) ", rhport, sockfd, devid, speed, usb_speed_string(speed)); |
04679b348 Staging: USB/IP: ... |
224 225 226 227 228 229 230 231 232 |
vdev->devid = devid; vdev->speed = speed; vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); /* end the lock */ |
ba46ce30f staging: usbip: f... |
233 234 |
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"); |
d1b2e95ab staging: usbip: v... |
235 |
|
04679b348 Staging: USB/IP: ... |
236 237 238 239 240 241 242 243 244 245 246 247 248 |
rh_port_connect(rhport, speed); return count; } static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach); static struct attribute *dev_attrs[] = { &dev_attr_status.attr, &dev_attr_detach.attr, &dev_attr_attach.attr, &dev_attr_usbip_debug.attr, NULL, }; |
cf77acfca usbip: change dev... |
249 |
const struct attribute_group dev_attr_group = { |
04679b348 Staging: USB/IP: ... |
250 251 |
.attrs = dev_attrs, }; |