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
));
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;
676 * Handle timeouts and other strange cases
678 static AROS_INTH1(PCN32_TimeoutHandler
,struct PCN32Unit
*, dev
)
683 struct Device
*TimerBase
= dev
->pcnu_TimerSlowReq
->tr_node
.io_Device
;
686 //D(bug("%s: PCN32_TimeoutHandler()\n", dev->pcnu_name));
689 * If timeout timer is expected, and time elapsed - regenerate the
692 if (dev
->pcnu_toutNEED
&& (CmpTime(&time
, &dev
->pcnu_toutPOLL
) < 0))
694 dev
->pcnu_toutNEED
= FALSE
;
695 Cause(&dev
->pcnu_tx_end_int
);
704 * The interrupt handler - schedules code execution to proper handlers depending
705 * on the message from nForce.
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
)
719 // struct fe_priv *np = dev->pcnu_fe_priv;
720 // UBYTE *base = (UBYTE*) dev->pcnu_BaseMem;
723 struct Device
*TimerBase
= dev
->pcnu_TimerSlowReq
->tr_node
.io_Device
;
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?
746 if ( csr_0
& (1 << 2) ) // (STOP) Chipset is stopped
752 if ( csr_0
& (1 << 4) ) // (TXON) Transmitter ON?
759 D(bug("[TXON:OFF]"));
762 if ( csr_0
& (1 << 5) ) // (RXON) Reciever ON?
769 D(bug("[RXON:OFF]"));
772 if ( csr_0
& (1 << 8) ) // (IDON) Initialisation Done?
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
));
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
;
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];
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
));
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
));
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
);
877 D(bug("SUCCESS!!\n"));
880 Remove((APTR
)request
);
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
;
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
;
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
)))
917 range
= (APTR
)range
->node
.mln_Succ
;
921 unit
->pcnu_special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
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
))
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
);
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
);
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
;
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"));
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
);
1023 D(bug("[pcnet32] PCN32_Schedular: Handle incomming signal.\n"));
1024 /* Handle incoming signals */
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
;
1043 D(bug("[pcnet32] CreateUnit()\n"));
1047 IPTR DeviceID
, base
, len
;
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
},
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(
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
;
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
;
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
;
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
;
1187 D(bug("%s: Error - Unsupported chipset .. (unknown data size)\n", unit
->pcnu_name
));
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
)
1206 unit
->pcnu_pcnet_chipname
= "PCnet/PCI 79c970";
1210 unit
->pcnu_pcnet_chipname
= "PCnet/PCI II 79c970A";
1211 unit
->pcnu_pcnet_supported
|= support_fdx
;
1215 unit
->pcnu_pcnet_chipname
= "PCnet/FAST 79c971";
1216 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
| support_fset
| support_ltint
);
1220 unit
->pcnu_pcnet_chipname
= "PCnet/FAST+ 79c972";
1221 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
| support_fset
);
1225 unit
->pcnu_pcnet_chipname
= "PCnet/FAST III 79c973";
1226 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
);
1230 unit
->pcnu_pcnet_chipname
= "PCnet/FAST III 79c975";
1231 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
);
1235 unit
->pcnu_pcnet_chipname
= "PCnet/Home 79c978";
1236 unit
->pcnu_pcnet_supported
|= support_fdx
;
1238 /* TODO: PCnet/Home needs extra set up .. */
1241 D(bug("%s: ERROR - Unsupported Chipset (unknown revision)\n", unit
->pcnu_name
));
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
));
1256 if (((unit
->pcnu_pcnet_chiprevision
+1) & 0xfffe) == 0x2624)
1258 i
= unit
->read_csr(unit
->pcnu_BaseMem
, 80) & 0x0c00; /* Check tx_start_pt */
1260 D(bug("%s: tx_start_pt(0x%hX):", unit
->pcnu_name
, i
));
1264 D(bug(" 20 bytes,"));
1267 D(bug(" 64 bytes,"));
1270 D(bug(" 128 bytes,"));
1273 D(bug("~220 bytes,"));
1277 i
= unit
->read_bcr(unit
->pcnu_BaseMem
, 18); /* Check burst/bus control */
1279 D(bug(" BCR18(%hX):", i
& 0xffff));
1281 D(bug("BurstWrEn "));
1283 D(bug("BurstRdEn "));
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);
1305 LIBBASE
->pcnb_syncport
= CreateMsgPort();
1307 unit
->pcnu_Process
= CreateNewProcTags(
1308 NP_Entry
, (IPTR
)PCN32_Schedular
,
1309 NP_Name
, PCNET32_TASK_NAME
,
1311 NP_UserData
, (IPTR
)unit
,
1312 NP_StackSize
, 140960,
1315 WaitPort(LIBBASE
->pcnb_syncport
);
1316 msg
= GetMsg(LIBBASE
->pcnb_syncport
);
1318 DeleteMsgPort(LIBBASE
->pcnb_syncport
);
1320 D(bug("[pcnet32] Unit up and running\n"));
1326 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit
->pcnu_name
));
1333 D(bug("[pcnet32] PANIC! Couldn't get MMIO area. Aborting\n"));
1336 DeleteUnit(PCNet32Base
, unit
);
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
)
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
)
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
;
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
))
1401 range
= (APTR
)range
->node
.mln_Succ
;
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
);
1429 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
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;
1439 AddTail((APTR
)&unit
->pcnu_multicast_ranges
, (APTR
)range
);
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
);
1469 if(--range
->add_count
== 0)
1472 Remove((APTR
)range
);
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
;