Blame view

drivers/usb/usbip/vhci_sysfs.c 6.18 KB
04679b348   Takahiro Hirofuchi   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   matt mooney   staging: usbip: f...
19
  #include <linux/kthread.h>
3d0a2a22c   Bernard Blackham   staging: usbip: D...
20
  #include <linux/file.h>
7aaacb43e   matt mooney   staging: usbip: f...
21
  #include <linux/net.h>
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
22
23
  #include "usbip_common.h"
  #include "vhci.h"
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
24
25
26
  /* TODO: refine locking ?*/
  
  /* Sysfs entry to show port status */
b1f56acac   Greg Kroah-Hartman   staging: usbip: u...
27
  static ssize_t status_show(struct device *dev, struct device_attribute *attr,
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
28
29
30
31
  			   char *out)
  {
  	char *s = out;
  	int i = 0;
2961f24f7   Stoyan Gaydarov   Staging: BUG to B...
32
  	BUG_ON(!the_controller || !out);
04679b348   Takahiro Hirofuchi   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   Cédric Cabessa   staging: usbip: f...
46
47
48
  	out += sprintf(out,
  		       "prt sta spd bus dev socket           local_busid
  ");
04679b348   Takahiro Hirofuchi   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   Takahiro Hirofuchi   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   matt mooney   staging: usbip: v...
58
  				       vdev->speed, vdev->devid);
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
59
  			out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
e91339720   Kay Sievers   staging: struct d...
60
  			out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
61

bd608f6ce   matt mooney   staging: usbip: v...
62
  		} else {
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
63
  			out += sprintf(out, "000 000 000 0000000000000000 0-0");
bd608f6ce   matt mooney   staging: usbip: v...
64
  		}
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
65
66
67
  
  		out += sprintf(out, "
  ");
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
68
69
70
71
72
73
74
  		spin_unlock(&vdev->ud.lock);
  	}
  
  	spin_unlock(&the_controller->lock);
  
  	return out - s;
  }
b1f56acac   Greg Kroah-Hartman   staging: usbip: u...
75
  static DEVICE_ATTR_RO(status);
04679b348   Takahiro Hirofuchi   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   Brian G. Merrell   Staging: USB-IP c...
81
82
  	usbip_dbg_vhci_sysfs("enter
  ");
04679b348   Takahiro Hirofuchi   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   matt mooney   staging: usbip: r...
91
92
  		pr_err("not connected %d
  ", vdev->ud.status);
04679b348   Takahiro Hirofuchi   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   John de la Garza   staging: usbip: v...
115
116
  	if (sscanf(buf, "%u", &rhport) != 1)
  		return -EINVAL;
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
117
118
119
  
  	/* check rhport */
  	if (rhport >= VHCI_NPORTS) {
1a4b6f662   matt mooney   staging: usbip: r...
120
121
  		dev_err(dev, "invalid port %u
  ", rhport);
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
122
123
124
125
126
127
  		return -EINVAL;
  	}
  
  	err = vhci_port_disconnect(rhport);
  	if (err < 0)
  		return -EINVAL;
b8868e45c   Brian G. Merrell   Staging: USB-IP c...
128
129
  	usbip_dbg_vhci_sysfs("Leave
  ");
bd608f6ce   matt mooney   staging: usbip: v...
130

04679b348   Takahiro Hirofuchi   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   Márton Németh   usbip: remove che...
139
  	if (rhport >= VHCI_NPORTS) {
1a4b6f662   matt mooney   staging: usbip: r...
140
141
  		pr_err("port %u
  ", rhport);
04679b348   Takahiro Hirofuchi   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   Greg Kroah-Hartman   USB: rename USB_S...
150
  	case USB_SPEED_WIRELESS:
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
151
152
  		break;
  	default:
8360fb0d9   Shuah Khan   staging/usbip: Fi...
153
154
155
  		pr_err("Failed attach request for unsupported USB speed: %s
  ",
  			usb_speed_string(speed));
04679b348   Takahiro Hirofuchi   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   Al Viro   usbip: don't open...
180
  	int err;
04679b348   Takahiro Hirofuchi   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   Shuah Khan   staging/usbip: fi...
188
  	if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4)
88fa1ebfa   John de la Garza   staging: usbip: v...
189
  		return -EINVAL;
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
190

b8868e45c   Brian G. Merrell   Staging: USB-IP c...
191
192
  	usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)
  ",
bd608f6ce   matt mooney   staging: usbip: v...
193
  			     rhport, sockfd, devid, speed);
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
194
195
196
197
  
  	/* check received parameters */
  	if (valid_args(rhport, speed) < 0)
  		return -EINVAL;
3d0a2a22c   Bernard Blackham   staging: usbip: D...
198
  	/* Extract socket from fd. */
964ea96eb   Al Viro   usbip: don't open...
199
  	socket = sockfd_lookup(sockfd, &err);
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
200
  	if (!socket)
a6d81814a   Márton Németh   usbip: remove ext...
201
  		return -EINVAL;
04679b348   Takahiro Hirofuchi   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   Takahiro Hirofuchi   Staging: USB/IP: ...
207
  	vdev = port_to_vdev(rhport);
04679b348   Takahiro Hirofuchi   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   Al Viro   usbip: don't open...
214
  		sockfd_put(socket);
3d0a2a22c   Bernard Blackham   staging: usbip: D...
215

1a4b6f662   matt mooney   staging: usbip: r...
216
217
  		dev_err(dev, "port %d already used
  ", rhport);
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
218
219
  		return -EINVAL;
  	}
a6646ea68   Shuah Khan   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   Takahiro Hirofuchi   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   Oleg Nesterov   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   Max Vozeler   staging: usbip: v...
235

04679b348   Takahiro Hirofuchi   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   Márton Németh   usbip: change dev...
249
  const struct attribute_group dev_attr_group = {
04679b348   Takahiro Hirofuchi   Staging: USB/IP: ...
250
251
  	.attrs = dev_attrs,
  };