xref: /haiku/src/libs/compat/freebsd_network/driver.c (revision d374a27286b8a52974a97dba0d5966ea026a665d)
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(driver_t *driver, device_t *_root, device_t *_child)
46 {
47 	static driver_t sRootDriver = {
48 		"pci",
49 		NULL,
50 		sizeof(struct root_device_softc)
51 	};
52 	device_t child;
53 
54 	device_t root = device_add_child(NULL, NULL, 0);
55 	if (root == NULL)
56 		return B_NO_MEMORY;
57 
58 	root->softc = malloc(sizeof(struct root_device_softc));
59 	if (root->softc == NULL) {
60 		device_delete_child(NULL, root);
61 		return B_NO_MEMORY;
62 	}
63 
64 	root->driver = &sRootDriver;
65 	root->root = root;
66 
67 	child = device_add_child(root, driver->name, 0);
68 	if (child == NULL) {
69 		device_delete_child(NULL, root);
70 		return B_ERROR;
71 	}
72 
73 	if (_root != NULL)
74 		*_root = root;
75 	if (_child != NULL)
76 		*_child = child;
77 
78 	return B_OK;
79 }
80 
81 
82 static pci_info *
83 get_pci_info(struct device *device)
84 {
85 	return &((struct root_device_softc *)device->softc)->pci_info;
86 }
87 
88 
89 //	#pragma mark - Haiku Driver API
90 
91 
92 status_t
93 _fbsd_init_hardware(driver_t *driver)
94 {
95 	status_t status = B_ENTRY_NOT_FOUND;
96 	device_t child, root;
97 	pci_info *info;
98 	int i;
99 
100 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
101 		return B_ERROR;
102 
103 	if (init_root_device(driver, &root, &child) != B_OK) {
104 		dprintf("%s: creating device failed.\n", gDriverName);
105 		put_module(B_PCI_MODULE_NAME);
106 		return B_ERROR;
107 	}
108 
109 	TRACE(("%s: init_hardware(%p)\n", gDriverName, driver));
110 
111 	if (child->methods.probe == NULL) {
112 		dprintf("%s: driver has no device_probe method.\n", gDriverName);
113 		device_delete_child(NULL, root);
114 		put_module(B_PCI_MODULE_NAME);
115 		return B_ERROR;
116 	}
117 
118 	info = get_pci_info(root);
119 
120 	for (i = 0; gPci->get_nth_pci_info(i, info) == B_OK; i++) {
121 		int result;
122 		result = child->methods.probe(child);
123 		if (result >= 0) {
124 			TRACE(("%s, found %s at %d\n", gDriverName,
125 				device_get_desc(child), i));
126 			status = B_OK;
127 			break;
128 		}
129 	}
130 
131 	if (status < B_OK)
132 		TRACE(("%s: no hardware found.\n", gDriverName));
133 
134 	device_delete_child(NULL, root);
135 	put_module(B_PCI_MODULE_NAME);
136 
137 	return status;
138 }
139 
140 
141 status_t
142 _fbsd_init_driver(driver_t *driver)
143 {
144 	status_t status;
145 	int i = 0;
146 
147 	dprintf("%s: init_driver(%p)\n", gDriverName, driver);
148 
149 	status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
150 	if (status < B_OK)
151 		return status;
152 
153 	// if it fails we just don't support x86 specific features (like MSIs)
154 	if (get_module(B_PCI_X86_MODULE_NAME, (module_info **)&gPCIx86) != B_OK)
155 		gPCIx86 = NULL;
156 
157 	status = init_hard_clock();
158 	if (status < B_OK)
159 		goto err1;
160 
161 	status = init_mutexes();
162 	if (status < B_OK)
163 		goto err2;
164 
165 	status = init_mbufs();
166 	if (status < B_OK)
167 		goto err3;
168 
169 	status = init_callout();
170 	if (status < B_OK)
171 		goto err4;
172 
173 	init_bounce_pages();
174 
175 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
176 		status = init_taskqueues();
177 		if (status < B_OK)
178 			goto err5;
179 	}
180 
181 	status = init_wlan_stack();
182 	if (status < B_OK)
183 		goto err6;
184 
185 	while (gDeviceCount < MAX_DEVICES) {
186 		device_t root, device;
187 		bool found = false;
188 		pci_info *info;
189 
190 		status = init_root_device(driver, &root, &device);
191 		if (status < B_OK)
192 			break;
193 
194 		info = get_pci_info(root);
195 
196 		for (; gPci->get_nth_pci_info(i, info) == B_OK; i++) {
197 			if (device->methods.probe(device) < 0)
198 				continue;
199 
200 			if (device_attach(device) == 0)
201 				found = true;
202 
203 			i++;
204 			break;
205 		}
206 
207 		if (!found) {
208 			device_delete_child(NULL, root);
209 			break;
210 		}
211 	}
212 
213 	if (gDeviceCount > 0)
214 		return B_OK;
215 
216 	if (status == B_OK)
217 		status = B_ERROR;
218 
219 	uninit_wlan_stack();
220 
221 err6:
222 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
223 		uninit_taskqueues();
224 err5:
225 	uninit_mbufs();
226 err4:
227 	uninit_callout();
228 err3:
229 	uninit_mutexes();
230 err2:
231 	uninit_hard_clock();
232 err1:
233 	put_module(B_PCI_MODULE_NAME);
234 	if (gPCIx86 != NULL)
235 		put_module(B_PCI_X86_MODULE_NAME);
236 
237 	return status;
238 }
239 
240 
241 void
242 _fbsd_uninit_driver(driver_t *driver)
243 {
244 	int i;
245 
246 	TRACE(("%s: uninit_driver(%p)\n", gDriverName, driver));
247 
248 	for (i = 0; i < gDeviceCount; i++) {
249 		device_delete_child(NULL, gDevices[i]->root_device);
250 	}
251 
252 	uninit_wlan_stack();
253 	uninit_bounce_pages();
254 	uninit_mbufs();
255 	if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
256 		uninit_taskqueues();
257 	uninit_callout();
258 	uninit_mutexes();
259 
260 	put_module(B_PCI_MODULE_NAME);
261 	if (gPCIx86 != NULL)
262 		put_module(B_PCI_X86_MODULE_NAME);
263 }
264