revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / pcnet32 / unit.c
blobdf25c099b4fe0cd3d7649dd1714cbff6f631c2cc
1 /*
2 * $Id$
3 */
5 /*
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
22 #include <exec/types.h>
23 #include <exec/resident.h>
24 #include <exec/io.h>
25 #include <exec/ports.h>
26 #include <exec/errors.h>
28 #include <aros/io.h>
30 #include <devices/sana2.h>
31 #include <devices/sana2specialstats.h>
32 #include <devices/newstyle.h>
33 #include <devices/timer.h>
35 #include <utility/utility.h>
36 #include <utility/tagitem.h>
37 #include <utility/hooks.h>
39 #include <proto/exec.h>
40 #include <proto/dos.h>
41 #include <proto/oop.h>
42 #include <proto/timer.h>
43 #include <proto/utility.h>
45 #include <stdlib.h>
47 #include "pcnet32.h"
48 #include "unit.h"
49 #include LC_LIBDEFS_FILE
51 /* BYTE IO */
52 UBYTE readb(APTR base)
54 return BYTEIN(base);
56 void writeb(UBYTE val, APTR base)
58 BYTEOUT(base, val);
61 /* WORD IO */
62 UWORD readw(APTR base)
64 return WORDIN(base);
66 void writew(UWORD val, APTR base)
68 WORDOUT(base, val);
71 /* LONG IO */
72 ULONG readl(APTR base)
74 return *((volatile ULONG*)base);
76 void writel(ULONG val, APTR base)
78 *((volatile ULONG*)base) = val;
81 /* 16/32bit control funcs */
82 static UWORD pcnet32_readcsr_16(APTR base, int index)
84 writew( index, base + 0x12);
85 return readw( base + 0x10);
88 static void pcnet32_writecsr_16(APTR base, int index, UWORD val)
90 writew( index, base + 0x12);
91 writew( val, base + 0x10);
94 static UWORD pcnet32_readbcr_16(APTR base, int index)
96 writew( index, base + 0x12);
97 return readw( base + 0x16);
100 static void pcnet32_writebcr_16(APTR base, int index, UWORD val)
102 writew( index, base + 0x12);
103 writew( val, base + 0x16);
106 static UWORD pcnet32_readrap_16(APTR base)
108 return readw(base + 0x12);
111 static void pcnet32_writerap_16(APTR base, UWORD val)
113 writew( val, base + 0x12);
116 static void pcnet32_reset_16(APTR base)
118 readw(base + 0x14);
121 static int pcnet32_check_16(APTR base)
123 writew(88, base + 0x12);
124 return (readw( base + 0x12) == 88);
127 /**/
129 static UWORD pcnet32_readcsr_32(APTR base, int index)
131 writel( index, base + 0x14);
132 return (readl( base + 0x10) & 0xffff);
135 static void pcnet32_writecsr_32(APTR base, int index, UWORD val)
137 writel( index, base + 0x14);
138 writel( val, base + 0x10);
141 static UWORD pcnet32_readbcr_32(APTR base, int index)
143 writel( index, base + 0x14);
144 return (readl( base + 0x1c) & 0xffff);
147 static void pcnet32_writebcr_32(APTR base, int index, UWORD val)
149 writel( index, base + 0x14);
150 writel( val, base + 0x1c);
153 static UWORD pcnet32_readrap_32(APTR base)
155 return (readl(base + 0x14) & 0xffff);
158 static void pcnet32_writerap_32(APTR base, UWORD val)
160 writel( val, base + 0x14);
163 static void pcnet32_reset_32(APTR base)
165 readl(base + 0x18);
168 static int pcnet32_check_32(APTR base)
170 writel(88, base + 0x14);
171 return ((readw( base + 0x14) & 0xffff) == 88);
175 * Report incoming events to all hyphotetical event receivers
177 VOID ReportEvents(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit, ULONG events)
179 struct IOSana2Req *request, *tail, *next_request;
180 struct List *list;
182 list = &unit->pcnu_request_ports[EVENT_QUEUE]->mp_MsgList;
183 next_request = (APTR)list->lh_Head;
184 tail = (APTR)&list->lh_Tail;
186 /* Go through list of event listeners. If send messages to receivers if event found */
187 Disable();
188 while(next_request != tail)
190 request = next_request;
191 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
193 if((request->ios2_WireError&events) != 0)
195 request->ios2_WireError = events;
196 Remove((APTR)request);
197 ReplyMsg((APTR)request);
200 Enable();
202 return;
205 struct TypeStats *FindTypeStats(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit,
206 struct MinList *list, ULONG packet_type)
208 struct TypeStats *stats, *tail;
209 BOOL found = FALSE;
211 stats = (APTR)list->mlh_Head;
212 tail = (APTR)&list->mlh_Tail;
214 while(stats != tail && !found)
216 if(stats->packet_type == packet_type)
217 found = TRUE;
218 else
219 stats = (APTR)stats->node.mln_Succ;
222 if(!found)
223 stats = NULL;
225 return stats;
228 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit, UBYTE last_queue, BYTE error)
230 struct IORequest *request;
231 UBYTE i;
232 struct Opener *opener, *tail;
234 D(bug("[pcnet32] unit.FlushUnit\n"));
236 /* Abort queued operations */
238 for (i=0; i <= last_queue; i++)
240 while ((request = (APTR)GetMsg(unit->pcnu_request_ports[i])) != NULL)
242 request->io_Error = IOERR_ABORTED;
243 ReplyMsg((struct Message *)request);
247 opener = (APTR)unit->pcnu_Openers.mlh_Head;
248 tail = (APTR)unit->pcnu_Openers.mlh_Tail;
250 /* Flush every opener's read queue */
252 while(opener != tail)
254 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
256 request->io_Error = error;
257 ReplyMsg((struct Message *)request);
259 opener = (struct Opener *)opener->node.mln_Succ;
263 static inline void pci_push(UBYTE *base)
265 /* force out pending posted writes */
266 readl(base);
270 * Interrupt handler called whenever pcnet32 NIC interface generates interrupt.
271 * It's duty is to iterate throgh RX queue searching for new packets.
273 * Please note, that allthough multicast support could be done on interface
274 * basis, it is done in this function as result of quick integration of both
275 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
276 * filter function).
278 AROS_INTH1(PCN32_RX_Int, struct PCN32Unit *, unit)
280 AROS_INTFUNC_INIT
282 struct PCN32Base *PCNet32Base = unit->pcnu_device;
283 struct fe_priv *np = unit->pcnu_fe_priv;
284 UWORD Flags;
285 struct TypeStats *tracker;
286 ULONG packet_type;
287 struct Opener *opener, *opener_tail;
288 struct IOSana2Req *request, *request_tail;
289 BOOL accepted, is_orphan;
291 D(bug("%s: PCN32_RX_Int() !!!!\n", unit->pcnu_name));
292 np->cur_rx = 0;
294 /* Endless loop, with break from inside */
295 for(;;)
297 int i;
298 UWORD len=0;
299 struct eth_frame *frame;
301 if (np->cur_rx >= RX_RING_SIZE)
302 break; /* we scanned the whole ring - do not continue */
304 /* Get the in-queue number */
305 i = np->cur_rx % RX_RING_SIZE;
306 Flags = AROS_LE2WORD(((struct rx_ring_desc *)np->ring_addr)[i].BufferStatus);
307 len = AROS_LE2WORD(((struct rx_ring_desc *)np->ring_addr)[i].BufferMsgLength);
309 D(bug("%s: PCN32_RX_Int: looking at packet %d:%d, Flags 0x%x, len %d\n",
310 unit->pcnu_name, np->cur_rx, i, Flags, len));
312 /* Do we own the packet or the chipset? */
313 if ((Flags & (1 << 15))!=0)
315 D(bug("%s: PCN32_RX_Int: packet owned by chipset\n", unit->pcnu_name));
316 goto next_pkt; /* still owned by hardware, */
319 D(bug("%s: PCN32_RX_Int: packet is for us\n", unit->pcnu_name));
321 /* the packet is for us - get it :) */
323 if (Flags & (1 << 7)) { // Bus Parity Error
324 D(bug("%s: PCN32_RX_Int: packet has Bus Parity error!\n", unit->pcnu_name));
325 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
326 unit->pcnu_stats.BadData++;
327 goto next_pkt;
330 if (Flags & (1 << 8)) { // End of Packet
331 D(bug("%s: PCN32_RX_Int: END of Packet\n", unit->pcnu_name));
333 if (Flags & (1 << 9)) { // Start of Packet
334 D(bug("%s: PCN32_RX_Int: START of Packet\n", unit->pcnu_name));
337 if (Flags & (1 << 10)) { // Buffer Error
338 D(bug("%s: PCN32_RX_Int: packet has CRC error!\n", unit->pcnu_name));
339 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
340 unit->pcnu_stats.BadData++;
341 goto next_pkt;
343 if (Flags & (1 << 11)) { // CRC Error
344 D(bug("%s: PCN32_RX_Int: packet has CRC error!\n", unit->pcnu_name));
345 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
346 unit->pcnu_stats.BadData++;
347 goto next_pkt;
349 if (Flags & (1 << 12)) { // OVERFLOW Error
350 D(bug("%s: PCN32_RX_Int: packet has OVERFLOW error!\n", unit->pcnu_name));
351 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
352 unit->pcnu_stats.BadData++;
353 goto next_pkt;
355 if (Flags & (1 << 13)) { // Framing Error
356 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
357 unit->pcnu_stats.BadData++;
358 goto next_pkt;
361 D(bug("%s: PCN32_RX_Int: packet doesnt report errors\n", unit->pcnu_name));
363 /* got a valid packet - forward it to the network core */
364 frame = &np->rx_buffer[i];
365 is_orphan = TRUE;
367 /* Dump contents of frame if DEBUG enabled */
368 #ifdef DEBUG
370 int j;
371 for (j=0; j<64; j++) {
372 if ((j%16) == 0)
373 D(bug("\n%03x:", j));
374 D(bug(" %02x", ((unsigned char*)frame)[j]));
376 D(bug("\n"));
378 #endif
380 /* Check for address validity */
381 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
383 /* Packet is addressed to this driver */
384 packet_type = AROS_BE2WORD(frame->eth_packet_type);
385 D(bug("%s: PCN32_RX_Int: Packet IP accepted with type = %d\n", unit->pcnu_name, packet_type));
387 opener = (APTR)unit->pcnu_Openers.mlh_Head;
388 opener_tail = (APTR)&unit->pcnu_Openers.mlh_Tail;
390 /* Offer packet to every opener */
391 while(opener != opener_tail)
393 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
394 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
395 accepted = FALSE;
397 /* Offer packet to each request until it's accepted */
398 while((request != request_tail) && !accepted)
400 if((request->ios2_PacketType == packet_type)
401 || ((request->ios2_PacketType <= ETH_MTU)
402 && (packet_type <= ETH_MTU)))
404 D(bug("%s: PCN32_RX_Int: copy packet for opener ..\n", unit->pcnu_name));
405 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
406 accepted = TRUE;
408 request =
409 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
412 if(accepted)
413 is_orphan = FALSE;
415 opener = (APTR)opener->node.mln_Succ;
418 /* If packet was unwanted, give it to S2_READORPHAN request */
419 if(is_orphan)
421 unit->pcnu_stats.UnknownTypesReceived++;
423 if(!IsMsgPortEmpty(unit->pcnu_request_ports[ADOPT_QUEUE]))
425 CopyPacket(LIBBASE, unit,
426 (APTR)unit->pcnu_request_ports[ADOPT_QUEUE]->
427 mp_MsgList.lh_Head, len, packet_type, frame);
428 D(bug("%s: PCN32_RX_Int: packet copied to orphan queue\n", unit->pcnu_name));
432 /* Update remaining statistics */
434 tracker =
435 FindTypeStats(LIBBASE, unit, &unit->pcnu_type_trackers, packet_type);
437 if(tracker != NULL)
439 tracker->stats.PacketsReceived++;
440 tracker->stats.BytesReceived += len;
444 unit->pcnu_stats.PacketsReceived++;
445 ((struct rx_ring_desc *)np->ring_addr)[i].BufferStatus = AROS_WORD2LE((1 << 8)|(1 << 9)|(1 << 15)); // Mark packet as available again
446 next_pkt:
447 np->cur_rx++;
450 return FALSE;
452 AROS_INTFUNC_EXIT
456 * Interrupt generated by Cause() to push new packets into the NIC interface
458 AROS_INTH1(PCN32_TX_Int, struct PCN32Unit *, unit)
460 AROS_INTFUNC_INIT
462 struct fe_priv *np = unit->pcnu_fe_priv;
463 struct PCN32Base *PCNet32Base = unit->pcnu_device;
464 int nr, try_count=1;
465 BOOL proceed = FALSE; /* Fails by default */
467 D(bug("%s: PCN32_TX_Int()\n", unit->pcnu_name));
469 /* send packet only if there is free space on tx queue. Otherwise do nothing */
470 if (!netif_queue_stopped(unit))
472 UWORD packet_size, data_size;
473 struct IOSana2Req *request;
474 struct Opener *opener;
475 UBYTE *buffer;
476 ULONG wire_error=0;
477 BYTE error;
478 struct MsgPort *port;
479 struct TypeStats *tracker;
481 proceed = TRUE; /* Success by default */
482 port = unit->pcnu_request_ports[WRITE_QUEUE];
484 /* Still no error and there are packets to be sent? */
485 while(proceed && (!IsMsgPortEmpty(port)))
487 nr = np->next_tx % TX_RING_SIZE;
488 error = 0;
490 if (!((((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].BufferStatus) & (1 << 15)))
493 request = (APTR)port->mp_MsgList.lh_Head;
494 data_size = packet_size = request->ios2_DataLength;
496 opener = (APTR)request->ios2_BufferManagement;
498 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
500 packet_size += ETH_PACKET_DATA;
501 CopyMem(request->ios2_DstAddr, np->tx_buffer[nr].eth_packet_dest, ETH_ADDRESSSIZE);
502 CopyMem(unit->pcnu_dev_addr, np->tx_buffer[nr].eth_packet_source, ETH_ADDRESSSIZE);
503 np->tx_buffer[nr].eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
505 buffer = np->tx_buffer[nr].eth_packet_data;
507 else
508 buffer = (UBYTE*)&np->tx_buffer[nr];
510 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
512 error = S2ERR_NO_RESOURCES;
513 wire_error = S2WERR_BUFF_ERROR;
514 ReportEvents(LIBBASE, unit,
515 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
516 | S2EVENT_TX);
519 /* Now the packet is already in TX buffer, update flags for NIC */
520 if (error == 0)
522 Disable();
523 D(bug("%s: PCN32_TX_Int: packet %d:%d [type = %d] queued for transmission.", unit->pcnu_name, np->next_tx, nr, np->tx_buffer[nr].eth_packet_type));
525 /* DEBUG? Dump frame if so */
526 #ifdef DEBUG
528 int j;
529 for (j=0; j<64; j++) {
530 if ((j%16) == 0)
531 D(bug("\n%03x:", j));
532 D(bug(" %02x", ((unsigned char*)&np->tx_buffer[nr])[j]));
534 D(bug("\n"));
536 #endif
538 Enable();
540 /* Set the ring details for the packet .. */
541 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].BufferLength = AROS_WORD2LE(-packet_size);
542 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].Misc = 0x00000000;
543 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].PacketBuffer = AROS_LONG2LE((IPTR)&np->tx_buffer[nr]);
544 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].BufferStatus = AROS_WORD2LE(0x8300);
546 unit->write_csr((APTR)unit->pcnu_BaseMem,0, ((1 << 6)|(1 << 3))); /* .. And trigger an imediate Tx poll */
547 D(bug("%s: PCN32_TX_Int: send poll triggered.\n", unit->pcnu_name));
550 /* Reply packet */
552 request->ios2_Req.io_Error = error;
553 request->ios2_WireError = wire_error;
554 Disable();
555 Remove((APTR)request);
556 Enable();
557 ReplyMsg((APTR)request);
559 /* Update statistics */
561 if(error == 0)
563 tracker = FindTypeStats(LIBBASE, unit, &unit->pcnu_type_trackers,
564 request->ios2_PacketType);
565 if(tracker != NULL)
567 tracker->stats.PacketsSent++;
568 tracker->stats.BytesSent += packet_size;
571 try_count=0;
573 np->next_tx++;
574 try_count++;
577 * If we've just run out of free space on the TX queue, stop
578 * it and give up pushing further frames
580 if ( (try_count + 1) >= TX_RING_SIZE)
582 D(bug("%s: output queue full!. Stopping [count = %d, TX_RING_SIZE = %d\n", unit->pcnu_name, try_count, TX_RING_SIZE));
583 netif_stop_queue(unit);
584 proceed = FALSE;
589 /* Was there success? Enable incomming of new packets */
590 if(proceed)
591 unit->pcnu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
592 else
593 unit->pcnu_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
595 return FALSE;
597 AROS_INTFUNC_EXIT
601 * Interrupt used to restart the real one
603 AROS_INTH1(PCN32_TX_End_Int, struct PCN32Unit *, unit)
605 AROS_INTFUNC_INIT
607 struct PCN32Base *PCNet32Base = unit->pcnu_device;
608 struct PCN32Unit *dev = unit;
609 struct fe_priv *np = dev->pcnu_fe_priv;
610 // UBYTE *base = (UBYTE*) dev->pcnu_BaseMem;
612 D(bug("%s: PCN32_TX_End_Int()\n", unit->pcnu_name));
614 int i;
615 UWORD Flags;
617 for(i = 0; i < TX_RING_SIZE; i++)
619 Flags = AROS_LE2WORD(((struct tx_ring_desc *)np->ring_addr)[i + RX_RING_SIZE].BufferStatus);
620 /* Do we own the packet or the chipset? */
621 D(bug("%s: PCN32_TX_End_Int: looking at TxRing packet %d:, Flags 0x%x\n",
622 unit->pcnu_name, i, Flags));
623 if ((Flags & (1 << 15))==0)
625 D(bug("%s: PCN32_TX_End_Int: TxRing packet %d owned by us\n", unit->pcnu_name, i));
626 /* TODO: We should report send errors here .. */
628 if (Flags & (1 << 14))
630 D(bug("%s: PCN32_TX_End_Int: Errors occured transmitting packet\n", unit->pcnu_name));
631 if (Flags & (1 << 11))
633 D(bug("%s: PCN32_TX_End_Int: packet reports CRC Error\n", unit->pcnu_name));
636 if (Flags & (1 << 12))
638 D(bug("%s: PCN32_TX_End_Int: packet reports OVERFLOW error\n", unit->pcnu_name));
641 if (Flags & (1 << 13))
643 D(bug("%s: PCN32_TX_End_Int: packet reports FRAMING error\n", unit->pcnu_name));
645 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
647 else unit->pcnu_stats.PacketsSent++;
649 if ((Flags & (1 << 8))||(Flags &(1 << 9))) //(ENP | STP)
651 D(bug("%s: PCN32_TX_End_Int: freeing TxRing packet for use\n", unit->pcnu_name));
652 ((struct tx_ring_desc *)np->ring_addr)[i + RX_RING_SIZE].BufferStatus = 0;
653 ((struct tx_ring_desc *)np->ring_addr)[i + RX_RING_SIZE].PacketBuffer = 0;
655 else
657 D(bug("%s: PCN32_TX_End_Int: TxRing packet unused ..??\n", unit->pcnu_name));
662 return FALSE;
664 AROS_INTFUNC_EXIT
667 #if (0)
669 * Maximum number of loops until we assume that a bit in the irq mask
670 * is stuck. Overridable with module param.
672 static const int max_interrupt_work = 5;
673 #endif
676 * Handle timeouts and other strange cases
678 static AROS_INTH1(PCN32_TimeoutHandler,struct PCN32Unit *, dev)
680 AROS_INTFUNC_INIT
682 struct timeval time;
683 struct Device *TimerBase = dev->pcnu_TimerSlowReq->tr_node.io_Device;
685 GetSysTime(&time);
686 //D(bug("%s: PCN32_TimeoutHandler()\n", dev->pcnu_name));
689 * If timeout timer is expected, and time elapsed - regenerate the
690 * interrupt handler
692 if (dev->pcnu_toutNEED && (CmpTime(&time, &dev->pcnu_toutPOLL ) < 0))
694 dev->pcnu_toutNEED = FALSE;
695 Cause(&dev->pcnu_tx_end_int);
698 return FALSE;
700 AROS_INTFUNC_EXIT
704 * The interrupt handler - schedules code execution to proper handlers depending
705 * on the message from nForce.
707 * NOTE.
709 * Don't be surprised - this driver used to restart itself several times, in
710 * order to handle events which occur when the driver was handling previous
711 * events. It reduces the latency and amount of dropped packets. Additionally,
712 * this interrupt may put itself into deep sleep (or just quit) and restarts
713 * after certain amount of time (POLL_WAIT).
715 static AROS_INTH1(PCN32_IntHandler, struct PCN32Unit *, dev)
717 AROS_INTFUNC_INIT
719 // struct fe_priv *np = dev->pcnu_fe_priv;
720 // UBYTE *base = (UBYTE*) dev->pcnu_BaseMem;
721 // ULONG events;
722 // int i;
723 struct Device *TimerBase = dev->pcnu_TimerSlowReq->tr_node.io_Device;
724 struct timeval time;
726 GetSysTime(&time);
727 int csr_0 = 0;
728 // int csr_4 = 0;
729 D(bug("%s: PCN32_IntHandler()!!!!!!!\n", dev->pcnu_name));
731 while ( (csr_0 = dev->read_csr(dev->pcnu_BaseMem, 0)) & (1 << 7))
733 dev->write_csr(dev->pcnu_BaseMem, 0, csr_0);
734 D(bug("%s: PCN32_IntHandler: csr[0] : %x\n", dev->pcnu_name, csr_0));
736 if ( csr_0 & (1 << 0) ) // (INIT) is the card initialising?
738 D(bug("%s: PCN32_IntHandler: Chipset init detected .. ", dev->pcnu_name));
739 BOOL have_Tx = FALSE, have_Rx = FALSE;
741 if ( csr_0 & (1 << 1) ) // (STRT) Start/ed/ing?
743 D(bug("[STRT]"));
746 if ( csr_0 & (1 << 2) ) // (STOP) Chipset is stopped
748 D(bug("[STOP]"));
749 have_Tx = TRUE;
752 if ( csr_0 & (1 << 4) ) // (TXON) Transmitter ON?
754 D(bug("[TXON]"));
755 have_Tx = TRUE;
757 else
759 D(bug("[TXON:OFF]"));
762 if ( csr_0 & (1 << 5) ) // (RXON) Reciever ON?
764 D(bug("[RXON]"));
765 have_Rx = TRUE;
767 else
769 D(bug("[RXON:OFF]"));
772 if ( csr_0 & (1 << 8) ) // (IDON) Initialisation Done?
774 D(bug("[IDON]"));
776 D(bug("\n"));
777 if ((!(have_Tx))&&(!(have_Rx)))
779 D(bug("%s: PCN32_IntHandler: Chipset is OFFLINE!\n", dev->pcnu_name));
783 if ( csr_0 & (1 << 10) ) // (RINT) Chipset has Recieved packet(s)
785 D(bug("%s: PCN32_IntHandler: Packet Reception detected!\n", dev->pcnu_name));
786 Cause(&dev->pcnu_rx_int);
789 if ( csr_0 & (1 << 9) ) // (TINT) Chipset has Sent packet(s)
791 D(bug("%s: PCN32_IntHandler: Packet Transmition detected!\n", dev->pcnu_name));
792 Cause(&dev->pcnu_tx_end_int);
795 if ( csr_0 & (1 << 15) ) // (ERR) Chipset has Reported an ERROR
797 D(bug("%s: PCN32_IntHandler: (ERR) ERROR Detected\n", dev->pcnu_name));
798 break;
802 return FALSE;
804 AROS_INTFUNC_EXIT
807 VOID CopyPacket(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit,
808 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
809 struct eth_frame *buffer)
811 struct Opener *opener;
812 BOOL filtered = FALSE;
813 UBYTE *ptr;
814 const UBYTE broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
816 D(bug("%s: CopyPacket(packet @ %x, len = %d)\n", unit->pcnu_name, buffer, packet_size));
818 /* Set multicast and broadcast flags */
820 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
821 if(memcmp(buffer->eth_packet_dest, broadcast, 6) == 0)
823 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
824 D(bug("%s: CopyPacket: BROADCAST Flag set\n", unit->pcnu_name));
826 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
828 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
829 D(bug("%s: CopyPacket: MULTICAST Flag set\n", unit->pcnu_name));
832 /* Set source and destination addresses and packet type */
833 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
834 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
835 request->ios2_PacketType = packet_type;
837 /* Adjust for cooked packet request */
839 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
841 packet_size -= ETH_PACKET_DATA;
842 ptr = (UBYTE*)&buffer->eth_packet_data[0];
844 else
846 ptr = (UBYTE*)buffer;
849 request->ios2_DataLength = packet_size;
851 D(bug("%s: CopyPacket: packet @ %x (%d bytes)\n", unit->pcnu_name, ptr, packet_size));
853 /* Filter packet */
855 opener = request->ios2_BufferManagement;
856 if((request->ios2_Req.io_Command == CMD_READ) &&
857 (opener->filter_hook != NULL))
858 if(!CallHookPkt(opener->filter_hook, request, ptr))
860 D(bug("%s: CopyPacket: packet filtered\n", unit->pcnu_name));
861 filtered = TRUE;
864 if(!filtered)
866 /* Copy packet into opener's buffer and reply packet */
867 D(bug("%s: CopyPacket: opener recieve packet .. ", unit->pcnu_name));
868 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
870 D(bug("ERROR occured!!\n"));
871 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
872 request->ios2_WireError = S2WERR_BUFF_ERROR;
873 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
875 else
877 D(bug("SUCCESS!!\n"));
879 Disable();
880 Remove((APTR)request);
881 Enable();
882 ReplyMsg((APTR)request);
883 D(bug("%s: CopyPacket: opener notified.\n", unit->pcnu_name));
887 BOOL AddressFilter(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit, UBYTE *address)
889 struct AddressRange *range, *tail;
890 BOOL accept = TRUE;
891 ULONG address_left;
892 UWORD address_right;
894 /* Check whether address is unicast/broadcast or multicast */
896 address_left = AROS_BE2LONG(*((ULONG *)address));
897 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
899 if((address_left & 0x01000000) != 0 &&
900 !(address_left == 0xffffffff && address_right == 0xffff))
902 /* Check if this multicast address is wanted */
904 range = (APTR)unit->pcnu_multicast_ranges.mlh_Head;
905 tail = (APTR)&unit->pcnu_multicast_ranges.mlh_Tail;
906 accept = FALSE;
908 while((range != tail) && !accept)
910 if((address_left > range->lower_bound_left ||
911 (address_left == range->lower_bound_left &&
912 address_right >= range->lower_bound_right)) &&
913 (address_left < range->upper_bound_left ||
914 (address_left == range->upper_bound_left &&
915 address_right <= range->upper_bound_right)))
916 accept = TRUE;
917 range = (APTR)range->node.mln_Succ;
920 if(!accept)
921 unit->pcnu_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
923 return accept;
927 * Unit process
929 AROS_UFH3(void, PCN32_Schedular,
930 AROS_UFHA(STRPTR, argPtr, A0),
931 AROS_UFHA(ULONG, argSize, D0),
932 AROS_UFHA(struct ExecBase *, SysBase, A6))
934 AROS_USERFUNC_INIT
936 struct PCN32Unit *dev = FindTask(NULL)->tc_UserData;
937 LIBBASETYPEPTR LIBBASE = dev->pcnu_device;
938 struct MsgPort *reply_port, *input;
940 D(bug("[pcnet32] PCN32_Schedular()\n"));
941 D(bug("[pcnet32] PCN32_Schedular: Setting device up\n"));
943 reply_port = CreateMsgPort();
944 input = CreateMsgPort();
946 dev->pcnu_input_port = input;
948 dev->pcnu_TimerSlowPort = CreateMsgPort();
950 if (dev->pcnu_TimerSlowPort)
952 dev->pcnu_TimerSlowReq = (struct timerequest *)
953 CreateIORequest((struct MsgPort *)dev->pcnu_TimerSlowPort, sizeof(struct timerequest));
955 if (dev->pcnu_TimerSlowReq)
957 if (!OpenDevice("timer.device", UNIT_VBLANK,
958 (struct IORequest *)dev->pcnu_TimerSlowReq, 0))
960 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
961 ULONG sigset;
963 D(bug("[pcnet32] PCN32_Schedular: Got VBLANK unit of timer.device\n"));
965 dev->initialize(dev);
967 msg->mn_ReplyPort = reply_port;
968 msg->mn_Length = sizeof(struct Message);
970 D(bug("[pcnet32] PCN32_Schedular: Setup complete. Sending handshake\n"));
971 PutMsg(LIBBASE->pcnb_syncport, msg);
972 WaitPort(reply_port);
973 GetMsg(reply_port);
975 FreeVec(msg);
977 D(bug("[pcnet32] PCN32_Schedular: entering forever loop ... \n"));
979 dev->pcnu_signal_0 = AllocSignal(-1);
980 dev->pcnu_signal_1 = AllocSignal(-1);
981 dev->pcnu_signal_2 = AllocSignal(-1);
982 dev->pcnu_signal_3 = AllocSignal(-1);
984 sigset = 1 << input->mp_SigBit |
985 1 << dev->pcnu_signal_0 |
986 1 << dev->pcnu_signal_1 |
987 1 << dev->pcnu_signal_2 |
988 1 << dev->pcnu_signal_3;
989 for(;;)
991 ULONG recvd = Wait(sigset);
992 if (recvd & 1 << dev->pcnu_signal_0)
995 * Shutdown process. Driver should close everything
996 * already and waits for our process to complete. Free
997 * memory allocared here and kindly return.
999 dev->deinitialize(dev);
1000 CloseDevice((struct IORequest *)dev->pcnu_TimerSlowReq);
1001 DeleteIORequest((struct IORequest *)dev->pcnu_TimerSlowReq);
1002 DeleteMsgPort(dev->pcnu_TimerSlowPort);
1003 DeleteMsgPort(input);
1004 DeleteMsgPort(reply_port);
1006 D(bug("[pcnet32] PCN32_Schedular: Process shutdown.\n"));
1007 return;
1009 else if (recvd & (1 << input->mp_SigBit))
1011 struct IOSana2Req *io;
1013 /* Handle incoming transactions */
1014 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL)
1016 D(bug("[pcnet32] PCN32_Schedular: Handle incomming transaction.\n"));
1017 ObtainSemaphore(&dev->pcnu_unit_lock);
1018 handle_request(LIBBASE, io);
1021 else
1023 D(bug("[pcnet32] PCN32_Schedular: Handle incomming signal.\n"));
1024 /* Handle incoming signals */
1031 AROS_USERFUNC_EXIT
1035 * Create new pcnet32 ethernet device unit
1037 struct PCN32Unit *CreateUnit(struct PCN32Base *PCNet32Base, OOP_Object *pciDevice)
1039 struct PCN32Unit *unit = AllocMem(sizeof(struct PCN32Unit), MEMF_PUBLIC | MEMF_CLEAR);
1040 BOOL success = TRUE;
1041 int i;
1043 D(bug("[pcnet32] CreateUnit()\n"));
1045 if (unit != NULL)
1047 IPTR DeviceID, base, len;
1048 OOP_Object *driver;
1050 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
1051 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
1053 unit->pcnu_device = PCNet32Base;
1054 unit->pcnu_DeviceID = DeviceID;
1055 unit->pcnu_mtu = ETH_MTU;
1056 unit->pcnu_PCIDevice = pciDevice;
1057 unit->pcnu_PCIDriver = driver;
1059 InitSemaphore(&unit->pcnu_unit_lock);
1060 NEWLIST(&unit->pcnu_Openers);
1061 NEWLIST(&unit->pcnu_multicast_ranges);
1062 NEWLIST(&unit->pcnu_type_trackers);
1064 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->pcnu_IRQ);
1065 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->pcnu_BaseIO);
1066 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
1067 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
1069 unit->pcnu_BaseMem = HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
1070 unit->pcnu_SizeMem = len;
1072 if (unit->pcnu_BaseMem)
1074 struct TagItem attrs[] = {
1075 { aHidd_PCIDevice_isIO, TRUE },
1076 { aHidd_PCIDevice_isMEM, TRUE },
1077 { aHidd_PCIDevice_isMaster, TRUE },
1078 { TAG_DONE, 0 },
1080 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1082 unit->pcnu_name = "[pcnet32.0]";
1084 unit->pcnu_fe_priv = AllocMem(sizeof(struct fe_priv), MEMF_PUBLIC|MEMF_CLEAR);
1086 unit->pcnu_fe_priv->fep_pcnet_init_block = HIDD_PCIDriver_AllocPCIMem(
1087 driver,
1088 sizeof(struct pcnet32_init_block));
1090 unit->pcnu_UnitNum = 0;
1092 pcn32_get_functions(unit);
1094 if (unit->pcnu_fe_priv)
1096 unit->pcnu_fe_priv->pci_dev = unit;
1097 InitSemaphore(&unit->pcnu_fe_priv->lock);
1100 struct Message *msg;
1102 unit->pcnu_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
1103 unit->pcnu_irqhandler.is_Node.ln_Pri = 100;
1104 unit->pcnu_irqhandler.is_Node.ln_Name = LIBBASE->pcnb_Device.dd_Library.lib_Node.ln_Name;
1105 unit->pcnu_irqhandler.is_Code = (VOID_FUNC)PCN32_IntHandler;
1106 unit->pcnu_irqhandler.is_Data = unit;
1108 unit->pcnu_touthandler.is_Node.ln_Type = NT_INTERRUPT;
1109 unit->pcnu_touthandler.is_Node.ln_Pri = 100;
1110 unit->pcnu_touthandler.is_Node.ln_Name = LIBBASE->pcnb_Device.dd_Library.lib_Node.ln_Name;
1111 unit->pcnu_touthandler.is_Code = (VOID_FUNC)PCN32_TimeoutHandler;
1112 unit->pcnu_touthandler.is_Data = unit;
1114 unit->pcnu_rx_int.is_Node.ln_Type = NT_INTERRUPT;
1115 unit->pcnu_rx_int.is_Node.ln_Name = unit->pcnu_name;
1116 unit->pcnu_rx_int.is_Code = (VOID_FUNC)PCN32_RX_Int;
1117 unit->pcnu_rx_int.is_Data = unit;
1119 unit->pcnu_tx_int.is_Node.ln_Type = NT_INTERRUPT;
1120 unit->pcnu_tx_int.is_Node.ln_Name = unit->pcnu_name;
1121 unit->pcnu_tx_int.is_Code = (VOID_FUNC)PCN32_TX_Int;
1122 unit->pcnu_tx_int.is_Data = unit;
1124 unit->pcnu_tx_end_int.is_Node.ln_Name = unit->pcnu_name;
1125 unit->pcnu_tx_end_int.is_Code = (VOID_FUNC)PCN32_TX_End_Int;
1126 unit->pcnu_tx_end_int.is_Data = unit;
1128 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1130 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
1131 unit->pcnu_request_ports[i] = port;
1133 if (port == NULL) success = FALSE;
1135 if (success)
1137 NEWLIST(&port->mp_MsgList);
1138 port->mp_Flags = PA_IGNORE;
1139 port->mp_SigTask = &unit->pcnu_tx_int;
1143 unit->pcnu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1145 if (success)
1147 D(bug("%s: Initialise Dev @ %x, IOBase @ %x\n", unit->pcnu_name, unit, unit->pcnu_BaseMem));
1149 pcnet32_reset_16(unit->pcnu_BaseMem);
1151 D(bug("%s: Chipset RESET\n", unit->pcnu_name));
1153 i = pcnet32_readcsr_16(unit->pcnu_BaseMem, 0); // Check for 16bit/32bit chip IO
1154 BOOL check = pcnet32_check_16(unit->pcnu_BaseMem);
1156 if ((i == 4)&&(check))
1158 D(bug("%s: Using 16bit I/O Funcs\n", unit->pcnu_name));
1159 unit->read_csr = pcnet32_readcsr_16;
1160 unit->write_csr = pcnet32_writecsr_16;
1161 unit->read_bcr = pcnet32_readbcr_16;
1162 unit->write_bcr = pcnet32_writebcr_16;
1163 unit->read_rap = pcnet32_readrap_16;
1164 unit->write_rap = pcnet32_writerap_16;
1165 unit->reset = pcnet32_reset_16;
1167 else
1169 pcnet32_reset_32(unit->pcnu_BaseMem); // 32bit reset..
1171 i = pcnet32_readcsr_32(unit->pcnu_BaseMem, 0);
1172 check = pcnet32_check_32(unit->pcnu_BaseMem);
1174 if ((i == 4)&&(check))
1176 D(bug("%s: Using 32bit I/O Funcs\n", unit->pcnu_name));
1177 unit->read_csr = pcnet32_readcsr_32;
1178 unit->write_csr = pcnet32_writecsr_32;
1179 unit->read_bcr = pcnet32_readbcr_32;
1180 unit->write_bcr = pcnet32_writebcr_32;
1181 unit->read_rap = pcnet32_readrap_32;
1182 unit->write_rap = pcnet32_writerap_32;
1183 unit->reset = pcnet32_reset_32;
1185 else
1187 D(bug("%s: Error - Unsupported chipset .. (unknown data size)\n", unit->pcnu_name));
1188 success = FALSE;
1192 if (success)
1194 i = (unit->read_csr(unit->pcnu_BaseMem, 88) | ( unit->read_csr(unit->pcnu_BaseMem, 89) << 16));
1196 unit->pcnu_pcnet_chiprevision = (i >> 12) & 0xffff;
1198 D(bug("%s: PCnet chip version %x [%x]\n", unit->pcnu_name, i, unit->pcnu_pcnet_chiprevision));
1200 unit->pcnu_pcnet_supported = 0;
1202 switch (unit->pcnu_pcnet_chiprevision)
1204 case 0x2420:
1205 case 0x2430:
1206 unit->pcnu_pcnet_chipname = "PCnet/PCI 79c970";
1207 break;
1209 case 0x2621:
1210 unit->pcnu_pcnet_chipname = "PCnet/PCI II 79c970A";
1211 unit->pcnu_pcnet_supported |= support_fdx;
1212 break;
1214 case 0x2623:
1215 unit->pcnu_pcnet_chipname = "PCnet/FAST 79c971";
1216 unit->pcnu_pcnet_supported |= (support_fdx | support_mii | support_fset | support_ltint );
1217 break;
1219 case 0x2624:
1220 unit->pcnu_pcnet_chipname = "PCnet/FAST+ 79c972";
1221 unit->pcnu_pcnet_supported |= (support_fdx | support_mii | support_fset );
1222 break;
1224 case 0x2625:
1225 unit->pcnu_pcnet_chipname = "PCnet/FAST III 79c973";
1226 unit->pcnu_pcnet_supported |= (support_fdx | support_mii );
1227 break;
1229 case 0x2627:
1230 unit->pcnu_pcnet_chipname = "PCnet/FAST III 79c975";
1231 unit->pcnu_pcnet_supported |= (support_fdx | support_mii );
1232 break;
1234 case 0x2626:
1235 unit->pcnu_pcnet_chipname = "PCnet/Home 79c978";
1236 unit->pcnu_pcnet_supported |= support_fdx;
1238 /* TODO: PCnet/Home needs extra set up .. */
1239 break;
1240 default:
1241 D(bug("%s: ERROR - Unsupported Chipset (unknown revision)\n", unit->pcnu_name));
1242 success = FALSE;
1244 #if defined(DEBUG)
1245 D(bug("%s: Found %s chipset based NIC\n", unit->pcnu_name, unit->pcnu_pcnet_chipname));
1246 if (unit->pcnu_pcnet_supported & support_fdx)
1247 D(bug("%s: Chip Supports Full Duplex\n", unit->pcnu_name));
1248 if (unit->pcnu_pcnet_supported & support_mii)
1249 D(bug("%s: Chip Supports MII\n", unit->pcnu_name));
1250 if (unit->pcnu_pcnet_supported & support_fset)
1251 D(bug("%s: Chip Supports FSET\n", unit->pcnu_name));
1252 if (unit->pcnu_pcnet_supported & support_ltint)
1253 D(bug("%s: Chip Supports LTINT\n", unit->pcnu_name));
1254 #endif
1256 if (((unit->pcnu_pcnet_chiprevision +1) & 0xfffe) == 0x2624)
1258 i = unit->read_csr(unit->pcnu_BaseMem, 80) & 0x0c00; /* Check tx_start_pt */
1259 #if defined(DEBUG)
1260 D(bug("%s: tx_start_pt(0x%hX):", unit->pcnu_name, i));
1261 switch(i >> 10)
1263 case 0:
1264 D(bug(" 20 bytes,"));
1265 break;
1266 case 1:
1267 D(bug(" 64 bytes,"));
1268 break;
1269 case 2:
1270 D(bug(" 128 bytes,"));
1271 break;
1272 case 3:
1273 D(bug("~220 bytes,"));
1274 break;
1276 #endif
1277 i = unit->read_bcr(unit->pcnu_BaseMem, 18); /* Check burst/bus control */
1278 #if defined(DEBUG)
1279 D(bug(" BCR18(%hX):", i & 0xffff));
1280 if (i & (1 << 5))
1281 D(bug("BurstWrEn "));
1282 if (i & (1 << 6))
1283 D(bug("BurstRdEn "));
1284 if (i & (1 << 7))
1285 D(bug("32bitIO "));
1286 if (i & (1 << 11))
1287 D(bug("NoUFlow "));
1288 #endif
1289 i = unit->read_bcr(unit->pcnu_BaseMem, 25);
1290 D(bug(" SRAMSIZE=0x%hX,", i << 8));
1291 i = unit->read_bcr(unit->pcnu_BaseMem, 26);
1292 D(bug(" SRAM_BND=0x%hX,", i << 8));
1293 i = unit->read_bcr(unit->pcnu_BaseMem, 27);
1294 #if defined(DEBUG)
1295 if (i & (1 << 14))
1296 D(bug("LowLatRx"));
1297 #endif
1298 D(bug("\n"));
1303 if (success)
1305 LIBBASE->pcnb_syncport = CreateMsgPort();
1307 unit->pcnu_Process = CreateNewProcTags(
1308 NP_Entry, (IPTR)PCN32_Schedular,
1309 NP_Name, PCNET32_TASK_NAME,
1310 NP_Priority, 0,
1311 NP_UserData, (IPTR)unit,
1312 NP_StackSize, 140960,
1313 TAG_DONE);
1315 WaitPort(LIBBASE->pcnb_syncport);
1316 msg = GetMsg(LIBBASE->pcnb_syncport);
1317 ReplyMsg(msg);
1318 DeleteMsgPort(LIBBASE->pcnb_syncport);
1320 D(bug("[pcnet32] Unit up and running\n"));
1322 return unit;
1324 else
1326 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit->pcnu_name));
1331 else
1333 D(bug("[pcnet32] PANIC! Couldn't get MMIO area. Aborting\n"));
1336 DeleteUnit(PCNet32Base, unit);
1337 return NULL;
1341 * DeleteUnit - removes selected unit. Frees all resources and structures.
1343 * The caller should be sure, that given unit is really ready to be freed.
1346 void DeleteUnit(struct PCN32Base *PCNet32Base, struct PCN32Unit *Unit)
1348 int i;
1349 if (Unit)
1351 if (Unit->pcnu_Process)
1353 /* Tell our process to quit, and wait until it does so */
1354 Signal(&Unit->pcnu_Process->pr_Task, 1 << Unit->pcnu_signal_0);
1355 while (FindTask(PCNET32_TASK_NAME) != NULL)
1356 Delay(5);
1359 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1361 if (Unit->pcnu_request_ports[i] != NULL)
1362 FreeMem(Unit->pcnu_request_ports[i], sizeof(struct MsgPort));
1364 Unit->pcnu_request_ports[i] = NULL;
1367 if (Unit->pcnu_fe_priv)
1369 FreeMem(Unit->pcnu_fe_priv, sizeof(struct fe_priv));
1370 Unit->pcnu_fe_priv = NULL;
1373 if (Unit->pcnu_BaseMem)
1375 HIDD_PCIDriver_UnmapPCI(Unit->pcnu_PCIDriver,
1376 (APTR)Unit->pcnu_BaseMem,
1377 Unit->pcnu_SizeMem);
1380 FreeMem(Unit, sizeof(struct PCN32Unit));
1384 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit,
1385 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
1387 struct AddressRange *range, *tail;
1388 BOOL found = FALSE;
1390 range = (APTR)unit->pcnu_multicast_ranges.mlh_Head;
1391 tail = (APTR)&unit->pcnu_multicast_ranges.mlh_Tail;
1393 while((range != tail) && !found)
1395 if((lower_bound_left == range->lower_bound_left) &&
1396 (lower_bound_right == range->lower_bound_right) &&
1397 (upper_bound_left == range->upper_bound_left) &&
1398 (upper_bound_right == range->upper_bound_right))
1399 found = TRUE;
1400 else
1401 range = (APTR)range->node.mln_Succ;
1404 if(!found)
1405 range = NULL;
1407 return range;
1410 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit, const UBYTE *lower_bound,
1411 const UBYTE *upper_bound)
1413 struct AddressRange *range;
1414 ULONG lower_bound_left, upper_bound_left;
1415 UWORD lower_bound_right, upper_bound_right;
1417 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1418 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1419 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1420 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1422 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1423 upper_bound_left, upper_bound_right);
1425 if(range != NULL)
1426 range->add_count++;
1427 else
1429 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1430 if(range != NULL)
1432 range->lower_bound_left = lower_bound_left;
1433 range->lower_bound_right = lower_bound_right;
1434 range->upper_bound_left = upper_bound_left;
1435 range->upper_bound_right = upper_bound_right;
1436 range->add_count = 1;
1438 Disable();
1439 AddTail((APTR)&unit->pcnu_multicast_ranges, (APTR)range);
1440 Enable();
1442 if (unit->pcnu_range_count++ == 0)
1444 unit->pcnu_flags |= IFF_ALLMULTI;
1445 unit->set_multicast(unit);
1450 return range != NULL;
1453 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1455 struct AddressRange *range;
1456 ULONG lower_bound_left, upper_bound_left;
1457 UWORD lower_bound_right, upper_bound_right;
1459 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1460 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1461 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1462 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1464 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1465 upper_bound_left, upper_bound_right);
1467 if(range != NULL)
1469 if(--range->add_count == 0)
1471 Disable();
1472 Remove((APTR)range);
1473 Enable();
1474 FreeMem(range, sizeof(struct AddressRange));
1476 if (--unit->pcnu_range_count == 0)
1478 unit->pcnu_flags &= ~IFF_ALLMULTI;
1479 unit->set_multicast(unit);
1483 return range != NULL;