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
init_root_device(device_t * _root,int bus_type)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
add_child_device(driver_t * driver,device_t root,device_t * _child)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
uninit_probed_devices()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
init_hardware_pci(driver_t * drivers[])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
init_hardware_uhub(driver_t * drivers[])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
_fbsd_init_hardware(driver_t * pci_drivers[],driver_t * uhub_drivers[])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
_fbsd_init_drivers()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
_fbsd_uninit_drivers()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