xref: /haiku/src/add-ons/kernel/drivers/network/ether/usb_asix/AX88178Device.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1*cbe0a0c4SAugustin Cavalier /*
2*cbe0a0c4SAugustin Cavalier  *	ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
3*cbe0a0c4SAugustin Cavalier  *	Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
4*cbe0a0c4SAugustin Cavalier  *	Distributed under the terms of the MIT license.
5*cbe0a0c4SAugustin Cavalier  *
6*cbe0a0c4SAugustin Cavalier  *	Heavily based on code of the
7*cbe0a0c4SAugustin Cavalier  *	Driver for USB Ethernet Control Model devices
8*cbe0a0c4SAugustin Cavalier  *	Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
9*cbe0a0c4SAugustin Cavalier  *	Distributed under the terms of the MIT license.
10*cbe0a0c4SAugustin Cavalier  *
11*cbe0a0c4SAugustin Cavalier  */
12*cbe0a0c4SAugustin Cavalier 
13*cbe0a0c4SAugustin Cavalier 
14*cbe0a0c4SAugustin Cavalier #include "AX88178Device.h"
15*cbe0a0c4SAugustin Cavalier 
16*cbe0a0c4SAugustin Cavalier #include <net/if_media.h>
17*cbe0a0c4SAugustin Cavalier 
18*cbe0a0c4SAugustin Cavalier #include "ASIXVendorRequests.h"
19*cbe0a0c4SAugustin Cavalier #include "Settings.h"
20*cbe0a0c4SAugustin Cavalier 
21*cbe0a0c4SAugustin Cavalier 
22*cbe0a0c4SAugustin Cavalier // Most of vendor requests for all supported chip types use the same
23*cbe0a0c4SAugustin Cavalier // constants (see ASIXVendorRequests.h) but the layout of request data
24*cbe0a0c4SAugustin Cavalier // may be slightly diferrent for specific chip type. Below is a quick
25*cbe0a0c4SAugustin Cavalier // reference for AX88178 vendor requests data layout.
26*cbe0a0c4SAugustin Cavalier 
27*cbe0a0c4SAugustin Cavalier // READ_RXTX_SRAM,		//C002_AA0B_0C00_0800 Rx/Tx SRAM Read
28*cbe0a0c4SAugustin Cavalier // WRITE_RXTX_SRAM,		//4003_AA0B_0C00_0800 Rx/Tx SRAM Write
29*cbe0a0c4SAugustin Cavalier // SW_MII_OP,			//4006_0000_0000_0000 SW Serial Management Control
30*cbe0a0c4SAugustin Cavalier // READ_MII,			//c007_aa00_cc00_0200 PHY Read
31*cbe0a0c4SAugustin Cavalier // WRITE_MII,			//4008_aa00_cc00_0200 PHY Write
32*cbe0a0c4SAugustin Cavalier // READ_MII_STATUS,		//c009_0000_0000_0100 Serial Management Status
33*cbe0a0c4SAugustin Cavalier // HW_MII_OP,			//400a_0000_0000_0000 HW Serial Management Control
34*cbe0a0c4SAugustin Cavalier // READ_SROM,			//C00B_AA00_0000_0200 SROM Read
35*cbe0a0c4SAugustin Cavalier // WRITE_SROM,			//400C_AA00_CCDD_0000 SROM Write
36*cbe0a0c4SAugustin Cavalier // WRITE_SROM_ENABLE,	//400D_0000_0000_0000 SROM Write Enable
37*cbe0a0c4SAugustin Cavalier // WRITE_SROM_DISABLE,	//400E_0000_0000_0000 SROM Write Disable
38*cbe0a0c4SAugustin Cavalier // READ_RX_CONTROL,		//C00F_0000_0000_0200 Read Rx Control
39*cbe0a0c4SAugustin Cavalier // WRITE_RX_CONTROL,	//4010_AABB_0000_0000 Write Rx Control
40*cbe0a0c4SAugustin Cavalier // READ_IPGS,			//C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register
41*cbe0a0c4SAugustin Cavalier // WRITE_IPGS,			//4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register
42*cbe0a0c4SAugustin Cavalier // READ_NODEID,			//C013_0000_0000_0600 Read Node ID
43*cbe0a0c4SAugustin Cavalier // WRITE_NODEID,		//4014_0000_0000_0600 Write Node ID
44*cbe0a0c4SAugustin Cavalier // READ_MF_ARRAY,		//C015_0000_0000_0800 Read Multicast Filter Array
45*cbe0a0c4SAugustin Cavalier // WRITE_MF_ARRAY,		//4016_0000_0000_0800 Write Multicast Filter Array
46*cbe0a0c4SAugustin Cavalier // READ_TEST,			//4017_AA00_0000_0000 Write Test Register
47*cbe0a0c4SAugustin Cavalier // READ_PHYID,			//C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address
48*cbe0a0c4SAugustin Cavalier // READ_MEDIUM_STATUS,	//C01A_0000_0000_0200 Read Medium Status
49*cbe0a0c4SAugustin Cavalier // WRITE_MEDIUM_MODE,	//401B_AABB_0000_0000 Write Medium Mode Register
50*cbe0a0c4SAugustin Cavalier // GET_MONITOR_MODE,	//C01C_0000_0000_0100 Read Monitor Mode Status
51*cbe0a0c4SAugustin Cavalier // SET_MONITOR_MODE,	//401D_AA00_0000_0000 Write Monitor Mode Register
52*cbe0a0c4SAugustin Cavalier // READ_GPIOS,			//C01E_0000_0000_0100 Read GPIOs Status
53*cbe0a0c4SAugustin Cavalier // WRITE_GPIOS,			//401F_AA00_0000_0000 Write GPIOs
54*cbe0a0c4SAugustin Cavalier // WRITE_SOFT_RESET,	//4020_AA00_0000_0000 Write Software Reset
55*cbe0a0c4SAugustin Cavalier // READ_MIIS_IF_STATE,	//C021_AA00_0000_0100 Read MII/GMII/RGMII Iface Status
56*cbe0a0c4SAugustin Cavalier // WRITE_MIIS_IF_STATE,	//4022_AA00_0000_0000 Write MII/GMII/RGMII Iface Control
57*cbe0a0c4SAugustin Cavalier 
58*cbe0a0c4SAugustin Cavalier // RX Control Register bits
59*cbe0a0c4SAugustin Cavalier // RXCTL_PROMISCUOUS,	// forward all frames up to the host
60*cbe0a0c4SAugustin Cavalier // RXCTL_ALL_MULTICAT,	// forward all multicast frames up to the host
61*cbe0a0c4SAugustin Cavalier // RXCTL_SEP,			// forward frames with CRC error up to the host
62*cbe0a0c4SAugustin Cavalier // RXCTL_BROADCAST,		// forward broadcast frames up to the host
63*cbe0a0c4SAugustin Cavalier // RXCTL_MULTICAST,		// forward multicast frames that are
64*cbe0a0c4SAugustin Cavalier //							matching to multicast filter up to the host
65*cbe0a0c4SAugustin Cavalier // RXCTL_AP,			// forward unicast frames that are matching
66*cbe0a0c4SAugustin Cavalier //							to multicast filter up to the host
67*cbe0a0c4SAugustin Cavalier // RXCTL_START,			// ethernet MAC start operating
68*cbe0a0c4SAugustin Cavalier // RXCTL_USB_MFB,		// Max Frame Burst TX on USB
69*cbe0a0c4SAugustin Cavalier 
70*cbe0a0c4SAugustin Cavalier 
71*cbe0a0c4SAugustin Cavalier // PHY IDs request answer data layout
72*cbe0a0c4SAugustin Cavalier struct AX88178_PhyIDs {
73*cbe0a0c4SAugustin Cavalier 	uint8 SecPhyID;
74*cbe0a0c4SAugustin Cavalier 	uint8 PriPhyID2;
75*cbe0a0c4SAugustin Cavalier } _PACKED;
76*cbe0a0c4SAugustin Cavalier 
77*cbe0a0c4SAugustin Cavalier 
78*cbe0a0c4SAugustin Cavalier // Medium state bits
79*cbe0a0c4SAugustin Cavalier enum AX88178_MediumState {
80*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_GM		= 0x0001,
81*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_FD		= 0x0002,
82*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_AC		= 0x0004, // must be always set
83*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_ENCK	= 0x0008,
84*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_RFC	= 0x0010,
85*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_TFC	= 0x0020,
86*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_JFE	= 0x0040,
87*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_PF_ON	= 0x0080,
88*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_PF_OFF	= 0x0000,
89*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_RE	   	= 0x0100,
90*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_PS_100	= 0x0200,
91*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_PS_10 	= 0x0000,
92*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_SBP1  	= 0x0800,
93*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_SBP0  	= 0x0000,
94*cbe0a0c4SAugustin Cavalier 	MEDIUM_STATE_SM_ON 	= 0x1000
95*cbe0a0c4SAugustin Cavalier };
96*cbe0a0c4SAugustin Cavalier 
97*cbe0a0c4SAugustin Cavalier 
98*cbe0a0c4SAugustin Cavalier // Monitor Mode bits
99*cbe0a0c4SAugustin Cavalier enum AX88178_MonitorMode {
100*cbe0a0c4SAugustin Cavalier 	MONITOR_MODE_MOM	= 0x01,
101*cbe0a0c4SAugustin Cavalier 	MONITOR_MODE_RWLU	= 0x02,
102*cbe0a0c4SAugustin Cavalier 	MONITOR_MODE_RWMP	= 0x04,
103*cbe0a0c4SAugustin Cavalier 	MONITOR_MODE_US 	= 0x10
104*cbe0a0c4SAugustin Cavalier };
105*cbe0a0c4SAugustin Cavalier 
106*cbe0a0c4SAugustin Cavalier 
107*cbe0a0c4SAugustin Cavalier // General Purpose I/O Register
108*cbe0a0c4SAugustin Cavalier enum AX88178_GPIO {
109*cbe0a0c4SAugustin Cavalier 	GPIO_OO_0EN	= 0x01,
110*cbe0a0c4SAugustin Cavalier 	GPIO_IO_0	= 0x02,
111*cbe0a0c4SAugustin Cavalier 	GPIO_OO_1EN	= 0x04,
112*cbe0a0c4SAugustin Cavalier 	GPIO_IO_1	= 0x08,
113*cbe0a0c4SAugustin Cavalier 	GPIO_OO_2EN	= 0x10,
114*cbe0a0c4SAugustin Cavalier 	GPIO_IO_2	= 0x20,
115*cbe0a0c4SAugustin Cavalier 	GPIO_RSE	= 0x80
116*cbe0a0c4SAugustin Cavalier };
117*cbe0a0c4SAugustin Cavalier 
118*cbe0a0c4SAugustin Cavalier 
119*cbe0a0c4SAugustin Cavalier // Software Reset Register bits
120*cbe0a0c4SAugustin Cavalier enum AX88178_SoftwareReset {
121*cbe0a0c4SAugustin Cavalier 	SW_RESET_RR		= 0x01,
122*cbe0a0c4SAugustin Cavalier 	SW_RESET_RT		= 0x02,
123*cbe0a0c4SAugustin Cavalier 	SW_RESET_PRTE	= 0x04,
124*cbe0a0c4SAugustin Cavalier 	SW_RESET_PRL	= 0x08,
125*cbe0a0c4SAugustin Cavalier 	SW_RESET_BZ		= 0x10,
126*cbe0a0c4SAugustin Cavalier 	SW_RESET_BIT6	= 0x40 // always set to 1
127*cbe0a0c4SAugustin Cavalier };
128*cbe0a0c4SAugustin Cavalier 
129*cbe0a0c4SAugustin Cavalier 
130*cbe0a0c4SAugustin Cavalier // MII/GMII/RGMII Interface Conttrol
131*cbe0a0c4SAugustin Cavalier enum AX88178_MIISInterfaceStatus {
132*cbe0a0c4SAugustin Cavalier 	MIIS_IF_STATE_DM	= 0x01,
133*cbe0a0c4SAugustin Cavalier 	MIIS_IF_STATE_RB	= 0x02
134*cbe0a0c4SAugustin Cavalier };
135*cbe0a0c4SAugustin Cavalier 
136*cbe0a0c4SAugustin Cavalier 
137*cbe0a0c4SAugustin Cavalier // Notification data layout
138*cbe0a0c4SAugustin Cavalier struct AX88178_Notify {
139*cbe0a0c4SAugustin Cavalier 	uint8  btA1;
140*cbe0a0c4SAugustin Cavalier 	uint8  bt01;
141*cbe0a0c4SAugustin Cavalier 	uint8  btBB; // AX88178_BBState below
142*cbe0a0c4SAugustin Cavalier 	uint8  bt03;
143*cbe0a0c4SAugustin Cavalier 	uint16 regCCDD;
144*cbe0a0c4SAugustin Cavalier 	uint16 regEEFF;
145*cbe0a0c4SAugustin Cavalier } _PACKED;
146*cbe0a0c4SAugustin Cavalier 
147*cbe0a0c4SAugustin Cavalier 
148*cbe0a0c4SAugustin Cavalier // Link-State bits
149*cbe0a0c4SAugustin Cavalier enum AX88178_BBState {
150*cbe0a0c4SAugustin Cavalier 	LINK_STATE_PPLS		= 0x01,
151*cbe0a0c4SAugustin Cavalier 	LINK_STATE_SPLS		= 0x02,
152*cbe0a0c4SAugustin Cavalier 	LINK_STATE_FLE		= 0x04,
153*cbe0a0c4SAugustin Cavalier 	LINK_STATE_MDINT	= 0x08
154*cbe0a0c4SAugustin Cavalier };
155*cbe0a0c4SAugustin Cavalier 
156*cbe0a0c4SAugustin Cavalier 
157*cbe0a0c4SAugustin Cavalier const uint16 maxFrameSize = 1536;
158*cbe0a0c4SAugustin Cavalier 
159*cbe0a0c4SAugustin Cavalier 
AX88178Device(usb_device device,DeviceInfo & deviceInfo)160*cbe0a0c4SAugustin Cavalier AX88178Device::AX88178Device(usb_device device, DeviceInfo& deviceInfo)
161*cbe0a0c4SAugustin Cavalier 	:
162*cbe0a0c4SAugustin Cavalier 	ASIXDevice(device, deviceInfo)
163*cbe0a0c4SAugustin Cavalier {
164*cbe0a0c4SAugustin Cavalier 	fStatus = InitDevice();
165*cbe0a0c4SAugustin Cavalier }
166*cbe0a0c4SAugustin Cavalier 
167*cbe0a0c4SAugustin Cavalier 
168*cbe0a0c4SAugustin Cavalier status_t
InitDevice()169*cbe0a0c4SAugustin Cavalier AX88178Device::InitDevice()
170*cbe0a0c4SAugustin Cavalier {
171*cbe0a0c4SAugustin Cavalier 	fFrameSize = maxFrameSize;
172*cbe0a0c4SAugustin Cavalier 	fUseTRXHeader = true;
173*cbe0a0c4SAugustin Cavalier 
174*cbe0a0c4SAugustin Cavalier 	fReadNodeIDRequest = READ_NODEID;
175*cbe0a0c4SAugustin Cavalier 
176*cbe0a0c4SAugustin Cavalier 	fNotifyBufferLength = sizeof(AX88178_Notify);
177*cbe0a0c4SAugustin Cavalier 	fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength);
178*cbe0a0c4SAugustin Cavalier 	if (fNotifyBuffer == NULL) {
179*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of allocating memory for notify buffer.\n");
180*cbe0a0c4SAugustin Cavalier 		return B_NO_MEMORY;
181*cbe0a0c4SAugustin Cavalier 	}
182*cbe0a0c4SAugustin Cavalier 
183*cbe0a0c4SAugustin Cavalier 	TRACE_RET(B_OK);
184*cbe0a0c4SAugustin Cavalier 	return B_OK;
185*cbe0a0c4SAugustin Cavalier }
186*cbe0a0c4SAugustin Cavalier 
187*cbe0a0c4SAugustin Cavalier 
188*cbe0a0c4SAugustin Cavalier status_t
SetupDevice(bool deviceReplugged)189*cbe0a0c4SAugustin Cavalier AX88178Device::SetupDevice(bool deviceReplugged)
190*cbe0a0c4SAugustin Cavalier {
191*cbe0a0c4SAugustin Cavalier 	status_t result = ASIXDevice::SetupDevice(deviceReplugged);
192*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
193*cbe0a0c4SAugustin Cavalier 		return result;
194*cbe0a0c4SAugustin Cavalier 	}
195*cbe0a0c4SAugustin Cavalier 
196*cbe0a0c4SAugustin Cavalier 	result = fMII.Init(fDevice);
197*cbe0a0c4SAugustin Cavalier 
198*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
199*cbe0a0c4SAugustin Cavalier 		return result;
200*cbe0a0c4SAugustin Cavalier 	}
201*cbe0a0c4SAugustin Cavalier 
202*cbe0a0c4SAugustin Cavalier 	size_t actualLength = 0;
203*cbe0a0c4SAugustin Cavalier 	// get the "magic" word from EEPROM
204*cbe0a0c4SAugustin Cavalier 	result = gUSBModule->send_request(fDevice,
205*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SROM_ENABLE,
206*cbe0a0c4SAugustin Cavalier 		0, 0, 0, 0, &actualLength);
207*cbe0a0c4SAugustin Cavalier 
208*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
209*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of enabling SROM access:%#010x\n", result);
210*cbe0a0c4SAugustin Cavalier 		return result;
211*cbe0a0c4SAugustin Cavalier 	}
212*cbe0a0c4SAugustin Cavalier 
213*cbe0a0c4SAugustin Cavalier 	uint16 eepromData = 0;
214*cbe0a0c4SAugustin Cavalier 	status_t op_result = gUSBModule->send_request(fDevice,
215*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, READ_SROM,
216*cbe0a0c4SAugustin Cavalier 		0x17, 0, sizeof(eepromData), &eepromData, &actualLength);
217*cbe0a0c4SAugustin Cavalier 
218*cbe0a0c4SAugustin Cavalier 	if (op_result != B_OK) {
219*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of reading SROM data:%#010x\n", result);
220*cbe0a0c4SAugustin Cavalier 	}
221*cbe0a0c4SAugustin Cavalier 
222*cbe0a0c4SAugustin Cavalier 	if (actualLength != sizeof(eepromData)) {
223*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Mismatch of reading SROM data."
224*cbe0a0c4SAugustin Cavalier 			"Read %d bytes instead of %d\n", actualLength, sizeof(eepromData));
225*cbe0a0c4SAugustin Cavalier 	}
226*cbe0a0c4SAugustin Cavalier 
227*cbe0a0c4SAugustin Cavalier 	result = gUSBModule->send_request(fDevice,
228*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SROM_DISABLE,
229*cbe0a0c4SAugustin Cavalier 		0, 0, 0, 0, &actualLength);
230*cbe0a0c4SAugustin Cavalier 
231*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
232*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of disabling SROM access: %#010x\n", result);
233*cbe0a0c4SAugustin Cavalier 		return result;
234*cbe0a0c4SAugustin Cavalier 	}
235*cbe0a0c4SAugustin Cavalier 
236*cbe0a0c4SAugustin Cavalier 	if (op_result != B_OK) {
237*cbe0a0c4SAugustin Cavalier 		return op_result;
238*cbe0a0c4SAugustin Cavalier 	}
239*cbe0a0c4SAugustin Cavalier 
240*cbe0a0c4SAugustin Cavalier 	// some shaman's dances with GPIO
241*cbe0a0c4SAugustin Cavalier 	struct GPIOData {
242*cbe0a0c4SAugustin Cavalier 		bigtime_t	delay;
243*cbe0a0c4SAugustin Cavalier 		uint16 		value;
244*cbe0a0c4SAugustin Cavalier 	} GPIOCommands[] = {
245*cbe0a0c4SAugustin Cavalier 		// eeprom bit 8 is off
246*cbe0a0c4SAugustin Cavalier 		{ 40000  , GPIO_OO_1EN | GPIO_IO_1 | GPIO_RSE                },
247*cbe0a0c4SAugustin Cavalier 		{ 30000  , GPIO_OO_2EN | GPIO_IO_2 | GPIO_OO_1EN | GPIO_IO_1 },
248*cbe0a0c4SAugustin Cavalier 		{ 300000 , GPIO_OO_2EN |             GPIO_OO_1EN | GPIO_IO_1 },
249*cbe0a0c4SAugustin Cavalier 		{ 30000  , GPIO_OO_2EN | GPIO_IO_2 | GPIO_OO_1EN | GPIO_IO_1 },
250*cbe0a0c4SAugustin Cavalier 		// eeprom bit 8 is on
251*cbe0a0c4SAugustin Cavalier 		{ 40000  , GPIO_OO_1EN | GPIO_IO_1 | GPIO_RSE },
252*cbe0a0c4SAugustin Cavalier 		{ 30000  , GPIO_OO_1EN                        },
253*cbe0a0c4SAugustin Cavalier 		{ 30000  , GPIO_OO_1EN | GPIO_IO_1            },
254*cbe0a0c4SAugustin Cavalier 	};
255*cbe0a0c4SAugustin Cavalier 
256*cbe0a0c4SAugustin Cavalier 	bool bCase8 = (eepromData >> 8) != 1;
257*cbe0a0c4SAugustin Cavalier 	size_t from = bCase8 ? 0 : 4;
258*cbe0a0c4SAugustin Cavalier 	size_t to   = bCase8 ? 3 : 6;
259*cbe0a0c4SAugustin Cavalier 
260*cbe0a0c4SAugustin Cavalier 	for (size_t i = from; i <= to; i++) {
261*cbe0a0c4SAugustin Cavalier 		result = gUSBModule->send_request(fDevice,
262*cbe0a0c4SAugustin Cavalier 			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_GPIOS,
263*cbe0a0c4SAugustin Cavalier 			GPIOCommands[i].value, 0, 0, 0, &actualLength);
264*cbe0a0c4SAugustin Cavalier 
265*cbe0a0c4SAugustin Cavalier 		snooze(GPIOCommands[i].delay);
266*cbe0a0c4SAugustin Cavalier 
267*cbe0a0c4SAugustin Cavalier 		if (result != B_OK) {
268*cbe0a0c4SAugustin Cavalier 			TRACE_ALWAYS("Error of GPIO setup command %d:[%#04x]: %#010x\n",
269*cbe0a0c4SAugustin Cavalier 				i, GPIOCommands[i].value, result);
270*cbe0a0c4SAugustin Cavalier 			return result;
271*cbe0a0c4SAugustin Cavalier 		}
272*cbe0a0c4SAugustin Cavalier 	}
273*cbe0a0c4SAugustin Cavalier 
274*cbe0a0c4SAugustin Cavalier 	uint8 uSWReset = 0;
275*cbe0a0c4SAugustin Cavalier 	// finally a bit of exercises for SW reset register...
276*cbe0a0c4SAugustin Cavalier 	result = gUSBModule->send_request(fDevice,
277*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SOFT_RESET,
278*cbe0a0c4SAugustin Cavalier 		uSWReset, 0, 0, 0, &actualLength);
279*cbe0a0c4SAugustin Cavalier 
280*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
281*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result);
282*cbe0a0c4SAugustin Cavalier 		return result;
283*cbe0a0c4SAugustin Cavalier 	}
284*cbe0a0c4SAugustin Cavalier 
285*cbe0a0c4SAugustin Cavalier 	snooze(150000);
286*cbe0a0c4SAugustin Cavalier 
287*cbe0a0c4SAugustin Cavalier 	uSWReset = SW_RESET_PRL | SW_RESET_BIT6;
288*cbe0a0c4SAugustin Cavalier 	result = gUSBModule->send_request(fDevice,
289*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SOFT_RESET,
290*cbe0a0c4SAugustin Cavalier 		uSWReset, 0, 0, 0, &actualLength);
291*cbe0a0c4SAugustin Cavalier 
292*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
293*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result);
294*cbe0a0c4SAugustin Cavalier 		return result;
295*cbe0a0c4SAugustin Cavalier 	}
296*cbe0a0c4SAugustin Cavalier 
297*cbe0a0c4SAugustin Cavalier 	snooze(150000);
298*cbe0a0c4SAugustin Cavalier 
299*cbe0a0c4SAugustin Cavalier 	result = WriteRXControlRegister(0);
300*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
301*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
302*cbe0a0c4SAugustin Cavalier 		return result;
303*cbe0a0c4SAugustin Cavalier 	}
304*cbe0a0c4SAugustin Cavalier 
305*cbe0a0c4SAugustin Cavalier 	result = fMII.SetupPHY();
306*cbe0a0c4SAugustin Cavalier 
307*cbe0a0c4SAugustin Cavalier 	TRACE_RET(result);
308*cbe0a0c4SAugustin Cavalier 	return result;
309*cbe0a0c4SAugustin Cavalier }
310*cbe0a0c4SAugustin Cavalier 
311*cbe0a0c4SAugustin Cavalier 
312*cbe0a0c4SAugustin Cavalier status_t
StartDevice()313*cbe0a0c4SAugustin Cavalier AX88178Device::StartDevice()
314*cbe0a0c4SAugustin Cavalier {
315*cbe0a0c4SAugustin Cavalier 	size_t actualLength = 0;
316*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->send_request(fDevice,
317*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_IPGS,
318*cbe0a0c4SAugustin Cavalier 		0, 0, sizeof(fIPG), fIPG, &actualLength);
319*cbe0a0c4SAugustin Cavalier 
320*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
321*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result);
322*cbe0a0c4SAugustin Cavalier 		return result;
323*cbe0a0c4SAugustin Cavalier 	}
324*cbe0a0c4SAugustin Cavalier 
325*cbe0a0c4SAugustin Cavalier 	if (actualLength != sizeof(fIPG)) {
326*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Mismatch of written IPGs data. "
327*cbe0a0c4SAugustin Cavalier 			"%d bytes of %d written.\n", actualLength, sizeof(fIPG));
328*cbe0a0c4SAugustin Cavalier 	}
329*cbe0a0c4SAugustin Cavalier 
330*cbe0a0c4SAugustin Cavalier 	uint16 rxcontrol = RXCTL_START | RXCTL_BROADCAST;
331*cbe0a0c4SAugustin Cavalier 	result = WriteRXControlRegister(rxcontrol);
332*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
333*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
334*cbe0a0c4SAugustin Cavalier 			rxcontrol, result);
335*cbe0a0c4SAugustin Cavalier 	}
336*cbe0a0c4SAugustin Cavalier 
337*cbe0a0c4SAugustin Cavalier 	TRACE_RET(result);
338*cbe0a0c4SAugustin Cavalier 	return result;
339*cbe0a0c4SAugustin Cavalier }
340*cbe0a0c4SAugustin Cavalier 
341*cbe0a0c4SAugustin Cavalier 
342*cbe0a0c4SAugustin Cavalier status_t
OnNotify(uint32 actualLength)343*cbe0a0c4SAugustin Cavalier AX88178Device::OnNotify(uint32 actualLength)
344*cbe0a0c4SAugustin Cavalier {
345*cbe0a0c4SAugustin Cavalier 	if (actualLength < sizeof(AX88178_Notify)) {
346*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n",
347*cbe0a0c4SAugustin Cavalier 			actualLength, sizeof(AX88178_Notify));
348*cbe0a0c4SAugustin Cavalier 		return B_BAD_DATA;
349*cbe0a0c4SAugustin Cavalier 	}
350*cbe0a0c4SAugustin Cavalier 
351*cbe0a0c4SAugustin Cavalier 	AX88178_Notify *notification = (AX88178_Notify *)fNotifyBuffer;
352*cbe0a0c4SAugustin Cavalier 
353*cbe0a0c4SAugustin Cavalier 	if (notification->btA1 != 0xa1) {
354*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n",
355*cbe0a0c4SAugustin Cavalier 			notification->btA1);
356*cbe0a0c4SAugustin Cavalier 	}
357*cbe0a0c4SAugustin Cavalier 
358*cbe0a0c4SAugustin Cavalier 	uint phyIndex = 0;
359*cbe0a0c4SAugustin Cavalier 	bool linkIsUp = fHasConnection;
360*cbe0a0c4SAugustin Cavalier 	switch(fMII.ActivePHY()) {
361*cbe0a0c4SAugustin Cavalier 		case PrimaryPHY:
362*cbe0a0c4SAugustin Cavalier 			phyIndex = 1;
363*cbe0a0c4SAugustin Cavalier 			linkIsUp = (notification->btBB & LINK_STATE_PPLS)
364*cbe0a0c4SAugustin Cavalier 				== LINK_STATE_PPLS;
365*cbe0a0c4SAugustin Cavalier 			break;
366*cbe0a0c4SAugustin Cavalier 		case SecondaryPHY:
367*cbe0a0c4SAugustin Cavalier 			phyIndex = 2;
368*cbe0a0c4SAugustin Cavalier 			linkIsUp = (notification->btBB & LINK_STATE_SPLS)
369*cbe0a0c4SAugustin Cavalier 				== LINK_STATE_SPLS;
370*cbe0a0c4SAugustin Cavalier 			break;
371*cbe0a0c4SAugustin Cavalier 		default:
372*cbe0a0c4SAugustin Cavalier 		case CurrentPHY:
373*cbe0a0c4SAugustin Cavalier 			TRACE_ALWAYS("Error: PHY is not initialized.\n");
374*cbe0a0c4SAugustin Cavalier 			return B_NO_INIT;
375*cbe0a0c4SAugustin Cavalier 	}
376*cbe0a0c4SAugustin Cavalier 
377*cbe0a0c4SAugustin Cavalier 	bool linkStateChange = linkIsUp != fHasConnection;
378*cbe0a0c4SAugustin Cavalier 	fHasConnection = linkIsUp;
379*cbe0a0c4SAugustin Cavalier 
380*cbe0a0c4SAugustin Cavalier 	if (linkStateChange) {
381*cbe0a0c4SAugustin Cavalier 		TRACE("Link state of PHY%d has been changed to '%s'\n",
382*cbe0a0c4SAugustin Cavalier 			phyIndex, fHasConnection ? "up" : "down");
383*cbe0a0c4SAugustin Cavalier 	}
384*cbe0a0c4SAugustin Cavalier 
385*cbe0a0c4SAugustin Cavalier 	if (linkStateChange && fLinkStateChangeSem >= B_OK)
386*cbe0a0c4SAugustin Cavalier 		release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
387*cbe0a0c4SAugustin Cavalier 
388*cbe0a0c4SAugustin Cavalier 	return B_OK;
389*cbe0a0c4SAugustin Cavalier }
390*cbe0a0c4SAugustin Cavalier 
391*cbe0a0c4SAugustin Cavalier 
392*cbe0a0c4SAugustin Cavalier status_t
GetLinkState(ether_link_state * linkState)393*cbe0a0c4SAugustin Cavalier AX88178Device::GetLinkState(ether_link_state *linkState)
394*cbe0a0c4SAugustin Cavalier {
395*cbe0a0c4SAugustin Cavalier 	size_t actualLength = 0;
396*cbe0a0c4SAugustin Cavalier 	uint16 mediumStatus = 0;
397*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->send_request(fDevice,
398*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, READ_MEDIUM_STATUS,
399*cbe0a0c4SAugustin Cavalier 		0, 0, sizeof(mediumStatus), &mediumStatus, &actualLength);
400*cbe0a0c4SAugustin Cavalier 
401*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
402*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result);
403*cbe0a0c4SAugustin Cavalier 		return result;
404*cbe0a0c4SAugustin Cavalier 	}
405*cbe0a0c4SAugustin Cavalier 
406*cbe0a0c4SAugustin Cavalier 	if (actualLength != sizeof(mediumStatus)) {
407*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Mismatch of reading medium status."
408*cbe0a0c4SAugustin Cavalier 							"Read %d bytes instead of %d\n",
409*cbe0a0c4SAugustin Cavalier 									actualLength, sizeof(mediumStatus));
410*cbe0a0c4SAugustin Cavalier 	}
411*cbe0a0c4SAugustin Cavalier 
412*cbe0a0c4SAugustin Cavalier 	TRACE_FLOW("Medium status is %#04x\n", mediumStatus);
413*cbe0a0c4SAugustin Cavalier 
414*cbe0a0c4SAugustin Cavalier 	linkState->quality = 1000;
415*cbe0a0c4SAugustin Cavalier 
416*cbe0a0c4SAugustin Cavalier 	linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0);
417*cbe0a0c4SAugustin Cavalier 	linkState->media |= (mediumStatus & MEDIUM_STATE_FD)
418*cbe0a0c4SAugustin Cavalier 		? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
419*cbe0a0c4SAugustin Cavalier 
420*cbe0a0c4SAugustin Cavalier 	linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100)
421*cbe0a0c4SAugustin Cavalier 		? 100000000 : 10000000;
422*cbe0a0c4SAugustin Cavalier 	linkState->speed = (mediumStatus & MEDIUM_STATE_GM)
423*cbe0a0c4SAugustin Cavalier 		? 1000000000 : linkState->speed;
424*cbe0a0c4SAugustin Cavalier 
425*cbe0a0c4SAugustin Cavalier 	TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
426*cbe0a0c4SAugustin Cavalier 		(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
427*cbe0a0c4SAugustin Cavalier 		linkState->speed / 1000000,
428*cbe0a0c4SAugustin Cavalier 		(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
429*cbe0a0c4SAugustin Cavalier 	return B_OK;
430*cbe0a0c4SAugustin Cavalier }
431