vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / network / usb_davicom / DavicomDevice.cpp
blob9ceb5f987ad70fe5173f0e811f5be344207924ed
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.
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"
16 #include <stdio.h>
17 #include <net/if_media.h>
19 #include "Driver.h"
20 #include "Settings.h"
23 const int kFrameSize = 1522;
25 enum VendorRequests {
26 ReqReadRegister = 0,
27 ReqWriteRegister = 1,
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
82 enum MIIRegisters {
83 RegBMCR = 0x00,
84 BMCRIsolate = 0x0400,
85 BMCRReset = 0x8000,
87 RegBMSR = 0x01,
88 RegPHYID1 = 0x02,
89 RegPHYID2 = 0x03,
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)
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)
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",
126 fNotifyReadSem);
127 return;
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;
137 fNotifyData = new DM9601NotifyData();
138 if (fNotifyData == NULL) {
139 TRACE_ALWAYS("Error allocating notify buffer\n");
140 return;
143 if (_SetupEndpoints() != B_OK) {
144 return;
147 _InitMII();
149 fStatus = B_OK;
150 TRACE("Created!\n");
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);
164 delete fNotifyData;
165 TRACE("Deleted!\n");
169 status_t
170 DavicomDevice::Open(uint32 flags)
172 if (fOpen)
173 return B_BUSY;
174 if (fRemoved)
175 return B_ERROR;
177 status_t result = _StartDevice();
178 if (result != B_OK) {
179 return result;
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;
190 result = _EnableInterrupts(true);
192 fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK;
193 fOpen = true;
194 TRACE("Opened: %#010x!\n", result);
195 return result;
199 status_t
200 DavicomDevice::Close()
202 if (fRemoved) {
203 fOpen = false;
204 return B_OK;
207 _EnableInterrupts(false);
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);
216 fOpen = false;
218 status_t result = _StopDevice();
219 TRACE("Closed: %#010x!\n", result);
220 return result;
224 status_t
225 DavicomDevice::Free()
227 TRACE("Freed!\n");
228 return B_OK;
232 status_t
233 DavicomDevice::Read(uint8 *buffer, size_t *numBytes)
235 size_t numBytesToRead = *numBytes;
236 *numBytes = 0;
238 if (fRemoved) {
239 TRACE_ALWAYS("Error of receiving %d bytes from removed device.\n",
240 numBytesToRead);
241 return B_DEVICE_NOT_FOUND;
244 TRACE_RX("Request %d bytes.\n", numBytesToRead);
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;
258 uint8 Errors() { return 0xbf & *(uint8*)this; }
259 } __attribute__((__packed__));
261 _RXHeader header = { 0 };
263 iovec rxData[] = {
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);
272 return result;
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;
282 if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !fRemoved) {
283 TRACE_ALWAYS("Device status error:%#010x\n", fStatusRead);
284 return fStatusRead;
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;
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);
309 return B_OK;
313 status_t
314 DavicomDevice::Write(const uint8 *buffer, size_t *numBytes)
316 size_t numBytesToWrite = *numBytes;
317 *numBytes = 0;
319 if (fRemoved) {
320 TRACE_ALWAYS("Error of writing %d bytes to removed device.\n",
321 numBytesToWrite);
322 return B_DEVICE_NOT_FOUND;
325 if (!fHasConnection) {
326 TRACE_ALWAYS("Error of writing %d bytes to device while down.\n",
327 numBytesToWrite);
328 return B_ERROR;
331 if (fTXBufferFull) {
332 TRACE_ALWAYS("Error of writing %d bytes to device: TX buffer full.\n",
333 numBytesToWrite);
334 return B_ERROR;
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;
342 size_t count = 2;
343 if (((numBytesToWrite + 2) % fMaxTXPacketSize) == 0) {
344 length++;
345 count++;
348 struct _TXHeader {
349 uint8 countLow;
350 uint8 countHigh;
351 } __attribute__((__packed__));
353 _TXHeader header = { (uint8)(length & 0xff),
354 (uint8)((length >> 8) & 0xff) };
356 uint8 padding = 0;
358 iovec txData[] = {
359 { &header, sizeof(_TXHeader) },
360 { (uint8*)buffer, numBytesToWrite },
361 { &padding, 1 }
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;
371 result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0);
373 if (result < B_OK) {
374 TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result);
375 return result;
378 if (fStatusWrite != B_OK && fStatusWrite != B_CANCELED && !fRemoved) {
379 TRACE_ALWAYS("Device status error:%#010x\n", fStatusWrite);
380 return fStatusWrite;
383 *numBytes = fActualLengthWrite - sizeof(_TXHeader);
385 TRACE_TX("Written %d bytes.\n", *numBytes);
386 return B_OK;
390 status_t
391 DavicomDevice::Control(uint32 op, void *buffer, size_t length)
393 switch (op) {
394 case ETHER_INIT:
395 return B_OK;
397 case ETHER_GETADDR:
398 memcpy(buffer, &fMACAddress, sizeof(fMACAddress));
399 return B_OK;
401 case ETHER_GETFRAMESIZE:
402 *(uint32 *)buffer = kFrameSize;
403 return B_OK;
405 case ETHER_NONBLOCK:
406 TRACE("ETHER_NONBLOCK\n");
407 fNonBlocking = *((uint8*)buffer);
408 return B_OK;
410 case ETHER_SETPROMISC:
411 TRACE("ETHER_SETPROMISC\n");
412 return _SetPromiscuousMode(*((uint8*)buffer));
414 case ETHER_ADDMULTI:
415 TRACE("ETHER_ADDMULTI\n");
416 return _ModifyMulticastTable(true, (ether_address_t*)buffer);
418 case ETHER_REMMULTI:
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;
424 return B_OK;
426 case ETHER_GET_LINK_STATE:
427 return _GetLinkState((ether_link_state *)buffer);
429 default:
430 TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op);
433 return B_DEV_INVALID_IOCTL;
437 void
438 DavicomDevice::Removed()
440 fRemoved = true;
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)
450 snooze(100);
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);
461 status_t
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);
468 return 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
486 } else
487 fMACAddress = address;
489 return B_OK;
493 status_t
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");
501 return B_ERROR;
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;
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;
521 // we need to setup hardware on device replug
522 result = SetupDevice(true);
523 if (result != B_OK) {
524 return result;
527 if (fOpen) {
528 fOpen = false;
529 result = Open(fNonBlocking ? O_NONBLOCK : 0);
532 return result;
536 status_t
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");
544 return B_ERROR;
547 if (config->interface_count <= 0) {
548 TRACE_ALWAYS("Error:no interfaces found in USB device configuration\n");
549 return B_ERROR;
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;
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)
568 notifyEndpoint = ep;
569 continue;
572 if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
573 != USB_ENDPOINT_ATTR_BULK)
575 TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n",
576 epd->attributes);
577 continue;
580 if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
581 == USB_ENDPOINT_ADDR_DIR_IN)
583 readEndpoint = ep;
584 continue;
587 if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_OUT)
588 == USB_ENDPOINT_ADDR_DIR_OUT)
590 writeEndpoint = ep;
591 continue;
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;
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;
608 return B_OK;
612 status_t
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);
619 return result;
622 return B_OK;
626 status_t
627 DavicomDevice::_StartDevice()
629 uint8 control = 0;
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;
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);
645 return 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);
652 return 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);
660 return 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);
667 return 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);
674 return result;
677 result = _ReadRegister(RegGPR, 1, &control);
678 if (result != B_OK) {
679 TRACE_ALWAYS("Error reading GPR: %#010x.\n", result);
680 return 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);
687 return result;
690 return B_OK;
694 status_t
695 DavicomDevice::_StopDevice()
697 uint8 control = 0;
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;
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);
711 return result;
715 status_t
716 DavicomDevice::_SetPromiscuousMode(bool on)
718 uint8 control = 0;
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;
726 if (on)
727 control |= RCRPromiscuous;
728 else
729 control &= ~RCRPromiscuous;
731 result = _Write1Register(RegRCR, control);
732 if (result != B_OK)
733 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result);
735 return result;
739 uint32
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);
747 result <<= 1;
748 if (carry != 0)
749 result = (result ^ 0x04c11db6) | carry;
752 return result;
756 status_t
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);
773 return B_ERROR;
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);
783 return result;
786 if (join)
787 fMulticastHashes.PushBack(hash);
788 else
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
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;
804 if (fMulticastHashes.Count() > 0)
805 control &= ~RCRAllMulticast;
806 else
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);
812 return result;
815 result = _WriteRegister(RegMAR, hashLength, hashTable);
816 if (result != B_OK)
817 TRACE_ALWAYS("Error writing hash table in MAR: %#010x.\n", result);
819 return result;
823 void
824 DavicomDevice::_ReadCallback(void *cookie, int32 status, void *data,
825 size_t actualLength)
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);
836 void
837 DavicomDevice::_WriteCallback(void *cookie, int32 status, void *data,
838 size_t actualLength)
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);
849 void
850 DavicomDevice::_NotifyCallback(void *cookie, int32 status, void *data,
851 size_t actualLength)
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;
860 if (status == B_OK)
861 device->_OnNotify(actualLength);
862 else
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);
872 status_t
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));
878 return B_BAD_DATA;
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");
892 } else
893 TRACE("Link is now down");
896 #ifdef UDAV_TRACE
897 if (gTraceStats) {
898 if (fNotifyData->TXFULL)
899 fStats.txFull++;
900 if (fNotifyData->RXOV)
901 fStats.rxOverflow++;
903 if (fNotifyData->ROC)
904 fStats.rxOvCount += fNotifyData->ROC;
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++;
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++;
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++;
943 fStats.notifyCount++;
945 #endif
947 if (rxOverflow)
948 TRACE("RX buffer overflow. %d packets dropped\n", fNotifyData->ROC);
950 uint8 tsr = 0xfc & *(uint8*)&fNotifyData->TSR1;
951 if (tsr != 0)
952 TRACE("TX packet 1: Status %#04x is not OK.\n", tsr);
954 tsr = 0xfc & *(uint8*)&fNotifyData->TSR2;
955 if (tsr != 0)
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);
960 return B_OK;
964 status_t
965 DavicomDevice::_GetLinkState(ether_link_state *linkState)
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;
974 if (registerValue & NSRSpeed10)
975 linkState->speed = 10000000;
976 else
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, &registerValue);
985 if (result != B_OK) {
986 TRACE_ALWAYS("Error reading NCR register! %x\n", result);
987 return result;
990 if (registerValue & NCRFullDX)
991 linkState->media |= IFM_FULL_DUPLEX;
992 else
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);
1013 return B_OK;
1017 status_t
1018 DavicomDevice::_ReadRegister(uint8 reg, size_t size, uint8* buffer)
1020 if (size > 255)
1021 return B_BAD_VALUE;
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);
1033 return result;
1037 status_t
1038 DavicomDevice::_WriteRegister(uint8 reg, size_t size, uint8* buffer)
1040 if (size > 255)
1041 return B_BAD_VALUE;
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);
1049 return result;
1053 status_t
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);
1062 return result;
1066 status_t
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);
1073 return 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);
1080 return result;
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;
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;
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;
1105 *data = values[0] | values[1] << 8;
1106 return result;
1110 status_t
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);
1117 return 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);
1125 return 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);
1132 return result;
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;
1143 result = _Write1Register(RegEPCR, control & ~EPCRRegWrite);
1144 if (result != B_OK)
1145 TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result);
1147 return result;
1151 status_t
1152 DavicomDevice::_InitMII()
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;
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;
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;
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;
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;
1186 TRACE_ALWAYS("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n",
1187 MII_OUI(id01, id02), MII_MODEL(id02), MII_REV(id02));
1189 return result;
1193 status_t
1194 DavicomDevice::_EnableInterrupts(bool enable)
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;
1203 if (enable) {
1204 control |= USBCIntAck;
1205 control &= ~USBCIntNAck;
1206 } else {
1207 control &= ~USBCIntAck;
1210 result = _Write1Register(RegUSBC, control);
1211 if (result != B_OK)
1212 TRACE_ALWAYS("Error of setting USB control register:%#010x\n", result);
1214 return result;