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
36static 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
44const char* gDeviceNameList[MAX_DEVICES + 1];
45struct ifnet* gDevices[MAX_DEVICES];
46int32 gDeviceCount;
47
48
49static status_t
50init_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
92static status_t
93add_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
106static void
107uninit_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
124static status_t
125init_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
194static status_t
195init_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
271status_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
286status_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
355err7:
356	uninit_wlan_stack();
357err6:
358	uninit_sysinit();
359	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
360		uninit_taskqueues();
361err5:
362	uninit_callout();
363err4:
364	uninit_mbufs();
365err3:
366	uninit_mutexes();
367err2:
368	uninit_probed_devices();
369
370	uninit_usb();
371	uninit_pci();
372
373	return status;
374}
375
376
377status_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