if_ed_rtl80x9.c revision 257176
1139825Simp/*-
282899Sjake * Copyright (c) 2003, David Madole
382899Sjake * All rights reserved.
482899Sjake * Copyright (c) 2005, M. Warner Losh.
580708Sjake * All rights reserved.
682899Sjake *
782899Sjake * Redistribution and use in source and binary forms, with or without
882899Sjake * modification, are permitted provided that the following conditions
982899Sjake * are met:
1082899Sjake * 1. Redistributions of source code must retain the above copyright
1180708Sjake *    notice unmodified, this list of conditions, and the following
1282899Sjake *    disclaimer.
1382899Sjake * 2. Redistributions in binary form must reproduce the above copyright
1482899Sjake *    notice, this list of conditions and the following disclaimer in the
1580708Sjake *    documentation and/or other materials provided with the distribution.
1682899Sjake *
1782899Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1882899Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1982899Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2082899Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2182899Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2282899Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2382899Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2482899Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2582899Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2682899Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2780708Sjake * SUCH DAMAGE.
2880708Sjake *
2980708Sjake * Based on patches subitted by: David Madole, edited by M. Warner Losh.
3080708Sjake */
3180708Sjake
3280708Sjake
3380709Sjake#include <sys/cdefs.h>
3480709Sjake__FBSDID("$FreeBSD: head/sys/dev/ed/if_ed_rtl80x9.c 257176 2013-10-26 17:58:36Z glebius $");
3580709Sjake
3680709Sjake#include "opt_ed.h"
3780709Sjake
3880709Sjake#include <sys/param.h>
3982004Sjake#include <sys/systm.h>
4080709Sjake#include <sys/sockio.h>
41131952Smarcel#include <sys/mbuf.h>
4280709Sjake#include <sys/kernel.h>
43115970Sjake#include <sys/socket.h>
4480709Sjake#include <sys/syslog.h>
4580709Sjake
4680709Sjake#include <sys/bus.h>
4786525Sjake
48131952Smarcel#include <machine/bus.h>
49131952Smarcel#include <sys/rman.h>
5086525Sjake#include <machine/resource.h>
5180709Sjake
52131952Smarcel#include <net/ethernet.h>
53131952Smarcel#include <net/if.h>
5480709Sjake#include <net/if_var.h>
5580709Sjake#include <net/if_arp.h>
5680709Sjake#include <net/if_dl.h>
5780709Sjake#include <net/if_mib.h>
5880709Sjake#include <net/if_media.h>
5980709Sjake
6080709Sjake#include <net/bpf.h>
6180709Sjake
6280709Sjake#include <dev/ed/if_edreg.h>
6380709Sjake#include <dev/ed/if_edvar.h>
6480709Sjake#include <dev/ed/rtl80x9reg.h>
6580709Sjake
6680709Sjakestatic int	ed_rtl_set_media(struct ifnet *ifp);
6780709Sjakestatic void	ed_rtl_get_media(struct ifnet *ifp, struct ifmediareq *);
6880709Sjake
6980708Sjakestatic int
70ed_rtl80x9_media_ioctl(struct ed_softc *sc, struct ifreq *ifr, u_long command)
71{
72	return (ifmedia_ioctl(sc->ifp, ifr, &sc->ifmedia, command));
73}
74
75int
76ed_probe_RTL80x9(device_t dev, int port_rid, int flags)
77{
78	struct ed_softc *sc = device_get_softc(dev);
79	char *ts;
80	int error;
81
82	if ((error = ed_alloc_port(dev, port_rid, ED_NOVELL_IO_PORTS)))
83		return (error);
84
85	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
86	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
87
88	if (ed_nic_inb(sc, ED_P0_CR) & (ED_CR_PS0 | ED_CR_PS1))
89		ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
90
91	if (ed_nic_inb(sc, ED_RTL80X9_80X9ID0) != ED_RTL80X9_ID0)
92		return (ENXIO);
93
94	switch (ed_nic_inb(sc, ED_RTL80X9_80X9ID1)) {
95	case ED_RTL8019_ID1:
96		sc->chip_type = ED_CHIP_TYPE_RTL8019;
97		ts = "RTL8019";
98		break;
99	case ED_RTL8029_ID1:
100		sc->chip_type = ED_CHIP_TYPE_RTL8029;
101		ts = "RTL8029";
102		break;
103	default:
104		return (ENXIO);
105	}
106
107	if ((error = ed_probe_Novell_generic(dev, flags)))
108		return (error);
109
110	sc->type_str = ts;
111	sc->sc_media_ioctl = &ed_rtl80x9_media_ioctl;
112	ifmedia_init(&sc->ifmedia, 0, ed_rtl_set_media, ed_rtl_get_media);
113
114	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, 0);
115	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
116	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_2, 0, 0);
117	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
118	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
119
120	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_3 | ED_CR_STP);
121
122	switch (ed_nic_inb(sc, ED_RTL80X9_CONFIG2) & ED_RTL80X9_CF2_MEDIA) {
123	case ED_RTL80X9_CF2_AUTO:
124		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_AUTO);
125		break;
126	case ED_RTL80X9_CF2_10_5:
127		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_5);
128		break;
129	case ED_RTL80X9_CF2_10_2:
130		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_2);
131		break;
132	case ED_RTL80X9_CF2_10_T:
133		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_T |
134		    ((ed_nic_inb(sc, ED_RTL80X9_CONFIG3)
135		    & ED_RTL80X9_CF3_FUDUP) ? IFM_FDX : 0));
136		break;
137	}
138	return (0);
139}
140
141static int
142ed_rtl_set_media(struct ifnet *ifp)
143{
144	struct ed_softc *sc;
145
146	sc = ifp->if_softc;
147	ED_LOCK(sc);
148	ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_3
149		| (ed_nic_inb(sc, ED_P0_CR) & (ED_CR_STA | ED_CR_STP)));
150
151	switch(IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) {
152	case IFM_10_T:
153		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_10_T
154			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
155				& ~ED_RTL80X9_CF2_MEDIA));
156		break;
157	case IFM_10_2:
158		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_10_2
159			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
160				& ~ED_RTL80X9_CF2_MEDIA));
161		break;
162	case IFM_10_5:
163		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_10_5
164			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
165				& ~ED_RTL80X9_CF2_MEDIA));
166		break;
167	case IFM_AUTO:
168		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_AUTO
169			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
170				& ~ED_RTL80X9_CF2_MEDIA));
171		break;
172	}
173	ed_nic_outb(sc, ED_RTL80X9_CONFIG3,
174		(sc->ifmedia.ifm_cur->ifm_media & IFM_FDX) ?
175		(ed_nic_inb(sc, ED_RTL80X9_CONFIG3) | ED_RTL80X9_CF3_FUDUP) :
176		(ed_nic_inb(sc, ED_RTL80X9_CONFIG3) & ~ED_RTL80X9_CF3_FUDUP));
177
178	ED_UNLOCK(sc);
179	return (0);
180}
181
182static void
183ed_rtl_get_media(struct ifnet *ifp, struct ifmediareq *imr)
184{
185	struct ed_softc *sc;
186
187	sc = ifp->if_softc;
188	imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media;
189
190
191	if (IFM_SUBTYPE(imr->ifm_active) == IFM_AUTO) {
192		ED_LOCK(sc);
193		ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_3 |
194			(ed_nic_inb(sc, ED_P0_CR) & (ED_CR_STA | ED_CR_STP)));
195
196		switch (ed_nic_inb(sc, ED_RTL80X9_CONFIG0)
197				& (sc->chip_type == ED_CHIP_TYPE_RTL8029 ? ED_RTL80X9_CF0_BNC
198				: (ED_RTL80X9_CF0_AUI | ED_RTL80X9_CF0_BNC))) {
199		case ED_RTL80X9_CF0_BNC:
200			imr->ifm_active |= IFM_10_2;
201			break;
202		case ED_RTL80X9_CF0_AUI:
203			imr->ifm_active |= IFM_10_5;
204			break;
205		default:
206			imr->ifm_active |= IFM_10_T;
207			break;
208		}
209		ED_UNLOCK(sc);
210	}
211	imr->ifm_status = 0;
212}
213
214