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