xref: /haiku/src/libs/compat/freebsd_network/driver.c (revision 4c1d9cf74e1c1706922e5b5795e788fb14fe81c9)
1 /*
2  * Copyright 2007, Hugo Santos. All Rights Reserved.
3  * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
4  * Copyright 2004, Marcus Overhagen. All Rights Reserved.
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 /*!	Driver functions that adapt the FreeBSD driver to Haiku's driver API.
10 	The actual driver functions are exported by the HAIKU_FBSD_DRIVER_GLUE
11 	macro, and just call the functions here.
12 */
13 
14 
15 #include "device.h"
16 
17 #include <stdlib.h>
18 #include <sys/sockio.h>
19 
20 #include <Drivers.h>
21 #include <ether_driver.h>
22 #include <PCI_x86.h>
23 
24 #include <compat/sys/haiku-module.h>
25 
26 #include <compat/sys/bus.h>
27 #include <compat/sys/mbuf.h>
28 #include <compat/net/ethernet.h>
29 
30 
31 //#define TRACE_DRIVER
32 #ifdef TRACE_DRIVER
33 #	define TRACE(x) dprintf x
34 #else
35 #	define TRACE(x)
36 #endif
37 
38 
39 const char *gDeviceNameList[MAX_DEVICES + 1];
40 struct ifnet *gDevices[MAX_DEVICES];
41 int32 gDeviceCount;
42 
43 
44 static status_t
45 init_root_device(device_t *_root)
46 {
47 	static driver_t sRootDriver = {
48 		"pci",
49 		NULL,
50 		sizeof(struct root_device_softc)
51 	};
52 
53 	device_t root = device_add_child(NULL, NULL, 0);
54 	if (root == NULL)
55 		return B_NO_MEMORY;
56 
57 	root->softc = malloc(sizeof(struct root_device_softc));
58 	if (root->softc == NULL) {
59 		device_delete_child(NULL, root);
60 		return B_NO_MEMORY;
61 	}
62 
63 	bzero(root->softc, sizeof(struct root_device_softc));
64 	root->driver = &sRootDriver;
65 	root->root = root;
66 
67 	if (_root != NULL)
68 		*_root = root;
69 
70 	return B_OK;
71 }
72 
73 
74 static status_t
75 add_child_device(driver_t *driver, device_t root, device_t *_child)
76 {
77 	device_t child = device_add_child(root, driver->name, 0);
78 	if (child == NULL) {
79 		return B_ERROR;
80 	}
81 
82 	if (_child != NULL)
83 		*_child = child;
84 
85 	return B_OK;
86 }
87 
88 
89 static pci_info *
90 get_pci_info(struct device *device)
91 {
92 	return &((struct root_device_softc *)device->softc)->pci_info;
93 }
94 
95 
96 //	#pragma mark - Haiku Driver API
97 
98 
99 status_t
100 _fbsd_init_drivers(driver_t *drivers[])
101 {
102 	status_t status;
103 	int i = 0;
104 	int index = 0;
105 	pci_info *info;
106 	device_t root;
107 
108 	status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
109 	if (status < B_OK)
110 		return status;
111 
112 	// if it fails we just don't support x86 specific features (like MSIs)
113 	if (get_module(B_PCI_X86_MODULE_NAME, (module_info **)&gPCIx86) != B_OK)
114 		gPCIx86 = NULL;
115 
116 	status = init_mutexes();
117 	if (status < B_OK)
118 		goto err2;
119 
120 	status = init_mbufs();
121 	if (status < B_OK)
122 		goto err3;
123 
124 	status = init_callout();
125 	if (status < B_OK)
126 		goto err4;
127 
128 	init_bounce_pages();
129 
130 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
131 		status = init_taskqueues();
132 		if (status < B_OK)
133 			goto err5;
134 	}
135 
136 	status = init_wlan_stack();
137 	if (status < B_OK)
138 		goto err6;
139 
140 	status = init_root_device(&root);
141 	if (status != B_OK)
142 		goto err7;
143 
144 	for (info = get_pci_info(root); gPci->get_nth_pci_info(i, info) == B_OK;
145 		i++) {
146 		int best = 0;
147 		driver_t *driver = NULL;
148 
149 		for (index = 0; drivers[index] && gDeviceCount < MAX_DEVICES; index++) {
150 			int result;
151 			device_t device;
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 			device_t device;
168 			status = add_child_device(driver, root, &device);
169 			if (status != B_OK)
170 				break;
171 			// some drivers expect probe() to be called before attach()
172 			// (i.e. they set driver softc in probe(), etc.)
173 			if (device->methods.probe(device) >= 0
174 					&& device_attach(device) == 0) {
175 				dprintf("%s: init_driver(%p) at %d\n", gDriverName, driver, i);
176 				status = init_root_device(&root);
177 				if (status != B_OK)
178 					break;
179 				info = get_pci_info(root);
180 			} else
181 				device_delete_child(root, device);
182 		}
183 	}
184 
185 	if (gDeviceCount > 0)
186 		return B_OK;
187 
188 	device_delete_child(NULL, root);
189 
190 	if (status == B_OK)
191 		status = B_ERROR;
192 
193 err7:
194 	uninit_wlan_stack();
195 
196 err6:
197 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
198 		uninit_taskqueues();
199 err5:
200 	uninit_callout();
201 err4:
202 	uninit_mbufs();
203 err3:
204 	uninit_mutexes();
205 err2:
206 	put_module(B_PCI_MODULE_NAME);
207 	if (gPCIx86 != NULL)
208 		put_module(B_PCI_X86_MODULE_NAME);
209 
210 	return status;
211 }
212 
213 
214 status_t
215 _fbsd_uninit_drivers(driver_t *drivers[])
216 {
217 	int i;
218 
219 	for (i = 0; drivers[i]; i++)
220 		TRACE(("%s: uninit_driver(%p)\n", gDriverName, drivers[i]));
221 
222 	for (i = 0; i < gDeviceCount; i++) {
223 		device_delete_child(NULL, gDevices[i]->root_device);
224 	}
225 
226 	uninit_wlan_stack();
227 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
228 		uninit_taskqueues();
229 	uninit_bounce_pages();
230 	uninit_callout();
231 	uninit_mbufs();
232 	uninit_mutexes();
233 
234 	put_module(B_PCI_MODULE_NAME);
235 	if (gPCIx86 != NULL)
236 		put_module(B_PCI_X86_MODULE_NAME);
237 
238 	return B_OK;
239 }
240