This source file includes following definitions.
- max
- wd_start
- wd8003_open
- wdget
- wd8003_start_xmit
- wd_put_bnd
- wd_get_bnd
- wd_get_cur
- wd_rcv
- wd_rx_over
- wd_trs
- wd8003_interrupt
- we8003_probe
- we8003_8bit
- we8003_cmem
- we8003_geth
- we8003_conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <linux/config.h>
21 #include <linux/kernel.h>
22 #include <linux/sched.h>
23 #include <linux/fs.h>
24 #include <linux/tty.h>
25 #include <linux/types.h>
26 #include <linux/ptrace.h>
27 #include <linux/string.h>
28 #include <asm/system.h>
29 #include <asm/segment.h>
30 #include <asm/io.h>
31 #include <errno.h>
32 #include <linux/fcntl.h>
33 #include <netinet/in.h>
34 #include <linux/interrupt.h>
35 #include "dp8390.h"
36 #include "we8003.h"
37
38
39 static unsigned char interrupt_mask;
40
41 static struct enet_statistics stats;
42 static unsigned char max_pages;
43 static unsigned char wd_debug = 0;
44 static unsigned char dconfig = WD_DCONFIG;
45 static int tx_aborted = 0;
46
47 static void wd_trs (struct device *);
48
49 static int
50 max(int a, int b)
51 {
52 if (a>b) return (a);
53 return (b);
54 }
55
56 static void
57 wd_start(struct device *dev)
58 {
59 unsigned char cmd;
60 interrupt_mask=RECV_MASK|TRANS_MASK;
61 cli();
62 cmd = inb_p(WD_COMM);
63 cmd &= ~(CSTOP|CPAGE);
64 cmd |= CSTART;
65 outb_p(cmd, WD_COMM);
66 outb_p(interrupt_mask,WD_IMR);
67 sti();
68 dev->start = 1;
69 }
70
71 int
72 wd8003_open(struct device *dev)
73 {
74 unsigned char cmd;
75 int i;
76
77 cli();
78
79
80
81
82 cmd=inb_p(WD_COMM);
83 cmd|=CSTOP;
84 cmd &= ~(CSTART|CPAGE);
85 outb_p(cmd, WD_COMM);
86 outb_p(0, WD_IMR);
87 sti();
88 outb_p( dconfig,WD_DCR);
89
90 outb_p(0, WD_RBY0);
91 outb_p(0, WD_RBY1);
92 outb_p(WD_MCONFIG,WD_RCC);
93 outb_p(WD_TCONFIG,WD_TRC);
94 outb_p(0,WD_TRPG);
95 outb_p( max_pages,WD_PSTOP);
96 outb_p(WD_TXBS,WD_PSTRT);
97 outb_p(WD_TXBS,WD_BNDR);
98
99 outb_p(0xff,WD_ISR);
100
101 outb_p(0 ,WD_IMR);
102 cmd|=1<<CPAGE_SHIFT;
103 outb_p(cmd,WD_COMM);
104
105 for (i=0; i < ETHER_ADDR_LEN; i++)
106 {
107 outb_p(dev->dev_addr[i],WD_PAR0+i);
108 }
109
110 outb_p(WD_TXBS+1,WD_CUR);
111
112 for (i=0; i < ETHER_ADDR_LEN; i++)
113 {
114 outb_p(dev->broadcast[i],WD_MAR0+i);
115 }
116
117 cmd&=~(CPAGE|CRDMA);
118 cmd|= 4<<CRDMA_SHIFT;
119 outb_p(cmd, WD_COMM);
120 outb_p(WD_RCONFIG,WD_RCC);
121 wd_start(dev);
122 return (0);
123 }
124
125
126 static int
127 wdget(volatile struct wd_ring *ring, struct device *dev)
128 {
129 unsigned char *fptr;
130 long len;
131 fptr = (unsigned char *)(ring +1);
132
133
134
135 len = ring->count-4;
136 if (len < 56)
137 printk ("we.c: Hardware problem, runt packet. ring->count = %d\n",
138 ring->count);
139 return (dev_rint(fptr, len, 0, dev));
140 }
141
142 int
143 wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
144 {
145 unsigned char cmd;
146 int len;
147
148 cli();
149 if (dev->tbusy)
150 {
151
152 if (jiffies - dev->trans_start < 30)
153 {
154 return (1);
155 }
156
157 printk ("wd8003 transmit timed out. \n");
158 }
159 dev->tbusy = 1;
160
161 if (skb == NULL)
162 {
163 sti();
164 wd_trs(dev);
165 return (0);
166 }
167
168
169 if (skb->dev != dev)
170 {
171 sti();
172 return (0);
173 }
174
175
176 if (!skb->arp)
177 {
178 if ( dev->rebuild_header (skb+1, dev))
179 {
180 cli();
181 if (skb->dev == dev)
182 {
183 arp_queue (skb);
184 }
185 cli ();
186 dev->tbusy = 0;
187 sti();
188 return (0);
189 }
190 }
191
192 memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);
193
194 len = skb->len;
195
196
197 dev->trans_start = jiffies;
198 len=max(len, ETHER_MIN_LEN);
199
200
201
202 cmd=inb_p(WD_COMM);
203 cmd &= ~CPAGE;
204 outb_p(cmd, WD_COMM);
205
206 interrupt_mask |= TRANS_MASK;
207 if (!(dev->interrupt))
208 outb (interrupt_mask, WD_IMR);
209
210 outb_p(len&0xff,WD_TB0);
211 outb_p(len>>8,WD_TB1);
212 cmd |= CTRANS;
213 outb_p(cmd,WD_COMM);
214 sti();
215
216 if (skb->free)
217 {
218 kfree_skb (skb, FREE_WRITE);
219 }
220
221 return (0);
222 }
223
224
225
226 static void
227 wd_put_bnd(unsigned char bnd, struct device *dev )
228 {
229
230 unsigned char cmd;
231
232
233 cmd = inb_p( CR );
234 if (cmd & 0x40) {
235 outb_p(cmd & (~CPAGE1), WD_COMM);
236 outb_p(bnd, WD_BNDR);
237 outb_p(cmd | CPAGE1, WD_COMM);
238 } else {
239 outb_p(bnd, WD_BNDR);
240 }
241 }
242
243 static unsigned char
244 wd_get_bnd( struct device *dev )
245 {
246
247 unsigned char cmd, bnd;
248
249
250 cmd = inb_p(WD_COMM);
251 if (cmd & 0x40) {
252 outb_p(cmd & (~CPAGE1), WD_COMM);
253 bnd = inb_p(WD_BNDR);
254 outb_p(cmd | CPAGE1, WD_COMM);
255 return (bnd);
256 } else {
257 return (inb_p(WD_BNDR));
258 }
259 }
260
261 static unsigned char
262 wd_get_cur( struct device *dev )
263 {
264
265 unsigned char cmd, cur;
266
267
268 cmd = inb_p(WD_COMM);
269 if (cmd & 0x40) {
270 return (inb_p(WD_CUR));
271 } else {
272 outb_p(cmd | CPAGE1, WD_COMM);
273 cur = inb_p(WD_CUR);
274 outb_p(cmd & (~CPAGE1), WD_COMM);
275 return (cur);
276 }
277 }
278
279
280
281
282
283 static void
284 wd_rcv( struct device *dev )
285 {
286
287 unsigned char pkt;
288 unsigned char bnd;
289 unsigned char cur;
290 unsigned char cmd;
291 volatile struct wd_ring *ring;
292 int done=0;
293
294
295 cur = wd_get_cur( dev );
296 bnd = wd_get_bnd( dev );
297 if( (pkt = bnd + 1) == max_pages )
298 pkt = WD_TXBS;
299
300 while( done != 1)
301 {
302 if (pkt != cur)
303 {
304
305
306 ring = (volatile struct wd_ring *) (dev->mem_start + (pkt << 8));
307
308
309 if( ring->status & 1 )
310 {
311
312
313 if( wd_debug )
314 printk("\nwd8013 - wdget: bnd = %d, pkt = %d, "
315 "cur = %d, status = %d, len = %d, next = %d",
316 bnd, pkt, cur, ring->status, ring->count,
317 ring->next);
318
319 stats.rx_packets++;
320 done = wdget( ring, dev );
321
322
323 pkt = ring->next;
324
325
326 if( (bnd = pkt - 1) < WD_TXBS )
327 bnd = max_pages - 1;
328 wd_put_bnd(bnd, dev);
329
330
331 cur = wd_get_cur(dev);
332 }
333 else
334 {
335
336 printk("wd8013 - bad packet: len = %d, status = x%x, "
337 "bnd = %d, pkt = %d, cur = %d\n"
338 "trashing receive buffer!",
339 ring->count, ring->status, bnd, pkt,
340 cur);
341
342 if( ( bnd = wd_get_cur( dev ) - 1 ) < WD_TXBS )
343 bnd = max_pages - 1;
344 wd_put_bnd( bnd, dev );
345 break;
346 }
347
348 }
349 else
350 {
351 done = dev_rint(NULL, 0,0, dev);
352 }
353 }
354
355
356 cmd = inb_p(WD_COMM);
357 if (cmd & 0x40)
358 {
359 outb_p(cmd & ~(CPAGE1), WD_COMM);
360 }
361 }
362
363
364
365 static void
366 wd_rx_over( struct device *dev )
367 {
368 unsigned char cmd, dummy;
369 register int io;
370
371
372
373
374
375
376
377 printk("wd_rx_over\n");
378 cmd = inb_p( CR );
379 cmd = (cmd&~(STA|PS0|PS1))|STOP;
380 outb_p( cmd, CR );
381 dummy = inb_p( RBCR0 );
382 dummy = inb_p( RBCR1 );
383 wd_rcv( dev );
384
385 if( inb_p( ISR ) & PRX )
386 outb_p( PRX, ISR );
387 while( ( inb_p( ISR ) & RST ) == 0 );
388 outb_p( RST, ISR );
389 outb_p( (cmd&~STOP)|STA, CR );
390 outb_p( WD_TCONFIG, TCR );
391 }
392
393
394
395
396
397
398 static void
399 wd_trs( struct device *dev )
400 {
401 unsigned char errors;
402
403 if( wd_debug )
404 printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
405
406 if( ( errors = inb_p( TSR ) & PTXOK ) || tx_aborted ){
407 if( (errors&~0x02) == 0 ){
408 stats.tx_packets++;
409 tx_aborted = 0;
410 }
411 dev->tbusy = 0;
412 mark_bh (INET_BH);
413
414 #if 0
415
416 len = dev_tint( (unsigned char *)dev->mem_start, dev );
417 if( len != 0 ){
418 len=max(len, ETHER_MIN_LEN);
419 cmd=inb_p(WD_COMM);
420 outb_p(len&0xff,WD_TB0);
421 outb_p(len>>8,WD_TB1);
422 cmd |= CTRANS;
423 outb_p(cmd,WD_COMM);
424 interrupt_mask |= TRANS_MASK;
425 }
426 else
427 {
428 dev->tbusy = 0
429 interrupt_mask &= ~TRANS_MASK;
430 return;
431 }
432 #endif
433 }
434 else{
435 if( errors & CRS ){
436 stats.tx_carrier_errors++;
437 printk("\nwd8013 - network cable short!");
438 }
439 if (errors & COL )
440 stats.collisions += inb_p( NCR );
441 if (errors & CDH )
442 stats.tx_heartbeat_errors++;
443 if (errors & OWC )
444 stats.tx_window_errors++;
445 }
446 }
447
448 void
449 wd8003_interrupt(int reg_ptr)
450 {
451 unsigned char cmd;
452 unsigned char errors;
453 unsigned char isr;
454 struct device *dev;
455 struct pt_regs *ptr;
456 int irq;
457 int count = 0;
458
459 ptr = (struct pt_regs *)reg_ptr;
460 irq = -(ptr->orig_eax+2);
461 for (dev = dev_base; dev != NULL; dev = dev->next)
462 {
463 if (dev->irq == irq) break;
464 }
465 if (dev == NULL)
466 {
467 printk ("we.c: irq %d for unknown device\n", irq);
468 return;
469 }
470 sti();
471
472 cmd = inb_p( CR );
473 if( cmd & (PS0|PS1 ) ){
474 cmd &= ~(PS0|PS1);
475 outb_p(cmd, CR );
476 }
477
478 if (wd_debug)
479 printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
480
481 dev->interrupt = 1;
482
483 do{
484 sti();
485
486 if ( ( isr = inb_p( ISR ) ) & OVW ) {
487 stats.rx_over_errors++;
488 if( wd_debug )
489 printk("\nwd8013 overrun bnd = %d, cur = %d", wd_get_bnd( dev ), wd_get_cur( dev ) );
490 wd_rx_over( dev );
491 outb_p( OVW, ISR );
492 }
493 else if ( isr & PRX ) {
494 wd_rcv( dev );
495 outb_p( PRX, ISR );
496 }
497
498
499 if ( inb_p( ISR ) & PTX ) {
500 wd_trs( dev );
501 outb_p( PTX, ISR );
502 }
503
504 if (inb_p( ISR ) & RXE ) {
505 stats.rx_errors++;
506 errors = inb_p( RSR );
507 if (errors & CRC )
508 stats.rx_crc_errors++;
509 if (errors & FAE )
510 stats.rx_frame_errors++;
511 if (errors & FO )
512 stats.rx_fifo_errors++;
513 if (errors & MPA )
514 stats.rx_missed_errors++;
515 outb_p( RXE, ISR );
516 }
517
518 if (inb_p( ISR ) & TXE ) {
519 stats.tx_errors++;
520 errors = inb_p( TSR );
521 if (errors & ABT ){
522 stats.tx_aborted_errors++;
523 printk("\nwd8013 - network cable open!");
524 }
525 if (errors & FU )
526 {
527 stats.tx_fifo_errors++;
528 printk("\nwd8013 - TX FIFO underrun!");
529 }
530
531
532 tx_aborted = 1;
533 wd_trs( dev );
534 tx_aborted = 0;
535
536 outb_p( TXE, ISR );
537 }
538
539 if( inb_p( ISR ) & CNTE ){
540 errors = inb_p( CNTR0 );
541 errors = inb_p( CNTR1 );
542 errors = inb_p( CNTR2 );
543 outb_p( CNTE, ISR );
544 }
545 if( inb_p( ISR ) & RST )
546 outb_p( RST, ISR );
547
548 if( wd_debug ){
549 if( ( isr = inb_p( ISR ) ) != 0 )
550 printk("\nwd8013 - ISR not cleared = x%x", isr );
551 }
552 if( ++count > max_pages + 1 ){
553 printk("\nwd8013_interrupt - infinite loop detected, isr = x%x, count = %d", isr, count );
554 }
555 cli();
556 } while( inb_p( ISR ) != 0 );
557
558 dev->interrupt = 0;
559 }
560
561
562 static struct sigaction wd8003_sigaction =
563 {
564 wd8003_interrupt,
565 0,
566 0,
567 NULL
568 };
569
570
571
572 static int
573 we8003_probe(struct ddconf *conf)
574 {
575 unsigned char csum;
576 register int io;
577 int i;
578
579 io = conf->ioaddr;
580 csum = 0;
581 for (i = 0; i < 8; i++) {
582 csum += inb_p(io + WD_ROM + i);
583 }
584 if (csum != WD_CHECK) {
585 PRINTK (("%s: Warning: board not found at IO=0x%X.\n", io));
586 return(-ENODEV);
587 }
588 return(0);
589 }
590
591
592
593 static void
594 we8003_8bit(struct ddi *dev)
595 {
596 #if !FORCE_8BIT
597 unsigned char csum;
598 register int io;
599 int i;
600
601 io = dev->config.ioaddr;
602 for (i = 0; i < 8; i++) {
603 if (inb_p(io + EN_SAPROM +i) != inb_p(io + EN_CMD + i)) {
604
605 csum = inb_p(io + EN_REG1);
606
607
608 outb(csum ^ BUS16, io + EN_REG1);
609 if ((csum & BUS16) == (inb_p(io + EN_REG1) & BUS16)) {
610 outb_p(LAN16ENABLE|MEMMASK, io + EN_REG5);
611 outb(csum, io + EN_REG1);
612 dev->flags |= DDI_FBUS16;
613 break;
614 }
615 outb(csum, io + EN_REG1);
616 }
617 }
618 #endif
619 }
620
621
622
623 static void
624 we8003_cmem(struct ddi *dev)
625 {
626 register int io;
627
628 io = dev->config.ioaddr;
629 outb_p(WD_IMEM, io + WD_CTL);
630
631
632 }
633
634
635
636 static void
637 we8003_geth(struct ddi *dev)
638 {
639 register int io;
640 register int i;
641
642 io = dev->config.ioaddr;
643 for (i = 0; i < ETHER_ADDR_LEN; i++) {
644 dev->dev_addr[i] = inb_p(io + WD_ROM + i);
645 dev->broadcast[i] = 0xff;
646 }
647 }
648
649
650
651 int
652 we8003_conf(struct ddi *dev)
653 {
654
655
656
657
658
659 if (dev->config.ioaddr == 0) return(0);
660 if (we8003_probe(&dev->config) < 0) return(1);
661
662
663 we8003_8bit(dev);
664
665
666 we8003_cmem(dev);
667
668
669 we8003_geth(dev);
670
671
672 memset((char *) &stats, 0, sizeof(struct enet_statistics);
673
674 dev->tbusy = 0;
675 dev->interrupt = 0;
676 if (irqaction (dev->irq, &we8003_sigaction)) {
677 printk("%s: unable to get IRQ%d\n", dev->name, dev->irq);
678 return(1);
679 }
680 return(0);
681 }