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,
22 #include <exec/types.h>
23 #include <exec/resident.h>
25 #include <exec/ports.h>
26 #include <exec/errors.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>
49 #include LC_LIBDEFS_FILE
52 UBYTE
readb(APTR base
)
56 void writeb(UBYTE val
, APTR base
)
62 UWORD
readw(APTR base
)
66 void writew(UWORD val
, APTR base
)
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
)
121 static int pcnet32_check_16(APTR base
)
123 writew(88, base
+ 0x12);
124 return (readw( base
+ 0x12) == 88);
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
)
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
;
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 */
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
);
205 struct TypeStats
*FindTypeStats(struct PCN32Base
*PCNet32Base
, struct PCN32Unit
*unit
,
206 struct MinList
*list
, ULONG packet_type
)
208 struct TypeStats
*stats
, *tail
;
211 stats
= (APTR
)list
->mlh_Head
;
212 tail
= (APTR
)&list
->mlh_Tail
;
214 while(stats
!= tail
&& !found
)
216 if(stats
->packet_type
== packet_type
)
219 stats
= (APTR
)stats
->node
.mln_Succ
;
228 void FlushUnit(LIBBASETYPEPTR LIBBASE
, struct PCN32Unit
*unit
, UBYTE last_queue
, BYTE error
)
230 struct IORequest
*request
;
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 */
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
278 AROS_INTH1(PCN32_RX_Int
, struct PCN32Unit
*, unit
)
282 struct PCN32Base
*PCNet32Base
= unit
->pcnu_device
;
283 struct fe_priv
*np
= unit
->pcnu_fe_priv
;
285 struct TypeStats
*tracker
;
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
));
294 /* Endless loop, with break from inside */
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
++;
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
++;
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
++;
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
++;
355 if (Flags
& (1 << 13)) { // Framing Error
356 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
357 unit
->pcnu_stats
.BadData
++;
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
];
367 /* Dump contents of frame if DEBUG enabled */
371 for (j
=0; j
<64; j
++) {
373 D(bug("\n%03x:", j
));
374 D(bug(" %02x", ((unsigned char*)frame
)[j
]));
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
;
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
);
409 (struct IOSana2Req
*)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
415 opener
= (APTR
)opener
->node
.mln_Succ
;
418 /* If packet was unwanted, give it to S2_READORPHAN request */
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 */
435 FindTypeStats(LIBBASE
, unit
, &unit
->pcnu_type_trackers
, packet_type
);
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
456 * Interrupt generated by Cause() to push new packets into the NIC interface
458 AROS_INTH1(PCN32_TX_Int
, struct PCN32Unit
*, unit
)
462 struct fe_priv
*np
= unit
->pcnu_fe_priv
;
463 struct PCN32Base
*PCNet32Base
= unit
->pcnu_device
;
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
;
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
;
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
;
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
519 /* Now the packet is already in TX buffer, update flags for NIC */
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 */
529 for (j
=0; j
<64; j
++) {
531 D(bug("\n%03x:", j
));
532 D(bug(" %02x", ((unsigned char*)&np
->tx_buffer
[nr
])[j
]));
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
));
552 request
->ios2_Req
.io_Error
= error
;
553 request
->ios2_WireError
= wire_error
;
555 Remove((APTR
)request
);
557 ReplyMsg((APTR
)request
);
559 /* Update statistics */
563 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->pcnu_type_trackers
,
564 request
->ios2_PacketType
);
567 tracker
->stats
.PacketsSent
++;
568 tracker
->stats
.BytesSent
+= packet_size
;
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
);
589 /* Was there success? Enable incomming of new packets */
591 unit
->pcnu_request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
593 unit
->pcnu_request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
601 * Interrupt used to restart the real one
603 AROS_INTH1(PCN32_TX_End_Int
, struct PCN32Unit
*, unit
)
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
));
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;
657 D(bug("%s: PCN32_TX_End_Int: TxRing packet unused ..??\n", unit
->pcnu_name
));
668 * Maximum number of loops until we assume that a bit in the irq mask
669 * is stuck. Overridable with module param.
671 static const int max_interrupt_work
= 5;
674 * Handle timeouts and other strange cases
676 static AROS_INTH1(PCN32_TimeoutHandler
,struct PCN32Unit
*, dev
)
681 struct Device
*TimerBase
= dev
->pcnu_TimerSlowReq
->tr_node
.io_Device
;
684 //D(bug("%s: PCN32_TimeoutHandler()\n", dev->pcnu_name));
687 * If timeout timer is expected, and time elapsed - regenerate the
690 if (dev
->pcnu_toutNEED
&& (CmpTime(&time
, &dev
->pcnu_toutPOLL
) < 0))
692 dev
->pcnu_toutNEED
= FALSE
;
693 Cause(&dev
->pcnu_tx_end_int
);
702 * The interrupt handler - schedules code execution to proper handlers depending
703 * on the message from nForce.
707 * Don't be surprised - this driver used to restart itself several times, in
708 * order to handle events which occur when the driver was handling previous
709 * events. It reduces the latency and amount of dropped packets. Additionally,
710 * this interrupt may put itself into deep sleep (or just quit) and restarts
711 * after certain amount of time (POLL_WAIT).
713 static AROS_INTH1(PCN32_IntHandler
, struct PCN32Unit
*, dev
)
717 // struct fe_priv *np = dev->pcnu_fe_priv;
718 // UBYTE *base = (UBYTE*) dev->pcnu_BaseMem;
721 struct Device
*TimerBase
= dev
->pcnu_TimerSlowReq
->tr_node
.io_Device
;
727 D(bug("%s: PCN32_IntHandler()!!!!!!!\n", dev
->pcnu_name
));
729 while ( (csr_0
= dev
->read_csr(dev
->pcnu_BaseMem
, 0)) & (1 << 7))
731 dev
->write_csr(dev
->pcnu_BaseMem
, 0, csr_0
);
732 D(bug("%s: PCN32_IntHandler: csr[0] : %x\n", dev
->pcnu_name
, csr_0
));
734 if ( csr_0
& (1 << 0) ) // (INIT) is the card initialising?
736 D(bug("%s: PCN32_IntHandler: Chipset init detected .. ", dev
->pcnu_name
));
737 BOOL have_Tx
= FALSE
, have_Rx
= FALSE
;
739 if ( csr_0
& (1 << 1) ) // (STRT) Start/ed/ing?
744 if ( csr_0
& (1 << 2) ) // (STOP) Chipset is stopped
750 if ( csr_0
& (1 << 4) ) // (TXON) Transmitter ON?
757 D(bug("[TXON:OFF]"));
760 if ( csr_0
& (1 << 5) ) // (RXON) Reciever ON?
767 D(bug("[RXON:OFF]"));
770 if ( csr_0
& (1 << 8) ) // (IDON) Initialisation Done?
775 if ((!(have_Tx
))&&(!(have_Rx
)))
777 D(bug("%s: PCN32_IntHandler: Chipset is OFFLINE!\n", dev
->pcnu_name
));
781 if ( csr_0
& (1 << 10) ) // (RINT) Chipset has Recieved packet(s)
783 D(bug("%s: PCN32_IntHandler: Packet Reception detected!\n", dev
->pcnu_name
));
784 Cause(&dev
->pcnu_rx_int
);
787 if ( csr_0
& (1 << 9) ) // (TINT) Chipset has Sent packet(s)
789 D(bug("%s: PCN32_IntHandler: Packet Transmition detected!\n", dev
->pcnu_name
));
790 Cause(&dev
->pcnu_tx_end_int
);
793 if ( csr_0
& (1 << 15) ) // (ERR) Chipset has Reported an ERROR
795 D(bug("%s: PCN32_IntHandler: (ERR) ERROR Detected\n", dev
->pcnu_name
));
805 VOID
CopyPacket(struct PCN32Base
*PCNet32Base
, struct PCN32Unit
*unit
,
806 struct IOSana2Req
*request
, UWORD packet_size
, UWORD packet_type
,
807 struct eth_frame
*buffer
)
809 struct Opener
*opener
;
810 BOOL filtered
= FALSE
;
812 const UBYTE broadcast
[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
814 D(bug("%s: CopyPacket(packet @ %x, len = %d)\n", unit
->pcnu_name
, buffer
, packet_size
));
816 /* Set multicast and broadcast flags */
818 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
819 if(memcmp(buffer
->eth_packet_dest
, broadcast
, 6) == 0)
821 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
822 D(bug("%s: CopyPacket: BROADCAST Flag set\n", unit
->pcnu_name
));
824 else if((buffer
->eth_packet_dest
[0] & 0x1) != 0)
826 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
827 D(bug("%s: CopyPacket: MULTICAST Flag set\n", unit
->pcnu_name
));
830 /* Set source and destination addresses and packet type */
831 CopyMem(buffer
->eth_packet_source
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
832 CopyMem(buffer
->eth_packet_dest
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
833 request
->ios2_PacketType
= packet_type
;
835 /* Adjust for cooked packet request */
837 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
839 packet_size
-= ETH_PACKET_DATA
;
840 ptr
= (UBYTE
*)&buffer
->eth_packet_data
[0];
844 ptr
= (UBYTE
*)buffer
;
847 request
->ios2_DataLength
= packet_size
;
849 D(bug("%s: CopyPacket: packet @ %x (%d bytes)\n", unit
->pcnu_name
, ptr
, packet_size
));
853 opener
= request
->ios2_BufferManagement
;
854 if((request
->ios2_Req
.io_Command
== CMD_READ
) &&
855 (opener
->filter_hook
!= NULL
))
856 if(!CallHookPkt(opener
->filter_hook
, request
, ptr
))
858 D(bug("%s: CopyPacket: packet filtered\n", unit
->pcnu_name
));
864 /* Copy packet into opener's buffer and reply packet */
865 D(bug("%s: CopyPacket: opener recieve packet .. ", unit
->pcnu_name
));
866 if(!opener
->rx_function(request
->ios2_Data
, ptr
, packet_size
))
868 D(bug("ERROR occured!!\n"));
869 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
870 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
871 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
);
875 D(bug("SUCCESS!!\n"));
878 Remove((APTR
)request
);
880 ReplyMsg((APTR
)request
);
881 D(bug("%s: CopyPacket: opener notified.\n", unit
->pcnu_name
));
885 BOOL
AddressFilter(struct PCN32Base
*PCNet32Base
, struct PCN32Unit
*unit
, UBYTE
*address
)
887 struct AddressRange
*range
, *tail
;
892 /* Check whether address is unicast/broadcast or multicast */
894 address_left
= AROS_BE2LONG(*((ULONG
*)address
));
895 address_right
= AROS_BE2WORD(*((UWORD
*)(address
+ 4)));
897 if((address_left
& 0x01000000) != 0 &&
898 !(address_left
== 0xffffffff && address_right
== 0xffff))
900 /* Check if this multicast address is wanted */
902 range
= (APTR
)unit
->pcnu_multicast_ranges
.mlh_Head
;
903 tail
= (APTR
)&unit
->pcnu_multicast_ranges
.mlh_Tail
;
906 while((range
!= tail
) && !accept
)
908 if((address_left
> range
->lower_bound_left
||
909 (address_left
== range
->lower_bound_left
&&
910 address_right
>= range
->lower_bound_right
)) &&
911 (address_left
< range
->upper_bound_left
||
912 (address_left
== range
->upper_bound_left
&&
913 address_right
<= range
->upper_bound_right
)))
915 range
= (APTR
)range
->node
.mln_Succ
;
919 unit
->pcnu_special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
927 AROS_UFH3(void, PCN32_Schedular
,
928 AROS_UFHA(STRPTR
, argPtr
, A0
),
929 AROS_UFHA(ULONG
, argSize
, D0
),
930 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
934 struct PCN32Unit
*dev
= FindTask(NULL
)->tc_UserData
;
935 LIBBASETYPEPTR LIBBASE
= dev
->pcnu_device
;
936 struct MsgPort
*reply_port
, *input
;
938 D(bug("[pcnet32] PCN32_Schedular()\n"));
939 D(bug("[pcnet32] PCN32_Schedular: Setting device up\n"));
941 reply_port
= CreateMsgPort();
942 input
= CreateMsgPort();
944 dev
->pcnu_input_port
= input
;
946 dev
->pcnu_TimerSlowPort
= CreateMsgPort();
948 if (dev
->pcnu_TimerSlowPort
)
950 dev
->pcnu_TimerSlowReq
= (struct timerequest
*)
951 CreateIORequest((struct MsgPort
*)dev
->pcnu_TimerSlowPort
, sizeof(struct timerequest
));
953 if (dev
->pcnu_TimerSlowReq
)
955 if (!OpenDevice("timer.device", UNIT_VBLANK
,
956 (struct IORequest
*)dev
->pcnu_TimerSlowReq
, 0))
958 struct Message
*msg
= AllocVec(sizeof(struct Message
), MEMF_PUBLIC
|MEMF_CLEAR
);
961 D(bug("[pcnet32] PCN32_Schedular: Got VBLANK unit of timer.device\n"));
963 dev
->initialize(dev
);
965 msg
->mn_ReplyPort
= reply_port
;
966 msg
->mn_Length
= sizeof(struct Message
);
968 D(bug("[pcnet32] PCN32_Schedular: Setup complete. Sending handshake\n"));
969 PutMsg(LIBBASE
->pcnb_syncport
, msg
);
970 WaitPort(reply_port
);
975 D(bug("[pcnet32] PCN32_Schedular: entering forever loop ... \n"));
977 dev
->pcnu_signal_0
= AllocSignal(-1);
978 dev
->pcnu_signal_1
= AllocSignal(-1);
979 dev
->pcnu_signal_2
= AllocSignal(-1);
980 dev
->pcnu_signal_3
= AllocSignal(-1);
982 sigset
= 1 << input
->mp_SigBit
|
983 1 << dev
->pcnu_signal_0
|
984 1 << dev
->pcnu_signal_1
|
985 1 << dev
->pcnu_signal_2
|
986 1 << dev
->pcnu_signal_3
;
989 ULONG recvd
= Wait(sigset
);
990 if (recvd
& 1 << dev
->pcnu_signal_0
)
993 * Shutdown process. Driver should close everything
994 * already and waits for our process to complete. Free
995 * memory allocared here and kindly return.
997 dev
->deinitialize(dev
);
998 CloseDevice((struct IORequest
*)dev
->pcnu_TimerSlowReq
);
999 DeleteIORequest((struct IORequest
*)dev
->pcnu_TimerSlowReq
);
1000 DeleteMsgPort(dev
->pcnu_TimerSlowPort
);
1001 DeleteMsgPort(input
);
1002 DeleteMsgPort(reply_port
);
1004 D(bug("[pcnet32] PCN32_Schedular: Process shutdown.\n"));
1007 else if (recvd
& (1 << input
->mp_SigBit
))
1009 struct IOSana2Req
*io
;
1011 /* Handle incoming transactions */
1012 while ((io
= (struct IOSana2Req
*)GetMsg(input
))!= NULL
);
1014 D(bug("[pcnet32] PCN32_Schedular: Handle incomming transaction.\n"));
1015 ObtainSemaphore(&dev
->pcnu_unit_lock
);
1016 handle_request(LIBBASE
, io
);
1021 D(bug("[pcnet32] PCN32_Schedular: Handle incomming signal.\n"));
1022 /* Handle incoming signals */
1033 * Create new pcnet32 ethernet device unit
1035 struct PCN32Unit
*CreateUnit(struct PCN32Base
*PCNet32Base
, OOP_Object
*pciDevice
)
1037 struct PCN32Unit
*unit
= AllocMem(sizeof(struct PCN32Unit
), MEMF_PUBLIC
| MEMF_CLEAR
);
1038 BOOL success
= TRUE
;
1041 D(bug("[pcnet32] CreateUnit()\n"));
1045 IPTR DeviceID
, base
, len
;
1048 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_ProductID
, &DeviceID
);
1049 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (APTR
)&driver
);
1051 unit
->pcnu_device
= PCNet32Base
;
1052 unit
->pcnu_DeviceID
= DeviceID
;
1053 unit
->pcnu_mtu
= ETH_MTU
;
1054 unit
->pcnu_PCIDevice
= pciDevice
;
1055 unit
->pcnu_PCIDriver
= driver
;
1057 InitSemaphore(&unit
->pcnu_unit_lock
);
1058 NEWLIST(&unit
->pcnu_Openers
);
1059 NEWLIST(&unit
->pcnu_multicast_ranges
);
1060 NEWLIST(&unit
->pcnu_type_trackers
);
1062 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &unit
->pcnu_IRQ
);
1063 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base1
, &unit
->pcnu_BaseIO
);
1064 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base0
, &base
);
1065 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Size0
, &len
);
1067 unit
->pcnu_BaseMem
= HIDD_PCIDriver_MapPCI(driver
, (APTR
)base
, len
);
1068 unit
->pcnu_SizeMem
= len
;
1070 if (unit
->pcnu_BaseMem
)
1072 struct TagItem attrs
[] = {
1073 { aHidd_PCIDevice_isIO
, TRUE
},
1074 { aHidd_PCIDevice_isMEM
, TRUE
},
1075 { aHidd_PCIDevice_isMaster
, TRUE
},
1078 OOP_SetAttrs(pciDevice
, (struct TagItem
*)&attrs
);
1080 unit
->pcnu_name
= "[pcnet32.0]";
1082 unit
->pcnu_fe_priv
= AllocMem(sizeof(struct fe_priv
), MEMF_PUBLIC
|MEMF_CLEAR
);
1084 unit
->pcnu_fe_priv
->fep_pcnet_init_block
= HIDD_PCIDriver_AllocPCIMem(
1086 sizeof(struct pcnet32_init_block
));
1088 unit
->pcnu_UnitNum
= 0;
1090 pcn32_get_functions(unit
);
1092 if (unit
->pcnu_fe_priv
)
1094 unit
->pcnu_fe_priv
->pci_dev
= unit
;
1095 InitSemaphore(&unit
->pcnu_fe_priv
->lock
);
1098 struct Message
*msg
;
1100 unit
->pcnu_irqhandler
.is_Node
.ln_Type
= NT_INTERRUPT
;
1101 unit
->pcnu_irqhandler
.is_Node
.ln_Pri
= 100;
1102 unit
->pcnu_irqhandler
.is_Node
.ln_Name
= LIBBASE
->pcnb_Device
.dd_Library
.lib_Node
.ln_Name
;
1103 unit
->pcnu_irqhandler
.is_Code
= (VOID_FUNC
)PCN32_IntHandler
;
1104 unit
->pcnu_irqhandler
.is_Data
= unit
;
1106 unit
->pcnu_touthandler
.is_Node
.ln_Type
= NT_INTERRUPT
;
1107 unit
->pcnu_touthandler
.is_Node
.ln_Pri
= 100;
1108 unit
->pcnu_touthandler
.is_Node
.ln_Name
= LIBBASE
->pcnb_Device
.dd_Library
.lib_Node
.ln_Name
;
1109 unit
->pcnu_touthandler
.is_Code
= (VOID_FUNC
)PCN32_TimeoutHandler
;
1110 unit
->pcnu_touthandler
.is_Data
= unit
;
1112 unit
->pcnu_rx_int
.is_Node
.ln_Type
= NT_INTERRUPT
;
1113 unit
->pcnu_rx_int
.is_Node
.ln_Name
= unit
->pcnu_name
;
1114 unit
->pcnu_rx_int
.is_Code
= (VOID_FUNC
)PCN32_RX_Int
;
1115 unit
->pcnu_rx_int
.is_Data
= unit
;
1117 unit
->pcnu_tx_int
.is_Node
.ln_Type
= NT_INTERRUPT
;
1118 unit
->pcnu_tx_int
.is_Node
.ln_Name
= unit
->pcnu_name
;
1119 unit
->pcnu_tx_int
.is_Code
= (VOID_FUNC
)PCN32_TX_Int
;
1120 unit
->pcnu_tx_int
.is_Data
= unit
;
1122 unit
->pcnu_tx_end_int
.is_Node
.ln_Name
= unit
->pcnu_name
;
1123 unit
->pcnu_tx_end_int
.is_Code
= (VOID_FUNC
)PCN32_TX_End_Int
;
1124 unit
->pcnu_tx_end_int
.is_Data
= unit
;
1126 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
1128 struct MsgPort
*port
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
| MEMF_CLEAR
);
1129 unit
->pcnu_request_ports
[i
] = port
;
1131 if (port
== NULL
) success
= FALSE
;
1135 NEWLIST(&port
->mp_MsgList
);
1136 port
->mp_Flags
= PA_IGNORE
;
1137 port
->mp_SigTask
= &unit
->pcnu_tx_int
;
1141 unit
->pcnu_request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
1145 D(bug("%s: Initialise Dev @ %x, IOBase @ %x\n", unit
->pcnu_name
, unit
, unit
->pcnu_BaseMem
));
1147 pcnet32_reset_16(unit
->pcnu_BaseMem
);
1149 D(bug("%s: Chipset RESET\n", unit
->pcnu_name
));
1151 i
= pcnet32_readcsr_16(unit
->pcnu_BaseMem
, 0); // Check for 16bit/32bit chip IO
1152 BOOL check
= pcnet32_check_16(unit
->pcnu_BaseMem
);
1154 if ((i
== 4)&&(check
))
1156 D(bug("%s: Using 16bit I/O Funcs\n", unit
->pcnu_name
));
1157 unit
->read_csr
= pcnet32_readcsr_16
;
1158 unit
->write_csr
= pcnet32_writecsr_16
;
1159 unit
->read_bcr
= pcnet32_readbcr_16
;
1160 unit
->write_bcr
= pcnet32_writebcr_16
;
1161 unit
->read_rap
= pcnet32_readrap_16
;
1162 unit
->write_rap
= pcnet32_writerap_16
;
1163 unit
->reset
= pcnet32_reset_16
;
1167 pcnet32_reset_32(unit
->pcnu_BaseMem
); // 32bit reset..
1169 i
= pcnet32_readcsr_32(unit
->pcnu_BaseMem
, 0);
1170 check
= pcnet32_check_32(unit
->pcnu_BaseMem
);
1172 if ((i
== 4)&&(check
))
1174 D(bug("%s: Using 32bit I/O Funcs\n", unit
->pcnu_name
));
1175 unit
->read_csr
= pcnet32_readcsr_32
;
1176 unit
->write_csr
= pcnet32_writecsr_32
;
1177 unit
->read_bcr
= pcnet32_readbcr_32
;
1178 unit
->write_bcr
= pcnet32_writebcr_32
;
1179 unit
->read_rap
= pcnet32_readrap_32
;
1180 unit
->write_rap
= pcnet32_writerap_32
;
1181 unit
->reset
= pcnet32_reset_32
;
1185 D(bug("%s: Error - Unsupported chipset .. (unknown data size)\n", unit
->pcnu_name
));
1192 i
= (unit
->read_csr(unit
->pcnu_BaseMem
, 88) | ( unit
->read_csr(unit
->pcnu_BaseMem
, 89) << 16));
1194 unit
->pcnu_pcnet_chiprevision
= (i
>> 12) & 0xffff;
1196 D(bug("%s: PCnet chip version %x [%x]\n", unit
->pcnu_name
, i
, unit
->pcnu_pcnet_chiprevision
));
1198 unit
->pcnu_pcnet_supported
= 0;
1200 switch (unit
->pcnu_pcnet_chiprevision
)
1204 unit
->pcnu_pcnet_chipname
= "PCnet/PCI 79c970";
1208 unit
->pcnu_pcnet_chipname
= "PCnet/PCI II 79c970A";
1209 unit
->pcnu_pcnet_supported
|= support_fdx
;
1213 unit
->pcnu_pcnet_chipname
= "PCnet/FAST 79c971";
1214 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
| support_fset
| support_ltint
);
1218 unit
->pcnu_pcnet_chipname
= "PCnet/FAST+ 79c972";
1219 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
| support_fset
);
1223 unit
->pcnu_pcnet_chipname
= "PCnet/FAST III 79c973";
1224 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
);
1228 unit
->pcnu_pcnet_chipname
= "PCnet/FAST III 79c975";
1229 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
);
1233 unit
->pcnu_pcnet_chipname
= "PCnet/Home 79c978";
1234 unit
->pcnu_pcnet_supported
|= support_fdx
;
1236 /* TODO: PCnet/Home needs extra set up .. */
1239 D(bug("%s: ERROR - Unsupported Chipset (unknown revision)\n", unit
->pcnu_name
));
1243 D(bug("%s: Found %s chipset based NIC\n", unit
->pcnu_name
, unit
->pcnu_pcnet_chipname
));
1244 if (unit
->pcnu_pcnet_supported
& support_fdx
)
1245 D(bug("%s: Chip Supports Full Duplex\n", unit
->pcnu_name
));
1246 if (unit
->pcnu_pcnet_supported
& support_mii
)
1247 D(bug("%s: Chip Supports MII\n", unit
->pcnu_name
));
1248 if (unit
->pcnu_pcnet_supported
& support_fset
)
1249 D(bug("%s: Chip Supports FSET\n", unit
->pcnu_name
));
1250 if (unit
->pcnu_pcnet_supported
& support_ltint
)
1251 D(bug("%s: Chip Supports LTINT\n", unit
->pcnu_name
));
1254 if (((unit
->pcnu_pcnet_chiprevision
+1) & 0xfffe) == 0x2624)
1256 i
= unit
->read_csr(unit
->pcnu_BaseMem
, 80) & 0x0c00; /* Check tx_start_pt */
1258 D(bug("%s: tx_start_pt(0x%hX):", unit
->pcnu_name
, i
));
1262 D(bug(" 20 bytes,"));
1265 D(bug(" 64 bytes,"));
1268 D(bug(" 128 bytes,"));
1271 D(bug("~220 bytes,"));
1275 i
= unit
->read_bcr(unit
->pcnu_BaseMem
, 18); /* Check burst/bus control */
1277 D(bug(" BCR18(%hX):", i
& 0xffff));
1279 D(bug("BurstWrEn "));
1281 D(bug("BurstRdEn "));
1287 i
= unit
->read_bcr(unit
->pcnu_BaseMem
, 25);
1288 D(bug(" SRAMSIZE=0x%hX,", i
<< 8));
1289 i
= unit
->read_bcr(unit
->pcnu_BaseMem
, 26);
1290 D(bug(" SRAM_BND=0x%hX,", i
<< 8));
1291 i
= unit
->read_bcr(unit
->pcnu_BaseMem
, 27);
1303 LIBBASE
->pcnb_syncport
= CreateMsgPort();
1305 unit
->pcnu_Process
= CreateNewProcTags(
1306 NP_Entry
, (IPTR
)PCN32_Schedular
,
1307 NP_Name
, PCNET32_TASK_NAME
,
1309 NP_UserData
, (IPTR
)unit
,
1310 NP_StackSize
, 140960,
1313 WaitPort(LIBBASE
->pcnb_syncport
);
1314 msg
= GetMsg(LIBBASE
->pcnb_syncport
);
1316 DeleteMsgPort(LIBBASE
->pcnb_syncport
);
1318 D(bug("[pcnet32] Unit up and running\n"));
1324 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit
->pcnu_name
));
1330 D(bug("[pcnet32] PANIC! Couldn't get MMIO area. Aborting\n"));
1332 DeleteUnit(PCNet32Base
, unit
);
1337 * DeleteUnit - removes selected unit. Frees all resources and structures.
1339 * The caller should be sure, that given unit is really ready to be freed.
1342 void DeleteUnit(struct PCN32Base
*PCNet32Base
, struct PCN32Unit
*Unit
)
1347 if (Unit
->pcnu_Process
)
1349 /* Tell our process to quit, and wait until it does so */
1350 Signal(&Unit
->pcnu_Process
->pr_Task
, 1 << Unit
->pcnu_signal_0
);
1351 while (FindTask(PCNET32_TASK_NAME
) != NULL
)
1355 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
1357 if (Unit
->pcnu_request_ports
[i
] != NULL
)
1358 FreeMem(Unit
->pcnu_request_ports
[i
], sizeof(struct MsgPort
));
1360 Unit
->pcnu_request_ports
[i
] = NULL
;
1363 if (Unit
->pcnu_fe_priv
)
1365 FreeMem(Unit
->pcnu_fe_priv
, sizeof(struct fe_priv
));
1366 Unit
->pcnu_fe_priv
= NULL
;
1369 if (Unit
->pcnu_BaseMem
)
1371 HIDD_PCIDriver_UnmapPCI(Unit
->pcnu_PCIDriver
,
1372 (APTR
)Unit
->pcnu_BaseMem
,
1373 Unit
->pcnu_SizeMem
);
1376 FreeMem(Unit
, sizeof(struct PCN32Unit
));
1380 static struct AddressRange
*FindMulticastRange(LIBBASETYPEPTR LIBBASE
, struct PCN32Unit
*unit
,
1381 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
, UWORD upper_bound_right
)
1383 struct AddressRange
*range
, *tail
;
1386 range
= (APTR
)unit
->pcnu_multicast_ranges
.mlh_Head
;
1387 tail
= (APTR
)&unit
->pcnu_multicast_ranges
.mlh_Tail
;
1389 while((range
!= tail
) && !found
)
1391 if((lower_bound_left
== range
->lower_bound_left
) &&
1392 (lower_bound_right
== range
->lower_bound_right
) &&
1393 (upper_bound_left
== range
->upper_bound_left
) &&
1394 (upper_bound_right
== range
->upper_bound_right
))
1397 range
= (APTR
)range
->node
.mln_Succ
;
1406 BOOL
AddMulticastRange(LIBBASETYPEPTR LIBBASE
, struct PCN32Unit
*unit
, const UBYTE
*lower_bound
,
1407 const UBYTE
*upper_bound
)
1409 struct AddressRange
*range
;
1410 ULONG lower_bound_left
, upper_bound_left
;
1411 UWORD lower_bound_right
, upper_bound_right
;
1413 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1414 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1415 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1416 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1418 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1419 upper_bound_left
, upper_bound_right
);
1425 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1428 range
->lower_bound_left
= lower_bound_left
;
1429 range
->lower_bound_right
= lower_bound_right
;
1430 range
->upper_bound_left
= upper_bound_left
;
1431 range
->upper_bound_right
= upper_bound_right
;
1432 range
->add_count
= 1;
1435 AddTail((APTR
)&unit
->pcnu_multicast_ranges
, (APTR
)range
);
1438 if (unit
->pcnu_range_count
++ == 0)
1440 unit
->pcnu_flags
|= IFF_ALLMULTI
;
1441 unit
->set_multicast(unit
);
1446 return range
!= NULL
;
1449 BOOL
RemMulticastRange(LIBBASETYPEPTR LIBBASE
, struct PCN32Unit
*unit
, const UBYTE
*lower_bound
, const UBYTE
*upper_bound
)
1451 struct AddressRange
*range
;
1452 ULONG lower_bound_left
, upper_bound_left
;
1453 UWORD lower_bound_right
, upper_bound_right
;
1455 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1456 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1457 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1458 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1460 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1461 upper_bound_left
, upper_bound_right
);
1465 if(--range
->add_count
== 0)
1468 Remove((APTR
)range
);
1470 FreeMem(range
, sizeof(struct AddressRange
));
1472 if (--unit
->pcnu_range_count
== 0)
1474 unit
->pcnu_flags
&= ~IFF_ALLMULTI
;
1475 unit
->set_multicast(unit
);
1479 return range
!= NULL
;