]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/devs/eth/davicom/dm9000/v2_0/src/if_dm9000.c
79c9993291c4aa2c55808d9cb3d8be5ff4297bc6
[karo-tx-redboot.git] / packages / devs / eth / davicom / dm9000 / v2_0 / src / if_dm9000.c
1 //==========================================================================
2 //
3 //      if_dm9000.c
4 //
5 //      Davicom DM9000 ethernet driver
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003, 2004 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 //#####DESCRIPTIONBEGIN####
41 //
42 // Author(s):    msalter
43 // Contributors: msalter
44 // Date:         2004-03-18
45 // Purpose:      
46 // Description:  hardware driver for Davicom DM9000 NIC
47 // Notes:
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <pkgconf/system.h>
54 #include <pkgconf/io_eth_drivers.h>
55 #include <pkgconf/devs_eth_davicom_dm9000.h>
56 #include <cyg/infra/cyg_type.h>
57 #include <cyg/infra/cyg_ass.h>
58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/hal_cache.h>
60 #include <cyg/hal/hal_intr.h>
61 #include <cyg/hal/hal_endian.h>
62 #include <cyg/infra/diag.h>
63 #include <cyg/hal/hal_if.h>
64 #include <cyg/hal/drv_api.h>
65 #include <cyg/io/eth/netdev.h>
66 #include <cyg/io/eth/eth_drv.h>
67
68 #include <dm9000_info.h>
69
70 #ifdef CYGPKG_REDBOOT
71 #include <pkgconf/redboot.h>
72 #include <redboot.h>
73 #include <flash_config.h>
74 #endif
75
76 #include CYGDAT_DEVS_ETH_DAVICOM_DM9000_INL
77
78 #define DM9000_PKT_MAX 1536
79
80 //
81 // Control and Status register offsets
82 //
83 #define DM_NCR      0x00
84 #define DM_NSR      0x01
85 #define DM_TCR      0x02
86 #define DM_TSRI     0x03
87 #define DM_TSRII    0x04
88 #define DM_RCR      0x05
89 #define DM_RSR      0x06
90 #define DM_ROCR     0x07
91 #define DM_BPTR     0x08
92 #define DM_FCTR     0x09
93 #define DM_FCR      0x0a
94 #define DM_EPCR     0x0b
95 #define DM_EPAR     0x0c
96 #define DM_EPDRL    0x0d
97 #define DM_EPDRH    0x0e
98 #define DM_WCR      0x0f
99 #define DM_PAR      0x10
100 #define DM_MAR      0x16
101 #define DM_GPCR     0x1e
102 #define DM_GPR      0x1f
103 #define DM_TRPAL    0x22
104 #define DM_TRPAH    0x23
105 #define DM_RWPAL    0x24
106 #define DM_RWPAH    0x25
107 #define DM_VIDL     0x28
108 #define DM_VIDH     0x29
109 #define DM_PIDL     0x2a
110 #define DM_PIDH     0x2b
111 #define DM_CHIPR    0x2c
112 #define DM_SMCR     0x2f
113 #define DM_MRCMDX   0xf0
114 #define DM_MRCMD    0xf2
115 #define DM_MDRAL    0xf4
116 #define DM_MDRAH    0xf5
117 #define DM_MWCMDX   0xf6
118 #define DM_MWCMD    0xf8
119 #define DM_MDWAL    0xfa
120 #define DM_MDWAH    0xfb
121 #define DM_TXPLL    0xfc
122 #define DM_TXPLH    0xfd
123 #define DM_ISR      0xfe
124 #define DM_IMR      0xff
125
126 // NCR (Network Control Register)
127 #define NCR_EXT_PHY   (1 << 7)     // 1 ==> external PHY, 0 ==> internal
128 #define NCR_WAKEEN    (1 << 6)     // enable wakeup events
129 #define NCR_FCOL      (1 << 4)     // force collision mode (test)
130 #define NCR_FDX       (1 << 3)     // full duplex (read-only for internal phy)
131 #define NCR_LBK_NOR   (0 << 1)     // loopback off
132 #define NCR_LBK_MAC   (1 << 1)     // MAC loopback
133 #define NCR_LBK_PHY   (2 << 1)     // PHY loopback
134 #define NCR_RST       (1 << 0)     // Reset (auto-clears after 10us)
135
136 // NSR (Network Status Register)
137 #define NSR_SPEED     (1 << 7)     // 0 = 100Mbps, 1 = 10Mbps
138 #define NSR_LINKST    (1 << 6)     // link status (1 = okay)
139 #define NSR_WAKEST    (1 << 5)     // wake status (clear by read)
140 #define NSR_TX2END    (1 << 3)     // TX packet 2 complete
141 #define NSR_TX1END    (1 << 2)     // TX packet 1 complete
142 #define NSR_RXOV      (1 << 1)     // RX overflow
143
144 // TCR (TX Control Register)
145 #define TCR_TJDIS     (1 << 6)     // TX jabber disable
146 #define TCR_EXCECM    (1 << 5)     // 0 = abort after 15 collisions
147 #define TCR_PAD_DIS2  (1 << 4)
148 #define TCR_CRC_DIS2  (1 << 3)
149 #define TCR_PAD_DIS1  (1 << 2)
150 #define TCR_CRC_DIS1  (1 << 1)
151 #define TCR_TXREQ     (1 << 0)
152
153 // TSR (TX Status Register)
154 #define TSR_TJTO      (1 << 7)
155 #define TSR_LC        (1 << 6)
156 #define TSR_NC        (1 << 5)
157 #define TSR_LCOL      (1 << 4)
158 #define TSR_COL       (1 << 3)
159 #define TSR_EC        (1 << 2)
160
161 // RCR (RX Control Register)
162 #define RCR_WTDIS     (1 << 6)
163 #define RCR_DIS_LONG  (1 << 5)
164 #define RCR_DIS_CRC   (1 << 4)
165 #define RCR_ALL       (1 << 3)
166 #define RCR_RUNT      (1 << 2)
167 #define RCR_PRMSC     (1 << 1)
168 #define RCR_RXEN      (1 << 0)
169
170 // RSR (RX Status Register)
171 #define RSR_RF        (1 << 7)
172 #define RSR_MF        (1 << 6)
173 #define RSR_LCS       (1 << 5)
174 #define RSR_RWTO      (1 << 4)
175 #define RSR_PLE       (1 << 3)
176 #define RSR_AE        (1 << 2)
177 #define RSR_CE        (1 << 1)
178 #define RSR_FOE       (1 << 0)
179
180 // FCR (Flow Control Register)
181 #define FCR_TXPO      (1 << 7)
182 #define FCR_TXPF      (1 << 6)
183 #define FCR_TXPEN     (1 << 5)
184 #define FCR_BKPA      (1 << 4)
185 #define FCR_BKPM      (1 << 3)
186 #define FCR_RXPS      (1 << 2)
187 #define FCR_RXPCS     (1 << 1)
188 #define FCR_FLCE      (1 << 0)
189
190 // EPCR (EEPROM & PHY Control Register)
191 #define EPCR_REEP     (1 << 5)
192 #define EPCR_WEP      (1 << 4)
193 #define EPCR_EPOS     (1 << 3)
194 #define EPCR_ERPRR    (1 << 2)
195 #define EPCR_ERPRW    (1 << 1)
196 #define EPCR_ERRE     (1 << 0)
197
198 // WCR (Wakeup Control Register)
199 #define WCR_LINKEN    (1 << 5)
200 #define WCR_SAMPLEEN  (1 << 4)
201 #define WCR_MAGICEN   (1 << 3)
202 #define WCR_LINKST    (1 << 2)
203 #define WCR_SAMPLEST  (1 << 1)
204 #define WCR_MAGIGST   (1 << 0)
205
206 // SMCR (Special Mode Control Register)
207 #define SMCR_SM_EN    (1 << 7)
208 #define SMCR_FLC      (1 << 2)
209 #define SMCR_FB1      (1 << 1)
210 #define SMCR_FB0      (1 << 0)
211
212 // ISR (Interrupt Status Register)
213 #define ISR_IOMODE_16 (0 << 6)
214 #define ISR_IOMODE_32 (1 << 6)
215 #define ISR_IOMODE_8  (2 << 6)
216 #define ISR_ROOS      (1 << 3)
217 #define ISR_ROS       (1 << 2)
218 #define ISR_PTS       (1 << 1)
219 #define ISR_PRS       (1 << 0)
220
221 // IMR (Interrupt Mask Register)
222 #define IMR_PAR       (1 << 7)
223 #define IMR_ROOM      (1 << 3)
224 #define IMR_ROM       (1 << 2)
225 #define IMR_PTM       (1 << 1)
226 #define IMR_PRM       (1 << 0)
227
228
229 // Read one datum from 8-bit bus
230 static int read_data_8(struct dm9000 *p, cyg_uint8 *dest)
231 {
232     HAL_READ_UINT8(p->io_data, *dest);
233     return 1;
234 }
235
236 // Read one datum from 16-bit bus 
237 static int read_data_16(struct dm9000 *p, cyg_uint8 *dest)
238 {
239     cyg_uint16 val;
240
241     HAL_READ_UINT16(p->io_data, val);
242     memcpy(dest, &val, 2);
243     return 2;
244 }
245
246 // Read one datum from 32-bit bus 
247 static int read_data_32(struct dm9000 *p, cyg_uint8 *dest)
248 {
249     cyg_uint32 val;
250
251     HAL_READ_UINT32(p->io_data, val);
252     memcpy(dest, &val, 4);
253     return 4;
254 }
255
256
257 // Write one datum to 8-bit bus
258 static int write_data_8(struct dm9000 *p, cyg_uint8 *src)
259 {
260     HAL_WRITE_UINT8(p->io_data, *src);
261     return 1;
262 }
263
264 // Write one datum to 16-bit bus 
265 static int write_data_16(struct dm9000 *p, cyg_uint8 *src)
266 {
267     cyg_uint16 val;
268
269     memcpy(&val, src, 2);
270     HAL_WRITE_UINT16(p->io_data, val);
271     return 2;
272 }
273
274 // Write one datum to 32-bit bus 
275 static int write_data_32(struct dm9000 *p, cyg_uint8 *src)
276 {
277     cyg_uint32 val;
278
279     memcpy(&val, src, 4);
280     HAL_WRITE_UINT32(p->io_data, val);
281     return 4;
282 }
283
284
285
286 // Return one byte from DM9000 register
287 static cyg_uint8 getreg(struct dm9000 *p, cyg_uint8 reg)
288 {
289     cyg_uint8 val;
290     HAL_WRITE_UINT8(p->io_addr, reg);
291     HAL_READ_UINT8(p->io_data, val);
292     return val;
293 }
294
295 // Write one byte to DM9000 register
296 static void putreg(struct dm9000 *p, cyg_uint8 reg, cyg_uint8 val)
297 {
298     HAL_WRITE_UINT8(p->io_addr, reg);
299     HAL_WRITE_UINT8(p->io_data, val);
300 }
301
302 // Read a word from EEPROM
303 static cyg_uint16 eeprom_read(struct dm9000 *p, int offset)
304 {
305     putreg(p, DM_EPAR, offset);
306     putreg(p, DM_EPCR, EPCR_ERPRR);
307     while (getreg(p, DM_EPCR) & EPCR_ERRE)
308         ;
309     CYGACC_CALL_IF_DELAY_US(200);
310     putreg(p, DM_EPCR, 0);
311     return getreg(p, DM_EPDRL) | (getreg(p, DM_EPDRH) << 8);
312 }
313
314 // Write a word to EEPROM
315 static void eeprom_write(struct dm9000 *p, int offset, cyg_uint16 val)
316 {
317     putreg(p, DM_EPAR, offset);
318     putreg(p, DM_EPDRH, val >> 8);
319     putreg(p, DM_EPDRL, val);
320     putreg(p, DM_EPCR, EPCR_WEP | EPCR_ERPRW);
321     while (getreg(p, DM_EPCR) & EPCR_ERRE)
322         ;
323     CYGACC_CALL_IF_DELAY_US(200);
324     putreg(p, DM_EPCR, 0);
325 }
326
327 // Reload info from EEPROM
328 static void eeprom_reload(struct dm9000 *p)
329 {
330     putreg(p, DM_EPCR, EPCR_REEP);
331     while (getreg(p, DM_EPCR) & EPCR_ERRE)
332         ;
333     CYGACC_CALL_IF_DELAY_US(200);
334     putreg(p, DM_EPCR, 0);
335 }
336
337
338 // Read a word from PHY
339 static cyg_uint16 phy_read(struct dm9000 *p, int offset)
340 {
341     putreg(p, DM_EPAR, 0x40 + offset);
342     putreg(p, DM_EPCR, EPCR_EPOS | EPCR_ERPRR);
343     CYGACC_CALL_IF_DELAY_US(200);
344     putreg(p, DM_EPCR, 0);
345     return getreg(p, DM_EPDRL) | (getreg(p, DM_EPDRH) << 8);
346 }
347
348 // Write a word to PHY
349 static void phy_write(struct dm9000 *p, int offset, cyg_uint16 val)
350 {
351     putreg(p, DM_EPAR, 0x40 + offset);
352     putreg(p, DM_EPDRL, val);
353     putreg(p, DM_EPDRH, val >> 8);
354     putreg(p, DM_EPCR, EPCR_EPOS | EPCR_ERPRW);
355     CYGACC_CALL_IF_DELAY_US(500);
356     putreg(p, DM_EPCR, 0);
357 }
358
359
360 static void init_phy(struct dm9000 *p)
361 {
362     phy_write(p, 4, 0x1e1); // Advertise 10/100 half/full duplex w/CSMA
363     phy_write(p, 0, 0x1200); // enable autoneg
364
365     // release reset
366     putreg(p, DM_GPCR, 1);
367     putreg(p, DM_GPR, 0);  
368 }
369
370
371 static inline void dm9000_reset(struct dm9000 *p)
372 {
373     putreg(p, DM_NCR, NCR_RST);
374     CYGACC_CALL_IF_DELAY_US(100);
375 }
376
377 static int initialize_nic(struct dm9000 *priv)
378 {
379     int i;
380
381     dm9000_reset(priv);
382
383     switch (getreg(priv, DM_ISR) >> 6) {
384     case 0:
385         priv->read_data = read_data_16;
386         priv->write_data = write_data_16;
387         priv->buswidth = 2;
388         break;
389     case 1:
390         priv->read_data = read_data_32;
391         priv->write_data = write_data_32;
392         priv->buswidth = 4;
393         break;
394     case 2:
395         priv->read_data = read_data_8;
396         priv->write_data = write_data_8;
397         priv->buswidth = 1;
398         break;
399     default:
400         diag_printf("Unknown DM9000 bus i/f.\n");
401         return 0;
402     }
403
404     init_phy(priv);
405
406     putreg(priv, DM_TCR, 0);
407     putreg(priv, DM_BPTR, 0x3f);
408     putreg(priv, DM_FCTR, 0x38);
409     putreg(priv, DM_FCR, 0xff);
410     putreg(priv, DM_SMCR, 0);
411     putreg(priv, DM_NSR, NSR_WAKEST | NSR_TX1END | NSR_TX2END);
412     putreg(priv, DM_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
413     
414     // set MAC address
415     for (i = 0; i < 6; i++)
416         putreg(priv, DM_PAR + i, priv->mac_address[i]);
417
418     // clear multicast table except for broadcast address
419     for (i = 0; i < 6; i++)
420         putreg(priv, DM_MAR + i, 0x00);
421     putreg(priv, DM_MAR + 6, 0x00);
422     putreg(priv, DM_MAR + 7, 0x80);
423
424     return 1;
425 }
426
427
428 // ------------------------------------------------------------------------
429 //
430 //  API Function : dm9000_init
431 //
432 // ------------------------------------------------------------------------
433 static bool
434 dm9000_init(struct cyg_netdevtab_entry * ndp)
435 {
436     struct eth_drv_sc *sc;
437     struct dm9000 *priv;
438     int i;
439     unsigned id;
440     unsigned short u16tab[64];
441
442     sc = (struct eth_drv_sc *)ndp->device_instance;
443     priv = (struct dm9000 *)sc->driver_private;
444
445     priv->sc = sc;
446
447 #ifdef CYG_HAL_DM9000_PRESENT
448     if (!CYG_HAL_DM9000_PRESENT())
449         return 0;
450 #endif
451
452     id = getreg(priv, DM_VIDL);
453     id |= getreg(priv, DM_VIDH) << 8;
454     id |= getreg(priv, DM_PIDL) << 16;
455     id |= getreg(priv, DM_PIDH) << 24;
456
457     if (id != 0x90000A46)
458         return 0;
459
460     for (i = 0; i < 64; i++)
461         u16tab[i] = eeprom_read(priv, i);
462
463     u16tab[3] &= ~0xc;
464     u16tab[3] |= 4;
465     u16tab[6] &= 0xfe00;
466     u16tab[6] |= 6;
467
468 #if 0
469     eeprom_write(priv, 6, u16tab[6]);
470     eeprom_write(priv, 3, u16tab[3]);
471 #endif
472
473     eeprom_reload(priv);
474
475     do {
476         for (i = 0; i < 64; i++)
477             u16tab[i] = eeprom_read(priv, i);
478     } while ((u16tab[0] | u16tab[1] | u16tab[2]) == 0);
479
480     priv->mac_address[0] = u16tab[0];
481     priv->mac_address[1] = u16tab[0] >> 8;
482     priv->mac_address[2] = u16tab[1];
483     priv->mac_address[3] = u16tab[1] >> 8;
484     priv->mac_address[4] = u16tab[2];
485     priv->mac_address[5] = u16tab[2] >> 8;
486
487     if (!initialize_nic(priv))
488         return 0;
489
490     // Initialize upper level driver
491     (sc->funs->eth_drv->init)(sc, &(priv->mac_address[0]) );
492     return 1;
493 }
494
495 // ------------------------------------------------------------------------
496 //
497 //  API Function : dm9000_start
498 //
499 // ------------------------------------------------------------------------
500 static void 
501 dm9000_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
502 {
503     struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
504
505     // turn on receiver
506     putreg(priv, DM_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
507
508     // unmask interrupt
509     putreg(priv, DM_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
510
511     priv->active = 1;
512 }
513
514 // ------------------------------------------------------------------------
515 //
516 //  API Function : dm9000_stop
517 //
518 // ------------------------------------------------------------------------
519 static void
520 dm9000_stop( struct eth_drv_sc *sc )
521 {
522     struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
523
524     // turn on receiver
525     putreg(priv, DM_RCR, 0);
526
527     // mask interrupts
528     putreg(priv, DM_IMR, IMR_PAR);
529
530     priv->active = 0;
531 }
532
533
534 // ------------------------------------------------------------------------
535 //
536 //  API Function : dm9000_recv
537 //
538 // ------------------------------------------------------------------------
539 static void 
540 dm9000_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
541 {
542     struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
543     struct eth_drv_sg *sg = sg_list;
544     cyg_uint8   tmpbuf[4];
545     char *p;
546     int len, total_len, nread, n, leftover;
547
548     total_len = priv->rxlen;
549     nread = leftover = 0;
550
551 //    diag_printf("dm9000_recv: total_len=%d\n", total_len);
552
553     do {
554         p = (char *)sg->buf;
555         len = sg->len;
556
557 //      diag_printf("recv: buf=%p len=%d to_read=%d, leftover=%d\n", p, len, total_len - nread, leftover);
558
559         if ((nread + len) > total_len)
560             len = total_len - nread;
561
562         if (leftover) {
563             if (leftover <= len) {
564                 memcpy(p, tmpbuf + (sizeof(tmpbuf) - leftover), leftover);
565                 p += leftover;
566                 len -= leftover;
567                 nread += leftover;
568                 leftover = 0;
569             } else {
570                 memcpy(p, tmpbuf + (sizeof(tmpbuf) - leftover), len);
571                 leftover -= len;
572                 p += len;
573                 nread += len;
574                 len = 0;
575             }
576         }
577
578         while (len >= sizeof(tmpbuf)) {
579             n = priv->read_data(priv, p);
580             nread += n;
581             len -= n;
582             p += n;
583         }
584
585         while (len > 0) {
586             n = priv->read_data(priv, tmpbuf);
587             if (n <= len) {
588                 memcpy(p, tmpbuf, n);
589                 len -= n;
590                 nread += n;
591                 p += n;
592             } else {
593                 memcpy(p, tmpbuf, len);
594                 nread += len;
595                 leftover = n - len;
596                 len = 0;
597             } 
598         }
599         
600         ++sg;
601     } while (nread < total_len);
602
603 #if 0
604     // dump packet
605     for (sg = sg_list; sg < (sg_list + sg_len); sg++) {
606         diag_printf("\n");
607         diag_dump_buf(sg->buf, sg->len);
608     }
609 #endif
610 }
611
612 // ------------------------------------------------------------------------
613 //
614 //  API Function : dm9000_can_send
615 //
616 // ------------------------------------------------------------------------
617 static int 
618 dm9000_can_send(struct eth_drv_sc *sc)
619 {
620     struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
621
622     if (!priv->active || priv->txbusy || priv->reset_pending)
623         return 0;
624
625     return 1;
626 }
627
628
629 // ------------------------------------------------------------------------
630 //
631 //  API Function : dm9000_send
632 //
633 // ------------------------------------------------------------------------
634 static void 
635 dm9000_send(struct eth_drv_sc *sc,
636             struct eth_drv_sg *sg_list, int sg_len,
637             int total_len, unsigned long key)
638 {
639     struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
640     struct eth_drv_sg *sg = sg_list;
641     cyg_uint8 tmpbuf[4];
642     int i, len, extra, n, save_len;
643     char *p;
644
645     if (0) {
646         diag_printf("dm9000_send: NCR[%02x] NSR[%02x] TPL[%02x]\n",
647                     getreg(priv, DM_NCR), getreg(priv, DM_NSR),
648                     getreg(priv, DM_TRPAL) | (getreg(priv, DM_TRPAH) << 8)
649             );
650     }
651
652     priv->txbusy = 1;
653
654     save_len = total_len;
655     extra = 0;
656
657     HAL_WRITE_UINT8(priv->io_addr, DM_MWCMD);
658
659     while (total_len > 0) {
660         len = sg->len;
661         if (len > total_len)
662             len = total_len;
663         p = (char *)sg->buf;
664
665         if (extra) {
666             n = sizeof(tmpbuf) - extra;
667             memcpy(tmpbuf + extra, p, n);
668             p += n;
669             len -= n;
670             for (i = 0; i < sizeof(tmpbuf) && total_len > 0; i += n) {
671                 n = priv->write_data(priv, tmpbuf + i);
672                 total_len -= n;
673             }
674             extra = 0;
675         }
676         
677         while (len >= sizeof(tmpbuf) && total_len > 0) {
678             n = priv->write_data(priv, p);
679             len -= n;
680             total_len -= n;
681             p += n;
682         }
683
684         if (len > 0 && total_len > 0) {
685             extra = len;
686             memcpy(tmpbuf, p, extra);
687
688             if ((total_len - extra) <= 0) {
689                 // go ahead and write it now
690                 for (i = 0; total_len > 0; i += n, total_len -= n) {
691                     n = priv->write_data(priv, tmpbuf + i);
692                     total_len = 0;
693                 }
694                 break;
695             }
696         }
697         sg++;
698     }
699
700     priv->txkey = key;
701
702     putreg(priv, DM_TXPLL, save_len);
703     putreg(priv, DM_TXPLH, save_len >> 8);
704
705     putreg(priv, DM_TCR, TCR_TXREQ);
706
707     return;
708 }
709
710 // ------------------------------------------------------------------------
711 //
712 //  API Function : dm9000_poll
713 //
714 // ------------------------------------------------------------------------
715 static void
716 dm9000_poll(struct eth_drv_sc *sc)
717 {
718     struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
719     cyg_uint8 status, rxstat, rx1;
720     cyg_uint16 pkt_stat, pkt_len;
721     int i;
722
723     // mask interrupts
724     putreg(priv, DM_IMR, IMR_PAR);
725
726     // get and clear staus
727     status = getreg(priv, DM_ISR);
728     putreg(priv, DM_ISR, status);
729
730     // check for rx done
731     if (1 /*status & ISR_PRS*/) {
732
733         rx1 = getreg(priv, DM_MRCMDX);
734         HAL_READ_UINT8(priv->io_data, rxstat);
735
736         // check for packet ready
737         if (rxstat == 1) {
738             cyg_uint16 u16[2];
739             cyg_uint8 *cp;
740
741             HAL_WRITE_UINT8(priv->io_addr, DM_MRCMD);
742             for (i = 0, cp = (cyg_uint8 *)u16; i < 4; )
743                 i += priv->read_data(priv, cp + i);
744
745             u16[0] = CYG_LE16_TO_CPU(u16[0]);
746             u16[1] = CYG_LE16_TO_CPU(u16[1]);
747
748 #if (CYG_BYTEORDER == CYG_MSBFIRST)
749             pkt_stat = u16[0];
750             pkt_len = u16[1];
751 #else
752             pkt_stat = u16[1];
753             pkt_len = u16[0];
754 #endif
755
756 #ifdef DEBUG
757             diag_printf("pkt_stat=%04x pkt_len=%04x\n", pkt_stat, pkt_len);
758 #endif
759
760             if (pkt_len < 0x40) {
761                 diag_printf("packet too short: %d (0x%04x)\n", pkt_len, pkt_len);
762                 i = 0;
763                 while (i < pkt_len)
764                     i += priv->read_data(priv, cp);
765             } else if (pkt_len > 1536) {
766                 priv->reset_pending = 1;
767                 diag_printf("packet too long: %d (0x%04x)\n", pkt_len, pkt_len);
768             } else if (pkt_stat & 0xbf00) {
769                 diag_printf("bad packet status: 0x%04x\n", pkt_stat);
770                 i = 0;
771                 while (i < pkt_len)
772                     i += priv->read_data(priv, cp);
773             } else {
774                 // receive packet
775                 priv->rxlen = pkt_len;
776                 (sc->funs->eth_drv->recv)(sc, pkt_len);
777             }
778
779         } else if (rxstat > 1) {
780             // this should never happen.
781             diag_printf("unknown rxstat byte: %d\n", rxstat);
782             priv->reset_pending = 1;
783         }
784     }
785
786
787     // check transmit status
788     if (status & ISR_PTS) {
789         cyg_uint8 txstat;
790
791         txstat = getreg(priv, DM_NSR);
792
793         if (txstat & (NSR_TX1END | NSR_TX2END)) {
794             if (txstat & NSR_TX1END)
795                 txstat = getreg(priv, DM_TSRI);
796             else
797                 txstat = getreg(priv, DM_TSRII);
798
799             if (txstat & TSR_COL) {
800                 // collision
801             }
802
803             if (getreg(priv, DM_TRPAL) & 3) {
804                 // NIC bug detected. Need to reset.
805                 priv->reset_pending = 1;
806                 diag_printf("NIC collision bug detected!\n");
807             }
808
809             (sc->funs->eth_drv->tx_done)(sc, priv->txkey, 0);
810             priv->txbusy = 0;
811         }
812     }
813
814     if (priv->reset_pending && !priv->txbusy) {
815         initialize_nic(priv);
816
817         // turn on receiver
818         putreg(priv, DM_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
819
820         priv->reset_pending = 0;
821     }
822
823     // unmask interrupts
824     putreg(priv, DM_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
825 }
826
827
828 // ------------------------------------------------------------------------
829 //
830 //  API Function : dm9000_deliver
831 //
832 // ------------------------------------------------------------------------
833 static void
834 dm9000_deliver(struct eth_drv_sc *sc)
835 {
836     dm9000_poll(sc);
837 }
838
839 // ------------------------------------------------------------------------
840 //
841 //  API Function : dm9000_int_vector
842 //
843 // ------------------------------------------------------------------------
844 static int
845 dm9000_int_vector(struct eth_drv_sc *sc)
846 {
847     struct dm9000 *priv;
848     priv = (struct dm9000 *)sc->driver_private;
849
850     return -1;
851 }
852
853
854 // ------------------------------------------------------------------------
855 //
856 //  API Function : dm9000_ioctl
857 //
858 // ------------------------------------------------------------------------
859 static int
860 dm9000_ioctl(struct eth_drv_sc *sc, unsigned long key,
861           void *data, int data_length)
862 {
863     return -1;
864 }
865
866 // ------------------------------------------------------------------------
867 // EOF if_dm9000.c