xref: /haiku/src/libs/compat/freebsd_network/driver.c (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2007-2010, Axel Dörfler. All rights reserved.
3  * Copyright 2009-2022, Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "device.h"
9 #include "sysinit.h"
10 
11 #include <stdlib.h>
12 #include <sys/sockio.h>
13 
14 #include <Drivers.h>
15 #include <ether_driver.h>
16 
17 #include <compat/sys/haiku-module.h>
18 
19 #include <compat/sys/bus.h>
20 #include <compat/sys/mbuf.h>
21 #include <compat/net/ethernet.h>
22 
23 #include <dev/usb/usb.h>
24 #include <dev/usb/usbdi.h>
25 #include <dev/usb/usb_device.h>
26 
27 
28 //#define TRACE_DRIVER
29 #ifdef TRACE_DRIVER
30 #	define TRACE(x) dprintf x
31 #else
32 #	define TRACE(x)
33 #endif
34 
35 
36 static struct {
37 	driver_t* driver;
38 	int bus;
39 	struct pci_info pci_info;
40 	struct freebsd_usb_device usb_dev;
41 	struct usb_attach_arg uaa;
42 } sProbedDevices[MAX_DEVICES];
43 
44 const char* gDeviceNameList[MAX_DEVICES + 1];
45 struct ifnet* gDevices[MAX_DEVICES];
46 int32 gDeviceCount;
47 
48 
49 static status_t
50 init_root_device(device_t *_root, int bus_type)
51 {
52 	static driver_t sRootDriverPCI = {
53 		"pci",
54 		NULL,
55 		sizeof(struct root_device_softc),
56 	};
57 	static driver_t sRootDriverUSB = {
58 		"uhub",
59 		NULL,
60 		sizeof(struct root_device_softc),
61 	};
62 
63 	device_t root = device_add_child(NULL, NULL, 0);
64 	if (root == NULL)
65 		return B_NO_MEMORY;
66 
67 	root->softc = malloc(sizeof(struct root_device_softc));
68 	if (root->softc == NULL) {
69 		device_delete_child(NULL, root);
70 		return B_NO_MEMORY;
71 	}
72 
73 	bzero(root->softc, sizeof(struct root_device_softc));
74 
75 	if (bus_type == BUS_pci)
76 		root->driver = &sRootDriverPCI;
77 	else if (bus_type == BUS_uhub)
78 		root->driver = &sRootDriverUSB;
79 	else
80 		panic("unknown bus type");
81 	((struct root_device_softc*)root->softc)->bus = bus_type;
82 
83 	root->root = root;
84 
85 	if (_root != NULL)
86 		*_root = root;
87 
88 	return B_OK;
89 }
90 
91 
92 static status_t
93 add_child_device(driver_t* driver, device_t root, device_t* _child)
94 {
95 	device_t child = device_add_child_driver(root, driver->name, driver, 0);
96 	if (child == NULL)
97 		return B_ERROR;
98 
99 	if (_child != NULL)
100 		*_child = child;
101 
102 	return B_OK;
103 }
104 
105 
106 static void
107 uninit_probed_devices()
108 {
109 	for (int p = 0; sProbedDevices[p].bus != BUS_INVALID; p++) {
110 		if (sProbedDevices[p].bus == BUS_pci) {
111 			gPci->unreserve_device(sProbedDevices[p].pci_info.bus,
112 				sProbedDevices[p].pci_info.device, sProbedDevices[p].pci_info.function,
113 				gDriverName, NULL);
114 		} else if (sProbedDevices->bus == BUS_uhub) {
115 			usb_cleanup_device(&sProbedDevices[p].usb_dev);
116 		}
117 	}
118 }
119 
120 
121 //	#pragma mark - Haiku Driver API
122 
123 
124 static status_t
125 init_hardware_pci(driver_t* drivers[])
126 {
127 	status_t status;
128 	int i = 0;
129 	pci_info* info;
130 	device_t root;
131 
132 	int p = 0;
133 	while (sProbedDevices[p].bus != BUS_INVALID)
134 		p++;
135 
136 	status = init_pci();
137 	if (status != B_OK)
138 		return status;
139 
140 	status = init_root_device(&root, BUS_pci);
141 	if (status != B_OK)
142 		return status;
143 
144 	bool found = false;
145 	for (info = get_device_pci_info(root); gPci->get_nth_pci_info(i, info) == B_OK; i++) {
146 		int best = 0;
147 		driver_t* driver = NULL;
148 
149 		for (int index = 0; drivers[index] != NULL; index++) {
150 			int result;
151 			device_t device = NULL;
152 			status = add_child_device(drivers[index], root, &device);
153 			if (status < B_OK)
154 				break;
155 
156 			result = device->methods.probe(device);
157 			if (result >= 0 && (driver == NULL || result > best)) {
158 				TRACE(("%s, found %s at %d (%d)\n", gDriverName,
159 					device_get_desc(device), i, result));
160 				driver = drivers[index];
161 				best = result;
162 			}
163 			device_delete_child(root, device);
164 		}
165 
166 		if (driver == NULL)
167 			continue;
168 
169 		// We've found a driver; now try to reserve the device and store it
170 		if (gPci->reserve_device(info->bus, info->device, info->function,
171 				gDriverName, NULL) != B_OK) {
172 			dprintf("%s: Failed to reserve PCI:%d:%d:%d\n",
173 				gDriverName, info->bus, info->device, info->function);
174 			continue;
175 		}
176 		sProbedDevices[p].bus = BUS_pci;
177 		sProbedDevices[p].driver = driver;
178 		sProbedDevices[p].pci_info = *info;
179 		found = true;
180 		p++;
181 	}
182 	sProbedDevices[p].bus = BUS_INVALID;
183 
184 	device_delete_child(NULL, root);
185 
186 	if (found)
187 		return B_OK;
188 
189 	uninit_pci();
190 	return B_NOT_SUPPORTED;
191 }
192 
193 
194 static status_t
195 init_hardware_uhub(driver_t* drivers[])
196 {
197 	status_t status;
198 	device_t root;
199 
200 	int p = 0;
201 	while (sProbedDevices[p].bus != BUS_INVALID)
202 		p++;
203 
204 	status = init_usb();
205 	if (status != B_OK)
206 		return status;
207 
208 	status = init_root_device(&root, BUS_uhub);
209 	if (status != B_OK)
210 		return status;
211 
212 	bool found = false;
213 	uint32 cookie = 0;
214 	struct freebsd_usb_device udev = {};
215 	while ((status = get_next_usb_device(&cookie, &udev)) == B_OK) {
216 		int best = 0;
217 		driver_t* driver = NULL;
218 
219 		struct usb_attach_arg uaa;
220 		status = get_usb_device_attach_arg(&udev, &uaa);
221 		if (status != B_OK)
222 			continue;
223 
224 		for (int index = 0; drivers[index] != NULL; index++) {
225 			int result;
226 			device_t device = NULL;
227 			status = add_child_device(drivers[index], root, &device);
228 			if (status < B_OK)
229 				break;
230 
231 			device_set_ivars(device, &uaa);
232 
233 			result = device->methods.probe(device);
234 			if (result >= 0 && (driver == NULL || result > best)) {
235 				TRACE(("%s, found %s at %d (%d)\n", gDriverName,
236 					device_get_desc(device), i, result));
237 				driver = drivers[index];
238 				best = result;
239 			}
240 			device_delete_child(root, device);
241 		}
242 
243 		if (driver == NULL)
244 			continue;
245 
246 		sProbedDevices[p].bus = BUS_uhub;
247 		sProbedDevices[p].driver = driver;
248 		sProbedDevices[p].usb_dev = udev;
249 		sProbedDevices[p].uaa = uaa;
250 		sProbedDevices[p].uaa.device = &sProbedDevices[p].usb_dev;
251 
252 		// We just "transferred ownership" of usb_dev to sProbedDevices.
253 		memset(&udev, 0, sizeof(udev));
254 
255 		found = true;
256 		p++;
257 	}
258 	sProbedDevices[p].bus = BUS_INVALID;
259 
260 	device_delete_child(NULL, root);
261 	usb_cleanup_device(&udev);
262 
263 	if (found)
264 		return B_OK;
265 
266 	uninit_usb();
267 	return B_NOT_SUPPORTED;
268 }
269 
270 
271 status_t
272 _fbsd_init_hardware(driver_t* pci_drivers[], driver_t* uhub_drivers[])
273 {
274 	sProbedDevices[0].bus = BUS_INVALID;
275 
276 	if (pci_drivers != NULL)
277 		init_hardware_pci(pci_drivers);
278 
279 	if (uhub_drivers != NULL)
280 		init_hardware_uhub(uhub_drivers);
281 
282 	return (sProbedDevices[0].bus != BUS_INVALID) ? B_OK : B_NOT_SUPPORTED;
283 }
284 
285 
286 status_t
287 _fbsd_init_drivers()
288 {
289 	status_t status = init_mutexes();
290 	if (status < B_OK)
291 		goto err2;
292 
293 	status = init_mbufs();
294 	if (status < B_OK)
295 		goto err3;
296 
297 	status = init_callout();
298 	if (status < B_OK)
299 		goto err4;
300 
301 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
302 		status = init_taskqueues();
303 		if (status < B_OK)
304 			goto err5;
305 	}
306 
307 	init_sysinit();
308 
309 	status = init_wlan_stack();
310 	if (status < B_OK)
311 		goto err6;
312 
313 	// Always hold the giant lock during attach.
314 	mtx_lock(&Giant);
315 
316 	for (int p = 0; sProbedDevices[p].bus != BUS_INVALID; p++) {
317 		device_t root, device = NULL;
318 		status = init_root_device(&root, sProbedDevices[p].bus);
319 		if (status != B_OK)
320 			break;
321 
322 		if (sProbedDevices[p].bus == BUS_pci) {
323 			pci_info* info = get_device_pci_info(root);
324 			*info = sProbedDevices[p].pci_info;
325 		} else if (sProbedDevices[p].bus == BUS_uhub) {
326 			struct root_device_softc* root_softc = (struct root_device_softc*)root->softc;
327 			root_softc->usb_dev = &sProbedDevices[p].usb_dev;
328 		}
329 
330 		status = add_child_device(sProbedDevices[p].driver, root, &device);
331 		if (status != B_OK)
332 			break;
333 
334 		if (sProbedDevices[p].bus == BUS_uhub)
335 			device_set_ivars(device, &sProbedDevices[p].uaa);
336 
337 		// some drivers expect probe() to be called before attach()
338 		// (i.e. they set driver softc in probe(), etc.)
339 		if (device->methods.probe(device) >= 0
340 				&& device_attach(device) == 0) {
341 			dprintf("%s: init_driver(%p)\n", gDriverName,
342 				sProbedDevices[p].driver);
343 		} else
344 			device_delete_child(NULL, root);
345 	}
346 
347 	mtx_unlock(&Giant);
348 
349 	if (gDeviceCount > 0)
350 		return B_OK;
351 
352 	if (status == B_OK)
353 		status = B_ERROR;
354 
355 err7:
356 	uninit_wlan_stack();
357 err6:
358 	uninit_sysinit();
359 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
360 		uninit_taskqueues();
361 err5:
362 	uninit_callout();
363 err4:
364 	uninit_mbufs();
365 err3:
366 	uninit_mutexes();
367 err2:
368 	uninit_probed_devices();
369 
370 	uninit_usb();
371 	uninit_pci();
372 
373 	return status;
374 }
375 
376 
377 status_t
378 _fbsd_uninit_drivers()
379 {
380 	for (int i = 0; i < gDeviceCount; i++)
381 		device_delete_child(NULL, gDevices[i]->root_device);
382 
383 	uninit_wlan_stack();
384 	uninit_sysinit();
385 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
386 		uninit_taskqueues();
387 	uninit_callout();
388 	uninit_mbufs();
389 	uninit_mutexes();
390 
391 	uninit_probed_devices();
392 
393 	uninit_usb();
394 	uninit_pci();
395 
396 	return B_OK;
397 }
398