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 "modules/system/network-stack/NetworkStack.h"
22 #include "modules/system/usb/UsbConstants.h"
23 #include "pedigree/kernel/LockGuard.h"
24 #include "pedigree/kernel/Log.h"
25 #include "pedigree/kernel/machine/Network.h"
26 #include "pedigree/kernel/network/IpAddress.h"
27 #include "pedigree/kernel/network/MacAddress.h"
28 #include "pedigree/kernel/process/Thread.h"
29 #include "pedigree/kernel/processor/Processor.h"
30 #include "pedigree/kernel/processor/ProcessorInformation.h"
31 #include "pedigree/kernel/time/Time.h"
32 #include "pedigree/kernel/utilities/MemoryPool.h"
33 #include "pedigree/kernel/utilities/Vector.h"
34 #include "pedigree/kernel/utilities/utility.h"
35 
36 Dm9601::Dm9601(UsbDevice *pDev)
37  : UsbDevice(pDev), ::Network(), m_pInEndpoint(0), m_pOutEndpoint(0),
38  m_TxLock(false), m_IncomingPackets(false), m_RxPacketQueue(),
39  m_RxPacketQueueLock(), m_TxPacket(0)
40 {
41 }
42 
43 Dm9601::~Dm9601()
44 {
45 }
46 
48 {
49  // Grab USB endpoints for the driver to use later
50  for (size_t i = 0; i < m_pInterface->endpointList.count(); i++)
51  {
52  Endpoint *pEndpoint = m_pInterface->endpointList[i];
53  if (!m_pInEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) &&
54  pEndpoint->bIn)
55  m_pInEndpoint = pEndpoint;
56  if (!m_pOutEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) &&
57  pEndpoint->bOut)
58  m_pOutEndpoint = pEndpoint;
59  if (m_pInEndpoint && m_pOutEndpoint)
60  break;
61  }
62 
63  if (!m_pInEndpoint)
64  {
65  ERROR("dm9601: no bulk IN endpoint");
66  return;
67  }
68 
69  if (!m_pOutEndpoint)
70  {
71  ERROR("dm9601: no bulk OUT endpoint");
72  return;
73  }
74 
75  uint16_t *pMac = new uint16_t[3];
76  for (size_t i = 0; i < 3; ++i)
77  pMac[i] = readEeprom(i);
78  m_StationInfo.mac.setMac(pMac, false);
79 
80  NOTICE(
81  "DM9601: MAC " << pMac[0] << ":" << pMac[1] << ":" << pMac[2] << ":"
82  << pMac[3] << ":" << pMac[4] << ":" << pMac[5]);
83 
84  // Reset the chip
85  writeRegister(NetworkControl, 1);
86  Time::delay(100 * Time::Multiplier::Millisecond);
87 
88  // Select internal MII
89  writeRegister(NetworkControl, 0);
90 
91  // Enable output on GPIO
92  writeRegister(GeneralPurposeCtl, 0x1);
93 
94  // Disable GPIO0 - POWER_DOWN
95  writeRegister(GeneralPurpose, 0);
96 
97  // Enter into the default state - half-duplex, internal PHY
98  writeRegister(NetworkControl, 0);
99 
100  // Jam the RX line when there's less than 3K in the SRAM space
101  writeRegister(BackPressThreshold, 0x37);
102 
103  // Flow control: 3K high water overflow, 8K low water overflow
104  writeRegister(FlowControl, 0x38);
105 
106  // Set up flow control for RX and TX
107  writeRegister(RxFlowControl, 1 | (1 << 3) | (1 << 5));
108 
109  // Enable proper interrupt handling regardless of NAK state
110  writeRegister(UsbControl, 0);
111 
112  // Write the physical address of this station to the card so it can filter
113  // incoming packets.
114  writeRegister(PhysicalAddress, reinterpret_cast<uintptr_t>(pMac), 6);
115 
116  // Configure RX control - accept runts, all multicast packets, and turn on
117  // the receiver
118  writeRegister(RxControl, 5 | (1 << 3));
119 
120  // Wait for the link to become active
122  uint8_t *p = new uint8_t;
123  *p = 0;
124  while (!*p)
125  {
126  readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(p), 1);
127  Time::delay(100 * Time::Multiplier::Millisecond);
128  }
129 
130  Thread *pThread = new Thread(
131  Processor::information().getCurrentThread()->getParent(), trampoline,
132  this);
133  pThread->detach();
134  pThread = new Thread(
135  Processor::information().getCurrentThread()->getParent(),
136  recvTrampoline, this);
137  pThread->detach();
138 
140 
141  m_UsbState = HasDriver;
142 }
143 
144 int Dm9601::recvTrampoline(void *p)
145 {
146  Dm9601 *pDm9601 = reinterpret_cast<Dm9601 *>(p);
147  pDm9601->receiveLoop();
148 }
149 
150 int Dm9601::trampoline(void *p)
151 {
152  Dm9601 *pDm9601 = reinterpret_cast<Dm9601 *>(p);
153  pDm9601->receiveThread();
154 }
155 
156 void Dm9601::receiveThread()
157 {
158  while (true)
159  {
160  m_IncomingPackets.acquire();
161 
162  m_RxPacketQueueLock.acquire();
163  Packet *pPacket = m_RxPacketQueue.popFront();
164  m_RxPacketQueueLock.release();
165 
167  pPacket->len, pPacket->buffer + pPacket->offset, this, 0);
168 
169  uintptr_t buffer = pPacket->buffer;
170  delete pPacket;
171 
173  }
174 }
175 
176 void Dm9601::receiveLoop()
177 {
178  while (true)
179  doReceive();
180 }
181 
182 bool Dm9601::send(size_t nBytes, uintptr_t buffer)
183 {
184  // Don't let anything else get in our way here
185  LockGuard<Mutex> guard(m_TxLock);
186 
187  uint8_t *p = new uint8_t;
188  readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(p), 1);
189  while (*p & (1 << 4))
190  {
191  Time::delay(100 * Time::Multiplier::Millisecond);
192  readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(p), 1);
193  }
194 
195  // Avoid runt packets
196  size_t padBytes = 0;
197  if (nBytes < 64)
198  {
199  padBytes = nBytes % 64;
200  ByteSet(reinterpret_cast<void *>(buffer + nBytes), 0, padBytes);
201 
202  nBytes = 64;
203  }
204 
205  size_t txSize = nBytes + 2;
206 
207  if (!(txSize % 64))
208  txSize++;
209 
210  // Transmit endpoint
211  uint16_t *pBuffer = new uint16_t[(txSize / sizeof(uint16_t)) + 1];
212  *pBuffer = HOST_TO_LITTLE16(static_cast<uint16_t>(nBytes));
213  MemoryCopy(&pBuffer[1], reinterpret_cast<void *>(buffer), nBytes);
214 
215  ssize_t ret =
216  syncOut(m_pOutEndpoint, reinterpret_cast<uintptr_t>(pBuffer), txSize);
217  delete[] pBuffer;
218 
219  // Grab the TX status register so we can find errors
220  readRegister(TxStatus1 + m_TxPacket, reinterpret_cast<uintptr_t>(p), 1);
221 
222  m_TxPacket = (m_TxPacket + 1) % 2;
223 
224  // Read and clear the network status (which will contain the "packet
225  // complete" indicator)
226  readRegister(NetworkStatus, reinterpret_cast<uintptr_t>(p), 1);
227 
228  return ret >= 0;
229 }
230 
231 #define MAX_MTU 1518
232 
233 void Dm9601::doReceive()
234 {
235  uintptr_t buff = NetworkStack::instance().getMemPool().allocate();
236  ssize_t ret = syncIn(m_pInEndpoint, buff, MAX_MTU, 0); // Never time out.
237 
238  if (ret < 0)
239  {
240  WARNING("dm9601: rx failure due to USB error: " << ret);
242  return;
243  }
244 
245  uint8_t *pBuffer = reinterpret_cast<uint8_t *>(buff);
246  uint8_t rxstatus = pBuffer[0];
247  uint16_t len =
248  LITTLE_TO_HOST16(*reinterpret_cast<uint16_t *>(buff + 1)) - 4;
249 
250  if (rxstatus & 0x3F)
251  {
252  WARNING("dm9601: rx failure: " << rxstatus << ", length was " << len);
254  badPacket();
255  return;
256  }
257 
258  Packet *pPacket = new Packet;
259  pPacket->buffer = buff;
260  pPacket->len = len;
261  pPacket->offset = 3;
262 
263  m_RxPacketQueueLock.acquire();
264  m_RxPacketQueue.pushBack(pPacket);
265  m_RxPacketQueueLock.release();
266 
267  m_IncomingPackets.release();
268 }
269 
271 {
272  // Free the old DNS server list, if there is one
273  if (m_StationInfo.dnsServers)
274  delete[] m_StationInfo.dnsServers;
275 
276  // MAC isn't changeable, so set it all manually
277  m_StationInfo.ipv4 = info.ipv4;
278  NOTICE(
279  "DM9601: Setting ipv4, " << info.ipv4.toString() << ", "
280  << m_StationInfo.ipv4.toString() << "...");
281  m_StationInfo.ipv6 = info.ipv6;
282 
283  m_StationInfo.subnetMask = info.subnetMask;
284  NOTICE(
285  "DM9601: Setting subnet mask, " << info.subnetMask.toString() << ", "
286  << m_StationInfo.subnetMask.toString()
287  << "...");
288  m_StationInfo.gateway = info.gateway;
289  NOTICE(
290  "DM9601: Setting gateway, " << info.gateway.toString() << ", "
291  << m_StationInfo.gateway.toString()
292  << "...");
293 
294  // Callers do not free their dnsServers memory
295  m_StationInfo.dnsServers = info.dnsServers;
296  m_StationInfo.nDnsServers = info.nDnsServers;
297  NOTICE(
298  "DM9601: Setting DNS servers [" << Dec << m_StationInfo.nDnsServers
299  << Hex << " servers being set]...");
300 
301  return true;
302 }
303 
305 {
306  return m_StationInfo;
307 }
308 
309 ssize_t Dm9601::readRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
310 {
311  if (!buffer || (nBytes > 0xFF))
312  return -1;
313  return controlRequest(
314  UsbRequestType::Vendor | UsbRequestDirection::In, ReadRegister, 0, reg,
315  nBytes, buffer);
316 }
317 
318 ssize_t Dm9601::writeRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
319 {
320  if (!buffer || (nBytes > 0xFF))
321  return -1;
322  return controlRequest(
323  UsbRequestType::Vendor | UsbRequestDirection::Out, WriteRegister, 0,
324  reg, nBytes, buffer);
325 }
326 
327 ssize_t Dm9601::writeRegister(uint8_t reg, uint8_t data)
328 {
329  return controlRequest(
330  UsbRequestType::Vendor | UsbRequestDirection::Out, WriteRegister1, data,
331  reg);
332 }
333 
334 ssize_t Dm9601::readMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
335 {
336  if (!buffer || (nBytes > 0xFF))
337  return -1;
338  return controlRequest(
339  UsbRequestType::Vendor | UsbRequestDirection::In, ReadMemory, 0, offset,
340  nBytes, buffer);
341 }
342 
343 ssize_t Dm9601::writeMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
344 {
345  if (!buffer || (nBytes > 0xFF))
346  return -1;
347  return controlRequest(
348  UsbRequestType::Vendor | UsbRequestDirection::Out, WriteMemory, 0,
349  offset, nBytes, buffer);
350 }
351 
352 ssize_t Dm9601::writeMemory(uint16_t offset, uint8_t data)
353 {
354  return controlRequest(
355  UsbRequestType::Vendor | UsbRequestDirection::Out, WriteMemory1, data,
356  offset);
357 }
358 
359 uint16_t Dm9601::readEeprom(uint8_t offset)
360 {
362  uint16_t *ret = new uint16_t;
363  writeRegister(PhyAddress, offset);
364  writeRegister(PhyControl, 0x4); // Read from EEPROM
365  Time::delay(100 * Time::Multiplier::Millisecond);
366  writeRegister(PhyControl, 0); // Stop the transfer
367  readRegister(PhyLowByte, reinterpret_cast<uintptr_t>(ret), 2);
368 
369  uint16_t retVal = *ret;
370  delete ret;
371 
372  return retVal;
373 }
374 
375 void Dm9601::writeEeprom(uint8_t offset, uint16_t data)
376 {
378  uint16_t *input = new uint16_t;
379  *input = data;
380  writeRegister(PhyAddress, offset);
381  writeRegister(PhyLowByte, reinterpret_cast<uintptr_t>(input), 2);
382  writeRegister(PhyControl, 0x12); // Write to EEPROM
383  Time::delay(100 * Time::Multiplier::Millisecond);
384  writeRegister(PhyControl, 0);
385 
386  delete input;
387 }
388 
389 uint16_t Dm9601::readMii(uint8_t offset)
390 {
392  uint16_t *ret = new uint16_t;
393  writeRegister(PhyAddress, offset | 0x40); // External MII starts at 0x40
394  writeRegister(PhyControl, 0xc); // Read from PHY
395  Time::delay(100 * Time::Multiplier::Millisecond);
396  writeRegister(PhyControl, 0); // Stop the transfer
397  readRegister(PhyLowByte, reinterpret_cast<uintptr_t>(ret), 2);
398 
399  uint16_t retVal = *ret;
400  delete ret;
401 
402  return retVal;
403 }
404 
405 void Dm9601::writeMii(uint8_t offset, uint16_t data)
406 {
408  uint16_t *input = new uint16_t;
409  *input = data;
410  writeRegister(PhyAddress, offset | 0x40);
411  writeRegister(PhyLowByte, reinterpret_cast<uintptr_t>(input), 2);
412  writeRegister(PhyControl, 0xa); // Transfer to PHY
413  Time::delay(100 * Time::Multiplier::Millisecond);
414  writeRegister(PhyControl, 0);
415 
416  delete input;
417 }
virtual void initialiseDriver()
Implemented by the driver class, initialises driver-specific stuff.
Definition: Dm9601.cc:47
Definition: Dm9601.h:34
ssize_t readMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
Reads data from device memory into a buffer.
Definition: Dm9601.cc:334
ssize_t writeRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
Writes data from a buffer to a register.
Definition: Dm9601.cc:318
IpAddress gateway
Automatically calculated?
static ProcessorInformation & information()
Definition: Processor.cc:45
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
void writeMii(uint8_t offset, uint16_t data)
Writes a 16-bit value to the external MII.
Definition: Dm9601.cc:405
size_t nDnsServers
Can contain IPv6 addresses.
uint16_t readMii(uint8_t offset)
Reads a 16-bit value from the external MII.
Definition: Dm9601.cc:389
MemoryPool & getMemPool()
Definition: NetworkStack.h:81
#define WARNING(text)
Definition: Log.h:78
ssize_t writeMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
Writes data from a buffer into device memory.
Definition: Dm9601.cc:343
#define NOTICE(text)
Definition: Log.h:74
uintptr_t allocate()
Definition: MemoryPool.cc:176
Definition: Log.h:136
virtual bool setStationInfo(const StationInfo &info)
Definition: Dm9601.cc:270
virtual const StationInfo & getStationInfo()
Definition: Dm9601.cc:304
void writeEeprom(uint8_t offset, uint16_t data)
Writes a 16-bit value to the device EEPROM.
Definition: Dm9601.cc:375
uint16_t readEeprom(uint8_t offset)
Reads a 16-bit value from the device EEPROM.
Definition: Dm9601.cc:359
static NetworkStack & instance()
Definition: NetworkStack.h:47
void registerDevice(Network *pDevice)
Definition: Thread.h:54
ssize_t readRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
Reads data from a register into a buffer.
Definition: Dm9601.cc:309
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
Definition: MemoryPool.cc:251
#define ERROR(text)
Definition: Log.h:82
bool detach()
Definition: Thread.cc:885
Definition: Log.h:138
Device * getParent() const
Definition: Device.h:149
virtual bool send(size_t nBytes, uintptr_t buffer)
Definition: Dm9601.cc:182