[usb] Add generic USB network device framework
[ipxe.git] / src / drivers / usb / usbnet.c
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 }