xref: /haiku/src/libs/compat/freebsd_network/device.c (revision 5115ca085884f7b604a3d607688f0ca20fb7cf57)
1 /*
2  * Copyright 2007, Hugo Santos. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Hugo Santos, hugosantos@gmail.com
7  *
8  * Some of this code is based on previous work by Marcus Overhagen.
9  */
10 
11 #include "device.h"
12 
13 #include <stdlib.h>
14 #include <Drivers.h>
15 #include <ether_driver.h>
16 
17 #include <compat/sys/haiku-module.h>
18 
19 #include <compat/sys/mbuf.h>
20 #include <compat/net/ethernet.h>
21 
22 
23 #define MAX_DEVICES		8
24 
25 
26 device_t gDevices[MAX_DEVICES];
27 char *gDevNameList[MAX_DEVICES + 1];
28 
29 
30 static device_probe_t  *sDeviceProbe;
31 static device_attach_t *sDeviceAttach;
32 static device_detach_t *sDeviceDetach;
33 
34 
35 static device_t
36 allocate_device(driver_t *driver)
37 {
38 	char semName[64];
39 
40 	device_t dev = (device_t)malloc(sizeof(struct device));
41 	if (dev == NULL)
42 		return NULL;
43 
44 	memset(dev, 0, sizeof(struct device));
45 
46 	snprintf(semName, sizeof(semName), "%s rcv", gDriverName);
47 
48 	dev->softc = malloc(driver->softc_size);
49 	if (dev->softc == NULL) {
50 		free(dev);
51 		return NULL;
52 	}
53 
54 	dev->receive_sem = create_sem(0, semName);
55 	if (dev->receive_sem < 0) {
56 		free(dev->softc);
57 		free(dev);
58 		return NULL;
59 	}
60 
61 	return dev;
62 }
63 
64 
65 static void
66 free_device(device_t dev)
67 {
68 	delete_sem(dev->receive_sem);
69 	free(dev->softc);
70 	free(dev);
71 }
72 
73 
74 static device_method_signature_t
75 _resolve_method(driver_t *driver, const char *name)
76 {
77 	device_method_signature_t method = NULL;
78 	int i;
79 
80 	for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
81 		if (strcmp(driver->methods[i].name, name) == 0)
82 			method = driver->methods[i].method;
83 	}
84 
85 	return method;
86 }
87 
88 
89 static status_t
90 compat_open(const char *name, uint32 flags, void **cookie)
91 {
92 	status_t status;
93 	device_t dev;
94 	int i;
95 
96 	dprintf("%s, compat_open(%s, 0x%lx)\n", gDriverName, name, flags);
97 
98 	for (i = 0; gDevNameList[i] != NULL; i++) {
99 		if (strcmp(gDevNameList[i], name) == 0)
100 			break;
101 	}
102 
103 	if (gDevNameList[i] == NULL)
104 		return B_ERROR;
105 
106 	dev = gDevices[i];
107 
108 	if (atomic_or(&dev->flags, DEVICE_OPEN) & DEVICE_OPEN)
109 		return B_BUSY;
110 
111 	status = sDeviceAttach(dev);
112 	if (status != 0)
113 		dev->flags = 0;
114 
115 	*cookie = dev;
116 
117 	return status;
118 }
119 
120 
121 static status_t
122 compat_close(void *cookie)
123 {
124 	device_t dev = cookie;
125 
126 	dprintf("%s, compat_close(%p)\n", gDriverName, dev);
127 
128 	return B_ERROR;
129 }
130 
131 
132 static status_t
133 compat_free(void *cookie)
134 {
135 	device_t dev = cookie;
136 
137 	dprintf("%s, compat_free(%p)\n", gDriverName, dev);
138 
139 	free_device(dev);
140 	return B_ERROR;
141 }
142 
143 
144 static status_t
145 compat_read(void *cookie, off_t position, void *buf, size_t *numBytes)
146 {
147 	uint32 semFlags = B_CAN_INTERRUPT;
148 	device_t dev = cookie;
149 	status_t status;
150 	struct mbuf *mb;
151 	size_t len;
152 
153 	if (dev->flags & DEVICE_CLOSED)
154 		return B_INTERRUPTED;
155 
156 	if (dev->flags & DEVICE_NON_BLOCK)
157 		semFlags |= B_RELATIVE_TIMEOUT;
158 
159 	do {
160 		status = acquire_sem_etc(dev->receive_sem, 1, semFlags, 0);
161 		if (dev->flags & DEVICE_CLOSED)
162 			return B_INTERRUPTED;
163 
164 		if (status == B_WOULD_BLOCK) {
165 			*numBytes = 0;
166 			return B_OK;
167 		} else if (status < B_OK)
168 			return status;
169 
170 		IF_DEQUEUE(&dev->receive_queue, mb);
171 	} while (mb == NULL);
172 
173 	len = min_c(max_c((size_t)mb->m_len, 0), *numBytes);
174 
175 	mb = m_defrag(mb, 0);
176 	if (mb == NULL) {
177 		*numBytes = 0;
178 		return B_NO_MEMORY;
179 	}
180 
181 	memcpy(buf, mtod(mb, const void *), len);
182 	*numBytes = len;
183 
184 	m_freem(mb);
185 	return B_OK;
186 }
187 
188 
189 static status_t
190 compat_write(void *cookie, off_t position, const void *buffer,
191 	size_t *numBytes)
192 {
193 	device_t dev = cookie;
194 	struct mbuf *mb;
195 
196 	mb = m_getcl(0, MT_DATA, 0);
197 	if (mb == NULL)
198 		return ENOBUFS;
199 
200 	/* if we waited, check after if the ifp is still valid */
201 
202 	mb->m_len = min_c(*numBytes, (size_t)MCLBYTES);
203 	memcpy(mtod(mb, void *), buffer, mb->m_len);
204 
205 	return dev->ifp->if_output(dev->ifp, mb, NULL, NULL);
206 }
207 
208 
209 static status_t
210 compat_control(void *cookie, uint32 op, void *arg, size_t len)
211 {
212 	device_t dev = cookie;
213 
214 	switch (op) {
215 		case ETHER_INIT:
216 			return B_OK;
217 
218 		case ETHER_GETADDR:
219 			memcpy(arg, IF_LLADDR(dev->ifp), ETHER_ADDR_LEN);
220 			return B_OK;
221 
222 		case ETHER_NONBLOCK:
223 			if (*(int32 *)arg)
224 				dev->flags |= DEVICE_NON_BLOCK;
225 			else
226 				dev->flags &= ~DEVICE_NON_BLOCK;
227 			return B_OK;
228 
229 		case ETHER_SETPROMISC:
230 			/* TODO */
231 			return B_ERROR;
232 
233 		case ETHER_GETFRAMESIZE:
234 			*(uint32 *)arg = dev->ifp->if_mtu;
235 			return B_OK;
236 
237 		case ETHER_ADDMULTI:
238 		case ETHER_REMMULTI:
239 			/* TODO */
240 			return B_ERROR;
241 
242 		case ETHER_GET_LINK_STATE:
243 			/* TODO */
244 			return B_ERROR;
245 
246 		case ETHER_SET_LINK_STATE_SEM:
247 			/* TODO */
248 			return B_OK;
249 	}
250 
251 	return B_BAD_VALUE;
252 }
253 
254 
255 device_hooks gDeviceHooks = {
256 	compat_open,
257 	compat_close,
258 	compat_free,
259 	compat_control,
260 	compat_read,
261 	compat_write,
262 };
263 
264 
265 status_t
266 _fbsd_init_hardware(driver_t *driver)
267 {
268 	struct device fakeDevice;
269 	device_probe_t *probe;
270 	int i;
271 
272 	dprintf("%s: init_hardware(%p)\n", gDriverName, driver);
273 
274 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
275 		return B_ERROR;
276 
277 	probe = (device_probe_t *)_resolve_method(driver, "device_probe");
278 	if (probe == NULL) {
279 		dprintf("%s: driver has no device_probe method.\n", gDriverName);
280 		return B_ERROR;
281 	}
282 
283 	memset(&fakeDevice, 0, sizeof(struct device));
284 
285 	for (i = 0; gPci->get_nth_pci_info(i, &fakeDevice.pci_info) == B_OK; i++) {
286 		if (probe(&fakeDevice) >= 0) {
287 			dprintf("%s, found %s at %d\n", gDriverName,
288 				fakeDevice.description, i);
289 			put_module(B_PCI_MODULE_NAME);
290 			return B_OK;
291 		}
292 	}
293 
294 	dprintf("%s: no hardware found.\n", gDriverName);
295 	put_module(B_PCI_MODULE_NAME);
296 
297 	return B_ERROR;
298 }
299 
300 
301 status_t
302 _fbsd_init_driver(driver_t *driver)
303 {
304 	int i, ncards = 0;
305 	status_t status;
306 	device_t dev;
307 
308 	dprintf("%s: init_driver(%p)\n", gDriverName, driver);
309 
310 	sDeviceProbe  = (device_probe_t  *)_resolve_method(driver, "device_probe");
311 	sDeviceAttach = (device_attach_t *)_resolve_method(driver, "device_attach");
312 	sDeviceDetach = (device_detach_t *)_resolve_method(driver, "device_detach");
313 
314 	dev = allocate_device(driver);
315 	if (dev == NULL)
316 		return B_NO_MEMORY;
317 
318 	status = init_mutexes();
319 	if (status < B_OK) {
320 		free_device(dev);
321 		return status;
322 	}
323 
324 	status = init_mbufs();
325 	if (status < B_OK) {
326 		uninit_mutexes();
327 		free_device(dev);
328 		return status;
329 	}
330 
331 	init_bounce_pages();
332 
333 	for (i = 0; dev != NULL
334 			&& gPci->get_nth_pci_info(i, &dev->pci_info) == B_OK; i++) {
335 		if (sDeviceProbe(dev) >= 0) {
336 			snprintf(dev->dev_name, sizeof(dev->dev_name), "net/%s/%i",
337 				gDriverName, ncards);
338 			dprintf("%s, adding %s @%d -> /dev/%s\n", gDriverName, dev->description,
339 				i, dev->dev_name);
340 
341 			gDevices[ncards] = dev;
342 			gDevNameList[ncards] = dev->dev_name;
343 
344 			ncards++;
345 			if (ncards < MAX_DEVICES)
346 				dev = allocate_device(driver);
347 			else
348 				dev = NULL;
349 		}
350 	}
351 
352 	if (dev != NULL)
353 		free_device(dev);
354 
355 	dprintf("%s, ... %d cards.\n", gDriverName, ncards);
356 
357 	gDevNameList[ncards + 1] = NULL;
358 
359 	return B_OK;
360 }
361 
362 
363 void
364 _fbsd_uninit_driver(driver_t *driver)
365 {
366 	int i;
367 
368 	dprintf("%s: uninit_driver(%p)\n", gDriverName, driver);
369 
370 	for (i = 0; gDevNameList[i] != NULL; i++) {
371 		free_device(gDevices[i]);
372 	}
373 
374 	uninit_bounce_pages();
375 	uninit_mbufs();
376 	uninit_mutexes();
377 }
378