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