Browse Source

[usb] Add generic USB network device framework

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
a92fb8d9a5
3 changed files with 343 additions and 0 deletions
  1. 280
    0
      src/drivers/usb/usbnet.c
  2. 1
    0
      src/include/ipxe/errfile.h
  3. 62
    0
      src/include/ipxe/usbnet.h

+ 280
- 0
src/drivers/usb/usbnet.c View File

@@ -0,0 +1,280 @@
1
+/*
2
+ * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <string.h>
23
+#include <errno.h>
24
+#include <ipxe/usb.h>
25
+#include <ipxe/usbnet.h>
26
+
27
+/** @file
28
+ *
29
+ * USB network devices
30
+ *
31
+ * USB network devices use a variety of packet formats and interface
32
+ * descriptors, but tend to have several features in common:
33
+ *
34
+ *  - a single interrupt endpoint using the generic refill mechanism
35
+ *
36
+ *  - a single bulk IN endpoint using the generic refill mechanism
37
+ *
38
+ *  - a single bulk OUT endpoint
39
+ *
40
+ *  - optional use of an alternate setting to enable the data interface
41
+ *
42
+ */
43
+
44
+/**
45
+ * Open USB network device
46
+ *
47
+ * @v usbnet		USB network device
48
+ * @ret rc		Return status code
49
+ */
50
+int usbnet_open ( struct usbnet_device *usbnet ) {
51
+	struct usb_device *usb = usbnet->func->usb;
52
+	int rc;
53
+
54
+	/* Open interrupt endpoint */
55
+	if ( ( rc = usb_endpoint_open ( &usbnet->intr ) ) != 0 ) {
56
+		DBGC ( usbnet, "USBNET %s could not open interrupt: %s\n",
57
+		       usbnet->func->name, strerror ( rc ) );
58
+		goto err_open_intr;
59
+	}
60
+
61
+	/* Refill interrupt endpoint */
62
+	if ( ( rc = usb_refill ( &usbnet->intr ) ) != 0 ) {
63
+		DBGC ( usbnet, "USBNET %s could not refill interrupt: %s\n",
64
+		       usbnet->func->name, strerror ( rc ) );
65
+		goto err_refill_intr;
66
+	}
67
+
68
+	/* Select alternate setting for data interface, if applicable */
69
+	if ( usbnet->alternate &&
70
+	     ( ( rc = usb_set_interface ( usb, usbnet->data,
71
+					  usbnet->alternate ) ) != 0 ) ) {
72
+		DBGC ( usbnet, "USBNET %s could not set alternate interface "
73
+		       "%d: %s\n", usbnet->func->name, usbnet->alternate,
74
+		       strerror ( rc ) );
75
+		goto err_set_interface;
76
+	}
77
+
78
+	/* Open bulk IN endpoint */
79
+	if ( ( rc = usb_endpoint_open ( &usbnet->in ) ) != 0 ) {
80
+		DBGC ( usbnet, "USBNET %s could not open bulk IN: %s\n",
81
+		       usbnet->func->name, strerror ( rc ) );
82
+		goto err_open_in;
83
+	}
84
+
85
+	/* Open bulk OUT endpoint */
86
+	if ( ( rc = usb_endpoint_open ( &usbnet->out ) ) != 0 ) {
87
+		DBGC ( usbnet, "USBNET %s could not open bulk OUT: %s\n",
88
+		       usbnet->func->name, strerror ( rc ) );
89
+		goto err_open_out;
90
+	}
91
+
92
+	/* Refill bulk IN endpoint */
93
+	if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 ) {
94
+		DBGC ( usbnet, "USBNET %s could not refill bulk IN: %s\n",
95
+		       usbnet->func->name, strerror ( rc ) );
96
+		goto err_refill_in;
97
+	}
98
+
99
+	return 0;
100
+
101
+ err_refill_in:
102
+	usb_endpoint_close ( &usbnet->out );
103
+ err_open_out:
104
+	usb_endpoint_close ( &usbnet->in );
105
+ err_open_in:
106
+	if ( usbnet->alternate )
107
+		usb_set_interface ( usb, usbnet->data, 0 );
108
+ err_set_interface:
109
+ err_refill_intr:
110
+	usb_endpoint_close ( &usbnet->intr );
111
+ err_open_intr:
112
+	return rc;
113
+}
114
+
115
+/**
116
+ * Close USB network device
117
+ *
118
+ * @v usbnet		USB network device
119
+ */
120
+void usbnet_close ( struct usbnet_device *usbnet ) {
121
+	struct usb_device *usb = usbnet->func->usb;
122
+
123
+	/* Close bulk OUT endpoint */
124
+	usb_endpoint_close ( &usbnet->out );
125
+
126
+	/* Close bulk IN endpoint */
127
+	usb_endpoint_close ( &usbnet->in );
128
+
129
+	/* Reset alternate setting for data interface, if applicable */
130
+	if ( usbnet->alternate )
131
+		usb_set_interface ( usb, usbnet->data, 0 );
132
+
133
+	/* Close interrupt endpoint */
134
+	usb_endpoint_close ( &usbnet->intr );
135
+}
136
+
137
+/**
138
+ * Refill USB network device bulk IN and interrupt endpoints
139
+ *
140
+ * @v usbnet		USB network device
141
+ * @ret rc		Return status code
142
+ */
143
+int usbnet_refill ( struct usbnet_device *usbnet ) {
144
+	int rc;
145
+
146
+	/* Refill bulk IN endpoint */
147
+	if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 )
148
+		return rc;
149
+
150
+	/* Refill interrupt endpoint */
151
+	if ( ( rc = usb_refill ( &usbnet->intr ) ) != 0 )
152
+		return rc;
153
+
154
+	return 0;
155
+}
156
+
157
+/**
158
+ * Describe communications interface and interrupt endpoint
159
+ *
160
+ * @v usbnet		USB network device
161
+ * @v config		Configuration descriptor
162
+ * @ret rc		Return status code
163
+ */
164
+static int usbnet_comms_describe ( struct usbnet_device *usbnet,
165
+				   struct usb_configuration_descriptor *config){
166
+	struct usb_interface_descriptor *desc;
167
+	unsigned int comms;
168
+	unsigned int i;
169
+	int rc;
170
+
171
+	/* Iterate over all available interfaces */
172
+	for ( i = 0 ; i < usbnet->func->count ; i++ ) {
173
+
174
+		/* Get interface number */
175
+		comms = usbnet->func->interface[i];
176
+
177
+		/* Locate interface descriptor */
178
+		desc = usb_interface_descriptor ( config, comms, 0 );
179
+		if ( ! desc )
180
+			continue;
181
+
182
+		/* Describe interrupt endpoint */
183
+		if ( ( rc = usb_endpoint_described ( &usbnet->intr, config,
184
+						     desc, USB_INTERRUPT,
185
+						     0 ) ) != 0 )
186
+			continue;
187
+
188
+		/* Record communications interface */
189
+		usbnet->comms = comms;
190
+		DBGC ( usbnet, "USBNET %s found communications interface %d\n",
191
+		       usbnet->func->name, comms );
192
+		return 0;
193
+	}
194
+
195
+	DBGC ( usbnet, "USBNET %s found no communications interface\n",
196
+	       usbnet->func->name );
197
+	return -ENOENT;
198
+}
199
+
200
+/**
201
+ * Describe data interface and bulk endpoints
202
+ *
203
+ * @v usbnet		USB network device
204
+ * @v config		Configuration descriptor
205
+ * @ret rc		Return status code
206
+ */
207
+static int usbnet_data_describe ( struct usbnet_device *usbnet,
208
+				  struct usb_configuration_descriptor *config ){
209
+	struct usb_interface_descriptor *desc;
210
+	unsigned int data;
211
+	unsigned int alt;
212
+	unsigned int i;
213
+	int rc;
214
+
215
+	/* Iterate over all available interfaces */
216
+	for ( i = 0 ; i < usbnet->func->count ; i++ ) {
217
+
218
+		/* Get interface number */
219
+		data = usbnet->func->interface[i];
220
+
221
+		/* Iterate over all existent alternate settings */
222
+		for ( alt = 0 ; ; alt++ ) {
223
+
224
+			/* Locate interface descriptor */
225
+			desc = usb_interface_descriptor ( config, data, alt );
226
+			if ( ! desc )
227
+				break;
228
+
229
+			/* Describe bulk IN endpoint */
230
+			if ( ( rc = usb_endpoint_described ( &usbnet->in,
231
+							     config, desc,
232
+							     USB_BULK_IN,
233
+							     0 ) ) != 0 )
234
+				continue;
235
+
236
+			/* Describe bulk OUT endpoint */
237
+			if ( ( rc = usb_endpoint_described ( &usbnet->out,
238
+							     config, desc,
239
+							     USB_BULK_OUT,
240
+							     0 ) ) != 0 )
241
+				continue;
242
+
243
+			/* Record data interface and alternate setting */
244
+			usbnet->data = data;
245
+			usbnet->alternate = alt;
246
+			DBGC ( usbnet, "USBNET %s found data interface %d",
247
+			       usbnet->func->name, data );
248
+			if ( alt )
249
+				DBGC ( usbnet, " using alternate %d", alt );
250
+			DBGC ( usbnet, "\n" );
251
+			return 0;
252
+		}
253
+	}
254
+
255
+	DBGC ( usbnet, "USBNET %s found no data interface\n",
256
+	       usbnet->func->name );
257
+	return -ENOENT;
258
+}
259
+
260
+/**
261
+ * Describe USB network device interfaces
262
+ *
263
+ * @v usbnet		USB network device
264
+ * @v config		Configuration descriptor
265
+ * @ret rc		Return status code
266
+ */
267
+int usbnet_describe ( struct usbnet_device *usbnet,
268
+		      struct usb_configuration_descriptor *config ) {
269
+	int rc;
270
+
271
+	/* Describe communications interface */
272
+	if ( ( rc = usbnet_comms_describe ( usbnet, config ) ) != 0 )
273
+		return rc;
274
+
275
+	/* Describe data interface */
276
+	if ( ( rc = usbnet_data_describe ( usbnet, config ) ) != 0 )
277
+		return rc;
278
+
279
+	return 0;
280
+}

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -163,6 +163,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
163 163
 #define ERRFILE_netvsc		     ( ERRFILE_DRIVER | 0x006b0000 )
164 164
 #define ERRFILE_ecm		     ( ERRFILE_DRIVER | 0x006c0000 )
165 165
 #define ERRFILE_ncm		     ( ERRFILE_DRIVER | 0x006d0000 )
166
+#define ERRFILE_usbnet		     ( ERRFILE_DRIVER | 0x006e0000 )
166 167
 
167 168
 #define ERRFILE_scsi		     ( ERRFILE_DRIVER | 0x00700000 )
168 169
 #define ERRFILE_arbel		     ( ERRFILE_DRIVER | 0x00710000 )

+ 62
- 0
src/include/ipxe/usbnet.h View File

@@ -0,0 +1,62 @@
1
+#ifndef _IPXE_USBNET_H
2
+#define _IPXE_USBNET_H
3
+
4
+/** @file
5
+ *
6
+ * USB network devices
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <ipxe/usb.h>
13
+
14
+/** A USB network device */
15
+struct usbnet_device {
16
+	/** USB function */
17
+	struct usb_function *func;
18
+
19
+	/** Communications interface */
20
+	unsigned int comms;
21
+	/** Data interface */
22
+	unsigned int data;
23
+	/** Alternate setting for data interface */
24
+	unsigned int alternate;
25
+
26
+	/** Interrupt endpoint */
27
+	struct usb_endpoint intr;
28
+	/** Bulk IN endpoint */
29
+	struct usb_endpoint in;
30
+	/** Bulk OUT endpoint */
31
+	struct usb_endpoint out;
32
+};
33
+
34
+/**
35
+ * Initialise USB network device
36
+ *
37
+ * @v usbnet		USB network device
38
+ * @v func		USB function
39
+ * @v intr		Interrupt endpoint operations
40
+ * @v in		Bulk IN endpoint operations
41
+ * @v out		Bulk OUT endpoint operations
42
+ */
43
+static inline __attribute__ (( always_inline )) void
44
+usbnet_init ( struct usbnet_device *usbnet, struct usb_function *func,
45
+	      struct usb_endpoint_driver_operations *intr,
46
+	      struct usb_endpoint_driver_operations *in,
47
+	      struct usb_endpoint_driver_operations *out ) {
48
+	struct usb_device *usb = func->usb;
49
+
50
+	usbnet->func = func;
51
+	usb_endpoint_init ( &usbnet->intr, usb, intr );
52
+	usb_endpoint_init ( &usbnet->in, usb, in );
53
+	usb_endpoint_init ( &usbnet->out, usb, out );
54
+}
55
+
56
+extern int usbnet_open ( struct usbnet_device *usbnet );
57
+extern void usbnet_close ( struct usbnet_device *usbnet );
58
+extern int usbnet_refill ( struct usbnet_device *usbnet );
59
+extern int usbnet_describe ( struct usbnet_device *usbnet,
60
+			     struct usb_configuration_descriptor *config );
61
+
62
+#endif /* _IPXE_USBNET_H */

Loading…
Cancel
Save