The Pedigree Project 0.1
Dm9601.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "Dm9601.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/machine/Network.h"
24#include "pedigree/kernel/network/IpAddress.h"
25#include "pedigree/kernel/network/MacAddress.h"
26#include "pedigree/kernel/process/TerminationDeferral.h"
27#include "pedigree/kernel/process/Thread.h"
28#include "pedigree/kernel/processor/Processor.h"
29#include "pedigree/kernel/processor/ProcessorInformation.h"
30#include "pedigree/kernel/time/Time.h"
31#include "pedigree/kernel/utilities/MemoryPool.h"
32#include "pedigree/kernel/utilities/PointerGuard.h"
33#include "pedigree/kernel/utilities/Vector.h"
34#include "pedigree/kernel/utilities/utility.h"
35
36#include "modules/system/network-stack/NetworkStack.h"
37#include "modules/system/usb/UsbConstants.h"
38
39namespace {
40constexpr size_t MaxPacketBytes = 1518;
41constexpr size_t RxUsbOverhead = 8;
42constexpr uint32_t ControlTransferTimeoutMs = 250;
43constexpr uint32_t BulkTransferTimeoutMs = 1000;
44constexpr Time::Timestamp ResetTimeout = 20 * Time::Multiplier::Millisecond;
45constexpr Time::Timestamp SharedOperationTimeout = 20 * Time::Multiplier::Millisecond;
46constexpr Time::Timestamp LinkWaitTimeout = Time::Multiplier::Second;
47constexpr Time::Timestamp LinkPollInterval = 50 * Time::Multiplier::Millisecond;
48constexpr Time::Timestamp TxReadyTimeout = 100 * Time::Multiplier::Millisecond;
49constexpr Time::Timestamp RegisterPollInterval = Time::Multiplier::Millisecond;
50constexpr Time::Timestamp SharedPollInterval = Time::Multiplier::Millisecond;
51constexpr size_t ResetPollLimit = 16;
52constexpr size_t SharedPollLimit = 16;
53constexpr size_t LinkPollLimit = 16;
54constexpr size_t TxReadyPollLimit = 16;
55constexpr size_t TxPaddingLimit = 3;
56
57constexpr uint8_t NetworkStatusLinkUp = 1 << 6;
58constexpr uint8_t NetworkStatusTxBusy = 1 << 4;
59constexpr uint8_t PhyControlBusy = 1;
60constexpr uint8_t RxStatusErrorMask = 0xBF;
61} // namespace
62
63Dm9601::Dm9601(UsbDevice* pDev)
64 : UsbDevice(pDev),
65 ::Network(),
66 m_pInEndpoint(0),
67 m_pOutEndpoint(0),
68 m_TxLock(),
69 m_SharedRegisterLock(),
70 m_IncomingPackets(false),
71 m_RxQueueHead(nullptr),
72 m_RxQueueTail(nullptr),
73 m_RxPacketQueueLock(),
74 m_TxPacket(0),
75 m_Running(false),
76 m_Registered(false),
77 m_Operations(),
78 m_PacketWorker(),
79 m_ReceiveWorker() {}
80
81Dm9601::~Dm9601() {
82 // Closing admission first makes deregistration a publication change rather
83 // than the only protection against a late network-stack caller.
84 m_Operations.close();
85 m_Running = false;
86
87 if (m_Registered) {
89 m_Registered = false;
90 }
91
92 // doSync cancellation drains its USB callback before the RX thread joins.
93 // The packet worker is then unable to race queue retirement below.
94 m_ReceiveWorker.stop();
96 m_PacketWorker.stop();
97 m_Operations.wait();
98
99 Packet* packets = nullptr;
100 {
101 LockGuard<Spinlock> guard(m_RxPacketQueueLock);
102 packets = m_RxQueueHead;
103 m_RxQueueHead = nullptr;
104 m_RxQueueTail = nullptr;
105 }
106 while (packets) {
107 Packet* packet = packets;
108 packets = packet->next;
109 if (packet->buffer) {
110 NetworkStack::instance().getMemPool().free(packet->buffer);
111 }
112 delete packet;
113 }
114}
115
117 // Grab USB endpoints for the driver to use later
118 for (size_t i = 0; i < m_pInterface->endpointList.count(); i++) {
119 Endpoint* pEndpoint = m_pInterface->endpointList[i];
120 if (!m_pInEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) && pEndpoint->bIn)
121 m_pInEndpoint = pEndpoint;
122 if (!m_pOutEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) && pEndpoint->bOut)
123 m_pOutEndpoint = pEndpoint;
125 break;
126 }
127
128 if (!m_pInEndpoint) {
129 ERROR("dm9601: no bulk IN endpoint");
130 return;
131 }
132
133 if (!m_pOutEndpoint) {
134 ERROR("dm9601: no bulk OUT endpoint");
135 return;
136 }
137
138 uint8_t mac[6] ALIGN(16) = {};
139 for (size_t i = 0; i < 3; ++i) {
140 uint16_t word = 0;
141 if (!readEeprom(i, word)) {
142 ERROR("dm9601: could not read its MAC address from EEPROM");
143 return;
144 }
145 mac[i * 2] = static_cast<uint8_t>(word);
146 mac[i * 2 + 1] = static_cast<uint8_t>(word >> 8);
147 m_StationInfo.mac.setMac(mac[i * 2], i * 2);
148 m_StationInfo.mac.setMac(mac[i * 2 + 1], i * 2 + 1);
149 }
150
151 NOTICE("DM9601: MAC " << m_StationInfo.mac[0] << ":" << m_StationInfo.mac[1] << ":"
152 << m_StationInfo.mac[2] << ":" << m_StationInfo.mac[3] << ":"
153 << m_StationInfo.mac[4] << ":" << m_StationInfo.mac[5]);
154
155 if (!resetDevice()) {
156 ERROR("dm9601: device reset did not complete");
157 return;
158 }
159
160 // Publish no software-visible device until every setup transfer succeeded.
161 if (!writeRegister(NetworkControl, 0) || !writeRegister(GeneralPurposeCtl, 0x1) ||
162 !writeRegister(GeneralPurpose, 0) || !writeRegister(BackPressThreshold, 0x37) ||
163 !writeRegister(FlowControl, 0x38) || !writeRegister(RxFlowControl, 1 | (1 << 3) | (1 << 5)) ||
164 !writeRegister(UsbControl, 0) ||
165 !writeRegister(PhysicalAddress, reinterpret_cast<uintptr_t>(mac), sizeof(mac)) ||
166 !writeRegister(RxControl, 5 | (1 << 3))) {
167 ERROR("dm9601: device setup transfer failed");
168 return;
169 }
170
171 if (!waitForLink()) {
172 ERROR("dm9601: could not read initial link status");
173 return;
174 }
175
176 m_Running = true;
177 Thread* pThread =
178 new Thread(Processor::information().getCurrentThread()->getParent(), trampoline, this);
179 pThread->setName("DM9601 RX worker");
180 m_PacketWorker.adopt(pThread);
181 pThread =
182 new Thread(Processor::information().getCurrentThread()->getParent(), recvTrampoline, this);
183 pThread->setName("DM9601 RX loop");
184 m_ReceiveWorker.adopt(pThread);
185
187 m_Registered = true;
188
189 m_UsbState = HasDriver;
190}
191
192int Dm9601::recvTrampoline(void* p) {
193 Dm9601* pDm9601 = reinterpret_cast<Dm9601*>(p);
194 pDm9601->receiveLoop();
195 return 0;
196}
197
198int Dm9601::trampoline(void* p) {
199 Dm9601* pDm9601 = reinterpret_cast<Dm9601*>(p);
200 pDm9601->receiveThread();
201 return 0;
202}
203
204void Dm9601::receiveThread() {
205 while (true) {
206 if (!m_IncomingPackets.acquire()) {
207 if (!m_Running ||
208 Processor::information().getCurrentThread()->getUnwindState() != Thread::Continue)
209 return;
210 continue;
211 }
212
213 TerminationDeferral packetLifetime;
214 Packet* pPacket = nullptr;
215 {
216 LockGuard<Spinlock> guard(m_RxPacketQueueLock);
217 pPacket = m_RxQueueHead;
218 if (pPacket) {
219 m_RxQueueHead = pPacket->next;
220 if (!m_RxQueueHead)
221 m_RxQueueTail = nullptr;
222 }
223 }
224 if (!pPacket) {
225 if (!m_Running)
226 return;
227 continue;
228 }
229
230 if (m_Running) {
231 NetworkStack::instance().receive(pPacket->len, pPacket->buffer + pPacket->offset, this, 0);
232 }
233
234 uintptr_t buffer = pPacket->buffer;
235 delete pPacket;
236
238 if (!m_Running)
239 return;
240 }
241}
242
243void Dm9601::receiveLoop() {
244 while (m_Running) {
245 doReceive();
246 }
247}
248
249bool Dm9601::send(size_t nBytes, uintptr_t buffer) {
250 TerminationDeferral operationLifetime;
251 OperationBarrier::Lease operation;
252 if (!m_Operations.tryAcquire(operation) || !m_Running || !buffer || !nBytes ||
253 nBytes > MaxPacketBytes || !m_pOutEndpoint || !m_pOutEndpoint->nMaxPacketSize) {
254 return false;
255 }
256
257 size_t payloadBytes = nBytes < 64 ? 64 : nBytes;
258 size_t txSize = payloadBytes + 2;
259 for (size_t padding = 0;
260 padding < TxPaddingLimit && ((txSize & 1) || !(txSize % m_pOutEndpoint->nMaxPacketSize));
261 ++padding) {
262 ++payloadBytes;
263 ++txSize;
264 }
265 if ((txSize & 1) || !(txSize % m_pOutEndpoint->nMaxPacketSize))
266 return false;
267
268 const size_t txWords = (txSize + sizeof(uint16_t) - 1) / sizeof(uint16_t);
269 uint16_t* pBuffer = new uint16_t[txWords];
270 PointerGuard<uint16_t> bufferGuard(pBuffer, true);
271 ByteSet(pBuffer, 0, txWords * sizeof(uint16_t));
272 *pBuffer = HOST_TO_LITTLE16(static_cast<uint16_t>(payloadBytes));
273 MemoryCopy(&pBuffer[1], reinterpret_cast<void*>(buffer), nBytes);
274
275 // The mutex begins after all caller-independent allocation and formatting.
277 if (!m_Running || !waitForTxReady())
278 return false;
279
280 const ssize_t ret =
281 syncOut(m_pOutEndpoint, reinterpret_cast<uintptr_t>(pBuffer), txSize, BulkTransferTimeoutMs);
282 if (ret != static_cast<ssize_t>(txSize)) {
283 WARNING("dm9601: transmit transfer failed or was short (" << ret << "/" << txSize << ")");
284 return false;
285 }
286
287 // Grab the TX status register so we can find errors
288 uint8_t txStatus ALIGN(16) = 0;
289 uint8_t networkStatus ALIGN(16) = 0;
290 const uint8_t txStatusRegister = static_cast<uint8_t>(TxStatus1 + m_TxPacket);
291 m_TxPacket = (m_TxPacket + 1) % 2;
292 if (!readRegister(txStatusRegister, reinterpret_cast<uintptr_t>(&txStatus), 1)) {
293 WARNING("dm9601: could not read transmit status");
294 return false;
295 }
296
297 // Read and clear the network status (which will contain the "packet
298 // complete" indicator)
299 if (!readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(&networkStatus), 1)) {
300 WARNING("dm9601: could not clear network status after transmit");
301 return false;
302 }
303
304 return true;
305}
306
307void Dm9601::doReceive() {
308 TerminationDeferral receiveLifetime;
309 uintptr_t buff = NetworkStack::instance().getMemPool().allocate();
310 if (!buff)
311 return;
312
313 const ssize_t ret =
314 syncIn(m_pInEndpoint, buff, MaxPacketBytes + RxUsbOverhead, BulkTransferTimeoutMs);
315
316 if (ret < 0) {
317 if (m_Running) {
318 DEBUG_LOG("dm9601: receive transfer did not complete: " << ret);
319 }
321 return;
322 }
323
324 if (!m_Running) {
326 return;
327 }
328
329 if (ret < 7) {
330 WARNING("dm9601: receive transfer was too short: " << ret);
332 badPacket();
333 return;
334 }
335
336 uint8_t* pBuffer = reinterpret_cast<uint8_t*>(buff);
337 uint8_t rxstatus = pBuffer[0];
338 const uint16_t wireLength =
339 static_cast<uint16_t>(pBuffer[1]) | static_cast<uint16_t>(pBuffer[2] << 8);
340 if (wireLength < 4 || wireLength > static_cast<size_t>(ret - 3)) {
341 WARNING("dm9601: invalid receive length " << wireLength << " in " << ret << " byte transfer");
343 badPacket();
344 return;
345 }
346 const size_t len = wireLength - 4;
347
348 if ((rxstatus & RxStatusErrorMask) || !len || len > MaxPacketBytes) {
349 WARNING("dm9601: rx failure: " << rxstatus << ", length was " << len);
351 badPacket();
352 return;
353 }
354
355 Packet* pPacket = new Packet;
356 pPacket->buffer = buff;
357 pPacket->len = len;
358 pPacket->offset = 3;
359 pPacket->next = nullptr;
360
361 bool queued = false;
362 {
363 LockGuard<Spinlock> guard(m_RxPacketQueueLock);
364 if (m_Running) {
365 if (m_RxQueueTail)
366 m_RxQueueTail->next = pPacket;
367 else
368 m_RxQueueHead = pPacket;
369 m_RxQueueTail = pPacket;
370 queued = true;
371 }
372 }
373
374 if (queued) {
376 } else {
377 delete pPacket;
379 }
380}
381
383 // Free the old DNS server list, if there is one
384 if (m_StationInfo.dnsServers)
385 delete[] m_StationInfo.dnsServers;
386
387 // MAC isn't changeable, so set it all manually
388 m_StationInfo.ipv4 = info.ipv4;
389 NOTICE("DM9601: Setting ipv4, " << info.ipv4.toString() << ", " << m_StationInfo.ipv4.toString()
390 << "...");
391 m_StationInfo.ipv6 = info.ipv6;
392
393 m_StationInfo.subnetMask = info.subnetMask;
394 NOTICE("DM9601: Setting subnet mask, " << info.subnetMask.toString() << ", "
395 << m_StationInfo.subnetMask.toString() << "...");
396 m_StationInfo.gateway = info.gateway;
397 NOTICE("DM9601: Setting gateway, " << info.gateway.toString() << ", "
398 << m_StationInfo.gateway.toString() << "...");
399
400 // Callers do not free their dnsServers memory
401 m_StationInfo.dnsServers = info.dnsServers;
402 m_StationInfo.nDnsServers = info.nDnsServers;
403 NOTICE("DM9601: Setting DNS servers [" << Dec << m_StationInfo.nDnsServers << Hex
404 << " servers being set]...");
405
406 return true;
407}
408
410 return m_StationInfo;
411}
412
413bool Dm9601::readRegister(uint8_t reg, uintptr_t buffer, size_t nBytes) {
414 if (!buffer || (nBytes > 0xFF))
415 return false;
416 return controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Vendor) |
417 static_cast<uint8_t>(UsbRequestDirection::In)),
418 ReadRegister, 0, reg, nBytes, buffer, ControlTransferTimeoutMs);
419}
420
421bool Dm9601::writeRegister(uint8_t reg, uintptr_t buffer, size_t nBytes) {
422 if (!buffer || (nBytes > 0xFF))
423 return false;
424 return controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Vendor) |
425 static_cast<uint8_t>(UsbRequestDirection::Out)),
426 WriteRegister, 0, reg, nBytes, buffer, ControlTransferTimeoutMs);
427}
428
429bool Dm9601::writeRegister(uint8_t reg, uint8_t data) {
430 return controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Vendor) |
431 static_cast<uint8_t>(UsbRequestDirection::Out)),
432 WriteRegister1, data, reg, 0, 0, ControlTransferTimeoutMs);
433}
434
435bool Dm9601::readMemory(uint16_t offset, uintptr_t buffer, size_t nBytes) {
436 if (!buffer || (nBytes > 0xFF))
437 return false;
438 return controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Vendor) |
439 static_cast<uint8_t>(UsbRequestDirection::In)),
440 ReadMemory, 0, offset, nBytes, buffer, ControlTransferTimeoutMs);
441}
442
443bool Dm9601::writeMemory(uint16_t offset, uintptr_t buffer, size_t nBytes) {
444 if (!buffer || (nBytes > 0xFF))
445 return false;
446 return controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Vendor) |
447 static_cast<uint8_t>(UsbRequestDirection::Out)),
448 WriteMemory, 0, offset, nBytes, buffer, ControlTransferTimeoutMs);
449}
450
451bool Dm9601::writeMemory(uint16_t offset, uint8_t data) {
452 return controlRequest(static_cast<uint8_t>(static_cast<uint8_t>(UsbRequestType::Vendor) |
453 static_cast<uint8_t>(UsbRequestDirection::Out)),
454 WriteMemory1, data, offset, 0, 0, ControlTransferTimeoutMs);
455}
456
457bool Dm9601::readEeprom(uint8_t offset, uint16_t& value) {
458 return readSharedWord(false, offset, value);
459}
460
461bool Dm9601::writeEeprom(uint8_t offset, uint16_t data) {
462 return writeSharedWord(false, offset, data);
463}
464
465bool Dm9601::readMii(uint8_t offset, uint16_t& value) {
466 return readSharedWord(true, offset, value);
467}
468
469bool Dm9601::writeMii(uint8_t offset, uint16_t data) {
470 return writeSharedWord(true, offset, data);
471}
472
473bool Dm9601::readSharedWord(bool phy, uint8_t offset, uint16_t& value) {
475 uint16_t rawValue ALIGN(16) = 0;
476 const uint8_t address = phy ? static_cast<uint8_t>(offset | 0x40) : offset;
477 const uint8_t command = phy ? 0x0C : 0x04;
478
479 if (!writeRegister(PhyAddress, address) || !writeRegister(PhyControl, command) ||
480 !waitForSharedOperation()) {
481 (void)writeRegister(PhyControl, 0);
482 return false;
483 }
484
485 if (!writeRegister(PhyControl, 0) ||
486 !readRegister(PhyLowByte, reinterpret_cast<uintptr_t>(&rawValue), sizeof(rawValue))) {
487 return false;
488 }
489
490 value = LITTLE_TO_HOST16(rawValue);
491 return true;
492}
493
494bool Dm9601::writeSharedWord(bool phy, uint8_t offset, uint16_t value) {
496 uint16_t rawValue ALIGN(16) = HOST_TO_LITTLE16(value);
497 const uint8_t address = phy ? static_cast<uint8_t>(offset | 0x40) : offset;
498 const uint8_t command = phy ? 0x1A : 0x12;
499
500 if (!writeRegister(PhyLowByte, reinterpret_cast<uintptr_t>(&rawValue), sizeof(rawValue)) ||
501 !writeRegister(PhyAddress, address) || !writeRegister(PhyControl, command) ||
502 !waitForSharedOperation()) {
503 (void)writeRegister(PhyControl, 0);
504 return false;
505 }
506
507 return writeRegister(PhyControl, 0);
508}
509
510bool Dm9601::waitForSharedOperation() {
511 const Time::Timestamp deadline = Time::getTicks() + SharedOperationTimeout;
512 for (size_t poll = 0; poll < SharedPollLimit; ++poll) {
513 uint8_t control ALIGN(16) = 0;
514 if (!readRegister(PhyControl, reinterpret_cast<uintptr_t>(&control), sizeof(control))) {
515 return false;
516 }
517 if (!(control & PhyControlBusy))
518 return true;
519 if (Time::getTicks() >= deadline || poll + 1 == SharedPollLimit ||
520 !Time::delay(SharedPollInterval))
521 break;
522 }
523
524 WARNING("dm9601: EEPROM/PHY operation timed out");
525 return false;
526}
527
528bool Dm9601::resetDevice() {
529 if (!writeRegister(NetworkControl, 1) || !Time::delay(20 * Time::Multiplier::Microsecond)) {
530 return false;
531 }
532
533 const Time::Timestamp deadline = Time::getTicks() + ResetTimeout;
534 for (size_t poll = 0; poll < ResetPollLimit; ++poll) {
535 uint8_t control ALIGN(16) = 0;
536 if (!readRegister(NetworkControl, reinterpret_cast<uintptr_t>(&control), sizeof(control))) {
537 return false;
538 }
539 if (!(control & 1))
540 return true;
541 if (Time::getTicks() >= deadline || poll + 1 == ResetPollLimit ||
542 !Time::delay(RegisterPollInterval))
543 break;
544 }
545
546 return false;
547}
548
549bool Dm9601::waitForLink() {
550 const Time::Timestamp deadline = Time::getTicks() + LinkWaitTimeout;
551 for (size_t poll = 0; poll < LinkPollLimit; ++poll) {
552 uint8_t status ALIGN(16) = 0;
553 if (!readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(&status), sizeof(status))) {
554 return false;
555 }
556 if (status & NetworkStatusLinkUp)
557 return true;
558 if (Time::getTicks() >= deadline || poll + 1 == LinkPollLimit)
559 break;
560 if (!Time::delay(LinkPollInterval))
561 return false;
562 }
563
564 NOTICE("dm9601: link is down; continuing without blocking USB discovery");
565 return true;
566}
567
568bool Dm9601::waitForTxReady() {
569 const Time::Timestamp deadline = Time::getTicks() + TxReadyTimeout;
570 for (size_t poll = 0; poll < TxReadyPollLimit; ++poll) {
571 if (!m_Running)
572 return false;
573
574 uint8_t status ALIGN(16) = 0;
575 if (!readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(&status), sizeof(status))) {
576 return false;
577 }
578 if (!(status & NetworkStatusTxBusy))
579 return true;
580 if (Time::getTicks() >= deadline || poll + 1 == TxReadyPollLimit ||
581 !Time::delay(RegisterPollInterval))
582 break;
583 }
584
585 WARNING("dm9601: transmitter remained busy");
586 return false;
587}
Device * getParent() const
Definition Device.h:166
bool writeMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
Writes data from a buffer into device memory.
Definition Dm9601.cc:443
bool writeRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
Writes data from a buffer to a register.
Definition Dm9601.cc:421
bool writeMii(uint8_t offset, uint16_t data)
Writes a 16-bit value to the external MII.
Definition Dm9601.cc:469
Mutex m_SharedRegisterLock
Definition Dm9601.h:173
size_t m_TxPacket
Definition Dm9601.h:190
Endpoint * m_pOutEndpoint
Definition Dm9601.h:167
virtual void initialiseDriver()
Implemented by the driver class, initialises driver-specific stuff.
Definition Dm9601.cc:116
virtual bool send(size_t nBytes, uintptr_t buffer)
Definition Dm9601.cc:249
bool writeEeprom(uint8_t offset, uint16_t data)
Writes a 16-bit value to the device EEPROM.
Definition Dm9601.cc:461
bool readRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
Reads data from a register into a buffer.
Definition Dm9601.cc:413
bool readMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
Reads data from device memory into a buffer.
Definition Dm9601.cc:435
bool readMii(uint8_t offset, uint16_t &value)
Reads a 16-bit value from the external MII.
Definition Dm9601.cc:465
Mutex m_TxLock
Definition Dm9601.h:170
Semaphore m_IncomingPackets
Definition Dm9601.h:176
virtual bool setStationInfo(const StationInfo &info)
Definition Dm9601.cc:382
virtual const StationInfo & getStationInfo()
Definition Dm9601.cc:409
Endpoint * m_pInEndpoint
Definition Dm9601.h:164
bool readEeprom(uint8_t offset, uint16_t &value)
Reads a 16-bit value from the device EEPROM.
Definition Dm9601.cc:457
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
uintptr_t allocate()
MemoryPool & getMemPool()
void deRegisterDevice(Network *pDevice)
static NetworkStack & instance()
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
void registerDevice(Network *pDevice)
virtual void badPacket()
Definition Network.cc:131
MUST_USE_RESULT bool tryAcquire(Lease &lease)
static ProcessorInformation & information()
void release(size_t n=1)
Definition Semaphore.cc:549
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:355
size_t nDnsServers
Can contain IPv6 addresses.
Definition Network.h:51
IpAddress gateway
Automatically calculated?
Definition Network.h:47
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:517
Interface * m_pInterface
Interface in use.
Definition UsbDevice.h:320
bool controlRequest(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Performs an USB control request.
Definition UsbDevice.cc:558
UsbState m_UsbState
The current state of the device.
Definition UsbDevice.h:311
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124