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.
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.
14 #include "DavicomDevice.h"
17 #include <net/if_media.h>
23 const int kFrameSize
= 1522;
28 ReqWriteRegisterByte
= 3,
32 enum 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
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
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
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
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]
60 RegEPDRL
= 0x0d, // EEPROM & PHY Low Byte Data Register
62 RegEPDRH
= 0x0e, // EEPROM & PHY Low Byte Data Register
64 RegPAR
= 0x10, // [0x10 - 0x15] Physical Address Register
66 RegMAR
= 0x16, // [0x16 - 0x1d] Multicast Address Register
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
72 RegGPR
= 0x1F, // General Purpose Register
73 GPRPowerDownInPHY
= 0x01, // Power down Internal PHY
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
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)
97 DavicomDevice::DavicomDevice(usb_device device
, DeviceInfo
& deviceInfo
)
102 fHasConnection(false),
103 fTXBufferFull(false),
110 fActualLengthRead(0),
111 fActualLengthWrite(0),
116 fLinkStateChangeSem(-1),
119 fDeviceInfo
= deviceInfo
;
121 memset(&fMACAddress
, 0, sizeof(fMACAddress
));
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",
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",
137 fNotifyData
= new DM9601NotifyData();
138 if (fNotifyData
== NULL
) {
139 TRACE_ALWAYS("Error allocating notify buffer\n");
143 if (_SetupEndpoints() != B_OK
) {
154 DavicomDevice::~DavicomDevice()
156 if (fNotifyReadSem
>= B_OK
)
157 delete_sem(fNotifyReadSem
);
158 if (fNotifyWriteSem
>= B_OK
)
159 delete_sem(fNotifyWriteSem
);
161 if (!fRemoved
) // ???
162 gUSBModule
->cancel_queued_transfers(fNotifyEndpoint
);
170 DavicomDevice::Open(uint32 flags
)
177 status_t result
= _StartDevice();
178 if (result
!= B_OK
) {
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
);
190 result
= _EnableInterrupts(true);
192 fNonBlocking
= (flags
& O_NONBLOCK
) == O_NONBLOCK
;
194 TRACE("Opened: %#010x!\n", result
);
200 DavicomDevice::Close()
207 _EnableInterrupts(false);
209 // wait until possible notification handling finished...
210 while (atomic_add(&fInsideNotify
, 0) != 0)
212 gUSBModule
->cancel_queued_transfers(fNotifyEndpoint
);
213 gUSBModule
->cancel_queued_transfers(fReadEndpoint
);
214 gUSBModule
->cancel_queued_transfers(fWriteEndpoint
);
218 status_t result
= _StopDevice();
219 TRACE("Closed: %#010x!\n", result
);
225 DavicomDevice::Free()
233 DavicomDevice::Read(uint8
*buffer
, size_t *numBytes
)
235 size_t numBytesToRead
= *numBytes
;
239 TRACE_ALWAYS("Error of receiving %d bytes from removed device.\n",
241 return B_DEVICE_NOT_FOUND
;
244 TRACE_RX("Request %d bytes.\n", numBytesToRead
);
258 uint8
Errors() { return 0xbf & *(uint8
*)this; }
259 } __attribute__((__packed__
));
261 _RXHeader header
= { 0 };
264 { &header
, sizeof(header
) },
265 { buffer
, numBytesToRead
}
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
);
275 uint32 flags
= B_CAN_INTERRUPT
| (fNonBlocking
? B_TIMEOUT
: 0);
276 result
= acquire_sem_etc(fNotifyReadSem
, 1, flags
, 0);
278 TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result
);
282 if (fStatusRead
!= B_OK
&& fStatusRead
!= B_CANCELED
&& !fRemoved
) {
283 TRACE_ALWAYS("Device status error:%#010x\n", fStatusRead
);
287 if (fActualLengthRead
< sizeof(_RXHeader
)) {
288 TRACE_ALWAYS("Error: no place for RXHeader: only %d of %d bytes.\n",
289 fActualLengthRead
, sizeof(_RXHeader
));
293 if (header
.Errors() != 0) {
294 TRACE_ALWAYS("RX header errors %#04x detected!\n", header
.Errors());
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
);
301 *numBytes
= header
.countLow
| ( header
.countHigh
<< 8 );
303 if (fActualLengthRead
- sizeof(_RXHeader
) > *numBytes
) {
304 TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; received:%d\n",
305 *numBytes
, fActualLengthRead
- sizeof(_RXHeader
));
308 TRACE_RX("Read %d bytes.\n", *numBytes
);
314 DavicomDevice::Write(const uint8
*buffer
, size_t *numBytes
)
316 size_t numBytesToWrite
= *numBytes
;
320 TRACE_ALWAYS("Error of writing %d bytes to removed device.\n",
322 return B_DEVICE_NOT_FOUND
;
325 if (!fHasConnection
) {
326 TRACE_ALWAYS("Error of writing %d bytes to device while down.\n",
332 TRACE_ALWAYS("Error of writing %d bytes to device: TX buffer full.\n",
337 TRACE_TX("Write %d bytes.\n", numBytesToWrite
);
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
;
343 if (((numBytesToWrite
+ 2) % fMaxTXPacketSize
) == 0) {
351 } __attribute__((__packed__
));
353 _TXHeader header
= { (uint8
)(length
& 0xff),
354 (uint8
)((length
>> 8) & 0xff) };
359 { &header
, sizeof(_TXHeader
) },
360 { (uint8
*)buffer
, numBytesToWrite
},
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
);
371 result
= acquire_sem_etc(fNotifyWriteSem
, 1, B_CAN_INTERRUPT
, 0);
374 TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result
);
378 if (fStatusWrite
!= B_OK
&& fStatusWrite
!= B_CANCELED
&& !fRemoved
) {
379 TRACE_ALWAYS("Device status error:%#010x\n", fStatusWrite
);
383 *numBytes
= fActualLengthWrite
- sizeof(_TXHeader
);
385 TRACE_TX("Written %d bytes.\n", *numBytes
);
391 DavicomDevice::Control(uint32 op
, void *buffer
, size_t length
)
398 memcpy(buffer
, &fMACAddress
, sizeof(fMACAddress
));
401 case ETHER_GETFRAMESIZE
:
402 *(uint32
*)buffer
= kFrameSize
;
406 TRACE("ETHER_NONBLOCK\n");
407 fNonBlocking
= *((uint8
*)buffer
);
410 case ETHER_SETPROMISC
:
411 TRACE("ETHER_SETPROMISC\n");
412 return _SetPromiscuousMode(*((uint8
*)buffer
));
415 TRACE("ETHER_ADDMULTI\n");
416 return _ModifyMulticastTable(true, (ether_address_t
*)buffer
);
419 TRACE("ETHER_REMMULTI\n");
420 return _ModifyMulticastTable(false, (ether_address_t
*)buffer
);
422 case ETHER_SET_LINK_STATE_SEM
:
423 fLinkStateChangeSem
= *(sem_id
*)buffer
;
426 case ETHER_GET_LINK_STATE
:
427 return _GetLinkState((ether_link_state
*)buffer
);
430 TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op
);
433 return B_DEV_INVALID_IOCTL
;
438 DavicomDevice::Removed()
441 fHasConnection
= false;
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)
452 gUSBModule
->cancel_queued_transfers(fNotifyEndpoint
);
453 gUSBModule
->cancel_queued_transfers(fReadEndpoint
);
454 gUSBModule
->cancel_queued_transfers(fWriteEndpoint
);
456 if (fLinkStateChangeSem
>= B_OK
)
457 release_sem_etc(fLinkStateChangeSem
, 1, B_DO_NOT_RESCHEDULE
);
462 DavicomDevice::SetupDevice(bool deviceReplugged
)
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
);
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]);
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
487 fMACAddress
= address
;
494 DavicomDevice::CompareAndReattach(usb_device device
)
496 const usb_device_descriptor
*deviceDescriptor
497 = gUSBModule
->get_device_descriptor(device
);
499 if (deviceDescriptor
== NULL
) {
500 TRACE_ALWAYS("Error getting USB device descriptor.\n");
504 if (deviceDescriptor
->vendor_id
!= fDeviceInfo
.VendorId()
505 && deviceDescriptor
->product_id
!= fDeviceInfo
.ProductId()) {
506 // this certainly isn't the same device
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
515 status_t result
= _SetupEndpoints();
516 if (result
!= B_OK
) {
521 // we need to setup hardware on device replug
522 result
= SetupDevice(true);
523 if (result
!= B_OK
) {
529 result
= Open(fNonBlocking
? O_NONBLOCK
: 0);
537 DavicomDevice::_SetupEndpoints()
539 const usb_configuration_info
*config
540 = gUSBModule
->get_nth_configuration(fDevice
, 0);
542 if (config
== NULL
) {
543 TRACE_ALWAYS("Error of getting USB device configuration.\n");
547 if (config
->interface_count
<= 0) {
548 TRACE_ALWAYS("Error:no interfaces found in USB device configuration\n");
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");
559 int notifyEndpoint
= -1;
560 int readEndpoint
= -1;
561 int writeEndpoint
= -1;
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
)
572 if ((epd
->attributes
& USB_ENDPOINT_ATTR_MASK
)
573 != USB_ENDPOINT_ATTR_BULK
)
575 TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n",
580 if ((epd
->endpoint_address
& USB_ENDPOINT_ADDR_DIR_IN
)
581 == USB_ENDPOINT_ADDR_DIR_IN
)
587 if ((epd
->endpoint_address
& USB_ENDPOINT_ADDR_DIR_OUT
)
588 == USB_ENDPOINT_ADDR_DIR_OUT
)
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
);
601 gUSBModule
->set_configuration(fDevice
, config
);
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
;
613 DavicomDevice::_ReadMACAddress(ether_address_t
*address
)
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
);
627 DavicomDevice::_StartDevice()
632 status_t result
= _ReadRegister(RegNCR
, 1, &control
);
633 if (result
!= B_OK
) {
634 TRACE_ALWAYS("Error reading NCR: %#010x.\n", result
);
638 if (control
& NCRExtPHY
)
639 TRACE_ALWAYS("Device uses external PHY\n");
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
);
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
);
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
);
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
);
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
);
677 result
= _ReadRegister(RegGPR
, 1, &control
);
678 if (result
!= B_OK
) {
679 TRACE_ALWAYS("Error reading GPR: %#010x.\n", result
);
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
);
695 DavicomDevice::_StopDevice()
700 status_t result
= _ReadRegister(RegRCR
, 1, &control
);
701 if (result
!= B_OK
) {
702 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result
);
706 control
&= ~RCRRXEnable
;
707 result
= _Write1Register(RegRCR
, control
);
709 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control
, result
);
716 DavicomDevice::_SetPromiscuousMode(bool on
)
720 status_t result
= _ReadRegister(RegRCR
, 1, &control
);
721 if (result
!= B_OK
) {
722 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result
);
727 control
|= RCRPromiscuous
;
729 control
&= ~RCRPromiscuous
;
731 result
= _Write1Register(RegRCR
, control
);
733 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control
, result
);
740 DavicomDevice::_EthernetCRC32(const uint8
* buffer
, size_t length
)
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);
749 result
= (result
^ 0x04c11db6) | carry
;
757 DavicomDevice::_ModifyMulticastTable(bool join
, ether_address_t
*group
)
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
);
765 uint32 hash
= _EthernetCRC32(group
->ebyte
, 6);
766 bool isInTable
= fMulticastHashes
.Find(hash
) != fMulticastHashes
.End();
768 if (isInTable
&& join
)
769 return B_OK
; // already listed - nothing to do
771 if (!isInTable
&& !join
) {
772 TRACE_ALWAYS("Cannot leave unlisted multicast group %s!\n", groupName
);
776 const size_t hashLength
= 8;
777 uint8 hashTable
[hashLength
] = { 0 };
778 hashTable
[hashLength
- 1] |= 0x80; // broadcast address
780 status_t result
= _WriteRegister(RegMAR
, hashLength
, hashTable
);
781 if (result
!= B_OK
) {
782 TRACE_ALWAYS("Error initializing MAR: %#010x.\n", result
);
787 fMulticastHashes
.PushBack(hash
);
789 fMulticastHashes
.Remove(hash
);
791 for (int32 i
= 0; i
< fMulticastHashes
.Count(); i
++) {
792 uint32 hash
= fMulticastHashes
[i
] >> 26;
793 hashTable
[hash
/ 8] |= 1 << (hash
% 8);
796 // clear/set pass all multicast bit as required
798 result
= _ReadRegister(RegRCR
, 1, &control
);
799 if (result
!= B_OK
) {
800 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result
);
804 if (fMulticastHashes
.Count() > 0)
805 control
&= ~RCRAllMulticast
;
807 control
|= RCRAllMulticast
;
809 result
= _Write1Register(RegRCR
, control
);
810 if (result
!= B_OK
) {
811 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control
, result
);
815 result
= _WriteRegister(RegMAR
, hashLength
, hashTable
);
817 TRACE_ALWAYS("Error writing hash table in MAR: %#010x.\n", result
);
824 DavicomDevice::_ReadCallback(void *cookie
, int32 status
, void *data
,
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
);
837 DavicomDevice::_WriteCallback(void *cookie
, int32 status
, void *data
,
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
);
850 DavicomDevice::_NotifyCallback(void *cookie
, int32 status
, void *data
,
853 DavicomDevice
*device
= (DavicomDevice
*)cookie
;
854 atomic_add(&device
->fInsideNotify
, 1);
855 if (status
== B_CANCELED
|| device
->fRemoved
) {
856 atomic_add(&device
->fInsideNotify
, -1);
861 device
->_OnNotify(actualLength
);
863 TRACE_ALWAYS("Status error:%#010x; length:%d\n", status
, actualLength
);
865 // schedule next notification buffer
866 gUSBModule
->queue_interrupt(device
->fNotifyEndpoint
, device
->fNotifyData
,
867 sizeof(DM9601NotifyData
), _NotifyCallback
, device
);
868 atomic_add(&device
->fInsideNotify
, -1);
873 DavicomDevice::_OnNotify(uint32 actualLength
)
875 if (actualLength
!= sizeof(DM9601NotifyData
)) {
876 TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n",
877 actualLength
, sizeof(DM9601NotifyData
));
881 bool linkIsUp
= fNotifyData
->LINKST
!= 0;
882 fTXBufferFull
= fNotifyData
->TXFULL
!= 0;
883 bool rxOverflow
= fNotifyData
->RXOV
!= 0;
885 bool linkStateChange
= (linkIsUp
!= fHasConnection
);
886 fHasConnection
= linkIsUp
;
888 if (linkStateChange
) {
889 if (fHasConnection
) {
890 TRACE("Link is now up at %s Mb/s\n",
891 fNotifyData
->SPEED
? "10" : "100");
893 TRACE("Link is now down");
898 if (fNotifyData
->TXFULL
)
900 if (fNotifyData
->RXOV
)
903 if (fNotifyData
->ROC
)
904 fStats
.rxOvCount
+= fNotifyData
->ROC
;
908 if (fNotifyData
->LCS
)
909 fStats
.lateRXCollisions
++;
910 if (fNotifyData
->RWTO
)
912 if (fNotifyData
->PLE
)
913 fStats
.physLayerErros
++;
915 fStats
.alignmentErros
++;
918 if (fNotifyData
->FOE
)
921 if (fNotifyData
->TSR1
.LC
)
922 fStats
.lateTXCollisions
++;
923 if (fNotifyData
->TSR1
.LCR
)
924 fStats
.lostOfCarrier
++;
925 if (fNotifyData
->TSR1
.NC
)
927 if (fNotifyData
->TSR1
.COL
)
928 fStats
.txCollisions
++;
929 if (fNotifyData
->TSR1
.EC
)
930 fStats
.excCollisions
++;
932 if (fNotifyData
->TSR2
.LC
)
933 fStats
.lateTXCollisions
++;
934 if (fNotifyData
->TSR2
.LCR
)
935 fStats
.lostOfCarrier
++;
936 if (fNotifyData
->TSR2
.NC
)
938 if (fNotifyData
->TSR2
.COL
)
939 fStats
.txCollisions
++;
940 if (fNotifyData
->TSR2
.EC
)
941 fStats
.excCollisions
++;
943 fStats
.notifyCount
++;
948 TRACE("RX buffer overflow. %d packets dropped\n", fNotifyData
->ROC
);
950 uint8 tsr
= 0xfc & *(uint8
*)&fNotifyData
->TSR1
;
952 TRACE("TX packet 1: Status %#04x is not OK.\n", tsr
);
954 tsr
= 0xfc & *(uint8
*)&fNotifyData
->TSR2
;
956 TRACE("TX packet 2: Status %#04x is not OK.\n", tsr
);
958 if (linkStateChange
&& fLinkStateChangeSem
>= B_OK
)
959 release_sem_etc(fLinkStateChangeSem
, 1, B_DO_NOT_RESCHEDULE
);
965 DavicomDevice::_GetLinkState(ether_link_state
*linkState
)
967 uint8 registerValue
= 0;
968 status_t result
= _ReadRegister(RegNSR
, 1, ®isterValue
);
969 if (result
!= B_OK
) {
970 TRACE_ALWAYS("Error reading NSR register! %x\n", result
);
974 if (registerValue
& NSRSpeed10
)
975 linkState
->speed
= 10000000;
977 linkState
->speed
= 100000000;
979 linkState
->quality
= 1000;
981 linkState
->media
= IFM_ETHER
| IFM_100_TX
;
982 if (fHasConnection
) {
983 linkState
->media
|= IFM_ACTIVE
;
984 result
= _ReadRegister(RegNCR
, 1, ®isterValue
);
985 if (result
!= B_OK
) {
986 TRACE_ALWAYS("Error reading NCR register! %x\n", result
);
990 if (registerValue
& NCRFullDX
)
991 linkState
->media
|= IFM_FULL_DUPLEX
;
993 linkState
->media
|= IFM_HALF_DUPLEX
;
995 if (registerValue
& NCRLoopback
)
996 linkState
->media
|= IFM_LOOP
;
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");
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
);
1018 DavicomDevice::_ReadRegister(uint8 reg
, size_t size
, uint8
* buffer
)
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
);
1028 if (size
!= actualLength
) {
1029 TRACE_ALWAYS("Size mismatch reading register ! asked %d got %d",
1030 size
, actualLength
);
1038 DavicomDevice::_WriteRegister(uint8 reg
, size_t size
, uint8
* buffer
)
1043 size_t actualLength
= 0;
1045 status_t result
= gUSBModule
->send_request(fDevice
,
1046 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
,
1047 ReqWriteRegister
, 0, reg
, size
, buffer
, &actualLength
);
1054 DavicomDevice::_Write1Register(uint8 reg
, uint8 value
)
1056 size_t actualLength
= 0;
1058 status_t result
= gUSBModule
->send_request(fDevice
,
1059 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
,
1060 ReqWriteRegisterByte
, value
, reg
, 0, NULL
, &actualLength
);
1067 DavicomDevice::_ReadMII(uint8 reg
, uint16
* data
)
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
);
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
);
1085 result
= _ReadRegister(RegEPCR
, 1, &control
);
1086 if (result
!= B_OK
) {
1087 TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result
);
1091 result
= _Write1Register(RegEPCR
, control
& ~EPCRRegRead
);
1092 if (result
!= B_OK
) {
1093 TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result
);
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
);
1105 *data
= values
[0] | values
[1] << 8;
1111 DavicomDevice::_WriteMII(uint8 reg
, uint16 data
)
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
);
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
);
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
);
1137 result
= _ReadRegister(RegEPCR
, 1, &control
);
1138 if (result
!= B_OK
) {
1139 TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result
);
1143 result
= _Write1Register(RegEPCR
, control
& ~EPCRRegWrite
);
1145 TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result
);
1152 DavicomDevice::_InitMII()
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
);
1161 result
= _WriteMII(RegBMCR
, control
& ~BMCRIsolate
);
1162 if (result
!= B_OK
) {
1163 TRACE_ALWAYS("Failed to clear isolate PHY. Error:%#x\n", result
);
1167 result
= _WriteMII(0, BMCRReset
);
1168 if (result
!= B_OK
) {
1169 TRACE_ALWAYS("Failed to reset BMCR register. Error:%#x\n", result
);
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
);
1180 result
= _ReadMII(RegPHYID2
, &id02
);
1181 if (result
!= B_OK
) {
1182 TRACE_ALWAYS("Failed to read PHY ID 1. Error:%#x\n", result
);
1186 TRACE_ALWAYS("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n",
1187 MII_OUI(id01
, id02
), MII_MODEL(id02
), MII_REV(id02
));
1194 DavicomDevice::_EnableInterrupts(bool enable
)
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
);
1204 control
|= USBCIntAck
;
1205 control
&= ~USBCIntNAck
;
1207 control
&= ~USBCIntAck
;
1210 result
= _Write1Register(RegUSBC
, control
);
1212 TRACE_ALWAYS("Error of setting USB control register:%#010x\n", result
);