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