1 // vim: set et sw=4 sts=4 :
7 /// Datos persistentes del módulo
8 static union // Unión porque nunca se usan ambos juntos
10 byte send_len; ///> Tamaño del frame que será enviado
11 byte next_pkt; ///> Próximo frame a obtener
15 /// Cambia de página sin modificar los demás bits del CR
16 #define SELECT_REG_PAGE(page) \
19 write_reg(CR, read_reg(CR) & ~(PS1 | PS0)); \
20 write_reg(CR, read_reg(CR) | (page << 6)); \
24 /// Aborta (o completa) el DMA limpiando el ISR
25 #define ABORT_DMA(flags) \
28 write_reg(CR, flags); \
29 write_reg(ISR, RDC); \
34 static void write_reg(unsigned char reg, unsigned char wr_data)
36 // Select register address.
37 ADDR_PORT &= ~ADDR_PORT_MASK;
40 // Output register data to port.
43 // Clock register data into RTL8019AS.
44 // IOR & IOW are both active low.
50 // Set register data port as input again.
51 DATA_PORT = DATA_PORT_MASK;
55 static unsigned char read_reg(unsigned char reg)
57 // Select register address.
58 ADDR_PORT &= ~ADDR_PORT_MASK;
61 // Enable register data output from RTL8019AS.
65 // Read register data from port.
68 // Disable register data output from RTL8019AS.
75 /** Resetea placa de red en caso de buffer overflow */
78 bit retransmit = read_reg(CR) & TXP;
80 // If the receive buffer ring has overflowed we dump the whole
81 // thing and start over. There is no way of knowing whether the
82 // data it contains is uncorrupted, or will cause us grief.
84 // Stop RTL8019AS and abort DMA operation.
87 // Wait for controller to halt after any current tx completes.
88 while(!(read_reg(ISR) & RST)) continue;
90 // Reset remote byte count registers.
91 write_reg(RBCR0, 0x00);
92 write_reg(RBCR1, 0x00);
94 // Check whether currently transmitting a packet.
97 // If neither a successful transmission nor a tx abort error
98 // has occured, then flag current tx packet for resend.
99 if(read_reg(ISR) & (PTX | TXE))
105 // Set transmit configuration register to loopback internally.
106 write_reg(TCR, MODE1);
108 // Restart the RTL8019AS.
109 write_reg(CR, START);
111 // Re-initialise last receive buffer read pointer.
112 write_reg(BNRY, RX_PAGE_START);
114 // Select RTL8019AS register page 1.
117 // Re-initialise current packet receive buffer page pointer.
118 write_reg(CURR, RX_PAGE_START + 1);
120 // Select RTL8019AS register page 0.
123 // Clear rx buffer overflow & packet received interrupt flags.
124 write_reg(ISR, PRX | OVW);
126 // Re-itialise transmit configuration reg for normal operation.
127 write_reg(TCR, MODE0);
131 // Retransmit packet in RTL8019AS local tx buffer.
132 write_reg(CR, START | TXP);
137 /** Inicializa dispositivo de red
138 * @return true si se inicializó correctamente, false si no
142 // Set IOR & IOW as they're active low.
147 // Set register data port as input.
148 DATA_PORT = DATA_PORT_MASK;
150 // Configure RTL8019AS ethernet controller.
152 // Keil startup code takes 4ms to execute (18.432MHz, X1 mode).
153 // That leaves plenty of time for the RTL8019AS to read it's
154 // configuration in from the 9346 EEPROM before we get here.
156 // Select RTL8019AS register page 0.
159 // Check if RTL8019AS fully reset.
160 if(!(read_reg(ISR) & RST))
165 // Stop RTL8019AS, select page 0 and abort DMA operation.
168 // Initialise data configuration register.
169 // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
170 write_reg(DCR, FT1 | LS);
172 // Reset remote byte count registers.
173 write_reg(RBCR0, 0u);
174 write_reg(RBCR1, 0u);
176 // Receive configuration register to monitor mode.
179 // Initialise transmit configuration register to loopback internally.
180 write_reg(TCR, MODE1);
182 // Clear interrupt status register bits by writing 1 to each.
185 // Mask all interrupts in mask register.
186 write_reg(IMR, NONE);
188 // Obtengo MAC de la placa
189 write_reg(RBCR0, 12u); // Vamos a leer 12 bytes (2 x 6)
190 write_reg(RBCR1, 0u);
191 write_reg(RSAR0, 0u); // En la dirección 0x0000
192 write_reg(RSAR1, 0u);
193 write_reg(CR, READ); // Comienza lectura
194 eth_addr_local[0] = read_reg(RDMA);
195 read_reg(RDMA); // Ignoramos porque viene como un word
196 eth_addr_local[1] = read_reg(RDMA);
197 read_reg(RDMA); // Ignoramos porque viene como un word
198 eth_addr_local[2] = read_reg(RDMA);
199 read_reg(RDMA); // Ignoramos porque viene como un word
200 eth_addr_local[3] = read_reg(RDMA);
201 read_reg(RDMA); // Ignoramos porque viene como un word
202 eth_addr_local[4] = read_reg(RDMA);
203 read_reg(RDMA); // Ignoramos porque viene como un word
204 eth_addr_local[5] = read_reg(RDMA);
205 read_reg(RDMA); // Ignoramos porque viene como un word
207 // Abort/ complete DMA operation.
210 // Set transmit page start.
211 write_reg(TPSR, TX_PAGE_START);
213 // Set receive buffer page start.
214 write_reg(PSTART, RX_PAGE_START);
216 // Initialise last receive buffer read pointer.
217 write_reg(BNRY, RX_PAGE_START);
219 // Set receive buffer page stop.
220 write_reg(PSTOP, RX_PAGE_STOP);
222 // Select RTL8019AS register page 1.
225 // Initialise current packet receive buffer page pointer
226 write_reg(CURR, RX_PAGE_START + 1);
228 // Set physical address
229 write_reg(PAR0, eth_addr_local[0]);
230 write_reg(PAR1, eth_addr_local[1]);
231 write_reg(PAR2, eth_addr_local[2]);
232 write_reg(PAR3, eth_addr_local[3]);
233 write_reg(PAR4, eth_addr_local[4]);
234 write_reg(PAR5, eth_addr_local[5]);
236 // Restart RTL8019AS.
237 write_reg(CR, START);
239 // Initialise transmit configuration register for normal operation.
240 write_reg(TCR, MODE0);
242 // Receive configuration register to accept broadcast packets.
249 /** Comienza el envío de un nuevo frame
250 * @param len Tamaño del frame a enviar
252 void netdev_send_start()
254 persistent.send_len = 0;
255 // Wait until pending transmit operation completes.
256 while(read_reg(CR) & TXP) continue;
258 // Set remote DMA start address registers to indicate where to load packet.
259 write_reg(RSAR0, 0u);
260 write_reg(RSAR1, TX_PAGE_START);
262 // Set remote DMA byte count registers to indicate length of packet load.
263 write_reg(RBCR0, MAX_PACKET_LEN); // Tamaño máximo en principio
264 write_reg(RBCR1, 0u);
266 // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
267 write_reg(CR, WRITE);
270 /** Escribe un byte al buffer de la placa de red para ser enviado
271 * @precond netdev_send_start() debe haber sido ejecutada
272 * @param b Byte a enviar
274 void netdev_send_byte(byte b)
276 persistent.send_len++;
280 /** Escribe un word al buffer de la placa de red para ser enviado
281 * @precond netdev_send_start() debe haber sido ejecutada
282 * @param w Word a enviar
284 void netdev_send_word(uint16 w)
286 persistent.send_len += 2;
287 write_reg(RDMA, HIGH(w));
288 write_reg(RDMA, LOW(w));
291 /** Finaliza el envío del frame
292 * @precond netdev_send_start() debe haber sido ejecutada
294 void netdev_send_end()
296 // Abort/ complete DMA operation.
299 // Set transmit page start to indicate packet start.
300 write_reg(TPSR, TX_PAGE_START);
302 // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
303 if (persistent.send_len < MIN_PACKET_LEN)
305 persistent.send_len = MIN_PACKET_LEN;
308 // Set transmit byte count registers to indicate packet length.
309 write_reg(TBCR0, LOW(persistent.send_len));
310 write_reg(TBCR1, 0u);
312 // Issue command for RTL8019AS to transmit packet from it's local buffer.
313 write_reg(CR, START | TXP);
316 /** Comienza la lectura de un nuevo frame
317 * @return Cantidad de bytes del frame leído
319 byte netdev_recv_start()
321 // Check if the rx buffer has overflowed.
322 if (read_reg(ISR) & OVW)
326 // Select RTL8019AS register page 1.
329 // Retrieve current receive buffer page
330 current = read_reg(CURR);
332 // Select RTL8019AS register page 1.
335 if (read_reg(BNRY) == current)
337 printb(read_reg(ISR), 0x01);
338 printb(read_reg(BNRY), 0x02);
339 printb(current, 0x04);
344 // Check if there is a packet in the rx buffer.
345 else if (read_reg(ISR) & PRX)
349 byte status; // Estado del frame recibido
350 byte next; // Offset del próximo frame
351 uint16 len; // Tamaño del frame
357 // Retrieve packet header. (status, next_ptr, length_l, length_h)
359 // Set remote DMA start address registers to packet header.
360 bnry = read_reg(BNRY) + 1;
361 if (bnry >= RX_PAGE_STOP)
362 bnry = RX_PAGE_START;
363 write_reg(RSAR0, 0u);
364 write_reg(RSAR1, bnry);
366 // Select RTL8019AS register page 1.
369 // Retrieve current receive buffer page
370 current = read_reg(CURR);
372 // Select RTL8019AS register page 1.
375 // Check if last packet has been removed from rx buffer.
378 // Clear packet received interrupt flag.
379 write_reg(ISR, PRX | RXE);
383 // Set remote DMA byte count registers to packet header length.
384 write_reg(RBCR0, sizeof(struct buf_hdr_t));
385 write_reg(RBCR1, 0x00);
387 // Clear remote DMA complete interrupt status register bit.
390 // Initiate DMA transfer of packet header.
394 buf_hdr.status = read_reg(RDMA);
396 // Save next packet pointer.
397 buf_hdr.next = read_reg(RDMA);
399 // Indicamos cual es el próximo paquete para cuando termine
400 // FIXME poner más lindo para que consuma menos memoria
401 persistent.next_pkt = buf_hdr.next - 1;
403 // Retrieve packet data length and subtract CRC bytes.
404 buf_hdr.len = read_reg(RDMA) - sizeof(struct buf_hdr_t);
406 // Si es muy grande, muy chico o hubo error, lo descartamos
407 if ((buf_hdr.len < MIN_PACKET_LEN) || (buf_hdr.len > MAX_PACKET_LEN)
408 || ((buf_hdr.status & 0x0F) != RXSOK)
409 || read_reg(RDMA)) // Parte alta del tamaño
411 // Abort/ complete DMA operation.
414 // Advance boundary pointer to next packet start.
415 write_reg(BNRY, persistent.next_pkt);
420 // Set remote DMA start address registers to packet data.
421 write_reg(RSAR0, sizeof(struct buf_hdr_t));
422 write_reg(RSAR1, bnry);
424 // Set remote DMA byte count registers to packet data length.
425 write_reg(RBCR0, buf_hdr.len);
426 write_reg(RBCR1, 0u);
428 // Initiate DMA transfer of packet data.
436 /** Lee un byte del buffer de la placa de red
437 * @precond netdev_recv_start() debe haber sido ejecutada
439 byte netdev_recv_byte()
441 return read_reg(RDMA);
444 /** Lee un word del buffer de la placa de red
445 * @precond netdev_recv_start() debe haber sido ejecutada
447 uint16 netdev_recv_word()
449 uint16 w = netdev_recv_byte() << 8;
450 return w + netdev_recv_byte();
453 /** Finaliza la lectura del frame
454 * @precond netdev_recv_start() debe haber sido ejecutada
456 void netdev_recv_end()
458 // Abort/ complete DMA operation.
461 // Advance boundary pointer to next packet start.
462 write_reg(BNRY, persistent.next_pkt);