// vim: set et sw=4 sts=4 :
+#include "debug.h"
#include "eth.h"
#include "dp8390.h"
-#ifdef DEBUG
-void sleep(unsigned char);
-#ifdef SDCC
-static xdata at 0x0080 byte leds0;
-static xdata at 0x00c0 byte leds1;
-#else
-static byte xdata leds0 _at_ 0x0080;
-static byte xdata leds1 _at_ 0x00c0;
-#endif
-#endif
-
-/// Datos persistentes del módulo
-static union
+/** Tamaño del frame */
+byte netdev_len;
+
+// Próximo frame a obtener
+static struct
{
- byte send_len; ///> Tamaño del frame que será enviado
- byte next_pkt; ///> Próximo frame a obtener
+ byte next_buf;
+ byte curr_buf;
+ byte curr_off;
}
-persistent;
+recv_state;
+
+/// Tamaño de la cabecera de los buffers de la placa de red
+#define BUF_HDR_SIZE 4
/// Cambia de página sin modificar los demás bits del CR
#define SELECT_REG_PAGE(page) \
*/
bool netdev_init()
{
+ byte i;
+
// Set IOR & IOW as they're active low.
IOR = 1;
IOW = 1;
write_reg(RSAR0, 0u); // En la dirección 0x0000
write_reg(RSAR1, 0u);
write_reg(CR, READ); // Comienza lectura
- eth_addr_local[0] = read_reg(RDMA);
- read_reg(RDMA); // Ignoramos porque viene como un word
- eth_addr_local[1] = read_reg(RDMA);
- read_reg(RDMA); // Ignoramos porque viene como un word
- eth_addr_local[2] = read_reg(RDMA);
- read_reg(RDMA); // Ignoramos porque viene como un word
- eth_addr_local[3] = read_reg(RDMA);
- read_reg(RDMA); // Ignoramos porque viene como un word
- eth_addr_local[4] = read_reg(RDMA);
- read_reg(RDMA); // Ignoramos porque viene como un word
- eth_addr_local[5] = read_reg(RDMA);
- read_reg(RDMA); // Ignoramos porque viene como un word
+ for (i = 0; i < ETH_ADDR_SIZE; ++i)
+ {
+ eth_addr_local[i] = read_reg(RDMA);
+ read_reg(RDMA); // Ignoramos porque viene como un word
+ }
// Abort/ complete DMA operation.
ABORT_DMA(STOP);
write_reg(CURR, RX_PAGE_START + 1);
// Set physical address
- write_reg(PAR0, eth_addr_local[0]);
- write_reg(PAR1, eth_addr_local[1]);
- write_reg(PAR2, eth_addr_local[2]);
- write_reg(PAR3, eth_addr_local[3]);
- write_reg(PAR4, eth_addr_local[4]);
- write_reg(PAR5, eth_addr_local[5]);
+ for (i = 0; i < ETH_ADDR_SIZE; ++i)
+ write_reg(PAR_BASE + i, eth_addr_local[i]);
// Restart RTL8019AS.
write_reg(CR, START);
}
-/** Comienza el envío de un nuevo frame
- * @param len Tamaño del frame a enviar
- */
+/** Comienza el envío de un nuevo frame */
void netdev_send_start()
{
- persistent.send_len = 0;
// Wait until pending transmit operation completes.
- while(read_reg(CR) & TXP) continue;
+ while (read_reg(CR) & TXP) continue;
+ write_reg(ISR, PTX); // Limpio bit de interrupción
// Set remote DMA start address registers to indicate where to load packet.
write_reg(RSAR0, 0u);
write_reg(RSAR1, TX_PAGE_START);
+}
+
+/** Finaliza el envío del frame
+ * @precond netdev_send_start() debe haber sido ejecutada
+ * @precond se copiaron datos al dispositivo para enviar
+ * @param len Cantidad de bytes a transmitir
+ */
+void netdev_send_end(byte len)
+{
+ // Set transmit page start to indicate packet start.
+ write_reg(TPSR, TX_PAGE_START);
+
+ // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
+ if (len < MIN_PACKET_LEN)
+ len = MIN_PACKET_LEN;
+ // Set transmit byte count registers to indicate packet length.
+ write_reg(TBCR0, len);
+ write_reg(TBCR1, 0u);
+
+ // Issue command for RTL8019AS to transmit packet from it's local buffer.
+ write_reg(CR, START | TXP);
+}
+
+void netdev_write_start(byte len)
+{
// Set remote DMA byte count registers to indicate length of packet load.
- write_reg(RBCR0, MAX_PACKET_LEN); // Tamaño máximo en principio
+ write_reg(RBCR0, len);
write_reg(RBCR1, 0u);
// Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
- write_reg(CR, WRITE | STA);
+ write_reg(CR, WRITE);
+}
+
+void netdev_write_start_at(byte offset, byte len)
+{
+ // Set remote DMA start address registers to packet data.
+ write_reg(RSAR0, offset);
+ write_reg(RSAR1, TX_PAGE_START);
+
+ // Set remote DMA byte count registers to indicate length of packet load.
+ write_reg(RBCR0, len);
+ write_reg(RBCR1, 0u);
+
+ // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
+ write_reg(CR, WRITE);
}
/** Escribe un byte al buffer de la placa de red para ser enviado
* @precond netdev_send_start() debe haber sido ejecutada
* @param b Byte a enviar
*/
-void netdev_send_byte(byte b)
+void netdev_write_byte(byte b)
{
- persistent.send_len++;
write_reg(RDMA, b);
}
* @precond netdev_send_start() debe haber sido ejecutada
* @param w Word a enviar
*/
-void netdev_send_word(uint16 w)
+void netdev_write_word(uint16 w)
{
- persistent.send_len += 2;
write_reg(RDMA, HIGH(w));
write_reg(RDMA, LOW(w));
}
-/** Finaliza el envío del frame
- * @precond netdev_send_start() debe haber sido ejecutada
- */
-void netdev_send_end()
+void netdev_write_end()
{
// Abort/ complete DMA operation.
ABORT_DMA(START);
-
- // Set transmit page start to indicate packet start.
- write_reg(TPSR, TX_PAGE_START);
-
- // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
- if (persistent.send_len < MIN_PACKET_LEN)
- {
- persistent.send_len = MIN_PACKET_LEN;
- }
-
- // Set transmit byte count registers to indicate packet length.
- write_reg(TBCR0, LOW(persistent.send_len));
- write_reg(TBCR1, 0u);
-
- // Issue command for RTL8019AS to transmit packet from it's local buffer.
- write_reg(CR, START | TXP);
}
/** Comienza la lectura de un nuevo frame
- * @return Cantidad de bytes del frame leído
+ * @return Cantidad de bytes a recibir
*/
byte netdev_recv_start()
-{
+{
// Check if the rx buffer has overflowed.
if (read_reg(ISR) & OVW)
{
byte current;
- // Select RTL8019AS register page 1.
SELECT_REG_PAGE(1);
-
- // Retrieve current receive buffer page
current = read_reg(CURR);
-
- // Select RTL8019AS register page 1.
SELECT_REG_PAGE(0);
+ // Hack: a veces reporta mal el flag de OVW, así que verificamos que
+ // relamente haya habido overflow.
if (read_reg(BNRY) == current)
{
-#ifdef DEBUG
- leds1 = ~0x01;
- leds2 = ~read_reg(ISR);
- sleep(5);
- leds1 = ~0x02;
- leds2 = ~read_reg(BNRY);
- sleep(5);
- leds1 = ~0x04;
- leds2 = ~current;
- sleep(5);
-#endif
+ printb(read_reg(ISR), 0x01);
+ printb(read_reg(BNRY), 0x02);
+ printb(current, 0x04);
+ printb(0x00, 0x00);
reset();
}
- return 0u;
+ return 0;
}
// Check if there is a packet in the rx buffer.
else if (read_reg(ISR) & PRX)
{
- struct buf_hdr_t
- {
- byte status; // Estado del frame recibido
- byte next; // Offset del próximo frame
- uint16 len; // Tamaño del frame
- }
- buf_hdr;
+ byte status;
+ byte len;
byte current;
- byte bnry;
// Retrieve packet header. (status, next_ptr, length_l, length_h)
- // Set remote DMA start address registers to packet header.
- bnry = read_reg(BNRY) + 1;
- if (bnry >= RX_PAGE_STOP)
- bnry = RX_PAGE_START;
- write_reg(RSAR0, 0u);
- write_reg(RSAR1, bnry);
+ // Obtiene el buffer a leer actualmente
+ recv_state.curr_buf = read_reg(BNRY) + 1;
+ if (recv_state.curr_buf >= RX_PAGE_STOP)
+ recv_state.curr_buf = RX_PAGE_START;
// Select RTL8019AS register page 1.
SELECT_REG_PAGE(1);
SELECT_REG_PAGE(0);
// Check if last packet has been removed from rx buffer.
- if(bnry == current)
+ if(recv_state.curr_buf == current)
{
// Clear packet received interrupt flag.
write_reg(ISR, PRX | RXE);
- return 0u;
+ return 0;
}
// Set remote DMA byte count registers to packet header length.
- write_reg(RBCR0, sizeof(struct buf_hdr_t));
- write_reg(RBCR1, 0u);
-
- // Clear remote DMA complete interrupt status register bit.
- write_reg(ISR, RDC);
-
- // Initiate DMA transfer of packet header.
- write_reg(CR, READ);
+ recv_state.curr_off = 0;
+ netdev_read_start(BUF_HDR_SIZE);
// Packet status.
- buf_hdr.status = read_reg(RDMA);
+ status = netdev_read_byte();
// Save next packet pointer.
- buf_hdr.next = persistent.next_pkt = read_reg(RDMA);
+ recv_state.next_buf = netdev_read_byte() - 1;
// Retrieve packet data length and subtract CRC bytes.
- buf_hdr.len = read_reg(RDMA) - sizeof(struct buf_hdr_t);
+ len = netdev_read_byte() - BUF_HDR_SIZE;
// Si es muy grande, muy chico o hubo error, lo descartamos
- if ((buf_hdr.len < MIN_PACKET_LEN) || (buf_hdr.len > MAX_PACKET_LEN)
- || ((buf_hdr.status & 0x0F) != RXSOK)
- || read_reg(RDMA)) // Parte alta del tamaño
+ if ((len < MIN_PACKET_LEN) || (len > MAX_PACKET_LEN)
+ || ((status & 0x0F) != RXSOK)
+ || netdev_read_byte()) // Parte alta del tamaño
{
- ABORT_DMA(START); // Termina DMA
- write_reg(BNRY, buf_hdr.next - 1); // Pasa al próximo frame
+ // Terminamos DMA y pasamos al próximo frame
+ netdev_read_end();
+ write_reg(BNRY, recv_state.next_buf);
return 0;
}
// Abort/ complete DMA operation.
- ABORT_DMA(START);
+ netdev_read_end();
- // Set remote DMA start address registers to packet data.
- write_reg(RSAR0, sizeof(struct buf_hdr_t));
- write_reg(RSAR1, bnry);
+ return len;
+ }
- // Set remote DMA byte count registers to packet data length.
- write_reg(RBCR0, buf_hdr.len);
- write_reg(RBCR1, 0u);
+ return 0;
+}
- // Initiate DMA transfer of packet data.
- write_reg(CR, READ);
+/** Finaliza la recepción del frame
+ * @precond netdev_recv_start() debe haber sido ejecutada
+ */
+void netdev_recv_end()
+{
+ // Pasa el próximo frame
+ write_reg(BNRY, recv_state.next_buf);
+}
- return buf_hdr.len;
- }
- return 0;
+void netdev_read_start(byte len)
+{
+ // Set remote DMA start address registers to packet data.
+ write_reg(RSAR0, recv_state.curr_off);
+ write_reg(RSAR1, recv_state.curr_buf);
+ recv_state.curr_off += len;
+
+ // Set remote DMA byte count registers to packet data length.
+ write_reg(RBCR0, len);
+ write_reg(RBCR1, 0);
+
+ // Initiate DMA transfer of packet data.
+ write_reg(CR, READ);
}
/** Lee un byte del buffer de la placa de red
* @precond netdev_recv_start() debe haber sido ejecutada
*/
-byte netdev_recv_byte()
+byte netdev_read_byte()
{
return read_reg(RDMA);
}
/** Lee un word del buffer de la placa de red
* @precond netdev_recv_start() debe haber sido ejecutada
*/
-uint16 netdev_recv_word()
+uint16 netdev_read_word()
{
- uint16 w = netdev_recv_byte() << 8;
- return w + netdev_recv_byte();
+ uint16 w = read_reg(RDMA) << 8;
+ return w + read_reg(RDMA);
}
/** Finaliza la lectura del frame
* @precond netdev_recv_start() debe haber sido ejecutada
*/
-void netdev_recv_end()
+void netdev_read_end()
{
- // Abort/ complete DMA operation.
+ // Completa DMA
ABORT_DMA(START);
-
- // Advance boundary pointer to next packet start.
- write_reg(BNRY, persistent.next_pkt - 1);
}