xref: /haiku/src/add-ons/kernel/drivers/network/ether/usb_davicom/DavicomDevice.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1*cbe0a0c4SAugustin Cavalier /*
2*cbe0a0c4SAugustin Cavalier  *	Davicom DM9601 USB 1.1 Ethernet Driver.
3*cbe0a0c4SAugustin Cavalier  *	Copyright (c) 2008, 2011 Siarzhuk Zharski <imker@gmx.li>
4*cbe0a0c4SAugustin Cavalier  *	Copyright (c) 2009 Adrien Destugues <pulkomandy@gmail.com>
5*cbe0a0c4SAugustin Cavalier  *	Distributed under the terms of the MIT license.
6*cbe0a0c4SAugustin Cavalier  *
7*cbe0a0c4SAugustin Cavalier  *	Heavily based on code of the
8*cbe0a0c4SAugustin Cavalier  *	Driver for USB Ethernet Control Model devices
9*cbe0a0c4SAugustin Cavalier  *	Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
10*cbe0a0c4SAugustin Cavalier  *	Distributed under the terms of the MIT license.
11*cbe0a0c4SAugustin Cavalier  */
12*cbe0a0c4SAugustin Cavalier 
13*cbe0a0c4SAugustin Cavalier 
14*cbe0a0c4SAugustin Cavalier #include "DavicomDevice.h"
15*cbe0a0c4SAugustin Cavalier 
16*cbe0a0c4SAugustin Cavalier #include <stdio.h>
17*cbe0a0c4SAugustin Cavalier #include <net/if_media.h>
18*cbe0a0c4SAugustin Cavalier 
19*cbe0a0c4SAugustin Cavalier #include "Driver.h"
20*cbe0a0c4SAugustin Cavalier #include "Settings.h"
21*cbe0a0c4SAugustin Cavalier 
22*cbe0a0c4SAugustin Cavalier 
23*cbe0a0c4SAugustin Cavalier const int kFrameSize = 1522;
24*cbe0a0c4SAugustin Cavalier 
25*cbe0a0c4SAugustin Cavalier enum VendorRequests {
26*cbe0a0c4SAugustin Cavalier 	ReqReadRegister			= 0,
27*cbe0a0c4SAugustin Cavalier 	ReqWriteRegister		= 1,
28*cbe0a0c4SAugustin Cavalier 	ReqWriteRegisterByte	= 3,
29*cbe0a0c4SAugustin Cavalier };
30*cbe0a0c4SAugustin Cavalier 
31*cbe0a0c4SAugustin Cavalier 
32*cbe0a0c4SAugustin Cavalier enum DM9601Registers {
33*cbe0a0c4SAugustin Cavalier 	RegNCR	= 0x00,	// Network Control Register
34*cbe0a0c4SAugustin Cavalier 		NCRExtPHY	= 0x80,	// Select External PHY
35*cbe0a0c4SAugustin Cavalier 		NCRFullDX	= 0x08,	// Full duplex
36*cbe0a0c4SAugustin Cavalier 		NCRLoopback	= 0x06,	// Internal PHY analog loopback
37*cbe0a0c4SAugustin Cavalier 
38*cbe0a0c4SAugustin Cavalier 	RegNSR	= 0x01,	// Network Status Register
39*cbe0a0c4SAugustin Cavalier 		NSRSpeed10	= 0x80,	// 0 = 100MBps, 1 = 10MBps (internal PHY)
40*cbe0a0c4SAugustin Cavalier 		NSRLinkUp	= 0x40,	// 1 = link up (internal PHY)
41*cbe0a0c4SAugustin Cavalier 		NSRTXFull	= 0x10,	// TX FIFO full
42*cbe0a0c4SAugustin Cavalier 		NSRRXOver	= 0x08,	// RX FIFO overflow
43*cbe0a0c4SAugustin Cavalier 
44*cbe0a0c4SAugustin Cavalier 	RegRCR	= 0x05,	// RX Control Register
45*cbe0a0c4SAugustin Cavalier 		RCRDiscardLong	= 0x20,	// Discard long packet (over 1522 bytes)
46*cbe0a0c4SAugustin Cavalier 		RCRDiscardCRC	= 0x10,	// Discard CRC error packet
47*cbe0a0c4SAugustin Cavalier 		RCRAllMulticast	= 0x08,	// Pass all multicast
48*cbe0a0c4SAugustin Cavalier 		RCRPromiscuous	= 0x02,	// Promiscuous
49*cbe0a0c4SAugustin Cavalier 		RCRRXEnable		= 0x01,	// RX enable
50*cbe0a0c4SAugustin Cavalier 
51*cbe0a0c4SAugustin Cavalier 	RegEPCR	= 0x0b,	// EEPROM & PHY Control Register
52*cbe0a0c4SAugustin Cavalier 		EPCROpSelect	= 0x08,	// EEPROM or PHY Operation Select
53*cbe0a0c4SAugustin Cavalier 		EPCRRegRead		= 0x04,	// EEPROM or PHY Register Read Command
54*cbe0a0c4SAugustin Cavalier 		EPCRRegWrite	= 0x02,	// EEPROM or PHY Register Write Command
55*cbe0a0c4SAugustin Cavalier 
56*cbe0a0c4SAugustin Cavalier 	RegEPAR	= 0x0c,	// EEPROM & PHY Address Register
57*cbe0a0c4SAugustin Cavalier 		EPARIntPHY		= 0x40,	// [7:6] force to 01 if Internal PHY is selected
58*cbe0a0c4SAugustin Cavalier 		EPARMask		= 0x1f,	// mask [0:5]
59*cbe0a0c4SAugustin Cavalier 
60*cbe0a0c4SAugustin Cavalier 	RegEPDRL = 0x0d, // EEPROM & PHY Low Byte Data Register
61*cbe0a0c4SAugustin Cavalier 
62*cbe0a0c4SAugustin Cavalier 	RegEPDRH = 0x0e, // EEPROM & PHY Low Byte Data Register
63*cbe0a0c4SAugustin Cavalier 
64*cbe0a0c4SAugustin Cavalier 	RegPAR	= 0x10,	// [0x10 - 0x15] Physical Address Register
65*cbe0a0c4SAugustin Cavalier 
66*cbe0a0c4SAugustin Cavalier 	RegMAR	= 0x16,	// [0x16 - 0x1d] Multicast Address Register
67*cbe0a0c4SAugustin Cavalier 
68*cbe0a0c4SAugustin Cavalier 	RegGPCR	= 0x1E,	// General Purpose Control Register
69*cbe0a0c4SAugustin Cavalier 		GPCRPowerDown	= 0x01,	// [0:6] Define in/out direction of GPCR
70*cbe0a0c4SAugustin Cavalier 								// GPIO0 - is output for Power Down function
71*cbe0a0c4SAugustin Cavalier 
72*cbe0a0c4SAugustin Cavalier 	RegGPR	= 0x1F,	// General Purpose Register
73*cbe0a0c4SAugustin Cavalier 		GPRPowerDownInPHY = 0x01,	// Power down Internal PHY
74*cbe0a0c4SAugustin Cavalier 
75*cbe0a0c4SAugustin Cavalier 	RegUSBC	= 0xf4, // USB Control Register
76*cbe0a0c4SAugustin Cavalier 		USBCIntAck		= 0x20,	// ACK with 8-bytes of data on interrupt EP
77*cbe0a0c4SAugustin Cavalier 		USBCIntNAck		= 0x10,	// Supress ACK on interrupt EP
78*cbe0a0c4SAugustin Cavalier 
79*cbe0a0c4SAugustin Cavalier };
80*cbe0a0c4SAugustin Cavalier 
81*cbe0a0c4SAugustin Cavalier 
82*cbe0a0c4SAugustin Cavalier enum MIIRegisters {
83*cbe0a0c4SAugustin Cavalier 	RegBMCR	= 0x00,
84*cbe0a0c4SAugustin Cavalier 		BMCRIsolate	= 0x0400,
85*cbe0a0c4SAugustin Cavalier 		BMCRReset	= 0x8000,
86*cbe0a0c4SAugustin Cavalier 
87*cbe0a0c4SAugustin Cavalier 	RegBMSR	= 0x01,
88*cbe0a0c4SAugustin Cavalier 	RegPHYID1	= 0x02,
89*cbe0a0c4SAugustin Cavalier 	RegPHYID2	= 0x03,
90*cbe0a0c4SAugustin Cavalier };
91*cbe0a0c4SAugustin Cavalier 
92*cbe0a0c4SAugustin Cavalier #define MII_OUI(id1, id2)       (((id1) << 6) | ((id2) >> 10))
93*cbe0a0c4SAugustin Cavalier #define MII_MODEL(id2)          (((id2) & 0x03f0) >> 4)
94*cbe0a0c4SAugustin Cavalier #define MII_REV(id2)             ((id2) & 0x000f)
95*cbe0a0c4SAugustin Cavalier 
96*cbe0a0c4SAugustin Cavalier 
DavicomDevice(usb_device device,DeviceInfo & deviceInfo)97*cbe0a0c4SAugustin Cavalier DavicomDevice::DavicomDevice(usb_device device, DeviceInfo& deviceInfo)
98*cbe0a0c4SAugustin Cavalier 	:	fDevice(device),
99*cbe0a0c4SAugustin Cavalier 		fStatus(B_ERROR),
100*cbe0a0c4SAugustin Cavalier 		fOpen(false),
101*cbe0a0c4SAugustin Cavalier 		fRemoved(false),
102*cbe0a0c4SAugustin Cavalier 		fHasConnection(false),
103*cbe0a0c4SAugustin Cavalier 		fTXBufferFull(false),
104*cbe0a0c4SAugustin Cavalier 		fNonBlocking(false),
105*cbe0a0c4SAugustin Cavalier 		fInsideNotify(0),
106*cbe0a0c4SAugustin Cavalier 		fNotifyEndpoint(0),
107*cbe0a0c4SAugustin Cavalier 		fReadEndpoint(0),
108*cbe0a0c4SAugustin Cavalier 		fWriteEndpoint(0),
109*cbe0a0c4SAugustin Cavalier 		fMaxTXPacketSize(0),
110*cbe0a0c4SAugustin Cavalier 		fActualLengthRead(0),
111*cbe0a0c4SAugustin Cavalier 		fActualLengthWrite(0),
112*cbe0a0c4SAugustin Cavalier 		fStatusRead(0),
113*cbe0a0c4SAugustin Cavalier 		fStatusWrite(0),
114*cbe0a0c4SAugustin Cavalier 		fNotifyReadSem(-1),
115*cbe0a0c4SAugustin Cavalier 		fNotifyWriteSem(-1),
116*cbe0a0c4SAugustin Cavalier 		fLinkStateChangeSem(-1),
117*cbe0a0c4SAugustin Cavalier 		fNotifyData(NULL)
118*cbe0a0c4SAugustin Cavalier {
119*cbe0a0c4SAugustin Cavalier 	fDeviceInfo = deviceInfo;
120*cbe0a0c4SAugustin Cavalier 
121*cbe0a0c4SAugustin Cavalier 	memset(&fMACAddress, 0, sizeof(fMACAddress));
122*cbe0a0c4SAugustin Cavalier 
123*cbe0a0c4SAugustin Cavalier 	fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read");
124*cbe0a0c4SAugustin Cavalier 	if (fNotifyReadSem < B_OK) {
125*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of creating read notify semaphore:%#010x\n",
126*cbe0a0c4SAugustin Cavalier 															fNotifyReadSem);
127*cbe0a0c4SAugustin Cavalier 		return;
128*cbe0a0c4SAugustin Cavalier 	}
129*cbe0a0c4SAugustin Cavalier 
130*cbe0a0c4SAugustin Cavalier 	fNotifyWriteSem = create_sem(0, DRIVER_NAME"_notify_write");
131*cbe0a0c4SAugustin Cavalier 	if (fNotifyWriteSem < B_OK) {
132*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of creating write notify semaphore:%#010x\n",
133*cbe0a0c4SAugustin Cavalier 															fNotifyWriteSem);
134*cbe0a0c4SAugustin Cavalier 		return;
135*cbe0a0c4SAugustin Cavalier 	}
136*cbe0a0c4SAugustin Cavalier 
137*cbe0a0c4SAugustin Cavalier 	fNotifyData = new DM9601NotifyData();
138*cbe0a0c4SAugustin Cavalier 	if (fNotifyData == NULL) {
139*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error allocating notify buffer\n");
140*cbe0a0c4SAugustin Cavalier 		return;
141*cbe0a0c4SAugustin Cavalier 	}
142*cbe0a0c4SAugustin Cavalier 
143*cbe0a0c4SAugustin Cavalier 	if (_SetupEndpoints() != B_OK) {
144*cbe0a0c4SAugustin Cavalier 		return;
145*cbe0a0c4SAugustin Cavalier 	}
146*cbe0a0c4SAugustin Cavalier 
147*cbe0a0c4SAugustin Cavalier 	_InitMII();
148*cbe0a0c4SAugustin Cavalier 
149*cbe0a0c4SAugustin Cavalier 	fStatus = B_OK;
150*cbe0a0c4SAugustin Cavalier 	TRACE("Created!\n");
151*cbe0a0c4SAugustin Cavalier }
152*cbe0a0c4SAugustin Cavalier 
153*cbe0a0c4SAugustin Cavalier 
~DavicomDevice()154*cbe0a0c4SAugustin Cavalier DavicomDevice::~DavicomDevice()
155*cbe0a0c4SAugustin Cavalier {
156*cbe0a0c4SAugustin Cavalier 	if (fNotifyReadSem >= B_OK)
157*cbe0a0c4SAugustin Cavalier 		delete_sem(fNotifyReadSem);
158*cbe0a0c4SAugustin Cavalier 	if (fNotifyWriteSem >= B_OK)
159*cbe0a0c4SAugustin Cavalier 		delete_sem(fNotifyWriteSem);
160*cbe0a0c4SAugustin Cavalier 
161*cbe0a0c4SAugustin Cavalier 	if (!fRemoved) // ???
162*cbe0a0c4SAugustin Cavalier 		gUSBModule->cancel_queued_transfers(fNotifyEndpoint);
163*cbe0a0c4SAugustin Cavalier 
164*cbe0a0c4SAugustin Cavalier 	delete fNotifyData;
165*cbe0a0c4SAugustin Cavalier 	TRACE("Deleted!\n");
166*cbe0a0c4SAugustin Cavalier }
167*cbe0a0c4SAugustin Cavalier 
168*cbe0a0c4SAugustin Cavalier 
169*cbe0a0c4SAugustin Cavalier status_t
Open(uint32 flags)170*cbe0a0c4SAugustin Cavalier DavicomDevice::Open(uint32 flags)
171*cbe0a0c4SAugustin Cavalier {
172*cbe0a0c4SAugustin Cavalier 	if (fOpen)
173*cbe0a0c4SAugustin Cavalier 		return B_BUSY;
174*cbe0a0c4SAugustin Cavalier 	if (fRemoved)
175*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
176*cbe0a0c4SAugustin Cavalier 
177*cbe0a0c4SAugustin Cavalier 	status_t result = _StartDevice();
178*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
179*cbe0a0c4SAugustin Cavalier 		return result;
180*cbe0a0c4SAugustin Cavalier 	}
181*cbe0a0c4SAugustin Cavalier 
182*cbe0a0c4SAugustin Cavalier 	// setup state notifications
183*cbe0a0c4SAugustin Cavalier 	result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyData,
184*cbe0a0c4SAugustin Cavalier 		sizeof(DM9601NotifyData), _NotifyCallback, this);
185*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
186*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of requesting notify interrupt:%#010x\n", result);
187*cbe0a0c4SAugustin Cavalier 		return result;
188*cbe0a0c4SAugustin Cavalier 	}
189*cbe0a0c4SAugustin Cavalier 
190*cbe0a0c4SAugustin Cavalier 	result = _EnableInterrupts(true);
191*cbe0a0c4SAugustin Cavalier 
192*cbe0a0c4SAugustin Cavalier 	fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK;
193*cbe0a0c4SAugustin Cavalier 	fOpen = true;
194*cbe0a0c4SAugustin Cavalier 	TRACE("Opened: %#010x!\n", result);
195*cbe0a0c4SAugustin Cavalier 	return result;
196*cbe0a0c4SAugustin Cavalier }
197*cbe0a0c4SAugustin Cavalier 
198*cbe0a0c4SAugustin Cavalier 
199*cbe0a0c4SAugustin Cavalier status_t
Close()200*cbe0a0c4SAugustin Cavalier DavicomDevice::Close()
201*cbe0a0c4SAugustin Cavalier {
202*cbe0a0c4SAugustin Cavalier 	if (fRemoved) {
203*cbe0a0c4SAugustin Cavalier 		fOpen = false;
204*cbe0a0c4SAugustin Cavalier 		return B_OK;
205*cbe0a0c4SAugustin Cavalier 	}
206*cbe0a0c4SAugustin Cavalier 
207*cbe0a0c4SAugustin Cavalier 	_EnableInterrupts(false);
208*cbe0a0c4SAugustin Cavalier 
209*cbe0a0c4SAugustin Cavalier 	// wait until possible notification handling finished...
210*cbe0a0c4SAugustin Cavalier 	while (atomic_add(&fInsideNotify, 0) != 0)
211*cbe0a0c4SAugustin Cavalier 		snooze(100);
212*cbe0a0c4SAugustin Cavalier 	gUSBModule->cancel_queued_transfers(fNotifyEndpoint);
213*cbe0a0c4SAugustin Cavalier 	gUSBModule->cancel_queued_transfers(fReadEndpoint);
214*cbe0a0c4SAugustin Cavalier 	gUSBModule->cancel_queued_transfers(fWriteEndpoint);
215*cbe0a0c4SAugustin Cavalier 
216*cbe0a0c4SAugustin Cavalier 	fOpen = false;
217*cbe0a0c4SAugustin Cavalier 
218*cbe0a0c4SAugustin Cavalier 	status_t result = _StopDevice();
219*cbe0a0c4SAugustin Cavalier 	TRACE("Closed: %#010x!\n", result);
220*cbe0a0c4SAugustin Cavalier 	return result;
221*cbe0a0c4SAugustin Cavalier }
222*cbe0a0c4SAugustin Cavalier 
223*cbe0a0c4SAugustin Cavalier 
224*cbe0a0c4SAugustin Cavalier status_t
Free()225*cbe0a0c4SAugustin Cavalier DavicomDevice::Free()
226*cbe0a0c4SAugustin Cavalier {
227*cbe0a0c4SAugustin Cavalier 	TRACE("Freed!\n");
228*cbe0a0c4SAugustin Cavalier 	return B_OK;
229*cbe0a0c4SAugustin Cavalier }
230*cbe0a0c4SAugustin Cavalier 
231*cbe0a0c4SAugustin Cavalier 
232*cbe0a0c4SAugustin Cavalier status_t
Read(uint8 * buffer,size_t * numBytes)233*cbe0a0c4SAugustin Cavalier DavicomDevice::Read(uint8 *buffer, size_t *numBytes)
234*cbe0a0c4SAugustin Cavalier {
235*cbe0a0c4SAugustin Cavalier 	size_t numBytesToRead = *numBytes;
236*cbe0a0c4SAugustin Cavalier 	*numBytes = 0;
237*cbe0a0c4SAugustin Cavalier 
238*cbe0a0c4SAugustin Cavalier 	if (fRemoved) {
239*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of receiving %d bytes from removed device.\n",
240*cbe0a0c4SAugustin Cavalier 			numBytesToRead);
241*cbe0a0c4SAugustin Cavalier 		return B_DEVICE_NOT_FOUND;
242*cbe0a0c4SAugustin Cavalier 	}
243*cbe0a0c4SAugustin Cavalier 
244*cbe0a0c4SAugustin Cavalier 	TRACE_RX("Request %d bytes.\n", numBytesToRead);
245*cbe0a0c4SAugustin Cavalier 
246*cbe0a0c4SAugustin Cavalier 	struct _RXHeader {
247*cbe0a0c4SAugustin Cavalier 		uint	FOE	:1;
248*cbe0a0c4SAugustin Cavalier 		uint	CE	:1;
249*cbe0a0c4SAugustin Cavalier 		uint	LE	:1;
250*cbe0a0c4SAugustin Cavalier 		uint	PLE	:1;
251*cbe0a0c4SAugustin Cavalier 		uint	RWTO:1;
252*cbe0a0c4SAugustin Cavalier 		uint	LCS	:1;
253*cbe0a0c4SAugustin Cavalier 		uint	MF	:1;
254*cbe0a0c4SAugustin Cavalier 		uint	RF	:1;
255*cbe0a0c4SAugustin Cavalier 		uint	countLow	:8;
256*cbe0a0c4SAugustin Cavalier 		uint	countHigh	:8;
257*cbe0a0c4SAugustin Cavalier 
258*cbe0a0c4SAugustin Cavalier 		uint8	Errors() { return 0xbf & *(uint8*)this; }
259*cbe0a0c4SAugustin Cavalier 	} __attribute__((__packed__));
260*cbe0a0c4SAugustin Cavalier 
261*cbe0a0c4SAugustin Cavalier 	_RXHeader header = { 0 };
262*cbe0a0c4SAugustin Cavalier 
263*cbe0a0c4SAugustin Cavalier 	iovec rxData[] = {
264*cbe0a0c4SAugustin Cavalier 		{ &header, sizeof(header) },
265*cbe0a0c4SAugustin Cavalier 		{ buffer,  numBytesToRead }
266*cbe0a0c4SAugustin Cavalier 	};
267*cbe0a0c4SAugustin Cavalier 
268*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->queue_bulk_v(fReadEndpoint,
269*cbe0a0c4SAugustin Cavalier 		rxData, 2, _ReadCallback, this);
270*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
271*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result);
272*cbe0a0c4SAugustin Cavalier 		return result;
273*cbe0a0c4SAugustin Cavalier 	}
274*cbe0a0c4SAugustin Cavalier 
275*cbe0a0c4SAugustin Cavalier 	uint32 flags = B_CAN_INTERRUPT | (fNonBlocking ? B_TIMEOUT : 0);
276*cbe0a0c4SAugustin Cavalier 	result = acquire_sem_etc(fNotifyReadSem, 1, flags, 0);
277*cbe0a0c4SAugustin Cavalier 	if (result < B_OK) {
278*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result);
279*cbe0a0c4SAugustin Cavalier 		return result;
280*cbe0a0c4SAugustin Cavalier 	}
281*cbe0a0c4SAugustin Cavalier 
282*cbe0a0c4SAugustin Cavalier 	if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !fRemoved) {
283*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Device status error:%#010x\n", fStatusRead);
284*cbe0a0c4SAugustin Cavalier 		return fStatusRead;
285*cbe0a0c4SAugustin Cavalier 	}
286*cbe0a0c4SAugustin Cavalier 
287*cbe0a0c4SAugustin Cavalier 	if (fActualLengthRead < sizeof(_RXHeader)) {
288*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error: no place for RXHeader: only %d of %d bytes.\n",
289*cbe0a0c4SAugustin Cavalier 			fActualLengthRead, sizeof(_RXHeader));
290*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
291*cbe0a0c4SAugustin Cavalier 	}
292*cbe0a0c4SAugustin Cavalier 
293*cbe0a0c4SAugustin Cavalier 	if (header.Errors() != 0) {
294*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("RX header errors %#04x detected!\n", header.Errors());
295*cbe0a0c4SAugustin Cavalier 	}
296*cbe0a0c4SAugustin Cavalier 
297*cbe0a0c4SAugustin Cavalier 	TRACE_STATS("FOE:%d CE:%d LE:%d PLE:%d rwTO:%d LCS:%d MF:%d RF:%d\n",
298*cbe0a0c4SAugustin Cavalier 			header.FOE, header.CE, header.LE, header.PLE,
299*cbe0a0c4SAugustin Cavalier 			header.RWTO, header.LCS, header.MF, header.RF);
300*cbe0a0c4SAugustin Cavalier 
301*cbe0a0c4SAugustin Cavalier 	*numBytes = header.countLow | ( header.countHigh << 8 );
302*cbe0a0c4SAugustin Cavalier 
303*cbe0a0c4SAugustin Cavalier 	if (fActualLengthRead - sizeof(_RXHeader) > *numBytes) {
304*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; received:%d\n",
305*cbe0a0c4SAugustin Cavalier 			*numBytes, fActualLengthRead - sizeof(_RXHeader));
306*cbe0a0c4SAugustin Cavalier 	}
307*cbe0a0c4SAugustin Cavalier 
308*cbe0a0c4SAugustin Cavalier 	TRACE_RX("Read %d bytes.\n", *numBytes);
309*cbe0a0c4SAugustin Cavalier 	return B_OK;
310*cbe0a0c4SAugustin Cavalier }
311*cbe0a0c4SAugustin Cavalier 
312*cbe0a0c4SAugustin Cavalier 
313*cbe0a0c4SAugustin Cavalier status_t
Write(const uint8 * buffer,size_t * numBytes)314*cbe0a0c4SAugustin Cavalier DavicomDevice::Write(const uint8 *buffer, size_t *numBytes)
315*cbe0a0c4SAugustin Cavalier {
316*cbe0a0c4SAugustin Cavalier 	size_t numBytesToWrite = *numBytes;
317*cbe0a0c4SAugustin Cavalier 	*numBytes = 0;
318*cbe0a0c4SAugustin Cavalier 
319*cbe0a0c4SAugustin Cavalier 	if (fRemoved) {
320*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of writing %d bytes to removed device.\n",
321*cbe0a0c4SAugustin Cavalier 			numBytesToWrite);
322*cbe0a0c4SAugustin Cavalier 		return B_DEVICE_NOT_FOUND;
323*cbe0a0c4SAugustin Cavalier 	}
324*cbe0a0c4SAugustin Cavalier 
325*cbe0a0c4SAugustin Cavalier 	if (!fHasConnection) {
326*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of writing %d bytes to device while down.\n",
327*cbe0a0c4SAugustin Cavalier 			numBytesToWrite);
328*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
329*cbe0a0c4SAugustin Cavalier 	}
330*cbe0a0c4SAugustin Cavalier 
331*cbe0a0c4SAugustin Cavalier 	if (fTXBufferFull) {
332*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of writing %d bytes to device: TX buffer full.\n",
333*cbe0a0c4SAugustin Cavalier 			numBytesToWrite);
334*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
335*cbe0a0c4SAugustin Cavalier 	}
336*cbe0a0c4SAugustin Cavalier 
337*cbe0a0c4SAugustin Cavalier 	TRACE_TX("Write %d bytes.\n", numBytesToWrite);
338*cbe0a0c4SAugustin Cavalier 
339*cbe0a0c4SAugustin Cavalier 	// additional padding byte must be transmitted in case data size
340*cbe0a0c4SAugustin Cavalier 	// to be send is multiple of pipe's max packet size
341*cbe0a0c4SAugustin Cavalier 	uint16 length = numBytesToWrite;
342*cbe0a0c4SAugustin Cavalier 	size_t count = 2;
343*cbe0a0c4SAugustin Cavalier 	if (((numBytesToWrite + 2) % fMaxTXPacketSize) == 0) {
344*cbe0a0c4SAugustin Cavalier 		length++;
345*cbe0a0c4SAugustin Cavalier 		count++;
346*cbe0a0c4SAugustin Cavalier 	}
347*cbe0a0c4SAugustin Cavalier 
348*cbe0a0c4SAugustin Cavalier 	struct _TXHeader {
349*cbe0a0c4SAugustin Cavalier 		uint8	countLow;
350*cbe0a0c4SAugustin Cavalier 		uint8	countHigh;
351*cbe0a0c4SAugustin Cavalier 	} __attribute__((__packed__));
352*cbe0a0c4SAugustin Cavalier 
353*cbe0a0c4SAugustin Cavalier 	_TXHeader header = { (uint8)(length & 0xff),
354*cbe0a0c4SAugustin Cavalier 		(uint8)((length >> 8) & 0xff) };
355*cbe0a0c4SAugustin Cavalier 
356*cbe0a0c4SAugustin Cavalier 	uint8 padding = 0;
357*cbe0a0c4SAugustin Cavalier 
358*cbe0a0c4SAugustin Cavalier 	iovec txData[] = {
359*cbe0a0c4SAugustin Cavalier 		{ &header, sizeof(_TXHeader) },
360*cbe0a0c4SAugustin Cavalier 		{ (uint8*)buffer, numBytesToWrite },
361*cbe0a0c4SAugustin Cavalier 		{ &padding, 1 }
362*cbe0a0c4SAugustin Cavalier 	};
363*cbe0a0c4SAugustin Cavalier 
364*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint,
365*cbe0a0c4SAugustin Cavalier 		txData, count, _WriteCallback, this);
366*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
367*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result);
368*cbe0a0c4SAugustin Cavalier 		return result;
369*cbe0a0c4SAugustin Cavalier 	}
370*cbe0a0c4SAugustin Cavalier 
371*cbe0a0c4SAugustin Cavalier 	result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0);
372*cbe0a0c4SAugustin Cavalier 
373*cbe0a0c4SAugustin Cavalier 	if (result < B_OK) {
374*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result);
375*cbe0a0c4SAugustin Cavalier 		return result;
376*cbe0a0c4SAugustin Cavalier 	}
377*cbe0a0c4SAugustin Cavalier 
378*cbe0a0c4SAugustin Cavalier 	if (fStatusWrite != B_OK && fStatusWrite != B_CANCELED && !fRemoved) {
379*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Device status error:%#010x\n", fStatusWrite);
380*cbe0a0c4SAugustin Cavalier 		return fStatusWrite;
381*cbe0a0c4SAugustin Cavalier 	}
382*cbe0a0c4SAugustin Cavalier 
383*cbe0a0c4SAugustin Cavalier 	*numBytes = fActualLengthWrite - sizeof(_TXHeader);
384*cbe0a0c4SAugustin Cavalier 
385*cbe0a0c4SAugustin Cavalier 	TRACE_TX("Written %d bytes.\n", *numBytes);
386*cbe0a0c4SAugustin Cavalier 	return B_OK;
387*cbe0a0c4SAugustin Cavalier }
388*cbe0a0c4SAugustin Cavalier 
389*cbe0a0c4SAugustin Cavalier 
390*cbe0a0c4SAugustin Cavalier status_t
Control(uint32 op,void * buffer,size_t length)391*cbe0a0c4SAugustin Cavalier DavicomDevice::Control(uint32 op, void *buffer, size_t length)
392*cbe0a0c4SAugustin Cavalier {
393*cbe0a0c4SAugustin Cavalier 	switch (op) {
394*cbe0a0c4SAugustin Cavalier 		case ETHER_INIT:
395*cbe0a0c4SAugustin Cavalier 			return B_OK;
396*cbe0a0c4SAugustin Cavalier 
397*cbe0a0c4SAugustin Cavalier 		case ETHER_GETADDR:
398*cbe0a0c4SAugustin Cavalier 			memcpy(buffer, &fMACAddress, sizeof(fMACAddress));
399*cbe0a0c4SAugustin Cavalier 			return B_OK;
400*cbe0a0c4SAugustin Cavalier 
401*cbe0a0c4SAugustin Cavalier 		case ETHER_GETFRAMESIZE:
402*cbe0a0c4SAugustin Cavalier 			*(uint32 *)buffer = kFrameSize;
403*cbe0a0c4SAugustin Cavalier 			return B_OK;
404*cbe0a0c4SAugustin Cavalier 
405*cbe0a0c4SAugustin Cavalier 		case ETHER_NONBLOCK:
406*cbe0a0c4SAugustin Cavalier 			TRACE("ETHER_NONBLOCK\n");
407*cbe0a0c4SAugustin Cavalier 			fNonBlocking = *((uint8*)buffer);
408*cbe0a0c4SAugustin Cavalier 			return B_OK;
409*cbe0a0c4SAugustin Cavalier 
410*cbe0a0c4SAugustin Cavalier 		case ETHER_SETPROMISC:
411*cbe0a0c4SAugustin Cavalier 			TRACE("ETHER_SETPROMISC\n");
412*cbe0a0c4SAugustin Cavalier 			return _SetPromiscuousMode(*((uint8*)buffer));
413*cbe0a0c4SAugustin Cavalier 
414*cbe0a0c4SAugustin Cavalier 		case ETHER_ADDMULTI:
415*cbe0a0c4SAugustin Cavalier 			TRACE("ETHER_ADDMULTI\n");
416*cbe0a0c4SAugustin Cavalier 			return _ModifyMulticastTable(true, (ether_address_t*)buffer);
417*cbe0a0c4SAugustin Cavalier 
418*cbe0a0c4SAugustin Cavalier 		case ETHER_REMMULTI:
419*cbe0a0c4SAugustin Cavalier 			TRACE("ETHER_REMMULTI\n");
420*cbe0a0c4SAugustin Cavalier 			return _ModifyMulticastTable(false, (ether_address_t*)buffer);
421*cbe0a0c4SAugustin Cavalier 
422*cbe0a0c4SAugustin Cavalier 		case ETHER_SET_LINK_STATE_SEM:
423*cbe0a0c4SAugustin Cavalier 			fLinkStateChangeSem = *(sem_id *)buffer;
424*cbe0a0c4SAugustin Cavalier 			return B_OK;
425*cbe0a0c4SAugustin Cavalier 
426*cbe0a0c4SAugustin Cavalier 		case ETHER_GET_LINK_STATE:
427*cbe0a0c4SAugustin Cavalier 			return _GetLinkState((ether_link_state *)buffer);
428*cbe0a0c4SAugustin Cavalier 
429*cbe0a0c4SAugustin Cavalier 		default:
430*cbe0a0c4SAugustin Cavalier 			TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op);
431*cbe0a0c4SAugustin Cavalier 	}
432*cbe0a0c4SAugustin Cavalier 
433*cbe0a0c4SAugustin Cavalier 	return B_DEV_INVALID_IOCTL;
434*cbe0a0c4SAugustin Cavalier }
435*cbe0a0c4SAugustin Cavalier 
436*cbe0a0c4SAugustin Cavalier 
437*cbe0a0c4SAugustin Cavalier void
Removed()438*cbe0a0c4SAugustin Cavalier DavicomDevice::Removed()
439*cbe0a0c4SAugustin Cavalier {
440*cbe0a0c4SAugustin Cavalier 	fRemoved = true;
441*cbe0a0c4SAugustin Cavalier 	fHasConnection = false;
442*cbe0a0c4SAugustin Cavalier 
443*cbe0a0c4SAugustin Cavalier 	// the notify hook is different from the read and write hooks as it does
444*cbe0a0c4SAugustin Cavalier 	// itself schedule traffic (while the other hooks only release a semaphore
445*cbe0a0c4SAugustin Cavalier 	// to notify another thread which in turn safly checks for the removed
446*cbe0a0c4SAugustin Cavalier 	// case) - so we must ensure that we are not inside the notify hook anymore
447*cbe0a0c4SAugustin Cavalier 	// before returning, as we would otherwise violate the promise not to use
448*cbe0a0c4SAugustin Cavalier 	// any of the pipes after returning from the removed hook
449*cbe0a0c4SAugustin Cavalier 	while (atomic_add(&fInsideNotify, 0) != 0)
450*cbe0a0c4SAugustin Cavalier 		snooze(100);
451*cbe0a0c4SAugustin Cavalier 
452*cbe0a0c4SAugustin Cavalier 	gUSBModule->cancel_queued_transfers(fNotifyEndpoint);
453*cbe0a0c4SAugustin Cavalier 	gUSBModule->cancel_queued_transfers(fReadEndpoint);
454*cbe0a0c4SAugustin Cavalier 	gUSBModule->cancel_queued_transfers(fWriteEndpoint);
455*cbe0a0c4SAugustin Cavalier 
456*cbe0a0c4SAugustin Cavalier 	if (fLinkStateChangeSem >= B_OK)
457*cbe0a0c4SAugustin Cavalier 		release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
458*cbe0a0c4SAugustin Cavalier }
459*cbe0a0c4SAugustin Cavalier 
460*cbe0a0c4SAugustin Cavalier 
461*cbe0a0c4SAugustin Cavalier status_t
SetupDevice(bool deviceReplugged)462*cbe0a0c4SAugustin Cavalier DavicomDevice::SetupDevice(bool deviceReplugged)
463*cbe0a0c4SAugustin Cavalier {
464*cbe0a0c4SAugustin Cavalier 	ether_address address;
465*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadMACAddress(&address);
466*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
467*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading MAC address:%#010x\n", result);
468*cbe0a0c4SAugustin Cavalier 		return result;
469*cbe0a0c4SAugustin Cavalier 	}
470*cbe0a0c4SAugustin Cavalier 
471*cbe0a0c4SAugustin Cavalier 	TRACE("MAC address is:%02x:%02x:%02x:%02x:%02x:%02x\n",
472*cbe0a0c4SAugustin Cavalier 				address.ebyte[0], address.ebyte[1], address.ebyte[2],
473*cbe0a0c4SAugustin Cavalier 				address.ebyte[3], address.ebyte[4], address.ebyte[5]);
474*cbe0a0c4SAugustin Cavalier 
475*cbe0a0c4SAugustin Cavalier 	if (deviceReplugged) {
476*cbe0a0c4SAugustin Cavalier 		// this might be the same device that was replugged - read the MAC
477*cbe0a0c4SAugustin Cavalier 		// address (which should be at the same index) to make sure
478*cbe0a0c4SAugustin Cavalier 		if (memcmp(&address, &fMACAddress, sizeof(address)) != 0) {
479*cbe0a0c4SAugustin Cavalier 			TRACE_ALWAYS("Cannot replace device with MAC address:"
480*cbe0a0c4SAugustin Cavalier 				"%02x:%02x:%02x:%02x:%02x:%02x\n",
481*cbe0a0c4SAugustin Cavalier 				fMACAddress.ebyte[0], fMACAddress.ebyte[1],
482*cbe0a0c4SAugustin Cavalier 				fMACAddress.ebyte[2], fMACAddress.ebyte[3],
483*cbe0a0c4SAugustin Cavalier 				fMACAddress.ebyte[4], fMACAddress.ebyte[5]);
484*cbe0a0c4SAugustin Cavalier 			return B_BAD_VALUE; // is not the same
485*cbe0a0c4SAugustin Cavalier 		}
486*cbe0a0c4SAugustin Cavalier 	} else
487*cbe0a0c4SAugustin Cavalier 		fMACAddress = address;
488*cbe0a0c4SAugustin Cavalier 
489*cbe0a0c4SAugustin Cavalier 	return B_OK;
490*cbe0a0c4SAugustin Cavalier }
491*cbe0a0c4SAugustin Cavalier 
492*cbe0a0c4SAugustin Cavalier 
493*cbe0a0c4SAugustin Cavalier status_t
CompareAndReattach(usb_device device)494*cbe0a0c4SAugustin Cavalier DavicomDevice::CompareAndReattach(usb_device device)
495*cbe0a0c4SAugustin Cavalier {
496*cbe0a0c4SAugustin Cavalier 	const usb_device_descriptor *deviceDescriptor
497*cbe0a0c4SAugustin Cavalier 		= gUSBModule->get_device_descriptor(device);
498*cbe0a0c4SAugustin Cavalier 
499*cbe0a0c4SAugustin Cavalier 	if (deviceDescriptor == NULL) {
500*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error getting USB device descriptor.\n");
501*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
502*cbe0a0c4SAugustin Cavalier 	}
503*cbe0a0c4SAugustin Cavalier 
504*cbe0a0c4SAugustin Cavalier 	if (deviceDescriptor->vendor_id != fDeviceInfo.VendorId()
505*cbe0a0c4SAugustin Cavalier 		&& deviceDescriptor->product_id != fDeviceInfo.ProductId()) {
506*cbe0a0c4SAugustin Cavalier 		// this certainly isn't the same device
507*cbe0a0c4SAugustin Cavalier 		return B_BAD_VALUE;
508*cbe0a0c4SAugustin Cavalier 	}
509*cbe0a0c4SAugustin Cavalier 
510*cbe0a0c4SAugustin Cavalier 	// this is the same device that was replugged - clear the removed state,
511*cbe0a0c4SAugustin Cavalier 	// re-setup the endpoints and transfers and open the device if it was
512*cbe0a0c4SAugustin Cavalier 	// previously opened
513*cbe0a0c4SAugustin Cavalier 	fDevice = device;
514*cbe0a0c4SAugustin Cavalier 	fRemoved = false;
515*cbe0a0c4SAugustin Cavalier 	status_t result = _SetupEndpoints();
516*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
517*cbe0a0c4SAugustin Cavalier 		fRemoved = true;
518*cbe0a0c4SAugustin Cavalier 		return result;
519*cbe0a0c4SAugustin Cavalier 	}
520*cbe0a0c4SAugustin Cavalier 
521*cbe0a0c4SAugustin Cavalier 	// we need to setup hardware on device replug
522*cbe0a0c4SAugustin Cavalier 	result = SetupDevice(true);
523*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
524*cbe0a0c4SAugustin Cavalier 		return result;
525*cbe0a0c4SAugustin Cavalier 	}
526*cbe0a0c4SAugustin Cavalier 
527*cbe0a0c4SAugustin Cavalier 	if (fOpen) {
528*cbe0a0c4SAugustin Cavalier 		fOpen = false;
529*cbe0a0c4SAugustin Cavalier 		result = Open(fNonBlocking ? O_NONBLOCK : 0);
530*cbe0a0c4SAugustin Cavalier 	}
531*cbe0a0c4SAugustin Cavalier 
532*cbe0a0c4SAugustin Cavalier 	return result;
533*cbe0a0c4SAugustin Cavalier }
534*cbe0a0c4SAugustin Cavalier 
535*cbe0a0c4SAugustin Cavalier 
536*cbe0a0c4SAugustin Cavalier status_t
_SetupEndpoints()537*cbe0a0c4SAugustin Cavalier DavicomDevice::_SetupEndpoints()
538*cbe0a0c4SAugustin Cavalier {
539*cbe0a0c4SAugustin Cavalier 	const usb_configuration_info *config
540*cbe0a0c4SAugustin Cavalier 		= gUSBModule->get_nth_configuration(fDevice, 0);
541*cbe0a0c4SAugustin Cavalier 
542*cbe0a0c4SAugustin Cavalier 	if (config == NULL) {
543*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of getting USB device configuration.\n");
544*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
545*cbe0a0c4SAugustin Cavalier 	}
546*cbe0a0c4SAugustin Cavalier 
547*cbe0a0c4SAugustin Cavalier 	if (config->interface_count <= 0) {
548*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error:no interfaces found in USB device configuration\n");
549*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
550*cbe0a0c4SAugustin Cavalier 	}
551*cbe0a0c4SAugustin Cavalier 
552*cbe0a0c4SAugustin Cavalier 	usb_interface_info *interface = config->interface[0].active;
553*cbe0a0c4SAugustin Cavalier 	if (interface == 0) {
554*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error:invalid active interface in "
555*cbe0a0c4SAugustin Cavalier 												"USB device configuration\n");
556*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
557*cbe0a0c4SAugustin Cavalier 	}
558*cbe0a0c4SAugustin Cavalier 
559*cbe0a0c4SAugustin Cavalier 	int notifyEndpoint = -1;
560*cbe0a0c4SAugustin Cavalier 	int readEndpoint   = -1;
561*cbe0a0c4SAugustin Cavalier 	int writeEndpoint  = -1;
562*cbe0a0c4SAugustin Cavalier 
563*cbe0a0c4SAugustin Cavalier 	for (size_t ep = 0; ep < interface->endpoint_count; ep++) {
564*cbe0a0c4SAugustin Cavalier 		usb_endpoint_descriptor *epd = interface->endpoint[ep].descr;
565*cbe0a0c4SAugustin Cavalier 		if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
566*cbe0a0c4SAugustin Cavalier 				== USB_ENDPOINT_ATTR_INTERRUPT)
567*cbe0a0c4SAugustin Cavalier 		{
568*cbe0a0c4SAugustin Cavalier 			notifyEndpoint = ep;
569*cbe0a0c4SAugustin Cavalier 			continue;
570*cbe0a0c4SAugustin Cavalier 		}
571*cbe0a0c4SAugustin Cavalier 
572*cbe0a0c4SAugustin Cavalier 		if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
573*cbe0a0c4SAugustin Cavalier 				!= USB_ENDPOINT_ATTR_BULK)
574*cbe0a0c4SAugustin Cavalier 		{
575*cbe0a0c4SAugustin Cavalier 			TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n",
576*cbe0a0c4SAugustin Cavalier 					epd->attributes);
577*cbe0a0c4SAugustin Cavalier 			continue;
578*cbe0a0c4SAugustin Cavalier 		}
579*cbe0a0c4SAugustin Cavalier 
580*cbe0a0c4SAugustin Cavalier 		if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_MASK)
581*cbe0a0c4SAugustin Cavalier 				== USB_ENDPOINT_ADDR_DIR_IN)
582*cbe0a0c4SAugustin Cavalier 		{
583*cbe0a0c4SAugustin Cavalier 			readEndpoint = ep;
584*cbe0a0c4SAugustin Cavalier 			continue;
585*cbe0a0c4SAugustin Cavalier 		}
586*cbe0a0c4SAugustin Cavalier 
587*cbe0a0c4SAugustin Cavalier 		if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_MASK)
588*cbe0a0c4SAugustin Cavalier 				== USB_ENDPOINT_ADDR_DIR_OUT)
589*cbe0a0c4SAugustin Cavalier 		{
590*cbe0a0c4SAugustin Cavalier 			writeEndpoint = ep;
591*cbe0a0c4SAugustin Cavalier 			continue;
592*cbe0a0c4SAugustin Cavalier 		}
593*cbe0a0c4SAugustin Cavalier 	}
594*cbe0a0c4SAugustin Cavalier 
595*cbe0a0c4SAugustin Cavalier 	if (notifyEndpoint == -1 || readEndpoint == -1 || writeEndpoint == -1) {
596*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error: not all USB endpoints were found: notify:%d; "
597*cbe0a0c4SAugustin Cavalier 			"read:%d; write:%d\n", notifyEndpoint, readEndpoint, writeEndpoint);
598*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
599*cbe0a0c4SAugustin Cavalier 	}
600*cbe0a0c4SAugustin Cavalier 
601*cbe0a0c4SAugustin Cavalier 	gUSBModule->set_configuration(fDevice, config);
602*cbe0a0c4SAugustin Cavalier 
603*cbe0a0c4SAugustin Cavalier 	fNotifyEndpoint = interface->endpoint[notifyEndpoint].handle;
604*cbe0a0c4SAugustin Cavalier 	fReadEndpoint   = interface->endpoint[readEndpoint  ].handle;
605*cbe0a0c4SAugustin Cavalier 	fWriteEndpoint  = interface->endpoint[writeEndpoint ].handle;
606*cbe0a0c4SAugustin Cavalier 	fMaxTXPacketSize = interface->endpoint[writeEndpoint].descr->max_packet_size;
607*cbe0a0c4SAugustin Cavalier 
608*cbe0a0c4SAugustin Cavalier 	return B_OK;
609*cbe0a0c4SAugustin Cavalier }
610*cbe0a0c4SAugustin Cavalier 
611*cbe0a0c4SAugustin Cavalier 
612*cbe0a0c4SAugustin Cavalier status_t
_ReadMACAddress(ether_address_t * address)613*cbe0a0c4SAugustin Cavalier DavicomDevice::_ReadMACAddress(ether_address_t *address)
614*cbe0a0c4SAugustin Cavalier {
615*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadRegister(RegPAR,
616*cbe0a0c4SAugustin Cavalier 							sizeof(ether_address), (uint8*)address);
617*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
618*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result);
619*cbe0a0c4SAugustin Cavalier 		return result;
620*cbe0a0c4SAugustin Cavalier 	}
621*cbe0a0c4SAugustin Cavalier 
622*cbe0a0c4SAugustin Cavalier 	return B_OK;
623*cbe0a0c4SAugustin Cavalier }
624*cbe0a0c4SAugustin Cavalier 
625*cbe0a0c4SAugustin Cavalier 
626*cbe0a0c4SAugustin Cavalier status_t
_StartDevice()627*cbe0a0c4SAugustin Cavalier DavicomDevice::_StartDevice()
628*cbe0a0c4SAugustin Cavalier {
629*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
630*cbe0a0c4SAugustin Cavalier 
631*cbe0a0c4SAugustin Cavalier 	// disable loopback
632*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadRegister(RegNCR, 1, &control);
633*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
634*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading NCR: %#010x.\n", result);
635*cbe0a0c4SAugustin Cavalier 		return result;
636*cbe0a0c4SAugustin Cavalier 	}
637*cbe0a0c4SAugustin Cavalier 
638*cbe0a0c4SAugustin Cavalier 	if (control & NCRExtPHY)
639*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Device uses external PHY\n");
640*cbe0a0c4SAugustin Cavalier 
641*cbe0a0c4SAugustin Cavalier 	control &= ~NCRLoopback;
642*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegNCR, control);
643*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
644*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to NCR: %#010x.\n", control, result);
645*cbe0a0c4SAugustin Cavalier 		return result;
646*cbe0a0c4SAugustin Cavalier 	}
647*cbe0a0c4SAugustin Cavalier 
648*cbe0a0c4SAugustin Cavalier 	// Initialize RX control register, enable RX and activate multicast
649*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegRCR, 1, &control);
650*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
651*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
652*cbe0a0c4SAugustin Cavalier 		return result;
653*cbe0a0c4SAugustin Cavalier 	}
654*cbe0a0c4SAugustin Cavalier 
655*cbe0a0c4SAugustin Cavalier 	control &= ~RCRPromiscuous;
656*cbe0a0c4SAugustin Cavalier 	control |= RCRDiscardLong | RCRDiscardCRC | RCRRXEnable | RCRAllMulticast;
657*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegRCR, control);
658*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
659*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result);
660*cbe0a0c4SAugustin Cavalier 		return result;
661*cbe0a0c4SAugustin Cavalier 	}
662*cbe0a0c4SAugustin Cavalier 
663*cbe0a0c4SAugustin Cavalier 	// clear POWER_DOWN state of internal PHY
664*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegGPCR, 1, &control);
665*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
666*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading GPCR: %#010x.\n", result);
667*cbe0a0c4SAugustin Cavalier 		return result;
668*cbe0a0c4SAugustin Cavalier 	}
669*cbe0a0c4SAugustin Cavalier 
670*cbe0a0c4SAugustin Cavalier 	control |= GPCRPowerDown;
671*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegGPCR, control);
672*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
673*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to GPCR: %#010x.\n", control, result);
674*cbe0a0c4SAugustin Cavalier 		return result;
675*cbe0a0c4SAugustin Cavalier 	}
676*cbe0a0c4SAugustin Cavalier 
677*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegGPR, 1, &control);
678*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
679*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading GPR: %#010x.\n", result);
680*cbe0a0c4SAugustin Cavalier 		return result;
681*cbe0a0c4SAugustin Cavalier 	}
682*cbe0a0c4SAugustin Cavalier 
683*cbe0a0c4SAugustin Cavalier 	control &= ~GPRPowerDownInPHY;
684*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegGPR, control);
685*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
686*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to GPR: %#010x.\n", control, result);
687*cbe0a0c4SAugustin Cavalier 		return result;
688*cbe0a0c4SAugustin Cavalier 	}
689*cbe0a0c4SAugustin Cavalier 
690*cbe0a0c4SAugustin Cavalier 	return B_OK;
691*cbe0a0c4SAugustin Cavalier }
692*cbe0a0c4SAugustin Cavalier 
693*cbe0a0c4SAugustin Cavalier 
694*cbe0a0c4SAugustin Cavalier status_t
_StopDevice()695*cbe0a0c4SAugustin Cavalier DavicomDevice::_StopDevice()
696*cbe0a0c4SAugustin Cavalier {
697*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
698*cbe0a0c4SAugustin Cavalier 
699*cbe0a0c4SAugustin Cavalier 	// disable RX
700*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadRegister(RegRCR, 1, &control);
701*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
702*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
703*cbe0a0c4SAugustin Cavalier 		return result;
704*cbe0a0c4SAugustin Cavalier 	}
705*cbe0a0c4SAugustin Cavalier 
706*cbe0a0c4SAugustin Cavalier 	control &= ~RCRRXEnable;
707*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegRCR, control);
708*cbe0a0c4SAugustin Cavalier 	if (result != B_OK)
709*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result);
710*cbe0a0c4SAugustin Cavalier 
711*cbe0a0c4SAugustin Cavalier 	return result;
712*cbe0a0c4SAugustin Cavalier }
713*cbe0a0c4SAugustin Cavalier 
714*cbe0a0c4SAugustin Cavalier 
715*cbe0a0c4SAugustin Cavalier status_t
_SetPromiscuousMode(bool on)716*cbe0a0c4SAugustin Cavalier DavicomDevice::_SetPromiscuousMode(bool on)
717*cbe0a0c4SAugustin Cavalier {
718*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
719*cbe0a0c4SAugustin Cavalier 
720*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadRegister(RegRCR, 1, &control);
721*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
722*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
723*cbe0a0c4SAugustin Cavalier 		return result;
724*cbe0a0c4SAugustin Cavalier 	}
725*cbe0a0c4SAugustin Cavalier 
726*cbe0a0c4SAugustin Cavalier 	if (on)
727*cbe0a0c4SAugustin Cavalier 		control |= RCRPromiscuous;
728*cbe0a0c4SAugustin Cavalier 	else
729*cbe0a0c4SAugustin Cavalier 		control &= ~RCRPromiscuous;
730*cbe0a0c4SAugustin Cavalier 
731*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegRCR, control);
732*cbe0a0c4SAugustin Cavalier 	if (result != B_OK)
733*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result);
734*cbe0a0c4SAugustin Cavalier 
735*cbe0a0c4SAugustin Cavalier 	return result;
736*cbe0a0c4SAugustin Cavalier }
737*cbe0a0c4SAugustin Cavalier 
738*cbe0a0c4SAugustin Cavalier 
739*cbe0a0c4SAugustin Cavalier uint32
_EthernetCRC32(const uint8 * buffer,size_t length)740*cbe0a0c4SAugustin Cavalier DavicomDevice::_EthernetCRC32(const uint8* buffer, size_t length)
741*cbe0a0c4SAugustin Cavalier {
742*cbe0a0c4SAugustin Cavalier 	uint32 result = 0xffffffff;
743*cbe0a0c4SAugustin Cavalier 	for (size_t i = 0; i < length; i++) {
744*cbe0a0c4SAugustin Cavalier 		uint8 data = *buffer++;
745*cbe0a0c4SAugustin Cavalier 		for (int bit = 0; bit < 8; bit++, data >>= 1) {
746*cbe0a0c4SAugustin Cavalier 			uint32 carry = ((result & 0x80000000) ? 1 : 0) ^ (data & 0x01);
747*cbe0a0c4SAugustin Cavalier 			result <<= 1;
748*cbe0a0c4SAugustin Cavalier 			if (carry != 0)
749*cbe0a0c4SAugustin Cavalier 				result = (result ^ 0x04c11db6) | carry;
750*cbe0a0c4SAugustin Cavalier 		}
751*cbe0a0c4SAugustin Cavalier 	}
752*cbe0a0c4SAugustin Cavalier 	return result;
753*cbe0a0c4SAugustin Cavalier }
754*cbe0a0c4SAugustin Cavalier 
755*cbe0a0c4SAugustin Cavalier 
756*cbe0a0c4SAugustin Cavalier status_t
_ModifyMulticastTable(bool join,ether_address_t * group)757*cbe0a0c4SAugustin Cavalier DavicomDevice::_ModifyMulticastTable(bool join, ether_address_t *group)
758*cbe0a0c4SAugustin Cavalier {
759*cbe0a0c4SAugustin Cavalier 	char groupName[6 * 3 + 1] = { 0 };
760*cbe0a0c4SAugustin Cavalier 	sprintf(groupName, "%02x:%02x:%02x:%02x:%02x:%02x",
761*cbe0a0c4SAugustin Cavalier 		group->ebyte[0], group->ebyte[1], group->ebyte[2],
762*cbe0a0c4SAugustin Cavalier 		group->ebyte[3], group->ebyte[4], group->ebyte[5]);
763*cbe0a0c4SAugustin Cavalier 	TRACE("%s multicast group %s\n", join ? "Joining" : "Leaving", groupName);
764*cbe0a0c4SAugustin Cavalier 
765*cbe0a0c4SAugustin Cavalier 	uint32 hash = _EthernetCRC32(group->ebyte, 6);
766*cbe0a0c4SAugustin Cavalier 	bool isInTable = fMulticastHashes.Find(hash) != fMulticastHashes.End();
767*cbe0a0c4SAugustin Cavalier 
768*cbe0a0c4SAugustin Cavalier 	if (isInTable && join)
769*cbe0a0c4SAugustin Cavalier 		return B_OK; // already listed - nothing to do
770*cbe0a0c4SAugustin Cavalier 
771*cbe0a0c4SAugustin Cavalier 	if (!isInTable && !join) {
772*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Cannot leave unlisted multicast group %s!\n", groupName);
773*cbe0a0c4SAugustin Cavalier 		return B_ERROR;
774*cbe0a0c4SAugustin Cavalier 	}
775*cbe0a0c4SAugustin Cavalier 
776*cbe0a0c4SAugustin Cavalier 	const size_t hashLength = 8;
777*cbe0a0c4SAugustin Cavalier 	uint8 hashTable[hashLength] = { 0 };
778*cbe0a0c4SAugustin Cavalier 	hashTable[hashLength - 1] |= 0x80; // broadcast address
779*cbe0a0c4SAugustin Cavalier 
780*cbe0a0c4SAugustin Cavalier 	status_t result = _WriteRegister(RegMAR, hashLength, hashTable);
781*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
782*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error initializing MAR: %#010x.\n", result);
783*cbe0a0c4SAugustin Cavalier 		return result;
784*cbe0a0c4SAugustin Cavalier 	}
785*cbe0a0c4SAugustin Cavalier 
786*cbe0a0c4SAugustin Cavalier 	if (join)
787*cbe0a0c4SAugustin Cavalier 		fMulticastHashes.PushBack(hash);
788*cbe0a0c4SAugustin Cavalier 	else
789*cbe0a0c4SAugustin Cavalier 		fMulticastHashes.Remove(hash);
790*cbe0a0c4SAugustin Cavalier 
791*cbe0a0c4SAugustin Cavalier 	for (int32 i = 0; i < fMulticastHashes.Count(); i++) {
792*cbe0a0c4SAugustin Cavalier 		uint32 hash = fMulticastHashes[i] >> 26;
793*cbe0a0c4SAugustin Cavalier 		hashTable[hash / 8] |= 1 << (hash % 8);
794*cbe0a0c4SAugustin Cavalier 	}
795*cbe0a0c4SAugustin Cavalier 
796*cbe0a0c4SAugustin Cavalier 	// clear/set pass all multicast bit as required
797*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
798*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegRCR, 1, &control);
799*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
800*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading RCR: %#010x.\n", result);
801*cbe0a0c4SAugustin Cavalier 		return result;
802*cbe0a0c4SAugustin Cavalier 	}
803*cbe0a0c4SAugustin Cavalier 
804*cbe0a0c4SAugustin Cavalier 	if (fMulticastHashes.Count() > 0)
805*cbe0a0c4SAugustin Cavalier 		control &= ~RCRAllMulticast;
806*cbe0a0c4SAugustin Cavalier 	else
807*cbe0a0c4SAugustin Cavalier 		control |= RCRAllMulticast;
808*cbe0a0c4SAugustin Cavalier 
809*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegRCR, control);
810*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
811*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result);
812*cbe0a0c4SAugustin Cavalier 		return result;
813*cbe0a0c4SAugustin Cavalier 	}
814*cbe0a0c4SAugustin Cavalier 
815*cbe0a0c4SAugustin Cavalier 	result = _WriteRegister(RegMAR, hashLength, hashTable);
816*cbe0a0c4SAugustin Cavalier 	if (result != B_OK)
817*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error writing hash table in MAR: %#010x.\n", result);
818*cbe0a0c4SAugustin Cavalier 
819*cbe0a0c4SAugustin Cavalier 	return result;
820*cbe0a0c4SAugustin Cavalier }
821*cbe0a0c4SAugustin Cavalier 
822*cbe0a0c4SAugustin Cavalier 
823*cbe0a0c4SAugustin Cavalier void
_ReadCallback(void * cookie,int32 status,void * data,size_t actualLength)824*cbe0a0c4SAugustin Cavalier DavicomDevice::_ReadCallback(void *cookie, int32 status, void *data,
825*cbe0a0c4SAugustin Cavalier 	size_t actualLength)
826*cbe0a0c4SAugustin Cavalier {
827*cbe0a0c4SAugustin Cavalier 	TRACE_RX("ReadCB: %d bytes; status:%#010x\n", actualLength, status);
828*cbe0a0c4SAugustin Cavalier 	DavicomDevice *device = (DavicomDevice *)cookie;
829*cbe0a0c4SAugustin Cavalier 	device->fActualLengthRead = actualLength;
830*cbe0a0c4SAugustin Cavalier 	device->fStatusRead = status;
831*cbe0a0c4SAugustin Cavalier 	device->fStats.readCount++;
832*cbe0a0c4SAugustin Cavalier 	release_sem_etc(device->fNotifyReadSem, 1, B_DO_NOT_RESCHEDULE);
833*cbe0a0c4SAugustin Cavalier }
834*cbe0a0c4SAugustin Cavalier 
835*cbe0a0c4SAugustin Cavalier 
836*cbe0a0c4SAugustin Cavalier void
_WriteCallback(void * cookie,int32 status,void * data,size_t actualLength)837*cbe0a0c4SAugustin Cavalier DavicomDevice::_WriteCallback(void *cookie, int32 status, void *data,
838*cbe0a0c4SAugustin Cavalier 	size_t actualLength)
839*cbe0a0c4SAugustin Cavalier {
840*cbe0a0c4SAugustin Cavalier 	TRACE_TX("WriteCB: %d bytes; status:%#010x\n", actualLength, status);
841*cbe0a0c4SAugustin Cavalier 	DavicomDevice *device = (DavicomDevice *)cookie;
842*cbe0a0c4SAugustin Cavalier 	device->fActualLengthWrite = actualLength;
843*cbe0a0c4SAugustin Cavalier 	device->fStatusWrite = status;
844*cbe0a0c4SAugustin Cavalier 	device->fStats.writeCount++;
845*cbe0a0c4SAugustin Cavalier 	release_sem_etc(device->fNotifyWriteSem, 1, B_DO_NOT_RESCHEDULE);
846*cbe0a0c4SAugustin Cavalier }
847*cbe0a0c4SAugustin Cavalier 
848*cbe0a0c4SAugustin Cavalier 
849*cbe0a0c4SAugustin Cavalier void
_NotifyCallback(void * cookie,int32 status,void * data,size_t actualLength)850*cbe0a0c4SAugustin Cavalier DavicomDevice::_NotifyCallback(void *cookie, int32 status, void *data,
851*cbe0a0c4SAugustin Cavalier 	size_t actualLength)
852*cbe0a0c4SAugustin Cavalier {
853*cbe0a0c4SAugustin Cavalier 	DavicomDevice *device = (DavicomDevice *)cookie;
854*cbe0a0c4SAugustin Cavalier 	atomic_add(&device->fInsideNotify, 1);
855*cbe0a0c4SAugustin Cavalier 	if (status == B_CANCELED || device->fRemoved) {
856*cbe0a0c4SAugustin Cavalier 		atomic_add(&device->fInsideNotify, -1);
857*cbe0a0c4SAugustin Cavalier 		return;
858*cbe0a0c4SAugustin Cavalier 	}
859*cbe0a0c4SAugustin Cavalier 
860*cbe0a0c4SAugustin Cavalier 	if (status == B_OK)
861*cbe0a0c4SAugustin Cavalier 		device->_OnNotify(actualLength);
862*cbe0a0c4SAugustin Cavalier 	else
863*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Status error:%#010x; length:%d\n", status, actualLength);
864*cbe0a0c4SAugustin Cavalier 
865*cbe0a0c4SAugustin Cavalier 	// schedule next notification buffer
866*cbe0a0c4SAugustin Cavalier 	gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyData,
867*cbe0a0c4SAugustin Cavalier 		sizeof(DM9601NotifyData), _NotifyCallback, device);
868*cbe0a0c4SAugustin Cavalier 	atomic_add(&device->fInsideNotify, -1);
869*cbe0a0c4SAugustin Cavalier }
870*cbe0a0c4SAugustin Cavalier 
871*cbe0a0c4SAugustin Cavalier 
872*cbe0a0c4SAugustin Cavalier status_t
_OnNotify(uint32 actualLength)873*cbe0a0c4SAugustin Cavalier DavicomDevice::_OnNotify(uint32 actualLength)
874*cbe0a0c4SAugustin Cavalier {
875*cbe0a0c4SAugustin Cavalier 	if (actualLength != sizeof(DM9601NotifyData)) {
876*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n",
877*cbe0a0c4SAugustin Cavalier 			actualLength, sizeof(DM9601NotifyData));
878*cbe0a0c4SAugustin Cavalier 		return B_BAD_DATA;
879*cbe0a0c4SAugustin Cavalier 	}
880*cbe0a0c4SAugustin Cavalier 
881*cbe0a0c4SAugustin Cavalier 	bool linkIsUp = fNotifyData->LINKST != 0;
882*cbe0a0c4SAugustin Cavalier 	fTXBufferFull = fNotifyData->TXFULL != 0;
883*cbe0a0c4SAugustin Cavalier 	bool rxOverflow = fNotifyData->RXOV != 0;
884*cbe0a0c4SAugustin Cavalier 
885*cbe0a0c4SAugustin Cavalier 	bool linkStateChange = (linkIsUp != fHasConnection);
886*cbe0a0c4SAugustin Cavalier 	fHasConnection = linkIsUp;
887*cbe0a0c4SAugustin Cavalier 
888*cbe0a0c4SAugustin Cavalier 	if (linkStateChange) {
889*cbe0a0c4SAugustin Cavalier 		if (fHasConnection) {
890*cbe0a0c4SAugustin Cavalier 			TRACE("Link is now up at %s Mb/s\n",
891*cbe0a0c4SAugustin Cavalier 				fNotifyData->SPEED ? "10" : "100");
892*cbe0a0c4SAugustin Cavalier 		} else
893*cbe0a0c4SAugustin Cavalier 			TRACE("Link is now down");
894*cbe0a0c4SAugustin Cavalier 	}
895*cbe0a0c4SAugustin Cavalier 
896*cbe0a0c4SAugustin Cavalier #ifdef UDAV_TRACE
897*cbe0a0c4SAugustin Cavalier 	if (gTraceStats) {
898*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TXFULL)
899*cbe0a0c4SAugustin Cavalier 			fStats.txFull++;
900*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->RXOV)
901*cbe0a0c4SAugustin Cavalier 			fStats.rxOverflow++;
902*cbe0a0c4SAugustin Cavalier 
903*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->ROC)
904*cbe0a0c4SAugustin Cavalier 			fStats.rxOvCount += fNotifyData->ROC;
905*cbe0a0c4SAugustin Cavalier 
906*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->RT)
907*cbe0a0c4SAugustin Cavalier 			fStats.runtFrames++;
908*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->LCS)
909*cbe0a0c4SAugustin Cavalier 			fStats.lateRXCollisions++;
910*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->RWTO)
911*cbe0a0c4SAugustin Cavalier 			fStats.rwTOs++;
912*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->PLE)
913*cbe0a0c4SAugustin Cavalier 			fStats.physLayerErros++;
914*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->AE)
915*cbe0a0c4SAugustin Cavalier 			fStats.alignmentErros++;
916*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->CE)
917*cbe0a0c4SAugustin Cavalier 			fStats.crcErrors++;
918*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->FOE)
919*cbe0a0c4SAugustin Cavalier 			fStats.overErrors++;
920*cbe0a0c4SAugustin Cavalier 
921*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR1.LC)
922*cbe0a0c4SAugustin Cavalier 			fStats.lateTXCollisions++;
923*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR1.LCR)
924*cbe0a0c4SAugustin Cavalier 			fStats.lostOfCarrier++;
925*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR1.NC)
926*cbe0a0c4SAugustin Cavalier 			fStats.noCarrier++;
927*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR1.COL)
928*cbe0a0c4SAugustin Cavalier 			fStats.txCollisions++;
929*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR1.EC)
930*cbe0a0c4SAugustin Cavalier 			fStats.excCollisions++;
931*cbe0a0c4SAugustin Cavalier 
932*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR2.LC)
933*cbe0a0c4SAugustin Cavalier 			fStats.lateTXCollisions++;
934*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR2.LCR)
935*cbe0a0c4SAugustin Cavalier 			fStats.lostOfCarrier++;
936*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR2.NC)
937*cbe0a0c4SAugustin Cavalier 			fStats.noCarrier++;
938*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR2.COL)
939*cbe0a0c4SAugustin Cavalier 			fStats.txCollisions++;
940*cbe0a0c4SAugustin Cavalier 		if (fNotifyData->TSR2.EC)
941*cbe0a0c4SAugustin Cavalier 			fStats.excCollisions++;
942*cbe0a0c4SAugustin Cavalier 
943*cbe0a0c4SAugustin Cavalier 		fStats.notifyCount++;
944*cbe0a0c4SAugustin Cavalier 	}
945*cbe0a0c4SAugustin Cavalier #endif
946*cbe0a0c4SAugustin Cavalier 
947*cbe0a0c4SAugustin Cavalier 	if (rxOverflow)
948*cbe0a0c4SAugustin Cavalier 		TRACE("RX buffer overflow. %d packets dropped\n", fNotifyData->ROC);
949*cbe0a0c4SAugustin Cavalier 
950*cbe0a0c4SAugustin Cavalier 	uint8 tsr = 0xfc & *(uint8*)&fNotifyData->TSR1;
951*cbe0a0c4SAugustin Cavalier 	if (tsr != 0)
952*cbe0a0c4SAugustin Cavalier 		TRACE("TX packet 1: Status %#04x is not OK.\n", tsr);
953*cbe0a0c4SAugustin Cavalier 
954*cbe0a0c4SAugustin Cavalier 	tsr = 0xfc & *(uint8*)&fNotifyData->TSR2;
955*cbe0a0c4SAugustin Cavalier 	if (tsr != 0)
956*cbe0a0c4SAugustin Cavalier 		TRACE("TX packet 2: Status %#04x is not OK.\n", tsr);
957*cbe0a0c4SAugustin Cavalier 
958*cbe0a0c4SAugustin Cavalier 	if (linkStateChange && fLinkStateChangeSem >= B_OK)
959*cbe0a0c4SAugustin Cavalier 		release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
960*cbe0a0c4SAugustin Cavalier 	return B_OK;
961*cbe0a0c4SAugustin Cavalier }
962*cbe0a0c4SAugustin Cavalier 
963*cbe0a0c4SAugustin Cavalier 
964*cbe0a0c4SAugustin Cavalier status_t
_GetLinkState(ether_link_state * linkState)965*cbe0a0c4SAugustin Cavalier DavicomDevice::_GetLinkState(ether_link_state *linkState)
966*cbe0a0c4SAugustin Cavalier {
967*cbe0a0c4SAugustin Cavalier 	uint8 registerValue = 0;
968*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadRegister(RegNSR, 1, &registerValue);
969*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
970*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error reading NSR register! %x\n", result);
971*cbe0a0c4SAugustin Cavalier 		return result;
972*cbe0a0c4SAugustin Cavalier 	}
973*cbe0a0c4SAugustin Cavalier 
974*cbe0a0c4SAugustin Cavalier 	if (registerValue & NSRSpeed10)
975*cbe0a0c4SAugustin Cavalier 		linkState->speed = 10000000;
976*cbe0a0c4SAugustin Cavalier 	else
977*cbe0a0c4SAugustin Cavalier 		linkState->speed = 100000000;
978*cbe0a0c4SAugustin Cavalier 
979*cbe0a0c4SAugustin Cavalier 	linkState->quality = 1000;
980*cbe0a0c4SAugustin Cavalier 
981*cbe0a0c4SAugustin Cavalier 	linkState->media = IFM_ETHER | IFM_100_TX;
982*cbe0a0c4SAugustin Cavalier 	if (fHasConnection) {
983*cbe0a0c4SAugustin Cavalier 		linkState->media |= IFM_ACTIVE;
984*cbe0a0c4SAugustin Cavalier 		result = _ReadRegister(RegNCR, 1, &registerValue);
985*cbe0a0c4SAugustin Cavalier 		if (result != B_OK) {
986*cbe0a0c4SAugustin Cavalier 			TRACE_ALWAYS("Error reading NCR register! %x\n", result);
987*cbe0a0c4SAugustin Cavalier 			return result;
988*cbe0a0c4SAugustin Cavalier 		}
989*cbe0a0c4SAugustin Cavalier 
990*cbe0a0c4SAugustin Cavalier 		if (registerValue & NCRFullDX)
991*cbe0a0c4SAugustin Cavalier 			linkState->media |= IFM_FULL_DUPLEX;
992*cbe0a0c4SAugustin Cavalier 		else
993*cbe0a0c4SAugustin Cavalier 			linkState->media |= IFM_HALF_DUPLEX;
994*cbe0a0c4SAugustin Cavalier 
995*cbe0a0c4SAugustin Cavalier 		if (registerValue & NCRLoopback)
996*cbe0a0c4SAugustin Cavalier 			linkState->media |= IFM_LOOP;
997*cbe0a0c4SAugustin Cavalier 	}
998*cbe0a0c4SAugustin Cavalier 
999*cbe0a0c4SAugustin Cavalier 	TRACE_STATE("Medium state: %s, %lld MBit/s, %s duplex.\n",
1000*cbe0a0c4SAugustin Cavalier 						(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
1001*cbe0a0c4SAugustin Cavalier 						linkState->speed / 1000000,
1002*cbe0a0c4SAugustin Cavalier 						(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
1003*cbe0a0c4SAugustin Cavalier 
1004*cbe0a0c4SAugustin Cavalier 	TRACE_STATS("tx:%d rx:%d rxCn:%d rtF:%d lRxC:%d rwTO:%d PLE:%d AE:%d CE:%d "
1005*cbe0a0c4SAugustin Cavalier 				"oE:%d ltxC:%d lCR:%d nC:%d txC:%d exC:%d r:%d w:%d n:%d\n",
1006*cbe0a0c4SAugustin Cavalier 					fStats.txFull, fStats.rxOverflow, fStats.rxOvCount,
1007*cbe0a0c4SAugustin Cavalier 					fStats.runtFrames, fStats.lateRXCollisions, fStats.rwTOs,
1008*cbe0a0c4SAugustin Cavalier 					fStats.physLayerErros, fStats.alignmentErros,
1009*cbe0a0c4SAugustin Cavalier 					fStats.crcErrors, fStats.overErrors,
1010*cbe0a0c4SAugustin Cavalier 					fStats.lateTXCollisions, fStats.lostOfCarrier,
1011*cbe0a0c4SAugustin Cavalier 					fStats.noCarrier, fStats.txCollisions, fStats.excCollisions,
1012*cbe0a0c4SAugustin Cavalier 					fStats.readCount, fStats.writeCount, fStats.notifyCount);
1013*cbe0a0c4SAugustin Cavalier 	return B_OK;
1014*cbe0a0c4SAugustin Cavalier }
1015*cbe0a0c4SAugustin Cavalier 
1016*cbe0a0c4SAugustin Cavalier 
1017*cbe0a0c4SAugustin Cavalier status_t
_ReadRegister(uint8 reg,size_t size,uint8 * buffer)1018*cbe0a0c4SAugustin Cavalier DavicomDevice::_ReadRegister(uint8 reg, size_t size, uint8* buffer)
1019*cbe0a0c4SAugustin Cavalier {
1020*cbe0a0c4SAugustin Cavalier 	if (size > 255)
1021*cbe0a0c4SAugustin Cavalier 		return B_BAD_VALUE;
1022*cbe0a0c4SAugustin Cavalier 
1023*cbe0a0c4SAugustin Cavalier 	size_t actualLength = 0;
1024*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->send_request(fDevice,
1025*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
1026*cbe0a0c4SAugustin Cavalier 		ReqReadRegister, 0, reg, size, buffer, &actualLength);
1027*cbe0a0c4SAugustin Cavalier 
1028*cbe0a0c4SAugustin Cavalier 	if (size != actualLength) {
1029*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Size mismatch reading register ! asked %d got %d",
1030*cbe0a0c4SAugustin Cavalier 			size, actualLength);
1031*cbe0a0c4SAugustin Cavalier 	}
1032*cbe0a0c4SAugustin Cavalier 
1033*cbe0a0c4SAugustin Cavalier 	return result;
1034*cbe0a0c4SAugustin Cavalier }
1035*cbe0a0c4SAugustin Cavalier 
1036*cbe0a0c4SAugustin Cavalier 
1037*cbe0a0c4SAugustin Cavalier status_t
_WriteRegister(uint8 reg,size_t size,uint8 * buffer)1038*cbe0a0c4SAugustin Cavalier DavicomDevice::_WriteRegister(uint8 reg, size_t size, uint8* buffer)
1039*cbe0a0c4SAugustin Cavalier {
1040*cbe0a0c4SAugustin Cavalier 	if (size > 255)
1041*cbe0a0c4SAugustin Cavalier 		return B_BAD_VALUE;
1042*cbe0a0c4SAugustin Cavalier 
1043*cbe0a0c4SAugustin Cavalier 	size_t actualLength = 0;
1044*cbe0a0c4SAugustin Cavalier 
1045*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->send_request(fDevice,
1046*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
1047*cbe0a0c4SAugustin Cavalier 		ReqWriteRegister, 0, reg, size, buffer, &actualLength);
1048*cbe0a0c4SAugustin Cavalier 
1049*cbe0a0c4SAugustin Cavalier 	return result;
1050*cbe0a0c4SAugustin Cavalier }
1051*cbe0a0c4SAugustin Cavalier 
1052*cbe0a0c4SAugustin Cavalier 
1053*cbe0a0c4SAugustin Cavalier status_t
_Write1Register(uint8 reg,uint8 value)1054*cbe0a0c4SAugustin Cavalier DavicomDevice::_Write1Register(uint8 reg, uint8 value)
1055*cbe0a0c4SAugustin Cavalier {
1056*cbe0a0c4SAugustin Cavalier 	size_t actualLength = 0;
1057*cbe0a0c4SAugustin Cavalier 
1058*cbe0a0c4SAugustin Cavalier 	status_t result = gUSBModule->send_request(fDevice,
1059*cbe0a0c4SAugustin Cavalier 		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
1060*cbe0a0c4SAugustin Cavalier 		ReqWriteRegisterByte, value, reg, 0, NULL, &actualLength);
1061*cbe0a0c4SAugustin Cavalier 
1062*cbe0a0c4SAugustin Cavalier 	return result;
1063*cbe0a0c4SAugustin Cavalier }
1064*cbe0a0c4SAugustin Cavalier 
1065*cbe0a0c4SAugustin Cavalier 
1066*cbe0a0c4SAugustin Cavalier status_t
_ReadMII(uint8 reg,uint16 * data)1067*cbe0a0c4SAugustin Cavalier DavicomDevice::_ReadMII(uint8 reg, uint16* data)
1068*cbe0a0c4SAugustin Cavalier {
1069*cbe0a0c4SAugustin Cavalier 	// select PHY and set PHY register address
1070*cbe0a0c4SAugustin Cavalier 	status_t result = _Write1Register(RegEPAR, EPARIntPHY | (reg & EPARMask));
1071*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1072*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, result);
1073*cbe0a0c4SAugustin Cavalier 		return result;
1074*cbe0a0c4SAugustin Cavalier 	}
1075*cbe0a0c4SAugustin Cavalier 
1076*cbe0a0c4SAugustin Cavalier 	// select PHY operation and initiate reading
1077*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegEPCR, EPCROpSelect | EPCRRegRead);
1078*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1079*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to starting MII reading. Error:%#x\n", result);
1080*cbe0a0c4SAugustin Cavalier 		return result;
1081*cbe0a0c4SAugustin Cavalier 	}
1082*cbe0a0c4SAugustin Cavalier 
1083*cbe0a0c4SAugustin Cavalier 	// finalize writing
1084*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
1085*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegEPCR, 1, &control);
1086*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1087*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result);
1088*cbe0a0c4SAugustin Cavalier 		return result;
1089*cbe0a0c4SAugustin Cavalier 	}
1090*cbe0a0c4SAugustin Cavalier 
1091*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegEPCR, control & ~EPCRRegRead);
1092*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1093*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result);
1094*cbe0a0c4SAugustin Cavalier 		return result;
1095*cbe0a0c4SAugustin Cavalier 	}
1096*cbe0a0c4SAugustin Cavalier 
1097*cbe0a0c4SAugustin Cavalier 	// retrieve the result from data registers
1098*cbe0a0c4SAugustin Cavalier 	uint8 values[2] = { 0 };
1099*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegEPDRL, 2, values);
1100*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1101*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to retrieve data %#x. Error:%#x\n", data, result);
1102*cbe0a0c4SAugustin Cavalier 		return result;
1103*cbe0a0c4SAugustin Cavalier 	}
1104*cbe0a0c4SAugustin Cavalier 
1105*cbe0a0c4SAugustin Cavalier 	*data = values[0] | values[1] << 8;
1106*cbe0a0c4SAugustin Cavalier 	return result;
1107*cbe0a0c4SAugustin Cavalier }
1108*cbe0a0c4SAugustin Cavalier 
1109*cbe0a0c4SAugustin Cavalier 
1110*cbe0a0c4SAugustin Cavalier status_t
_WriteMII(uint8 reg,uint16 data)1111*cbe0a0c4SAugustin Cavalier DavicomDevice::_WriteMII(uint8 reg, uint16 data)
1112*cbe0a0c4SAugustin Cavalier {
1113*cbe0a0c4SAugustin Cavalier 	// select PHY and set PHY register address
1114*cbe0a0c4SAugustin Cavalier 	status_t result = _Write1Register(RegEPAR, EPARIntPHY | (reg & EPARMask));
1115*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1116*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, result);
1117*cbe0a0c4SAugustin Cavalier 		return result;
1118*cbe0a0c4SAugustin Cavalier 	}
1119*cbe0a0c4SAugustin Cavalier 
1120*cbe0a0c4SAugustin Cavalier 	// put the value to data register
1121*cbe0a0c4SAugustin Cavalier 	uint8 values[] = { (uint8)(data & 0xff), (uint8)((data >> 8) & 0xff) };
1122*cbe0a0c4SAugustin Cavalier 	result = _WriteRegister(RegEPDRL, sizeof(uint16), values);
1123*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1124*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to put data %#x. Error:%#x\n", data, result);
1125*cbe0a0c4SAugustin Cavalier 		return result;
1126*cbe0a0c4SAugustin Cavalier 	}
1127*cbe0a0c4SAugustin Cavalier 
1128*cbe0a0c4SAugustin Cavalier 	// select PHY operation and initiate writing
1129*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegEPCR, EPCROpSelect | EPCRRegWrite);
1130*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1131*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to starting MII wrintig. Error:%#x\n", result);
1132*cbe0a0c4SAugustin Cavalier 		return result;
1133*cbe0a0c4SAugustin Cavalier 	}
1134*cbe0a0c4SAugustin Cavalier 
1135*cbe0a0c4SAugustin Cavalier 	// finalize writing
1136*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
1137*cbe0a0c4SAugustin Cavalier 	result = _ReadRegister(RegEPCR, 1, &control);
1138*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1139*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result);
1140*cbe0a0c4SAugustin Cavalier 		return result;
1141*cbe0a0c4SAugustin Cavalier 	}
1142*cbe0a0c4SAugustin Cavalier 
1143*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegEPCR, control & ~EPCRRegWrite);
1144*cbe0a0c4SAugustin Cavalier 	if (result != B_OK)
1145*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result);
1146*cbe0a0c4SAugustin Cavalier 
1147*cbe0a0c4SAugustin Cavalier 	return result;
1148*cbe0a0c4SAugustin Cavalier }
1149*cbe0a0c4SAugustin Cavalier 
1150*cbe0a0c4SAugustin Cavalier 
1151*cbe0a0c4SAugustin Cavalier status_t
_InitMII()1152*cbe0a0c4SAugustin Cavalier DavicomDevice::_InitMII()
1153*cbe0a0c4SAugustin Cavalier {
1154*cbe0a0c4SAugustin Cavalier 	uint16 control = 0;
1155*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadMII(RegBMCR, &control);
1156*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1157*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to read MII BMCR register. Error:%#x\n", result);
1158*cbe0a0c4SAugustin Cavalier 		return result;
1159*cbe0a0c4SAugustin Cavalier 	}
1160*cbe0a0c4SAugustin Cavalier 
1161*cbe0a0c4SAugustin Cavalier 	result = _WriteMII(RegBMCR, control & ~BMCRIsolate);
1162*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1163*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to clear isolate PHY. Error:%#x\n", result);
1164*cbe0a0c4SAugustin Cavalier 		return result;
1165*cbe0a0c4SAugustin Cavalier 	}
1166*cbe0a0c4SAugustin Cavalier 
1167*cbe0a0c4SAugustin Cavalier 	result = _WriteMII(0, BMCRReset);
1168*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1169*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to reset BMCR register. Error:%#x\n", result);
1170*cbe0a0c4SAugustin Cavalier 		return result;
1171*cbe0a0c4SAugustin Cavalier 	}
1172*cbe0a0c4SAugustin Cavalier 
1173*cbe0a0c4SAugustin Cavalier 	uint16 id01 = 0, id02 = 0;
1174*cbe0a0c4SAugustin Cavalier 	result = _ReadMII(RegPHYID1, &id01);
1175*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1176*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to read PHY ID 0. Error:%#x\n", result);
1177*cbe0a0c4SAugustin Cavalier 		return result;
1178*cbe0a0c4SAugustin Cavalier 	}
1179*cbe0a0c4SAugustin Cavalier 
1180*cbe0a0c4SAugustin Cavalier 	result = _ReadMII(RegPHYID2, &id02);
1181*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1182*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Failed to read PHY ID 1. Error:%#x\n", result);
1183*cbe0a0c4SAugustin Cavalier 		return result;
1184*cbe0a0c4SAugustin Cavalier 	}
1185*cbe0a0c4SAugustin Cavalier 
1186*cbe0a0c4SAugustin Cavalier 	TRACE_ALWAYS("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n",
1187*cbe0a0c4SAugustin Cavalier 			MII_OUI(id01, id02), MII_MODEL(id02), MII_REV(id02));
1188*cbe0a0c4SAugustin Cavalier 
1189*cbe0a0c4SAugustin Cavalier 	return result;
1190*cbe0a0c4SAugustin Cavalier }
1191*cbe0a0c4SAugustin Cavalier 
1192*cbe0a0c4SAugustin Cavalier 
1193*cbe0a0c4SAugustin Cavalier status_t
_EnableInterrupts(bool enable)1194*cbe0a0c4SAugustin Cavalier DavicomDevice::_EnableInterrupts(bool enable)
1195*cbe0a0c4SAugustin Cavalier {
1196*cbe0a0c4SAugustin Cavalier 	uint8 control = 0;
1197*cbe0a0c4SAugustin Cavalier 	status_t result = _ReadRegister(RegUSBC, 1, &control);
1198*cbe0a0c4SAugustin Cavalier 	if (result != B_OK) {
1199*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of reading USB control register:%#010x\n", result);
1200*cbe0a0c4SAugustin Cavalier 		return result;
1201*cbe0a0c4SAugustin Cavalier 	}
1202*cbe0a0c4SAugustin Cavalier 
1203*cbe0a0c4SAugustin Cavalier 	if (enable) {
1204*cbe0a0c4SAugustin Cavalier 		control |= USBCIntAck;
1205*cbe0a0c4SAugustin Cavalier 		control &= ~USBCIntNAck;
1206*cbe0a0c4SAugustin Cavalier 	} else {
1207*cbe0a0c4SAugustin Cavalier 		control &= ~USBCIntAck;
1208*cbe0a0c4SAugustin Cavalier 	}
1209*cbe0a0c4SAugustin Cavalier 
1210*cbe0a0c4SAugustin Cavalier 	result = _Write1Register(RegUSBC, control);
1211*cbe0a0c4SAugustin Cavalier 	if (result != B_OK)
1212*cbe0a0c4SAugustin Cavalier 		TRACE_ALWAYS("Error of setting USB control register:%#010x\n", result);
1213*cbe0a0c4SAugustin Cavalier 
1214*cbe0a0c4SAugustin Cavalier 	return result;
1215*cbe0a0c4SAugustin Cavalier }
1216*cbe0a0c4SAugustin Cavalier 
1217