summaryrefslogtreecommitdiffstats
path: root/bsd_eth_drivers/libbsdport/ifmedia.c
blob: cd7ebc021c2b5eadc9f5aacfff0e41cc6522faac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <rtems.h>
#define _KERNEL
#include <rtems/rtems_bsdnet.h>
#include <rtems/rtems_bsdnet_internal.h>

#include <bsp/rtems_verscheck.h>

#if RTEMS_REV_AT_LEAST(4,8,99) && !RTEMS_REV_AT_LEAST(4,10,99)
#include <rtems/bsd/sys/queue.h>
#else
#include <sys/queue.h>
#endif

#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_media.h>
#include <rtems/rtems_mii_ioctl.h>

void
ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
             ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
{
	ifm->ifm_mask  = dontcare_mask;
	ifm->ifm_media = 0;
	ifm->ifm_cur   = 0;
	ifm->ifm_list.lh_first = NULL;
	ifm->ifm_change = change_callback;
	ifm->ifm_status = status_callback;
}

void
ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux)
{
struct ifmedia_entry *ifmen, *ifmep, *ifme;
	if ( ( ifme = malloc(sizeof(*ifme), M_DEVBUF, M_NOWAIT) ) ) {
		ifme->ifm_media = mword;
		ifme->ifm_data  = data;
		ifme->ifm_aux   = aux;
		for ( ifmep = LIST_FIRST(&ifm->ifm_list); ifmep; ifmep = ifmen ) {
			if ( !(ifmen = LIST_NEXT(ifmep, ifm_list)) )
				break;
		}
		if ( ifmep )
			LIST_INSERT_AFTER(ifmep, ifme, ifm_list);
		else
			LIST_INSERT_HEAD( &ifm->ifm_list, ifme, ifm_list);
	}
}

void
ifmedia_removeall(struct ifmedia *ifm)
{
struct ifmedia_entry *ifmen, *ifmep;
		for ( ifmep = LIST_FIRST(&ifm->ifm_list); ifmep; ifmep = ifmen ) {
			ifmen = LIST_NEXT(ifmep, ifm_list);
			free(ifmep, M_DEVBUF);
		}
}

int
ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm, u_long cmd)
{
int               rval = 0;
struct ifmediareq ifmr;
	if ( SIOCGIFMEDIA == cmd ) {
		if ( !ifm->ifm_status )
			return ENOTSUP;
		ifm->ifm_status(ifp, &ifmr);
		if ( ! (IFM_AVALID & ifmr.ifm_status) )
			return EINVAL;
		/* translate */
		ifr->ifr_media = ifmr.ifm_active;
		if ( IFM_ACTIVE & ifmr.ifm_status )
			ifr->ifr_media |= IFM_LINK_OK;
		/* no way to determine if autoneg is forcefully disabled
		 * from ifmr :-(
		 * Look at current ifm_media for now.
		 */
		if ( IFM_SUBTYPE(ifm->ifm_media) != IFM_AUTO )
			ifr->ifr_media |= IFM_ANEG_DIS;
	} else {
		if ( !ifm->ifm_change )
			return ENOTSUP;
		ifm->ifm_media = ifr->ifr_media;
		rval = ifm->ifm_change(ifp);
	}
	return rval;
}

void
ifmedia_set(struct ifmedia *ifm, int mword)
{
	ifm->ifm_media = mword;
	/* cannot invoke the ifm_change callback because we have
	 * no ifp here.
	 */
}