Commit | Line | Data |
---|---|---|
cb6311a2 MM |
1 | #include "LPC17XX_Ethernet.h" |
2 | ||
3 | #include <cstring> | |
4 | #include <cstdio> | |
5 | ||
6 | #include "lpc17xx_clkpwr.h" | |
7 | ||
8 | #include <mri.h> | |
9 | ||
10 | #include "netcore.h" | |
11 | ||
12 | static const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 }; | |
13 | ||
14 | /*--------------------------- write_PHY -------------------------------------*/ | |
15 | /*********************************************************************//** | |
16 | * @brief Write value to PHY device | |
17 | * @param[in] PhyReg: PHY Register address | |
18 | * @param[in] Value: Value to write | |
19 | * @return 0 - if success | |
20 | * 1 - if fail | |
21 | ***********************************************************************/ | |
22 | static int32_t write_PHY (uint32_t PhyReg, uint16_t Value) | |
23 | { | |
24 | /* Write a data 'Value' to PHY register 'PhyReg'. */ | |
25 | uint32_t tout; | |
26 | ||
27 | LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; | |
28 | LPC_EMAC->MWTD = Value; | |
29 | ||
30 | /* Wait until operation completed */ | |
31 | tout = 0; | |
32 | for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) { | |
33 | if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { | |
34 | return (0); | |
35 | } | |
36 | } | |
37 | printf("write PHY %lu %04X failed!\n", PhyReg, Value); | |
38 | // Time out! | |
39 | return (-1); | |
40 | } | |
41 | ||
42 | ||
43 | /*--------------------------- read_PHY --------------------------------------*/ | |
44 | /*********************************************************************//** | |
45 | * @brief Read value from PHY device | |
46 | * @param[in] PhyReg: PHY Register address | |
47 | * @return 0 - if success | |
48 | * 1 - if fail | |
49 | ***********************************************************************/ | |
50 | static int32_t read_PHY (uint32_t PhyReg) | |
51 | { | |
52 | /* Read a PHY register 'PhyReg'. */ | |
53 | uint32_t tout; | |
54 | ||
55 | LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; | |
56 | LPC_EMAC->MCMD = EMAC_MCMD_READ; | |
57 | ||
58 | /* Wait until operation completed */ | |
59 | tout = 0; | |
60 | for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) { | |
61 | if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { | |
62 | LPC_EMAC->MCMD = 0; | |
63 | return (LPC_EMAC->MRDD); | |
64 | } | |
65 | } | |
66 | printf("read PHY %lu failed!\n", PhyReg); | |
67 | // Time out! | |
68 | return (-1); | |
69 | } | |
70 | ||
71 | /*********************************************************************//** | |
72 | * @brief Set Station MAC address for EMAC module | |
73 | * @param[in] abStationAddr Pointer to Station address that contains 6-bytes | |
74 | * of MAC address (should be in order from MAC Address 1 to MAC Address 6) | |
75 | * @return None | |
76 | **********************************************************************/ | |
77 | static void setEmacAddr(uint8_t abStationAddr[]) | |
78 | { | |
79 | /* Set the Ethernet MAC Address registers */ | |
80 | LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4]; | |
81 | LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2]; | |
82 | LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0]; | |
83 | } | |
84 | ||
85 | /*********************************************************************//** | |
86 | * @brief Set specified PHY mode in EMAC peripheral | |
87 | * @param[in] ulPHYMode Specified PHY mode, should be: | |
88 | * - EMAC_MODE_AUTO | |
89 | * - EMAC_MODE_10M_FULL | |
90 | * - EMAC_MODE_10M_HALF | |
91 | * - EMAC_MODE_100M_FULL | |
92 | * - EMAC_MODE_100M_HALF | |
93 | * @return Return (0) if no error, otherwise return (-1) | |
94 | **********************************************************************/ | |
95 | int32_t emac_SetPHYMode(uint32_t ulPHYMode) | |
96 | { | |
97 | int32_t id1, id2, tout, regv; | |
98 | ||
99 | id1 = read_PHY (EMAC_PHY_REG_IDR1); | |
100 | id2 = read_PHY (EMAC_PHY_REG_IDR2); | |
101 | ||
102 | if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_SMSC_8720A) { | |
103 | switch(ulPHYMode){ | |
104 | case EMAC_MODE_AUTO: | |
105 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); | |
106 | /* Wait to complete Auto_Negotiation */ | |
107 | for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { | |
108 | regv = read_PHY (EMAC_PHY_REG_BMSR); | |
109 | if (regv & EMAC_PHY_BMSR_AUTO_DONE) { | |
110 | /* Auto-negotiation Complete. */ | |
111 | break; | |
112 | } | |
113 | if (tout == 0){ | |
114 | // Time out, return error | |
115 | return (-1); | |
116 | } | |
117 | } | |
118 | break; | |
119 | case EMAC_MODE_10M_FULL: | |
120 | /* Connect at 10MBit full-duplex */ | |
121 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M); | |
122 | break; | |
123 | case EMAC_MODE_10M_HALF: | |
124 | /* Connect at 10MBit half-duplex */ | |
125 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M); | |
126 | break; | |
127 | case EMAC_MODE_100M_FULL: | |
128 | /* Connect at 100MBit full-duplex */ | |
129 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M); | |
130 | break; | |
131 | case EMAC_MODE_100M_HALF: | |
132 | /* Connect at 100MBit half-duplex */ | |
133 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M); | |
134 | break; | |
135 | default: | |
136 | // un-supported | |
137 | return (-1); | |
138 | } | |
139 | } | |
140 | // It's not correct module ID | |
141 | else { | |
142 | printf("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1, id2); | |
143 | return (-1); | |
144 | } | |
145 | ||
146 | // Update EMAC configuration with current PHY status | |
147 | if (EMAC_UpdatePHYStatus() < 0){ | |
148 | return (-1); | |
149 | } | |
150 | ||
151 | // Complete | |
152 | return (0); | |
153 | } | |
154 | ||
155 | _rxbuf_t LPC17XX_Ethernet::rxbuf __attribute__ ((section ("AHBSRAM1"))); | |
156 | _txbuf_t LPC17XX_Ethernet::txbuf __attribute__ ((section ("AHBSRAM1"))); | |
157 | ||
158 | LPC17XX_Ethernet* LPC17XX_Ethernet::instance; | |
159 | ||
160 | LPC17XX_Ethernet::LPC17XX_Ethernet() | |
161 | { | |
162 | mac_address[0] = 0xAE; | |
163 | mac_address[1] = 0xF0; | |
164 | mac_address[2] = 0x28; | |
165 | mac_address[3] = 0x5D; | |
166 | mac_address[4] = 0x66; | |
167 | mac_address[5] = 0x41; | |
168 | ||
169 | ip_address = IPA(192,168,1,27); | |
170 | ip_mask = 0xFFFFFF00; | |
171 | ||
172 | for (int i = 0; i < 5; i++) | |
173 | { | |
174 | rxbuf.rxdesc[i].packet = rxbuf.buf[i]; | |
175 | rxbuf.rxdesc[i].control = (1536 - 1) | EMAC_RCTRL_INT; | |
176 | ||
177 | rxbuf.rxstat[i].Info = 0; | |
178 | rxbuf.rxstat[i].HashCRC = 0; | |
179 | ||
180 | txbuf.txdesc[i].packet = txbuf.buf[i]; | |
181 | txbuf.txdesc[i].control = (1536 - 1) | EMAC_TCTRL_PAD | EMAC_TCTRL_CRC | EMAC_TCTRL_LAST | EMAC_TCTRL_INT; | |
182 | ||
183 | txbuf.txstat[i].Info = 0; | |
184 | } | |
185 | ||
186 | interface_name = (uint8_t*) malloc(5); | |
187 | memcpy(interface_name, "eth0", 5); | |
188 | ||
189 | instance = this; | |
190 | ||
191 | up = false; | |
192 | } | |
193 | ||
194 | void LPC17XX_Ethernet::on_module_loaded() | |
195 | { | |
196 | LPC_PINCON->PINSEL2 = (1 << 0) | (1 << 2) | (1 << 8) | (1 << 16) | (1 << 18) | (1 << 20) | (1 << 28) | (1 << 30); | |
197 | LPC_PINCON->PINSEL3 &= (2 << 0) | (2 << 2); | |
198 | LPC_PINCON->PINSEL3 |= (1 << 0) | (1 << 2); | |
199 | ||
200 | printf("EMAC_INIT\n"); | |
201 | emac_init(); | |
202 | printf("INIT OK\n"); | |
203 | ||
204 | register_for_event(ON_IDLE); | |
205 | register_for_event(ON_SECOND_TICK); | |
206 | } | |
207 | ||
208 | void LPC17XX_Ethernet::on_idle(void*) | |
209 | { | |
210 | _receive_frame(); | |
211 | } | |
212 | ||
213 | void LPC17XX_Ethernet::on_second_tick(void*) | |
214 | { | |
215 | // LPC_EMAC->Command = 0x303; | |
216 | // setEmacAddr(mac_address); | |
217 | uint32_t st; | |
218 | st = read_PHY (EMAC_PHY_REG_BMSR); | |
219 | ||
220 | if ((st & EMAC_PHY_BMSR_LINK_ESTABLISHED) && (st & EMAC_PHY_BMSR_AUTO_DONE) && (up == false)) | |
221 | { | |
222 | // TODO: link up event | |
223 | up = true; | |
b3feda04 | 224 | net->set_interface_status(this, up); |
cb6311a2 MM |
225 | uint32_t scsr = read_PHY(EMAC_PHY_REG_SCSR); |
226 | printf("%s: link up: ", interface_name); | |
227 | switch ((scsr >> 2) & 0x7) | |
228 | { | |
229 | case 1: | |
230 | printf("10MBit Half Duplex\n"); | |
231 | break; | |
232 | case 5: | |
233 | printf("10MBit Full Duplex\n"); | |
234 | break; | |
235 | case 2: | |
236 | printf("100MBit Half Duplex\n"); | |
237 | break; | |
238 | case 6: | |
239 | printf("100MBit Full Duplex\n"); | |
240 | break; | |
241 | default: | |
242 | printf("Unknown speed: SCSR = 0x%04lX\n", scsr); | |
243 | break; | |
244 | } | |
245 | } | |
246 | else if (((st & EMAC_PHY_BMSR_LINK_ESTABLISHED) == 0) && up) | |
247 | { | |
248 | // TODO: link down event | |
249 | up = false; | |
b3feda04 | 250 | net->set_interface_status(this, up); |
cb6311a2 MM |
251 | printf("%s: link down\n", interface_name); |
252 | } | |
253 | ||
254 | // printf("PHY: id:%04lX %04lX st:%04lX\n", id1, id2, st); | |
255 | // printf("ETH: Rx:%lu/%lu Tx:%lu/%lu\n", LPC_EMAC->RxConsumeIndex, LPC_EMAC->RxProduceIndex, LPC_EMAC->TxProduceIndex, LPC_EMAC->TxConsumeIndex); | |
256 | // printf("MII: 0x%1lX\n", LPC_EMAC->MIND); | |
257 | // printf("Command: 0x%03lX Status: 0x%1lX\n", LPC_EMAC->Command, LPC_EMAC->Status); | |
258 | // printf("RxN: %lu TxN: %lu\n", LPC_EMAC->RxDescriptorNumber, LPC_EMAC->TxDescriptorNumber); | |
259 | // printf("MAC1: 0x%04lX MAC2: 0x%04lX\n", LPC_EMAC->MAC1, LPC_EMAC->MAC2); | |
260 | // printf("MAC Address: %02lX:%02lX:%02lX:%02lX:%02lX:%02lX\n", (LPC_EMAC->SA2) & 0xFF, (LPC_EMAC->SA2 >> 8) & 0xFF, (LPC_EMAC->SA1) & 0xFF, (LPC_EMAC->SA1 >> 8) & 0xFF, (LPC_EMAC->SA0) & 0xFF, (LPC_EMAC->SA0 >> 8) & 0xFF); | |
261 | } | |
262 | ||
263 | void LPC17XX_Ethernet::emac_init() | |
264 | { | |
265 | /* Initialize the EMAC Ethernet controller. */ | |
266 | int32_t regv,tout, tmp; | |
267 | volatile uint32_t d; | |
268 | ||
269 | /* Set up clock and power for Ethernet module */ | |
270 | CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE); | |
271 | ||
272 | /* Reset all EMAC internal modules */ | |
273 | LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX | | |
274 | EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES; | |
275 | ||
276 | LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES; | |
277 | ||
278 | /* A short delay after reset. */ | |
279 | for (d = 256; d; d--); | |
280 | ||
281 | /* Initialize MAC control registers. */ | |
282 | LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; | |
283 | LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | EMAC_MAC2_FULL_DUP; | |
284 | LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; | |
285 | /* | |
286 | * Find the clock that close to desired target clock | |
287 | */ | |
288 | tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK; | |
289 | for (tout = 0; tout < (int32_t) sizeof (EMAC_clkdiv); tout++){ | |
290 | if (EMAC_clkdiv[tout] >= tmp) break; | |
291 | } | |
292 | tout++; | |
293 | // Write to MAC configuration register and reset | |
294 | LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII; | |
295 | // release reset | |
296 | LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII); | |
297 | LPC_EMAC->CLRT = EMAC_CLRT_DEF; | |
298 | LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF; | |
299 | ||
300 | /* Enable Reduced MII interface. */ | |
301 | LPC_EMAC->Command = EMAC_CR_RMII; | |
302 | ||
303 | /* Reset Reduced MII Logic. */ | |
304 | LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII; | |
305 | ||
306 | for (d = 256; d; d--); | |
307 | LPC_EMAC->SUPP = EMAC_SUPP_SPEED; | |
308 | ||
309 | /* Put the DP83848C in reset mode */ | |
310 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET); | |
311 | ||
312 | /* Wait for hardware reset to end. */ | |
313 | for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { | |
314 | regv = read_PHY (EMAC_PHY_REG_BMCR); | |
315 | if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) { | |
316 | /* Reset complete, device not Power Down. */ | |
317 | break; | |
318 | } | |
319 | if (tout == 0){ | |
320 | // Time out, return ERROR | |
321 | printf("ETH: PHY TIMEOUT\n"); | |
322 | return; | |
323 | } | |
324 | } | |
325 | ||
326 | // Set PHY mode | |
327 | // if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){ | |
328 | // printf("ETH: Error Setting Mode\n"); | |
329 | // return; | |
330 | // } | |
331 | write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); | |
332 | ||
333 | // Set EMAC address | |
334 | setEmacAddr(mac_address); | |
335 | ||
336 | /* Initialize Tx and Rx DMA Descriptors */ | |
337 | LPC_EMAC->RxDescriptor = (uint32_t) rxbuf.rxdesc; | |
338 | LPC_EMAC->RxStatus = (uint32_t) rxbuf.rxstat; | |
339 | LPC_EMAC->RxDescriptorNumber = 4; | |
340 | ||
341 | LPC_EMAC->TxDescriptor = (uint32_t) txbuf.txdesc; | |
342 | LPC_EMAC->TxStatus = (uint32_t) txbuf.txstat; | |
343 | LPC_EMAC->TxDescriptorNumber = 4; | |
344 | ||
345 | // Set Receive Filter register: enable broadcast and multicast | |
346 | LPC_EMAC->RxFilterCtrl = EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN; | |
347 | ||
348 | /* Enable Rx Done and Tx Done interrupt for EMAC */ | |
349 | LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE; | |
350 | ||
351 | /* Reset all interrupts */ | |
352 | LPC_EMAC->IntClear = 0xFFFF; | |
353 | ||
354 | /* Enable receive and transmit mode of MAC Ethernet core */ | |
355 | LPC_EMAC->Command = EMAC_CR_RX_EN | EMAC_CR_TX_EN | EMAC_CR_RMII | EMAC_CR_FULL_DUP | EMAC_CR_PASS_RUNT_FRM; | |
356 | LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; | |
357 | ||
358 | printf("ETH:EMAC INITIALISED\n"); | |
359 | } | |
360 | ||
361 | void LPC17XX_Ethernet::set_mac(uint8_t* newmac) | |
362 | { | |
363 | memcpy(mac_address, newmac, 6); | |
364 | } | |
365 | ||
366 | void LPC17XX_Ethernet::_receive_frame() | |
367 | { | |
368 | if (can_read_packet() && can_write_packet()) | |
369 | { | |
370 | int i = LPC_EMAC->RxConsumeIndex; | |
371 | RX_Stat* stat = &(rxbuf.rxstat[i]); | |
372 | NET_PACKET packet = (NET_PACKET) rxbuf.buf[i]; | |
373 | ||
374 | int size = stat->Info & EMAC_RINFO_SIZE; | |
375 | printf("Received %d byte Ethernet frame %lu/%lu\n", size, LPC_EMAC->RxProduceIndex, LPC_EMAC->RxConsumeIndex); | |
376 | // printf("Flags are 0x%04lX0000\n", (stat->Info >> 16UL)); | |
377 | ||
378 | // int j = size; | |
379 | // if (j > 64) j = 64; | |
380 | ||
381 | // for (int k = 0; k < j; k++) | |
382 | // { | |
383 | // printf("0x%02X ", packet[k]); | |
384 | // } | |
385 | // printf("\n"); | |
386 | ||
387 | int s = net->receive_packet(this, packet, size); | |
388 | if (s) | |
389 | { | |
390 | memcpy(request_packet_buffer(), packet, s); | |
391 | write_packet((uint8_t*) request_packet_buffer(), s); | |
392 | } | |
393 | ||
394 | uint32_t r = LPC_EMAC->RxConsumeIndex + 1; | |
395 | if (r > LPC_EMAC->RxDescriptorNumber) | |
396 | r = 0; | |
397 | LPC_EMAC->RxConsumeIndex = r; | |
398 | } | |
399 | } | |
400 | ||
401 | void LPC17XX_Ethernet::irq() | |
402 | { | |
403 | if (EMAC_IntGetStatus(EMAC_INT_RX_DONE)) | |
404 | { | |
405 | _receive_frame(); | |
406 | } | |
407 | ||
408 | if (EMAC_IntGetStatus(EMAC_INT_TX_DONE)) | |
409 | { | |
410 | } | |
411 | } | |
412 | ||
413 | bool LPC17XX_Ethernet::can_read_packet() | |
414 | { | |
415 | return (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex); | |
416 | } | |
417 | ||
418 | int LPC17XX_Ethernet::read_packet(uint8_t** buf) | |
419 | { | |
420 | *buf = rxbuf.buf[LPC_EMAC->RxConsumeIndex]; | |
421 | return rxbuf.rxstat[LPC_EMAC->RxConsumeIndex].Info & EMAC_RINFO_SIZE; | |
422 | } | |
423 | ||
424 | void LPC17XX_Ethernet::release_read_packet(uint8_t*) | |
425 | { | |
426 | uint32_t r = LPC_EMAC->RxConsumeIndex + 1; | |
427 | if (r > LPC_EMAC->RxDescriptorNumber) | |
428 | r = 0; | |
429 | LPC_EMAC->RxConsumeIndex = r; | |
430 | } | |
431 | ||
432 | bool LPC17XX_Ethernet::can_write_packet() | |
433 | { | |
434 | uint32_t r = LPC_EMAC->TxProduceIndex + 1; | |
435 | if (r > LPC_EMAC->TxDescriptorNumber) | |
436 | r = 0; | |
437 | return (r != LPC_EMAC->TxConsumeIndex); | |
438 | } | |
439 | ||
440 | int LPC17XX_Ethernet::write_packet(uint8_t* buf, int size) | |
441 | { | |
442 | txbuf.txdesc[LPC_EMAC->TxProduceIndex].control = size | EMAC_TCTRL_LAST | EMAC_TCTRL_CRC | EMAC_TCTRL_PAD | EMAC_TCTRL_INT; | |
443 | ||
444 | uint32_t r = LPC_EMAC->TxProduceIndex + 1; | |
445 | if (r > LPC_EMAC->TxDescriptorNumber) | |
446 | r = 0; | |
447 | ||
448 | if (r == LPC_EMAC->TxConsumeIndex) | |
449 | return 0; | |
450 | ||
451 | LPC_EMAC->TxProduceIndex = r; | |
452 | ||
453 | return size; | |
454 | } | |
455 | ||
456 | void* LPC17XX_Ethernet::request_packet_buffer() | |
457 | { | |
458 | return txbuf.txdesc[LPC_EMAC->TxProduceIndex].packet; | |
459 | } | |
460 | ||
461 | NET_PACKET LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface* ni) | |
462 | { | |
463 | if (ni != this) | |
464 | return NULL; | |
465 | ||
466 | return (NET_PACKET) request_packet_buffer(); | |
467 | } | |
468 | ||
469 | NET_PAYLOAD LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet) | |
470 | { | |
471 | return (NET_PAYLOAD) packet; | |
472 | } | |
473 | ||
b3feda04 | 474 | void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet, int length) |
cb6311a2 MM |
475 | { |
476 | uint32_t offset = ((uint8_t*) packet) - txbuf.buf[0]; | |
477 | int i = (offset / LPC17XX_MAX_PACKET); | |
478 | if ((i < LPC17XX_TXBUFS) && ((offset % LPC17XX_MAX_PACKET) == 0)) | |
479 | { | |
480 | txbuf.txdesc[i].control = (txbuf.txdesc[i].control & ~EMAC_TCTRL_SIZE) | (length & EMAC_TCTRL_SIZE); | |
481 | } | |
482 | } | |
483 | ||
484 | int LPC17XX_Ethernet::receive(NetworkInterface* ni, NET_PACKET packet, int length) | |
485 | { | |
486 | if (can_write_packet()) | |
487 | return write_packet((uint8_t*) packet, length); | |
488 | return 0; | |
489 | } | |
490 | ||
491 | int LPC17XX_Ethernet::construct(NetworkInterface* ni, NET_PACKET packet, int length) | |
492 | { | |
493 | return length; | |
494 | } | |
495 | ||
496 | extern "C" { | |
497 | void ENET_IRQHandler() | |
498 | { | |
499 | LPC17XX_Ethernet::instance->irq(); | |
500 | } | |
501 | } | |
b3feda04 MM |
502 | |
503 | void LPC17XX_Ethernet::provide_net(netcore* n) | |
504 | { | |
505 | NetworkInterface::provide_net(n); | |
506 | up = false; | |
507 | n->set_interface_status(this, up); | |
508 | } |