// vim: set et sw=4 sts=4 :
#include "debug.h"
+#include "leds.h"
#include "eth.h"
#include "dp8390.h"
-/// Datos persistentes del módulo
-static union // Unión porque nunca se usan ambos juntos
+/** 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) \
static void write_reg(unsigned char reg, unsigned char wr_data)
{
+ leds_lock();
// Select register address.
ADDR_PORT &= ~ADDR_PORT_MASK;
ADDR_PORT |= reg;
// Set register data port as input again.
DATA_PORT = DATA_PORT_MASK;
+ leds_unlock();
}
static unsigned char read_reg(unsigned char reg)
{
+ leds_lock();
// Select register address.
ADDR_PORT &= ~ADDR_PORT_MASK;
ADDR_PORT |= reg;
IOR = 1;
NICE = 1;
+ leds_unlock();
return reg;
}
SELECT_REG_PAGE(0);
// Clear rx buffer overflow & packet received interrupt flags.
- write_reg(ISR, OVW);
+ write_reg(ISR, PRX | OVW);
// Re-itialise transmit configuration reg for normal operation.
write_reg(TCR, MODE0);
*/
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, len);
+ write_reg(RBCR1, 0u);
+
+ // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
+ 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, 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.
* @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()
{
{
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)
{
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, 0x00);
-
- // 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 = read_reg(RDMA);
-
- // Indicamos cual es el próximo paquete para cuando termine
- // FIXME poner más lindo para que consuma menos memoria
- persistent.next_pkt = buf_hdr.next - 1;
+ 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/ complete DMA operation.
- ABORT_DMA(START);
-
- // Advance boundary pointer to next packet start.
- write_reg(BNRY, persistent.next_pkt);
-
+ // Terminamos DMA y pasamos al próximo frame
+ netdev_read_end();
+ write_reg(BNRY, recv_state.next_buf);
return 0;
}
- // Set remote DMA start address registers to packet data.
- write_reg(RSAR0, sizeof(struct buf_hdr_t));
- write_reg(RSAR1, bnry);
-
- // Set remote DMA byte count registers to packet data length.
- write_reg(RBCR0, buf_hdr.len);
- write_reg(RBCR1, 0u);
-
- // Initiate DMA transfer of packet data.
- write_reg(CR, READ);
+ // Abort/ complete DMA operation.
+ netdev_read_end();
- return buf_hdr.len;
+ return len;
}
+
return 0;
}
+/** 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);
+}
+
+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);
}