[pci] Add support for PCI MSI-X interrupts
[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 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <string.h>
27 #include <errno.h>
28 #include <ipxe/usb.h>
29 #include <ipxe/usbnet.h>
30
31 /** @file
32 *
33 * USB network devices
34 *
35 * USB network devices use a variety of packet formats and interface
36 * descriptors, but tend to have several features in common:
37 *
38 * - a single bulk OUT endpoint
39 *
40 * - a single bulk IN endpoint using the generic refill mechanism
41 *
42 * - an optional interrupt endpoint using the generic refill mechanism
43 *
44 * - optional use of an alternate setting to enable the data interface
45 *
46 */
47
48 /**
49 * Open USB network device
50 *
51 * @v usbnet USB network device
52 * @ret rc Return status code
53 */
54 int usbnet_open ( struct usbnet_device *usbnet ) {
55 struct usb_device *usb = usbnet->func->usb;
56 int rc;
57
58 /* Open interrupt endpoint, if applicable */
59 if ( usbnet_has_intr ( usbnet ) &&
60 ( rc = usb_endpoint_open ( &usbnet->intr ) ) != 0 ) {
61 DBGC ( usbnet, "USBNET %s could not open interrupt: %s\n",
62 usbnet->func->name, strerror ( rc ) );
63 goto err_open_intr;
64 }
65
66 /* Refill interrupt endpoint, if applicable */
67 if ( usbnet_has_intr ( usbnet ) &&
68 ( rc = usb_refill ( &usbnet->intr ) ) != 0 ) {
69 DBGC ( usbnet, "USBNET %s could not refill interrupt: %s\n",
70 usbnet->func->name, strerror ( rc ) );
71 goto err_refill_intr;
72 }
73
74 /* Select alternate setting for data interface, if applicable */
75 if ( usbnet->alternate &&
76 ( ( rc = usb_set_interface ( usb, usbnet->data,
77 usbnet->alternate ) ) != 0 ) ) {
78 DBGC ( usbnet, "USBNET %s could not set alternate interface "
79 "%d: %s\n", usbnet->func->name, usbnet->alternate,
80 strerror ( rc ) );
81 goto err_set_interface;
82 }
83
84 /* Open bulk IN endpoint */
85 if ( ( rc = usb_endpoint_open ( &usbnet->in ) ) != 0 ) {
86 DBGC ( usbnet, "USBNET %s could not open bulk IN: %s\n",
87 usbnet->func->name, strerror ( rc ) );
88 goto err_open_in;
89 }
90
91 /* Open bulk OUT endpoint */
92 if ( ( rc = usb_endpoint_open ( &usbnet->out ) ) != 0 ) {
93 DBGC ( usbnet, "USBNET %s could not open bulk OUT: %s\n",
94 usbnet->func->name, strerror ( rc ) );
95 goto err_open_out;
96 }
97
98 /* Refill bulk IN endpoint */
99 if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 ) {
100 DBGC ( usbnet, "USBNET %s could not refill bulk IN: %s\n",
101 usbnet->func->name, strerror ( rc ) );
102 goto err_refill_in;
103 }
104
105 return 0;
106
107 err_refill_in:
108 usb_endpoint_close ( &usbnet->out );
109 err_open_out:
110 usb_endpoint_close ( &usbnet->in );
111 err_open_in:
112 if ( usbnet->alternate )
113 usb_set_interface ( usb, usbnet->data, 0 );
114 err_set_interface:
115 err_refill_intr:
116 if ( usbnet_has_intr ( usbnet ) )
117 usb_endpoint_close ( &usbnet->intr );
118 err_open_intr:
119 return rc;
120 }
121
122 /**
123 * Close USB network device
124 *
125 * @v usbnet USB network device
126 */
127 void usbnet_close ( struct usbnet_device *usbnet ) {
128 struct usb_device *usb = usbnet->func->usb;
129
130 /* Close bulk OUT endpoint */
131 usb_endpoint_close ( &usbnet->out );
132
133 /* Close bulk IN endpoint */
134 usb_endpoint_close ( &usbnet->in );
135
136 /* Reset alternate setting for data interface, if applicable */
137 if ( usbnet->alternate )
138 usb_set_interface ( usb, usbnet->data, 0 );
139
140 /* Close interrupt endpoint, if applicable */
141 if ( usbnet_has_intr ( usbnet ) )
142 usb_endpoint_close ( &usbnet->intr );
143 }
144
145 /**
146 * Refill USB network device bulk IN and interrupt endpoints
147 *
148 * @v usbnet USB network device
149 * @ret rc Return status code
150 */
151 int usbnet_refill ( struct usbnet_device *usbnet ) {
152 int rc;
153
154 /* Refill bulk IN endpoint */
155 if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 )
156 return rc;
157
158 /* Refill interrupt endpoint, if applicable */
159 if ( usbnet_has_intr ( usbnet ) &&
160 ( rc = usb_refill ( &usbnet->intr ) ) != 0 ) {
161 return rc;
162 }
163
164 return 0;
165 }
166
167 /**
168 * Describe communications interface and interrupt endpoint
169 *
170 * @v usbnet USB network device
171 * @v config Configuration descriptor
172 * @ret rc Return status code
173 */
174 static int usbnet_comms_describe ( struct usbnet_device *usbnet,
175 struct usb_configuration_descriptor *config){
176 struct usb_interface_descriptor *desc;
177 unsigned int comms;
178 unsigned int i;
179 int rc;
180
181 /* Iterate over all available interfaces */
182 for ( i = 0 ; i < usbnet->func->desc.count ; i++ ) {
183
184 /* Get interface number */
185 comms = usbnet->func->interface[i];
186
187 /* Locate interface descriptor */
188 desc = usb_interface_descriptor ( config, comms, 0 );
189 if ( ! desc )
190 continue;
191
192 /* Describe interrupt endpoint */
193 if ( ( rc = usb_endpoint_described ( &usbnet->intr, config,
194 desc, USB_INTERRUPT_IN,
195 0 ) ) != 0 )
196 continue;
197
198 /* Record communications interface */
199 usbnet->comms = comms;
200 DBGC ( usbnet, "USBNET %s found communications interface %d\n",
201 usbnet->func->name, comms );
202 return 0;
203 }
204
205 DBGC ( usbnet, "USBNET %s found no communications interface\n",
206 usbnet->func->name );
207 return -ENOENT;
208 }
209
210 /**
211 * Describe data interface and bulk endpoints
212 *
213 * @v usbnet USB network device
214 * @v config Configuration descriptor
215 * @ret rc Return status code
216 */
217 static int usbnet_data_describe ( struct usbnet_device *usbnet,
218 struct usb_configuration_descriptor *config ){
219 struct usb_interface_descriptor *desc;
220 unsigned int data;
221 unsigned int alt;
222 unsigned int i;
223 int rc;
224
225 /* Iterate over all available interfaces */
226 for ( i = 0 ; i < usbnet->func->desc.count ; i++ ) {
227
228 /* Get interface number */
229 data = usbnet->func->interface[i];
230
231 /* Iterate over all existent alternate settings */
232 for ( alt = 0 ; ; alt++ ) {
233
234 /* Locate interface descriptor */
235 desc = usb_interface_descriptor ( config, data, alt );
236 if ( ! desc )
237 break;
238
239 /* Describe bulk IN endpoint */
240 if ( ( rc = usb_endpoint_described ( &usbnet->in,
241 config, desc,
242 USB_BULK_IN,
243 0 ) ) != 0 )
244 continue;
245
246 /* Describe bulk OUT endpoint */
247 if ( ( rc = usb_endpoint_described ( &usbnet->out,
248 config, desc,
249 USB_BULK_OUT,
250 0 ) ) != 0 )
251 continue;
252
253 /* Record data interface and alternate setting */
254 usbnet->data = data;
255 usbnet->alternate = alt;
256 DBGC ( usbnet, "USBNET %s found data interface %d",
257 usbnet->func->name, data );
258 if ( alt )
259 DBGC ( usbnet, " using alternate %d", alt );
260 DBGC ( usbnet, "\n" );
261 return 0;
262 }
263 }
264
265 DBGC ( usbnet, "USBNET %s found no data interface\n",
266 usbnet->func->name );
267 return -ENOENT;
268 }
269
270 /**
271 * Describe USB network device interfaces
272 *
273 * @v usbnet USB network device
274 * @v config Configuration descriptor
275 * @ret rc Return status code
276 */
277 int usbnet_describe ( struct usbnet_device *usbnet,
278 struct usb_configuration_descriptor *config ) {
279 int rc;
280
281 /* Describe communications interface, if applicable */
282 if ( usbnet_has_intr ( usbnet ) &&
283 ( rc = usbnet_comms_describe ( usbnet, config ) ) != 0 ) {
284 return rc;
285 }
286
287 /* Describe data interface */
288 if ( ( rc = usbnet_data_describe ( usbnet, config ) ) != 0 )
289 return rc;
290
291 return 0;
292 }