]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/cl/cs8900a/v2_0/src/if_cs8900a.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / eth / cl / cs8900a / v2_0 / src / if_cs8900a.c
1 //==========================================================================
2 //
3 //      dev/if_cs8900a.c
4 //
5 //      Device driver for Cirrus Logic CS8900A ethernet controller
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //####BSDCOPYRIGHTBEGIN####
41 //
42 // -------------------------------------------
43 //
44 // Portions of this software may have been derived from OpenBSD or other sources,
45 // and are covered by the appropriate copyright disclaimers included herein.
46 //
47 // -------------------------------------------
48 //
49 //####BSDCOPYRIGHTEND####
50 //==========================================================================
51 //#####DESCRIPTIONBEGIN####
52 //
53 // Author(s):    gthomas
54 // Contributors: gthomas, jskov
55 // Date:         2001-11-02
56 // Purpose:      
57 // Description:  Driver for CS8900 ethernet controller
58 //
59 // Note:         Platform can define CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS
60 //               to get a timer thread polling instead of interupt based
61 //               operation.
62 //
63 // Note:         Driver will need some changes to support multiple instances
64 //
65 //####DESCRIPTIONEND####
66 //
67 //==========================================================================
68
69 #include <pkgconf/system.h>
70 #ifdef CYGPKG_KERNEL
71 #include <cyg/kernel/kapi.h>
72 #endif
73 #include <pkgconf/io_eth_drivers.h>
74
75 #include <cyg/infra/cyg_type.h>
76 #include <cyg/infra/cyg_ass.h>
77 #include <cyg/hal/hal_arch.h>
78 #include <cyg/hal/hal_intr.h>
79 #include <cyg/hal/hal_endian.h>
80 #include <cyg/infra/diag.h>
81 #include <cyg/hal/drv_api.h>
82 #undef __ECOS
83 #define __ECOS
84 #include <cyg/io/eth/eth_drv.h>
85 #include <cyg/io/eth/netdev.h>
86
87 #include <cyg/io/cs8900.h>
88
89 #define __WANT_DEVS
90 #include CYGDAT_DEVS_ETH_CL_CS8900A_INL
91 #undef __WANT_DEVS
92
93 // NOINTS operation only relevant when the NET package is loaded
94 #if !defined(CYGPKG_NET) || !defined(CYGPKG_KERNEL)
95 # undef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS
96 #endif
97
98 #ifdef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS
99 #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
100 static char cs8900a_fake_int_stack[STACK_SIZE];
101 static cyg_thread cs8900a_fake_int_thread_data;
102 static cyg_handle_t cs8900a_fake_int_thread_handle;
103 static void cs8900a_fake_int(cyg_addrword_t);
104 #endif
105
106 #ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
107 extern int cyg_io_eth_net_debug;
108 #endif
109
110 static void cs8900a_poll(struct eth_drv_sc *sc);
111 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
112 // This ISR is called when the ethernet interrupt occurs
113 static int
114 cs8900a_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
115 {
116     cs8900a_priv_data_t* cpd = (cs8900a_priv_data_t *)data;
117     cyg_drv_interrupt_mask(cpd->interrupt);
118     cyg_drv_interrupt_acknowledge(cpd->interrupt);
119     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
120 }
121
122 static void
123 cs8900a_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
124 {
125     // This conditioning out is necessary because of explicit calls to this
126     // DSR - which would not ever be called in the case of a polled mode
127     // usage ie. in RedBoot.
128 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
129     cs8900a_priv_data_t* cpd = (cs8900a_priv_data_t *)data;
130     struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->tab);
131     struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
132
133     DEBUG_FUNCTION();
134
135     // but here, it must be a *sc:
136     eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
137 #else
138 # ifndef CYGPKG_REDBOOT
139 #  error Empty CS8900A ethernet DSR is compiled.  Is this what you want?
140 # endif
141 #endif
142 }
143 #endif
144
145 // The deliver function (ex-DSR)  handles the ethernet [logical] processing
146 static void
147 cs8900a_deliver(struct eth_drv_sc *sc)
148 {
149     cs8900a_poll(sc);
150 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
151     {
152         cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
153         // Allow interrupts to happen again
154         cyg_drv_interrupt_unmask(cpd->interrupt);
155     }
156 #endif
157 }
158
159 static int
160 cs8900a_int_vector(struct eth_drv_sc *sc)
161 {
162     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
163     return (cpd->interrupt);
164 }
165
166 static bool 
167 cs8900a_init(struct cyg_netdevtab_entry *tab)
168 {
169     struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
170     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
171     cyg_addrword_t base = cpd->base;
172     cyg_uint16 chip_type, chip_rev, chip_status;
173     cyg_uint16 i;
174 #ifndef CS8900A_RESET_BYPASS
175     long timeout = 500000;
176 #endif
177     cyg_bool esa_configured = false;
178     
179     cpd->tab = tab;
180
181     CYGHWR_CL_CS8900A_PLF_INIT(cpd);
182
183 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
184     // Initialize environment, setup interrupt handler
185     cyg_drv_interrupt_create(cpd->interrupt,
186                              cpd->priority,
187                              (cyg_addrword_t)cpd, //  Data item passed to interrupt handler
188                              (cyg_ISR_t *)cs8900a_isr,
189                              (cyg_DSR_t *)cs8900a_dsr,
190                              &cpd->interrupt_handle,
191                              &cpd->interrupt_object);
192     cyg_drv_interrupt_attach(cpd->interrupt_handle);
193     cyg_drv_interrupt_acknowledge(cpd->interrupt);
194     cyg_drv_interrupt_unmask(cpd->interrupt);
195
196 #ifdef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS
197     cyg_thread_create(1,                 // Priority
198                       cs8900a_fake_int,   // entry
199                       (cyg_addrword_t)sc, // entry parameter
200                       "CS8900 int",      // Name
201                       &cs8900a_fake_int_stack[0],         // Stack
202                       STACK_SIZE,        // Size
203                       &cs8900a_fake_int_thread_handle,    // Handle
204                       &cs8900a_fake_int_thread_data       // Thread data structure
205             );
206     cyg_thread_resume(cs8900a_fake_int_thread_handle);  // Start it
207 #endif
208 #endif
209
210     // Read controller ID - the first is a dummy read, since (on some
211     // platforms) the first access to the controller seems to skip the
212     // MSB 8 bits.
213     get_reg(base, PP_ChipID);
214     chip_type = get_reg(base, PP_ChipID);
215     chip_rev = get_reg(base, PP_ChipRev);
216 #if DEBUG & 8
217     diag_printf("CS8900A[%p] - type: 0x%04x, rev: 0x%04x\n", base, chip_type, chip_rev);
218 #endif
219     if (chip_type != PP_ChipID_CL) {
220 #if DEBUG & 8
221         diag_printf("CS8900 - invalid type (0x%04x), must be 0x630e\n", chip_type);
222 #endif
223         return false;
224     }
225
226     CYGHWR_CL_CS8900A_PLF_RESET(base);
227 #ifndef CS8900A_RESET_BYPASS
228     put_reg(base, PP_SelfCtl, PP_SelfCtl_Reset);  // Reset chip
229
230     CYGHWR_CL_CS8900A_PLF_POST_RESET(base);
231     
232     while ((get_reg(base, PP_SelfStat) & PP_SelfStat_InitD) == 0) {
233         if (--timeout <= 0) {
234 #if DEBUG & 8
235             diag_printf("CS8900 didn't reset - abort!\n");
236 #endif
237             return false;
238         }
239     }
240 #endif /* CS8900A_RESET_BYPASS */
241
242     chip_status = get_reg(base, PP_SelfStat);
243 #if DEBUG & 8
244     diag_printf("CS8900 - status: 0x%04x (%sEEPROM present)\n", chip_status,
245                 chip_status & PP_SelfStat_EEPROM ? "" : "no ");
246 #endif
247
248
249     // Disable reception whilst finding the ESA
250     put_reg(base, PP_LineCTL, 0 );
251     // Find ESA - check possible sources in sequence and stop when
252     // one provides the ESA:
253     //   RedBoot option (via provide_esa)
254     //   Compile-time configuration
255     //   EEPROM
256     //   <fail configuration of device>
257     if (NULL != cpd->provide_esa) {
258         esa_configured = cpd->provide_esa(cpd);
259 # if DEBUG & 8
260         if (esa_configured)
261             diag_printf("Got ESA from RedBoot option\n");
262 # endif
263     }
264     if (!esa_configured && cpd->hardwired_esa) {
265         // ESA is already set in cpd->esa[]
266 #if DEBUG & 8
267         diag_printf("Got hardcoded ESA\n");
268 #endif
269         esa_configured = true;
270     }
271     if (!esa_configured && (chip_status & PP_SelfStat_EEPROM)) {
272         // Get ESA from EEPROM - via the PP_IA registers
273         cyg_uint16 esa_word;
274         for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
275 #ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
276             esa_word = get_reg(base, PP_IA+i);
277             cpd->esa[i] = (esa_word & 0xFF);
278             cpd->esa[i+1] = (esa_word >> 8) & 0xFF;
279 #else
280             esa_word = get_reg(base, PP_IA+CYG_SWAP16(i));
281             cpd->esa[i+1] = (esa_word & 0xFF);
282             cpd->esa[i] = (esa_word >> 8) & 0xFF;
283 #endif
284         }
285 #if DEBUG & 8
286         diag_printf("Got EEPROM ESA\n");
287 #endif
288         esa_configured = true;
289     }
290     if (!esa_configured) {
291 # if DEBUG & 8
292         diag_printf("CS8900 - no EEPROM, static ESA or RedBoot config option.\n");
293 # endif
294         return false;
295     }
296
297     // Tell the chip what ESA to use
298     for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
299 #ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
300         put_reg(base, PP_IA+i, cpd->esa[i] | (cpd->esa[i+1] << 8));
301 #else
302         put_reg(base, PP_IA+CYG_SWAP16(i), cpd->esa[i+1] | (cpd->esa[i] << 8));
303 #endif
304     }
305     // Set logical address mask
306     for (i = 0;  i < 8;  i += 2) {
307 #ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
308         put_reg(base, PP_LAF+i, 0xFFFF);
309 #else
310         put_reg(base, PP_LAF+CYG_SWAP16(i), 0xFFFF);
311 #endif
312     }
313 # if DEBUG & 8
314     diag_printf("ESA %02x:%02x:%02x:%02x:%02x:%02x\n",
315                 cpd->esa[0], cpd->esa[1], cpd->esa[2],
316                 cpd->esa[3], cpd->esa[4], cpd->esa[5]);
317 # endif
318
319     // Initialize upper level driver
320     (sc->funs->eth_drv->init)(sc, cpd->esa);
321
322     return true;
323 }
324
325 static void
326 cs8900a_stop(struct eth_drv_sc *sc)
327 {
328     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
329     cyg_addrword_t base = cpd->base;
330
331     put_reg(base, PP_LineCTL, 0);
332 }
333
334 // This function is called to "start up" the interface.  It may be called
335 // multiple times, even when the hardware is already running.  It will be
336 // called whenever something "hardware oriented" changes and should leave
337 // the hardware ready to send/receive packets.
338 static void
339 cs8900a_start(struct eth_drv_sc *sc, cyg_uint8 *esa, int flags)
340 {
341     cyg_uint16 stat;
342     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
343     cyg_addrword_t base = cpd->base;
344
345     put_reg(base, PP_BusCtl, PP_BusCtl_MemoryE);  // Disable interrupts, memory mode
346     put_reg(base, PP_IntReg, PP_IntReg_IRQ0);  // Only possibility
347     put_reg(base, PP_RxCFG, PP_RxCFG_RxOK | PP_RxCFG_CRC | 
348                       PP_RxCFG_RUNT | PP_RxCFG_EXTRA);
349     cpd->rxmode = PP_RxCTL_RxOK | PP_RxCTL_Broadcast | PP_RxCTL_IA;
350     put_reg(base, PP_RxCTL, cpd->rxmode);
351     put_reg(base, PP_TxCFG, PP_TxCFG_TxOK | PP_TxCFG_Collision | 
352                       PP_TxCFG_CRS | PP_TxCFG_SQE | PP_TxCFG_Late | 
353                       PP_TxCFG_Jabber | PP_TxCFG_16Collisions);
354     put_reg(base, PP_BufCFG, PP_BufCFG_TxRDY | PP_BufCFG_TxUE | PP_BufCFG_RxMiss | 
355                        PP_BufCFG_TxCol | PP_BufCFG_Miss | PP_BufCFG_SWI);
356     put_reg(base, PP_IntReg, PP_IntReg_IRQ0);  // Only possibility
357     put_reg(base, PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
358     // Clear Interrupt Status Queue before enabling interrupts
359     do {
360         HAL_READ_UINT16(cpd->base+CS8900A_ISQ, stat);
361     }  while (stat != 0) ;
362     cpd->txbusy = false;
363     put_reg(base, PP_BusCtl, PP_BusCtl_EnableIRQ);
364 }
365
366 // This routine is called to perform special "control" opertions
367 static int
368 cs8900a_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
369 {
370     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
371     cyg_addrword_t base = cpd->base;
372     struct eth_drv_mc_list *mc_list = data;
373     unsigned char *esa = (unsigned char *)data;
374     int i;
375
376     switch (key) {
377     case ETH_DRV_SET_MAC_ADDRESS:
378 #if 9 & DEBUG
379         diag_printf("CS8900A - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
380                 esa[0], esa[1], esa[2],
381                 esa[3], esa[4], esa[5] );
382 #if !defined(CYGSEM_DEVS_ETH_CL_CS8900A_WRITE_EEPROM) || !defined(CS8900A_PROGRAM_EEPROM)
383         diag_printf("*** PERMANENT EEPROM WRITE NOT ENABLED ***\n");
384 #endif
385 #endif // DEBUG
386
387         // We can write the MAC address into the interface info,
388         // and the chip registers no problem.
389         for ( i = 0; i < sizeof(cpd->esa);  i++ )
390             cpd->esa[i] = esa[i];
391         for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
392             cyg_uint16 reg = cpd->esa[i] | (cpd->esa[i+1] << 8);
393             put_reg(cpd->base, PP_IA+i, reg );
394         }
395 #if defined(CYGSEM_DEVS_ETH_CL_CS8900A_WRITE_EEPROM) && defined(CS8900A_PROGRAM_EEPROM)
396         if (CS8900A_PROGRAM_EEPROM(cpd))
397             return 1;
398         else 
399             return 0;
400 #elif defined(CYGSEM_DEVS_ETH_CL_CS8900A_WRITE_EEPROM) && !defined(CS8900A_PROGRAM_EEPROM)
401         /* WRITE_EEPROM requested, but no PROGRAM_EEPROM provided */
402         return 1;
403 #else /* !CYGSEM_DEVS_ETH_CL_CS8900A_WRITE_EEPROM - No need to write EEPROM */
404         return 0;
405 #endif
406
407 #ifdef ETH_DRV_GET_MAC_ADDRESS
408     case ETH_DRV_GET_MAC_ADDRESS:
409         // Extract the MAC address that is in the chip, and tell the
410         // system about it.
411         for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
412             unsigned short z = get_reg(cpd->base, PP_IA+i/2 );
413             esa[i] =   (unsigned char)(0xff & z);
414             esa[i+1] = (unsigned char)(0xff & (z >> 8));
415         }
416         return 0;
417 #endif
418     case ETH_DRV_SET_MC_LIST:
419     case ETH_DRV_SET_MC_ALL:
420         // Note: this code always accepts all multicast addresses if any
421         // are desired.  It would be possible to accept a subset by adjusting
422         // the Logical Address Filter (LAF), but that would require scanning
423         // this list and building a suitable mask.
424         if (mc_list->len) {
425             cpd->rxmode |= PP_RxCTL_Multicast;
426         } else {
427             cpd->rxmode &= ~PP_RxCTL_Multicast;
428         }
429         put_reg(base, PP_RxCTL, cpd->rxmode);  // When is it safe to do this?
430         return 0;
431     default:
432         return 1;
433         break;
434     }
435 }
436
437 // This routine is called to see if it is possible to send another packet.
438 // It will return non-zero if a transmit is possible, zero otherwise.
439 static int
440 cs8900a_can_send(struct eth_drv_sc *sc)
441 {
442     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
443     cyg_addrword_t base = cpd->base;
444     cyg_uint16 stat;
445
446     stat = get_reg(base, PP_LineStat);
447     if ((stat & PP_LineStat_LinkOK) == 0) {
448         return false;  // Link not connected
449     }
450 #ifdef CYGPKG_KERNEL
451     // Horrible hack!
452     if (cpd->txbusy) {
453         cyg_tick_count_t now = cyg_current_time();
454         if ((now - cpd->txstart) > 25) {
455             // 250ms is more than enough to transmit one frame
456 #if DEBUG & 1
457             diag_printf("CS8900: Tx interrupt lost\n");
458 #endif
459             cpd->txbusy = false;
460             // Free up the buffer (with error indication)
461             (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, 1);
462         }
463     }
464 #endif
465     return (cpd->txbusy == false);
466 }
467
468 // This routine is called to send data to the hardware.
469 static void 
470 cs8900a_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, 
471             int total_len, unsigned long key)
472 {
473     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
474     cyg_addrword_t base = cpd->base;
475     int i;
476     int len;
477     cyg_uint8 *data;
478     cyg_uint16 saved_data = 0, *sdata;
479     cyg_uint16 stat;
480     bool odd_byte = false;
481
482     // Mark xmitter busy
483     cpd->txbusy = true;
484     cpd->txkey = key;
485 #ifdef CYGPKG_KERNEL
486     cpd->txstart = cyg_current_time();
487 #endif
488
489     // Start the xmit sequence
490 #ifdef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
491     total_len = CYG_SWAP16(total_len);
492 #endif
493         
494     // The hardware indicates that there are options as to when the actual
495     // packet transmission will start wrt moving of data into the transmit
496     // buffer.  However, impirical results seem to indicate that if the
497     // packet is large and transmission is allowed to start before the
498     // entire packet has been pushed into the buffer, the hardware gets
499     // confused and the packet is lost, along with a "lost" Tx interrupt.
500     // This may be a case of the copy loop below being interrupted, e.g.
501     // a system timer interrupt, and the hardware getting unhappy that 
502     // not all of the data was provided before the transmission should
503     // have completed (i.e. buffer underrun).
504     // For now, the solution is to not allow this overlap.
505     //HAL_WRITE_UINT16(cpd->base+CS8900A_TxCMD, PP_TxCmd_TxStart_5)
506
507     // Start only when all data sent to chip
508     HAL_WRITE_UINT16(cpd->base+CS8900A_TxCMD, PP_TxCmd_TxStart_Full);
509
510     HAL_WRITE_UINT16(cpd->base+CS8900A_TxLEN, total_len);
511     // Wait for controller ready signal
512     {
513         // add timeout per cs8900a bugzilla report 1000281 */
514         int timeout = 1000;
515
516         do {
517             stat = get_reg(base, PP_BusStat);
518 #if DEBUG & 1
519             if( stat & PP_BusStat_TxBid )
520                 diag_printf( "cs8900a_send: Bid error!\n" );
521 #endif
522         } while (!(stat & PP_BusStat_TxRDY) && --timeout);
523
524         if( !timeout ) {
525             // we might as well just return, since if we write the data it will
526             // just get thrown away
527             diag_printf("if_cs8900a.c:  PP_BusStat_TXRDY is not set. Cannot transmit packet\n");
528             return;
529         }
530     }
531
532     // Put data into buffer
533     for (i = 0;  i < sg_len;  i++) {
534         data = (cyg_uint8 *)sg_list[i].buf;
535         len = sg_list[i].len;
536
537         if (len > 0) {
538             /* Finish the last word. */
539             if (odd_byte) {
540 // This new byte must get on the bus _after_ the last saved odd byte, it therefore
541 // belongs in the MSB of the CS8900a
542 #ifdef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED                            
543                 saved_data |= *data++;
544 #else
545                 saved_data |= ((cyg_uint16)*data++) << 8;
546 #endif
547                 HAL_WRITE_UINT16(cpd->base+CS8900A_RTDATA, saved_data);
548                 len--;
549                 odd_byte = false;
550             }
551             if (((CYG_ADDRESS)data & 0x1) == 0) {
552                 /* Aligned on 16-bit boundary, so output contiguous words. */
553                 sdata = (cyg_uint16 *)data;
554                 while (len > 1) {
555                                         // Make sure data get on the bus in Big Endian format
556 #if((CYG_BYTEORDER == CYG_MSBFIRST) && defined(CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED) || \
557     (CYG_BYTEORDER == CYG_LSBFIRST) && !defined(CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED ))
558                     HAL_WRITE_UINT16(cpd->base+CS8900A_RTDATA, *sdata++);
559 #else
560                     HAL_WRITE_UINT16(cpd->base+CS8900A_RTDATA, CYG_SWAP16(*sdata++));
561 #endif
562                     len -= sizeof(cyg_uint16);
563                 }
564                 data = (cyg_uint8 *)sdata;
565             } else {
566                 /* Not 16-bit aligned, so byte copy */
567                 while (len > 1) {
568                     saved_data = (cyg_uint16)*data++;   // reuse saved_data
569                                         // Make sure data get on the bus in Big Endian format, the first byte belongs in the
570                                         // LSB of the CS8900A
571 #ifdef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
572                     saved_data =  ((cyg_uint16)*data++) | (saved_data << 8);
573 #else
574                     saved_data |= ((cyg_uint16)*data++) << 8;
575 #endif
576                     HAL_WRITE_UINT16(cpd->base+CS8900A_RTDATA, saved_data);
577                     len -= sizeof(cyg_uint16);
578                 }
579             }
580             /* Save last byte, if necessary. */
581             if (len == 1) {
582                 saved_data = (cyg_uint16)*data;
583 // This _last_ byte must get on the bus _first_, it therefore belongs in the LSB of
584 // the CS8900a
585 #ifdef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
586                 saved_data = (saved_data << 8);
587 #endif
588                 odd_byte = true;
589             }
590         }
591     }
592     if (odd_byte) {
593         HAL_WRITE_UINT16(cpd->base+CS8900A_RTDATA, saved_data);
594     }
595 }
596
597 // This function is called when a packet has been received.  It's job is
598 // to prepare to unload the packet from the hardware.  Once the length of
599 // the packet is known, the upper layer of the driver can be told.  When
600 // the upper layer is ready to unload the packet, the internal function
601 // 'cs8900a_recv' will be called to actually fetch it from the hardware.
602 static void
603 cs8900a_RxEvent(struct eth_drv_sc *sc, int stat)
604 {
605     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
606     cyg_addrword_t base = cpd->base;
607     cyg_uint16 len;
608
609     if(stat & PP_RxCFG_RxOK) {
610         // Only start reading a message if one has been received
611         HAL_READ_UINT16(base+CS8900A_RTDATA, stat);
612         HAL_READ_UINT16(base+CS8900A_RTDATA, len);
613
614 #ifdef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED
615         len = CYG_SWAP16(len);
616 #endif
617
618         CYG_ASSERT(len > 0, "Zero length ethernet frame received");
619         
620 #ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
621         if (cyg_io_eth_net_debug) {
622             diag_printf("RxEvent - stat: %x, len: %d\n", stat, len);
623         }
624 #endif
625         (sc->funs->eth_drv->recv)(sc, len);
626     }
627 }
628
629 // This function is called as a result of the "eth_drv_recv()" call above.
630 // It's job is to actually fetch data for a packet from the hardware once
631 // memory buffers have been allocated for the packet.  Note that the buffers
632 // may come in pieces, using a scatter-gather list.  This allows for more
633 // efficient processing in the upper layers of the stack.
634 static void
635 cs8900a_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
636 {
637     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
638     cyg_addrword_t base = cpd->base;
639     int i, mlen;
640     cyg_uint16 *data, val;
641     cyg_uint8 *cp, cval;
642
643     for (i = 0;  i < sg_len;  i++) {
644         data = (cyg_uint16 *)sg_list[i].buf;
645         mlen = sg_list[i].len;
646         while (mlen >= sizeof(*data)) {
647             HAL_READ_UINT16(base+CS8900A_RTDATA, val);
648             if (data) {
649 #if((CYG_BYTEORDER == CYG_MSBFIRST) && defined(CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED) || \
650     (CYG_BYTEORDER == CYG_LSBFIRST) && !defined(CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED ))
651                 *data++ = val;
652 #else
653                 *data++ = CYG_SWAP16(val);
654 #endif
655             }
656             mlen -= sizeof(*data);
657         }
658         if (mlen) {
659             HAL_READ_UINT16(base+CS8900A_RTDATA, val);
660 #ifndef CYGIMP_DEVS_ETH_CL_CS8900A_DATABUS_BYTE_SWAPPED 
661             // last odd byte will be in the LSB
662             cval = (cyg_uint8)(val);
663 #elif(CYG_BYTEORDER == CYG_MSBFIRST)
664             // last odd byte will be in the MSB
665             cval = (cyg_uint8)(val >> 8);
666 #endif
667             cval &= 0xff;
668             if ((cp = (cyg_uint8 *)data) != 0) {
669                 *cp = cval;
670             }
671         }
672     }
673 }
674
675 static void
676 cs8900a_TxEvent(struct eth_drv_sc *sc, int stat)
677 {
678     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
679     cyg_addrword_t base = cpd->base;
680
681     stat = get_reg(base, PP_TER);
682 #ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
683     if (cyg_io_eth_net_debug) {
684         diag_printf("Tx event: %x\n", stat);
685     }
686 #endif
687     cpd->txbusy = false;
688     (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, 0);
689 }
690
691 static void
692 cs8900a_BufEvent(struct eth_drv_sc *sc, int stat)
693 {
694     if (stat & PP_BufCFG_RxMiss) {
695     }
696     if (stat & PP_BufCFG_TxUE) {
697     }
698 }
699
700 static void
701 cs8900a_poll(struct eth_drv_sc *sc)
702 {
703     cyg_uint16 event;
704     cs8900a_priv_data_t *cpd = (cs8900a_priv_data_t *)sc->driver_private;
705     cyg_addrword_t base = cpd->base;
706     volatile int timeout=5000;
707
708     HAL_READ_UINT16(base+CS8900A_ISQ, event);
709     while (event != 0) {
710         switch (event & ISQ_EventMask) {
711         case ISQ_RxEvent:
712             cs8900a_RxEvent(sc, event);
713             break;
714         case ISQ_TxEvent:
715             cs8900a_TxEvent(sc, event);
716             break;
717         case ISQ_BufEvent:
718             cs8900a_BufEvent(sc, event);
719             break;
720         case ISQ_RxMissEvent:
721             // Receive miss counter has overflowed
722             break;
723         case ISQ_TxColEvent:
724             // Transmit collision counter has overflowed
725             break;
726         default:
727 #if DEBUG & 1
728             diag_printf("%s: Unknown event: %x\n", __FUNCTION__, event);
729 #endif
730             break;
731         }
732         while(timeout--);
733         timeout=5000;
734         HAL_READ_UINT16(base+CS8900A_ISQ, event);
735     }
736
737     CYGHWR_CL_CS8900A_PLF_INT_CLEAR(cpd);
738 }
739
740 #ifdef CYGSEM_DEVS_ETH_CL_CS8900A_NOINTS
741 void
742 cs8900a_fake_int(cyg_addrword_t param)
743 {
744     struct eth_drv_sc *sc = (struct eth_drv_sc *) param;
745     int s;
746
747 #if DEBUG & 1
748     diag_printf("cs8900a_fake_int()\n");
749 #endif
750
751     while (true) {
752         cyg_thread_delay(5);
753         s = splnet();
754         cs8900a_poll(sc);
755         splx(s);
756     }
757 }
758 #endif