• source navigation • diff markup • identifier search • freetext search •
Version: 2.6.32 2.6.33 2.6.34 2.6.35 2.6.36 2.6.37 2.6.38 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9
Architecture: x86 arm avr32 blackfin m68k m68knommu microblaze mips powerpc sh
1 /* 2 * Copyright (C) 2003-2008 Takahiro Hirofuchi 3 * 4 * This is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 * USA. 18 */ 19 20 #include <linux/kthread.h> 21 #include <linux/net.h> 22 23 #include "usbip_common.h" 24 #include "vhci.h" 25 26 /* TODO: refine locking ?*/ 27 28 /* Sysfs entry to show port status */ 29 static ssize_t show_status(struct device *dev, struct device_attribute *attr, 30 char *out) 31 { 32 char *s = out; 33 int i = 0; 34 35 BUG_ON(!the_controller || !out); 36 37 spin_lock(&the_controller->lock); 38 39 /* 40 * output example: 41 * prt sta spd dev socket local_busid 42 * 000 004 000 000 c5a7bb80 1-2.3 43 * 001 004 000 000 d8cee980 2-3.4 44 * 45 * IP address can be retrieved from a socket pointer address by looking 46 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a 47 * port number and its peer IP address. 48 */ 49 out += sprintf(out, "prt sta spd bus dev socket " 50 "local_busid\n"); 51 52 for (i = 0; i < VHCI_NPORTS; i++) { 53 struct vhci_device *vdev = port_to_vdev(i); 54 55 spin_lock(&vdev->ud.lock); 56 out += sprintf(out, "%03u %03u ", i, vdev->ud.status); 57 58 if (vdev->ud.status == VDEV_ST_USED) { 59 out += sprintf(out, "%03u %08x ", 60 vdev->speed, vdev->devid); 61 out += sprintf(out, "%16p ", vdev->ud.tcp_socket); 62 out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); 63 64 } else { 65 out += sprintf(out, "000 000 000 0000000000000000 0-0"); 66 } 67 68 out += sprintf(out, "\n"); 69 spin_unlock(&vdev->ud.lock); 70 } 71 72 spin_unlock(&the_controller->lock); 73 74 return out - s; 75 } 76 static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); 77 78 /* Sysfs entry to shutdown a virtual connection */ 79 static int vhci_port_disconnect(__u32 rhport) 80 { 81 struct vhci_device *vdev; 82 83 usbip_dbg_vhci_sysfs("enter\n"); 84 85 /* lock */ 86 spin_lock(&the_controller->lock); 87 88 vdev = port_to_vdev(rhport); 89 90 spin_lock(&vdev->ud.lock); 91 if (vdev->ud.status == VDEV_ST_NULL) { 92 pr_err("not connected %d\n", vdev->ud.status); 93 94 /* unlock */ 95 spin_unlock(&vdev->ud.lock); 96 spin_unlock(&the_controller->lock); 97 98 return -EINVAL; 99 } 100 101 /* unlock */ 102 spin_unlock(&vdev->ud.lock); 103 spin_unlock(&the_controller->lock); 104 105 usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); 106 107 return 0; 108 } 109 110 static ssize_t store_detach(struct device *dev, struct device_attribute *attr, 111 const char *buf, size_t count) 112 { 113 int err; 114 __u32 rhport = 0; 115 116 sscanf(buf, "%u", &rhport); 117 118 /* check rhport */ 119 if (rhport >= VHCI_NPORTS) { 120 dev_err(dev, "invalid port %u\n", rhport); 121 return -EINVAL; 122 } 123 124 err = vhci_port_disconnect(rhport); 125 if (err < 0) 126 return -EINVAL; 127 128 usbip_dbg_vhci_sysfs("Leave\n"); 129 130 return count; 131 } 132 static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); 133 134 /* Sysfs entry to establish a virtual connection */ 135 static int valid_args(__u32 rhport, enum usb_device_speed speed) 136 { 137 /* check rhport */ 138 if (rhport >= VHCI_NPORTS) { 139 pr_err("port %u\n", rhport); 140 return -EINVAL; 141 } 142 143 /* check speed */ 144 switch (speed) { 145 case USB_SPEED_LOW: 146 case USB_SPEED_FULL: 147 case USB_SPEED_HIGH: 148 case USB_SPEED_WIRELESS: 149 break; 150 default: 151 pr_err("speed %d\n", speed); 152 return -EINVAL; 153 } 154 155 return 0; 156 } 157 158 /* 159 * To start a new USB/IP attachment, a userland program needs to setup a TCP 160 * connection and then write its socket descriptor with remote device 161 * information into this sysfs file. 162 * 163 * A remote device is virtually attached to the root-hub port of @rhport with 164 * @speed. @devid is embedded into a request to specify the remote device in a 165 * server host. 166 * 167 * write() returns 0 on success, else negative errno. 168 */ 169 static ssize_t store_attach(struct device *dev, struct device_attribute *attr, 170 const char *buf, size_t count) 171 { 172 struct vhci_device *vdev; 173 struct socket *socket; 174 int sockfd = 0; 175 __u32 rhport = 0, devid = 0, speed = 0; 176 177 /* 178 * @rhport: port number of vhci_hcd 179 * @sockfd: socket descriptor of an established TCP connection 180 * @devid: unique device identifier in a remote host 181 * @speed: usb device speed in a remote host 182 */ 183 sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed); 184 185 usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", 186 rhport, sockfd, devid, speed); 187 188 /* check received parameters */ 189 if (valid_args(rhport, speed) < 0) 190 return -EINVAL; 191 192 /* check sockfd */ 193 socket = sockfd_to_socket(sockfd); 194 if (!socket) 195 return -EINVAL; 196 197 /* now need lock until setting vdev status as used */ 198 199 /* begin a lock */ 200 spin_lock(&the_controller->lock); 201 vdev = port_to_vdev(rhport); 202 spin_lock(&vdev->ud.lock); 203 204 if (vdev->ud.status != VDEV_ST_NULL) { 205 /* end of the lock */ 206 spin_unlock(&vdev->ud.lock); 207 spin_unlock(&the_controller->lock); 208 209 dev_err(dev, "port %d already used\n", rhport); 210 return -EINVAL; 211 } 212 213 dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u)\n", 214 rhport, sockfd, devid, speed); 215 216 vdev->devid = devid; 217 vdev->speed = speed; 218 vdev->ud.tcp_socket = socket; 219 vdev->ud.status = VDEV_ST_NOTASSIGNED; 220 221 spin_unlock(&vdev->ud.lock); 222 spin_unlock(&the_controller->lock); 223 /* end the lock */ 224 225 vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); 226 vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); 227 228 rh_port_connect(rhport, speed); 229 230 return count; 231 } 232 static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach); 233 234 static struct attribute *dev_attrs[] = { 235 &dev_attr_status.attr, 236 &dev_attr_detach.attr, 237 &dev_attr_attach.attr, 238 &dev_attr_usbip_debug.attr, 239 NULL, 240 }; 241 242 const struct attribute_group dev_attr_group = { 243 .attrs = dev_attrs, 244 }; 245
This page was automatically generated by LXR 0.3.1 (source). • Linux is a registered trademark of Linus Torvalds