// vim: set et sw=4 sts=4 :
#include "debug.h"
+#include "leds.h"
#include "eth.h"
#include "dp8390.h"
/** Tamaño del frame */
byte netdev_len;
-/// Datos persistentes del módulo
-static union // Unión porque nunca se usan ambos juntos
+// 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;
-
-/// Estructura de la cabecera del buffer de la placa de red.
-struct buf_hdr_t
-{
- byte status; ///> Estado del frame recibido
- byte next; ///> Offset del próximo frame
- uint16 len; ///> Tamaño del frame
-};
+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;
}
}
-/** 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
- * @precond netdev_recv_start() debe haber sido ejecutada
+ * @return Cantidad de bytes a recibir
*/
-void netdev_recv_start()
+byte netdev_recv_start()
{
- // Limpio tamaño del frame
- netdev_len = 0;
-
// Check if the rx buffer has overflowed.
if (read_reg(ISR) & OVW)
{
printb(read_reg(ISR), 0x01);
printb(read_reg(BNRY), 0x02);
printb(current, 0x04);
+ printb(0x00, 0x00);
reset();
}
- return;
+ return 0;
}
// Check if there is a packet in the rx buffer.
else if (read_reg(ISR) & PRX)
{
- struct buf_hdr_t 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;
+ 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
{
// Terminamos DMA y pasamos al próximo frame
- ABORT_DMA(START);
- write_reg(BNRY, persistent.next_pkt);
- return;
+ netdev_read_end();
+ write_reg(BNRY, recv_state.next_buf);
+ return 0;
}
// Abort/ complete DMA operation.
- ABORT_DMA(START);
+ netdev_read_end();
- // Todo OK, empezamos a recibir así que ponemos bien el tamaño del frame
- netdev_len = buf_hdr.len;
+ return len;
+ }
- // Set remote DMA start address registers to packet data.
- write_reg(RSAR0, sizeof(struct buf_hdr_t));
- write_reg(RSAR1, bnry);
+ return 0;
+}
- // Set remote DMA byte count registers to packet data length.
- write_reg(RBCR0, buf_hdr.len);
- write_reg(RBCR1, 0u);
+/** 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);
+}
- // Initiate DMA transfer of packet data.
- write_reg(CR, READ);
- }
+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()
{
- // Termina de leer bytes de padding (si hay)
- netdev_len += sizeof(struct buf_hdr_t);
- if (read_reg(CRDA0) < netdev_len)
- {
- netdev_len -= read_reg(CRDA0) - 1; // El puntero está adelantado en 1
- while (netdev_len--)
- {
- //printb(read_reg(CRDA0), netdev_len);
- netdev_recv_byte();
- }
- }
// Completa DMA
ABORT_DMA(START);
- // Pasa el próximo frame
- write_reg(BNRY, persistent.next_pkt);
}