]> git.llucax.com Git - z.facultad/66.09/etherled.git/blob - src/dp8390.c
ARP implementado y andando (más pequeños bugfixes)!
[z.facultad/66.09/etherled.git] / src / dp8390.c
1 // vim: set et sw=4 sts=4 :     
2
3 #include "debug.h"
4 #include "leds.h"
5 #include "eth.h"
6 #include "dp8390.h"
7
8 /** Tamaño del frame */
9 byte netdev_len;
10
11 // Próximo frame a obtener
12 static struct
13 {
14     byte next_buf;
15     byte curr_buf;
16     byte curr_off;
17 }
18 recv_state;
19
20 /// Tamaño de la cabecera de los buffers de la placa de red
21 #define BUF_HDR_SIZE 4
22
23 /// Cambia de página sin modificar los demás bits del CR
24 #define SELECT_REG_PAGE(page)                         \
25     do                                                \
26     {                                                 \
27         write_reg(CR, read_reg(CR) & ~(PS1 | PS0));   \
28         write_reg(CR, read_reg(CR) | (page << 6));    \
29     }                                                 \
30     while (0)
31
32 /// Aborta (o completa) el DMA limpiando el ISR
33 #define ABORT_DMA(flags)        \
34     do                          \
35     {                           \
36         write_reg(CR, flags);   \
37         write_reg(ISR, RDC);    \
38     }                           \
39     while (0)
40
41
42 static void write_reg(unsigned char reg, unsigned char wr_data)
43 {
44     leds_lock();
45     // Select register address.
46     ADDR_PORT &= ~ADDR_PORT_MASK; 
47     ADDR_PORT |= reg;
48
49     // Output register data to port.
50     DATA_PORT = wr_data;
51
52     // Clock register data into RTL8019AS.
53     // IOR & IOW are both active low.
54     NICE = 0;
55     IOW = 0;
56     IOW = 1;
57     NICE = 1;
58
59     // Set register data port as input again.
60     DATA_PORT = DATA_PORT_MASK;
61     leds_unlock();
62
63
64
65 static unsigned char read_reg(unsigned char reg)
66 {
67     leds_lock();
68     // Select register address.
69     ADDR_PORT &= ~ADDR_PORT_MASK;
70     ADDR_PORT |= reg;
71
72     // Enable register data output from RTL8019AS.
73     NICE = 0;
74     IOR = 0;
75
76     // Read register data from port.
77     reg = DATA_PORT;
78
79     // Disable register data output from RTL8019AS.
80     IOR = 1; 
81     NICE = 1;   
82
83     leds_unlock();
84     return reg;
85
86
87 /** Resetea placa de red en caso de buffer overflow */
88 static void reset()
89 {
90     bit retransmit = read_reg(CR) & TXP;
91
92     // If the receive buffer ring has overflowed we dump the whole
93     // thing and start over. There is no way of knowing whether the
94     // data it contains is uncorrupted, or will cause us grief.
95
96     // Stop RTL8019AS and abort DMA operation.
97     write_reg(CR, STOP);
98
99     // Wait for controller to halt after any current tx completes.
100     while(!(read_reg(ISR) & RST)) continue;
101
102     // Reset remote byte count registers.
103     write_reg(RBCR0, 0x00);
104     write_reg(RBCR1, 0x00);
105
106     // Check whether currently transmitting a packet.
107     if(retransmit)
108     {
109         // If neither a successful transmission nor a tx abort error 
110         // has occured, then flag current tx packet for resend.
111         if(read_reg(ISR) & (PTX | TXE))
112         {
113             retransmit = 0;
114         }
115     }
116
117     // Set transmit configuration register to loopback internally.
118     write_reg(TCR, MODE1);
119
120     // Restart the RTL8019AS.
121     write_reg(CR, START);
122
123     // Re-initialise last receive buffer read pointer.
124     write_reg(BNRY, RX_PAGE_START);
125
126     // Select RTL8019AS register page 1.
127     SELECT_REG_PAGE(1);
128
129     // Re-initialise current packet receive buffer page pointer.
130     write_reg(CURR, RX_PAGE_START + 1);
131
132     // Select RTL8019AS register page 0.
133     SELECT_REG_PAGE(0);
134
135     // Clear rx buffer overflow & packet received interrupt flags.
136     write_reg(ISR, PRX | OVW);
137
138     // Re-itialise transmit configuration reg for normal operation.
139     write_reg(TCR, MODE0);
140
141     if(retransmit)
142     {
143         // Retransmit packet in RTL8019AS local tx buffer.
144         write_reg(CR, START | TXP);
145     }
146 }
147
148
149 /** Inicializa dispositivo de red
150  * @return true si se inicializó correctamente, false si no
151  */
152 bool netdev_init()
153 {
154     byte i;
155
156     // Set IOR & IOW as they're active low.
157     IOR = 1;
158     IOW = 1;
159     NICE = 1;
160
161     // Set register data port as input.
162     DATA_PORT = DATA_PORT_MASK;
163
164     // Configure RTL8019AS ethernet controller.
165
166     // Keil startup code takes 4ms to execute (18.432MHz, X1 mode).
167     // That leaves plenty of time for the RTL8019AS to read it's
168     // configuration in from the 9346 EEPROM before we get here.
169
170     // Select RTL8019AS register page 0.
171     SELECT_REG_PAGE(0);
172
173     // Check if RTL8019AS fully reset.
174     if(!(read_reg(ISR) & RST))
175     {
176         return 0;
177     }
178
179     // Stop RTL8019AS, select page 0 and abort DMA operation.
180     write_reg(CR, STOP);
181
182     // Initialise data configuration register. 
183     // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
184     write_reg(DCR, FT1 | LS);
185
186     // Reset remote byte count registers.
187     write_reg(RBCR0, 0u);
188     write_reg(RBCR1, 0u);
189
190     // Receive configuration register to monitor mode.
191     write_reg(RCR, MON);
192
193     // Initialise transmit configuration register to loopback internally.
194     write_reg(TCR, MODE1);
195
196     // Clear interrupt status register bits by writing 1 to each.
197     write_reg(ISR, ALL);
198
199     // Mask all interrupts in mask register.
200     write_reg(IMR, NONE);
201
202     // Obtengo MAC de la placa
203     write_reg(RBCR0, 12u); // Vamos a leer 12 bytes (2 x 6)
204     write_reg(RBCR1, 0u); 
205     write_reg(RSAR0, 0u); // En la dirección 0x0000
206     write_reg(RSAR1, 0u);
207     write_reg(CR, READ); // Comienza lectura
208     for (i = 0; i < ETH_ADDR_SIZE; ++i)
209     {
210         eth_addr_local[i] = read_reg(RDMA);
211         read_reg(RDMA); // Ignoramos porque viene como un word
212     }
213
214     // Abort/ complete DMA operation.
215     ABORT_DMA(STOP);
216
217     // Set transmit page start.
218     write_reg(TPSR, TX_PAGE_START);
219
220     // Set receive buffer page start.
221     write_reg(PSTART, RX_PAGE_START);
222
223     // Initialise last receive buffer read pointer.
224     write_reg(BNRY, RX_PAGE_START);
225
226     // Set receive buffer page stop.
227     write_reg(PSTOP, RX_PAGE_STOP);
228
229     // Select RTL8019AS register page 1.
230     SELECT_REG_PAGE(1);
231
232     // Initialise current packet receive buffer page pointer
233     write_reg(CURR, RX_PAGE_START + 1);
234
235     // Set physical address
236     for (i = 0; i < ETH_ADDR_SIZE; ++i)
237         write_reg(PAR_BASE + i, eth_addr_local[i]);
238
239     // Restart RTL8019AS. 
240     write_reg(CR, START);
241
242     // Initialise transmit configuration register for normal operation.
243     write_reg(TCR, MODE0);
244
245     // Receive configuration register to accept broadcast packets.
246     write_reg(RCR, AB);
247
248     return 1;
249 }
250
251
252 /** Comienza el envío de un nuevo frame */
253 void netdev_send_start()
254 {
255     // Wait until pending transmit operation completes.
256     while (read_reg(CR) & TXP) continue;
257     write_reg(ISR, PTX); // Limpio bit de interrupción
258
259     // Set remote DMA start address registers to indicate where to load packet.
260     write_reg(RSAR0, 0u);
261     write_reg(RSAR1, TX_PAGE_START);
262 }
263
264 /** Finaliza el envío del frame
265  * @precond netdev_send_start() debe haber sido ejecutada
266  * @precond se copiaron datos al dispositivo para enviar
267  * @param len Cantidad de bytes a transmitir
268  */
269 void netdev_send_end(byte len)
270 {
271     // Set transmit page start to indicate packet start.
272     write_reg(TPSR, TX_PAGE_START);
273
274     // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
275     if (len < MIN_PACKET_LEN)
276         len = MIN_PACKET_LEN;
277
278     // Set transmit byte count registers to indicate packet length.
279     write_reg(TBCR0, len);
280     write_reg(TBCR1, 0u);
281
282     // Issue command for RTL8019AS to transmit packet from it's local buffer.
283     write_reg(CR, START | TXP);
284 }
285
286 void netdev_write_start(byte len)
287 {
288     // Set remote DMA byte count registers to indicate length of packet load.
289     write_reg(RBCR0, len);
290     write_reg(RBCR1, 0u);
291
292     // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
293     write_reg(CR, WRITE);
294 }
295
296 void netdev_write_start_at(byte offset, byte len)
297 {
298     // Set remote DMA start address registers to packet data.
299     write_reg(RSAR0, offset);
300     write_reg(RSAR1, TX_PAGE_START);
301
302     // Set remote DMA byte count registers to indicate length of packet load.
303     write_reg(RBCR0, len);
304     write_reg(RBCR1, 0u);
305
306     // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
307     write_reg(CR, WRITE);
308 }
309
310 /** Escribe un byte al buffer de la placa de red para ser enviado
311  * @precond netdev_send_start() debe haber sido ejecutada
312  * @param b Byte a enviar
313  */
314 void netdev_write_byte(byte b)
315 {
316     write_reg(RDMA, b);
317 }
318
319 /** Escribe un word al buffer de la placa de red para ser enviado
320  * @precond netdev_send_start() debe haber sido ejecutada
321  * @param w Word a enviar
322  */
323 void netdev_write_word(uint16 w)
324 {
325     write_reg(RDMA, HIGH(w));
326     write_reg(RDMA, LOW(w));
327 }
328
329 void netdev_write_end()
330 {
331     // Abort/ complete DMA operation.
332     ABORT_DMA(START);
333 }
334
335 /** Comienza la lectura de un nuevo frame
336  * @return Cantidad de bytes a recibir
337  */
338 byte netdev_recv_start()
339 {
340     // Check if the rx buffer has overflowed.
341     if (read_reg(ISR) & OVW)
342     {
343         byte current;
344
345         SELECT_REG_PAGE(1);
346         current = read_reg(CURR);
347         SELECT_REG_PAGE(0);
348
349         // Hack: a veces reporta mal el flag de OVW, así que verificamos que
350         // relamente haya habido overflow.
351         if (read_reg(BNRY) == current)
352         {
353             printb(read_reg(ISR), 0x01);
354             printb(read_reg(BNRY), 0x02);
355             printb(current, 0x04);
356             printb(0x00, 0x00);
357             reset();
358         }
359         return 0;
360     }
361     // Check if there is a packet in the rx buffer.
362     else if (read_reg(ISR) & PRX)
363     {
364         byte status;
365         byte len;
366         byte current;
367
368         // Retrieve packet header. (status, next_ptr, length_l, length_h)
369
370         // Obtiene el buffer a leer actualmente
371         recv_state.curr_buf = read_reg(BNRY) + 1;
372         if (recv_state.curr_buf >= RX_PAGE_STOP)
373             recv_state.curr_buf = RX_PAGE_START;
374
375         // Select RTL8019AS register page 1.
376         SELECT_REG_PAGE(1);
377
378         // Retrieve current receive buffer page
379         current = read_reg(CURR);
380
381         // Select RTL8019AS register page 1.
382         SELECT_REG_PAGE(0);
383
384         // Check if last packet has been removed from rx buffer.
385         if(recv_state.curr_buf == current)
386         {
387             // Clear packet received interrupt flag.
388             write_reg(ISR, PRX | RXE);
389             return 0;
390         }
391
392         // Set remote DMA byte count registers to packet header length.
393         recv_state.curr_off = 0;
394         netdev_read_start(BUF_HDR_SIZE);
395
396         // Packet status.
397         status = netdev_read_byte();
398
399         // Save next packet pointer.
400         recv_state.next_buf = netdev_read_byte() - 1;
401
402         // Retrieve packet data length and subtract CRC bytes.
403         len = netdev_read_byte() - BUF_HDR_SIZE;
404
405         // Si es muy grande, muy chico o hubo error, lo descartamos
406         if ((len < MIN_PACKET_LEN) || (len > MAX_PACKET_LEN)
407                 || ((status & 0x0F) != RXSOK)
408                 || netdev_read_byte()) // Parte alta del tamaño
409         {
410             // Terminamos DMA y pasamos al próximo frame
411             netdev_read_end();
412             write_reg(BNRY, recv_state.next_buf);
413             return 0;
414         }
415
416         // Abort/ complete DMA operation.
417         netdev_read_end();
418
419         return len;
420     }
421
422     return 0;
423 }
424
425 /** Finaliza la recepción del frame
426  * @precond netdev_recv_start() debe haber sido ejecutada
427  */
428 void netdev_recv_end()
429 {
430     // Pasa el próximo frame
431     write_reg(BNRY, recv_state.next_buf);
432 }
433
434 void netdev_read_start(byte len)
435 {
436     // Set remote DMA start address registers to packet data.
437     write_reg(RSAR0, recv_state.curr_off);
438     write_reg(RSAR1, recv_state.curr_buf);
439     recv_state.curr_off += len;
440
441     // Set remote DMA byte count registers to packet data length.
442     write_reg(RBCR0, len);
443     write_reg(RBCR1, 0);
444
445     // Initiate DMA transfer of packet data.
446     write_reg(CR, READ);
447 }
448
449 /** Lee un byte del buffer de la placa de red
450  * @precond netdev_recv_start() debe haber sido ejecutada
451  */
452 byte netdev_read_byte()
453 {
454     return read_reg(RDMA);
455 }
456
457 /** Lee un word del buffer de la placa de red
458  * @precond netdev_recv_start() debe haber sido ejecutada
459  */
460 uint16 netdev_read_word()
461 {
462     uint16 w = read_reg(RDMA) << 8;
463     return w + read_reg(RDMA);
464 }
465
466 /** Finaliza la lectura del frame
467  * @precond netdev_recv_start() debe haber sido ejecutada
468  */
469 void netdev_read_end()
470 {
471     // Completa DMA
472     ABORT_DMA(START);
473 }
474