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.
6 * Distributed under the terms of the MIT License.
14 #include <KernelExport.h>
17 #include <util/BitUtils.h>
19 #include <compat/machine/resource.h>
20 #include <compat/dev/mii/mii.h>
21 #include <compat/sys/bus.h>
22 #include <compat/sys/malloc.h>
23 #include <compat/net/if_media.h>
25 #include <compat/dev/mii/miivar.h>
27 #include "compat_cpp.h"
30 spinlock __haiku_intr_spinlock
;
32 struct net_stack_module_info
*gStack
;
33 pci_module_info
*gPci
;
34 struct pci_x86_module_info
*gPCIx86
;
36 static struct list sRootDevices
;
39 // #pragma mark - private functions
43 init_device(device_t device
, driver_t
*driver
)
45 list_init_etc(&device
->children
, offsetof(struct device
, link
));
46 device
->unit
= sNextUnit
++;
48 if (driver
!= NULL
&& device_set_driver(device
, driver
) < 0)
56 new_device(driver_t
*driver
)
58 device_t dev
= malloc(sizeof(struct device
));
62 memset(dev
, 0, sizeof(struct device
));
64 if (init_device(dev
, driver
) == NULL
) {
78 while (get_next_image_info(B_SYSTEM_TEAM
, &cookie
, &info
) == B_OK
) {
79 if (((addr_t
)info
.text
<= (addr_t
)find_own_image
80 && (addr_t
)info
.text
+ (addr_t
)info
.text_size
81 > (addr_t
)find_own_image
)) {
82 // found our own image
87 return B_ENTRY_NOT_FOUND
;
91 static device_method_signature_t
92 resolve_method(driver_t
*driver
, const char *name
)
94 device_method_signature_t method
= NULL
;
97 for (i
= 0; method
== NULL
&& driver
->methods
[i
].name
!= NULL
; i
++) {
98 if (strcmp(driver
->methods
[i
].name
, name
) == 0)
99 method
= driver
->methods
[i
].method
;
106 // #pragma mark - Device
110 driver_printf(const char *format
, ...)
113 va_start(vl
, format
);
114 driver_vprintf(format
, vl
);
120 driver_vprintf_etc(const char *extra
, const char *format
, va_list vl
)
123 vsnprintf(buf
, sizeof(buf
), format
, vl
);
126 dprintf("[%s] (%s) %s", gDriverName
, extra
, buf
);
128 dprintf("[%s] %s", gDriverName
, buf
);
133 driver_vprintf(const char *format
, va_list vl
)
135 driver_vprintf_etc(NULL
, format
, vl
);
140 device_printf(device_t dev
, const char *format
, ...)
144 va_start(vl
, format
);
145 driver_vprintf_etc(dev
->device_name
, format
, vl
);
152 device_set_desc(device_t dev
, const char *desc
)
154 dev
->description
= desc
;
159 device_set_desc_copy(device_t dev
, const char *desc
)
161 dev
->description
= strdup(desc
);
162 dev
->flags
|= DEVICE_DESC_ALLOCED
;
167 device_get_desc(device_t dev
)
169 return dev
->description
;
174 device_get_parent(device_t dev
)
181 device_get_devclass(device_t dev
)
183 // TODO find out what to do
189 device_get_children(device_t dev
, device_t
**devlistp
, int *devcountp
)
192 device_t child
= NULL
;
196 while ((child
= list_get_next_item(&dev
->children
, child
)) != NULL
) {
200 list
= malloc(count
* sizeof(device_t
));
205 while ((child
= list_get_next_item(&dev
->children
, child
)) != NULL
) {
218 device_set_ivars(device_t dev
, void *ivars
)
225 device_get_ivars(device_t dev
)
232 device_get_name(device_t dev
)
237 return dev
->device_name
;
242 device_get_unit(device_t dev
)
249 device_get_nameunit(device_t dev
)
251 return dev
->nameunit
;
256 device_get_softc(device_t dev
)
263 device_get_flags(device_t dev
)
270 device_set_driver(device_t dev
, driver_t
*driver
)
272 device_method_signature_t method
= NULL
;
275 dev
->softc
= malloc(driver
->softc_size
);
276 if (dev
->softc
== NULL
)
279 memset(dev
->softc
, 0, driver
->softc_size
);
280 dev
->driver
= driver
;
282 for (i
= 0; method
== NULL
&& driver
->methods
[i
].name
!= NULL
; i
++) {
283 device_method_t
*mth
= &driver
->methods
[i
];
285 if (strcmp(mth
->name
, "device_probe") == 0)
286 dev
->methods
.probe
= (void *)mth
->method
;
287 else if (strcmp(mth
->name
, "device_attach") == 0)
288 dev
->methods
.attach
= (void *)mth
->method
;
289 else if (strcmp(mth
->name
, "device_detach") == 0)
290 dev
->methods
.detach
= (void *)mth
->method
;
291 else if (strcmp(mth
->name
, "device_suspend") == 0)
292 dev
->methods
.suspend
= (void *)mth
->method
;
293 else if (strcmp(mth
->name
, "device_resume") == 0)
294 dev
->methods
.resume
= (void *)mth
->method
;
295 else if (strcmp(mth
->name
, "device_shutdown") == 0)
296 dev
->methods
.shutdown
= (void *)mth
->method
;
297 else if (strcmp(mth
->name
, "miibus_readreg") == 0)
298 dev
->methods
.miibus_readreg
= (void *)mth
->method
;
299 else if (strcmp(mth
->name
, "miibus_writereg") == 0)
300 dev
->methods
.miibus_writereg
= (void *)mth
->method
;
301 else if (strcmp(mth
->name
, "miibus_statchg") == 0)
302 dev
->methods
.miibus_statchg
= (void *)mth
->method
;
303 else if (!strcmp(mth
->name
, "miibus_linkchg"))
304 dev
->methods
.miibus_linkchg
= (void *)mth
->method
;
305 else if (!strcmp(mth
->name
, "miibus_mediainit"))
306 dev
->methods
.miibus_mediainit
= (void *)mth
->method
;
314 device_is_alive(device_t device
)
316 return (device
->flags
& DEVICE_ATTACHED
) != 0;
321 device_add_child(device_t parent
, const char *name
, int unit
)
323 device_t child
= NULL
;
326 if (strcmp(name
, "miibus") == 0)
327 child
= new_device(&miibus_driver
);
329 // find matching driver structure
333 snprintf(symbol
, sizeof(symbol
), "__fbsd_%s_%s", name
,
334 parent
->driver
->name
);
335 if (get_image_symbol(find_own_image(), symbol
, B_SYMBOL_TYPE_DATA
,
336 (void **)&driver
) == B_OK
) {
337 child
= new_device(*driver
);
339 device_printf(parent
, "couldn't find symbol %s\n", symbol
);
342 child
= new_device(NULL
);
348 strlcpy(child
->device_name
, name
, sizeof(child
->device_name
));
350 child
->parent
= parent
;
352 if (parent
!= NULL
) {
353 list_add_item(&parent
->children
, child
);
354 child
->root
= parent
->root
;
356 if (sRootDevices
.link
.next
== NULL
)
357 list_init_etc(&sRootDevices
, offsetof(struct device
, link
));
358 list_add_item(&sRootDevices
, child
);
365 /*! Delete the child and all of its children. Detach as necessary.
368 device_delete_child(device_t parent
, device_t child
)
376 list_remove_item(&parent
->children
, child
);
378 list_remove_item(&sRootDevices
, child
);
380 // We differentiate from the FreeBSD logic here - it will first delete
381 // the children, and will then detach the device.
382 // This has the problem that you cannot safely call device_delete_child()
383 // as you don't know if one of the children deletes its own children this
384 // way when it is detached.
385 // Therefore, we'll detach first, and then delete whatever is left.
391 while ((child
= list_get_next_item(&parent
->children
, child
)) != NULL
) {
392 device_detach(child
);
396 status
= device_detach(parent
);
401 while ((child
= list_get_first_item(&parent
->children
)) != NULL
) {
402 device_delete_child(parent
, child
);
406 if (parent
->flags
& DEVICE_DESC_ALLOCED
)
407 free((char *)parent
->description
);
416 device_is_attached(device_t device
)
418 return (device
->flags
& DEVICE_ATTACHED
) != 0;
423 device_attach(device_t device
)
427 if (device
->driver
== NULL
428 || device
->methods
.attach
== NULL
)
431 result
= device
->methods
.attach(device
);
434 atomic_or(&device
->flags
, DEVICE_ATTACHED
);
437 result
= start_wlan(device
);
444 device_detach(device_t device
)
446 if (device
->driver
== NULL
)
449 if ((atomic_and(&device
->flags
, ~DEVICE_ATTACHED
) & DEVICE_ATTACHED
) != 0
450 && device
->methods
.detach
!= NULL
) {
453 result
= stop_wlan(device
);
455 atomic_or(&device
->flags
, DEVICE_ATTACHED
);
459 result
= device
->methods
.detach(device
);
461 atomic_or(&device
->flags
, DEVICE_ATTACHED
);
471 bus_generic_attach(device_t dev
)
473 device_t child
= NULL
;
475 while ((child
= list_get_next_item(&dev
->children
, child
)) != NULL
) {
476 if (child
->driver
== NULL
) {
477 driver_t
*driver
= __haiku_select_miibus_driver(child
);
478 if (driver
== NULL
) {
479 struct mii_attach_args
*ma
= device_get_ivars(child
);
481 device_printf(dev
, "No PHY module found (%x/%x)!\n",
482 MII_OUI(ma
->mii_id1
, ma
->mii_id2
), MII_MODEL(ma
->mii_id2
));
484 device_set_driver(child
, driver
);
486 child
->methods
.probe(child
);
488 if (child
->driver
!= NULL
) {
489 int result
= device_attach(child
);
500 bus_generic_detach(device_t device
)
502 device_t child
= NULL
;
504 if ((device
->flags
& DEVICE_ATTACHED
) == 0)
508 child
= list_get_next_item(&device
->children
, child
);
512 device_detach(child
);
519 // #pragma mark - Misc, Malloc
523 find_root_device(int unit
)
525 device_t device
= NULL
;
527 while ((device
= list_get_next_item(&sRootDevices
, device
)) != NULL
) {
528 if (device
->unit
<= unit
)
537 __haiku_probe_miibus(device_t dev
, driver_t
*drivers
[])
539 driver_t
*selected
= NULL
;
540 int i
, selectedResult
= 0;
545 for (i
= 0; drivers
[i
]; i
++) {
546 device_probe_t
*probe
= (device_probe_t
*)
547 resolve_method(drivers
[i
], "device_probe");
549 int result
= probe(dev
);
551 if (selected
== NULL
|| result
< selectedResult
) {
552 selected
= drivers
[i
];
553 selectedResult
= result
;
554 device_printf(dev
, "Found MII: %s\n", selected
->name
);
565 printf(const char *format
, ...)
569 va_start(vl
, format
);
570 vsnprintf(buf
, sizeof(buf
), format
, vl
);
586 for (; !(value
& 1); i
++)
594 resource_int_value(const char *name
, int unit
, const char *resname
,
597 /* no support for hints */
603 _kernel_malloc(size_t size
, int flags
)
605 // our kernel malloc() is insufficient, must handle M_WAIT
607 // According to the FreeBSD kernel malloc man page the allocator is expected
608 // to return power of two aligned addresses for allocations up to one page
609 // size. While it also states that this shouldn't be relied upon, at least
610 // bus_dmamem_alloc expects it and drivers may depend on it as well.
612 = memalign(size
>= PAGESIZE
? PAGESIZE
: next_power_of_2(size
), size
);
617 memset(ptr
, 0, size
);
624 _kernel_free(void *ptr
)
631 _kernel_contigmalloc(const char *file
, int line
, size_t size
, int flags
,
632 vm_paddr_t low
, vm_paddr_t high
, unsigned long alignment
,
633 unsigned long boundary
)
635 return _kernel_contigmalloc_cpp(file
, line
, size
, low
, high
,
636 alignment
, boundary
, (flags
& M_ZERO
) != 0, (flags
& M_NOWAIT
) != 0);
641 _kernel_contigfree(void *addr
, size_t size
)
643 delete_area(area_for(addr
));
648 pmap_kextract(vm_offset_t virtualAddress
)
650 physical_entry entry
;
651 status_t status
= get_memory_map((void *)virtualAddress
, 1, &entry
, 1);
653 panic("fbsd compat: get_memory_map failed for %p, error %08" B_PRIx32
654 "\n", (void *)virtualAddress
, status
);
657 return (vm_paddr_t
)entry
.address
;