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