]> git.llucax.com Git - z.facultad/66.09/etherled.git/blob - pruebas/keil/red_test_anda/etherdev.c
d3b1a5a2a29addc95d2542ce78436bb7e9757925
[z.facultad/66.09/etherled.git] / pruebas / keil / red_test_anda / etherdev.c
1 // vim: set et sw=4 sts=4 :     
2
3 #include "etherdev.h"
4
5 void sleep(unsigned char);
6
7 static xdata leds1 _at_ 0x0080;
8 static xdata leds2 _at_ 0x00c0;
9
10 unsigned char uip_buf[80] =
11 {
12         0x00, 0x0c, 0x6e, 0x37, 0x19, 0xbf, // MAC destino
13         //0x00, 0x80, 0xc7, 0x42, 0x8d, 0x27, // MAC destino
14         0x00, 0x0c, 0x6e, 0x37, 0x19, 0xbe, // MAC fuente
15         0x00, 0x00, // Type
16 };
17
18 unsigned int uip_len = 14;
19
20 // Packet transmit & receive buffer configuration
21 #define ETH_TX_PAGE_START  0x40    // 0x4000 Tx buffer is  6 * 256 = 1536 bytes
22 #define ETH_RX_PAGE_START  0x46    // 0x4600 Rx buffer is 26 * 256 = 6656 bytes
23 #define ETH_RX_PAGE_STOP   0x60    // 0x6000
24
25 #define ETH_ADDR_PORT_MASK 0x1F                 // 00011111y
26 #define ETH_DATA_PORT_MASK 0xFF                 // 11111111y
27
28 #define ETH_MIN_PACKET_LEN 0x3C                 // 60 bytes
29
30
31 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data);
32 static unsigned char etherdev_reg_read(unsigned char reg);
33
34 // Manipulate PS1 & PS0 in CR to select RTL8019AS register page. 
35 #define ETHERDEV_SELECT_REG_PAGE(page)                                      \
36           do                                                                \
37           {                                                                 \
38               etherdev_reg_write(CR, etherdev_reg_read(CR) & ~(PS1 | PS0)); \
39               etherdev_reg_write(CR, etherdev_reg_read(CR) | (page << 6));  \
40           } while(0)
41
42
43 static void etherdev_reg_write(unsigned char reg, unsigned char wr_data)
44 {
45     // Select register address.
46     ETH_ADDR_PORT &= ~ETH_ADDR_PORT_MASK; 
47     ETH_ADDR_PORT |= reg;
48
49     // Output register data to port.
50     ETH_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     ETH_DATA_PORT = ETH_DATA_PORT_MASK;
61
62     return;
63
64
65
66 static unsigned char etherdev_reg_read(unsigned char reg)
67 {
68     unsigned char rd_data;
69
70     // Select register address.
71     ETH_ADDR_PORT &= ~ETH_ADDR_PORT_MASK;
72     ETH_ADDR_PORT |= reg;
73
74     // Enable register data output from RTL8019AS.
75     NICE = 0;
76     IOR = 0;
77
78     // Read register data from port.
79     rd_data = ETH_DATA_PORT;
80
81     // Disable register data output from RTL8019AS.
82     IOR = 1; 
83     NICE = 1;   
84
85     return rd_data;
86
87
88
89 /*
90                                                                      
91                             etherdev_init()                          
92                                                                      
93   Returns: 1 on success, 0 on failure.                               
94   Refer to National Semiconductor DP8390 App Note 874, July 1993.    
95                                                                      
96  */
97 bit etherdev_init(void)
98 {
99     // Set IOR & IOW as they're active low.
100     IOR = 1;
101     IOW = 1;
102     NICE = 1;
103
104     // Set register data port as input.
105     ETH_DATA_PORT = ETH_DATA_PORT_MASK;
106
107     // Configure RTL8019AS ethernet controller.
108
109     // Keil startup code takes 4ms to execute (18.432MHz, X1 mode).
110     // That leaves plenty of time for the RTL8019AS to read it's
111     // configuration in from the 9346 EEPROM before we get here.
112
113     // Select RTL8019AS register page 0.
114     ETHERDEV_SELECT_REG_PAGE(0);
115
116     // Check if RTL8019AS fully reset.
117     if(!(etherdev_reg_read(ISR) & RST))
118     {
119         return 0;
120     }
121
122     // Stop RTL8019AS, select page 0 and abort DMA operation.
123     etherdev_reg_write(CR, RD2 | STP);
124
125     // Initialise data configuration register. 
126     // FIFO threshold 8 bytes, no loopback, don't use auto send packet.
127     etherdev_reg_write(DCR, FT1 | LS);
128
129     // Reset remote byte count registers.
130     etherdev_reg_write(RBCR0, 0x00);
131     etherdev_reg_write(RBCR1, 0x00);
132
133     // Receive configuration register to monitor mode.
134     etherdev_reg_write(RCR, MON);
135
136     // Initialise transmit configuration register to loopback internally.
137     etherdev_reg_write(TCR, LB0);
138
139     // Clear interrupt status register bits by writing 1 to each.
140     etherdev_reg_write(ISR, 0xFF);
141
142     // Mask all interrupts in mask register.
143     etherdev_reg_write(IMR, 0x00);
144
145     // Obtengo MAC de la placa
146     etherdev_reg_write(RBCR0, 0x0c); // Vamos a leer 12 bytes (2 x 6)
147     etherdev_reg_write(RBCR1, 0x00); 
148     etherdev_reg_write(RSAR0, 0x00); // En la dirección 0x0000
149     etherdev_reg_write(RSAR1, 0x00);
150     etherdev_reg_write(CR, RD0 | STA); // Comienza lectura
151     uip_buf[6] = etherdev_reg_read(RDMA);
152     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
153     uip_buf[7] = etherdev_reg_read(RDMA);
154     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
155     uip_buf[8] = etherdev_reg_read(RDMA);
156     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
157     uip_buf[9] = etherdev_reg_read(RDMA);
158     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
159     uip_buf[10] = etherdev_reg_read(RDMA);
160     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
161     uip_buf[11] = etherdev_reg_read(RDMA);
162     etherdev_reg_read(RDMA); // Ignoramos porque viene como un word
163
164     // Wait until remote DMA operation completes.
165     while(!(etherdev_reg_read(ISR) & RDC)) continue;
166
167     // Abort/ complete DMA operation.
168     etherdev_reg_write(CR, RD2 | STP);
169
170     // Limpia ISR
171     etherdev_reg_write(ISR, RDC);
172
173     // Set transmit page start.
174     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
175
176     // Set receive buffer page start.
177     etherdev_reg_write(PSTART, ETH_RX_PAGE_START);
178
179     // Initialise last receive buffer read pointer.
180     etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
181
182     // Set receive buffer page stop.
183     etherdev_reg_write(PSTOP, ETH_RX_PAGE_STOP);
184
185     // Select RTL8019AS register page 1.
186     etherdev_reg_write(CR, RD2 | PS0 | STP);
187
188     // Initialise current packet receive buffer page pointer
189     etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
190
191     // Set physical address
192     etherdev_reg_write(PAR0, uip_buf[0]);
193     etherdev_reg_write(PAR1, uip_buf[0]);
194     etherdev_reg_write(PAR2, uip_buf[0]);
195     etherdev_reg_write(PAR3, uip_buf[0]);
196     etherdev_reg_write(PAR4, uip_buf[0]);
197     etherdev_reg_write(PAR5, uip_buf[0]);
198
199     // Select RTL8019AS register page 0 and abort DMA operation.
200     etherdev_reg_write(CR, RD2 | STP);
201
202     // Restart RTL8019AS. 
203     etherdev_reg_write(CR, RD2 | STA);
204
205     // Initialise transmit configuration register for normal operation.
206     etherdev_reg_write(TCR, 0x00);
207
208     // Receive configuration register to accept broadcast packets.
209     etherdev_reg_write(RCR, AB);
210
211     return 1;
212 }
213
214
215 /*
216                                                                      
217                            etherdev_send()                           
218                                                                      
219  Send the packet in the uip_buf and uip_appdata buffers using the    
220  RTL8019AS ethernet card.                                            
221                                                                      
222  */
223 void etherdev_send(void)
224 {
225     unsigned int i;
226
227     // Setup for DMA transfer from uip_buf & uip_appdata buffers to RTL8019AS.
228
229     // Select RTL8019AS register page 0 and abort DMA operation.
230     etherdev_reg_write(CR, RD2 | STA);
231
232     // Wait until pending transmit operation completes.
233     while(etherdev_reg_read(CR) & TXP) continue;
234
235     // Set remote DMA start address registers to indicate where to load packet.
236     etherdev_reg_write(RSAR0, 0x00);
237     etherdev_reg_write(RSAR1, ETH_TX_PAGE_START);
238
239     // Set remote DMA byte count registers to indicate length of packet load.
240     etherdev_reg_write(RBCR0, (unsigned char)(uip_len & 0xFF));
241     etherdev_reg_write(RBCR1, (unsigned char)(uip_len >> 8));
242
243     // Initiate DMA transfer of uip_buf & uip_appdata buffers to RTL8019AS.
244     etherdev_reg_write(CR, RD1 | STA);
245
246     // DMA transfer packet from uip_buf & uip_appdata to RTL8019AS local
247     // transmit buffer memory.
248     for(i = 0; i < uip_len; i++)
249     {
250         etherdev_reg_write(RDMA, uip_buf[i]);
251     }
252
253     // Wait until remote DMA operation complete.
254     while(!(etherdev_reg_read(ISR) & RDC)) continue;
255
256     // Clear remote DMA complete interrupt status register bit.
257     etherdev_reg_write(ISR, RDC);
258
259     // Abort/ complete DMA operation.
260     etherdev_reg_write(CR, RD2 | STA);
261
262     // Set transmit page start to indicate packet start.
263     etherdev_reg_write(TPSR, ETH_TX_PAGE_START);
264
265     // Ethernet packets must be > 60 bytes, otherwise are rejected as runts.
266     if(uip_len < ETH_MIN_PACKET_LEN)
267     {
268         uip_len = ETH_MIN_PACKET_LEN;
269     }
270
271     // Set transmit byte count registers to indicate packet length.
272     etherdev_reg_write(TBCR0, (unsigned char)(uip_len & 0xFF));
273     etherdev_reg_write(TBCR1, (unsigned char)(uip_len >> 8));
274
275     // Issue command for RTL8019AS to transmit packet from it's local buffer.
276     etherdev_reg_write(CR, RD2 | TXP | STA);
277
278     return;
279 }
280
281
282 static void etherdev_reset()
283 {
284     bit retransmit = etherdev_reg_read(CR) & TXP;
285
286     // If the receive buffer ring has overflowed we dump the whole
287     // thing and start over. There is no way of knowing whether the
288     // data it contains is uncorrupted, or will cause us grief.
289
290     // Stop RTL8019AS and abort DMA operation.
291     etherdev_reg_write(CR, RD2 | STP);
292
293     // Wait for controller to halt after any current tx completes.
294     while(!(etherdev_reg_read(ISR) & RST)) continue;
295
296     // Reset remote byte count registers.
297     etherdev_reg_write(RBCR0, 0x00);
298     etherdev_reg_write(RBCR1, 0x00);
299
300     // Check whether currently transmitting a packet.
301     if(retransmit)
302     {
303         // If neither a successful transmission nor a tx abort error 
304         // has occured, then flag current tx packet for resend.
305         if(etherdev_reg_read(ISR) & (PTX | TXE))
306         {
307             retransmit = 0;
308         }
309     }
310
311     // Set transmit configuration register to loopback internally.
312     etherdev_reg_write(TCR, LB0);
313
314     // Restart the RTL8019AS.
315     etherdev_reg_write(CR, RD2 | STA);
316
317     // Re-initialise last receive buffer read pointer.
318     etherdev_reg_write(BNRY, ETH_RX_PAGE_START);
319
320     // Select RTL8019AS register page 1.
321     ETHERDEV_SELECT_REG_PAGE(1);
322
323     // Re-initialise current packet receive buffer page pointer.
324     etherdev_reg_write(CURR, ETH_RX_PAGE_START + 1);
325
326     // Select RTL8019AS register page 0.
327     ETHERDEV_SELECT_REG_PAGE(0);
328
329     // Clear rx buffer overflow & packet received interrupt flags.
330     etherdev_reg_write(ISR, PRX | OVW);
331
332     // Re-itialise transmit configuration reg for normal operation.
333     etherdev_reg_write(TCR, 0x00);
334
335     if(retransmit)
336     {
337         // Retransmit packet in RTL8019AS local tx buffer.
338         etherdev_reg_write(CR, RD2 | TXP | STA);
339     }
340 }
341
342
343 unsigned int etherdev_read(void)
344 {    
345     unsigned int len = 0;
346
347     // Check if the rx buffer has overflowed.
348     if (etherdev_reg_read(ISR) & OVW)
349     {
350         unsigned char current;
351
352         // Select RTL8019AS register page 1.
353         ETHERDEV_SELECT_REG_PAGE(1);
354
355         // Retrieve current receive buffer page
356         current = etherdev_reg_read(CURR);
357
358         // Select RTL8019AS register page 1.
359         ETHERDEV_SELECT_REG_PAGE(0);
360
361         if (etherdev_reg_read(BNRY) == current)
362         {
363
364             leds1 = ~0x01;
365             leds2 = ~etherdev_reg_read(ISR);
366             sleep(5);
367             leds1 = ~0x02;
368             leds2 = ~etherdev_reg_read(BNRY);
369             sleep(5);
370             leds1 = ~0x04;
371             leds2 = ~current;
372             sleep(5);
373
374             etherdev_reset();
375         }
376     }
377     // Check if there is a packet in the rx buffer.
378     else if (etherdev_reg_read(ISR) & PRX)
379     {
380         unsigned int i;
381         unsigned char next_rx_packet;
382         unsigned char current;
383         unsigned char bnry;
384         unsigned char status;
385
386         // Retrieve packet header. (status, next_ptr, length_l, length_h)
387
388         // Set remote DMA start address registers to packet header.
389         bnry = etherdev_reg_read(BNRY) + 1;
390         if (bnry >= ETH_RX_PAGE_STOP)
391             bnry = ETH_RX_PAGE_START;
392         etherdev_reg_write(RSAR0, 0x00);
393         etherdev_reg_write(RSAR1, bnry);
394
395         // Select RTL8019AS register page 1.
396         ETHERDEV_SELECT_REG_PAGE(1);
397
398         // Retrieve current receive buffer page
399         current = etherdev_reg_read(CURR);
400
401         // Select RTL8019AS register page 1.
402         ETHERDEV_SELECT_REG_PAGE(0);
403
404         // Check if last packet has been removed from rx buffer.
405         if(bnry == current)
406         {
407             // Clear packet received interrupt flag.
408             etherdev_reg_write(ISR, PRX | RXE);
409             return 0;
410         }
411
412         // Set remote DMA byte count registers to packet header length.
413         etherdev_reg_write(RBCR0, 0x04);
414         etherdev_reg_write(RBCR1, 0x00);
415
416         // Clear remote DMA complete interrupt status register bit.
417         etherdev_reg_write(ISR, RDC);
418
419         // Initiate DMA transfer of packet header.
420         etherdev_reg_write(CR, RD0 | STA);
421
422         // Packet status.
423         status = etherdev_reg_read(RDMA);
424
425         // Save next packet pointer.
426         next_rx_packet = etherdev_reg_read(RDMA);
427
428         // Retrieve packet data length and subtract CRC bytes.
429         len =  etherdev_reg_read(RDMA);
430         len += etherdev_reg_read(RDMA) << 8;
431         len -= 4;
432
433         // Wait until remote DMA operation completes.
434         while(!(etherdev_reg_read(ISR) & RDC)) continue;
435
436         // Abort/ complete DMA operation.
437         etherdev_reg_write(CR, RD2 | STA);
438
439         // Limpia ISR
440         etherdev_reg_write(ISR, RDC);
441
442         // Si es un paquete inválido, lo dropeamos
443         if (len < 60 || len > 1518)
444         {
445             len = 0;
446             goto drop;
447         }
448
449         // Si hubo un error, también lo dropeamos
450         if ((status & 0x0F) != RXSOK)
451         {
452             len = 0;
453             goto drop;
454         }
455
456         // Retrieve packet data.
457
458         // Check if incoming packet will fit into rx buffer.
459         if(len <= sizeof(uip_buf))
460         {
461
462             // Set remote DMA start address registers to packet data.
463             etherdev_reg_write(RSAR0, 0x04);
464             etherdev_reg_write(RSAR1, bnry);
465
466             // Set remote DMA byte count registers to packet data length.
467             etherdev_reg_write(RBCR0, (unsigned char)(len & 0xFF));
468             etherdev_reg_write(RBCR1, (unsigned char)(len >> 8));
469
470             // Initiate DMA transfer of packet data.
471             etherdev_reg_write(CR, RD0 | STA);
472
473             // Read packet data directly into uip_buf.
474             uip_len = len;
475             for(i = 0; i < 14; i++)
476             {
477                 etherdev_reg_read(RDMA); // XXX descarto cabecera eth
478             }
479             for(i = 14; i < len; i++)
480             {
481                 uip_buf[i] = etherdev_reg_read(RDMA); // XXX copio el resto
482             }
483
484             // Wait until remote DMA operation complete.
485             while(!(etherdev_reg_read(ISR) & RDC)) continue;
486
487             // Abort/ complete DMA operation.
488             etherdev_reg_write(CR, RD2 | STA);
489
490             // Clear remote DMA complete interrupt status register bit.
491             etherdev_reg_write(ISR, RDC);
492
493         }
494         else
495         {
496             // Incoming packet too big, so dump it.
497             len = 0;
498         }
499
500 drop:
501         // Advance boundary pointer to next packet start.
502         etherdev_reg_write(BNRY, next_rx_packet - 1);
503
504     }
505
506     return len;
507 }
508