]> git.llucax.com Git - z.facultad/66.09/etherled.git/blobdiff - src/dp8390.c
Copio el estado actual del proyecto como un ejemplo de echo server.
[z.facultad/66.09/etherled.git] / src / dp8390.c
index 642c36fc676b16539f32fc54265cd129ca3bbe38..5c472a5cb87311ccad342b9eb7b40c175979265d 100644 (file)
@@ -4,13 +4,20 @@
 #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)                         \
@@ -121,7 +128,7 @@ static void reset()
     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);
@@ -139,6 +146,8 @@ static void reset()
  */
 bool netdev_init()
 {
+    byte i;
+
     // Set IOR & IOW as they're active low.
     IOR = 1;
     IOW = 1;
@@ -191,18 +200,11 @@ bool netdev_init()
     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);
@@ -226,12 +228,8 @@ bool netdev_init()
     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);
@@ -246,21 +244,58 @@ bool netdev_init()
 }
 
 
-/** 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.
@@ -271,9 +306,8 @@ void netdev_send_start()
  * @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);
 }
 
@@ -281,40 +315,20 @@ void netdev_send_byte(byte 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()
 {
@@ -323,45 +337,35 @@ 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);
@@ -373,70 +377,74 @@ byte netdev_recv_start()
         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);
 }
@@ -444,21 +452,18 @@ byte netdev_recv_byte()
 /** 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);
 }