xref: /haiku/src/libs/compat/freebsd_network/device.c (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2007, Hugo Santos, hugosantos@gmail.com. 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  *
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include "device.h"
11 
12 #include <stdio.h>
13 
14 #include <KernelExport.h>
15 #include <image.h>
16 #include <kernel/heap.h>
17 
18 #include <compat/machine/resource.h>
19 #include <compat/dev/mii/mii.h>
20 #include <compat/sys/bus.h>
21 #include <compat/net/if_media.h>
22 
23 #include <compat/dev/mii/miivar.h>
24 
25 
26 spinlock __haiku_intr_spinlock;
27 
28 struct net_stack_module_info *gStack;
29 pci_module_info *gPci;
30 struct pci_x86_module_info *gPCIx86;
31 
32 static struct list sRootDevices;
33 static int sNextUnit;
34 
35 //	#pragma mark - private functions
36 
37 
38 static device_t
39 init_device(device_t device, driver_t *driver)
40 {
41 	list_init_etc(&device->children, offsetof(struct device, link));
42 	device->unit = sNextUnit++;
43 
44 	if (driver != NULL && device_set_driver(device, driver) < 0)
45 		return NULL;
46 
47 	return device;
48 }
49 
50 
51 static device_t
52 new_device(driver_t *driver)
53 {
54 	device_t dev = malloc(sizeof(struct device));
55 	if (dev == NULL)
56 		return NULL;
57 
58 	memset(dev, 0, sizeof(struct device));
59 
60 	if (init_device(dev, driver) == NULL) {
61 		free(dev);
62 		return NULL;
63 	}
64 
65 	return dev;
66 }
67 
68 
69 static image_id
70 find_own_image()
71 {
72 	int32 cookie = 0;
73 	image_info info;
74 	while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) {
75 		if (((addr_t)info.text <= (addr_t)find_own_image
76 			&& (addr_t)info.text + (addr_t)info.text_size
77 				> (addr_t)find_own_image)) {
78 			// found our own image
79 			return info.id;
80 		}
81 	}
82 
83 	return B_ENTRY_NOT_FOUND;
84 }
85 
86 
87 static device_method_signature_t
88 resolve_method(driver_t *driver, const char *name)
89 {
90 	device_method_signature_t method = NULL;
91 	int i;
92 
93 	for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
94 		if (strcmp(driver->methods[i].name, name) == 0)
95 			method = driver->methods[i].method;
96 	}
97 
98 	if (method == NULL)
99 		panic("resolve_method: method%s not found\n", name);
100 
101 	return method;
102 }
103 
104 
105 //	#pragma mark - Device
106 
107 
108 void
109 driver_printf(const char *format, ...)
110 {
111 	va_list vl;
112 	va_start(vl, format);
113 	driver_vprintf(format, vl);
114 	va_end(vl);
115 }
116 
117 
118 static int
119 driver_vprintf_etc(const char *extra, const char *format, va_list vl)
120 {
121 	char buf[256];
122 	int ret = vsnprintf(buf, sizeof(buf), format, vl);
123 
124 	if (extra)
125 		dprintf("[%s] (%s) %s", gDriverName, extra, buf);
126 	else
127 		dprintf("[%s] %s", gDriverName, buf);
128 
129 	return ret;
130 }
131 
132 
133 int
134 driver_vprintf(const char *format, va_list vl)
135 {
136 	return driver_vprintf_etc(NULL, format, vl);
137 }
138 
139 
140 int
141 device_printf(device_t dev, const char *format, ...)
142 {
143 	va_list vl;
144 
145 	va_start(vl, format);
146 	driver_vprintf_etc(dev->device_name, format, vl);
147 	va_end(vl);
148 	return 0;
149 }
150 
151 
152 void
153 device_set_desc(device_t dev, const char *desc)
154 {
155 	dev->description = desc;
156 }
157 
158 
159 void
160 device_set_desc_copy(device_t dev, const char *desc)
161 {
162 	dev->description = strdup(desc);
163 	dev->flags |= DEVICE_DESC_ALLOCED;
164 }
165 
166 
167 const char *
168 device_get_desc(device_t dev)
169 {
170 	return dev->description;
171 }
172 
173 
174 device_t
175 device_get_parent(device_t dev)
176 {
177 	return dev->parent;
178 }
179 
180 
181 devclass_t
182 device_get_devclass(device_t dev)
183 {
184 	// TODO find out what to do
185 	return 0;
186 }
187 
188 
189 int
190 device_get_children(device_t dev, device_t **devlistp, int *devcountp)
191 {
192 	int count;
193 	device_t child = NULL;
194 	device_t *list;
195 
196 	count = 0;
197 	while ((child = list_get_next_item(&dev->children, child)) != NULL) {
198 		count++;
199 	}
200 
201 	if (count == 0) {
202 		*devlistp = NULL;
203 		*devcountp = 0;
204 		return (0);
205 	}
206 
207 	list = malloc(count * sizeof(device_t));
208 	if (!list)
209 		return (ENOMEM);
210 
211 	count = 0;
212 	while ((child = list_get_next_item(&dev->children, child)) != NULL) {
213 		list[count] = child;
214 		count++;
215 	}
216 
217 	*devlistp = list;
218 	*devcountp = count;
219 
220 	return (0);
221 }
222 
223 
224 void
225 device_set_ivars(device_t dev, void *ivars)
226 {
227 	dev->ivars = ivars;
228 }
229 
230 
231 void *
232 device_get_ivars(device_t dev)
233 {
234 	return dev->ivars;
235 }
236 
237 
238 const char *
239 device_get_name(device_t dev)
240 {
241 	if (dev == NULL)
242 		return NULL;
243 
244 	return dev->device_name;
245 }
246 
247 
248 int
249 device_get_unit(device_t dev)
250 {
251 	return dev->unit;
252 }
253 
254 
255 const char *
256 device_get_nameunit(device_t dev)
257 {
258 	return dev->nameunit;
259 }
260 
261 
262 void *
263 device_get_softc(device_t dev)
264 {
265 	return dev->softc;
266 }
267 
268 
269 void
270 device_set_softc(device_t dev, void *softc)
271 {
272 	if (dev->softc == softc)
273 		return;
274 
275 	if ((dev->flags & DEVICE_SOFTC_SET) == 0) {
276 		// Not externally allocated. We own it so we must clean it up.
277 		free(dev->softc);
278 	}
279 
280 	dev->softc = softc;
281 	if (dev->softc != NULL)
282 		dev->flags |= DEVICE_SOFTC_SET;
283 	else
284 		dev->flags &= ~DEVICE_SOFTC_SET;
285 }
286 
287 
288 u_int32_t
289 device_get_flags(device_t dev)
290 {
291 	return dev->flags;
292 }
293 
294 
295 int
296 device_set_driver(device_t dev, driver_t *driver)
297 {
298 	int i;
299 
300 	dev->softc = malloc(driver->size);
301 	if (dev->softc == NULL)
302 		return -1;
303 
304 	memset(dev->softc, 0, driver->size);
305 	dev->driver = driver;
306 
307 	for (i = 0; driver->methods[i].name != NULL; i++) {
308 		device_method_t *mth = &driver->methods[i];
309 
310 		if (strcmp(mth->name, "device_register") == 0)
311 			dev->methods.device_register = (void *)mth->method;
312 		else if (strcmp(mth->name, "device_probe") == 0)
313 			dev->methods.probe = (void *)mth->method;
314 		else if (strcmp(mth->name, "device_attach") == 0)
315 			dev->methods.attach = (void *)mth->method;
316 		else if (strcmp(mth->name, "device_detach") == 0)
317 			dev->methods.detach = (void *)mth->method;
318 		else if (strcmp(mth->name, "device_suspend") == 0)
319 			dev->methods.suspend = (void *)mth->method;
320 		else if (strcmp(mth->name, "device_resume") == 0)
321 			dev->methods.resume = (void *)mth->method;
322 		else if (strcmp(mth->name, "device_shutdown") == 0)
323 			dev->methods.shutdown = (void *)mth->method;
324 		else if (strcmp(mth->name, "miibus_readreg") == 0)
325 			dev->methods.miibus_readreg = (void *)mth->method;
326 		else if (strcmp(mth->name, "miibus_writereg") == 0)
327 			dev->methods.miibus_writereg = (void *)mth->method;
328 		else if (strcmp(mth->name, "miibus_statchg") == 0)
329 			dev->methods.miibus_statchg = (void *)mth->method;
330 		else if (!strcmp(mth->name, "miibus_linkchg"))
331 			dev->methods.miibus_linkchg = (void *)mth->method;
332 		else if (!strcmp(mth->name, "miibus_mediainit"))
333 			dev->methods.miibus_mediainit = (void *)mth->method;
334 		else if (!strcmp(mth->name, "bus_child_location_str"))
335 			dev->methods.bus_child_location_str = (void *)mth->method;
336 		else if (!strcmp(mth->name, "bus_child_pnpinfo_str"))
337 			dev->methods.bus_child_pnpinfo_str = (void *)mth->method;
338 		else if (!strcmp(mth->name, "bus_hinted_child"))
339 			dev->methods.bus_hinted_child = (void *)mth->method;
340 		else if (!strcmp(mth->name, "bus_print_child"))
341 			dev->methods.bus_print_child = (void *)mth->method;
342 		else if (!strcmp(mth->name, "bus_read_ivar"))
343 			dev->methods.bus_read_ivar = (void *)mth->method;
344 		else if (!strcmp(mth->name, "bus_get_dma_tag"))
345 			dev->methods.bus_get_dma_tag = (void *)mth->method;
346 		else
347 			panic("device_set_driver: method %s not found\n", mth->name);
348 
349 	}
350 
351 	return 0;
352 }
353 
354 
355 int
356 device_is_alive(device_t device)
357 {
358 	return (device->flags & DEVICE_ATTACHED) != 0;
359 }
360 
361 
362 device_t
363 device_add_child_driver(device_t parent, const char* name, driver_t* _driver,
364 	int unit)
365 {
366 	device_t child = NULL;
367 
368 	if (_driver == NULL && name != NULL) {
369 		if (strcmp(name, "miibus") == 0)
370 			child = new_device(&miibus_driver);
371 		else {
372 			// find matching driver structure
373 			driver_t** driver;
374 			char symbol[128];
375 
376 			snprintf(symbol, sizeof(symbol), "__fbsd_%s_%s", name,
377 				parent->driver->name);
378 			if (get_image_symbol(find_own_image(), symbol, B_SYMBOL_TYPE_DATA,
379 					(void**)&driver) == B_OK) {
380 				child = new_device(*driver);
381 			} else
382 				device_printf(parent, "couldn't find symbol %s\n", symbol);
383 		}
384 	} else if (_driver != NULL) {
385 		child = new_device(_driver);
386 	} else
387 		child = new_device(NULL);
388 
389 	if (child == NULL)
390 		return NULL;
391 
392 	if (name != NULL)
393 		strlcpy(child->device_name, name, sizeof(child->device_name));
394 
395 	child->parent = parent;
396 
397 	if (parent != NULL) {
398 		list_add_item(&parent->children, child);
399 		child->root = parent->root;
400 	} else {
401 		if (sRootDevices.link.next == NULL)
402 			list_init_etc(&sRootDevices, offsetof(struct device, link));
403 		list_add_item(&sRootDevices, child);
404 	}
405 
406 	return child;
407 }
408 
409 
410 device_t
411 device_add_child(device_t parent, const char* name, int unit)
412 {
413 	return device_add_child_driver(parent, name, NULL, unit);
414 }
415 
416 
417 /*!	Delete the child and all of its children. Detach as necessary.
418 */
419 int
420 device_delete_child(device_t parent, device_t child)
421 {
422 	int status;
423 
424 	if (child == NULL)
425 		return 0;
426 
427 	if (parent != NULL)
428 		list_remove_item(&parent->children, child);
429 	else
430 		list_remove_item(&sRootDevices, child);
431 
432 	// We differentiate from the FreeBSD logic here - it will first delete
433 	// the children, and will then detach the device.
434 	// This has the problem that you cannot safely call device_delete_child()
435 	// as you don't know if one of the children deletes its own children this
436 	// way when it is detached.
437 	// Therefore, we'll detach first, and then delete whatever is left.
438 
439 	parent = child;
440 	child = NULL;
441 
442 	// detach children
443 	while ((child = list_get_next_item(&parent->children, child)) != NULL) {
444 		device_detach(child);
445 	}
446 
447 	// detach device
448 	status = device_detach(parent);
449 	if (status != 0)
450 		return status;
451 
452 	// delete children
453 	while ((child = list_get_first_item(&parent->children)) != NULL) {
454 		device_delete_child(parent, child);
455 	}
456 
457 	// delete device
458 	if (parent->flags & DEVICE_DESC_ALLOCED)
459 		free((char *)parent->description);
460 
461 	// Delete softc if we were the ones to allocate it.
462 	if ((parent->flags & DEVICE_SOFTC_SET) == 0)
463 		free(parent->softc);
464 
465 	free(parent);
466 	return 0;
467 }
468 
469 
470 int
471 device_is_attached(device_t device)
472 {
473 	return (device->flags & DEVICE_ATTACHED) != 0;
474 }
475 
476 
477 int
478 device_attach(device_t device)
479 {
480 	int result;
481 
482 	if (device->driver == NULL
483 		|| device->methods.attach == NULL)
484 		return B_ERROR;
485 
486 	result = device->methods.attach(device);
487 
488 	if (result == 0)
489 		atomic_or(&device->flags, DEVICE_ATTACHED);
490 
491 	if (result == 0 && HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE))
492 		result = start_wlan(device);
493 
494 	return result;
495 }
496 
497 
498 int
499 device_detach(device_t device)
500 {
501 	if (device->driver == NULL)
502 		return B_ERROR;
503 
504 	if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0
505 			&& device->methods.detach != NULL) {
506 		int result = 0;
507 		if (HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE))
508 			result = stop_wlan(device);
509 		if (result != 0 && result != B_BAD_VALUE) {
510 			atomic_or(&device->flags, DEVICE_ATTACHED);
511 			return result;
512 		}
513 
514 		result = device->methods.detach(device);
515 		if (result != 0) {
516 			atomic_or(&device->flags, DEVICE_ATTACHED);
517 			return result;
518 		}
519 	}
520 
521 	return 0;
522 }
523 
524 
525 int
526 bus_generic_attach(device_t dev)
527 {
528 	device_t child = NULL;
529 
530 	while ((child = list_get_next_item(&dev->children, child)) != NULL) {
531 		if (child->driver == NULL) {
532 			driver_t *driver = __haiku_select_miibus_driver(child);
533 			if (driver == NULL) {
534 				struct mii_attach_args *ma = device_get_ivars(child);
535 
536 				device_printf(dev, "No PHY module found (%x/%x)!\n",
537 					MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2));
538 			} else
539 				device_set_driver(child, driver);
540 		} else
541 			child->methods.probe(child);
542 
543 		if (child->driver != NULL) {
544 			int result = device_attach(child);
545 			if (result != 0)
546 				return result;
547 		}
548 	}
549 
550 	return 0;
551 }
552 
553 
554 int
555 bus_generic_detach(device_t device)
556 {
557 	device_t child = NULL;
558 
559 	if ((device->flags & DEVICE_ATTACHED) == 0)
560 		return B_ERROR;
561 
562 	while (true) {
563 		child = list_get_next_item(&device->children, child);
564 		if (child == NULL)
565 			break;
566 
567 		device_detach(child);
568 	}
569 
570 	return 0;
571 }
572 
573 
574 //	#pragma mark - Misc, Malloc
575 
576 
577 device_t
578 find_root_device(int unit)
579 {
580 	device_t device = NULL;
581 
582 	while ((device = list_get_next_item(&sRootDevices, device)) != NULL) {
583 		if (device->unit <= unit)
584 			return device;
585 	}
586 
587 	return NULL;
588 }
589 
590 
591 driver_t *
592 __haiku_probe_miibus(device_t dev, driver_t *drivers[])
593 {
594 	driver_t *selected = NULL;
595 	int i, selectedResult = 0;
596 
597 	if (drivers == NULL)
598 		return NULL;
599 
600 	for (i = 0; drivers[i]; i++) {
601 		device_probe_t *probe = (device_probe_t *)
602 			resolve_method(drivers[i], "device_probe");
603 		if (probe) {
604 			int result = probe(dev);
605 			if (result >= 0) {
606 				if (selected == NULL || result < selectedResult) {
607 					selected = drivers[i];
608 					selectedResult = result;
609 					device_printf(dev, "Found MII: %s\n", selected->name);
610 				}
611 			}
612 		}
613 	}
614 
615 	return selected;
616 }
617 
618 
619 int
620 printf(const char *format, ...)
621 {
622 	char buf[256];
623 	va_list vl;
624 	va_start(vl, format);
625 	vsnprintf(buf, sizeof(buf), format, vl);
626 	va_end(vl);
627 	dprintf("%s", buf);
628 
629 	return 0;
630 }
631 
632 
633 int
634 resource_int_value(const char *name, int unit, const char *resname,
635 	int *result)
636 {
637 	/* no support for hints */
638 	return -1;
639 }
640 
641 
642 int
643 resource_disabled(const char *name, int unit)
644 {
645 	int error, value;
646 
647 	error = resource_int_value(name, unit, "disabled", &value);
648 	if (error)
649 	       return (0);
650 	return (value);
651 }
652